Msrp/MsrpServer/src/TStates.cpp
author Petteri Saari <petteri.saari@digia.com>
Thu, 02 Dec 2010 15:23:48 +0200
branchMSRP_FrameWork
changeset 60 7634585a4347
parent 58 cdb720e67852
permissions -rw-r--r--
This release addresses the following: - Multiple concurrent file transfer bug fixes. i.e. one device is concurrently receiving multiple files from multiple devices

/*
* Copyright (c) 2009-2010 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:
* MSRP Implementation
*
*/

#include "TStates.h"
#include "TStateFactory.h"

#include "CMSRPServerSubSession.h"
#include "CMSRPMessageHandler.h"
#include "CMSRPResponse.h"
#include "MMSRPConnection.h"


TStateBase* TStateBase::HandleStateErrorL(CMSRPServerSubSession *aContext)
    {
    // Error handling for invalid events received in a given state.
    if(NULL != aContext->iClientMessage)
        {
        // Complete the client with a error.
        // Set this to iClientReceivedEventData to NULL.
        aContext->CompleteClient(KErrNone);                 
        }

    if(NULL != aContext->iReceivedMsg)
        {
        // !! Handle
        }
    return aContext->StateFactory().getStateL(EIdle);
    }  

TStateBase* TStateBase::processIncommingMessageL(CMSRPServerSubSession *aContext, 
                 CMSRPMessageHandler* incommingMsg)
    {
    MSRPLOG("TStateBase::processIncommingMessage Entered!");
    CMSRPMessageHandler *incommingMsgHandler;
    if(NULL == incommingMsg)
        {
        incommingMsgHandler = aContext->iInCommingMsgQ.DeQueue();
        }
    else
        {
        incommingMsgHandler = incommingMsg;
        }
 
    if(incommingMsgHandler)
        {        
        if(MMSRPIncomingMessage::EMSRPResponse == incommingMsgHandler->MessageType())
            {
            return handlesResponseL(aContext,incommingMsgHandler);                    
            }
        if( MMSRPIncomingMessage::EMSRPReport == incommingMsgHandler->MessageType( ) )
            {
            return handleRequestsL( aContext,incommingMsgHandler );
            }
        else
            {
            return handleRequestsL(aContext,incommingMsgHandler);
            }        
        }
    else
        return NULL; 
    } 

TStateBase* TStateBase::processPendingMessageQL(CMSRPServerSubSession *aContext)
    {
    MSRPLOG("TStateBase::processPendingMessagesL Entered!");
    CMSRPMessageHandler *msgHandler;
     
    msgHandler = aContext->iPendingSendMsgQ.DeQueue();
    msgHandler->SendMessageL(*aContext->iConnection);
    aContext->iOutMsgQ.Queue( *msgHandler );
    return aContext->StateFactory().getStateL( EActive );
    }
    
TStateBase* TStateBase::processCompletedMessageL( CMSRPServerSubSession *aContext )
    {
    MSRPLOG("TStateBase::processCompletedMessageL Entered!");
    CMSRPMessageHandler* msgHandler = aContext->iPendingDataSendCompleteQ.DeQueue();
    
    if ( msgHandler->IsTransmissionTerminated() )
        {
        MSRPLOG("TStateBase::processCompletedMessageL transmission terminated");
        if( aContext->iResponseListner.Check() )
            {
            MSRPLOG("TStateBase::processCompletedMessageL complete with KErrCancel");    
            aContext->iResponseListner.Complete( KErrCancel );
            }
        }
    else
        {
        aContext->sendResultToClientL( msgHandler );      
        }

    delete msgHandler;
    return aContext->StateFactory().getStateL( EWaitForClient );
    }
    
TStateBase* TStateBase::processCompletedIncomingMessageL( CMSRPServerSubSession *aContext )
    {
    MSRPLOG("TStateBase::processCompletedIncomingMessageL Entered!");
    CMSRPMessageHandler* msgHandler = aContext->iPendingDataIncCompleteQ.DeQueue();
    
    if ( msgHandler->IsTransmissionTerminated() )
        {
        MSRPLOG("TStateBase::processCompletedIncomingMessageL transmission terminated");
        if( aContext->iIncommingMessageListner.Check() )
            {
            MSRPLOG("TStateBase::processCompletedIncomingMessageL complete with KErrCancel");    
            aContext->iIncommingMessageListner.Complete( KErrCancel );
            }
        }
    else
        {
        aContext->sendMsgToClientL( msgHandler );      
        delete msgHandler;
        }
        
    return aContext->StateFactory().getStateL( EWaitForClient );
    }
 
