diff -r 000000000000 -r 62f9d29f7211 webservices/wsconnection/src/senservicedispatcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webservices/wsconnection/src/senservicedispatcher.cpp Thu Jan 07 16:19:19 2010 +0200 @@ -0,0 +1,543 @@ +/* +* Copyright (c) 2002-2005 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 + +#include "senserviceconnectionimpl.h" + +#include "sendebug.h" // internal Utils\inc - logging MACROs +#include "senlogger.h" +#include "senservicemanagerdefines.h" // internal Core\inc - IPC enumerations, plus + // to include KServerUid3 for SEN.EXE SecureID + // (UID3) that can be nicely used as Property + // Category UID +#include "senservicedispatcher.h" + +namespace + { + _LIT(KSenServiceDispatcherThreadName, "SenServiceDispatcher"); + const TInt KTransactionResetValue = 1000; + } + + +CSenServiceDispatcher* CSenServiceDispatcher::NewL( RSenServiceConnection& aConnection, + TInt aConnectionID) + { + CSenServiceDispatcher* pNew = NewLC(aConnection,aConnectionID); + CleanupStack::Pop(); + return(pNew) ; + } + +CSenServiceDispatcher* CSenServiceDispatcher::NewLC(RSenServiceConnection& aConnection, + TInt aConnectionID) + { + CSenServiceDispatcher* pNew = new (ELeave) CSenServiceDispatcher(aConnection); + CleanupStack::PushL(pNew); + pNew->ConstructL(aConnectionID); + return pNew; + } + +CSenServiceDispatcher::CSenServiceDispatcher(RSenServiceConnection& aConnection) + :iConnection(aConnection) + { + } + +void CSenServiceDispatcher::ConstructL(TInt aConnectionID) + { + iConnectionID = aConnectionID; + + ipTransactionsMap = new (ELeave) RTransactionsMap(ETrue, ETrue); + + User::LeaveIfError(iCsMessageQueue.CreateLocal()); + User::LeaveIfError(iCsSynchronizer.CreateLocal()); + User::LeaveIfError(iCsTransctnsMap.CreateLocal()); + + + RProcess process; + TFileName threadName; + threadName.Append( KSenServiceDispatcherThreadName); + threadName.AppendNum( aConnectionID ); + threadName.Append( KSenUnderline ); + threadName.Append( process.Name().Left(32)); + + RAllocator& heap = User::Allocator(); + User::LeaveIfError(iDispatcherThread.Create(threadName, + TThreadFunction(DispatcherThreadL), KDefaultStackSize, &heap, this)); + + //Resume the thread so that it should start waiting for any request. + iDispatcherThread.Resume(); + + //set iDispatchMessages = TRUE so that it should start dispacthing the messages + //when thread gets signaled. + iDispatchMessages = ETrue; + } + +CSenServiceDispatcher::~CSenServiceDispatcher() + { + //Set iDispatchMessages = FALSE to stop dispacthing messages if it already + //dispacthing and also to stop the thread which is waiting for any request. + iDispatchMessages = EFalse; + if(iCsSynchronizer.IsBlocked()) + { + iCsSynchronizer.Wait(); + } + + TRequestStatus requestStatus; + iDispatcherThread.Logon(requestStatus); + iDispatcherThread.RequestSignal(); + + //Wait until dispatcher thread exits + User::WaitForRequest(requestStatus); + + if(ipTransactionsMap) + { + ipTransactionsMap->Reset(); + delete ipTransactionsMap; + } + + iCsMessageQueue.Close(); + iCsSynchronizer.Close(); + iCsTransctnsMap.Close(); + + iDispatcherThread.Close(); + iMessageQueue.Close(); + } + + +TInt CSenServiceDispatcher::DispatcherThreadL(CSenServiceDispatcher* aThis) + { + CTrapCleanup* pCleanup = CTrapCleanup::New(); + CActiveScheduler::Install(NULL); // remove one + CActiveScheduler* pScheduler = new (ELeave) CActiveScheduler(); + CActiveScheduler::Install(pScheduler); + + RSenDocument::ManualXmlEngineTlsAttachL(); + + TInt leaveCode(KErrNone); + TRAP(leaveCode, CSenServiceDispatcher::ExecuteL(aThis)); + + RSenDocument::ManualXmlEngineTlsCleanup(); + + CActiveScheduler::Install(NULL); // uninstall scheduler + delete pScheduler; + delete pCleanup; + + return leaveCode; + } + +TInt CSenServiceDispatcher::ExecuteL(CSenServiceDispatcher* aThis) + { + + aThis->OpenDispatcherLogL(); + + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - Resumed."); + + for(;;) + { + User::WaitForAnyRequest(); + + //If iDispatchMessages = FALSE then stop dispacthing messages. + //Is called from the destructor and thread will end in cleaner way + //by deleting the allocated objects on it's heap. + if(!aThis->iDispatchMessages) + { + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- Called from owner thread's destructor"); + break; + } + + //Wait on this critical section until all the messages gets dispacthed or + //iDispatchMessages = FALSE is set from the destructor. + aThis->iCsSynchronizer.Wait(); + + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- Dispacthing messages.."); + + while(aThis->iMessageQueue.Count() && aThis->iDispatchMessages) + { + TThreadMessage thrMessage = aThis->iMessageQueue[0]; + + //Send message and get the actual transaction id. + TInt retVal = + aThis->iConnection.SendMsgAndReceiveTxnId(*(thrMessage.iMessage.iSenConnectionChunk)); + + TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, + _L("- SendMsgAndReceiveTxnId Returned: (%d)"), retVal)); + + + //Check if remove failed, possible in scenario where transaction has + //been cancled by client using CancleTransaction(aTransactionID) API, + //then cancel the request instaed of adding to the transaction map. + if(aThis->RemoveFromQueue(thrMessage.iVrtalTrnsnID)) + { + + //If RemoveFromQueue is sucess and also SendMsgAndReceiveTxnId + //returns actual transaction ID then add to the transaction MAP. + TInt* pVrtlaTxnId = new (ELeave) TInt(0); + *pVrtlaTxnId = thrMessage.iVrtalTrnsnID; + CleanupStack::PushL(pVrtlaTxnId); + + TInt* pActlTxnId = new (ELeave) TInt(0); + if (retVal>0) + { + *pActlTxnId = retVal; + } + + CleanupStack::PushL(pActlTxnId); + + //Add the to map as key=virtual transaction ID and + //value = actual transaction ID. + TInt transRetVal = KErrNone; + transRetVal = aThis->AddToTheTransMap(pVrtlaTxnId,pActlTxnId); + + TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, + _L("- AddToTheTransMap Returned: (%d)"), transRetVal)); + + if (transRetVal == KErrNone) + { + TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, + _L("- Virtual Transaction ID: (%d)"), pVrtlaTxnId)); + TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, + _L("- Actual Transaction ID: (%d)"), pActlTxnId)); + + CleanupStack::Pop(2); //pVrtlaTxnId,pActlTxnId + } + else + { + CleanupStack::PopAndDestroy(2); //pVrtlaTxnId,pActlTxnId + } + } + else + { + //Mean time if the transaction has been canceled by client + //using CancelTransaction(aTranscationID) and then cancel the + //same using CancelRequest(aVirtualTransactionID) + aThis->iConnection.CancelRequest(thrMessage.iVrtalTrnsnID); + } + } // End of while + + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- All the message has been dispacthed"); + + //Signal the critical section that message dispacthing is over so that it + // can wait for the another request. + aThis->iCsSynchronizer.Signal(); + + } + + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - Closing."); + + aThis->CloseDispatcherLogL(); + + return KErrNone; + } + +void CSenServiceDispatcher::OpenDispatcherLogL() + { +#ifdef _SENDEBUG + RThread thread; + RProcess process; + TFileName logFile; + logFile.Append( KSenDispactherThreadLog().Left(KSenDispactherThreadLog().Length()-4) ); // exclude ".log" file extension + logFile.AppendNum( iConnectionID ); + logFile.Append( KSenUnderline ); + logFile.Append( process.Name().Left(32)); + logFile.Append( KSenUnderline ); + logFile.Append( thread.Name().Left(20)); + logFile.Append( KSenDispactherThreadLog().Right(4) ); // postfix with ".log" file extension + + // Open connection to the file logger server + TLSLOG_OPEN( KSenDispatcherLogChannel, KSenDispatcherLogLevel, KSenDispactherThread, logFile ); + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - About to create new dispatcher thread.."); + TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, + _L("- Connection ID: (%d)"), iConnectionID)); +#endif + } + +void CSenServiceDispatcher::CloseDispatcherLogL() + { + TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "Log file closed."); + TLSLOG_CLOSE( KSenDispatcherLogChannel ); + } + + +TInt CSenServiceDispatcher::GetDispactherThreadId() + { + return iDispatcherThread.Id(); + } + + +TInt CSenServiceDispatcher::AddToTheQueue(TThreadMessage aThreadMessage) + { + TInt appendRetVal(KErrNone); + //Wait on message queue critical section if it is locked, and then add to + //the queue. + //Critical section is required as RemoveFromQueue(aTrasnactionID) is called + //from child thread(dispacther thread) also. To avoid crash as iMessageQueue + //is used by two threads to append as well as to delete from the queue. + iCsMessageQueue.Wait(); + appendRetVal = iMessageQueue.Append(aThreadMessage); + iCsMessageQueue.Signal(); + + if (appendRetVal == KErrNone) + { + //If dispatcher thread already dispatching the messages then no need to signal the + //thread as it is already working that is dispacthing the messages from queue. + if(!iCsSynchronizer.IsBlocked()) + { + //Signal the thread as it free and waiting for the reqest. + iDispatcherThread.RequestSignal(); + } + } + return appendRetVal; + } +TBool CSenServiceDispatcher::RemoveFromQueue(TInt aTransactionID) + { + //This method gets called from two places 1)main thread from + //CancelTransaction(aTransactionID) method and 2)child thread from + //ExecuteL method once message has been dispacthed. + TBool found = EFalse; + iCsMessageQueue.Wait(); + for(TInt i=0;i= KTransactionResetValue) + { + iMessageQueue.Compress(); + iMessagesQueueCounter = 0; + } + } + } + iCsMessageQueue.Signal(); + return found; + } + +TMessage CSenServiceDispatcher::GetMessageFromQueue(TInt aTransactionID) + { + TMessage message; + message.iSenAsyncOperation = NULL; + message.iSenConnectionChunk = NULL; + iCsMessageQueue.Wait(); + for(TInt i=0;iConstructL(aSenServiceConnectionImpl,aDispatcherThreadID); + return pNew; + } + +CSenUnderTakerWaiter::~CSenUnderTakerWaiter() + { + iSenServiceConnectionImpl = NULL; + Cancel(); + iUnderTaker.Close(); + } + +CSenUnderTakerWaiter::CSenUnderTakerWaiter() + :CActive(EPriorityNormal) + { + CActiveScheduler::Add(this); + } + +void CSenUnderTakerWaiter::ConstructL(CSenServiceConnectionImpl* aSenServiceConnectionImpl, + TInt aDispatcherThreadID ) + { + iSenServiceConnectionImpl = aSenServiceConnectionImpl; + iDispatcherThreadID = aDispatcherThreadID; + User::LeaveIfError(iUnderTaker.Create()); + } + +void CSenUnderTakerWaiter::StartWaiter() + { + if(!IsActive()) + { + iUnderTaker.Logon(iStatus,iDyingThreadNumber); + SetActive(); + } + } + +void CSenUnderTakerWaiter::StopWaiter() + { + Cancel(); + } + +void CSenUnderTakerWaiter::RunL() + { + if(iStatus == KErrDied) + { + RThread th; + th.SetHandle(iDyingThreadNumber); + TFullName name = th.FullName(); + TExitType type = th.ExitType(); + + + if(iDispatcherThreadID == th.Id()) + { + //Notifies client that thread is died. Client has to restart the + //connection here.In this case client has to create new SC object. + if(type == EExitKill) + { + if(iSenServiceConnectionImpl) + { + iSenServiceConnectionImpl->iErrorNumber = EExitKill; + iSenServiceConnectionImpl->iTxnId = -1; + iSenServiceConnectionImpl->HandleMessageFromChildAOL(iStatus.Int()); + } + } + else // panic + { + TExitCategoryName categ = th.ExitCategory(); + if(iSenServiceConnectionImpl) + { + iSenServiceConnectionImpl->iErrorNumber = EExitPanic; + iSenServiceConnectionImpl->iTxnId = -1; + iSenServiceConnectionImpl->HandleMessageFromChildAOL(iStatus.Int()); + } + } + } + th.Close(); + StartWaiter(); + } + } + +void CSenUnderTakerWaiter::DoCancel() + { + iUnderTaker.LogonCancel(); + }