upnp/upnpstack/dlnawebserver/src/upnphttpfiletransferwriter.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:  CUpnpHttpFileTransferWriter is a class responsible for 
*                   asynchronous writing to a socket owned by CUpnpTcpSession.
*
*/



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


// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::NewL
// Factory method.
// ---------------------------------------------------------------------------
//
CUpnpHttpFileTransferWriter* CUpnpHttpFileTransferWriter::NewL( CUpnpTcpSession& aSession,
                                                    RSocket& aSocket,
                                                    TThreadPriority aPriority,
                                                    TInt aWriteSize )
    {
    CUpnpHttpFileTransferWriter* self = new ( ELeave ) 
            CUpnpHttpFileTransferWriter( aSession, aSocket, aPriority, aWriteSize );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }
    
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::CUpnpHttpFileTransferWriter
// C++ constructor.
// ---------------------------------------------------------------------------
//
CUpnpHttpFileTransferWriter::CUpnpHttpFileTransferWriter( CUpnpTcpSession& aSession,
                                              RSocket& aSocket, 
                                              TThreadPriority aPriority,
                                              TInt aWriteSize )
    :CActive( aPriority ),
    iSocket( aSocket ),
    iSession( aSession ),
    iState(EUnknown),
    iSendPointer(NULL,0),
    iWriteSize(aWriteSize)
    {
    LOGS1( "%i, CUpnpHttpFileTransferWriter::CUpnpHttpFileTransferWriter", iSession.Id() );
    // No implementation required
    }

// ---------------------------------------------------------------------------
// CUpnpTcpSessionReader::ConstructL
// Two-phased constructor
// constructor that can leave. Used from derived classes.
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::ConstructL()
    {
    CActiveScheduler::Add( this );   
    iRetryWrite = CUpnpRetryWrite::NewL( iSession, iSocket, this, (TThreadPriority)Priority() );
    
    iSendBuffer.CreateL( iWriteSize );
    }
    
// ---------------------------------------------------------------------------
// CUpnpTcpSessionReader::~CUpnpTcpSessionReader
// Destructor.
// ---------------------------------------------------------------------------
//
CUpnpHttpFileTransferWriter::~CUpnpHttpFileTransferWriter()
    {    
    Cancel();    
    
    iSendBuffer.Close();
    
    delete iRetryWrite;
    }
 
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::DoCancel
// From class CActive
// Cancels issued writing request.
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::DoCancel()
    {
    LOGS1( "%i, CUpnpHttpFileTransferWriter::DoCancel", iSession.Id() );
    
	iState = ECancelled;
    }
    
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::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 CUpnpHttpFileTransferWriter::RunL()
    {
    LOGS2( "%i, CUpnpHttpFileTransferWriter::RunL(), iStatus %i", 
    		iSession.Id() , iStatus.Int() );
    
    // Active object request complete handler
    if ( iStatus == KErrNone )
        {
        switch( iState )
            {
            // Character has been written to socket
            case EHeaders:
            	//100-continue not expected
            	if(!iSession.FileAccess())
            		{
            		Cancel();
            		break;
            		}
            	else 
            		{
            		iState = EContent;            		
            		}
            case EContent:            	
            	SendNextPortionL();            
                
                break;
            case EFinished:                    	    	
            	iSession.FileTransferWriterDoneL();

            	iSession.StartTimeoutTimer(EFalse);            	                      	
				FinishL();
            	//export finished
            	break;    
            
            default:                
                break;
            };
        }
    else
        {
           if( (iState == EHeaders || iState == EContent || iState == EFinished) &&
              (iStatus.Int() == KErrNoMemory || iStatus.Int() == KErrNotReady ) )
           {
				iRetryWrite->IssueWriteRetry();
    	   }
		   else
	       {
				// Error: pass it up to session
				iSession.HandleErrorL( iStatus.Int() );
				iState = ECancelled;
			}
        }
    }