TStateBase* TStateBase::processReceiveReportL( CMSRPServerSubSession *aContext )
    {
    MSRPLOG("TStateBase::processReceiveReportL Entered!");
    CMSRPMessageHandler* msgHandler = aContext->iPendingReceiveProgressQ.DeQueue();

    aContext->ReceiveProgressToClientL( msgHandler );
    return aContext->StateFactory().getStateL( EWaitForClient );
    }
    
TStateBase* TStateBase::processSendReportL( CMSRPServerSubSession *aContext )
    {
    MSRPLOG("TStateBase::processSendReportL Entered!");
    CMSRPMessageHandler* msgHandler = aContext->iPendingSendProgressQ.DeQueue();

    aContext->SendProgressToClientL( msgHandler );
    return aContext->StateFactory().getStateL( EWaitForClient );
    }

TStateBase* TStateBase::handlesResponseL(CMSRPServerSubSession *aContext,
                 CMSRPMessageHandler *incommingMsgHandler)
    {
    TStateBase *nextState; 
    MSRPLOG("TStateBase::handlesResponseL Entered!");
    
    // Search the outgoing Queue to find the owner of the owner of this response.
    CMSRPMessageHandler *outgoingMsgHandler = 
                    aContext->iOutMsgQ.getMatch(incommingMsgHandler);
    
    if(NULL == outgoingMsgHandler)
        {
        // No outgoingMsgHandler to match the received response. Stray response.
        MSRPLOG("TStateBase::handlesResponseL() Received Stray Response!!");
        MSRPLOG("TStateBase::handlesResponseL() No Outgoing message handler found");
        nextState = this;
        }
    else
        {
        CleanupStack::PushL( incommingMsgHandler );
        TUint responseCode = outgoingMsgHandler->ConsumeResponseL( *incommingMsgHandler );
         
        if( outgoingMsgHandler->IsMessageComplete() ||
            responseCode != EAllOk ||
            ( outgoingMsgHandler->IsFailureHeaderPartial() &&
              responseCode != EAllOk ) )
            {
            aContext->iConnection->CancelSendingL( outgoingMsgHandler );
            aContext->sendResultToClientL( outgoingMsgHandler );
            aContext->iOutMsgQ.explicitRemove( outgoingMsgHandler );    
            delete outgoingMsgHandler;
            }
        else
            {
            aContext->iConnection->ContinueSendingL( *outgoingMsgHandler );
            }
                 
        CleanupStack::Pop(incommingMsgHandler); 
        nextState = aContext->StateFactory().getStateL(EWaitForClient);     
        }
    
    delete incommingMsgHandler;    
    
    MSRPLOG("TStateBase::handlesResponseL Exit!");
    return nextState;    
    }
 
TStateBase* TStateBase::handleRequestsL(CMSRPServerSubSession *aContext,
                 CMSRPMessageHandler *incommingMsgHandler)
    {
    MSRPLOG("-> TStateBase::handleRequestsL");
    MMSRPIncomingMessage::TMSRPMessageType msgType = incommingMsgHandler->MessageType();
    
    if(MMSRPIncomingMessage::EMSRPMessage == msgType) // SEND request
        {
        MSRPLOG("SEND request received");
        incommingMsgHandler->SendResponseL(aContext, *aContext->iConnection, EAllOk );        
        incommingMsgHandler->SendReportL(aContext, *aContext->iConnection, EAllOk );        
        if( incommingMsgHandler->IsMessageComplete() )
            {
            MSRPLOG("-> TStateBase::handleRequestsL complete");
            aContext->sendMsgToClientL(incommingMsgHandler);
            delete incommingMsgHandler;
            //aContext->iPendingForDeletionQ.Queue(*incommingMsgHandler);
            return aContext->StateFactory().getStateL(EWaitForClient);
            }
        return aContext->StateFactory().getStateL( EActive );
        }
    else if(MMSRPIncomingMessage::EMSRPReport == msgType) // Drop Reports
        {
        aContext->sendMsgToClientL( incommingMsgHandler );
        delete incommingMsgHandler;
        //aContext->iPendingForDeletionQ.Queue(*incommingMsgHandler);
        return aContext->StateFactory().getStateL( EWaitForClient );
        }
    else // It is an unrecognized request eg. AUTH
        {
        MSRPLOG("Unrecognized request received");
        incommingMsgHandler->SendResponseL(aContext, *aContext->iConnection, EUnknownRequestMethod );        
        aContext->iPendingForDeletionQ.Queue(*incommingMsgHandler);
        return aContext->StateFactory().getStateL(EWaitForClient);
        }
    } 
    
