browserutilities/downloadmgr/DownloadMgrServEng/Src/BuffStorage.cpp
changeset 0 dd21522fd290
child 47 e1bea15f9a39
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/browserutilities/downloadmgr/DownloadMgrServEng/Src/BuffStorage.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,444 @@
+/*
+* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:  Implements the double buffering functionality in the DownloadManager
+*
+*/
+
+
+#include <bldvariant.hrh>
+
+#include "FileExt.h"
+#include "HttpClientApp.h"
+#include "HttpDownload.h"
+#include "HttpStorage.h"
+#include "BuffStorage.h"
+
+#include "HttpDownloadManagerServerEngine.h"
+#include "HttpDownloadMgrLogger.h"
+#include "HeaderField.h"
+
+#include <SysUtil.h>
+#include <DocumentHandler.h>
+#include <APMSTD.H>
+
+#include "HttpDownloadMgrLogger.h"
+
+#ifdef __SYNCML_DM_FOTA
+#include <fotaengine.h>
+#endif
+
+#ifdef RD_MULTIPLE_DRIVE
+#include <driveinfo.h>
+#endif //RD_MULTIPLE_DRIVE
+
+// EXTERNAL DATA STRUCTURES
+//extern  ?external_data;
+
+// EXTERNAL FUNCTION PROTOTYPES  
+//extern ?external_function( ?arg_type,?arg_type );
+
+// CONSTANTS
+//const ?type ?constant_var = ?constant;
+
+// ---------------------------------------------------------
+// CBuffStorage::CBuffStorage
+// ---------------------------------------------------------
+//
+CBuffStorage::CBuffStorage( CHttpStorage* aHttpStorage )
+:CActive( EPriorityHigh ), 
+ iFile(aHttpStorage->iFile),
+ iDownloadedSize(aHttpStorage->iDownloadedSize), 
+ iBufferedSize(aHttpStorage->iBufferedSize),
+ iHttpStorageBufferSize(aHttpStorage->iBufferSize),
+ iHttpStorageLength(aHttpStorage->iLength),
+ iBufferingEnabled(aHttpStorage->iBufferingEnabled),
+ iProgressiveDownload(aHttpStorage->iProgressiveDownload)
+#ifdef __SYNCML_DM_FOTA
+ ,iFotaStream(aHttpStorage->iFotaStream)
+#endif // __SYNCML_DM_FOTA
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CBuffStorage::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CBuffStorage::ConstructL()
+    {
+    LOGGER_ENTERFN( "ConstructL" );
+    CActiveScheduler::Add( this );
+    }
+
+// -----------------------------------------------------------------------------
+// CBuffStorage::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CBuffStorage* CBuffStorage::NewL( CHttpStorage* aHttpStorage )
+    {
+    CBuffStorage* self = new( ELeave ) CBuffStorage( aHttpStorage );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+// ---------------------------------------------------------
+// CBuffStorage::~CBuffStorage
+// ---------------------------------------------------------
+//
+CBuffStorage::~CBuffStorage()
+    {
+    Cancel();
+
+	ResetBuffers();
+	
+	delete iWritePtr; iWritePtr = 0;
+    }
+
+
+
+// ---------------------------------------------------------
+// CBuffStorage::RunL
+// ---------------------------------------------------------
+//
+void CBuffStorage::RunL()
+    {
+    LOGGER_ENTERFN( "RunL" );
+    // Save the error code
+    iLastWriteErrorCode = iStatus.Int();
+   	
+    if(iLastWriteErrorCode==KErrNone && iWritePtr)
+    	{
+    	// Update how much was written on the file
+    	iDownloadedSize += iWritePtr->Length();
+    	
+    	CLOG_WRITE_2( "(%08X) CBuffStorage::RunL: Async write finished, downloaded now: %d", this, iDownloadedSize);
+    	}
+    else
+    	{
+    	CLOG_WRITE_2( "(%08X) CBuffStorage::RunL DH-iStat: %d, ", this, iStatus.Int() );
+    	}
+    	
+    if(iWait.IsStarted())
+		{
+		CLOG_WRITE_1 ( "(%08X) CBuffStorage::RunL() Stopping iWait", this );
+		iWait.AsyncStop();
+		}
+    }
+
+void CBuffStorage::DoCancel()
+	{
+	CLOG_WRITE_1("(%08X) CBuffStorage::DoCancel", this);
+	
+	// This is ok, CActive::Cancel always waits for the async operation to finish in this case
+	iLastWriteErrorCode = KErrCancel;
+	}
+
+// ---------------------------------------------------------
+// CBuffStorage::ResetBuffer
+// ---------------------------------------------------------
+//
+void CBuffStorage::ResetBuffers()
+	{	
+	CLOG_WRITE_1("(%08X) CBuffStorage::ResetBuffers >>", this);
+	
+	if(IsActive())
+		{
+		// Make sure async writes are finished
+		iWait.Start();
+		}
+	
+	// Cleanup
+    delete iBuff1; iBuff1 = NULL;
+    delete iBuff2; iBuff2 = NULL;
+    iClientBuffer = NULL;
+    iBufferSize = 0;
+    
+    CLOG_WRITE_1("(%08X) CBuffStorage::ResetBuffers <<", this);
+	}
+    
+// ---------------------------------------------------------
+// CBuffStorage::WriteOutNextBodyDataL
+// ---------------------------------------------------------
+//
+TBool CBuffStorage::WriteOutNextBodyDataL( const TDesC8& aBuf )
+    {
+    TBool retVal( ETrue );
+    
+    if( iFile )
+        {
+        if( iBufferingEnabled )
+            {
+            DoBufferingWriteL(aBuf);
+        	}
+        else
+        	{
+        	DoNonbufferingWriteL(aBuf);
+        	}
+        }        
+#ifdef __SYNCML_DM_FOTA                
+    else if( iFotaStream )
+        {
+        iFotaStream->WriteL( aBuf );
+        }
+#endif  // __SYNCML_DM_FOTA
+     
+
+    if( iHttpStorageLength != KDefaultContentLength &&
+        iBufferedSize > iHttpStorageLength )
+        // we don't know actually how many bytes will come down.
+        {
+        CLOG_WRITE_1( "(%08X) CBuffStorage::WriteOutNextBodyDataL: Length modified", this);
+        iHttpStorageLength = KDefaultContentLength;
+        retVal = EFalse;
+        }
+        
+    return retVal;
+    }
+
+// ---------------------------------------------------------
+// CBuffStorage::FlushBuffersL
+// ---------------------------------------------------------
+//
+void CBuffStorage::FlushBuffersL()
+	{
+	if(!iFile)
+		{
+		return;
+		}
+		
+	CLOG_WRITE_1("(%08X) CBuffStorage::FlushBuffersL >>", this);
+	
+	// Make sure async writes are finished before doing anything
+	if(IsActive())
+		{
+		CLOG_WRITE_1("(%08X) CBuffStorage::FlushBuffersL: stalling >>", this);
+	 	iWait.Start();
+	 	CLOG_WRITE_1("(%08X) CBuffStorage::FlushBuffersL: stalling <<", this);
+		}
+	
+	if(iLastWriteErrorCode != KErrNone)
+		{
+		CLOG_WRITE_2("(%08X) CBuffStorage::FlushBuffersL: last error = %d", this, iLastWriteErrorCode);
+		TInt err = iLastWriteErrorCode;
+		iLastWriteErrorCode = KErrNone;
+		User::Leave(err);
+		}
+	
+	if(iClientBuffer)
+		{
+		// Flush whatever is left on the client buffer
+		TInt len = iClientBuffer->Length();
+		
+		CLOG_WRITE_2("(%08X) CBuffStorage::FlushBuffersL: %d bytes", this, len);
+		if(len > 0)
+			{
+			// Write to file
+			TPtr8 des(iClientBuffer->Des());
+			
+			User::LeaveIfError(iFile->Write(des));
+			
+			// Update how much was written to file
+			iDownloadedSize += len;
+			
+			des.Zero();
+			}
+		}
+	
+	CLOG_WRITE_1("(%08X) CBuffStorage::FlushBuffersL <<", this);
+	}
+
+// ---------------------------------------------------------
+// CBuffStorage::DoBufferingWriteL
+// ---------------------------------------------------------
+//        
+void CBuffStorage::DoBufferingWriteL(const TDesC8& aBuf)
+	{	
+    if(iBufferSize != iHttpStorageBufferSize)
+        {
+        CLOG_WRITE_3("(%08X) CBuffStorage::DoBufferingWriteL: Allocate %d - downloaded %d", this, iHttpStorageBufferSize, iBufferedSize);
+        
+        // Make sure nothing is leaked
+        delete iBuff1; iBuff1 = 0;
+        delete iBuff2; iBuff2 = 0;
+        iBufferSize = 0;
+        
+        // Allocate buffers
+        iBuff1 = HBufC8::NewL(iHttpStorageBufferSize);
+        iBuff2 = HBufC8::NewL(iHttpStorageBufferSize);
+
+		// Mark that we now have buffers that are iBufferSize big
+		iBufferSize = iHttpStorageBufferSize;
+		
+        // Set client to use buffer 1
+        iClientBuffer = iBuff1;
+
+        }
+
+	// Get incoming data pointer and size
+    const TUint8* src = aBuf.Ptr();
+    TInt incomingBuffSize = aBuf.Length();
+    
+    // Process the data in blocks  
+	while(incomingBuffSize)
+		{
+		// Get pointer to current client buffer data (at start of loop since iClientBuffer can change)
+		TPtr8 buff = iClientBuffer->Des();
+		TInt buffLength = buff.Length();
+		
+		// How much space in the buffer
+		TInt toFillUp = iBufferSize - buffLength;
+		
+		// Check if we can just fit everything in the current buffer
+	    if(incomingBuffSize < toFillUp)
+	        {  
+	    	// Dump data on the current client buffer since ample space exists
+	    	buff.Append(src, incomingBuffSize);
+	    	
+	    	// Update the 'received' counter on how much we got from air
+	    	iBufferedSize += incomingBuffSize;
+	    	
+	    	CLOG_WRITE_4("(%08X) CBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d", this, incomingBuffSize, buff.Length(), iBufferSize);
+	    	
+	    	// And break out of the loop since we're finished for this round
+			break;
+			}
+		
+		// At this point we have data that either fills or overflows the buffer so append as much as fits
+		buff.Append( src, toFillUp );
+		
+		// Update the 'received' counter on how much we copied
+		iBufferedSize+=toFillUp;
+		
+		CLOG_WRITE_4("(%08X) CBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d", this, toFillUp, buff.Length(), iBufferSize);
+		
+		// Subtract how much we copied from the loop counter and advance source data pointer
+		incomingBuffSize -= toFillUp;
+		src+=toFillUp;
+	    
+	    // Now we have a full client buffer, better do something with it
+	    
+	    // Check if previous async write is still ongoing
+	    // Done here so if somebody switched on progressive download midway through we don't mix buffers
+		if(IsActive())
+			{
+			CLOG_WRITE_1("(%08X) CBuffStorage::DoBufferingWriteL: stalling >>", this);
+		 	iWait.Start();
+		 	CLOG_WRITE_1("(%08X) CBuffStorage::DoBufferingWriteL: stalling <<", this);
+			}
+		
+		// In case of async writes we have to check if there was error previously
+		if(iLastWriteErrorCode != KErrNone)
+			{
+			// Clear the error code and leave with it
+			TInt err = iLastWriteErrorCode;
+			iLastWriteErrorCode = KErrNone;
+			User::Leave(err);
+			}
+		
+		if(iProgressiveDownload)
+	    	{
+	    	CLOG_WRITE_1("(%08X) CBuffStorage::DoBufferingWriteL: Buffer full -> Progressive download", this);
+	    	TInt len = buff.Length();
+	    	
+	    	// Progressive download -> just do a synchronous write and update counter
+	    	User::LeaveIfError(iFile->Write(buff));
+	    	
+	    	// Update how much was written to file (sync write)
+	    	iDownloadedSize += len;
+	    	
+	    	// Clear out client buffer
+	    	buff.Zero();
+	    	
+	    	// Continue for next write
+	    	continue;
+	    	}
+	
+		// We must keep the descriptor alive until async operations have finished
+		if(!iWritePtr)
+			{
+			iWritePtr = new (ELeave) TPtr8(iClientBuffer->Des());
+			}
+		else
+			{
+			iWritePtr->Set(iClientBuffer->Des());
+			}
+	
+#ifdef _DEBUG
+		// Print out file position so we can check alignments
+		TInt currentPos(0);
+		iFile->Seek(ESeekCurrent, currentPos);
+		CLOG_WRITE_3("(%08X) CBuffStorage::DoBufferingWriteL - Start async write %d bytes, filepos=%d", this, iWritePtr->Length(), currentPos);
+#endif
+
+		// Start the async write and set AO active
+	 	iFile->Write( *iWritePtr, iStatus ) ;
+	 	SetActive();
+	 	
+	 	// Swap buffer pointers (we can't use the same buffer here 
+	 	// since it is not known when the buffer can be used again)
+	 	if(iClientBuffer == iBuff1)
+	 		{
+	 		iClientBuffer = iBuff2;
+	 		}
+	 	else
+	 		{
+	 		iClientBuffer = iBuff1;
+	 		}
+	 	
+	 	// Make sure the new client buffer is empty
+	 	iClientBuffer->Des().Zero();
+		}
+	}
+
+
+// ---------------------------------------------------------
+// CBuffStorage::DoNonbufferingWriteL
+// ---------------------------------------------------------
+//	
+void CBuffStorage::DoNonbufferingWriteL(const TDesC8& aBuf)
+	{
+	CLOG_WRITE_2("(%08X) CBuffStorage::DoNonbufferingWriteL: %d bytes", this, aBuf.Length());
+	
+	if(IsActive())
+		{
+		CLOG_WRITE_1("(%08X) CBuffStorage::DoNonbufferingWriteL: stalling >>", this);
+		iWait.Start();
+		CLOG_WRITE_1("(%08X) CBuffStorage::DoNonbufferingWriteL: stalling <<", this);
+		}
+		
+	TInt len = aBuf.Length();
+	if(len)
+		{
+    	User::LeaveIfError( iFile->Write( aBuf ) );
+    
+    	if( iProgressiveDownload )
+        	{
+        	User::LeaveIfError( iFile->Flush() );
+    		}
+		
+		// Update how much received from air
+		iBufferedSize += len;
+		
+		// Update how much written to file
+   		iDownloadedSize += len;
+   		}
+    }
+
+
+//  End of File