// -----------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::RunError
// RunError is called when RunL leaves.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpFileTransferWriter::RunError( TInt aError )
    {
    LOGS2( "%i, CUpnpHttpFileTransferWriter::RunError %d"
    		, iSession.Id() , aError);
    
    iState = EFinished;        
                
    TRAP_IGNORE( HandleErrorL() );
    iSession.StartClosingSession();
    
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::SendNextWriteRequestL
// Function checks if there are any write requests left and if there are then
// issues writing and removes this request from queue.
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::SendNextPortionL()
    {
    LOGS2( "%i, CUpnpHttpFileTransferWriter::SendNextPortionL(), iState %i",
    		iSession.Id() , iState );
	
	if( iSession.FileAccess() )
		{
		if( iState == EContent )    	
	    	if( !IsActive() )
	    		{      	
		    	iSendPointer.Set( (TUint8*)iSendBuffer.Ptr(),0,iSendBuffer.MaxLength() );
		        if( iSession.FileAccess()->GetL(iSendPointer,iSendBuffer.MaxLength()) )
		        	{
		        	iState = EFinished;     		
		        	}
		        
				
				iSession.TimerCancel();        
		        WriteToSocket();
		        iSession.StartTimeoutTimer(ETrue);	       
		        
	    		}
		}
	else
		{
		Cancel();
		}
  
    }  

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::StartL
// Passes control to the reader
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::StartL()
    {
    iWaiting = EFalse;    
	switch(iState)
		{
			case EUnknown:			
				
				iState = EHeaders;
				SendHeadersL();
				break;
			case EHeaders:
				
				if(iSession.FileAccess()->HeadersSent())
					{
					iState = EContent;				
					SendNextPortionL();
					}
				else
					SendHeadersL();
				break;
				
			default:
				break;
		}
    }

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::StartL
// Sends the HTTP headers of the content
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::SendHeadersL()
    {
    if(iState == EHeaders)
    	if( iSession.FileAccess() )
    		if(!IsActive())
    			{ 
    			//in case session not connected,waiting...
    			if(!iSession.IsConnected())
					{
					iWaiting = ETrue;
					return;
					}   			
				iSendBuffer.Zero();
				
				if ( ( iSession.FileAccess()->GetHeaders().Length() -
				       iSession.FileAccess()->TransferredBytes()) <= 
		               iSendBuffer.MaxLength() )
					{
					TPtrC8 headerPointer;
					headerPointer.Set(iSession.FileAccess()->GetHeaders());
					headerPointer.Set( headerPointer.Right( 
		            iSession.FileAccess()->GetHeaders().Length()-
		                iSession.FileAccess()->TransferredBytes()) );
				
					iSendBuffer.Append( headerPointer );			
					iSession.FileAccess()->SetHeadersSent();

                    // Adding file content to the header
                    TInt length = iSendBuffer.MaxLength()-iSendBuffer.Length();
                    						
                    HBufC8* tmpBuffer = HBufC8::NewLC(length);
					
                    iSendPointer.Set(tmpBuffer->Des());
                    if( iSession.FileAccess()->GetL(iSendPointer,length) )
                        {
                        iState = EFinished;
                        }
                    iSendBuffer.Append(iSendPointer);
                    CleanupStack::PopAndDestroy( tmpBuffer );
					}
				else
					{
					TPtrC8 headerPointer;
					headerPointer.Set( iSession.FileAccess()->GetHeaders() );
					headerPointer.Set( headerPointer.Right( 
		            iSession.FileAccess()->GetHeaders().Length() -
		                iSession.FileAccess()->TransferredBytes() ) );
					headerPointer.Set( headerPointer.Left( 
		                iSendBuffer.Length() ) );
					
					iSendBuffer.Append( headerPointer );				
					iSession.FileAccess()->SetPosOfHeader( 
					    iSession.FileAccess()->TransferredBytes() + headerPointer.Length() );							
					}
		    	
		    	iSendPointer.Set((TUint8*)iSendBuffer.Ptr(),iSendBuffer.Length(),iSendBuffer.MaxLength());
    	   		
    	   		iSession.TimerCancel();        
	        	WriteToSocket();
	        	iSession.StartTimeoutTimer(ETrue);
	        	
	        	if(!iHttpPostStarted)
	        		{
	        		iSession.NotifyUpperLayersOnPostL();
	        		iHttpPostStarted = ETrue;
	        		}
	        		
    			}
    }          

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::Reset
// Resets the state of the writer
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::Reset()
    {
    iState = EUnknown;  
    iHttpPostStarted = ETrue;  
    }

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::WriteToSocket
// Writes data to socket
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::WriteToSocket()
    {
	Deque();
	CActiveScheduler::Add(this);  

	iSocket.Write(iSendPointer,iStatus);
	SetActive();
    }

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::IsWaiting
// Checks if file transfer writer is in use
// ---------------------------------------------------------------------------
//
TBool CUpnpHttpFileTransferWriter::IsWaiting()
    {
	return iWaiting;
    }

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::IsActivated
// Writes data to socket
// ---------------------------------------------------------------------------
//
TBool CUpnpHttpFileTransferWriter::IsActivated()
    {
	return (!iWaiting && iState!=EUnknown);
    } 

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::IsRetrying
// if waiting to retry writing to a socket
// ---------------------------------------------------------------------------
//
TBool CUpnpHttpFileTransferWriter::IsRetrying()
    {
	return (iRetryWrite->IsStarted());
    }
    
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::IsCancelled
// Checks if transfer is cancelled
// ---------------------------------------------------------------------------
//
TBool CUpnpHttpFileTransferWriter::IsCancelled()
    {
	return (iState== ECancelled);
    }        
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::FinishL
// Finishes download
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::FinishL()
    {
	iSession.FileTransferWriterHandleMoreL();
    }    
    
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::HandleErrorL
// Handles RunL error
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::HandleErrorL()
    {
    iSession.FileTransferWriterDoneL(); // 200ok to upper layers + delete iFileServe    
    FinishL();                          // serving uotstanding requests  
    }
        
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::SetPostNotify
// Post notify will be sent
// ---------------------------------------------------------------------------
//
void CUpnpHttpFileTransferWriter::SetPostNotify()
    {
	iHttpPostStarted = EFalse;
    }    
        
// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::RetryWriteFailL
// 
// ---------------------------------------------------------------------------
//    
void CUpnpHttpFileTransferWriter::RetryWriteFailL( TInt aError )
	{
	// Error: pass it up to session
	iSession.HandleErrorL( aError );
    iState = ECancelled;
	}

// ---------------------------------------------------------------------------
// CUpnpHttpFileTransferWriter::RetryWriteSucceed
// 
// ---------------------------------------------------------------------------
// 
void CUpnpHttpFileTransferWriter::RetryWriteSucceed()
	{
	WriteToSocket();
	}
    
//  End of File