diff -r 000000000000 -r bde4ae8d615e os/ossrv/lowlevellibsandfws/apputils/src/Baksrv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/ossrv/lowlevellibsandfws/apputils/src/Baksrv.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1453 @@ +// 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: +// + +#include +#include "Baksrvs.h" +#include +#include +#include +#include +#include "patchdata.h" + +extern const BSUL::TClientMessageServerData KServerData; + +const TInt KBakServMaxOperationTimerLoops = 3; // Number of iterations for base operation timer + +_LIT(KPanic,"BackupServer"); +// +// RMessage::Panic() also 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 RMessagePtr2& aMessage, TInt aPanic) + { + aMessage.Panic(KPanic,aPanic); + } + + +// +// class CShutdownServer +// + +NONSHARABLE_CLASS(CShutdownServer) : public CTimer + { + enum {KMyShutdownDelay=0x2000000}; // approx 2s +public: + inline CShutdownServer(); + inline void ConstructL(); + inline void Start(); +private: + void RunL(); + }; + +inline CShutdownServer::CShutdownServer() + :CTimer(-1) + { + CActiveScheduler::Add(this); + } + +inline void CShutdownServer::ConstructL() + { + CTimer::ConstructL(); + } +inline void CShutdownServer::Start() + { + After(KMyShutdownDelay); + } + +// +// Initiate server exit when the timer expires +// +void CShutdownServer::RunL() + { + CActiveScheduler::Stop(); + } + + +// +// class CBaServBackupScheduler +// + +EXPORT_C CBaServBackupScheduler::CBaServBackupScheduler() +{ +} + +EXPORT_C CBaServBackupScheduler::~CBaServBackupScheduler() +{ +} + +/** + * + * Set the error handler to aErrorHandler to the current scheduler. + * + * @param "CBaServBackupSession* aErrorHandler" + * The handler session. + */ +EXPORT_C void CBaServBackupScheduler::SetErrorHandler(CBaServBackupSession* aErrorHandler) + { + iErrorHandler=aErrorHandler; + } + +/** + * + * Handles the error aError. + * + * @param "TInt aError" + * The error. + */ +EXPORT_C void CBaServBackupScheduler::Error(TInt aError) const + { + if (iErrorHandler) + { + iErrorHandler->HandleError(aError); + } + else if (aError!=KLeaveWithoutAlert) + { + // Handling the in this way implies that ServiceL should not leave. + CActiveScheduler::Error(aError); + } + } + +/** +Class CBaServBackupSession::CReRegistrationTimer +*/ +NONSHARABLE_CLASS(CBaServBackupSession::CReRegistrationTimer) : public CPeriodic +{ + public: + static CReRegistrationTimer* NewL(TInt aPriority); + static TInt ReRegistrationTimerCallBack(TAny* aPtr); + + protected: + TInt RunError(TInt aError); + + private: + CReRegistrationTimer(TInt aPriority); + void HandleReRegistrationTimerCallBack(); + + public: + CBaBackupServer* iBackupServer; +}; + +/** +Class CBaBackupServer::CBaServCloseAllOperationTimer +*/ + +NONSHARABLE_CLASS(CBaBackupServer::CBaServCloseAllOperationTimer): public CPeriodic +{ + public: + static CBaServCloseAllOperationTimer* NewL(CBaBackupServer* aBackupServer); + void ConstructL(CBaBackupServer* aBackupServer); + ~CBaServCloseAllOperationTimer(); + void SetMessage(const RMessagePtr2& aPtr); + RMessagePtr2 Message(); + TInt GetOperationCount(); + void SetOperationCount(TInt aCount); + static TInt OperationTimerCallBack(TAny* aPtr); + protected: + TInt RunError(TInt aError); + private: + void HandleOperationTimerCallBack(); + CBaServCloseAllOperationTimer(); + private: + RMessagePtr2 iCloseAllFilesMessage; + TInt16 iOperationCount; + CBaBackupServer* iBackupServer; +}; + +// +// class CBaBackupServer +// + +/** + * + * Returns a pointer to CBaBackupServer object. + * + * @return "CBaBackupServer" + * A newly-constructed backup server object. + */ +EXPORT_C CBaBackupServer* CBaBackupServer::NewL() + { // static + CBaBackupServer* self=new(ELeave) CBaBackupServer(CActive::EPriorityStandard); + return self; + } + +/** + * + * Constructor. + * + * @param "TInt aPriority" + * The active object priority. + */ +EXPORT_C CBaBackupServer::CBaBackupServer(TInt aPriority) + : CServer2(aPriority) + {} +/** + * + * Destructor. + * + */ +EXPORT_C CBaBackupServer::~CBaBackupServer() + { + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + delete session; + } + delete iShutdown; + delete iExtension; + delete iCloseAllFilesOperationTimer; + } + +/** + * + * Completes the server construction by adding the server to the active scheduler and creating + * a CShutdownServer object. + * + */ +EXPORT_C void CBaBackupServer::ConstructL() + { + StartL(__BACKUP_SERVER_NAME_V2); + iExtension = new(ELeave) CBaBackupServerExt(); + iShutdown = new (ELeave) CShutdownServer; + iShutdown->ConstructL(); + // ensure that the server still exits even if the 1st client fails to connect + iShutdown->Start(); + iRegisteredFilesCount = 0; + iCloseAllFilesOperationTimer = CBaBackupServer::CBaServCloseAllOperationTimer::NewL(this); + iCloseAllOperationRunning = EFalse; + + //initialise the client message framework + BSUL::CClientMessage::InitialiseFrameworkL(KServerData); + } + +/** + * + * Sets the server to be busy with the aUniqueClientId client. + * + * @param "TUint32 aUniqueClientId" + * A unique client identifier. + */ +EXPORT_C void CBaBackupServer::SetBusy(TUint32 aUniqueClientId) + { + iExtension->iUniqueBusyClientId=aUniqueClientId; + } + +/** + * + * Returns ETrue if the client using the server is not the one identified by aUniqueClientId + * oterwise EFalse + * + * @param "TUint32 aUniqueClientId" + * A unique client identifier. + */ +EXPORT_C TBool CBaBackupServer::IsOtherClientBusy(TUint32 aUniqueClientId) const + { + return (iExtension->iUniqueBusyClientId!=0 && iExtension->iUniqueBusyClientId!=aUniqueClientId); + } + +/** + * + * Returns ETrue if the client using the server corresponds has aUniqueClientId as unique id + * oterwise EFalse + * + * @param "TUint32 aUniqueClientId" + * A unique client identifier id. + */ +EXPORT_C TBool CBaBackupServer::IsClientBusy(TUint32 aUniqueClientId) const + { + return ((iExtension->iUniqueBusyClientId==aUniqueClientId) || + ((iExtension->iCachedBusyClientId != 0) && (iExtension->iCachedBusyClientId == aUniqueClientId))); + } + +/** + * + * Handles the closing of all files by signaling the new file lock flag, aFlag, to all client. + * + * @param "MBackupObserver::TFileLockFlags aFlag" + * A file lock flag. + */ +EXPORT_C void CBaBackupServer::CloseAllFilesL(MBackupObserver::TFileLockFlags aFlag) + { + // Set the close all operation flag and the reregistration counter to zero + iCloseAllOperationRunning = ETrue; + iSessionLockReRegistrationCount = 0; + + // cleanup that calls RestartAll if required + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + static_cast(session)->SignalReleaseAllFileLocksL(aFlag); + } + } + +/** + * + * Signals to all clients of getting the lock of their respective files. + * + */ +EXPORT_C void CBaBackupServer::RestartAll() + { + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + static_cast(session)->SignalRetakeAllFileLocks(); + } + } + +/** + * + * Allows any subclass of CBaBackupServer of completing the closing of files. + * The server will lose the ownership of aClosedFiles object, which implies it is up to this virtual + * function to deal with it in order to avoid a memory leak. + * + * @param "CArrayFix* aClosedFiles" + * An array of closed files. + */ +EXPORT_C void CBaBackupServer::CompleteClosingFiles(CArrayFix* aClosedFiles) + { + delete aClosedFiles; + } + +/** + * + * Allows application framework backup code to check if all registerd files have beem updated + * + */ +EXPORT_C TBool CBaBackupServer::HaveAllCloseAllFilesClientsReRegistered() + { + return((iRegisteredFilesCount == iSessionLockReRegistrationCount) ? ETrue : EFalse); + } + +void CBaBackupServer::CloseFileL(MBackupObserver::TFileLockFlags aFlag,const TDesC& aFileName) + { + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + static_cast(session)->SignalReleaseFileLockL(aFlag,aFileName); + } + } + +void CBaBackupServer::RestartFile(const TDesC& aFileName) + { + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + static_cast(session)->SignalRetakeFileLocks(aFileName); + } + } + +/** + * + * Creates a server-side client CBaServBackupSession session object by checking first if + * the version of the server is compatible with the client. + * + * @param "const TVersion &aVersion" + * Version information supplied by the client. + */ +EXPORT_C CSession2* CBaBackupServer::NewSessionL(const TVersion &aVersion, const RMessage2& /*aMessage*/) const + { + TVersion ver(KBakServMajorVN,KBakServMinorVN,KBakServBuildVN); + if (!User::QueryVersionSupported(ver,aVersion)) + User::Leave(KErrNotSupported); +// + return CBaServBackupSession::NewL(); + } + +/** + * + * Signals to all clients the aBackupOperationAttributes. + * + * @param "const TBackupOperationAttributes& aBackupOperationAttributes" + * Backup operation attributes. + */ +EXPORT_C void CBaBackupServer::SignalBackupOperation(const TBackupOperationAttributes& aBackupOperationAttributes) + { + TDblQueIter iter(iSessionIter); + iter.SetToFirst(); + + for (CSession2* session=iter++; session!=NULL; session=iter++) + { + static_cast(session)->SignalBackupOperation(aBackupOperationAttributes); + } + // Cache session id if starting backup + if (aBackupOperationAttributes.iOperation == MBackupOperationObserver::EStart) + iExtension->iCachedBusyClientId = iExtension->iUniqueBusyClientId; + } + +void CBaBackupServer::AddSession() + { + iShutdown->Cancel(); + ++iSessionCount; + } + +void CBaBackupServer::DropSession() + { + if (--iSessionCount==0) + { + iShutdown->Start(); + } + } + +/* + * Check to see if a CloseAll opertation is in progress + * + */ +TBool CBaBackupServer::IsCloseAllOperationRunning() + { + return iCloseAllOperationRunning; + } + +/* + * Set value of IsCloseAllOperationRunning + * + */ +EXPORT_C void CBaBackupServer::SetCloseAllOperationRunningState(TBool aRunning) + { + iCloseAllOperationRunning = aRunning; + } + +/** + * + * This timer will only be created in cases of no derived backup server + * + */ +void CBaBackupServer::StartCloseAllFilesOperationTimer(const RMessagePtr2& aPtr) + { + // Store the CloseAll message in case we need to Complete on a timeout + iCloseAllFilesOperationTimer->SetMessage(aPtr); + + // If hardware use patchable constant if not default to 3 seconds + iCloseAllFilesOperationTimer->Start(KBaBackupCloseallFilesTimeout, KBaBackupCloseallFilesTimeout, TCallBack(CBaBackupServer::CBaServCloseAllOperationTimer::OperationTimerCallBack, iCloseAllFilesOperationTimer)); + } + +/** + * Handle an error from CBaServBackupSession::ServiceL() + * A bad descriptor error implies a badly programmed client, so panic it; + * otherwise report the error to the client + * + * @param "TInt aError" + * The error. + */ +EXPORT_C TInt CBaBackupServer::RunError(TInt aError) + { + if (aError==KErrBadDescriptor) + { + PanicClient(Message(), EBufferOverflow); + } + else + { + Message().Complete(aError); + } + // + // The leave will result in an early return from CServer::RunL(), skipping + // the call to request another message. So do that now in order to keep the + // server running. + ReStart(); + return KErrNone; // handled the error fully + } + +// +// class CBaBackupServer::CBaServCloseAllOperationTimer +// + +/** +@internalComponent +*/ +CBaBackupServer::CBaServCloseAllOperationTimer* CBaBackupServer::CBaServCloseAllOperationTimer::NewL(CBaBackupServer* aBackupServer) + { // static + CBaBackupServer::CBaServCloseAllOperationTimer* self=new(ELeave) CBaBackupServer::CBaServCloseAllOperationTimer(); + CleanupStack::PushL(self); + self->ConstructL(aBackupServer); + CleanupStack::Pop(); // self + CActiveScheduler::Add(self); + return self; + } + +/** +@internalComponent +*/ + +void CBaBackupServer::CBaServCloseAllOperationTimer::ConstructL(CBaBackupServer* aBackupServer) + { + CTimer::ConstructL(); + iBackupServer = aBackupServer; + iOperationCount = 0; + } +/** +@internalComponent +*/ + +TInt CBaBackupServer::CBaServCloseAllOperationTimer::GetOperationCount() +{ + return iOperationCount; +} + +/** +@internalComponent +*/ + +void CBaBackupServer::CBaServCloseAllOperationTimer::SetOperationCount(TInt aCount) +{ + iOperationCount = aCount; +} + +/** +@internalComponent +*/ + +TInt CBaBackupServer::CBaServCloseAllOperationTimer::RunError(TInt aError) + { + if (aError==KLeaveWithoutAlert) + { + return KErrNone; + } + return aError; + } + +/** +@internalComponent +*/ +CBaBackupServer::CBaServCloseAllOperationTimer::CBaServCloseAllOperationTimer() + : CPeriodic(CActive::EPriorityStandard) + { ; } + +/** +@internalComponent +*/ +CBaBackupServer::CBaServCloseAllOperationTimer::~CBaServCloseAllOperationTimer() + { + if (IsActive()) + Cancel(); + } + +/** +@internalComponent +*/ +void CBaBackupServer::CBaServCloseAllOperationTimer::SetMessage(const RMessagePtr2& aPtr) + { + iCloseAllFilesMessage = aPtr; + } + +/** +@internalComponent +*/ +RMessagePtr2 CBaBackupServer::CBaServCloseAllOperationTimer::Message() + { + return iCloseAllFilesMessage; + } + +/** +@internalComponent +*/ +TInt CBaBackupServer::CBaServCloseAllOperationTimer::OperationTimerCallBack(TAny* aPtr) + { // static + TRAP_IGNORE(REINTERPRET_CAST(CBaBackupServer::CBaServCloseAllOperationTimer*,aPtr)->HandleOperationTimerCallBack()); + return 0; + } + +/** +@internalComponent +*/ +void CBaBackupServer::CBaServCloseAllOperationTimer::HandleOperationTimerCallBack() + { + TBool finished = iBackupServer->HaveAllCloseAllFilesClientsReRegistered(); + TInt retCode; + if (finished || (iOperationCount == KBakServMaxOperationTimerLoops)) + { + if (finished) + { + retCode = KErrNone; + } + else + { + retCode = KErrLocked; + } + + // One way or another CloseAll is finished at this point + iBackupServer->SetCloseAllOperationRunningState(EFalse); + + iCloseAllFilesMessage.Complete(retCode); + Cancel(); + } + else + { + iOperationCount++; + if (IsActive()) + { + Cancel(); + + // If hardware use patchable constant if not default to 3 seconds + Start(KBaBackupCloseallFilesTimeout, KBaBackupCloseallFilesTimeout, TCallBack(CBaBackupServer::CBaServCloseAllOperationTimer::OperationTimerCallBack,this)); + } + } + } + +// +// class CBaServBackupMessageQueue +// + +inline CBaServBackupMessageQueue::TQueueItem::TQueueItem(HBufC* aFileName,TInt aOperation) + : iFileName(aFileName), iOperation(aOperation) + {} + +CBaServBackupMessageQueue* CBaServBackupMessageQueue::NewL() + { // static + CBaServBackupMessageQueue* self=new(ELeave) CBaServBackupMessageQueue(); + return self; + } + +CBaServBackupMessageQueue::~CBaServBackupMessageQueue() + { + const TInt count=iQueue.Count(); + for (TInt ii=0;ii=0;ii--) + { + const TQueueItem& item=iQueue[ii]; + if (aFileName.MatchF(*item.iFileName) == KErrNone) + { + delete item.iFileName; + iQueue.Remove(ii); + iQueue.Compress(); + } + } + } + +void CBaServBackupMessageQueue::GetHead(TDes& aFileName,MBackupObserver::TFileLockFlags& aFlag) const + { + aFileName.Zero(); + const TInt index=HeadIndex(); + if (index!=KErrNotFound) + { + const TQueueItem& item=iQueue[index]; + aFileName=item.iFileName->Des(); + aFlag=(MBackupObserver::TFileLockFlags)item.iOperation; + } + } + +TInt CBaServBackupMessageQueue::HeadIndex() const + { + TInt index=KErrNotFound; + const TInt count=iQueue.Count(); + for (TInt ii=0;iiConstructL(); + CleanupStack::Pop(); // self + return self; + } + +/** + * + * Constructor. + * + * @param "RThread aClient" + * The client thread for which this server-side client session is being constructed. + */ +EXPORT_C CBaServBackupSession::CBaServBackupSession() + : CSession2() + { + iUniqueClientId = (TUint32)this; + } + +/** + * + * Destructor. + * + */ +EXPORT_C CBaServBackupSession::~CBaServBackupSession() + { + CBaBackupServer* server=BackupServer(); + if (server->IsClientBusy(iUniqueClientId)) + { + RestartAll(); + if (server->IsBackupOperationRunning()) + { + TBackupOperationAttributes backupOpAtt(MBackupObserver::ETakeLock, MBackupOperationObserver::EAbort); + server->SignalBackupOperation(backupOpAtt); + server->SetBackupOperationRunning(EFalse); + } + server->SetBusy(0); + } + + if (iFileLockObservers) + { + server->DecrementRegisteredFilesCount(iFileLockObservers->Count()); + } + + delete iClosedFiles; + delete iFileLockObservers; + delete iReleasedFiles; + delete iMessageQueue; + delete iReRegistrationTimer; + iReRegistrationTimer = 0; + server->DropSession(); + } + +/** + * + * Completes the session construction by creating a CBaServBackupMessageQueue object. + * + */ +EXPORT_C void CBaServBackupSession::ConstructL() + { + iMessageQueue=CBaServBackupMessageQueue::NewL(); + + // Cannot set iBackupServer in CReRegistrationTimer at this point but must be done before call to Start + iReRegistrationTimer=CBaServBackupSession::CReRegistrationTimer::NewL(CActive::EPriorityStandard); + } + +/** + * + * Completes the construction of this CBaServBackupSession session by just doing a base call class. + * It also notify the server that a new session has been created. + * + * @param "const CServer& aServer" + * The server active object which is responsible for this session + */ +EXPORT_C void CBaServBackupSession::CreateL() + { + BackupServer()->AddSession(); + } + +void CBaServBackupSession::SignalReleaseAllFileLocksL(MBackupObserver::TFileLockFlags aFlag) + { + CBaBackupServer* server=BackupServer(); + if (iFileLockObservers) + { + const TInt count=iFileLockObservers->Count(); + for (TInt ii=0;iiCloseFileL(aFlag,name); + } + } + } + +void CBaServBackupSession::SignalRetakeAllFileLocks() + { +// CBaBackupServer* server=BackupServer(); + if (iReleasedFiles) + { + const TInt count=iReleasedFiles->Count(); + for (TInt ii=count-1;ii>=0;ii--) + { + TFileName name=(*iReleasedFiles)[ii]; +// server->RestartFile(name); + SignalRetakeFileLocks(name); + } + } + } + +LOCAL_C void CleanupCloseFail(TAny* aPtr) + { + CDesCArray* array=REINTERPRET_CAST(CDesCArray*,aPtr); + array->Delete(array->Count()-1); + } + +void CBaServBackupSession::SignalReleaseFileLockL(MBackupObserver::TFileLockFlags aFlag,const TDesC& aFileName) + { + TInt pos; + if (iFileLockObservers && iFileLockObservers->Find(aFileName,pos)==KErrNone) + { + if (iReleasedFiles==NULL) + { + iReleasedFiles=new(ELeave) CDesCArraySeg(1); + } + const TBool addedReleasedFile=iReleasedFiles->Find(aFileName,pos)!=KErrNone; + if (addedReleasedFile) + { + iReleasedFiles->AppendL(aFileName); + CleanupStack::PushL(TCleanupItem(CleanupCloseFail,iReleasedFiles)); + } + iMessageQueue->AddItemL(aFileName,aFlag); + if (!iNotificationPullMsg.IsNull()) + { + iNotificationPullMsg.Complete(KErrNone); + + // Okay - if this is part of a CloseAll operation we need to kick off a ReRegistration timer + if (BackupServer()->IsCloseAllOperationRunning()) + { + // Set backup server for the timer + iReRegistrationTimer->iBackupServer = BackupServer(); + + // If hardware use patchable constant if not default to 3 seconds + iReRegistrationTimer->Start(KBaBackupFileLockReRegistrationTimeout, KBaBackupFileLockReRegistrationTimeout, TCallBack(CBaServBackupSession::CReRegistrationTimer::ReRegistrationTimerCallBack, iReRegistrationTimer)); + } + + } + if (addedReleasedFile) + { + CleanupStack::Pop(); // CleanupCloseFail + } + } + } + +void CBaServBackupSession::SignalRetakeFileLocks(const TDesC& aFileName) + { + if (iReleasedFiles) + { + const TInt count=iReleasedFiles->Count(); + for (TInt ii=count-1;ii>=0;ii--) + { + TFileName name=(*iReleasedFiles)[ii]; + if (name.MatchF(aFileName)==0) + { + iMessageQueue->AddItem(aFileName); + if (!iNotificationPullMsg.IsNull()) + { + iNotificationPullMsg.Complete(KErrNone); + } + iReleasedFiles->Delete(ii); + } + } + if (iReleasedFiles->Count()==0) + { + delete iReleasedFiles; + iReleasedFiles=NULL; + if (iClosedFiles==NULL && BackupServer()->IsClientBusy(iUniqueClientId)) + { + BackupServer()->SetBusy(0); + } + } + } + } + +/** + * + * Allows the session to handle the error. + * + * @param "TInt aError" + * The error. + */ +EXPORT_C void CBaServBackupSession::HandleError(TInt aError) + { + if (aError==KLeaveWithoutAlert) + { + CBaServBackupScheduler::Current()->SetErrorHandler(NULL); + } + } + +void CBaServBackupSession::DoServiceL(TCompletionType& aCompleteType) + { + switch (iClientMessage->Function()) + { + case EBakOpCodeEventReady: + { + HandleEventReadyL(); + aCompleteType = ECompleteAsync; + } + break; + case EBakOpCodeStopNotifications: + { + StopNotifications(); + } + break; + case EBakOpCodeGetEvent: + GetEventL(); + break; + case EBakOpCodeCloseAllFiles: + { + aCompleteType = CloseAllFilesL(iClientMessage->Message()); + } + break; + case EBakOpCodeRestartAll: + RestartAll(); + break; + case EBakOpCodeCloseFile: + CloseFileL(); + break; + case EBakOpCodeRestartFile: + RestartFileL(); + break; + case EBakOpCodeNotifyLockChange: + NotifyLockChangeL(); + break; + case EBakOpCodeNotifyLockChangeCancel: + NotifyLockChangeCancelL(); + break; + case EBakOpCodeNotifyBackupOperation: + NotifyBackupOperationL(); + break; + case EBakOpCodeCancelOutstandingBackupOperationEvent: + { + iBackupOperationObserverPresent = EFalse; + if (!iBackupOperationMessagePtr.IsNull()) + { + GetBackupOperationEventL(iBackupOperationMessagePtr); + iBackupOperationMessagePtr.Complete(KErrCancel); + } + } + break; + case EBakOpCodeGetBackupOperationState: + GetBackupOperationStateL(); + break; + case EBakOpCodeBackupOperationEventReady: + BackupOperationEventReadyL(); + aCompleteType = ECompleteAsync; + break; + case EBakOpCodeGetBackupOperationEvent: + GetBackupOperationEventL(iClientMessage->Message()); + break; + case EBakOpCodeSetBackupOperationObserverIsPresent: + { + iBackupOperationObserverPresent = iClientMessage->GetIntL(0); + } + break; + default: + User::Leave(KErrNotSupported); + break; + } + } + + +/** + * + * Handles the servicing of client requests passed to the backup server. + * + * @param "const RMessage& aMessage" + * The message containing the client request. + */ +EXPORT_C void CBaServBackupSession::ServiceL(const RMessage2& aMessage) + { + + TCompletionType completionType = ECompleteSync; + + BSUL::CClientMessage* clientMessage = 0; + clientMessage = BSUL::CClientMessage::NewL(aMessage); + + //Push iClientMessage onto the cleanupstack. Although an instance variable, + //the lifetime of the object is contained to this function so it needs to + //be pushed and popped here as it is not deleted in the destructor + CleanupStack::PushL(clientMessage); + + //Validate the message + TRAPD(error, clientMessage->ValidateL()); + + iClientMessage = clientMessage; + + if(error == KErrNone) + { + TRAP(error, DoServiceL(completionType)); + } + + if(completionType == ECompleteSync) + { + if (error==KLeaveWithoutAlert) + { + CBaServBackupScheduler::Current()->SetErrorHandler(NULL); + } + else + { + iClientMessage->CompleteRequestL(error); + } + } + + //Pop and destroy message + CleanupStack::PopAndDestroy(clientMessage); + clientMessage = NULL; + iClientMessage = NULL; + } + +void CBaServBackupSession::HandleEventReadyL() + { + if (iReRegistrationTimer->IsActive()) + { // If timer is still active (ie not timed out) we need to increment the counter and cancel the timer + BackupServer()->IncrementFilesReRegistrationCount(); + iReRegistrationTimer->Cancel(); + } + // else timer is already inactive because it's expired + + if (iMessageQueue->IsEmpty()) + { + iNotificationPullMsg = iClientMessage->Message(); + } + else + { + iClientMessage->CompleteRequestL(KErrNone); + } + } + +const TInt KEventFileNameOffset=1; + +void CBaServBackupSession::GetEventL() + { + TFileName fileName; + MBackupObserver::TFileLockFlags fileFlag; + if(!iMessageQueue->IsEmpty()) + { + iMessageQueue->GetHead(fileName,fileFlag); + TBuf num; + num.Num((TInt)fileFlag); + + iClientMessage->WriteL(0,num,0); + + iClientMessage->WriteL(0,fileName,KEventFileNameOffset); + + iMessageQueue->RemoveHead(); + } + else + { + iClientMessage->PanicClient(KPanic,ENoEventToFetch); + User::Leave(KLeaveWithoutAlert); + } + } + +void CBaServBackupSession::CleanupCloseAllFiles(TAny* aPtr) + { // static + CBaServBackupSession* self=REINTERPRET_CAST(CBaServBackupSession*,aPtr); + delete self->iClosedFiles; + self->iClosedFiles=NULL; + self->BackupServer()->RestartAll(); + } + +/** + Asks the server to close all files. This function may leave in case the server is busy. + If the requesting client is the current busy client and it has already requested CloseAll, + this request will be ignored. + + @param aMessage The reference to the message containing the client request: file lock. + @leave KErrServerBusy if the requesting client is not the busy client. Plus other system-wide + errors. + */ +EXPORT_C TCompletionType CBaServBackupSession::CloseAllFilesL(const RMessage2& aMessage) + { + // Raise file lock notifications + TRAPD(err,DoCloseAllFilesL(aMessage)); + + if (err == KErrNone) + { + // Start timer to check all file locks re-registered before completing message + BackupServer()->StartCloseAllFilesOperationTimer(aMessage); + } + else + { + // If the error is that the same client has already requested CloseAll, ignore this request + // If not this error, recover the CloseAllOperationRunningState flag and leave with the error. + if (err != KErrAlreadyExists) + { + BackupServer()->SetCloseAllOperationRunningState(EFalse); + User::Leave(err); + } + } + + return ECompleteAsync; + } + +void CBaBackupServer::IncrementRegisteredFilesCount() + { + iRegisteredFilesCount++; + } + +void CBaBackupServer::DecrementRegisteredFilesCount(TInt aNumberFiles) + { + iRegisteredFilesCount = iRegisteredFilesCount - aNumberFiles; + } + +void CBaBackupServer::IncrementFilesReRegistrationCount() + { + iSessionLockReRegistrationCount++; + } + +/** + Function called by both base and derived backup sessions in order to start asynchronous + file lock notifications. + The requesting client is set to the current busy client. + + @leave KErrServerBusy if the requesting client is not the current busy client or the server + is under CloseAll operation. KErrAlreadyExists if the same client has sent CloseAll request. + Plus other system-wide errors. + */ + +EXPORT_C TCompletionType CBaServBackupSession::DoCloseAllFilesL(const RMessage2& /*aMessage*/) + { + CBaBackupServer* server=BackupServer(); + if (server->IsOtherClientBusy(iUniqueClientId)) + { + User::Leave(KErrServerBusy); + } + + if (BackupServer()->IsCloseAllOperationRunning()) + { + User::Leave(KErrAlreadyExists); + } + + CleanupStack::PushL(TCleanupItem(CleanupCloseAllFiles,this)); + if (iClosedFiles) + { + delete iClosedFiles; + iClosedFiles=NULL; + } + server->SetBusy(iUniqueClientId); + + MBackupObserver::TFileLockFlags fileFlag= + (MBackupObserver::TFileLockFlags)iClientMessage->GetIntL(0); + server->CloseAllFilesL(fileFlag); + + iClosedFiles=new(ELeave) CArrayFixSeg(1); + CBaServBackupScheduler::Current()->SetErrorHandler(this); + CleanupStack::Pop(); // CleanupCloseAllFiles + return ECompleteAsync; + } + +/** + * + * Asks the server to signal all clients of getting the lock of their respective files. + * + */ +EXPORT_C void CBaServBackupSession::RestartAll() + { + CBaBackupServer* server=BackupServer(); + if (server->IsClientBusy(iUniqueClientId)) + { + DoRestartAll(); + } + } + +void CBaServBackupSession::DoRestartAll() + { + CBaBackupServer* server=BackupServer(); + server->RestartAll(); + delete iReleasedFiles; + iReleasedFiles=NULL; + if (iClosedFiles) + { + CArrayFix* closedFiles=iClosedFiles; + iClosedFiles=NULL; + server->CompleteClosingFiles(closedFiles); // takes ownership of closedFiles immediately + } + } + +/** +Handle the client's request to close a file. +The request will be ignored if the requesting client the current busy client and the server is +under CloseAll operation. + +@leave KErrServerBusy if the server is busy with the other client, plus other system-wide errors. +*/ +void CBaServBackupSession::CloseFileL() + { + CBaBackupServer* server=BackupServer(); + if (server->IsOtherClientBusy(iUniqueClientId)) + { + User::Leave(KErrServerBusy); + } + + if (! server->IsCloseAllOperationRunning()) + { + MBackupObserver::TFileLockFlags flag= + static_cast(iClientMessage->GetIntL(2)); + TFileName fileName; + GetFileNameL(fileName); + server->SetBusy(iUniqueClientId); + server->CloseFileL(flag,fileName); + } + } + +void CBaServBackupSession::RestartFileL() + { + TFileName fileName; + GetFileNameL(fileName); + BackupServer()->RestartFile(fileName); + } + +/** +Handles the client's request of notification of a file lock change. + +@leave KErrServerBusy if the server is under CloseAll operation, KLeaveWithoutAlert if the requested + file has been registered. Plus other system-wide errors. +*/ +void CBaServBackupSession::NotifyLockChangeL() + { + if(BackupServer()->IsCloseAllOperationRunning()) + { + User::Leave(KErrServerBusy); + } + + TFileName fileName; + GetFileNameL(fileName); + if (iFileLockObservers==NULL) + { + iFileLockObservers=new(ELeave) CDesCArraySeg(1); + } + else + { + TInt pos; + if(iFileLockObservers->Find(fileName,pos)== KErrNone) + { + iClientMessage->PanicClient(KPanic,EReqAlreadyOutstanding); + User::Leave(KLeaveWithoutAlert); + } + } + iFileLockObservers->AppendL(fileName); + BackupServer()->IncrementRegisteredFilesCount(); + } + +LOCAL_C void RemoveFileName(CDesCArray& aArray,const TDesC& aFileName) + { + TInt pos; + if (aArray.Find(aFileName,pos)==KErrNone) + { + aArray.Delete(pos); + } + } + +void CBaServBackupSession::NotifyLockChangeCancelL() + { + TFileName fileName; + GetFileNameL(fileName); + if (iFileLockObservers) + { + RemoveFileName(*iFileLockObservers,fileName); + BackupServer()->DecrementRegisteredFilesCount(); + } + if (iReleasedFiles) + { + RemoveFileName(*iReleasedFiles,fileName); + } + iMessageQueue->RemoveItem(fileName); + } + +void CBaServBackupSession::GetFileNameL(TDes& aFileName) + { + //The verification of this parameter has already been handled + //by the CClientMessage class so we can safely read the value + iClientMessage->ReadL(1,aFileName); + } + + +void CBaServBackupSession::GetBackupOperationEventL(const RMessagePtr2& aPtr) + { + TPckg backupOpAttPkg(iBackupOperationAttributes); + + aPtr.WriteL(0, backupOpAttPkg); + } + +void CBaServBackupSession::BackupOperationEventReadyL() + { + if (iBackupOperationObserverPresent) + { + iBackupOperationMessagePtr = iClientMessage->Message(); + } + else + { + iClientMessage->CompleteRequestL(KErrNone); + } + } + +void CBaServBackupSession::NotifyBackupOperationL() + { + CBaBackupServer* server=BackupServer(); + if (server->CBaBackupServer::IsOtherClientBusy(iUniqueClientId)) + { + User::Leave(KErrServerBusy); + } + TPckg backupOpAttPkg(iBackupOperationAttributes); + + iClientMessage->ReadL(0,backupOpAttPkg); + + const TBool backupOperationRunning = ((iBackupOperationAttributes.iOperation==MBackupOperationObserver::EStart) ? ETrue : EFalse); + server->SetBackupOperationRunning(backupOperationRunning); + server->SetBusy(backupOperationRunning ? iUniqueClientId : 0); + server->SignalBackupOperation(iBackupOperationAttributes); + if (!iBackupOperationMessagePtr.IsNull()) + { + GetBackupOperationEventL(iBackupOperationMessagePtr); + iBackupOperationMessagePtr.Complete(KErrCancel); + } + } + +void CBaServBackupSession::GetBackupOperationStateL() + { + const TBool isRunning = BackupServer()->IsBackupOperationRunning(); + TPckgC pkgObs(isRunning); + + iClientMessage->WriteL(0, pkgObs); + } + +void CBaServBackupSession::SignalBackupOperation(const TBackupOperationAttributes& aBackupOperationAttributes) + { + iBackupOperationAttributes = aBackupOperationAttributes; + if (!iBackupOperationMessagePtr.IsNull()) + { + TRAPD(err,GetBackupOperationEventL(iBackupOperationMessagePtr)); + iBackupOperationMessagePtr.Complete(err); + } + } + +void CBaServBackupSession::StopNotifications() + { + if(!iNotificationPullMsg.IsNull()) + {// complete the registration message + iNotificationPullMsg.Complete(KErrNone); + } + } + +/** +@internalComponent +*/ +CBaServBackupSession::CReRegistrationTimer* CBaServBackupSession::CReRegistrationTimer::NewL(TInt aPriority) + { // static + CBaServBackupSession::CReRegistrationTimer* self=new(ELeave) CBaServBackupSession::CReRegistrationTimer(aPriority); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); // self + CActiveScheduler::Add(self); + return self; + } + +/** +@internalComponent +*/ +TInt CBaServBackupSession::CReRegistrationTimer::RunError(TInt aError) + { + if (aError==KLeaveWithoutAlert) + { + return KErrNone; + } + return aError; + } + +/** +@internalComponent +*/ +CBaServBackupSession::CReRegistrationTimer::CReRegistrationTimer(TInt aPriority) + : CPeriodic(aPriority) + { } + +/** +@internalComponent +*/ +TInt CBaServBackupSession::CReRegistrationTimer::ReRegistrationTimerCallBack(TAny* aPtr) + { // static + TRAP_IGNORE(REINTERPRET_CAST(CBaServBackupSession::CReRegistrationTimer*,aPtr)->HandleReRegistrationTimerCallBack()); + return 0; + } + +/** +@internalComponent +*/ +void CBaServBackupSession::CReRegistrationTimer::HandleReRegistrationTimerCallBack() + { + iBackupServer->IncrementFilesReRegistrationCount(); + + if (IsActive()) + { + Cancel(); + } + } +