diff -r 000000000000 -r 3553901f7fa8 cellularsrvapitest/datatransferhaitest/esock/src/T_RSocketData.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cellularsrvapitest/datatransferhaitest/esock/src/T_RSocketData.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,1405 @@ +/* +* 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 +#include // RMobilePhone +#include // 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(GetDataObjectL(connectionName)); + INFO_PRINTF1(_L("Create a RSocketServ for iSocket")); + RSocketServ* socketServ = static_cast(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(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 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(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 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(GetDataObjectL(protocolDesc.iName)); + TInt* protocolIni = static_cast(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 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 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; + }