sl@0: // Copyright (c) 2002-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 "logservsession.h" sl@0: #include "LogNotify.h" sl@0: #include "LogServServer.h" sl@0: #include "logservpanic.h" sl@0: #include "LogServView.h" sl@0: #include "LogServOperationBase.h" sl@0: #include "LogServBackupInterface.h" sl@0: #include "LogServOperationFactory.h" sl@0: #include "LogServOperationManager.h" sl@0: #include "LogServDatabaseChangeInterface.h" sl@0: #include "LogServDatabaseChangeDefinition.h" sl@0: #include "LogServSqlStrings.h" sl@0: sl@0: // Constants sl@0: const TInt KLogViewListGranuality = 5; sl@0: const TInt KLogServPendingGlobalChangesArrayGranularity = 3; sl@0: sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: // -----> CLogServSession (source) sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CLogServSession::CLogServSession(TLogServSessionId aSessionId, sl@0: MLogServSessionLifetimeObserver& aObserver, sl@0: MLogServBackupInterface& aBackupInterface, sl@0: MLogServTaskInterface& aTaskInterface, sl@0: MLogServOperationManager& aOperationManager, sl@0: MLogServDatabaseChangeInterface& aChangeInterface, sl@0: MLogServDatabaseTransactionInterface& aDatabase) : sl@0: iSessionId(aSessionId), sl@0: iObserver(aObserver), sl@0: iBackupInterface(aBackupInterface), sl@0: iTaskInterface(aTaskInterface), sl@0: iOperationManager(aOperationManager), sl@0: iChangeInterface(aChangeInterface), sl@0: iDatabase(aDatabase), sl@0: iViewList(KLogViewListGranuality), sl@0: iPendingGlobalChanges(KLogServPendingGlobalChangesArrayGranularity) sl@0: { sl@0: iObserver.SLOHandleEvent(Id(), MLogServSessionLifetimeObserver::ELogServSessionEventCreated); sl@0: } sl@0: sl@0: CLogServSession::~CLogServSession() sl@0: { sl@0: LOGTEXT3("CLogServSession::~CLogServSession() - client logging off: %S, %d", &iClientThreadName, iSessionId); sl@0: sl@0: // Set second parameter to not complete the message, otherwise if the client has died a KERN-EXEC 44 will be generated. sl@0: iOperationManager.OMCancel(iSessionId, EFalse); sl@0: sl@0: delete iPackage; sl@0: delete iNotify; sl@0: sl@0: iChangeInterface.DCIRequestChangeNotificationsCancel(*this); sl@0: // sl@0: iViewList.ResetAndDestroy(); sl@0: iViewList.Close(); sl@0: iPendingGlobalChanges.Close(); sl@0: // sl@0: iObserver.SLOHandleEvent(Id(), MLogServSessionLifetimeObserver::ELogServSessionEventDestroyed); sl@0: sl@0: LOGTEXT2("CLogServSession::~CLogServSession() - client dead %d", iSessionId); sl@0: LOGTEXT(""); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServSession::DCOHandleGlobalChangeEventL(const TLogServDatabaseChangeDefinition& aChange) sl@0: { sl@0: if (iExtendedNotificationRequested) sl@0: User::LeaveIfError(iPendingGlobalChanges.Append(aChange)); sl@0: ExtendedNotifyCompleteL(KErrNone); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: void CLogServSession::CreateL() sl@0: { sl@0: iPackage = CLogPackage::NewL(); sl@0: sl@0: // Request change notifications sl@0: iChangeInterface.DCIRequestChangeNotificationsL(*this); sl@0: } sl@0: sl@0: // sl@0: // Handle a client request. sl@0: // sl@0: // Leaving is handled by CLogServ::RunError() which reports the error code to the client sl@0: // Note: operation add themselves to the server active queue in their constructor sl@0: // The server active object owns them and deletes them when necessary sl@0: // So the iffy looking code below won't actually leak memory sl@0: // sl@0: void CLogServSession::ServiceL(const RMessage2& aMessage) sl@0: { sl@0: LOGTEXT3("CLogServSession::ServiceL(%S, %d)", &iClientThreadName, aMessage.Function()); sl@0: sl@0: switch(aMessage.Function()) sl@0: { sl@0: /** sl@0: * Overall operation management sl@0: */ sl@0: case ELogOperationGetResult: sl@0: case ELogOperationCancel: sl@0: case ELogOperationInitiate: sl@0: ServiceOperationFunctionL(aMessage); sl@0: break; sl@0: sl@0: /** sl@0: * Notification related sl@0: */ sl@0: case ELogNotify: sl@0: { sl@0: if (!iNotify) sl@0: { sl@0: iNotify = CLogNotify::NewL(iBackupInterface, iChangeInterface, Server().Priority()); sl@0: sl@0: #ifdef LOGGING_ENABLED sl@0: iNotify->SetClientThreadName(iClientThreadName); sl@0: #endif sl@0: } sl@0: sl@0: if (!iNotify->IsActive()) sl@0: { sl@0: const TTimeIntervalMicroSeconds32 delayTime = reinterpret_cast(aMessage.Ptr0()); sl@0: sl@0: //Validate time value sl@0: if(delayTime.Int() < 0) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: iNotify->Notify(delayTime, aMessage); sl@0: } sl@0: else sl@0: ::PanicClientL(aMessage, ELogAlreadyActive19); sl@0: break; sl@0: } sl@0: case ELogNotifyCancel: sl@0: { sl@0: if (iNotify) sl@0: iNotify->Cancel(); sl@0: aMessage.Complete(KErrCancel); sl@0: break; sl@0: } sl@0: case ELogNotifyExtended: sl@0: { sl@0: if (iExtendedNotificationMessage == RMessage2()) sl@0: { sl@0: iExtendedNotificationMessage = aMessage; sl@0: iExtendedNotificationRequested = ETrue; sl@0: } sl@0: else sl@0: ::PanicClientL(aMessage, ELogExtendedMessageAlreadyActive); sl@0: break; sl@0: } sl@0: case ELogNotifyExtendedCancel: sl@0: { sl@0: if (iExtendedNotificationMessage != RMessage2()) sl@0: ExtendedNotifyCompleteL(KErrCancel); sl@0: // sl@0: iExtendedNotificationRequested = EFalse; sl@0: iPendingGlobalChanges.Reset(); sl@0: iPendingGlobalChanges.GranularCompress(); sl@0: // sl@0: aMessage.Complete(KErrCancel); sl@0: break; sl@0: } sl@0: sl@0: /** sl@0: * View functionality sl@0: */ sl@0: case ELogViewCreate: sl@0: case ELogViewDelete: sl@0: case ELogViewCount: sl@0: case ELogViewOperationInitiate: sl@0: case ELogViewChangeNotificationsRequest: sl@0: case ELogViewChangeNotificationsCancel: sl@0: case ELogViewFetchChanges: sl@0: case ELogViewNotifyLockStatusChange: sl@0: case ELogViewNotifyLockStatusChangeCancel: sl@0: ServiceViewFunctionL(aMessage); sl@0: break; sl@0: sl@0: /** sl@0: * Misc. (debug) functionality sl@0: */ sl@0: #ifdef _DEBUG sl@0: case ELogMakeTransient: sl@0: { sl@0: Server().MakeTransient((TBool)aMessage.Ptr0()); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case ELogIsServerReady: sl@0: { sl@0: const TBool serverReady = (iBackupInterface.BIErrorValueForCurrentState() == KErrNone); sl@0: aMessage.Complete(serverReady); sl@0: break; sl@0: } sl@0: case ELogSetHeapFail: sl@0: { sl@0: User::__DbgSetAllocFail(RHeap::EUser, RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1()); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: #endif// _DEBUG sl@0: /** sl@0: * Unknown operations sl@0: */ sl@0: default: sl@0: ::PanicClientL(aMessage, ELogIllegalFunction); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: If aError is KErrBadDescriptor, then panic the client, else - default error handling. sl@0: KErrBadDescriptor error may be thrown from "message write" operations, if the client supplied a bad sl@0: descriptor to the server. sl@0: */ sl@0: void CLogServSession::ServiceError(const RMessage2& aMessage,TInt aError) sl@0: { sl@0: if(aError == KErrBadDescriptor) sl@0: { sl@0: //The __LOGPANIC_CLIENT() macro cannot be used here because it calls a leaving function. A leaving call sl@0: //from a leaving call will terminate the server. sl@0: aMessage.Panic(KLogServ, ELogBadDescriptor); sl@0: } sl@0: CSession2::ServiceError(aMessage, aError); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CLogServServer& CLogServSession::Server() const sl@0: { sl@0: return *static_cast(const_cast(CSession2::Server())); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: sl@0: CLogServViewBase& CLogServSession::ViewByIdL(TUint32 aViewId) sl@0: { sl@0: const TInt index = ViewPositionById(aViewId); sl@0: User::LeaveIfError(index); sl@0: return *iViewList[index]; sl@0: } sl@0: sl@0: TInt CLogServSession::ViewPositionById(TUint32 aViewId) const sl@0: { sl@0: const TInt count = iViewList.Count(); sl@0: for(TInt i=0; i pData(aClientServerData); sl@0: aMessage.ReadL(0, pData); sl@0: sl@0: //Validate Operation Type sl@0: if((aClientServerData.iOperationType < aMinOperation) || sl@0: (aClientServerData.iOperationType > aMaxOperation)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: sl@0: void CLogServSession::ServiceViewFunctionL(const RMessage2& aMessage) sl@0: { sl@0: switch(aMessage.Function()) sl@0: { sl@0: case ELogViewCreate: sl@0: { sl@0: iViewList.ReserveL(iViewList.Count() + 1); sl@0: // Type is first parameter, view id is second sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: const TLogViewType type = static_cast(aMessage.Int1()); sl@0: sl@0: //Validate type value sl@0: if((type < ELogViewTypeEvent)||(type > ELogViewTypeDuplicate)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: // Ask the factory to create it sl@0: CLogServViewBase* view = LogServFactory::NewViewL(type, id, iDatabase, iBackupInterface, *iPackage, aMessage); sl@0: TInt err = iViewList.Append(view); sl@0: __ASSERT_ALWAYS(err == KErrNone, Panic(ELogArrayReserved)); sl@0: aMessage.Complete(err); sl@0: break; sl@0: } sl@0: case ELogViewDelete: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: TInt indexAndError = ViewPositionById(id); sl@0: if (indexAndError >= 0) sl@0: { sl@0: delete iViewList[indexAndError]; sl@0: iViewList.Remove(indexAndError); sl@0: indexAndError = KErrNone; sl@0: } sl@0: aMessage.Complete(indexAndError); sl@0: break; sl@0: } sl@0: case ELogViewCount: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: const TInt count = view.Count(); sl@0: aMessage.Complete(count); sl@0: break; sl@0: } sl@0: case ELogViewOperationInitiate: sl@0: { sl@0: // We don't allow any operations during a backup sl@0: iBackupInterface.BIValidateStateForDatabaseOperationL(); sl@0: // sl@0: TLogClientServerData clientServerData; sl@0: ReadClientServerDataL(clientServerData,aMessage, sl@0: ELogOperationViewSetup, ELogOperationViewWindowFetch); sl@0: sl@0: // sl@0: const TLogViewId id = static_cast(aMessage.Int1()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: sl@0: // Create operation. Operations are owned by the operation manager (they are added to a queue) sl@0: // when the objects are created, so this does not leak any memory. sl@0: CLogServOperationBase* operation = LogServFactory::NewViewOperationL(clientServerData, iTaskInterface, iOperationManager, aMessage, *iPackage, iSessionId, view); sl@0: (void) operation; sl@0: break; sl@0: } sl@0: case ELogViewChangeNotificationsRequest: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: view.RequestChangeNotifications(aMessage); sl@0: break; sl@0: } sl@0: case ELogViewChangeNotificationsCancel: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: view.RequestChangeNotificationsCancel(); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case ELogViewFetchChanges: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: view.RequestChangesL(aMessage); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: case ELogViewNotifyLockStatusChange: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: view.RequestLockStatusChanges(aMessage); sl@0: break; sl@0: } sl@0: case ELogViewNotifyLockStatusChangeCancel: sl@0: { sl@0: const TLogViewId id = static_cast(aMessage.Int0()); sl@0: CLogServViewBase& view = ViewByIdL(id); sl@0: view.RequestLockStatusChangesCancel(); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CLogServSession::ServiceOperationFunctionL(const RMessage2& aMessage) sl@0: { sl@0: // We don't allow any operations during a backup sl@0: iBackupInterface.BIValidateStateForDatabaseOperationL(); sl@0: // sl@0: TLogClientServerData clientServerData; sl@0: ReadClientServerDataL(clientServerData,aMessage, ELogOperationEventAdd,ELogOperationMaintain); sl@0: // sl@0: const TInt function = aMessage.Function(); sl@0: // sl@0: const TLogOperationId& operationId = clientServerData.iOperationId; sl@0: #ifdef LOGGING_ENABLED sl@0: const TLogOperationType& operationType = clientServerData.iOperationType; sl@0: #endif sl@0: LOGTEXT4("CLogServSession::ServiceOperationFunctionL() - Operation function for client %S: Id: %d, Type: %d", &iClientThreadName, operationId, operationType); sl@0: // sl@0: switch(function) sl@0: { sl@0: case ELogOperationGetResult: sl@0: LOGTEXT("CLogServSession::ServiceOperationFunctionL() - getting result"); sl@0: iOperationManager.OMGetResultL(operationId, iSessionId, aMessage); sl@0: aMessage.Complete(KErrNone); sl@0: break; sl@0: case ELogOperationCancel: sl@0: LOGTEXT("CLogServSession::ServiceOperationFunctionL() - cancelling"); sl@0: iOperationManager.OMCancel(operationId, iSessionId, ETrue); sl@0: aMessage.Complete(KErrCancel); sl@0: break; sl@0: case ELogOperationInitiate: sl@0: LOGTEXT("CLogServSession::ServiceOperationFunctionL() - initiating"); sl@0: // Create operation. Operations are owned by the operation manager (they are added to a queue) sl@0: // when the objects are created, so this does not leak any memory. sl@0: CLogServOperationBase* operation = LogServFactory::NewOperationL(clientServerData, iTaskInterface, iOperationManager, aMessage, *iPackage, iSessionId); sl@0: (void) operation; sl@0: break; sl@0: } sl@0: LOGTEXT("CLogServSession::ServiceOperationFunctionL() - end"); sl@0: } sl@0: sl@0: void CLogServSession::ExtendedNotifyCompleteL(TInt aCompletionCode) sl@0: { sl@0: const TInt count = iPendingGlobalChanges.Count(); sl@0: if (iExtendedNotificationMessage != RMessage2() && (count || aCompletionCode < KErrNone)) sl@0: { sl@0: if (aCompletionCode >= KErrNone && count) sl@0: { sl@0: const TLogServDatabaseChangeDefinition& change = iPendingGlobalChanges[0]; sl@0: // sl@0: const TPckgBuf pContext(change.iChangeType.iUid); sl@0: const TPckg pParam1(change.iChangeParam1); sl@0: const TPckg pParam2(change.iChangeParam2); sl@0: const TPckg pParam3(change.iChangeParam3); sl@0: // sl@0: iExtendedNotificationMessage.WriteL(0, pContext); sl@0: iExtendedNotificationMessage.WriteL(1, pParam1); sl@0: iExtendedNotificationMessage.WriteL(2, pParam2); sl@0: iExtendedNotificationMessage.WriteL(3, pParam3); sl@0: // sl@0: iPendingGlobalChanges.Remove(0); sl@0: } sl@0: // sl@0: iExtendedNotificationMessage.Complete(aCompletionCode); sl@0: } sl@0: }