cellularsrvapitest/datatransferhaitest/esock/src/T_RSocketData.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 23:59:33 +0200
branchRCL_3
changeset 9 962e6306d9d2
parent 0 3553901f7fa8
child 24 6638e7f4bd8f
permissions -rw-r--r--
Revision: 201007 Kit: 201007

/*
* Copyright (c) 2005-2009 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:
*
*/


#include "T_RSocketData.h"
#include "T_RHostResolverData.h"
#include <e32property.h>
#include <etelmm.h>   // RMobilePhone
#include <etelpckt.h> // RPacketService


const TInt KBufferSize = 1024;
_LIT( KNoFileSave, "NULL" );
const TUint KNoDataDealer = 0;
const TInt KNoDuration = -1;
const TInt KNoSpeedCheck = -1;

// Misc Types
_LIT( KProtocolHTTP,   "HTTP" );
_LIT( KOff,            "Off" );        // Can be used every2*where off is needed

// HSDPA checks
_LIT( KHsdpaIndicator, "Indicator" );  // Operator supports
_LIT( KHsdpaSupported, "Supported" );  // Device supports
_LIT( KHsdpaInUse,     "Used" );       // In use during PSD

// Constants for creating a HTTP request.
_LIT8(KHTTPGET, 		"GET");
_LIT8(KHTTPSeparator, 	" ");
_LIT8(KHTTPSuffix, 		"HTTP/1.0");
_LIT8(KEmptyLine, 		"\r\n\r\n");
const TInt KEmptySize = 4;

const TInt KHTTPSize = 17;
const TInt KMaxTag = 256;
const TInt KHeaderWithoutData=200;
//
// Manually created HTTP Post request is difficult to maintain.
// Request and server responce is logged into file during test run.
_LIT8(KHTTPPOST, "POST");
_LIT8(KLineBreak, "\r\n");

_LIT8(KAhti, "Ahti");

_LIT8(KServerScript, 	"/dy/upload/upfile.php");
_LIT8(KFrom, 			"From:");
_LIT8(KHost, 			"Host:");
_LIT8(KContentType, 	"Content-Type:");
_LIT8(KContentLength, 	"Content-Length:");
_LIT8(KContentDisposition, "Content-Disposition:");

_LIT8(KMultipartType, "multipart/form-data;");
_LIT8(KOctetType,     "application/octet-stream");
_LIT8(KBoundary,      "boundary=---------------------------sg976436h73");
_LIT8(KBoundaryStart, "-----------------------------sg976436h73");
_LIT8(KBoundaryEnd,   "-----------------------------sg976436h73--");
_LIT8(KDisposition,   "form-data; name=\"userfile\"; filename=\"test.bin\"");

_LIT( KPropertyCategory, 		"PropertyCategory");
_LIT( KPropertyKey,				"PropertyKey");
_LIT( KMaxPropertyLength,		"PropertyLength");

//const TInt 
_LIT( KPort,         					"Port" );
_LIT( KAddress,      					"Address" );
_LIT( KProtocol,     					"Protocol" );
_LIT( KFileName,     					"File" );
_LIT( KSaveName,     					"Save" );
_LIT( KDataDealerID, 					"DataDealer" );    // Data dealer ID is given may not be 0
_LIT( KHsdpaCheck,   					"HSDPA" );         // HSDPA check can be done several ways
_LIT( KDuration,     					"Duration" );      // How long should i.e. download last when it is stopped (THRO)
_LIT( KMinimumSpeed, 					"MinSpeed" );      // Data transfer must be faster than MinSpeed
_LIT( KBytes,        					"Bytes" );         // How many bytes are send
_LIT( KResponseLogFile,					"ResponseLogFile");
_LIT( KRequestLogFile,					"RequestLogFile");
//LIT's to read from ini file
_LIT( KDefaultSection,					"Default");
_LIT(KRConnection, 						"RConnection");
_LIT(KRSocketServ,						"RSocketServ");
_LIT(KRHostResolver,					"RHostResolver");
_LIT(KRMobilePhone,						"RMobilePhone");

/*@}*/

/*@{*/
//LIT's for commands
_LIT(KCmdRSocketOpen,							"Open");
_LIT(KCmdRSocketClose,							"Close");
_LIT(KCmdRSocketConnect, 						"Connect");
_LIT(KCmdRSocketShutDown,						"ShutDown");
_LIT(KCmdRSocketWrite,							"Write");
_LIT(KCmdResponseFromServer, 					"ResponseFromServer");
_LIT(KWriteRequest,								"WriteRequest");
_LIT(KCmdUtilityStartFile,						"StartFile");
_LIT(KCmdUtilityStartDealer,					"StartDealer");
_LIT(KCmdUtilityCheckHSDPA,						"CheckHSDPA");
_LIT(KCmdRecvOneOrMore,							"RecvOneOrMore");
_LIT(KCmdUtilityEndFile,						"EndFile");
_LIT(KCmdUtilityCalcDnloadStats,				"CalcDnloadStats");
_LIT(KCmdUtilityBuildRequest,					"BuildRequest");
_LIT(KCmdSendBytesToSocket,						"SendBytesToSocket");
_LIT(KCmdUtilityEndRequest,						"EndRequest");
_LIT(KCmdInfo,									"Info");
/*@}*/