TStateBase* TStateBase::handleClientListnerCancelL( CMSRPServerSubSession* aContext, 
        TMSRPFSMEvent aEvent)
    {
    MSRPLOG("-> TStateBase::handleClientListnerCancelL");
    if(aEvent == EMSRPCancelReceivingEvent)
        {
        // let's find the correct listener first
        TBuf8< KMaxLengthOfTransactionIdString > messageId;
        aContext->iClientMessage->ReadL( 0, messageId );
        // going through all incoming instances
        CMSRPMessageHandler* owner = aContext->iCurrentlyReceivingMsgQ.FindElement( messageId );
        if ( owner )
            {
            MSRPLOG2("TStateBase::handleClientListnerCancelL terminating %d", owner );
            owner->TerminateReceiving( aContext, *aContext->iConnection );
            }
        else
            {
            MSRPLOG("TStateBase::handleClientListnerCancelL completing incoming listener"  );
            if( aContext->iIncommingMessageListner.Check() )
                {
                aContext->iIncommingMessageListner.Complete( KErrNone );
                }
            }
        
        // Confirm completion of the Cancel Request.
        aContext->CompleteClient( KErrNone );
        }    
    
    if(aEvent == EMSRPCancelSendRespListeningEvent)
        {
        // Confirm completion of the Cancel Request.
        aContext->CompleteClient( KErrNone );
        
        // Complete the Listner if that is active.
        if(aContext->iResponseListner.Check())
            aContext->iResponseListner.Complete( KErrNone );        
        }
    
    return aContext->StateFactory().getStateL(EWaitForClient);    
    }
    
TStateBase* TStateBase::HandleClientCancelSendingL( CMSRPServerSubSession* aContext )
    {
    MSRPLOG("-> TStateBase::HandleClientCancelSendingL");
    // let's find the correct listener first
    TBuf8< KMaxLengthOfTransactionIdString > messageId;
    aContext->iClientMessage->ReadL( 0, messageId );
    
    // going through all incoming instances
    CMSRPMessageHandler* owner = aContext->iOutMsgQ.FindElement( messageId );
    if ( owner )
        {
        MSRPLOG2("TStateBase::HandleClientCancelSendingL terminating %d", owner );
        owner->TerminateSending( );
        }
    
    // Confirm completion of the Cancel Request.
    aContext->CompleteClient( KErrNone );
    return this;
    }
  
TStateBase* TStateBase::handleConnectionStateChangedL(CMSRPServerSubSession *aContext)
    {
    TStateBase* state = NULL;    
    TInt iConnectionEvent = aContext->iConnection->getConnectionState();
    
    MSRPLOG2("handleConnectionStateChanged::Connection Event %d \n",iConnectionEvent ); 
    
    switch(iConnectionEvent)
        {
        case -1: // Error Scenario    
            {
            // empty queue
            MSRPLOG("TStateBase::handleConnectionStateChangedL, emptying queue " ); 
            while ( aContext->iCurrentlyReceivingMsgQ.DeQueue() );
            state = handleConnectionErrorsL(aContext);
            break;
            }
        
        case 1:
        case 2:
            MSRPLOG("handleConnectionStateChanged::Connection in Progress \n");
            state = this;
            break;
         
        case 3: 
            // Connected.
            MSRPLOG("handleConnectionStateChanged: Connected now." );    
            aContext->informConnectionReadyToClient();
            state = aContext->StateFactory().getStateL(EWaitForClient);            
            break;
        
        case 4:
        case 5:
            MSRPLOG("handleConnectionStateChanged: TimeOut now." ); 
            if(EDownstream == aContext->iConnDirection)
                aContext->iConnectionListner.Complete(-33); // TODO : Change to query the exact erorr code from the connection.
            else
                aContext->iIncommingMessageListner.Complete(-33); // TODO : Change to query the exact erorr code from the connection.    
             
            state = aContext->StateFactory().getStateL(EWaitForClient);            
            break;
        
        case 0:      
            // Not Connected.
            MSRPLOG("handleConnectionStateChanged: TimeOut now." );
            state = this;  
            break;
        }
    
    return state;    
    }

