--- /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