/**
 * Two phase constructor
 */
CT_RSocketData* CT_RSocketData::NewL()
	{
	CT_RSocketData*	ret=new (ELeave) CT_RSocketData();
	CleanupStack::PushL(ret);
	ret->ConstructL();	
	CleanupStack::Pop(ret);
	return ret;
	}

/**
* Protected constructor. First phase construction
*/
CT_RSocketData::CT_RSocketData():
	iSocket(NULL),    
	iActiveCallback(NULL),
	iBreathSaver(NULL)
	{
	}

CT_RSocketData::~CT_RSocketData()
	{
	if(iBreathSaver)
		{
		delete iBreathSaver;
		iBreathSaver = NULL;
		}
	if(iActiveCallback)
		{
		delete iActiveCallback;
		iActiveCallback = NULL;
		}	
	if(iSocket)
		{
		delete iSocket;
		iSocket = NULL;
		}
	}

void CT_RSocketData::ConstructL()
	{
	iActiveCallback = CActiveCallback::NewL(*this);
	iBreathSaver = CBreathSaver::NewL();
	iSocket = new (ELeave)RSocket();
	}

void CT_RSocketData::InitialiseL()
	{
	CDataWrapperBase::InitialiseL();
	
	TInt propertyCategory;
	GetHexFromConfig(KDefaultSection, KPropertyCategory, propertyCategory);
	iPropertyCategory.iUid = propertyCategory;
	
	TInt propertyKey;
	GetIntFromConfig(KDefaultSection, KPropertyKey, propertyKey );
	iPropertyKey =(TUint)propertyKey;
	
	GetIntFromConfig(KDefaultSection, KMaxPropertyLength, iMaxPropertyLength );
	
	}



/**
	* Process a command read from the ini file
	*
	* @param aCommand			The command to process
	* @param aSection			The section in the ini containing data for the command
	* @param aAsyncErrorIndex	Command index for async calls to return errors to
	*
	* @return					ETrue if the command is processed
	*
	* @leave					System wide error
	*/
TBool CT_RSocketData::DoCommandL(const TTEFFunction& aCommand, const TTEFSectionName& aSection, const TInt aAsyncErrorIndex)
	{
	TBool retVal=ETrue;
	
	if (aCommand==KCmdRSocketOpen)
		{	
		DoCmdOpenL(aSection);
		}
	else if (aCommand==KCmdRSocketConnect)
		{
		DoCmdConnectL(aSection, aAsyncErrorIndex);
		}
	else if (aCommand==KCmdRSocketShutDown)
		{
		DoCmdShutDown(aAsyncErrorIndex);
		}
	else if (aCommand==KCmdRSocketClose)
		{
		DoCmdClose();
		}
	else if ( aCommand == KWriteRequest )
		{		
		DoCmdWriteRequest(aSection, aAsyncErrorIndex);
		}
	else if ( aCommand == KCmdUtilityStartFile )
		{
		DoCmdUtilityStartFile(aSection);
		}
	else if (aCommand == KCmdUtilityStartDealer )
		{
		DoCmdUtilityStartDealer(aSection);
		}
	else if (aCommand == KCmdUtilityCheckHSDPA )
		{
		DoCmdUtilityCheckHSDPAL(aSection);
		}
	else if (aCommand==KCmdRecvOneOrMore)
		{
		DoCmdRecvOneOrMore(aSection);
		}
	else if (aCommand == KCmdUtilityEndFile )
		{
		DoCmdUtilityEndFile(aSection);		
		}
	else if (aCommand == KCmdUtilityCalcDnloadStats )
		{
		DoCmdUtilityCalculateDownloadStats(aSection);		
		}
	else if (aCommand==KCmdUtilityBuildRequest)
		{
		DoCmdUtilityBuildRequest(aSection);
		}
	else if (aCommand==KCmdRSocketWrite)
		{
		DoCmdWrite(aAsyncErrorIndex);
		}
	else if (aCommand==KCmdSendBytesToSocket)
		{
		DoCmdSendBytesToSocket(aSection);
		}
	else if (aCommand==KCmdResponseFromServer)
		{
		DoCmdResponseFromServer(aSection);
		}
	else if (aCommand==KCmdUtilityEndRequest)
		{
		DoCmdUtilityEndRequest();
		}
	else if (aCommand==KCmdInfo)
		{
		DoCmdInfoL(aSection);
		}
	else
		{
		ERR_PRINTF1(_L("Unknown command"));
		retVal=EFalse;
		}

	return retVal;
	}
	
/**
	* Return a pointer to the object that the data wraps
	*
	* @return pointer to the object that the data wraps
	*/
TAny* CT_RSocketData::GetObject()
	{
	return iSocket;
	}
	

