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