TStateBase* TStateBase::handleConnectionErrorsL(CMSRPServerSubSession *aContext)
    {
    TStateBase* state;
    if(TRUE == aContext->iConnectionListner.Check())
        {
        // Have a connection listner to inform connection errors.
        // This scenario happens where there is a connection error during "Connect"
        
        aContext->iConnectionListner.Complete(KErrCouldNotConnect);  // TODO : Change to query the exact erorr code from the connection.
        aContext->iConnection->ReleaseConnection(*aContext);
        aContext->iConnection = NULL;
        state = aContext->StateFactory().getStateL(EWaitForClient);        
        }
     else
        {
        // If do not have a connection listner.
        // This is a case where a established connection(connect/listen) 
        // is now reporting a Error.
        
        // ConnectionErrors in the current scheme of things will be reported via
        // iIncommingMessageListner.
        
        if(!aContext->iIncommingMessageListner.Check())
            {
            // Case where the subsession is waiting for the Client subsessions 
            // to provide it with listner to reports issues on.
            // Just move to the EIdle state. EIdle is the not connected state.

            // The connection error here will be reported from the TIdle state.
            
            state = aContext->StateFactory().getStateL(EIdle);
            }
        else
            {
            aContext->iIncommingMessageListner.Complete(KErrDisconnected);
            aContext->iConnection->ReleaseConnection(*aContext);
            aContext->iConnection = NULL;
            state = aContext->StateFactory().getStateL(EIdle);
            }
        }
    return state;
    }

TStateBase* TStateBase::handleQueuesL(CMSRPServerSubSession *aContext)
    {
    TStateBase * state;

    if( aContext->QueuesEmpty() )
        {
        state = aContext->StateFactory().getStateL( EActive );
        }
    else
        {   
        CMSRPServerSubSession::TQueueType type = aContext->getQToProcess();
        if ( type == CMSRPServerSubSession::TReceiveProgressQueue )
            {
            state  =  processReceiveReportL( aContext );       
            }
        else if ( type == CMSRPServerSubSession::TSendProgressQueue )
            {
            state  =  processSendReportL( aContext );       
            }
        else if ( type == CMSRPServerSubSession::TCompletedSendQueue )
            {
            state  =  processCompletedMessageL( aContext );       
            }
        else if ( type == CMSRPServerSubSession::TCompletedIncQueue )
            {
            state  =  processCompletedIncomingMessageL( aContext );       
            }
        else if( type == CMSRPServerSubSession::TInCommingMsgQueue )
            {
            state  =  processIncommingMessageL( aContext );
            }
        else
            {
            state  =  processPendingMessageQL( aContext );
            }
        }   

    return state;
    }

TStateBase* TStateBase::handleInCommingMessagesL(CMSRPServerSubSession *aContext)
     {
     CMSRPMessageHandler* incommingMsg = aContext->iReceivedMsg;
     aContext->iReceivedMsg = NULL;
     
     return processIncommingMessageL(aContext, incommingMsg);             
     }

TStateBase* TStateBase::MessageSendCompleteL(CMSRPServerSubSession *aContext)
    {
    // Handle send message complete event.
    if( NULL == aContext->iCurrentMsgHandler)
        {
        MSRPLOG( "TStateBase::MessageSendCompleteL :: iCurrentMsgHandler is NULL \n" );                                     
        return this;
        }
        
    if ( aContext->iCurrentMsgHandler->IsTransmissionTerminated() )
        {
        MSRPLOG("TStateBase::processCompletedMessageL transmission terminated");
        if( aContext->iResponseListner.Check() )
            {
            MSRPLOG("TStateBase::processCompletedMessageL complete with KErrCancel");    
            aContext->iResponseListner.Complete( KErrCancel );
            }
        return aContext->StateFactory().getStateL( EWaitForClient );
        }
        
    if( aContext->iCurrentMsgHandler->IsMessageComplete() )
        {
        // Messages with Failure Report set to "No" will never get a response.        
        aContext->sendResultToClientL( aContext->iCurrentMsgHandler );      
        CMSRPMessageHandler* temp = aContext->iOutMsgQ.getMatch( aContext->iCurrentMsgHandler );
        if ( temp )
            {
            aContext->iOutMsgQ.explicitRemove( aContext->iCurrentMsgHandler );
            }
        delete aContext->iCurrentMsgHandler;
        aContext->iCurrentMsgHandler = NULL;
        return aContext->StateFactory().getStateL( EWaitForClient );
        }
    else
        {
        aContext->iCurrentMsgHandler = NULL;
        // Handle any pending events in Queue.
        return handleQueuesL(aContext);     
        }
    }

TStates TStateIdle::identity()
    {
    return EIdle;
    }
 