void CT_RSocketData::RunL(CActive* aActive, TInt aIndex)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::RunL"));
	DecOutstanding(); // One of the async calls has completed 
    
	if(aActive == iActiveCallback)
		{
		INFO_PRINTF1(_L("Asynchronous task has completed. RunL  called"));
		}
	else
		{ 
		ERR_PRINTF1(_L("Stray RunL signal"));
		TInt err = aActive->iStatus.Int(); 
		if( err != KErrNone )
			{
	        ERR_PRINTF2(_L("RunL Error %d"), err); 
	        SetAsyncError( aIndex, err );
			}
		}
	
	INFO_PRINTF1(_L("*END* CT_RSocketData::RunL"));
	}
	
/**
 * Opens a socket.
 * @param aSection - Section in config file to get a RSocketServer and RConnection
 * Sets TEF error if not successful.
 */	
void CT_RSocketData::DoCmdOpenL(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdOpenL"));
	TBool dataOk = ETrue;
	
	TPtrC connectionName;
	if ( !GetStringFromConfig(aSection, KRConnection(), connectionName) )
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KRConnection);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}

	TPtrC socketServName;
	if ( !GetStringFromConfig(aSection, KRSocketServ(), socketServName) )
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KRSocketServ);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}

	if (dataOk)
		{
		INFO_PRINTF1(_L("Create a RConnection for iSocket"));
		RConnection* connection = static_cast<RConnection*>(GetDataObjectL(connectionName));
		INFO_PRINTF1(_L("Create a RSocketServ for iSocket"));
		RSocketServ* socketServ = static_cast<RSocketServ*>(GetDataObjectL(socketServName));

		TInt error = iSocket->Open(*socketServ, KAfInet, KSockStream, KProtocolInetTcp, *connection);
		
		if (error == KErrNone)
			{
			INFO_PRINTF1(_L("Socket opening succeeded"));
			}
		else
			{
			ERR_PRINTF2(_L("Socket opening failed [%d]"), error);
			SetError(error);
			}
		}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdOpenL"));
	}

/**
 * Connects socket with a given address and port.
 * @param aSection			- The section in config file to look for the address, port and RHostResolver
 * @param aAsyncErrorIndex	- Command index for async calls to return errors to	
 */
void CT_RSocketData::DoCmdConnectL(const TTEFSectionName& aSection, const TInt aAsyncErrorIndex)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdConnectL"));
	TBool dataOk = ETrue;
	
	TInt port;
    if(!GetIntFromConfig( aSection, KPort, port ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KPort);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
    TPtrC address;
    if(!GetStringFromConfig( aSection, KAddress, address ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KAddress);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
	// Connect ready socket to given host and port number
	TPtrC hostResolverName;
	if(	!GetStringFromConfig(aSection, KRHostResolver, hostResolverName) )
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KRHostResolver);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
		}

	if (dataOk)
		{
		INFO_PRINTF3(_L("Connecting socket to server \"%S\" at port [%d]"), &address, port);
		
		CT_RHostResolverData* hostResolver = static_cast<CT_RHostResolverData*>(GetDataWrapperL(hostResolverName));
		iNameEntry = hostResolver->GetNameEntry();
		iNameEntry().iAddr.SetPort(port);
		iSocket->Connect(iNameEntry().iAddr, iActiveCallback->iStatus);
		iActiveCallback->Activate(aAsyncErrorIndex);
	    IncOutstanding();
		}

    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdConnectL"));
    }

/**
 * Shuts down a connected socket - asynchronous.
 * This method is asynchronous as non emergency shutdown may take a while.
 * The shut down method allows input and output to be individually stopped for a protocol endpoint. 
 * @param aAsyncErrorIndex - Command index for async calls to return errors to
 */
void CT_RSocketData::DoCmdShutDown(const TInt aAsyncErrorIndex)
    {
    INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdShutDownSocket"));

	// Shutdown the socket.
	iSocket->Shutdown(RSocket::ENormal, iActiveCallback->iStatus);
	iActiveCallback->Activate(aAsyncErrorIndex);
    IncOutstanding();

    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdShutDownSocket"));
    }

/**
 * Closes a socket.
 * If a socket has been opened using Open() then it should be closed using Close(). 
 * This will ensure all associated resources are released. 
 * Closing serves two distinct purposes: 
 * - To release resources associated with the IPC channel to the socket server. 
 * - To disconnect a socket if it is connected. 
 */
void CT_RSocketData::DoCmdClose()
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdCloseSocket"));
	iSocket->Close(); // Close does not return error code
    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdCloseSocket"));
    }


/**
 * Builds an HTTP Get request
 * @param  aSection - The section in config file to look for address, port, protocol, filename and save path.
 * @param aAsyncErrorIndex - Command index for async calls to return errors to
 */
