Msrp/MsrpServer/src/CMSRPServerSubSession.cpp
author shivsood
Sat, 12 Jun 2010 14:30:11 +0530
branchMSRP_FrameWork
changeset 25 505ad3f0ce5c
child 58 cdb720e67852
permissions -rw-r--r--
MSRP Chat and File Sharing FrameWork - Initial Contribution from Nokia. MSRP Implementation as per RFC 4975 and RCS specifications that supports 1. Multiple one to one chat data sessions as per RCS/RFC 4975 specifications. 2. Multiple file Sharing sessions as per RCS. 3. Data Chunking requirements as per 4975. 3. MSRP Connection sharing requirements as per RFC 4975

/*
* 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 "MSRPCommon.h"
#include "MSRPServerCommon.h"
#include "CMSRPServerSubSession.h"
#include "MMSRPConnectionManager.h"
#include "CMSRPServerSession.h"
#include "CMSRPMessageBase.h"
#include "MMSRPConnection.h"
#include "CMSRPMessageHandler.h"
#include "CMSRPResponse.h"
#include "s32mem.h"
#include "CMSRPMessage.h"
#include "TStateFactory.h"
#include "TStates.h"
#include "CMsrpToPathHeader.h"
#include "CMSRPFromPathHeader.h"


CRMessageContainer::CRMessageContainer()
    {
    iStatus = FALSE;
    }

CRMessageContainer::~CRMessageContainer()
    {
    
    }

TInt CRMessageContainer::Write(TInt aParam,const TDesC8& aDes,TInt aOffset) const
    {
    // Write the data, change status and complete the RMessage.
    return iMsg.Write(aParam, aDes, aOffset);        
    }

void CRMessageContainer:: ReadL(TInt aParam,TDes8& aDes,TInt aOffset) const
    {
    // Write the data, change status and complete the RMessage.
    return iMsg.ReadL(aParam, aDes, aOffset);        
    }

void CRMessageContainer::Complete(TInt aReason)
    {
    iStatus = FALSE;
    iMsg.Complete(aReason);    
    }

TBool CRMessageContainer::Check()
    {
    return iStatus;
    }

TBool CRMessageContainer::set(const RMessage2& aMessage)
    {    
    if(FALSE == iStatus)
        {
        iMsg = aMessage; // Exclicit copy.
        iStatus = TRUE;
        return iStatus;        
        }
    else
        {
        MSRPLOG("CRMessageContainer::set Error!! Container already full");
        return FALSE;
        }    
    }

CMSRPServerSubSession* CMSRPServerSubSession::NewL( CMSRPServerSession& aServerSession, CStateFactory& aStateFactory )
    {
    CMSRPServerSubSession* self = 
        CMSRPServerSubSession::NewLC( aServerSession, aStateFactory );

    CleanupStack::Pop(self);
    return self;    
    }    


CMSRPServerSubSession* CMSRPServerSubSession::NewLC( CMSRPServerSession& aServerSession,CStateFactory& aStateFactory )
    {
    
    CMSRPServerSubSession* self =
                            new (ELeave) CMSRPServerSubSession( aServerSession, aStateFactory );
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }


CMSRPServerSubSession::CMSRPServerSubSession( CMSRPServerSession& aServerSession,CStateFactory& aStateFactory )
                         : iServerSession(aServerSession), iStateFactory(aStateFactory)
                                              
    {
    }


CMSRPServerSubSession::~CMSRPServerSubSession()
    {
    MSRPLOG("CMSRPServerSubSession::~CMSRPServerSubSession Entered");
    
    iState = NULL;         

    iOutMsgQ.Destroy();
    iInCommingMsgQ.Destroy();
    iPendingSendMsgQ.Destroy();
    iPendingForDeletionQ.Destroy();

    QueueLog();

    if(iCurrentMsgHandler)
        {
        delete iCurrentMsgHandler;
        iCurrentMsgHandler = NULL;
        }
    
    if(iConnection)
        {
        iConnection->ReleaseConnection(*this);
        iConnection = NULL;
        }

    if(iLocalSessionID)
        {
        delete iLocalSessionID;
        iLocalSessionID = NULL;
        }

    if( iRemoteSessionID )
        {
        delete iRemoteSessionID;
        iRemoteSessionID = NULL;
        }

    if( iReceivedResp )
        {
        delete iReceivedResp;
        iReceivedResp = NULL;
        }
    if( iReceiveFileMsgHdler )
        {
        delete iReceiveFileMsgHdler;
        iReceiveFileMsgHdler = NULL;
        }

    MSRPLOG("CMSRPServerSubSession::~CMSRPServerSubSession Exit");
    }


void CMSRPServerSubSession::ConstructL( )
    {
    // Not the place where this should be done!!
    MSRPLOG("CMSRPServerSubSession::ConstructL");  
    iState = iStateFactory.getStateL( EIdle );
    iLocalSessionID = CreateSubSessionIDL();    
    }


HBufC8* CMSRPServerSubSession::CreateSubSessionIDL( )
    {
    MSRPLOG("CMSRPServerSubSession::CreateSubSessionIDL");
    HBufC8 *sessID = HBufC8::NewLC(KMSRPSessIdLength);
    TInt64 randSeed(Math::Random());
    TInt rand;
          
    /* Append Random bits using two Random strings */
    rand = Math::Rand(randSeed);
    (sessID->Des()).AppendNumFixedWidth(rand,EHex,KMSRPSessIdLength/2);
    rand = Math::Rand(randSeed);
    (sessID->Des()).AppendNumFixedWidth(rand,EHex,KMSRPSessIdLength/2);
        
    CleanupStack::Pop(1);// sessID
    return sessID;
    }


