Msrp/MsrpServer/src/TStates.cpp
author Petteri Saari <petteri.saari@digia.com>
Thu, 25 Nov 2010 13:59:42 +0200
branchMSRP_FrameWork
changeset 58 cdb720e67852
parent 25 505ad3f0ce5c
child 60 7634585a4347
permissions -rw-r--r--
This release addresses the following issues: 1. The crash bug fix when receiving file 2. Now the sending is based on MSRP messages, there is no longer file receiving or sending. Client sends data as MSRP was designed. 3. Soma MSRP stack was created so that the client told the correct session-id, Symbian stack generated it by itself. This is not allowed, it was changed so that clients tell the session-id (same as used in SIP INVITE). 4. Unnecessary division of data to chunks removed when there is no need to interrupt sending. The message is sent in as few chunks as possible. 5. Stack can now receive files and chunks with ?unlimited? size. Old stack wrote the incoming data to memory and did not utilize disk space until the end of chunk was reached (large chunks from another client crashed it). 6. Now when writing the incoming data to file, it will take into account the byte-range header values. So, this complies with the RFC4975 requirements that stack must be able to handle chunks that come in any sequence. 7. Some buffering changes to outgoing/incoming data. 8. The outgoing data is now checked that it does not contain the created transaction-id before sending the data. 9. MSRP success reports are now implemented and tested against servers. 10. Progress report system fixed so progress is now visible on client (all the way to 100%). 11. Message Cancel receiving / Cancel sending now corrected and made to work as rfc4975 requires. (termination from sender and error code from receiver when cancelling). 12. Bug correction related to messages received not belonging to any session, old stack implementation did send error response, but after response was written it did give the buffer to client anyway. Now corrected.

/*
* 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
            {
            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         
            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;   
    }