void CT_RSocketData::DoCmdWriteRequest(const TTEFSectionName& aSection, const TInt aAsyncErrorIndex)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdWriteRequest"));
	TBool dataOk = ETrue;

	TPtrC filename; 
	if(!GetStringFromConfig(aSection, KFileName, filename ))
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KFileName);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
		}
	
	TPtrC protocol; 
    if(!GetStringFromConfig(aSection, KProtocol, protocol ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KProtocol);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
    
    // Send http get request
    if (dataOk && protocol != KProtocolHTTP)
        {
        ERR_PRINTF2(_L("Protocol \"%S\" is unknown"), &protocol);
        SetBlockResult(EFail);
        dataOk = EFalse;
        }

    if (dataOk && filename.Length() > KMaxTag)
        {
        ERR_PRINTF1(_L("Filename is too long, cannot send HTTP request"));
        SetBlockResult(EFail);
        dataOk = EFalse;
        }

    if (dataOk)
    	{
        INFO_PRINTF1(_L("Sending HTTP request"));

    	// Buffer that will hold the request.
    	TBuf8<KHTTPSize + KMaxTag> request;

    	// Construct the final request.
    	request.Append(KHTTPGET);
    	request.Append(KHTTPSeparator);
    	request.Append(filename);
    	request.Append(KHTTPSeparator);
    	request.Append(KHTTPSuffix);
    	request.Append(KEmptyLine);

        // Send the request through socket
    	iSocket->Write(request, iActiveCallback->iStatus);
    	iActiveCallback->Activate(aAsyncErrorIndex);
        IncOutstanding();
    	}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdWriteRequest"));
	}


/**
 * Uses helper class BreathSaver to generate a file and save downloaded data in a given path.
 * @param  aSection - The section in config file to look for address, port, protocol, filename and save path.
 * Sets TEF error if not successful.
 */
void CT_RSocketData::DoCmdUtilityStartFile(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityStartFile"));
	TBool dataOk = ETrue;
	
    TPtrC savename( KNoFileSave );
    if(!GetStringFromConfig(aSection, KSaveName, savename))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KSaveName);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	
    if ( dataOk && savename == KNoFileSave)
    	{
    	ERR_PRINTF1(_L("Incorrect file name"));
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
	if (dataOk)
		{
		INFO_PRINTF2(_L("Save incoming file to \"%S\""), &savename);
		TInt error = iBreathSaver->StartFile(savename);
	    
	    if (error != KErrNone)
	        {
	        ERR_PRINTF2(_L("Failed to save data file [%d]"), error);
	        SetError(error);
	        }
		}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityStartFile"));
    }
	
/**
 * Uses helper class BreathSaver to start a Data dealer
 * @param  aSection - The section in config file to look for Data Dealer ID.
 * Sets TEF error if not successful.
 */
void CT_RSocketData::DoCmdUtilityStartDealer(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityStartDealer"));
	TBool dataOk = ETrue;
	
	TUint datadealerid( KNoDataDealer );
    if(!GetUintFromConfig(aSection,  KDataDealerID, datadealerid ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDataDealerID);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	
    if (dataOk && datadealerid != KNoDataDealer)
		{
		INFO_PRINTF2(_L("Use data dealer with id (%u) for incoming file"), datadealerid);
		TInt error = iBreathSaver->StartDealer(datadealerid);
        
        if (error == KErrNone)
            {
            INFO_PRINTF1(_L("iBreathSaver->StartDealer(datadealerid) was executed"));
            }
        else
        	{
            ERR_PRINTF2(_L("Failed to use data dealer [%d]"), error);
            SetError(error);
        	}
		}
    
	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityStartDealer"));
	}
	


/**
 * Checks HSDPA options.
 * @param  aSection - The section in config file to look for HSDPA parameters.
 * @return error - Error code. KErrNone if successful.
 */
void CT_RSocketData::DoCmdUtilityCheckHSDPAL(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityCheckHSDPAL"));
	TBool dataOk = ETrue;

    TPtrC hsdpacheck( KNullDesC );
    if(!GetStringFromConfig(aSection, KHsdpaCheck, hsdpacheck))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KHsdpaCheck);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
    if (dataOk)
    	{
        TPtrC mobilePhoneName;
        RMobilePhone* mobilePhone = NULL;
        if(GetStringFromConfig(aSection, KRMobilePhone(), mobilePhoneName))
        	{
        	mobilePhone = static_cast<RMobilePhone*>(GetDataObjectL(mobilePhoneName));
        	}
        
        INFO_PRINTF1(_L( "Checking HSDPA..." ));

    	if (hsdpacheck == KNullDesC)
            {
            INFO_PRINTF1(_L( "No HSDPA used. Nothing to check." ));
            }
    	else if (hsdpacheck == KHsdpaIndicator)
            {
            if (CheckHSDPAIndicator())
                {
                INFO_PRINTF1(_L("HSDPA indicator available"));
                }
            else
                {
                ERR_PRINTF1(_L("HSDPA indicator not available"));
                SetBlockResult(EFail);
                }
            }
        else if (hsdpacheck == KHsdpaSupported && mobilePhone)
            {
            if (CheckHSDPASupportL(*mobilePhone))
            	{
            	INFO_PRINTF1(_L("HSDPA support available"));
            	}
            else
            	{
            	ERR_PRINTF1(_L("HSDPA support not available"));
            	SetBlockResult(EFail);
            	}
            }
        else if (hsdpacheck == KHsdpaInUse && mobilePhone)
            {
    		if (CheckHSDPAUsageL(*mobilePhone))
    			{
    			INFO_PRINTF1(_L("HSDPA in use"));
    			}
    		else
    			{
    			ERR_PRINTF1(_L("HSDPA not in use"));
    			SetBlockResult(EFail);
    			}
            }
        else if (hsdpacheck == KOff)
            {
            INFO_PRINTF1(_L("Can HSDPA be turned off?"));
            }
        else
            {
            ERR_PRINTF2(_L("Unknown HSDPA usage parameter \"%S\""), &hsdpacheck);
            SetBlockResult(EFail);
            }
    	}
    
	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityCheckHSDPAL"));
	}