TStateBase* TStateIdle::EventL(TMSRPFSMEvent aEvent, CMSRPServerSubSession *aContext)
    {
    // TStateIdle is a state where the subsession is waiting to get connected.     
    // It is the first state which is entered post sub-session creation.
    // Also it is the state that is entered in case there is of a connection error.
    
    // It may be possible that the client could not be informed about the 
    // connection error. Thus any client listner setup events will inform the client about 
    // the current disconnected state.
    
    // Any existing queues of received messages, received client send requests would be 
    // retained as it is. Any events for send messages received from the client 
    // would be queued up.
    
    // An event from the connection layer is considered invalid as the connection is 
    // assumed to be dead. Such events will result in a error report being published.

     MSRPLOG2("Entered TStateIdle Event %d",aEvent);
     TStateBase* state;
     
     switch(aEvent)
         {
         case ELocalMSRPPathEvent:
             state =  handleLocalMSRPPathRequestL(aContext);
             break;     
                 
         case EMSRPConnectEvent:  
             aContext->iConnDirection = EDownstream; 
             state = handleConnectRequestL(aContext);
             break;
             
         case EMSRPListenEvent:        
             aContext->iConnDirection = EUpstream;
             state = handleListenRequestL( aContext );
             break;         

        case EMSRPListenMessagesEvent:
        case EMSRPListenSendResultEvent:
            // A MSRP Connection error code would be more appropriate here.
            aContext->CompleteClient(KErrCouldNotConnect); 
            state = this;
            break;
            
        case EMSRPCancelReceivingEvent:          
        case EMSRPCancelSendRespListeningEvent:
             state = handleClientListnerCancelL(aContext, aEvent);
                 break;

        case EConnectionStateChangedEvent:
             state = handleConnectionStateChangedL(aContext);
             break;
                 
        default:
             // Any such error usually a client/server protocol voilation.
             // A bug to fix.
             MSRPLOG2("TStateIdle::EventL :: Err!! Invalid state to have received %d",aEvent);                     
             state =  HandleStateErrorL(aContext);
             break;
        }
    return state;     
    }
 
TStateBase* TStateIdle::handleLocalMSRPPathRequestL( CMSRPServerSubSession *aContext)
    {
    // The function is reponsible for contructing a  Local MSRP path and returning it to the 
    // client.
    // path:msrp://atlanta.example.com:7654/jshA7weztas;tcp
    
    // !! The current implementation should change to fully construct a MSRP path in the 
    // subsessoin and send back the result as path buffer. Right now this done in the client. !!
    
    MSRPLOG("TStateIdle::HandleLocalPathRequestL()");
     
    TInetAddr localAddr;
    aContext->ConnectionManager().ResolveLocalIPAddressL( localAddr );               
    localAddr.Output(aContext->iLocalHost);          
    
    aContext->iLocalPathMSRPDataPckg().iLocalHost.Copy( aContext->iLocalHost );
    
    TInt reason = aContext->Write(0, aContext->iLocalPathMSRPDataPckg);     
    aContext->CompleteClient(KErrNone);
        
    return this; // No state change.
    }
 
TStateBase* TStateIdle::handleConnectRequestL(CMSRPServerSubSession *aContext)
    {
    
    if(!aContext->iConnectionListner.set(*(aContext->iClientMessage)))
        {
        MSRPLOG("TStateIdle::handleConnectRequestL() iConnectionListner is already setup");
        MSRPLOG("TStateIdle::handleConnectRequestL() Invalid state to setup for ConnectionListner");
        return HandleStateErrorL(aContext);
        }  
    aContext->iClientMessage = NULL; 
    
    aContext->iConnectionListner.ReadL( 0, aContext->iConnectMSRPdataPckg );     
    
    aContext->iRemoteHost = aContext->iConnectMSRPdataPckg().iRemoteHost;
    aContext->iRemotePort = aContext->iConnectMSRPdataPckg().iRemotePort;
    
    aContext->iRemoteSessionID = 
            HBufC8::NewL( aContext->iConnectMSRPdataPckg().iRemoteSessionID.Length());
    
    *(aContext->iRemoteSessionID) = 
             aContext->iConnectMSRPdataPckg().iRemoteSessionID;
    
    // Request for a Connection.
    MMSRPConnection &connection = 
             aContext->ConnectionManager().getConnectionL(
                                  aContext->iRemoteHost
                                 ,aContext->iRemotePort);
    aContext->iConnection = &connection;    
    
    TBool connReady = initializeConnectionL(aContext);
    
    if(!connReady)
        { 
        MSRPLOG("TStateIdle:: Transtion to State EConnecting" );
        return aContext->StateFactory().getStateL(EConnecting);
        }
    else
        {
        MSRPLOG("TStateIdle:: Transtion to State EConnecting" );
        aContext->informConnectionReadyToClient();
        return aContext->StateFactory().getStateL(EWaitForClient);    
        }
    }
 
