internetradio2.0/networkcontrollersrc/irdatatransfertracker.cpp
changeset 14 896e9dbc5f19
parent 12 608f67c22514
child 15 065198191975
equal deleted inserted replaced
12:608f67c22514 14:896e9dbc5f19
     1 /*
       
     2 * Copyright (c) 2008-2008 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Tracks data transmitted through a network connection.
       
    15 *
       
    16 */
       
    17 
       
    18 #include <httpstringconstants.h>
       
    19 #include <mhttpdatasupplier.h>
       
    20 #include <rhttpheaders.h>
       
    21 #include "irdebug.h"
       
    22 
       
    23 #include "irdatatransfertracker.h"
       
    24 
       
    25 // The threshold in bytes after which notifications are sent to observers.
       
    26 const TInt KIRDataTransferTrackerThreshold = 104858;	// 0.1  MB = 104857.6 bytes (rounded)
       
    27 const TInt KIRDataTransferTrackerMiniThreshold = 1049;	// 0.01 MB = 1048.57 bytes (rounded)
       
    28 
       
    29 // The overhead in bytes per one HTTP header.
       
    30 const TInt KVRBytesPerHeaderOverhead = 2; // "\r\n"
       
    31 // The overhead in bytes per one header field in a request.
       
    32 const TInt KVRBytesPerHeaderFieldOverhead = 4; // ": \r\n"
       
    33 // The overhead in bytes per one header sent.
       
    34 const TInt KVRBytesPerHeaderSentOverhead = 4; // "  \r\n"
       
    35 // The overhead in bytes per one header received.
       
    36 const TInt KVRBytesPerHeaderReceivedOverhead = 3; // " \r\n"
       
    37 
       
    38 // ---------------------------------------------------------------------------
       
    39 // Two-phased constructor.
       
    40 // ---------------------------------------------------------------------------
       
    41 //
       
    42 CIRDataTransferTracker* CIRDataTransferTracker::NewL()
       
    43     {
       
    44 	IRLOG_DEBUG( "CIRDataTransferTracker::NewL - Entering");
       
    45     CIRDataTransferTracker* self = new ( ELeave ) CIRDataTransferTracker;
       
    46     CleanupStack::PushL( self );
       
    47     self->ConstructL();
       
    48     CleanupStack::Pop( self );
       
    49 	IRLOG_DEBUG( "CIRDataTransferTracker::NewL - Exiting");
       
    50     return self;
       
    51     }
       
    52 
       
    53 // ---------------------------------------------------------------------------
       
    54 // Constructor.
       
    55 // ---------------------------------------------------------------------------
       
    56 //
       
    57 CIRDataTransferTracker::CIRDataTransferTracker()
       
    58     {
       
    59 	IRLOG_DEBUG( "CIRDataTransferTracker::CIRDataTransferTracker - Entering");
       
    60 	bThresholdCrossed = EFalse;
       
    61 	IRLOG_DEBUG( "CIRDataTransferTracker::CIRDataTransferTracker - Exiting");
       
    62     }
       
    63 
       
    64 // ---------------------------------------------------------------------------
       
    65 // Second-phase constructor.
       
    66 // ---------------------------------------------------------------------------
       
    67 //
       
    68 void CIRDataTransferTracker::ConstructL() const
       
    69     {
       
    70     IRLOG_DEBUG( "CIRDataTransferTracker::ConstructL");
       
    71 	return;
       
    72     }
       
    73 
       
    74 // ---------------------------------------------------------------------------
       
    75 // Destructor.
       
    76 // ---------------------------------------------------------------------------
       
    77 //
       
    78 CIRDataTransferTracker::~CIRDataTransferTracker()
       
    79     {
       
    80     	IRLOG_DEBUG( "CIRDataTransferTracker::~CIRDataTransferTracker - Entering");
       
    81     	iObserver = NULL;
       
    82         IRLOG_DEBUG( "CIRDataTransferTracker::~CIRDataTransferTracker - Exiting");
       
    83 
       
    84     }
       
    85 
       
    86 // ---------------------------------------------------------------------------
       
    87 // From class MIRDataTransferTracker.
       
    88 // Sets the observer.
       
    89 // ---------------------------------------------------------------------------
       
    90 //
       
    91 void CIRDataTransferTracker::SetObserver( MIRDataTransferObserver* aObserver )
       
    92     {
       
    93     IRLOG_DEBUG( "CIRDataTransferTracker::SetObserver - Entering");
       
    94     iObserver = aObserver;
       
    95     IRLOG_DEBUG( "CIRDataTransferTracker::SetObserver - Exiting");
       
    96     }
       
    97 
       
    98 // ---------------------------------------------------------------------------
       
    99 // From class MIRDataTransferTracker.
       
   100 // Returns the current transferred data amounts.
       
   101 // ---------------------------------------------------------------------------
       
   102 //
       
   103 const MIRDataTransferTracker::TIRDataTransferPckg& CIRDataTransferTracker::TransferredData() const
       
   104     {
       
   105     IRLOG_DEBUG( "CIRDataTransferTracker::TIRDataTransferPckg");
       
   106     return iPckg;
       
   107     }
       
   108 
       
   109 // ---------------------------------------------------------------------------
       
   110 // From class MIRDataTransferTracker.
       
   111 // Binds this to track the supplied HTTP session.
       
   112 // ---------------------------------------------------------------------------
       
   113 //
       
   114 void CIRDataTransferTracker::BindL( RHTTPSession aSession, TIRTransferCategory aCategory )
       
   115     {
       
   116     IRLOG_DEBUG2( "CIRDataTransferTracker::BindL() - aCategory = %d", static_cast<TInt>( aCategory ) );
       
   117 
       
   118     aSession.ConnectionInfo().SetPropertyL(
       
   119         aSession.StringPool().StringF( HTTP::ESessionId, aSession.GetTable() ), 
       
   120         	THTTPHdrVal( aCategory ) );
       
   121     aSession.FilterCollection().AddFilterL(
       
   122         *this, THTTPEvent::EAnyTransactionEvent, MHTTPFilter::EClientFilters, RStringF() );
       
   123     IRLOG_DEBUG( "CIRDataTransferTracker::BindL - Exiting");
       
   124     }
       
   125 
       
   126 // ---------------------------------------------------------------------------
       
   127 // From class MIRDataTransferTracker.
       
   128 // Handles raw data transfers.
       
   129 // ---------------------------------------------------------------------------
       
   130 //
       
   131 void CIRDataTransferTracker::RawDataTransferredL( TInt aBytesSent, TInt aBytesReceived, 
       
   132 												  TIRTransferCategory aCategory )
       
   133     {
       
   134     IRLOG_DEBUG( "CIRDataTransferTracker::RawDataTransferredL - Entering");
       
   135     ProcessDataL( aBytesSent, aBytesReceived, aCategory );
       
   136     IRLOG_DEBUG( "CIRDataTransferTracker::RawDataTransferredL - Exiting");
       
   137     }
       
   138 
       
   139 // ---------------------------------------------------------------------------
       
   140 // From class MHTTPFilter.
       
   141 // Invoked when HTTP transactions are sent or received.
       
   142 // ---------------------------------------------------------------------------
       
   143 //
       
   144 void CIRDataTransferTracker::MHFRunL(const RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
       
   145     {
       
   146     IRLOG_DEBUG2( "CIRDataTransferTracker::MHFRunL() - aEvent.iStatus = %d", aEvent.iStatus );
       
   147 
       
   148     RHTTPSession session = aTransaction.Session();
       
   149 
       
   150     THTTPHdrVal categoryVal;
       
   151 
       
   152     if( session.ConnectionInfo().Property(
       
   153         session.StringPool().StringF( HTTP::ESessionId, session.GetTable() ), categoryVal ) )
       
   154         {
       
   155         TIRTransferCategory category = static_cast<TIRTransferCategory>( categoryVal.Int() );
       
   156 
       
   157         switch ( aEvent.iStatus )
       
   158             {
       
   159             case THTTPEvent::EGotResponseHeaders:
       
   160                 ParseHeaderSizeL( aTransaction, category );
       
   161                 break;
       
   162             case THTTPEvent::EGotResponseBodyData:
       
   163                 ParseBodySizeL( aTransaction, category );
       
   164                 break;
       
   165             default:
       
   166                 break;
       
   167             }
       
   168         }
       
   169     IRLOG_DEBUG( "CIRDataTransferTracker::MHFRunL - Exiting");
       
   170     }
       
   171 
       
   172 // ---------------------------------------------------------------------------
       
   173 // Calculates the header field sizes in bytes from the specified headers.
       
   174 // ---------------------------------------------------------------------------
       
   175 //
       
   176 TInt CIRDataTransferTracker::HeaderSize( const RHTTPTransaction aTransaction, 
       
   177 										 RHTTPHeaders aHeaders )
       
   178     {
       
   179     IRLOG_DEBUG( "CIRDataTransferTracker::HeaderSize - Entering");
       
   180     TInt size = KVRBytesPerHeaderOverhead;
       
   181 
       
   182     RStringPool stringPool = aTransaction.Session().StringPool();
       
   183 
       
   184     THTTPHdrFieldIter it = aHeaders.Fields();
       
   185     it.First();
       
   186 
       
   187     while ( !it.AtEnd() )
       
   188         {
       
   189         RStringF key = stringPool.StringF( it() );
       
   190 
       
   191         TPtrC8 ptr;
       
   192         aHeaders.GetRawField( key, ptr );
       
   193 
       
   194         size += key.DesC().Size();
       
   195         size += ptr.Size();
       
   196         size += KVRBytesPerHeaderFieldOverhead;
       
   197 
       
   198         ++it;
       
   199         }
       
   200     IRLOG_DEBUG( "CIRDataTransferTracker::HeaderSize - Exiting");
       
   201     return size;
       
   202 
       
   203     }
       
   204 
       
   205 // ---------------------------------------------------------------------------
       
   206 // Parses the header sizes (both request and response) of the supplied HTTP
       
   207 // transaction, logging it under the specified category.
       
   208 // ---------------------------------------------------------------------------
       
   209 //
       
   210 void CIRDataTransferTracker::ParseHeaderSizeL( const RHTTPTransaction aTransaction, 
       
   211 								   			   TIRTransferCategory aCategory )
       
   212     {
       
   213     IRLOG_DEBUG2( "CIRDataTransferTracker::ParseHeaderSizeL() - aCategory = %d", static_cast<TInt>( aCategory ) );
       
   214 
       
   215     RHTTPSession session = aTransaction.Session();
       
   216 
       
   217     // Parse the request size first.
       
   218 
       
   219     RHTTPRequest request = aTransaction.Request();
       
   220     TInt sent = HeaderSize( aTransaction, request.GetHeaderCollection() );
       
   221 
       
   222     // Now that the actual header fields are parsed we have to manually extract the original request.
       
   223     // The format of the request is "%S %S %S\r\n", where the first string is the method (GET or POST),
       
   224     // the second is the full URI of the request, and the third the HTTP protocol version in use.
       
   225 
       
   226     RStringF http = session.StringPool().StringF( HTTP::EHttp11, session.GetTable() );
       
   227 
       
   228     sent += request.Method().DesC().Size();
       
   229     sent += request.URI().UriDes().Size();
       
   230     sent += http.DesC().Size();
       
   231     sent += KVRBytesPerHeaderSentOverhead;
       
   232 
       
   233     // Proceed to parse the response size.
       
   234 
       
   235     RHTTPResponse response = aTransaction.Response();
       
   236     TInt received = HeaderSize( aTransaction, response.GetHeaderCollection() );
       
   237 
       
   238     // Now that the actual header fields of the response are parsed, we have to manually extract the
       
   239     // original response. The format of the response is "%S %d %S\r\n", where the first string is the HTTP
       
   240     // protocol version, the first integer is the HTTP status code, and the second string is the
       
   241     // status text.
       
   242 
       
   243     TBuf8<KDefaultRealWidth> responseCode;
       
   244     responseCode.AppendNum( static_cast<TInt64>( response.StatusCode() ) );
       
   245 
       
   246     received += session.StringPool().StringF( HTTP::EHttp11, session.GetTable() ).DesC().Size();
       
   247     received += responseCode.Size(); // Contains the byte for the trailing space as is, so need not add it as overhead below.
       
   248     received += response.StatusText().DesC().Size();
       
   249     received += KVRBytesPerHeaderReceivedOverhead;
       
   250 
       
   251     ProcessDataL( sent, received, aCategory );
       
   252     IRLOG_DEBUG( "CIRDataTransferTracker::ParseHeaderSizeL - Exiting");
       
   253 
       
   254     }
       
   255 
       
   256 // ---------------------------------------------------------------------------
       
   257 // Parses the body size of the supplied HTTP transaction, logging it under the specified category.
       
   258 // ---------------------------------------------------------------------------
       
   259 //
       
   260 void CIRDataTransferTracker::ParseBodySizeL(const RHTTPTransaction aTransaction, 
       
   261 											TIRTransferCategory aCategory )
       
   262     {
       
   263     IRLOG_DEBUG2( "CIRDataTransferTracker::ParseBodySizeL() - aCategory = %d", static_cast<TInt>(aCategory) );
       
   264 
       
   265     ASSERT( aTransaction.Response().HasBody() );
       
   266 
       
   267     TPtrC8 ptr;
       
   268     aTransaction.Response().Body()->GetNextDataPart( ptr );
       
   269 
       
   270     ProcessDataL( 0, ptr.Size(), aCategory );
       
   271     IRLOG_DEBUG( "CIRDataTransferTracker::ParseBodySizeL - Exiting");
       
   272     }
       
   273 
       
   274 // ---------------------------------------------------------------------------
       
   275 // Processes raw data sent and/or received via the connection.
       
   276 // ---------------------------------------------------------------------------
       
   277 //
       
   278 void CIRDataTransferTracker::ProcessDataL( TInt aBytesSent, TInt aBytesReceived, 
       
   279 										   TIRTransferCategory aCategory )
       
   280     {
       
   281     IRLOG_DEBUG4( "CIRDataTransferTracker::ProcessDataL() - aBytesSent = %d, aBytesReceived = %d, aCategory = %d",
       
   282         aBytesSent, aBytesReceived, static_cast<TInt>(aCategory) );
       
   283 
       
   284     switch ( aCategory )
       
   285         {
       
   286         case MIRDataTransferTracker::EIRTransferCategoryIsds:
       
   287             iPckg.iBytesSentIsds += aBytesSent;
       
   288             iPckg.iBytesReceivedIsds += aBytesReceived;
       
   289             break;
       
   290         case MIRDataTransferTracker::EIRTransferCategoryAudio:
       
   291             iPckg.iBytesSentAudio += aBytesSent;
       
   292             iPckg.iBytesReceivedAudio += aBytesReceived;
       
   293             break;
       
   294         default:
       
   295             iPckg.iBytesSentUnknown += aBytesSent;
       
   296             iPckg.iBytesReceivedUnknown += aBytesReceived;
       
   297             break;
       
   298         }
       
   299 
       
   300     iPckg.iBytesSentTotal += aBytesSent;
       
   301     iPckg.iBytesReceivedTotal += aBytesReceived;
       
   302 
       
   303     iBytesSinceLastNotification += aBytesSent + aBytesReceived;
       
   304 
       
   305     DispatchNotificationL();
       
   306     IRLOG_DEBUG( "CIRDataTransferTracker::ProcessDataL() - Exiting");
       
   307     }
       
   308 
       
   309 // ---------------------------------------------------------------------------
       
   310 // Dispatches the notification of the data transfer conditionally.
       
   311 // ---------------------------------------------------------------------------
       
   312 //
       
   313 void CIRDataTransferTracker::DispatchNotificationL()
       
   314     {
       
   315     IRLOG_DEBUG2( "CIRDataTransferTracker::DispatchNotificationL() - iBytesSinceLastNotif = %d",
       
   316         iBytesSinceLastNotification );
       
   317 
       
   318 	// Set flag when Byte Counter crosses first threshold 0.1 MB
       
   319 	if( bThresholdCrossed == EFalse && 
       
   320 		(iPckg.iBytesSentTotal+iPckg.iBytesReceivedTotal) >= KIRDataTransferTrackerThreshold )
       
   321 		bThresholdCrossed = ETrue;
       
   322 
       
   323 	// Smooth updates to each 0.01 MB
       
   324 	if( /*bThresholdCrossed == EFalse &&*/ iBytesSinceLastNotification >= KIRDataTransferTrackerMiniThreshold)
       
   325         {
       
   326         if ( iObserver )
       
   327             {
       
   328             iObserver->HandleDataTransferEventL( iPckg );
       
   329             }
       
   330         iBytesSinceLastNotification = 0;
       
   331         }
       
   332 
       
   333 
       
   334 	// Streaming updates to each 0.1 MB afterwards
       
   335     else if ( iBytesSinceLastNotification >= KIRDataTransferTrackerThreshold )
       
   336         {
       
   337         if ( iObserver )
       
   338             {
       
   339             iObserver->HandleDataTransferEventL( iPckg );
       
   340             }
       
   341         iBytesSinceLastNotification = 0;
       
   342         }
       
   343     IRLOG_DEBUG( "CIRDataTransferTracker::DispatchNotificationL() - Exiting");
       
   344 
       
   345     }