/**
 * Downloads a file from a given address and saves it in specified path.
 * @param  aSection - The section in config file to look for address, port, protocol, filename and save path.
 * @return error - Error code. KErrNone if successful.
 */
void CT_RSocketData::DoCmdRecvOneOrMore(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdDownloadToFile"));
	TBool dataOk = ETrue;

	TInt duration( KNoDuration );
	if(!GetIntFromConfig(aSection, KDuration, duration  ))
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDuration);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}
	
	TPtrC protocol;
	if(!GetStringFromConfig(aSection, KProtocol, protocol ))
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KProtocol);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}

	TUint datadealerid( KNoDataDealer );
	if(!GetUintFromConfig(aSection,  KDataDealerID, datadealerid ))
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDataDealerID);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}
	
	TPtrC savename( KNoFileSave );
    if(!GetStringFromConfig(aSection, KSaveName, savename))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KSaveName);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	
	TBuf8<KBufferSize> buffer;
	if (protocol != KProtocolHTTP)
		{
    	ERR_PRINTF3(_L("Error, %S protocol is not supported. %S protocol is expected"), &protocol, &KProtocolHTTP);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
		}
	
	if (dataOk)
		{
	    INFO_PRINTF1(_L("Download starts"));
	    
		TInt error = KErrNone;
		TBool header = ETrue;
		TBool writeFail = EFalse;
		TRequestStatus status;
		TSockXfrLength received;

		// Start and end time for calculating the transfer speed.
		iStart.HomeTime();
		
		// receive until RecvOneOrMore fails.
		do
			{
			iSocket->RecvOneOrMore(buffer, 0, status, received);
			User::WaitForRequest(status);

			if (status == KErrNone)
				{
				iTotalReceived += received();

				if (header)
					{
					// HTTP server first sends header and then data
					TInt location = buffer.Find(KEmptyLine);
					// If the separator (two line breaks) is found...
					if (location != KErrNotFound)
						{
						TInt i = location + KEmptySize;
						// Remove the header from the buffer
						buffer.Delete(0, i);
				        if (savename != KNoFileSave ||
	                        datadealerid != KNoDataDealer)
				            {
				            error = iBreathSaver->Append(buffer);
				            if (error != KErrNone)
								{
								WARN_PRINTF2(_L("Data append failed [%d]"), error);
								iBreathSaver->End();
								writeFail = ETrue;
								}
				            }
						header = EFalse;
						}
					}
				// Header is already removed from the input data
				else
					{
					// Write data into file
			        if (savename != KNoFileSave ||
	                    datadealerid != KNoDataDealer)
			            {
			            error = iBreathSaver->Append(buffer);
			            if (error != KErrNone)
							{
							WARN_PRINTF2(_L("Data append failed [%d]"), error);
							iBreathSaver->End();
							writeFail = ETrue;
							}
			            }
					}
				}
	        else
	            {
	            // KErrEof means that socket was closed or there is not any data to be read anymore
	            ERR_PRINTF2(_L("RecvOneOrMore returned error status [%d]"), status.Int());
	            }
	        // Check if duration parameter is given
	        if (duration != KNoDuration)
	            {
	            iEnd.HomeTime();
	            TTimeIntervalSeconds seconds (0);
	            error = iEnd.SecondsFrom(iStart, seconds);
	            if(error != KErrNone)
	            	{
	            	ERR_PRINTF2(_L("Failed to get time interval with error %d"), error);
	            	SetError(error);
	            	break;
	            	}
	            if ( seconds.Int() >= duration )
	                {
	                WARN_PRINTF2(_L("Transfer is stopped because defined duration [%d] exceeded"), seconds.Int());
	                break;
	                }
	            }
			}
		while(status == KErrNone && writeFail == EFalse);
		}
	
	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdDownloadToFile"));
	}

/**
 * Ends downloaded file.
 * @param  aSection - The section in config file to look for file's name.
 * @return error - Error code. KErrNone if successful.
 */
void CT_RSocketData::DoCmdUtilityEndFile(const TTEFSectionName& aSection)
	{	
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityEndFile"));
	TBool dataOk = ETrue;

	TPtrC savename( KNoFileSave );
    if(!GetStringFromConfig(aSection, KSaveName, savename))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KSaveName);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
    if (dataOk)
    	{
        if (savename != KNoFileSave)
            {
            iBreathSaver->End();
            }

    	iEnd.HomeTime();
    	
    	INFO_PRINTF1(_L("Download ends"));
    	}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityEndFile"));
	}	

/**
 * Calculates download time and compares with a given duration and speed
 * @param  aSection - The section in config file to look for speed and duration parameters. 
 */