TStateBase* TStateIdle::handleListenRequestL(CMSRPServerSubSession *aContext)
    {  
    if(!aContext->iIncommingMessageListner.set(*(aContext->iClientMessage)))
        {
        MSRPLOG("TStateWaitForClient::EventL iIncomming listner is already setup");
        MSRPLOG("TStateWaitForClient::EventL Invalid state to setup a listner");
        return HandleStateErrorL(aContext);
        }    
    aContext->iClientMessage = NULL;    
    aContext->iIncommingMessageListner.ReadL( 0, aContext->iListenMSRPdataPckg );
    
    aContext->iRemoteHost = aContext->iListenMSRPdataPckg().iRemoteHost;
    aContext->iRemotePort = aContext->iListenMSRPdataPckg().iRemotePort; 
    aContext->iRemoteSessionID    = 
            HBufC8::NewL( aContext->iListenMSRPdataPckg().iRemoteSessionID.Length());
    
    *(aContext->iRemoteSessionID) = 
             aContext->iListenMSRPdataPckg().iRemoteSessionID;    
    
    // Request for a Connection.
    MMSRPConnection &connection   = 
             aContext->ConnectionManager().getConnectionL(
                                  aContext->iRemoteHost
                                 ,aContext->iRemotePort);
    aContext->iConnection = &connection;    
    
    TBool connReady = initializeConnectionL(aContext);
    
    if(!connReady)
        { 
        MSRPLOG("TStateIdle:: Transtion to State EConnecting" );
        return aContext->StateFactory().getStateL(EConnecting);
        }
    else
        {
        MSRPLOG("TStateIdle:: Transtion to State EConnecting" );
        aContext->informConnectionReadyToClient();
        return aContext->StateFactory().getStateL(EWaitForClient);    
        }
    } 
 
TBool TStateIdle::initializeConnectionL(CMSRPServerSubSession *aContext)
    {
     // Connect or Listen on Connection.
     // Return status based on connection is ready for use or not.
    TBool retVal = FALSE;
     
    if(EDownstream == aContext->iConnDirection)
        {
        if(3 == aContext->iConnection->ConnectL(*aContext))
            retVal = TRUE;              
        }
    else
        {
        if(3 == aContext->iConnection->ListenL(*aContext))
            retVal = TRUE;
        }
     
    return retVal;    
    }
 
TStates TStateConnecting::identity()
    {
    return EConnecting;
    }
  
TStateBase* TStateConnecting::EventL(TMSRPFSMEvent aEvent, CMSRPServerSubSession *aContext)
    {
    MSRPLOG2("Entered TStateConnecting Event %d",aEvent);
    TStateBase *state = this;

    switch(aEvent)
        {
        case EMSRPProcessQueuedRequestsEvent:
        aContext->CompleteClient(KErrNone);              
        break;
        
        case EConnectionStateChangedEvent:
        state = handleConnectionStateChangedL(aContext);
        break;
        
        case EMSRPDataSendMessageEvent:
        aContext->QueueClientSendRequestsL();                         
        break;
                 
        default:                      
        MSRPLOG2("TStateConnecting::EventL :: Err!! Invalid state to have received %d",
                              aEvent);                     
        state = HandleStateErrorL(aContext);            
        break;              
        }

    return state;    
    }

TStates TStateWaitForClient::identity()
    {
    return EWaitForClient;
    }
 
