diff -r 608f67c22514 -r 896e9dbc5f19 internetradio2.0/irnetworkcontroller/src/irdatatransfertracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/internetradio2.0/irnetworkcontroller/src/irdatatransfertracker.cpp Wed Aug 18 09:40:26 2010 +0300 @@ -0,0 +1,348 @@ +/* +* Copyright (c) 2007 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: Tracks data transmitted through a network connection. +* +*/ + + +#include +#include +#include + +#include "irdebug.h" +#include "irdatatransfertracker.h" + +// The threshold in bytes after which notifications are sent to observers. +// 0.1 MB = 104857.6 bytes ( rounded ) +const TInt KIRDataTransferTrackerThreshold = 104858; +// 0.01 MB = 1048.57 bytes ( rounded ) +const TInt KIRDataTransferTrackerMiniThreshold = 1049; +// The overhead in bytes per one HTTP header. +const TInt KVRBytesPerHeaderOverhead = 2; // "\r\n" +// The overhead in bytes per one header field in a request. +const TInt KVRBytesPerHeaderFieldOverhead = 4; // ": \r\n" +// The overhead in bytes per one header sent. +const TInt KVRBytesPerHeaderSentOverhead = 4; // " \r\n" +// The overhead in bytes per one header received. +const TInt KVRBytesPerHeaderReceivedOverhead = 3; // " \r\n" + + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CIRDataTransferTracker* CIRDataTransferTracker::NewL() + { + IRLOG_DEBUG( "CIRDataTransferTracker::NewL - Entering" ); + CIRDataTransferTracker* self = new ( ELeave ) CIRDataTransferTracker; + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + IRLOG_DEBUG( "CIRDataTransferTracker::NewL - Exiting" ); + return self; + } + +// --------------------------------------------------------------------------- +// Constructor. +// --------------------------------------------------------------------------- +// +CIRDataTransferTracker::CIRDataTransferTracker() + { + IRLOG_DEBUG( "CIRDataTransferTracker::CIRDataTransferTracker - Entering" ); + bThresholdCrossed = EFalse; + IRLOG_DEBUG( "CIRDataTransferTracker::CIRDataTransferTracker - Exiting" ); + } + +// --------------------------------------------------------------------------- +// Second-phase constructor. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::ConstructL() const + { + IRLOG_DEBUG( "CIRDataTransferTracker::ConstructL" ); + return; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CIRDataTransferTracker::~CIRDataTransferTracker() + { + IRLOG_DEBUG( "CIRDataTransferTracker::~CIRDataTransferTracker - Entering" ); + iObserver = NULL; + IRLOG_DEBUG( "CIRDataTransferTracker::~CIRDataTransferTracker - Exiting" ); + + } + +// --------------------------------------------------------------------------- +// From class MIRDataTransferTracker. +// Sets the observer. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::SetObserver( MIRDataTransferObserver* aObserver ) + { + IRLOG_DEBUG( "CIRDataTransferTracker::SetObserver - Entering" ); + iObserver = aObserver; + IRLOG_DEBUG( "CIRDataTransferTracker::SetObserver - Exiting" ); + } + +// --------------------------------------------------------------------------- +// From class MIRDataTransferTracker. +// Returns the current transferred data amounts. +// --------------------------------------------------------------------------- +// +const MIRDataTransferTracker::TIRDataTransferPckg& CIRDataTransferTracker::TransferredData() const + { + IRLOG_DEBUG( "CIRDataTransferTracker::TIRDataTransferPckg" ); + return iPckg; + } + +// --------------------------------------------------------------------------- +// From class MIRDataTransferTracker. +// Binds this to track the supplied HTTP session. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::BindL( RHTTPSession aSession, TIRTransferCategory aCategory ) + { + IRLOG_DEBUG2( "CIRDataTransferTracker::BindL() - aCategory = %d", static_cast( aCategory ) ); + + aSession.ConnectionInfo().SetPropertyL( + aSession.StringPool().StringF( HTTP::ESessionId, aSession.GetTable() ), + THTTPHdrVal( aCategory ) ); + aSession.FilterCollection().AddFilterL( + *this, THTTPEvent::EAnyTransactionEvent, MHTTPFilter::EClientFilters, RStringF() ); + IRLOG_DEBUG( "CIRDataTransferTracker::BindL - Exiting" ); + } + +// --------------------------------------------------------------------------- +// From class MIRDataTransferTracker. +// Handles raw data transfers. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::RawDataTransferredL( TInt aBytesSent, TInt aBytesReceived, + TIRTransferCategory aCategory ) + { + IRLOG_DEBUG( "CIRDataTransferTracker::RawDataTransferredL - Entering" ); + ProcessDataL( aBytesSent, aBytesReceived, aCategory ); + IRLOG_DEBUG( "CIRDataTransferTracker::RawDataTransferredL - Exiting" ); + } + +// --------------------------------------------------------------------------- +// From class MHTTPFilter. +// Invoked when HTTP transactions are sent or received. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::MHFRunL( const RHTTPTransaction aTransaction, const THTTPEvent& aEvent ) + { + IRLOG_DEBUG2( "CIRDataTransferTracker::MHFRunL() - aEvent.iStatus = %d", aEvent.iStatus ); + + RHTTPSession session = aTransaction.Session(); + + THTTPHdrVal categoryVal; + + if ( session.ConnectionInfo().Property( + session.StringPool().StringF( HTTP::ESessionId, session.GetTable() ), categoryVal ) ) + { + TIRTransferCategory category = static_cast( categoryVal.Int() ); + + switch ( aEvent.iStatus ) + { + case THTTPEvent::EGotResponseHeaders: + ParseHeaderSizeL( aTransaction, category ); + break; + case THTTPEvent::EGotResponseBodyData: + ParseBodySizeL( aTransaction, category ); + break; + default: + break; + } + } + IRLOG_DEBUG( "CIRDataTransferTracker::MHFRunL - Exiting" ); + } + +// --------------------------------------------------------------------------- +// Calculates the header field sizes in bytes from the specified headers. +// --------------------------------------------------------------------------- +// +TInt CIRDataTransferTracker::HeaderSize( const RHTTPTransaction aTransaction, + RHTTPHeaders aHeaders ) + { + IRLOG_DEBUG( "CIRDataTransferTracker::HeaderSize - Entering" ); + TInt size = KVRBytesPerHeaderOverhead; + + RStringPool stringPool = aTransaction.Session().StringPool(); + + THTTPHdrFieldIter it = aHeaders.Fields(); + it.First(); + + while ( !it.AtEnd() ) + { + RStringF key = stringPool.StringF( it() ); + + TPtrC8 ptr; + aHeaders.GetRawField( key, ptr ); + + size += key.DesC().Size(); + size += ptr.Size(); + size += KVRBytesPerHeaderFieldOverhead; + + ++it; + } + IRLOG_DEBUG( "CIRDataTransferTracker::HeaderSize - Exiting" ); + return size; + + } + +// --------------------------------------------------------------------------- +// Parses the header sizes ( both request and response ) of the supplied HTTP +// transaction, logging it under the specified category. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::ParseHeaderSizeL( const RHTTPTransaction aTransaction, + TIRTransferCategory aCategory ) + { + IRLOG_DEBUG2( "CIRDataTransferTracker::ParseHeaderSizeL() - aCategory = %d", static_cast( aCategory ) ); + + RHTTPSession session = aTransaction.Session(); + + // Parse the request size first. + + RHTTPRequest request = aTransaction.Request(); + TInt sent = HeaderSize( aTransaction, request.GetHeaderCollection() ); + + // Now that the actual header fields are parsed we have to manually extract the original request. + // The format of the request is "%S %S %S\r\n", where the first string is the method ( GET or POST ), + // the second is the full URI of the request, and the third the HTTP protocol version in use. + + RStringF http = session.StringPool().StringF( HTTP::EHttp11, session.GetTable() ); + + sent += request.Method().DesC().Size(); + sent += request.URI().UriDes().Size(); + sent += http.DesC().Size(); + sent += KVRBytesPerHeaderSentOverhead; + + // Proceed to parse the response size. + + RHTTPResponse response = aTransaction.Response(); + TInt received = HeaderSize( aTransaction, response.GetHeaderCollection() ); + + // Now that the actual header fields of the response are parsed, we have to manually extract the + // original response. The format of the response is "%S %d %S\r\n", where the first string is the HTTP + // protocol version, the first integer is the HTTP status code, and the second string is the + // status text. + + TBuf8 responseCode; + responseCode.AppendNum( static_cast( response.StatusCode() ) ); + + received += session.StringPool().StringF( HTTP::EHttp11, session.GetTable() ).DesC().Size(); + received += responseCode.Size(); // Contains the byte for the trailing space as is, so need not add it as overhead below. + received += response.StatusText().DesC().Size(); + received += KVRBytesPerHeaderReceivedOverhead; + + ProcessDataL( sent, received, aCategory ); + IRLOG_DEBUG( "CIRDataTransferTracker::ParseHeaderSizeL - Exiting" ); + + } + +// --------------------------------------------------------------------------- +// Parses the body size of the supplied HTTP transaction, logging it under the specified category. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::ParseBodySizeL(const RHTTPTransaction aTransaction, + TIRTransferCategory aCategory ) + { + IRLOG_DEBUG2( "CIRDataTransferTracker::ParseBodySizeL() - aCategory = %d", static_cast( aCategory ) ); + + ASSERT( aTransaction.Response().HasBody() ); + + TPtrC8 ptr; + aTransaction.Response().Body()->GetNextDataPart( ptr ); + + ProcessDataL( 0, ptr.Size(), aCategory ); + IRLOG_DEBUG( "CIRDataTransferTracker::ParseBodySizeL - Exiting" ); + } + +// --------------------------------------------------------------------------- +// Processes raw data sent and/or received via the connection. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::ProcessDataL( TInt aBytesSent, TInt aBytesReceived, + TIRTransferCategory aCategory ) + { + IRLOG_DEBUG4( "CIRDataTransferTracker::ProcessDataL() - aBytesSent = %d, aBytesReceived = %d, aCategory = %d", + aBytesSent, aBytesReceived, static_cast( aCategory ) ); + + switch ( aCategory ) + { + case MIRDataTransferTracker::EIRTransferCategoryIsds: + iPckg.iBytesSentIsds += aBytesSent; + iPckg.iBytesReceivedIsds += aBytesReceived; + break; + case MIRDataTransferTracker::EIRTransferCategoryAudio: + iPckg.iBytesSentAudio += aBytesSent; + iPckg.iBytesReceivedAudio += aBytesReceived; + break; + default: + iPckg.iBytesSentUnknown += aBytesSent; + iPckg.iBytesReceivedUnknown += aBytesReceived; + break; + } + + iPckg.iBytesSentTotal += aBytesSent; + iPckg.iBytesReceivedTotal += aBytesReceived; + + iBytesSinceLastNotification += aBytesSent + aBytesReceived; + + DispatchNotificationL(); + IRLOG_DEBUG( "CIRDataTransferTracker::ProcessDataL() - Exiting" ); + } + +// --------------------------------------------------------------------------- +// Dispatches the notification of the data transfer conditionally. +// --------------------------------------------------------------------------- +// +void CIRDataTransferTracker::DispatchNotificationL() + { + IRLOG_DEBUG2( "CIRDataTransferTracker::DispatchNotificationL() - iBytesSinceLastNotif = %d", + iBytesSinceLastNotification ); + + // Set flag when Byte Counter crosses first threshold 0.1 MB + if ( bThresholdCrossed == EFalse && + ( iPckg.iBytesSentTotal+iPckg.iBytesReceivedTotal ) >= KIRDataTransferTrackerThreshold ) + bThresholdCrossed = ETrue; + + // Smooth updates to each 0.01 MB + if ( /*bThresholdCrossed == EFalse &&*/ iBytesSinceLastNotification >= KIRDataTransferTrackerMiniThreshold) + { + if ( iObserver ) + { + iObserver->HandleDataTransferEventL( iPckg ); + } + iBytesSinceLastNotification = 0; + } + + + // Streaming updates to each 0.1 MB afterwards + else if ( iBytesSinceLastNotification >= KIRDataTransferTrackerThreshold ) + { + if ( iObserver ) + { + iObserver->HandleDataTransferEventL( iPckg ); + } + iBytesSinceLastNotification = 0; + } + IRLOG_DEBUG( "CIRDataTransferTracker::DispatchNotificationL() - Exiting" ); + + }