webservices/wsconnection/src/senservicedispatcher.cpp
changeset 0 62f9d29f7211
child 14 ab1e518f96da
child 23 a1df79fa35b4
equal deleted inserted replaced
-1:000000000000 0:62f9d29f7211
       
     1 /*
       
     2 * Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:        
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 
       
    22 
       
    23 
       
    24 
       
    25 #include <s32strm.h>
       
    26 #include <f32file.h>
       
    27 
       
    28 #include "senserviceconnectionimpl.h"
       
    29 
       
    30 #include "sendebug.h"                 // internal Utils\inc - logging MACROs
       
    31 #include "senlogger.h"
       
    32 #include "senservicemanagerdefines.h" // internal Core\inc  - IPC enumerations, plus 
       
    33                                       // to include KServerUid3 for SEN.EXE SecureID 
       
    34                                       // (UID3) that can be nicely used as Property 
       
    35                                       // Category UID
       
    36 #include "senservicedispatcher.h"
       
    37 
       
    38 namespace
       
    39     {
       
    40     _LIT(KSenServiceDispatcherThreadName, "SenServiceDispatcher");
       
    41     const TInt KTransactionResetValue = 1000;
       
    42     }
       
    43 
       
    44 
       
    45 CSenServiceDispatcher* CSenServiceDispatcher::NewL( RSenServiceConnection&  aConnection,
       
    46                                                                         TInt aConnectionID)
       
    47     {
       
    48     CSenServiceDispatcher* pNew = NewLC(aConnection,aConnectionID);
       
    49     CleanupStack::Pop();
       
    50     return(pNew) ;
       
    51     }
       
    52 
       
    53 CSenServiceDispatcher* CSenServiceDispatcher::NewLC(RSenServiceConnection&  aConnection,
       
    54                                                                         TInt aConnectionID)
       
    55     {
       
    56     CSenServiceDispatcher* pNew = new (ELeave) CSenServiceDispatcher(aConnection);
       
    57     CleanupStack::PushL(pNew);
       
    58     pNew->ConstructL(aConnectionID);
       
    59     return pNew;
       
    60     }
       
    61 
       
    62 CSenServiceDispatcher::CSenServiceDispatcher(RSenServiceConnection&  aConnection)
       
    63     :iConnection(aConnection)
       
    64     {
       
    65     }
       
    66 
       
    67 void CSenServiceDispatcher::ConstructL(TInt aConnectionID)
       
    68     {
       
    69     iConnectionID = aConnectionID;
       
    70     
       
    71     ipTransactionsMap = new (ELeave) RTransactionsMap(ETrue, ETrue);
       
    72 
       
    73     User::LeaveIfError(iCsMessageQueue.CreateLocal());
       
    74     User::LeaveIfError(iCsSynchronizer.CreateLocal());
       
    75     User::LeaveIfError(iCsTransctnsMap.CreateLocal());
       
    76        
       
    77     
       
    78     RProcess process;
       
    79     TFileName threadName;
       
    80     threadName.Append( KSenServiceDispatcherThreadName);
       
    81     threadName.AppendNum( aConnectionID );
       
    82     threadName.Append( KSenUnderline );
       
    83     threadName.Append( process.Name().Left(32));
       
    84     
       
    85     RAllocator& heap = User::Allocator(); 
       
    86     User::LeaveIfError(iDispatcherThread.Create(threadName,
       
    87         TThreadFunction(DispatcherThreadL), KDefaultStackSize, &heap, this));
       
    88     
       
    89     //Resume the thread so that it should start waiting for any request.
       
    90     iDispatcherThread.Resume();
       
    91     
       
    92     //set iDispatchMessages = TRUE so that it should start dispacthing the messages
       
    93     //when thread gets signaled.
       
    94     iDispatchMessages = ETrue;
       
    95     }
       
    96 
       
    97 CSenServiceDispatcher::~CSenServiceDispatcher()
       
    98     {
       
    99     //Set iDispatchMessages = FALSE to stop dispacthing messages if it already 
       
   100     //dispacthing and also to stop the thread which is waiting for any request.
       
   101     iDispatchMessages = EFalse;
       
   102     if(iCsSynchronizer.IsBlocked())
       
   103         {
       
   104         iCsSynchronizer.Wait();
       
   105         }
       
   106 
       
   107     TRequestStatus requestStatus;
       
   108     iDispatcherThread.Logon(requestStatus);
       
   109     iDispatcherThread.RequestSignal();
       
   110     
       
   111     //Wait until dispatcher thread exits
       
   112     User::WaitForRequest(requestStatus);
       
   113 
       
   114     if(ipTransactionsMap)
       
   115         {
       
   116         ipTransactionsMap->Reset();
       
   117         delete ipTransactionsMap;
       
   118          }
       
   119 
       
   120     iCsMessageQueue.Close();
       
   121     iCsSynchronizer.Close();
       
   122     iCsTransctnsMap.Close();
       
   123 
       
   124     iDispatcherThread.Close();
       
   125     iMessageQueue.Close();
       
   126     }
       
   127 
       
   128 
       
   129 TInt CSenServiceDispatcher::DispatcherThreadL(CSenServiceDispatcher* aThis)
       
   130     {
       
   131     CTrapCleanup* pCleanup = CTrapCleanup::New();
       
   132     CActiveScheduler::Install(NULL); // remove one
       
   133     CActiveScheduler* pScheduler = new (ELeave) CActiveScheduler();
       
   134     CActiveScheduler::Install(pScheduler);
       
   135 
       
   136     RSenDocument::ManualXmlEngineTlsAttachL();
       
   137         
       
   138     TInt leaveCode(KErrNone);
       
   139     TRAP(leaveCode, CSenServiceDispatcher::ExecuteL(aThis));
       
   140 
       
   141     RSenDocument::ManualXmlEngineTlsCleanup();
       
   142 
       
   143     CActiveScheduler::Install(NULL); // uninstall scheduler
       
   144     delete pScheduler;
       
   145     delete pCleanup;
       
   146 
       
   147     return leaveCode;
       
   148     }
       
   149 
       
   150 TInt CSenServiceDispatcher::ExecuteL(CSenServiceDispatcher* aThis)
       
   151     {
       
   152     
       
   153     aThis->OpenDispatcherLogL();
       
   154     
       
   155     TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - Resumed.");
       
   156     
       
   157     for(;;)
       
   158         {
       
   159         User::WaitForAnyRequest();
       
   160 
       
   161         //If iDispatchMessages = FALSE then stop dispacthing messages.
       
   162         //Is called from the destructor and thread will end in cleaner way
       
   163         //by deleting the allocated objects on it's heap.
       
   164         if(!aThis->iDispatchMessages)
       
   165             {
       
   166             TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- Called from owner thread's destructor");
       
   167             break;
       
   168             }
       
   169 
       
   170         //Wait on this critical section until all the messages gets dispacthed or 
       
   171         //iDispatchMessages = FALSE is set from the destructor.
       
   172         aThis->iCsSynchronizer.Wait();
       
   173 
       
   174         TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- Dispacthing messages..");
       
   175 
       
   176         while(aThis->iMessageQueue.Count() && aThis->iDispatchMessages)
       
   177             {
       
   178             TThreadMessage thrMessage = aThis->iMessageQueue[0];
       
   179 
       
   180             //Send message and get the actual transaction id.
       
   181             TInt retVal = 
       
   182             aThis->iConnection.SendMsgAndReceiveTxnId(*(thrMessage.iMessage.iSenConnectionChunk));
       
   183 
       
   184             TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, 
       
   185                             _L("- SendMsgAndReceiveTxnId Returned: (%d)"), retVal));
       
   186 
       
   187 
       
   188             //Check if remove failed, possible in scenario where transaction has
       
   189             //been cancled by client using CancleTransaction(aTransactionID) API,
       
   190             //then cancel the request instaed of adding to the transaction map.
       
   191             if(aThis->RemoveFromQueue(thrMessage.iVrtalTrnsnID))
       
   192                 {
       
   193                 
       
   194                 //If RemoveFromQueue is sucess and also SendMsgAndReceiveTxnId 
       
   195                 //returns actual transaction ID then add to the transaction MAP.    
       
   196                 TInt* pVrtlaTxnId = new (ELeave) TInt(0);
       
   197                 *pVrtlaTxnId = thrMessage.iVrtalTrnsnID;
       
   198                 CleanupStack::PushL(pVrtlaTxnId);
       
   199 
       
   200                 TInt* pActlTxnId = new (ELeave) TInt(0);
       
   201                 if (retVal>0)
       
   202                     {
       
   203                     *pActlTxnId = retVal;
       
   204                     }
       
   205                 
       
   206                 CleanupStack::PushL(pActlTxnId);
       
   207 
       
   208                 //Add the to map as key=virtual transaction ID and 
       
   209                 //value = actual transaction ID.
       
   210                 TInt transRetVal = KErrNone;
       
   211                 transRetVal  = aThis->AddToTheTransMap(pVrtlaTxnId,pActlTxnId);
       
   212 
       
   213                 TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, 
       
   214                                 _L("- AddToTheTransMap Returned: (%d)"), transRetVal));
       
   215 
       
   216                 if (transRetVal == KErrNone)
       
   217                     {
       
   218                     TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, 
       
   219                                     _L("- Virtual Transaction ID: (%d)"), pVrtlaTxnId));
       
   220                     TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, 
       
   221                                     _L("- Actual Transaction ID: (%d)"), pActlTxnId));
       
   222 
       
   223                     CleanupStack::Pop(2);   //pVrtlaTxnId,pActlTxnId
       
   224                     }
       
   225                 else
       
   226                     {
       
   227                     CleanupStack::PopAndDestroy(2); //pVrtlaTxnId,pActlTxnId
       
   228                     }
       
   229                 }
       
   230             else
       
   231                 {
       
   232                     //Mean time if the transaction has been canceled by client
       
   233                     //using CancelTransaction(aTranscationID) and then cancel the
       
   234                     //same using CancelRequest(aVirtualTransactionID)
       
   235                     aThis->iConnection.CancelRequest(thrMessage.iVrtalTrnsnID);
       
   236                 }
       
   237             }   // End of while
       
   238 
       
   239         TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL- All the message has been dispacthed");
       
   240 
       
   241         //Signal the critical section that message dispacthing is over so that it
       
   242         // can wait for the another request.
       
   243         aThis->iCsSynchronizer.Signal();
       
   244 
       
   245         }
       
   246 
       
   247     TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - Closing.");
       
   248     
       
   249     aThis->CloseDispatcherLogL();
       
   250     
       
   251     return KErrNone;
       
   252     }
       
   253     
       
   254 void CSenServiceDispatcher::OpenDispatcherLogL()
       
   255     {
       
   256 #ifdef _SENDEBUG
       
   257     RThread thread;
       
   258     RProcess process;
       
   259     TFileName logFile;
       
   260     logFile.Append( KSenDispactherThreadLog().Left(KSenDispactherThreadLog().Length()-4) ); // exclude ".log" file extension
       
   261     logFile.AppendNum( iConnectionID );
       
   262     logFile.Append( KSenUnderline );
       
   263     logFile.Append( process.Name().Left(32));
       
   264     logFile.Append( KSenUnderline );
       
   265     logFile.Append( thread.Name().Left(20));
       
   266     logFile.Append( KSenDispactherThreadLog().Right(4) ); // postfix with ".log" file extension
       
   267 
       
   268     // Open connection to the file logger server
       
   269     TLSLOG_OPEN( KSenDispatcherLogChannel, KSenDispatcherLogLevel, KSenDispactherThread, logFile );
       
   270     TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "CSenServiceDispatcher::ExecuteL - About to create new dispatcher thread..");
       
   271     TLSLOG_FORMAT((KSenDispatcherLogChannel, KSenDispatcherLogLevel, 
       
   272                                 _L("- Connection ID: (%d)"), iConnectionID));
       
   273 #endif
       
   274     }
       
   275 
       
   276 void CSenServiceDispatcher::CloseDispatcherLogL()
       
   277     {
       
   278     TLSLOG_L(KSenDispatcherLogChannel, KSenDispatcherLogLevel, "Log file closed.");
       
   279     TLSLOG_CLOSE( KSenDispatcherLogChannel );
       
   280     }
       
   281     
       
   282 
       
   283 TInt CSenServiceDispatcher::GetDispactherThreadId()
       
   284     {
       
   285     return iDispatcherThread.Id();
       
   286     }
       
   287 
       
   288 
       
   289 TInt CSenServiceDispatcher::AddToTheQueue(TThreadMessage aThreadMessage)
       
   290     {
       
   291     TInt appendRetVal(KErrNone);
       
   292     //Wait on message queue critical section if it is locked, and then add to 
       
   293     //the queue.
       
   294     //Critical section is required as RemoveFromQueue(aTrasnactionID) is called
       
   295     //from child thread(dispacther thread) also. To avoid crash as iMessageQueue
       
   296     //is used by two threads to append as well as to delete from the queue.
       
   297     iCsMessageQueue.Wait();
       
   298     appendRetVal = iMessageQueue.Append(aThreadMessage);
       
   299     iCsMessageQueue.Signal();
       
   300 
       
   301     if (appendRetVal == KErrNone)
       
   302         {
       
   303         //If dispatcher thread already dispatching the messages then no need to signal the 
       
   304         //thread as it is already working that is dispacthing the messages from queue.
       
   305         if(!iCsSynchronizer.IsBlocked())
       
   306             {
       
   307             //Signal the thread as it free and waiting for the reqest.
       
   308             iDispatcherThread.RequestSignal();
       
   309             }
       
   310         }  
       
   311     return appendRetVal;
       
   312     }
       
   313 TBool CSenServiceDispatcher::RemoveFromQueue(TInt aTransactionID)
       
   314     {
       
   315     //This method gets called from two places 1)main thread from
       
   316     //CancelTransaction(aTransactionID) method and 2)child thread from
       
   317     //ExecuteL method once message has been dispacthed.
       
   318     TBool found = EFalse;
       
   319     iCsMessageQueue.Wait();
       
   320     for(TInt i=0;i<iMessageQueue.Count();i++)
       
   321         {
       
   322         TThreadMessage threadMessage = iMessageQueue[i];
       
   323         if(threadMessage.iVrtalTrnsnID == aTransactionID)
       
   324             {   
       
   325             found = ETrue;
       
   326             iMessageQueue.Remove(i);
       
   327             if ((++iMessagesQueueCounter) >= KTransactionResetValue)
       
   328                 {
       
   329                 iMessageQueue.Compress();
       
   330                 iMessagesQueueCounter = 0;
       
   331                 }
       
   332             }
       
   333         }      
       
   334     iCsMessageQueue.Signal();    
       
   335     return found;
       
   336     }    
       
   337 
       
   338 TMessage CSenServiceDispatcher::GetMessageFromQueue(TInt aTransactionID)
       
   339     {
       
   340     TMessage message;
       
   341     message.iSenAsyncOperation = NULL;
       
   342     message.iSenConnectionChunk = NULL;
       
   343     iCsMessageQueue.Wait();
       
   344     for(TInt i=0;i<iMessageQueue.Count();i++)
       
   345         {
       
   346         TThreadMessage threadMessage = iMessageQueue[i];
       
   347         if(threadMessage.iVrtalTrnsnID == aTransactionID)
       
   348             {
       
   349             message.iSenAsyncOperation = threadMessage.iMessage.iSenAsyncOperation;
       
   350             message.iSenConnectionChunk = threadMessage.iMessage.iSenConnectionChunk;
       
   351             }
       
   352         }      
       
   353     iCsMessageQueue.Signal();    
       
   354     return message;
       
   355     }
       
   356 
       
   357 void CSenServiceDispatcher::ResetQueue()
       
   358     {
       
   359     iCsMessageQueue.Wait();
       
   360     iMessageQueue.Reset();
       
   361     iCsMessageQueue.Signal();     
       
   362     }    
       
   363     
       
   364 RTransactionsMap& CSenServiceDispatcher::TransactionMap()
       
   365     {
       
   366         return *ipTransactionsMap;
       
   367     }
       
   368 
       
   369 TInt CSenServiceDispatcher::AddToTheTransMap(TInt* pVrtlaTxnId,TInt* pActlTxnId)
       
   370     {
       
   371     TInt returnValue = KErrNone;
       
   372     //Wait on transaction map critical section if it is locked, and then add to 
       
   373     //the map.
       
   374     //Critical section is required as RemoveFromTransMap(aTrasnactionID) is called
       
   375     //from main thread also. To avoid crash as ipTransactionsMap
       
   376     //is used by two threads to append as well as to delete from the map.
       
   377     iCsTransctnsMap.Wait();
       
   378     returnValue = TransactionMap().Append(pVrtlaTxnId,pActlTxnId);
       
   379     iCsTransctnsMap.Signal(); 
       
   380     return returnValue;
       
   381     }
       
   382 
       
   383 TInt CSenServiceDispatcher::RemoveFromTransMap(TInt* pVrtlaTxnId)
       
   384     {
       
   385     TInt returnValue = KErrNone;
       
   386     //Is called from the main thread after we recieve the response.
       
   387     returnValue = TransactionMap().Find(*pVrtlaTxnId);
       
   388     if( returnValue != KErrNotFound )
       
   389         {
       
   390         iCsTransctnsMap.Wait();
       
   391         returnValue = TransactionMap().RemoveByKey(*pVrtlaTxnId);
       
   392         iCsTransctnsMap.Signal(); 
       
   393         }
       
   394     return returnValue;
       
   395     }
       
   396 
       
   397 TInt CSenServiceDispatcher::UpdateTransMap(TInt* pVrtlaTxnId,TInt* pActlTxnId)
       
   398     {
       
   399     TInt returnValue = KErrNone;
       
   400     //Is called from the main thread from HandleMessageChildAOL method.
       
   401     //Typically gets called when ESenReAuthAndResendNeeded and ESenResendNeeded
       
   402     //is required.
       
   403     returnValue = TransactionMap().Find(*pVrtlaTxnId);
       
   404     if( returnValue != KErrNotFound )
       
   405         {
       
   406         iCsTransctnsMap.Wait();
       
   407         returnValue = TransactionMap().UpdateValue(pVrtlaTxnId,pActlTxnId);
       
   408         iCsTransctnsMap.Signal(); 
       
   409         }
       
   410     return returnValue;
       
   411     }
       
   412 
       
   413 TInt CSenServiceDispatcher::GetActualTransactionID(TInt* pVrtlaTxnId)
       
   414     {
       
   415     //Getter for getting actual transaction ID
       
   416     TInt indexValue = TransactionMap().Find(*pVrtlaTxnId);
       
   417 
       
   418     if( indexValue != KErrNotFound )
       
   419         {
       
   420             const TInt* pValueAt = TransactionMap().ValueAt(indexValue);
       
   421             return *pValueAt;
       
   422         }
       
   423 
       
   424     return KErrNotFound;
       
   425     }
       
   426 
       
   427 TInt CSenServiceDispatcher::GetVirtualTransactionID(TInt* pActlTxnId)
       
   428     {
       
   429     //Getter for getting virtual transaction ID
       
   430     TInt indexValue = TransactionMap().FindValue(*pActlTxnId);
       
   431 
       
   432     if( indexValue != KErrNotFound )
       
   433         {
       
   434         const TInt* pKeyAt = TransactionMap().KeyAt(indexValue);
       
   435         return *pKeyAt;
       
   436         }
       
   437 
       
   438     return KErrNotFound;
       
   439     }
       
   440 
       
   441 void CSenServiceDispatcher::SetOwnerThreadId(TInt aOwnerThreadID)
       
   442     {
       
   443     iOwnerThreadId = aOwnerThreadID;
       
   444     }
       
   445 
       
   446 
       
   447 CSenUnderTakerWaiter* CSenUnderTakerWaiter::NewL(
       
   448                             CSenServiceConnectionImpl* aSenServiceConnectionImpl,
       
   449                             TInt aDispatcherThreadID )
       
   450     {
       
   451     CSenUnderTakerWaiter* pNew = NewLC(aSenServiceConnectionImpl,aDispatcherThreadID);
       
   452     CleanupStack::Pop();
       
   453     return(pNew) ;
       
   454     }
       
   455     
       
   456 CSenUnderTakerWaiter* CSenUnderTakerWaiter::NewLC(
       
   457                             CSenServiceConnectionImpl* aSenServiceConnectionImpl,
       
   458                             TInt aDispatcherThreadID )
       
   459     {
       
   460     CSenUnderTakerWaiter* pNew = new (ELeave) CSenUnderTakerWaiter();
       
   461     CleanupStack::PushL(pNew);
       
   462     pNew->ConstructL(aSenServiceConnectionImpl,aDispatcherThreadID);
       
   463     return pNew;
       
   464     }
       
   465 
       
   466 CSenUnderTakerWaiter::~CSenUnderTakerWaiter()
       
   467     {
       
   468     iSenServiceConnectionImpl = NULL;
       
   469     Cancel();
       
   470     iUnderTaker.Close();
       
   471     }
       
   472 
       
   473 CSenUnderTakerWaiter::CSenUnderTakerWaiter()
       
   474     :CActive(EPriorityNormal)
       
   475     {
       
   476     CActiveScheduler::Add(this);
       
   477     }
       
   478 
       
   479 void CSenUnderTakerWaiter::ConstructL(CSenServiceConnectionImpl* aSenServiceConnectionImpl,
       
   480                                       TInt aDispatcherThreadID )
       
   481     {
       
   482     iSenServiceConnectionImpl = aSenServiceConnectionImpl;
       
   483     iDispatcherThreadID = aDispatcherThreadID;
       
   484     User::LeaveIfError(iUnderTaker.Create());
       
   485     }
       
   486 
       
   487 void CSenUnderTakerWaiter::StartWaiter()
       
   488     {
       
   489     if(!IsActive())
       
   490         {
       
   491         iUnderTaker.Logon(iStatus,iDyingThreadNumber);
       
   492         SetActive();
       
   493         }
       
   494     }
       
   495 
       
   496 void CSenUnderTakerWaiter::StopWaiter()
       
   497     {
       
   498     Cancel();
       
   499     }
       
   500 
       
   501 void CSenUnderTakerWaiter::RunL()
       
   502     {
       
   503     if(iStatus == KErrDied)
       
   504         {
       
   505         RThread th;
       
   506         th.SetHandle(iDyingThreadNumber);
       
   507         TFullName name = th.FullName();
       
   508         TExitType type = th.ExitType();
       
   509 
       
   510         
       
   511         if(iDispatcherThreadID == th.Id())
       
   512             {
       
   513             //Notifies client that thread is died. Client has to restart the 
       
   514             //connection here.In this case client has to create new SC object.
       
   515             if(type == EExitKill)
       
   516                 {
       
   517                 if(iSenServiceConnectionImpl)
       
   518                     {
       
   519                     iSenServiceConnectionImpl->iErrorNumber = EExitKill;
       
   520                     iSenServiceConnectionImpl->iTxnId = -1;    
       
   521                     iSenServiceConnectionImpl->HandleMessageFromChildAOL(iStatus.Int());
       
   522                     }
       
   523                 }
       
   524             else    // panic
       
   525                 {
       
   526                 TExitCategoryName categ = th.ExitCategory();
       
   527                 if(iSenServiceConnectionImpl)
       
   528                     {
       
   529                     iSenServiceConnectionImpl->iErrorNumber = EExitPanic;
       
   530                     iSenServiceConnectionImpl->iTxnId = -1;
       
   531                     iSenServiceConnectionImpl->HandleMessageFromChildAOL(iStatus.Int());
       
   532                     }
       
   533                 }
       
   534             }
       
   535         th.Close();
       
   536         StartWaiter();
       
   537         }           
       
   538     }
       
   539 
       
   540 void CSenUnderTakerWaiter::DoCancel()
       
   541     {
       
   542     iUnderTaker.LogonCancel();
       
   543     }