TBool CMSRPServerSubSession::ProcessEventL( TMSRPFSMEvent aEvent)
    {
    // Call the relevant state. Setup Traps for graceful error propagation to the client.
    MSRPLOG("CMSRPServerSubSession::ProcessEventL() Entered");

    QueueLog();    
            
    iState = iState->EventL(aEvent, this); 
    
    MSRPLOG("CMSRPServerSubSession::ProcessEventL() Exit ");
    return TRUE;
    }


TBool CMSRPServerSubSession::ServiceL( const RMessage2& aMessage )
    {
    MSRPLOG("CMSRPServerSubSession::ServiceL()");

    // Process Client Server functions to FSM Events.

    // Getting rid of the switch for translation.
    TMSRPFSMEvent event = (TMSRPFSMEvent) (aMessage.Function() - 2); 

    // Store the incomming aMessage to form the context of the state machine.
    iClientMessage = &aMessage;        
        
    return ProcessEventL(event);    
    }


MMSRPConnectionManager& CMSRPServerSubSession::ConnectionManager( )
    {
    return iServerSession.ConnectionManager();
    }


// Implementation of interfaces from MMSRPConnectionObserver.
void CMSRPServerSubSession::ConnectionStateL( TInt /*aNewState*/, TInt /*aStatus*/ )
    {    
    ProcessEventL(EConnectionStateChangedEvent);
    }


TBool CMSRPServerSubSession::MessageReceivedL( CMSRPMessageHandler* aMsg )
    {
    MSRPLOG("CMSRPServerSubSession::MessageReceivedL - New message received");
    TBool retVal = FALSE;
    if(checkMessageForSelfL(aMsg))
        {           
        iReceivedMsg = aMsg;
        ProcessEventL(EMSRPIncomingMessageReceivedEvent);
        retVal = TRUE;
        }

    return retVal;    
    }


void CMSRPServerSubSession::UnclaimedMessageL( CMSRPMessageHandler* aMsg )
    {
    MSRPLOG("CMSRPServerSubSession::UnclaimedMessage - Unclaimed message received!!");
    
    if( (aMsg->MessageType() == MMSRPIncomingMessage::EMSRPMessage ||
            aMsg->MessageType() == MMSRPIncomingMessage::EMSRPNotDefined )
            && EFalse == matchSessionIDL(aMsg->GetIncomingMessage()->ToPathHeader()))
        {        
        TBool sendToClient = aMsg->SendResponseL(this, *iConnection, 
                CMSRPResponse::ESessionDoesNotExist);          
        iPendingForDeletionQ.Queue(*aMsg);
        }
    else
        {
        delete aMsg; 
        }    
    }