void CT_RSocketData::DoCmdUtilityCalculateDownloadStats(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityCalculateDownloadStats"));
	TBool dataOk = ETrue;
	
	TInt speed( KNoSpeedCheck );
	if(!GetIntFromConfig(aSection, KMinimumSpeed, speed))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KMinimumSpeed);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    
	TInt duration( KNoDuration );
	if(!GetIntFromConfig(aSection, KDuration, duration  ))
		{
		ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDuration);
		SetBlockResult(EFail);
		dataOk = EFalse;
		}
	
	if (dataOk)
		{
		// Calculate the duration of the download.
		TTimeIntervalMicroSeconds microseconds = iEnd.MicroSecondsFrom(iStart);
	    TInt error = KErrNone;
	    TReal throughput = 0;
	    
	    if (iTotalReceived != 0)
	        {
	        throughput = ThroughputInKiloBits( microseconds, iTotalReceived );
	        }
	    
	    error = SetThroughput(throughput);
	    if (error == KErrNone)
	        {
	        TBool speedEnough = ETrue;
		    if (speed != KNoSpeedCheck)
		        {
		        INFO_PRINTF2(_L("Check that the download speed was faster than (%d kpbs)"), speed);
		        if ( speed > throughput )
		            {
		            ERR_PRINTF1(_L("Speed was not fast enough"));
		            SetBlockResult(EFail);
		            speedEnough = EFalse;
		            }
		        else
		            {
		            INFO_PRINTF1(_L("Speed was fast enough"));
		            }
		        }

		    if (speedEnough && duration != KNoDuration)
		        {
		        TTimeIntervalSeconds seconds (0);
		        error = iEnd.SecondsFrom(iStart, seconds);
		        if(error != KErrNone)
		        	{
		        	ERR_PRINTF2(_L("Failed to get time interval with error %d"), error);
		        	SetError(error);
		        	}
		        else if ( seconds.Int() < duration )
		            {
		            ERR_PRINTF2(_L("Transfer failed, transfer did not last the defined duration [%d]"), duration);
		            SetBlockResult(EFail);
		            }
		        }
	        }
	    else
	    	{
	        ERR_PRINTF2(_L("SetThroughput failed [%d]"), error);
	        SetError(error);
	    	}
		}
    
    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityCalculateDownloadStats"));
    }


void CT_RSocketData::DoCmdInfoL(const TTEFSectionName& aSection)	
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdInfoL"));
	TBool dataOk = ETrue;
	
	TPtrC protocol;
    if(!GetStringFromConfig(aSection, KProtocol, protocol))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KProtocol);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	
    if(dataOk)
    	{
    	TProtocolDesc protocolDesc;
    	TInt err = iSocket->Info(protocolDesc);
    	if(err != KErrNone)
    		{
    		ERR_PRINTF2(_L("Getting Info failed with error %d"), err);
    		SetError(err);
    		}
    	
    	TInt* protocolApi = static_cast<TInt*>(GetDataObjectL(protocolDesc.iName));
    	TInt* protocolIni = static_cast<TInt*>(GetDataObjectL(protocol));
    	
    	if(protocolApi != protocolIni)
    		{
    		ERR_PRINTF3(_L("Mismatch between expected protocol [%S] and current protocol [%S]"),protocolIni, protocolApi);
    		SetBlockResult(EFail);
    		}
    	}
	
	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdInfoL"));
	}	


/**
 * Build http post request
 */
void CT_RSocketData::DoCmdUtilityBuildRequest(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityBuildRequest"));
	TBool dataOk = ETrue;

	INFO_PRINTF1(_L("Sending HTTP request"));
	TPtrC address( KNullDesC );
	if(!GetStringFromConfig(aSection, KAddress, address ))
	  	{
	  	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KAddress);
	   	SetBlockResult(EFail);
	   	dataOk = EFalse;
	   	}
	
	TInt bytes;
    if(!GetIntFromConfig(aSection, KBytes, bytes ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KBytes);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
    TPtrC requestLogFile;
    if(!GetStringFromConfig(aSection, KRequestLogFile, requestLogFile ))
	  	{
	  	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KRequestLogFile);
	   	SetBlockResult(EFail);
	   	dataOk = EFalse;
	   	}
    
    if (dataOk)
    	{
    	// Construct request
    	iRequest.Append(KHTTPPOST);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KServerScript);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KHTTPSuffix);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KHost);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(address);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KFrom);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KAhti);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KContentType);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KMultipartType);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KBoundary);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KContentLength);
    	iRequest.Append(KHTTPSeparator);
    	// Request size + size of the data to be sent. Server must know how much
    	// data is coming.
    	iRequest.AppendNum(KHeaderWithoutData+bytes);
    	iRequest.Append(KLineBreak);
    	
    	// extra line break
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KBoundaryStart);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KContentDisposition);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KDisposition);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KContentType);
    	iRequest.Append(KHTTPSeparator);
    	iRequest.Append(KOctetType);
    	iRequest.Append(KLineBreak);
    	
    	iRequest.Append(KLineBreak);
    	
    	// Make a log file of the request
    	TFileName fileName;
    	TDriveUnit driveUnit(EDriveC);
    	fileName.Zero();
    	fileName.Append(driveUnit.Name()); // c:
    	fileName.Append(requestLogFile);	
    	iBreathSaver->StartFile(fileName);

    	iBreathSaver->Append(iRequest);
    	}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityBuildRequest"));
	}

