upnp/upnpstack/dlnawebserver/src/upnptcpsessionwriter.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 10:42:04 +0300
changeset 27 226a2340cdd3
parent 0 f5a58ecadc66
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/** @file
* Copyright (c) 2005-2006 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:  CUpnpTcpSessionWriter is a class responsible for 
*                   asynchronous writing to a socket owned by CUpnpTcpSession.
*
*/



#include "upnptcpsession.h"
#include "upnptcpsessionwriter.h" 
#define KLogFile _L("DLNAWebServer.txt")
#include "upnpcustomlog.h"


class CUpnpTcpWriteRequest : public CBase
  	{
public:
  	static CUpnpTcpWriteRequest* NewL( const TDesC8& aBuffer )
		    {
		    CUpnpTcpWriteRequest* self = new (ELeave) CUpnpTcpWriteRequest();
		    CleanupStack::PushL( self );
		    self->ConstructL( aBuffer );
		    CleanupStack::Pop();
		
		    return self;
		    }
    
private:
	  CUpnpTcpWriteRequest() {}
	  void ConstructL( const TDesC8& aBuffer )
		    {
		    iBuffer.CreateL( aBuffer );
		    }
    
public:
  	TDesC8& Buffer()
		    {
		    return iBuffer;
		    }
  
	  ~CUpnpTcpWriteRequest()
		    {
		    iBuffer.Close();
		    }
    
private:
  	RBuf8 iBuffer;
  	};
  
// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::NewL
// Factory method.
// ---------------------------------------------------------------------------
//
CUpnpTcpSessionWriter* CUpnpTcpSessionWriter::NewL( CUpnpTcpSession& aSession,
                                                    RSocket& aSocket,
                                                    TThreadPriority aPriority )
    {
    CUpnpTcpSessionWriter* self = new ( ELeave ) 
            CUpnpTcpSessionWriter( aSession, aSocket, aPriority );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::CUpnpTcpSessionWriter
// C++ constructor.
// ---------------------------------------------------------------------------
//
CUpnpTcpSessionWriter::CUpnpTcpSessionWriter( CUpnpTcpSession& aSession,
                                              RSocket& aSocket, 
                                              TThreadPriority aPriority )
    :CActive( aPriority ),
    iSocket( aSocket ),
    iSession( aSession ),
    iInitialPriority( aPriority )
    {
    LOGS1( "%i, CUpnpTcpSessionWriter::CUpnpTcpSessionWriter", iSession.Id() );
    }

// ---------------------------------------------------------------------------
// CUpnpTcpSessionReader::TcpConstructL
// Two-phased constructor
// constructor that can leave. Used from derived classes.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::ConstructL()
    {
    CActiveScheduler::Add( this );
    iState = ENotConnected;
    iRetryWrite = CUpnpRetryWrite::NewL( iSession, iSocket, this, (TThreadPriority)Priority() );
    }
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionReader::~CUpnpTcpSessionReader
// Destructor.
// ---------------------------------------------------------------------------
//
CUpnpTcpSessionWriter::~CUpnpTcpSessionWriter()
    {
    LOGS1( "%i, CUpnpTcpSessionWriter::~CUpnpTcpSessionWriter", iSession.Id() );
    
    Cancel();
    iState = EDisconnected;
    
    iWriteRequestList.ResetAndDestroy();
    iWriteRequestList.Close();
  
    iSendBuffer.Close();

    delete iRetryWrite;
    }

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::IssueWriteL
// Issues writing request if session is connected and the socket is not 
// already sending. If metioned conditions are not met then it queues the request.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::IssueWriteL( const TDesC8& aBuffer )
    {
    LOGS1( "%i, CUpnpTcpSessionWriter::IssueWriteL(TDesC8&)", iSession.Id() );
    
    // Don't do anything because socket is already closed or we are writing already.
    if( iState == EDisconnected || (iSession.DownloadOngoing() ) 
        	|| (iSession.ShuttingDown() && iState != ENotConnected) )
        return;
    
    // If session not connected yet or is already sending then queue the write request
    if ( iState == ENotConnected || iState == EWriting )
        {
        CUpnpTcpWriteRequest* req = CUpnpTcpWriteRequest::NewL( aBuffer );
        CleanupStack::PushL(req);
        User::LeaveIfError(iWriteRequestList.Append( req ));
        CleanupStack::Pop();
        
        LOGS2(  "%i, CUpnpTcpSessionWriter::IssueWriteL - queue size=%i,"
                          , iSession.Id(), iWriteRequestList.Count() );
        return;
        }
    
    LOGS2( "%i, CUpnpTcpSessionWriter::IssueWriteL queue size=%i"
                     , iSession.Id() , iWriteRequestList.Count() );
                     
    // If session already connected then just prepare sending buffer and request 
    // send from socket

    iSendBuffer.Close();
    iSendBuffer.CreateL( aBuffer );
    
    /*if (Priority() == iInitialPriority)       
        SetPriority( iInitialPriority - 5);       
    else 
        SetPriority( iInitialPriority); */
        
    Deque();
    CActiveScheduler::Add(this);  
    
    iSocket.Write( iSendBuffer, iStatus );
    iState = EWriting;  
    
    SetActive();
    }
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::SessionConnected
// Informs writer if session is connected. If it is then writer checks if there
// are queued write requests. If there are any then it issues writing.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::SessionConnected( TBool aConnected )
    {
    LOGS2( "%i, CUpnpTcpSessionWriter::SessionConnected(),aConnected %i"
    		, iSession.Id() , aConnected );
    if( aConnected && iState == ENotConnected )
        {
        iState = EWaiting;
        TRAP_IGNORE( SendNextWriteRequestL() );
        }
    else if( !aConnected && iState != ENotConnected )
        {
        Cancel();
        iState = EDisconnected;
        }
    } 
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::HasWriteRequestsToSend
// Returns true if there are any write requests queued.
// ---------------------------------------------------------------------------
//
TBool CUpnpTcpSessionWriter::HasWriteRequestsToSend()
    {
    return ( iWriteRequestList.Count() > 0 );
    }

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::IsWriting
// Returns true if writer is writing data to the socket at the moment.
// ---------------------------------------------------------------------------
//          
TBool CUpnpTcpSessionWriter::IsWriting()
  {
  return iState == EWriting;    
  }
  
// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::DoCancel
// From class CActive
// Cancels issued writing request.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::DoCancel()
    {
    LOGS1( "%i, CUpnpTcpSessionWriter::DoCancel", iSession.Id() );
    
    // Cancel asychronous write request
    iState = EWaiting;
    }
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::RunL
// From class CActive
// Function called when issued writing is completed. Function checks if there
// are any write requests left to send and if there are then it issues writing.
// If queue is empty then function informs upper layer that writing is completed.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::RunL()
    {
    LOGS2( "%i, CUpnpTcpSessionWriter::RunL(), iStatus %i", 
    		iSession.Id() , iStatus.Int() );
    
    // Active object request complete handler
    if ( iStatus == KErrNone )
        {
        switch( iState )
            {
            // Character has been written to socket
            case EWriting:
                
                if (Priority() == iInitialPriority)       
                    SetPriority( iInitialPriority + 5);       
                else 
                    SetPriority( iInitialPriority); 
                
                // Change state because write request is finished already
                iState = EWaiting;
                if( HasWriteRequestsToSend() )
                    SendNextWriteRequestL();
                else
                    iSession.WritingCompletedL();
                break;
            
            default:
                LOGS2( "%i, PANIC: CUpnpTcpSessionWriter::RunL, %i",
                		iSession.Id() , iState );
                User::Panic( _L("Writer::RunL"), iState );
                break;
            };
        }
    else
        {
			if( iState == EWriting && (iStatus.Int() == KErrNoMemory || iStatus.Int() == KErrNotReady ) )
			{
				iRetryWrite->IssueWriteRetry();
       		}
        else
	        {

				// Error: pass it up to session
				iState = EWaiting;
				iSession.HandleErrorL( iStatus.Int() );
			}
        }
    }
// -----------------------------------------------------------------------------
// CUpnpTcpSessionWriter::RunError
// RunError is called when RunL leaves.
// -----------------------------------------------------------------------------
//
TInt CUpnpTcpSessionWriter::RunError( TInt aError )
    {
    LOGS2( "%i, CUpnpTcpSessionWriter::RunError %d"
    		, iSession.Id() , aError);
    return KErrNone;
    }


// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::SendNextWriteRequestL
// Function checks if there are any write requests left and if there are then
// issues writing and removes this request from queue.
// ---------------------------------------------------------------------------
//
void CUpnpTcpSessionWriter::SendNextWriteRequestL()
    {
    LOGS2( "%i, CUpnpTcpSessionWriter::SendNextWriteRequest(), iState %i",
    		iSession.Id() , iState );
    switch( iState )
        {
        case EWaiting:
            // Write queued request
            if ( iWriteRequestList.Count() > 0 )
            		{
                CUpnpTcpWriteRequest* req = iWriteRequestList[0];
                if ( req )
                    {
                    iWriteRequestList.Remove(0);
                    iWriteRequestList.Compress();
                    CleanupStack::PushL( req );
                    IssueWriteL( req->Buffer() );
                    CleanupStack::PopAndDestroy( req );
                    }
            }
            break;

        case ENotConnected:
        case EDisconnected:
            LOGS2( "%i, PANIC: CUpnpTcpSessionWriter::SendNextWriteRequest, %i",
            		iSession.Id() , iState );
            User::Panic( _L("SendNext::ENotConnected or EDisconnected"), iState );
            break;
        }
    }  

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::RetryWriteFailL
//    
// ---------------------------------------------------------------------------
//    
void CUpnpTcpSessionWriter::RetryWriteFailL( TInt aError )
	{
	// Error: pass it up to session
	iSession.HandleErrorL( aError );
	iState = EWaiting;
	}

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::RetryWriteSucceed
//    
// ---------------------------------------------------------------------------
//    
void CUpnpTcpSessionWriter::RetryWriteSucceed()
	{
    if ( iSendBuffer.Length() == 0 ) return;
    
    Deque();
    CActiveScheduler::Add(this);  
    
    iSocket.Write( iSendBuffer, iStatus );
    iState = EWriting;         
    
    SetActive();
	}

// ---------------------------------------------------------------------------
// CUpnpTcpSessionWriter::IsRetrying
//    
// ---------------------------------------------------------------------------
//    
TBool CUpnpTcpSessionWriter::IsRetrying()
	{
	return (iRetryWrite->IsStarted());
	}

//  End of File