Msrp/MsrpServer/src/CMSRPConnection.cpp
author Petteri Saari <petteri.saari@digia.com>
Thu, 25 Nov 2010 13:59:42 +0200
branchMSRP_FrameWork
changeset 58 cdb720e67852
parent 25 505ad3f0ce5c
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
*
*/

// CLASS HEADER
#include "CMSRPConnection.h"
#include "MSRPCommon.h"
// INTERNAL INCLUDES
#include "CMSRPConnector.h"
#include "CMSRPReader.h"
#include "CMSRPParser.h"
#include "CMSRPWriter.h"

// -----------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------
//
CMSRPConnection::CMSRPConnection( TInetAddr& aRemoteAddr, MMSRPConnectionManager& aConnMngr ): iHostAddress(aRemoteAddr), iConnMngr(aConnMngr)
    {
    MSRPLOG( "CMSRPConnection::CMSRPConnection enter" )
    MSRPLOG( "CMSRPConnection::CMSRPConnection exit" )
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::~CMSRPConnection
// -----------------------------------------------------------------------------
//
CMSRPConnection::~CMSRPConnection()
	{
	MSRPLOG( "CMSRPConnection::~CMSRPConnection enter" )
	iSubsessions.Reset();
	iSubsessions.Close();
	delete iListenTimer;
	delete iConnector;
	delete iWriter;
	delete iParser;
	delete iReader;  
	//delete iBufPool;
	if(iSocket)
	    {
	    iSocket->Close();
	    delete iSocket;
	    }
	
	MSRPLOG( "CMSRPConnection::~CMSRPConnection exit" )
	}

// -----------------------------------------------------------------------------
// CMSRPConnection* CMSRPConnection::NewL
// -----------------------------------------------------------------------------
//
/*static*/ MMSRPConnection* CMSRPConnection::NewL( TInetAddr& aRemoteAddr, MMSRPConnectionManager& aConnMngr )
    {
    MSRPLOG( "CMSRPConnection::NewL enter" )

	// Perform construction.
    CMSRPConnection* self = new ( ELeave ) CMSRPConnection(aRemoteAddr, aConnMngr);
    CleanupStack::PushL( self );
    self->ConstructL( );
    CleanupStack::Pop( self );

    MSRPLOG( "CMSRPConnection::NewL exit" )
    return self;
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::ConstructL
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ConstructL( )
	{
	MSRPLOG( "CMSRPConnection::ConstructL enter" )
	iConnectionState = ENotConnected;
	iListenTimer = CMSRPTimeOutTimer::NewL( *this );
	MSRPLOG( "CMSRPConnection::ConstructL exit" )	
	}

// -----------------------------------------------------------------------------
// CMSRPConnection::CheckIfConnected
// listening state check for validating listener connections 
// -----------------------------------------------------------------------------
//
TBool CMSRPConnection::CheckConnection(TInetAddr& aRemoteAddr, TBool aOnlyListen)
	{
	MSRPLOG( "CMSRPConnection::CheckConnection enter" )
	TUint port_stored = iHostAddress.Port();
	TUint port_connect = aRemoteAddr.Port();
	
	//if (iHostAddress.CmpAddr(aRemoteAddr))//v4, v6 issue	
	if (iHostAddress.Match(aRemoteAddr) && port_stored == port_connect)
	    {
	    if (aOnlyListen && iConnectionState == EListening) //check if listening
	        return ETrue;	    
	    else if (!aOnlyListen /*&& iConnectionState <= EConnected */) //not connected, connecting, listening, connected
	        return ETrue;	   
	    /*else
	        return EFalse;*/ //timed out, disconnecting, disconnected, create a new conn object
	    }
	MSRPLOG( "CMSRPConnection::CheckConnection exit" )	
	return EFalse;
	}

// -----------------------------------------------------------------------------
// CMSRPConnection::ConnectL
// -----------------------------------------------------------------------------
//
TInt CMSRPConnection::ConnectL(MMSRPConnectionObserver& aSubsession)
	{
	MSRPLOG("CMSRPConnection::ConnectL() enter")
	//subsession to ensure it does not reissue
	//connection does not check for pre-existent observers
	
	iSubsessions.AppendL(&aSubsession);	
	
	switch(iConnectionState)
	    {
	    case ENotConnected:
	        //create connector and issue connect
	        //delete iConnector;
	        iConnector = CMSRPConnector::NewL( iConnMngr, *this );
	        iConnector->Connect(iHostAddress);
	        iConnectionState = EConnecting;
	        
	        break;
	        
	    case EConnecting:        
	        break;
	        
	    case EListening: //as of now, dont try to issue connect,complete when other party connects
	        //TBD
	        //later change state to connecting and issue connect
	        //if connect completes before listen, then change state to connected
	        // if at all listen completes on same conn object, then check if state == connected and drop listen conn
	        // do vice versa if listen completes before connect	        	        
	        break;
	        
	    case EConnected:
            break;
            
	    case EListenTimedOut:
	    case EConnectTimedOut:
	    case EError:
	        //shudn't reach here, if connect issued immediately after/within getConn
	        //User::Leave(MMSRPConnectionObserver::EConnectionStateUnexpected);
	        break;                	        
	    
	    }
	MSRPLOG("CMSRPConnection::ConnectL() exit")
	return iConnectionState;
	}
		

// -----------------------------------------------------------------------------
// CMSRPConnection::ListenL
// -----------------------------------------------------------------------------
//
TInt CMSRPConnection::ListenL(MMSRPConnectionObserver& aSubsession)
    {
    MSRPLOG("CMSRPConnection::ListenL() enter")
        
    iSubsessions.AppendL(&aSubsession);
        
    
    switch(iConnectionState)
        {
        case ENotConnected:
            iConnectionState = EListening;
            iConnMngr.ListenL(this);
            //iListenTimer->After( KListenTimeoutInSeconds * KSecondinMicroseconds );
            
            break;
            
        case EConnecting: //dont issue listen, drop conn if other party connects, change later          
            
            //added check if listening in check connection to prevent accepting conn, 
            //simply allowing will corrupt listen count, TBD: introduce another EListeningandConnecting state                        
            break;
            
        case EListening:                      
            break;
            
        case EConnected:
            break;
                
        case EListenTimedOut:
        case EConnectTimedOut:
        case EError:
            //shudn't reach here, if connect issued immediately after/within getConn
            //User::Leave(MMSRPConnectionObserver::EConnectionStateUnexpected);
            break;                         
        
        }
    MSRPLOG("CMSRPConnection::ListenL() exit")
    return iConnectionState;
    
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::ReleaseConnection
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ReleaseConnection(MMSRPConnectionObserver& aSubsession)
    {
    MSRPLOG("CMSRPConnection::ReleaseConnection() enter")
    
    Remove(&aSubsession);
        
    if(iSubsessions.Count())
        {
        MSRPLOG("CMSRPConnection::ReleaseConnection() exit")
        return;
        }
    
    //if no subsessions (TBD : start timeout timer and disconnect on timeout)
    /*if(iConnectionState == EConnecting)
        {
            //iConnector->CancelConnect();
            delete iConnector;
            iConnector = NULL;
        }
    else if(iConnectionState == EConnected)*/
                
    CloseConnection();
        
    
    //iConnectionState = ENotConnected;
    MSRPLOG("CMSRPConnection::ReleaseConnection() exit")
    return;
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::ConnectionEstablishedL
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ConnectionEstablishedL( TInt aNewState, RSocket* aSocket, TInt aStatus )
    {
    MSRPLOG("CMSRPConnection::ConnectionEstablishedL() enter")
    iListenTimer->Cancel();
    //if not error
    if(aNewState == EConnected)
        {
        iConnectionState = aNewState;
        iSocket = aSocket;
        if(iConnector)
           {
           iConnector->ConnectComplete();
           /*dont delete now,as in case of leave, connector needs 2 b available*/
           //delete iConnector;
           //iConnector = NULL;
           }
        iWriter = CMSRPWriter::NewL(*iSocket , *this);               
        iParser = CMSRPParser::NewL(*this);
        iReader = CMSRPReader::NewL(*iSocket , *this);           
             
        iReader->StartReceivingL(iBufPool.ProvideBufferL());
        }

    /*not deleting connector as yet, notify all could leave in subsession  and also delete conn on conn error*/
    //intimate all subsessions
    NotifyAllL(aNewState, aStatus );
    
    //on error  or connect timeout close connection, i.e. intimate all subsessions and delete connection obj
    if(aStatus != KErrNone)
        {
        //listenaccepted does not comeback with error intimations, hence safe to decrement listen count
        //currently no risk of double decrementing listener count
        //CloseConnection();
        }
    

      
    MSRPLOG("CMSRPConnection::ConnectionEstablishedL() exit")   
    }

TInt CMSRPConnection::getConnectionState()
    {
    return iConnectionState;
    // iConnection state should not be Tint, it should be MMSRPConnection::TMSRPConnectionState.
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::ReadStatus
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ReadStatusL(RMsrpBuf& aBuf, TInt aStatus)
    {
    MSRPLOG("CMSRPConnection::ReadStatusL() enter")
    if(aStatus == KErrNone)
        {
        //post to parser and return immediate
        iParser->ParseL(aBuf);
        
        RMsrpBuf copy(aBuf);
        if(copy.MsrpRightExtract() > KThreshold)
            {
            iReader->StartReceivingL(copy);
            }   
        else
            {
            iReader->StartReceivingL(iBufPool.ProvideBufferL());
            }
        return;
        }
    //read error or connection error
    //intimate all subsessions
    NotifyAllL(EError, aStatus );
    //CloseConnection();
    
    MSRPLOG("CMSRPConnection::ReadStatusL() exit")     
    }

TInt CMSRPConnection::ParseStatusL (CMSRPMessageHandler* aMsg, TInt aStatus)
    {
    MSRPLOG("CMSRPConnection::ParseStatus enter")
    if (aStatus != KErrNone)
        {
        NotifyAllL(EError, aStatus );
        return MMSRPParserObserver::EParseStatusError;
        }
    
    /*if error, count is zero*/
    //while msg not consumed try to handover    
    TBool consumed = FALSE;
    for ( TInt i = 0; (!consumed) && i < iSubsessions.Count(); i++ )
         {
         TRAPD( err, consumed = iSubsessions[ i ]->MessageReceivedL( aMsg ) );
         if ( err )
             {
             // invalid message
             NotifyAllL( EError, err );
             return MMSRPParserObserver::EParseStatusError;
             }
         }
    
    //if unclaimed by any subsession, callback to first subsession
    if(!consumed && iSubsessions.Count())
        {
        iSubsessions[0]->UnclaimedMessageL( aMsg );
        return MMSRPParserObserver::EParseStatusMessageUnclaimed;
        }
          
    MSRPLOG("CMSRPConnection::ParseStatus exit")
    return MMSRPParserObserver::EParseStatusMessageHandled;
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::ReportReceiveprogressL
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ReportReceiveprogressL( CMSRPMessageHandler* aMsg )
    {
    MSRPLOG("-> CMSRPConnection::ReportReceiveprogressL")
    
    for ( TInt i = 0; i < iSubsessions.Count(); i++ )
         {
         TRAPD( err, iSubsessions[ i ]->MessageReceiveProgressL( aMsg ) );
         if ( err )
             {
             // invalid message
             NotifyAllL( EError, err );
             return;
             }
         }
          
    MSRPLOG("<- CMSRPConnection::ReportReceiveprogressL")
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::WriteSocketError
// -----------------------------------------------------------------------------
//
void CMSRPConnection::WriteSocketError(TInt aStatus)
    {
    MSRPLOG("CMSRPConnection::WriteSocketError() enter")
    TInt err =0;
    TRAP(err, NotifyAllL(EError, aStatus));
    //CloseConnection();
    MSRPLOG("CMSRPConnection::WriteSocketError() exit")
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::Send
// -----------------------------------------------------------------------------
//
void CMSRPConnection::SendL(MMSRPWriterObserver& aMsg)
    {
    MSRPLOG("CMSRPConnection::SendL() enter")
    if(iConnectionState == EConnected)
        iWriter->RequestSendL(aMsg);
    MSRPLOG("CMSRPConnection::SendL() exit") 
    }
    
// -----------------------------------------------------------------------------
// CMSRPConnection::ContinueSendingL
// -----------------------------------------------------------------------------
//
void CMSRPConnection::ContinueSendingL( MMSRPWriterObserver& aMsg )
    {
    MSRPLOG("-> CMSRPConnection::ContinueSendingL")
    if( iConnectionState == EConnected )
        {
        iWriter->RequestSendL( aMsg );
        }
    MSRPLOG("<- CMSRPConnection::ContinueSendingL") 
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::CancelSendingL
// -----------------------------------------------------------------------------
//
void CMSRPConnection::CancelSendingL( const MMSRPWriterObserver* aMsg )
    {
    MSRPLOG("-> CMSRPConnection::CancelSendingL")
    if( iConnectionState == EConnected )
        {
        iWriter->CancelSendingL( aMsg );
        }
    MSRPLOG("<- CMSRPConnection::CancelSendingL") 
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::TimerExpired
// -----------------------------------------------------------------------------
//
void CMSRPConnection::TimerExpiredL()   
    {
    MSRPLOG("CMSRPConnection::TimerExpired() enter")
    if(iConnectionState == EListening)
        NotifyAllL(EListenTimedOut, KErrTimedOut);
    else 
        NotifyAllL(EConnectTimedOut, KErrTimedOut);
    //iConnMngr.ListenCancel(this);
    MSRPLOG("CMSRPConnection::TimerExpired() exit")
    }


// -----------------------------------------------------------------------------
// CMSRPConnection::Remove
// -----------------------------------------------------------------------------
//
void CMSRPConnection::Remove(MMSRPConnectionObserver* aSubsession)
    {
    MSRPLOG("CMSRPConnection::Remove() enter")
    TInt index = iSubsessions.Find(aSubsession);    
    //iSubsessions[index].DisconnectIssued;
    if(index != KErrNotFound)
        iSubsessions.Remove(index);
    MSRPLOG("CMSRPConnection::Remove() exit")
    }

// -----------------------------------------------------------------------------
// CMSRPConnection::CloseConnection
// -----------------------------------------------------------------------------
//
void CMSRPConnection::CloseConnection()
    {
    MSRPLOG("CMSRPConnection::CloseConnection() enter")
    //for connected no listen cancel needed
    //for listener error listener deleted
    if(/*iConnectionState == EListenConnected ||*/ iConnectionState == EListening || iConnectionState == EListenTimedOut)
        iConnMngr.ListenCancel(this);
    else
        //deleting connection, takes care of issuing cancel connect on connector also (if connecting)
        iConnMngr.Remove(this);
    MSRPLOG("CMSRPConnection::CloseConnection() exit")
    }



// -----------------------------------------------------------------------------
// CMSRPConnection::NotifyAll
// -----------------------------------------------------------------------------
//
void CMSRPConnection::NotifyAllL(TInt aNewState, TInt aStatus ) 
    {
    MSRPLOG("CMSRPConnection::NotifyAll() enter")
    iConnectionState = aNewState;
    for ( TInt i = 0; i < iSubsessions.Count(); i++ )
         {
         //make sure connectionstate does not release in notify
         //else returns a value to reflect the same
         iSubsessions[ i ]->ConnectionStateL( aNewState, aStatus );
         }
    MSRPLOG("CMSRPConnection::NotifyAll() exit")
    }


// End of File