void CT_RSocketData::DoCmdWrite(const TInt aAsyncErrorIndex)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdWrite"));
	
	// Send the header before data
   	iSocket->Write(iRequest, iActiveCallback->iStatus);
   	iActiveCallback->Activate(aAsyncErrorIndex);
   	IncOutstanding();
   	
   	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdWrite"));
	}

void CT_RSocketData::DoCmdSendBytesToSocket(const TTEFSectionName& aSection)
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdSendBytesToSocket"));
	TBool dataOk = ETrue;
	
	TInt bytes;
	if(!GetIntFromConfig(aSection, KBytes, bytes ))
    	{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KBytes);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	TInt duration ( KNoDuration );
	if(!GetIntFromConfig(aSection, KDuration, duration ))
		{
    	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDuration);
    	SetBlockResult(EFail);
    	dataOk = EFalse;
    	}
	
	if (dataOk)
		{
		TInt error = SendBytesToSocket(bytes, duration);
		if (error != KErrNone)
			{
			ERR_PRINTF1(_L("Error in sending bytes to socket"));
			SetError(error);
			}
		}

	INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdSendBytesToSocket"));
	}

void CT_RSocketData::DoCmdUtilityEndRequest()
	{
	INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUtilityEndRequest"));

	iRequest.Delete(0, iRequest.Length());
    // Now the rest of the header data
    iRequest.Append(KLineBreak);

    iRequest.Append(KBoundaryEnd);
    iRequest.Append(KLineBreak);

    // add the rest of the reaquest to log file
    iBreathSaver->Append(iRequest);
    iBreathSaver->End(); // Close the file

    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUtilityEndRequest"));
	}

void CT_RSocketData::DoCmdResponseFromServer(const TTEFSectionName& aSection)
	{
    INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdResponseFromServer"));
    TBool dataOk = ETrue;
    TPtrC responseLogFile;
    if(!GetStringFromConfig(aSection, KResponseLogFile, responseLogFile ))
	  	{
	  	ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KResponseLogFile);
	   	SetBlockResult(EFail);
	   	dataOk = EFalse;
	   	}
    if(dataOk)
    	{
    	// After file was succesfully sent to HTTP server we can receive the response
    	// from the server.
    	// Create variables for receive buffer and received data counting variables.
    	
    	TBuf8<KBufferSize> buffer;
    	TSockXfrLength received;
    	TRequestStatus status;
    	
    	TFileName fileName;
    	TDriveUnit driveUnit(EDriveC);
    	fileName.Zero();
    	fileName.Append(driveUnit.Name()); // c:
    	fileName.Append(responseLogFile);
    	
    	iBreathSaver->StartFile(fileName);
    	// receive until RecvOneOrMore fails.
    	do
    		{
    		iSocket->RecvOneOrMore(buffer, 0, status, received);
    		User::WaitForRequest(status);
    	
    	    iBreathSaver->Append(buffer);
    		}
    	while(status.Int() == KErrNone);
    	
    	iBreathSaver->End();
    	}
    
	
    INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdResponseFromServer"));
	}

/**
 * Send Bytes to the socket
 * @param TInt How many bytes are sent
 * @return Symbian error code
 */
TInt CT_RSocketData::SendBytesToSocket(TInt aBytes, TInt aDuration)
    {
    const TInt KDataBufferSize = 256;
    TBuf8<KDataBufferSize> data;
    data.SetMax();
    data.FillZ();
    TInt bytesSent = 0;

    TRequestStatus status;

    INFO_PRINTF1(_L("Uploading bytes to server"));
	iStart.HomeTime();

    // Loop while enough bytes are sent to socket
    while (bytesSent < aBytes)
        {
        if ((aBytes - bytesSent) < KDataBufferSize)
            {
            // this is the last round where we don't send full buffer anymore
            data.SetLength(aBytes - bytesSent);
            iSocket->Write(data, status);
            User::WaitForRequest(status);
            if (status.Int() != KErrNone)
                {
                ERR_PRINTF2(_L("Failed to send data to socket [%d]"), status.Int());
                return status.Int();
                }

            bytesSent += (aBytes - bytesSent);
            // We can break because there are no more data to be send
            break;
            }
        iSocket->Write(data, status);
        User::WaitForRequest(status);
        if (status.Int() != KErrNone)
            {
            ERR_PRINTF2(_L("Failed to send data to socket [%d]"), status.Int());
            return status.Int();
            }

        bytesSent += KDataBufferSize;
        
        if (aDuration != KNoDuration)
            {
            iEnd.HomeTime();
            TTimeIntervalSeconds seconds (0);
            TInt error = iEnd.SecondsFrom(iStart, seconds);
            if (error != KErrNone)
                {
            	ERR_PRINTF2(_L("Failed to get time interval with error %d"), error);
                return error;
                }
            if ( seconds.Int() >= aDuration )
                {
                // Transfer has lasted long enough. Let's stop transfer
                INFO_PRINTF2(_L("Transfer is stopped because defined duration [%d] exceeded"), seconds.Int());
                break;
                }
            }
        }

    iEnd.HomeTime();

    TTimeIntervalMicroSeconds microseconds = iEnd.MicroSecondsFrom(iStart);

	// Calculate the upload speed
    TInt error=0;
    TReal throughput = 0;
    if (bytesSent != 0)
        {
        throughput = ThroughputInKiloBits( microseconds, bytesSent );
        }
    	error= SetThroughput(throughput);

    if (error != KErrNone)
        {
        ERR_PRINTF2(_L("SetThroughput failed [%d]"), error);
        return error;
        }

    if (aDuration != KNoDuration)
        {
        // Close the socket because next we try to read response from the server and it won't come
        // because transfer is cut early (server waits until all bytes are sent or socket is closed)
        iSocket->Shutdown(RSocket::ENormal, status);
        User::WaitForRequest(status);
        
        TTimeIntervalSeconds seconds (0);
        TInt error = iEnd.SecondsFrom(iStart, seconds);
        if (error != KErrNone)
            {
        	ERR_PRINTF2(_L("Failed to get time interval with error %d"), error);
            return error;
            }
        if ( seconds.Int() < aDuration )
            {
            // Transfer didn't last the defined duration!
            ERR_PRINTF2(_L("Transfer failed, transfer did not last the defined duration [%d]"), aDuration);
            return KErrEof;
            }
        else
            {
            // If duration was used and socket was closed early return KErrCancel (it won't cause the
            // whole test case to fail
            return KErrCancel;
            }
        }

    return KErrNone;
    }