// Implementation of interface from MMSRPMsgObserver.

void CMSRPServerSubSession::MessageSendCompleteL()
    {
    // Called when a message is fully sent out.
    ProcessEventL(EMSRPDataSendCompleteEvent);
    }

void CMSRPServerSubSession::MessageResponseSendCompleteL(CMSRPMessageHandler& aMsg)
    {
    // Called when a message is fully sent out.
    // Common event handling.
    iReceivedResp = &aMsg;
    if(iFileShare)
        {        
        ProcessEventL(EMSRPResponseSendCompleteEvent);
        }
        if(iPendingForDeletionQ.explicitRemove(iReceivedResp))
            {
            delete iReceivedResp;
            iReceivedResp = NULL;
            }
        
    }


void CMSRPServerSubSession::MessageSendProgressL(TInt aBytesSent, TInt aTotalBytes)
    {
    iBytesTransferred = aBytesSent;
    iTotalBytes = aTotalBytes;
    ProcessEventL(EMSRPSendProgressEvent);    
    }


void CMSRPServerSubSession::MessageReceiveProgressL(TInt aBytesRecvd, TInt aTotalBytes)
    {
    iBytesTransferred = aBytesRecvd;
    iTotalBytes = aTotalBytes;
    ProcessEventL(EMSRPReceiveProgressEvent);    
    }


void CMSRPServerSubSession::WriterError()
    {
    
    }


// Utility Stuff - Common functions used often by States.
void CMSRPServerSubSession::CompleteClient(TInt aReason)
    {
    iClientMessage->Complete(aReason);
    iClientMessage = NULL;
    }

TInt CMSRPServerSubSession::Write(TInt aParam,const TDesC8& aDes)
    {
    TInt retVal = iClientMessage->Write(aParam, aDes);  
    return retVal; 
    }


TBool CMSRPServerSubSession::QueueClientSendRequestsL()
    {
    // Generic function to Queue the client send requests message. Would be used by 
    // many states to add to the pending client requests queue.
    MSRPLOG("CMSRPServerSubSession::QueueClientSendRequestsL");
        
    const RMessage2* aMessage = iClientMessage;
    iClientMessage = NULL;

    aMessage->ReadL( 0, iSendMSRPdataPckg);

    CMSRPMessageHandler *aMessageHandler 
        = CMSRPMessageHandler::NewL(this,
            iSendMSRPdataPckg().iExtMessageBuffer); 
    
    iPendingSendMsgQ.Queue(*aMessageHandler);    
    aMessage->Complete( KErrNone );        
        return TRUE;            
    }


void CMSRPServerSubSession::NotifyFileReceiveResultToClientL(CMSRPMessageHandler */*msgHandler*/)
    {
    //TODO
    MSRPLOG("CMSRPServerSubSession::NotifyFileReceiveResultToClientL enter");
    iSendResultListenMSRPDataPckg().iStatus = 200;
    iSendResultListenMSRPDataPckg().iIsProgress = FALSE;
    iResponseListner.Write(0,iSendResultListenMSRPDataPckg);
    iResponseListner.Complete( KErrNone );
    MSRPLOG("CMSRPServerSubSession::NotifyFileReceiveResultToClientL exit");
    }


void CMSRPServerSubSession::NotifyFileSendResultToClientL(CMSRPMessageHandler */*msgHandler*/)
    {
    //TODO
    MSRPLOG("CMSRPServerSubSession::NotifyFileSendResultToClientL enter");
    iSendResultListenMSRPDataPckg().iStatus = 200;
    iSendResultListenMSRPDataPckg().iIsProgress = FALSE;
    iResponseListner.Write(0,iSendResultListenMSRPDataPckg);
    iResponseListner.Complete( KErrNone );
    MSRPLOG("CMSRPServerSubSession::NotifyFileSendResultToClientL exit");
    }


