upnp/upnpstack/dlnawebserver/src/upnphttpfiletransferreader.cpp
changeset 0 f5a58ecadc66
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnp/upnpstack/dlnawebserver/src/upnphttpfiletransferreader.cpp	Tue Feb 02 01:12:20 2010 +0200
@@ -0,0 +1,556 @@
+/** @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:  CUpnpHttpFileTransferReader is a class responsible for 
+*                asynchronous reading data from socket and controlling it
+*
+*/
+
+
+
+#include "upnphttpsession.h"
+#define KLogFile _L("DLNAWebServer.txt")
+#include "upnpcustomlog.h"
+#include "upnphttpfiletransferreader.h"
+#include "upnphttpfileaccess.h"
+#include "inet6err.h"
+
+
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::NewL
+// Factory method.
+// ---------------------------------------------------------------------------
+//
+CUpnpHttpFileTransferReader* CUpnpHttpFileTransferReader::NewL( CUpnpTcpSession& aSession,
+                                                RSocket& aSocket,
+                                                TThreadPriority aPriority,
+                                                TInt aReadPortion,
+                                                TInt aBufferSize)
+    {
+    CUpnpHttpFileTransferReader* self = new ( ELeave ) 
+                            CUpnpHttpFileTransferReader( aSession, aSocket,
+                                              aPriority, aReadPortion, aBufferSize );
+    CleanupStack::PushL( self );
+    self->BaseConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::CUpnpHttpFileTransferReader
+// C++ constructor.
+// ---------------------------------------------------------------------------
+//
+CUpnpHttpFileTransferReader::CUpnpHttpFileTransferReader( CUpnpTcpSession& aSession,
+                                          RSocket& aSocket,
+                                          TThreadPriority aPriority,
+                                          TInt aReadPortion,
+                                          TInt aBufferSize)
+    :CActive( aPriority ),
+    iSocket( aSocket ),
+    iSession( aSession ),
+    iReceivePtr( NULL, 0, 0 ),
+    iReadBufferSize(aReadPortion),
+    iBufferSize( aBufferSize )
+    {
+    LOGS1( "%i, CUpnpHttpFileTransferReader::CUpnpHttpFileTransferReader", iSession.Id() ); 
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::BaseConstructL
+// Two-phased constructor
+// constructor that can leave. Used from derived classes.
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::BaseConstructL()
+    {
+    CActiveScheduler::Add( this );              
+                
+    iRetryTimer = CUpnpNotifyTimer::NewL( this );
+    iCancelTimer = CUpnpNotifyTimer::NewL( this );        
+    
+    InitiateBufferL();
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::CalculateBufferSize
+// Finds nearest higher power of 2 for the given size
+// ---------------------------------------------------------------------------
+//
+TInt CUpnpHttpFileTransferReader::CalculateBufferSize( TInt aReadPortion, 
+                                                       TInt aBufferSize )
+    {
+    aBufferSize -= 1;
+    aBufferSize = aBufferSize | (aBufferSize >> 1);
+    aBufferSize = aBufferSize | (aBufferSize >> 2);
+    aBufferSize = aBufferSize | (aBufferSize >> 4);
+    aBufferSize = aBufferSize | (aBufferSize >> 8);
+    aBufferSize = aBufferSize | (aBufferSize >> 16);    
+    aBufferSize += 1;
+
+    if (aBufferSize <aReadPortion)
+        {        
+        aBufferSize = aReadPortion;
+        }
+    return aBufferSize;
+    }            
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::~CUpnpHttpFileTransferReader
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CUpnpHttpFileTransferReader::~CUpnpHttpFileTransferReader()
+    {    
+    Cancel();    
+    iCacheBuffer.Close();        
+    delete iRetryTimer;
+    delete iCancelTimer;   
+    }
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::Start
+// Starts reading.
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::StartL()
+    {    
+    LOGS1( "%i, CUpnpHttpFileTransferReader::Start", iSession.Id() );
+    if ( IsActive() )
+        {        
+        return;
+        }
+    
+    if ( RemainingBytes() <= 0 )
+        {
+        HandleOneBufferShortTransferL();
+        }
+    else 
+        {
+        IssueRead();
+        }
+    }    
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::HandleOneBufferShortTransferL
+// ---------------------------------------------------------------------------
+//    
+void CUpnpHttpFileTransferReader::HandleOneBufferShortTransferL()
+    {    
+    TInt totalLength = iSession.FileAccess()->TransferTotal();
+    if ( totalLength > 0 && totalLength < iCacheBuffer.Length() )
+        {
+        //cut off malicious bytes exceeding contenth-length
+        iCacheBuffer.SetLength( totalLength );
+        }
+    TInt error = iSession.FileAccess()->SaveL( iCacheBuffer );
+            
+    if ( error != KErrNone )
+        {                
+        iSession.FileTransferReaderErrorL( error );
+        LOGSH( error, "error in HandleOneBufferShortTransferL" );
+        return;
+        }
+    iSession.FileTransferReaderDoneL();
+    Finish();
+    }     
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::DoCancel
+// From class CActive.
+// Cancels issued reading.
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::DoCancel()
+    {
+    LOGS1( "%i, CUpnpHttpFileTransferReader::DoCancel", iSession.Id() );
+    // Cancel asychronous read request
+    iSocket.CancelRead();
+    }
+    
+// ---------------------------------------------------------------------------
+// CUpnpTcpSessionReader::CancelRetry
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::CancelTimers()
+    {
+    iRetryTimer->Cancel();
+    iCancelTimer->Cancel();
+    }       
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::RunL
+// From class CActive.
+// Function is called as a callback when the issued reading is completed.
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::RunL()
+    {
+    LOGS2( "%i, CUpnpHttpFileTransferReader::RunL(), iStatus %i",
+            iSession.Id(), iStatus.Int() );
+
+    // Active object request complete handler
+    switch ( iStatus.Int() )
+        {
+        case KErrNone:
+            iRetryErrorCount = 0;
+            iCancelTimer->Cancel();
+
+            iSession.TimerCancel();
+            iCacheBuffer.SetLength( iCacheBuffer.Length() + iLen() );
+            if ( ( iCacheBuffer.MaxLength() == iCacheBuffer.Length() ) 
+                || !(RemainingBytes() > 0))
+                {                
+                iIsFinished = HandleL();                               
+                }                                      
+            if ( !iIsFinished )
+                {
+                IssueRead();
+                iSession.StartTimeoutTimer( ETrue );
+                }
+            else
+                {                
+                Finish();
+                }                                       
+            break;
+         case KErrCancel:
+            if ( iCancelFromTimer ) 
+                {          
+                IssueRead();
+                iCancelFromTimer = EFalse;
+                }
+            break;            
+        case KErrEof:
+            iSession.TimerCancel();
+            iCacheBuffer.SetLength( iCacheBuffer.Length() + iLen() );
+            iIsFinished = HandleL();                        
+            if ( iIsFinished )
+                {
+                iSession.HandleErrorL( iStatus.Int() );
+                break;
+                }                       
+        case KErrNoMemory:
+        case KErrNotReady:
+        case KErrInet6AddressExpired:
+            if ( iRetryErrorCount < KMaxRetryErrors )
+                {
+                iRetryTimer->Cancel();
+                iRetryTimer->After( KRetryWaitTime * ++iRetryErrorCount, EFalse );
+                break;
+                }
+        default:            
+            iIsFinished = ETrue;
+            iIsActivated = EFalse;
+            if ( iSession.FileAccess() ) 
+                { 
+                iSession.FileAccess()->DeleteFile();            
+                }
+            iSession.HandleErrorL( iStatus.Int() );
+            break;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpTcpSessionWriter::RunError
+// RunError is called when RunL leaves.
+// -----------------------------------------------------------------------------
+//
+
+TInt CUpnpHttpFileTransferReader::RunError( TInt /*aError*/ )
+    {  
+    LOGS( "CUpnpHttpFileTransferReader::RunError"); 
+    HandleError();      
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpTcpSessionReader::TimerEventL
+// Retry read
+// -----------------------------------------------------------------------------
+//        
+void CUpnpHttpFileTransferReader::TimerEventL( CUpnpNotifyTimer* aTimer )
+    {
+    if ( aTimer == iCancelTimer )
+        {
+        LOGS( "CUpnpHttpFileTransferReader::TimerEventL, canceltimer");
+        iCancelFromTimer = ETrue;
+        iSocket.CancelRecv();
+        }
+    else if ( aTimer == iRetryTimer )
+        {
+        IssueRead();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpTcpSessionReader::StartCancelTimer
+// -----------------------------------------------------------------------------
+//  
+void CUpnpHttpFileTransferReader::StartCancelTimer()
+    {
+    LOGS( "CUpnpHttpFileTransferReader::StartCancelTimer");
+    TInt timeout = iSession.TimeoutCurrentValue();
+    iCancelTimer->Cancel();
+       
+    timeout = timeout/2 - KTwoSec;
+    if ( timeout <= 0 ) 
+        {
+        timeout = KOneSec;
+        }
+    iCancelTimer->After( timeout, EFalse );
+    iCancelFromTimer = EFalse;
+    }
+   
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::IssueRead
+// Issues reading.
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::IssueRead()
+    {       
+    if ( IsActive() )
+        {
+        LOGS1( "%i, PANIC: CUpnpHttpFileTransferReader::IssueRead!", 
+                iSession.Id() );
+        User::Panic( _L("CUpnpHttpFileTransferReader is active" ), KErrGeneral );    
+        } 
+                                               
+    if ( iSession.IsConnected() )
+        {          
+        ReadFromSocket();
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::RemainingBytes
+// Returns the remaining numbers of bytes to read
+// ---------------------------------------------------------------------------
+//
+TInt CUpnpHttpFileTransferReader::RemainingBytes()
+    {
+    LOGS( "CUpnpHttpFileTransferReader::RemainingBytes()");
+    if ( !iSession.FileAccess() )
+        {        
+        return 0;
+        }    
+    if ( iSession.FileAccess()->TransferTotal() == KErrNotFound ) 
+        {        
+        return ( TcpFinFoundRemainingBytes() );
+        }    
+    return ( iSession.FileAccess()->TransferTotal() - 
+             iSession.FileAccess()->BytesWritten() - iCacheBuffer.Length() );
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::ReadBufferSize
+// Returns the maximum size of bytes to read for once
+// ---------------------------------------------------------------------------
+//
+TInt CUpnpHttpFileTransferReader::ReadBufferSize()
+    {
+    LOGS( "CUpnpHttpFileTransferReader::ReadBufferSize()");
+    if ( !iSession.FileAccess() )
+        {        
+        return 0;
+        }
+    //checks how much space in the buffer
+    TInt availableSpace = AvailableSpace();
+    
+    //content-length no specified            
+    if( iSession.FileAccess()->TransferTotal() == KErrNotFound )
+        {        
+        return availableSpace;
+        }
+        
+    TInt remainingBytes = RemainingBytes();     
+    //chooses free space in the buffer or the num of remaining bytes to read        
+    return ( availableSpace >= remainingBytes ) ? remainingBytes : availableSpace;    
+    }               
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::HandleL
+// Handles adata in buffer, returns if file transfer has finished
+// ---------------------------------------------------------------------------
+//
+TBool CUpnpHttpFileTransferReader::HandleL()
+    {
+    LOGS( "CUpnpHttpFileTransferReader::HandleL");
+    TInt error = KErrGeneral;    
+    if ( iSession.FileAccess() )
+        {
+        LOGS( "calling iFile->SaveL()");
+        TPtr8 ptr = iCacheBuffer.LeftTPtr( iCacheBuffer.Size() );
+        error = iSession.FileAccess()->SaveL( ptr );
+        iCacheBuffer.SetLength(0);
+        }    
+    if ( error != KErrNone )
+        {                
+        iSession.FileTransferReaderErrorL( error );
+        LOGS( "returning ETrue after FileTransferReaderErrorL" );
+        return ETrue;
+        }
+    else if ( !( RemainingBytes() > 0 ) )
+        {
+        iSession.FileTransferReaderDoneL();
+        LOGS( "returning ETrue FileTransferReaderDoneL");
+        return ETrue;
+        }        
+    LOGS( "returning EFalse"); 
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::Finish
+// Finishes session
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::Finish()
+    {            
+    iIsActivated = EFalse;
+    iSession.StartClosingSession();        
+    }    
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::Reset
+// Makes reader ready to start reading new content
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::Reset()
+    {    
+    iIsFinished = EFalse;
+    iIsActivated = EFalse;
+    iCacheBuffer.SetLength(0);
+    }
+    
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::Activated
+// Checks if the filetransfer reader is started and in use
+// ---------------------------------------------------------------------------
+//
+TBool CUpnpHttpFileTransferReader::Activated()
+    {    
+    return iIsActivated;
+    } 
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::SetActivated
+// Filetransfer reader taken in use
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::SetActivated( TBool aValue )
+    {    
+    iIsActivated = aValue;
+    }
+        
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::ReadFromSocket
+// Reads data from socket
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::ReadFromSocket()
+    {    
+    Deque();
+    CActiveScheduler::Add(this);
+    
+    TInt len = ReadBufferSize();
+    TPtr8 ptr = iCacheBuffer.RightTPtr( 0 );
+    iReceivePtr.Set( (TUint8*)ptr.Ptr(), len, len );
+    StartCancelTimer();
+    iSocket.RecvOneOrMore( iReceivePtr, 0, iStatus, iLen );   
+    SetActive();
+    }        
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::AppendL(const TDesC8& aBeginning)
+// Appends beginning data to the buffer
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::AppendL( const TDesC8& aBeginning )
+    {    
+    //if no space for this operation, abort it,it shouldn't occur
+    if ( iCacheBuffer.MaxSize() - iCacheBuffer.Length() < aBeginning.Length() )
+        {        
+        User::Leave(KErrAbort);
+        }
+    
+    iCacheBuffer.Append( aBeginning );
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::InitiateBufferL()
+// Initiates the buffer
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::InitiateBufferL()
+    {    
+    if ( !iSession.FileAccess() )
+        {        
+        User::Leave( KErrGeneral );  
+        }
+    
+    iCacheBuffer.Close();    
+    iCacheBuffer.CreateL( iBufferSize );
+    }
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::HandleError
+// Handles error from RunL
+// ---------------------------------------------------------------------------
+//
+void CUpnpHttpFileTransferReader::HandleError()
+    {
+    if ( iSession.FileAccess() )
+        {
+        iSession.FileAccess()->DeleteFile();        
+        }
+    iIsFinished = ETrue;
+    Finish();        
+    }    
+
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::TcpFinFoundRemainingBytes
+// Detects end of body when no content length
+// ---------------------------------------------------------------------------
+//
+TInt CUpnpHttpFileTransferReader::TcpFinFoundRemainingBytes()
+    {
+    if ( iStatus.Int() == KErrEof )
+        {
+        //the num of written bytes will be the transfer total
+        iSession.FileAccess()->SetTransferTotal( 
+                                   iSession.FileAccess()->BytesWritten() );
+        return 0;
+        }        
+    else
+        {        
+        return AvailableSpace();        
+        }
+    }  
+       
+// ---------------------------------------------------------------------------
+// CUpnpHttpFileTransferReader::AvailableSpace
+// Returns num of bytes that will still fit into the buffer
+// ---------------------------------------------------------------------------
+//
+TInt CUpnpHttpFileTransferReader::AvailableSpace()
+    {
+    TInt space = (iBufferSize < iCacheBuffer.Length() + iReadBufferSize) ?
+                iBufferSize - iCacheBuffer.Length(): iReadBufferSize;    
+    return space;        
+    }  
+        
+//  End of File