/**
 * Calculates throughput based on duration of a data transfer and total transferred bytes.
 * @param aDuration Duration of the transfer.
 * @param aTotalTransferred Total transferred data length in bytes.
 * @return Throughput in KBps.
 */
TReal CT_RSocketData::ThroughputInKiloBits( TTimeIntervalMicroSeconds aDuration, TInt aBytes )
	{
	const TReal KKiloConversion(1000.0);
	TReal throughput = ThroughputInMegaBits( aDuration, aBytes ) * KKiloConversion;
	
	return throughput;
	}


/**
 * Calculates throughput based on duration of a data transfer and total transferred bytes.
 * @param aDuration Duration of the transfer.
 * @param aTotalTransferred Total transferred data length in bytes.
 * @return Throughput in MBps.
 */
TReal CT_RSocketData::ThroughputInMegaBits( TTimeIntervalMicroSeconds aDuration, TInt aBytes )
	{
	const TReal KBitsInByte(8.0);
	TReal throughput = ( KBitsInByte * (TReal) aBytes ) / (TReal) aDuration.Int64();
	
	return throughput;
	}

/**
 * Set throughput into RProperty
 * @param aThroughput The calculated throughput
 */
TInt CT_RSocketData::SetThroughput( const TReal aThroughput )
    {
	TInt err = RProperty::Define( iPropertyCategory, iPropertyKey, RProperty::EByteArray );

	if( err == KErrAlreadyExists )
		{
		INFO_PRINTF1(_L( "Property already exists. Contents will be overridden") );
		err = KErrNone;
		}
	
	if (err == KErrNone)
		{
	    // Convert throughput value (TReal) into descriptor
	    TBuf8<256> amount;
	    TRealFormat realFormat;
	    err = amount.AppendNum( aThroughput, realFormat );
	    // Set property value
	    err = RProperty::Set( iPropertyCategory, iPropertyKey, amount );
		}
	else
		{
		ERR_PRINTF2(_L( "Could not create pub&sub property: %d"), err );
		}

    return err;
    }

/**
Check if RMobileCall has HSDPA indicator
@return TBool value of the indicator
*/
TBool CT_RSocketData::CheckHSDPAIndicator()
    {
    RMobilePhone::TMobilePhoneNetworkInfoV5 networkInfo;
    return networkInfo.iHsdpaAvailableIndicator;
    }

/**
Check if RPacketService has HSDPA support
@param RMobileCall aMobileCall
@return TBool value of the indicator
*/
TBool CT_RSocketData::CheckHSDPASupportL(RMobilePhone &aMobilePhone)
    {
    RPacketService packetservice;
    
    CleanupClosePushL(packetservice);
    User::LeaveIfError(packetservice.Open(aMobilePhone));
    TUint caps;
    // Ask for static capabilities using CDMA context
    TInt error = packetservice.GetStaticCaps(caps, RPacketContext::EPdpTypeCDPD);
    CleanupStack::PopAndDestroy(&packetservice); // RPacketService.Close()

    User::LeaveIfError(error);
    
    return caps & RPacketService::KCapsHSDPASupported;
    }
    
/**
Check if RPacketService is currently using HSDPA
@param RMobileCall aMobileCall
@return TBool value of the indicator
*/
TBool CT_RSocketData::CheckHSDPAUsageL(RMobilePhone &aMobilePhone) 
    {
    RPacketService ps;
    
    CleanupClosePushL(ps); 
    User::LeaveIfError(ps.Open(aMobilePhone)); 
    RPacketService::TDynamicCapsFlags caps;
    TInt error = ps.GetDynamicCaps(caps);
	CleanupStack::PopAndDestroy(&ps); // RPacketService

	User::LeaveIfError(error); 
    
	return caps & RPacketService::KCapsHSDPA;
    }