TStateBase* TStateWaitForClient::EventL(TMSRPFSMEvent aEvent, CMSRPServerSubSession *aContext)
    {
      // In the TStateWaitForClient stat the server subsession waits for the client to setup 
      // handlers to receive requests/responses/reports from the MSRP peer.
      // TODO - TStateWaitForClient can be removed. Replace this with a eventQueue implementation.
      
      MSRPLOG2("Entered TStateWaitForClient Event %d",aEvent);
  
      TStateBase *state = NULL;
      switch(aEvent)
          {
          case EMSRPProcessQueuedRequestsEvent:
              aContext->CompleteClient(KErrNone);              
              break;
          
          case EMSRPListenMessagesEvent:
              if(!aContext->iIncommingMessageListner.set(*(aContext->iClientMessage)))
                  {
                  MSRPLOG("TStateWaitForClient::EventL iIncomming listner is already setup");
                  MSRPLOG2("TStateWaitForClient::EventL Invalid state to have received %d", aEvent);                
                  }              
              aContext->iClientMessage = NULL;
              break;
              
          case EMSRPListenSendResultEvent:
              if(!aContext->iResponseListner.set(*(aContext->iClientMessage)))
                  {
                  MSRPLOG("TStateWaitForClient::EventL SendResult Listner is already setup");
                  MSRPLOG2("TStateWaitForClient::EventL Invalid state to have received %d", aEvent);                
                  }              
              aContext->iClientMessage = NULL;
              break;
  
          case EMSRPIncomingMessageReceivedEvent:
              // Queue any thing that comes.
              aContext->iInCommingMsgQ.Queue(*aContext->iReceivedMsg);                  
              break;  
              
          case EMSRPDataSendCompleteEvent:
          case EMSRPDataCancelledEvent:
              {
              MSRPLOG("TStateWaitForClient::EventL EMSRPDataCancelledEvent");

              if( aContext->iCurrentMsgHandler->IsMessageComplete() )
                  {
                  MSRPLOG("TStateWaitForClient::EventL moving to pending data");
                  aContext->iOutMsgQ.explicitRemove( aContext->iCurrentMsgHandler );    
                  aContext->iPendingDataSendCompleteQ.Queue( *aContext->iCurrentMsgHandler );
                  }
              aContext->iCurrentMsgHandler = NULL;
              break;
              }
              
          case EMSRPResponseSendCompleteEvent:
              {
              if( aContext->iReceivedResp->IsMessageComplete() )
                  {
                  aContext->iPendingDataIncCompleteQ.Queue( *aContext->iReceivedResp );
                  }
              aContext->iReceivedResp = NULL;
              break;
              }

          case EMSRPReportSendCompleteEvent:
              {
              if( aContext->iReceivedReport->IsMessageComplete() )
                  {
                  aContext->iPendingDataIncCompleteQ.Queue( *aContext->iReceivedReport );
                  }
              aContext->iReceivedReport = NULL;
              break;
              }

          case EMSRPDataSendMessageEvent:
              aContext->QueueClientSendRequestsL();                         
              break;
                              
          case EMSRPCancelReceivingEvent:          
          case EMSRPCancelSendRespListeningEvent:
               handleClientListnerCancelL(aContext, aEvent);
               break;
               
          case EMSRPDataSendMessageCancelEvent:
              {
              HandleClientCancelSendingL( aContext );
              break;
              }

          case EConnectionStateChangedEvent:
              state = handleConnectionStateChangedL(aContext);
              break;
              
          case EMSRPSendProgressEvent:
              {
              state = aContext->StateFactory().getStateL( EWaitForClient );
              // queue only if this msghandler is not already in the queue
              if ( aContext->iPendingSendProgressQ.FindElement( aContext->iSendProgressMsg ) == NULL )
                  {
                  aContext->iPendingSendProgressQ.Queue( *aContext->iSendProgressMsg );                  
                  }
              break;
              }
          case EMSRPReceiveProgressEvent:
              {
              // Queue any thing that comes.
              state = aContext->StateFactory().getStateL( EWaitForClient );
              // queue only if this msghandler is not already in the queue
              if ( aContext->iPendingReceiveProgressQ.FindElement( aContext->iReceiveProgressMsg ) == NULL )
                  {
                  aContext->iPendingReceiveProgressQ.Queue( *aContext->iReceiveProgressMsg );                  
                  }
              break;
              }
                  
          default:          
              // Any such error usually a client/server protocol voilation or connection/subsession 
              // protocol voilation. A bug to fix!!
              MSRPLOG2("TStateWaitForClient::EventL :: Err!! Invalid state was received %d",aEvent);                     
              state = HandleStateErrorL(aContext);
              break;              
          };

      if(NULL == state)
        {
          // State not set.
          if( !aContext->listnerSetupComplete() )
              {
              state = this;
              }
          else
              {
              state = handleQueuesL(aContext);
              }
        }
        return state;    
    }
    
TStates TStateActive::identity()
    {
    return EActive;
    } 
 
TStateBase* TStateActive::EventL(TMSRPFSMEvent aEvent, CMSRPServerSubSession *aContext)
    {
     // TStateActive is entered when the subsession is in a connected state and  client setup 
     // is done.
 
     MSRPLOG2("Entered TStateActive Event %d",aEvent);
 
     TStateBase *state;
     switch(aEvent)
         {
         case EMSRPDataSendMessageEvent:
              state =  handleSendDataL(aContext);
              break; 
 
         case EMSRPIncomingMessageReceivedEvent:
              state =  handleInCommingMessagesL(aContext);
              break; 
 
         case EConnectionStateChangedEvent:
              state = handleConnectionStateChangedL(aContext);
              break;
  
         case EMSRPCancelReceivingEvent:          
         case EMSRPCancelSendRespListeningEvent:
              state =  handleClientListnerCancelL(aContext, aEvent);
              break;   
         
         case EMSRPDataSendMessageCancelEvent:
             {
             state = HandleClientCancelSendingL( aContext );
             break;
             }
              
         case EMSRPDataCancelledEvent:
         case EMSRPDataSendCompleteEvent:
             state = MessageSendCompleteL(aContext);
             break;
             
         case EMSRPResponseSendCompleteEvent:
             {
             state = handleResponseSentL(aContext);  
             break;
             }

         case EMSRPReportSendCompleteEvent:
             {
             state = handleReportSentL( aContext );  
             break;
             }

         case EMSRPReceiveProgressEvent:
             {
             aContext->ReceiveProgressToClientL( aContext->iReceiveProgressMsg );
             state = aContext->StateFactory().getStateL( EWaitForClient );
             break;
             }

         case EMSRPSendProgressEvent:
             {
             aContext->SendProgressToClientL( aContext->iSendProgressMsg );
             state = aContext->StateFactory().getStateL( EWaitForClient );
             break;
             }

         default: 
             // Any such error usually a client/server protocol voilation or connection/subsession 
             // protocol voilation. A bug to fix!!
             
             MSRPLOG2("TStateActive::EventL :: Err!! Invalid state to have received %d",aEvent);                     
             state =  HandleStateErrorL(aContext); 
             break; 
         }

     return state;     
    } 
 