TBool CMSRPServerSubSession::SendProgressToClientL(CMSRPMessageHandler */*msgHandler*/)
    {
    MSRPLOG("CMSRPServerSubSession::SendProgressToClientL enter");
    iSendResultListenMSRPDataPckg().iStatus    = KErrNone;
    iSendResultListenMSRPDataPckg().iIsProgress = TRUE;
    iSendResultListenMSRPDataPckg().iBytesSent = iBytesTransferred;
    iSendResultListenMSRPDataPckg().iTotalBytes = iTotalBytes;
    
    iResponseListner.Write(0,iSendResultListenMSRPDataPckg);
    iResponseListner.Complete( KErrNone );

    MSRPLOG("CMSRPServerSubSession::SendProgressToClientL exit");
    return TRUE;
    }


TBool CMSRPServerSubSession::ReceiveProgressToClientL(CMSRPMessageHandler */*msgHandler*/)
    {
    MSRPLOG("CMSRPServerSubSession::ReceiveProgressToClientL enter");
    iListenMSRPdataPckg().iStatus    = KErrNone;
    iListenMSRPdataPckg().iIsProgress = TRUE;
    iListenMSRPdataPckg().iBytesRecvd = iBytesTransferred;
    iListenMSRPdataPckg().iTotalBytes = iTotalBytes;
    
    iIncommingMessageListner.Write(0,iListenMSRPdataPckg);
    iIncommingMessageListner.Complete( KErrNone );
    MSRPLOG("CMSRPServerSubSession::ReceiveProgressToClientL exit");
    return TRUE;
    }


TBool CMSRPServerSubSession::sendResultToClientL(CMSRPMessageHandler *msgHandler)
    {
    MSRPLOG("CMSRPServerSubSession::sendResultToClientL");
    HBufC8* messageId = NULL;
    TUint i=0;

    // Allocates memory.
    TBool error = msgHandler->GetSendResultL( i, messageId );            

    iSendResultListenMSRPDataPckg().iIsProgress = FALSE;
    iSendResultListenMSRPDataPckg().iMessageId = *messageId;
    iSendResultListenMSRPDataPckg().iStatus    = i;
    iResponseListner.Write(0,iSendResultListenMSRPDataPckg);

    delete messageId;
    iResponseListner.Complete( KErrNone );
    return error;
    }


TBool CMSRPServerSubSession::sendMsgToClientL(CMSRPMessageHandler *incommingMsgHandler)
    {
    // Use the client send result listner to respond.
    // Extract the data and complete the iIncommingMessageListner.
    MSRPLOG("CMSRPServerSubSession::sendMsgToClientL");
    CMSRPMessage* inMsg = incommingMsgHandler->GetIncomingMessage();

    CBufSeg* buf1 = CBufSeg::NewL( 256 ); // expandsize 256
    CleanupStack::PushL( buf1 );
    RBufWriteStream writeStream( *buf1 );
    CleanupClosePushL( writeStream );

    inMsg->ExternalizeL( writeStream );
    writeStream.CommitL();

    iListenMSRPdataPckg().iIsProgress = FALSE;
    if ( buf1->Size() > KMaxLengthOfIncomingMessageExt )
        {
        // invalid message size
        iListenMSRPdataPckg().iStatus = KErrArgument;
        }
    else
        {
        buf1->Read( 0, iListenMSRPdataPckg().iExtMessageBuffer, buf1->Size() );
            iListenMSRPdataPckg().iStatus = KErrNone;            
        }

    CleanupStack::PopAndDestroy(2); // buf1, writestream    
   
    iIncommingMessageListner.Write(0,iListenMSRPdataPckg);
    iIncommingMessageListner.Complete(KErrNone);    

    return TRUE;
    }

void CMSRPServerSubSession::ReadSendDataPckgL()
    {
    iClientMessage->ReadL( 0, iSendMSRPdataPckg);
    return;
    }

TBool CMSRPServerSubSession::listnerSetupComplete()
    {
    if(iIncommingMessageListner.Check() && iResponseListner.Check())
        return TRUE;
    
    return FALSE;        
    }