TStateBase* TStateActive::handleSendDataL(CMSRPServerSubSession *aContext)
    {
    MSRPLOG("TStateActive::handleSendDataL()");     
    
    aContext->ReadSendDataPckgL(); 
    
    CMSRPMessageHandler *msgHandler 
     = CMSRPMessageHandler::NewL(aContext,
         aContext->iSendMSRPdataPckg().iExtMessageBuffer); 
    
    msgHandler->SendMessageL( *aContext->iConnection );   
    aContext->iOutMsgQ.Queue( *msgHandler );
    aContext->CompleteClient( KErrNone );
    
    return aContext->StateFactory().getStateL( EActive );
    }
   
TStateBase* TStateActive::handleResponseSentL( CMSRPServerSubSession* aContext )
    {
    MSRPLOG("-> TStateActive::handleResponseSentL");
    if( aContext->iReceivedResp->IsMessageComplete() )
        {
        if ( !aContext->iReceivedResp->SendReportL(aContext, *aContext->iConnection, EAllOk ) )
            {
            if ( aContext->iReceivedResp->IsTransmissionTerminated() )
                {
                if( aContext->iIncommingMessageListner.Check() )
                    {
                    aContext->iIncommingMessageListner.Complete( KErrCancel );
                    }
                }
            else
                {
                aContext->sendMsgToClientL( aContext->iReceivedResp );
                }
            return aContext->StateFactory().getStateL(EWaitForClient);
            }
        else
            {
            aContext->iReceivedResp = NULL;
            }
        }
    else
        {
        aContext->iReceivedResp->ResponseHandled();   
        aContext->iReceivedResp = NULL;
        }
    MSRPLOG("<- TStateBase::handleRequestsL");
    return aContext->StateFactory().getStateL( EActive );
    }

TStateBase* TStateActive::handleReportSentL( CMSRPServerSubSession* aContext)
    {
    MSRPLOG("-> TStateActive::handleReportSentL");
    aContext->sendReportToClientL( aContext->iReceivedReport );
    aContext->iPendingDataIncCompleteQ.Queue( *aContext->iReceivedReport );
    aContext->iReceivedReport = NULL;
    return aContext->StateFactory().getStateL( EWaitForClient );
    }

TStates TStateError::identity()
    {
    return EError;
    } 

TStateBase* TStateError::EventL(TMSRPFSMEvent aEvent, CMSRPServerSubSession *aContext)
    {
    // Error State is entered when we receive an Error Response from the opposite
    // end point to which we sent a SEND request. When this state is entered the client
    // is expected to close the session without trying to send further messages.
    
    MSRPLOG2("Entered TStateError Event %d", aEvent);
    TStateBase *state;
    
    switch(aEvent)
        {
        case EMSRPListenMessagesEvent:
            aContext->CompleteClient(KErrCouldNotConnect); 
            state = this;
            break;
            
        case EMSRPListenSendResultEvent:
            aContext->CompleteClient( KErrGeneral ); 
            state = this;
            break;
            
        case EMSRPDataSendMessageEvent:
            aContext->CompleteClient(KErrNone); 
            state = this;
            break;
            
        case EMSRPCancelReceivingEvent:
        case EMSRPCancelSendRespListeningEvent:
            state = handleClientListnerCancelL(aContext, aEvent);
            break;
            
        case EMSRPIncomingMessageReceivedEvent:            
            aContext->iInCommingMsgQ.Queue(*aContext->iReceivedMsg);
            state = this;           
            break;
        
        case EConnectionStateChangedEvent:
            state = handleConnectionStateChangedL(aContext);
            break;
            
        default:
            MSRPLOG2("TStateError::EventL :: Err!! Invalid state to have received %d",aEvent);                     
            state =  HandleStateErrorL(aContext);            
            break;                  
        }    
    return state;   
    }