CMSRPServerSubSession::TQueueType CMSRPServerSubSession::getQToProcess()
    {
    // Check the pending incomming message queue and client request queue and
    // decides which to process.
    // The longer queue is given a priority. If queues are equal incomming message queue 
    // is given priority.

    if(iPendingSendMsgQ.Length() > iInCommingMsgQ.Length())
        return TClientQueue;
    else
        return TInCommingMsgQueue;        
    }


TBool CMSRPServerSubSession::QueuesEmpty()
    {
    // Returns TRUE if there are no messages to process.
    if(iPendingSendMsgQ.isEmpty() && iInCommingMsgQ.isEmpty())
        return TRUE;
    else
        return FALSE;
    }

TBool CMSRPServerSubSession::informConnectionReadyToClient()
    {
    // The function informs the Client side that the pending connection request(Connect or Listen)
    // is now complete. 

    if(EDownstream == iConnDirection)
        {
        // Case of Connect request. 
        iConnectionListner.Complete(KErrNone);
        }
    else
        {
        // Case of Listen.
        iIncommingMessageListner.Complete(KErrNone);        
        }
    return TRUE;
    }

void CMSRPServerSubSession::QueueLog()
    {
    if(iOutMsgQ.Length() || iInCommingMsgQ.Length() || iPendingSendMsgQ.Length()||
        iPendingForDeletionQ.Length())
        {
        // If any of the Queue is not empty. Log a event.
        MSRPLOG2("CMSRPServerSubSession::ProcessEventL() Queue iOutMsgQ       %d",
                    iOutMsgQ.Length());
        
        MSRPLOG2("CMSRPServerSubSession::ProcessEventL() Queue iInCommingMsgQ %d",
                    iInCommingMsgQ.Length());
        
        MSRPLOG2("CMSRPServerSubSession::ProcessEventL() Queue iPendingSendMsgQ %d",
                    iPendingSendMsgQ.Length());

        MSRPLOG2("CMSRPServerSubSession::ProcessEventL() Queue iPendingForDeletionQ %d",
                    iPendingForDeletionQ.Length());
        }
    else
        {
        MSRPLOG("CMSRPServerSubSession::ProcessEventL() Queue All Empty");
        }        
    }


TBool CMSRPServerSubSession::checkMessageForSelfL(CMSRPMessageHandler *aMsgHandler)
    {
    MSRPLOG("CMSRPServerSubSession::checkMessageForSelfL");
    CMSRPMessageBase *message = aMsgHandler->GetIncomingResponse();
    if(!message)
        { 
        message = aMsgHandler->GetIncomingMessage();
        }
    
    if(!message)
        return FALSE;

    // Check if the sessionID in the 'To' path matches the LocalSessionID.
    if(FALSE == matchSessionIDL(message->ToPathHeader()))
        return FALSE;

    // Check if the sessionID in the 'From' path matches the known RemoteSessionID.
    return matchSessionIDL(message->FromPathHeader(), FALSE);            
    }


TBool CMSRPServerSubSession::matchSessionIDL(const CMSRPHeaderBase *aPathHeader, TBool local)
    {
    TBool retVal = FALSE;
    
    HBufC8* textValue = aPathHeader->ToTextValueLC();        
    TPtrC8 receivedSessionID = extractSessionID(*textValue);    
    
    if(local && receivedSessionID  == *iLocalSessionID)
        retVal =  TRUE;

    
    if(!local && receivedSessionID == *iRemoteSessionID)
        retVal =  TRUE;

    CleanupStack::PopAndDestroy(textValue);

    return retVal;
    }


TPtrC8 CMSRPServerSubSession::extractSessionID(const TDesC8& aPathBuffer)
    {
    // Extracts the sessionId from aPathBuffer and matches it again
    TInt posEndOfSessionString   = 
                aPathBuffer.LocateReverseF(KSemiColonCharacter);
    TInt posStartOfSessionString = 
                aPathBuffer.LocateReverseF(KDividedCharacter) + 1;

    TPtrC8 receivedSessionId = aPathBuffer.Mid(posStartOfSessionString, \
        (posEndOfSessionString - posStartOfSessionString));

    return receivedSessionId;
    }


CStateFactory& CMSRPServerSubSession::StateFactory()
    {
    return iStateFactory;
    }