diff -r 000000000000 -r c40eb8fe8501 wlanapitest/wlanhaitest/wlan/src/T_RSocketData.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlanapitest/wlanhaitest/wlan/src/T_RSocketData.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,1359 @@ +/* +* 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 +#include "t_rsocketdata.h" + +/*@{*/ +// LITs from the ini file +_LIT( KSocketServ, "socketserv"); +_LIT( KConnection, "connection"); +_LIT( KScanInfo, "scaninfo"); +_LIT( KAddress, "Ip"); +_LIT( KPort, "Port"); +_LIT( KFile, "File"); +_LIT( KSave, "Save"); +_LIT( KARates, "rate"); +_LIT( KFileServer, "FileServer"); +/*@}*/ + +/*@{*/ +// Upload +_LIT(KNullFile, "KNullDesC"); +/*@}*/ + +/*@{*/ +// LITs for the commands +_LIT( KCmdOpen, "Open"); +_LIT( KCmdConnect, "Connect"); +_LIT( KCmdHttpGet, "HttpGet"); +_LIT( KCmdDownloadSendHTTPGet, "DownloadSendHTTPGet"); +_LIT( KCmdRecvOneOrMore, "RecvOneOrMore"); +_LIT( KCmdUploadSendHTTPPost, "UploadSendHTTPPost"); +_LIT( KCmdCheckSupportedRates, "CheckSupportedRates"); +_LIT( KCmdShutdown, "Shutdown"); +_LIT( KCmdClose, "Close"); +/*@}*/ + +/*@{*/ +// Constants for creating a HTTP request in the command DoCmdDownloadSendHTTPGet +_LIT8( KHTTPGET, "GET"); +_LIT8( KHTTPSeparator, " "); +_LIT8( KHTTPSuffix, "HTTP/1.1"); +_LIT( KHostS, "Host"); +_LIT8( KLineFeed, "\r\n"); +_LIT8( KEmptyLine, "\r\n\r\n"); +_LIT8( KHeaderEndMark, "\r\n\r\n" ); +_LIT8( KContentLengthField, "Content-Length: "); +_LIT8( KFieldEnd, "\r\n" ); +_LIT8( KGETHTTP, "GET / HTTP/1.0\r\n\r\n" ); +/*@}*/ + +/*@{*/ +// Constants for CreateHTTPHeaderStart +_LIT8(KHTTPPOST, "POST"); +_LIT8(KLineBreak, "\r\n"); +_LIT(KClientID, "clientID"); +_LIT(KServerScript, "serverScript"); +_LIT8(KFrom, "From:"); +_LIT8(KHosts, "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(KDisposition, "form-data; name=\"userfile\"; filename="); +_LIT8(KBackS, "\""); +_LIT8(KBoundaryEnd, "-----------------------------sg976436h73--"); +/*@}*/ + + +const TInt KHttpHeaderBufferIncrement = 4096; +// Const for supported rates +// The first bit includes information about BSSBasicRateSet, +// mask it out + +const TUint32 KBasicRateMask = 0x7F; +// 802.11g supported speed rate +const TUint8 K80211Rate1Mbit = 2; +const TUint8 K80211Rate2Mbit = 4; +const TUint8 K80211Rate5Mbit = 11; +const TUint8 K80211Rate11Mbit = 22; +const TUint8 K80211Rate12Mbit = 24; +const TUint8 K80211Rate18Mbit = 36; +const TUint8 K80211Rate22Mbit = 44; +const TUint8 K80211Rate24Mbit = 48; +const TUint8 K80211Rate33Mbit = 66; +const TUint8 K80211Rate36Mbit = 72; +const TUint8 K80211Rate48Mbit = 96; +const TUint8 K80211Rate54Mbit = 108; + + + + + + + +/** + * Two phase constructor + * + * @leave system wide error + */ +CT_RSocketData* CT_RSocketData::NewL() + { + CT_RSocketData * ret = new (ELeave)CT_RSocketData(); + CleanupStack::PushL(ret); + ret->ConstructL(); + CleanupStack::Pop(ret); + return ret; + } + +/* + *RunL method for management Active callbacks + * @param aActive param to review which active call back is being fished + * @param aIndex + * @return void + */ +void CT_RSocketData::RunL(CActive* aActive, TInt /*aIndex*/) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::RunL")); + DecOutstanding(); // One of the async calls has completed + TInt err(KErrNone); + if(aActive == iActiveCallback) + { + INFO_PRINTF1(_L("active call back for Write Socket.")); + err = iActiveCallback->iStatus.Int(); + if(err != KErrNone) + { + ERR_PRINTF1(_L("iSocket->Write(...) Fail")); + SetError(err); + } + else + { + INFO_PRINTF2(_L("CT_RSocketData::SendHTTPGet [%d]"), iActiveCallback->iStatus.Int()); + INFO_PRINTF1(_L("Asynchronous task has completed. RunL called")); + } + } + else if(aActive == iActCallConnectSocket) + { + INFO_PRINTF1(_L("active call back for Connect Socket.")); + err = iActCallConnectSocket->iStatus.Int(); + if(err != KErrNone) + { + ERR_PRINTF1(_L("iSocket->Connect(...) Fail")); + SetError(err); + } + else + { + INFO_PRINTF1(_L("CT_RSocketData::DoCmdConnect(...) success")); + iSocketOpened = ETrue; + } + } + else if(aActive == iActCallShutDownSocket) + { + INFO_PRINTF1(_L("active call back for Shutdown Socket.")); + err = iActCallShutDownSocket->iStatus.Int(); + if(err != KErrNone) + { + ERR_PRINTF2(_L("iSocket->Shutdown(...): [%d] Fail"),iActCallShutDownSocket->iStatus.Int()); + SetError(err); + } + else + { + INFO_PRINTF1(_L("CT_RSocketData::Shutdown success")); + iSocketStarted = EFalse; + } + } + else + { + ERR_PRINTF1(_L("An unchecked active object completed")); + SetBlockResult(EFail); + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::RunL")); + } +/* + * public destructor + */ +CT_RSocketData::~CT_RSocketData() + { + if (iSocketStarted) + { + INFO_PRINTF1(_L("CT_RSocketData: Shutting down socket")); + Shutdown(); + } + if (iSocketOpened) + { + Close(); + } + if (iDownloadBuffer) + { + delete iDownloadBuffer; + iDownloadBuffer = NULL; + } + if (iSocket) + { + delete iSocket; + iSocket = NULL; + } + if (iActiveCallback) + { + delete iActiveCallback; + iActiveCallback = NULL; + } + if (iActCallShutDownSocket) + { + delete iActCallShutDownSocket; + iActCallShutDownSocket = NULL; + } + if (iActCallConnectSocket) + { + delete iActCallConnectSocket; + iActCallConnectSocket = NULL; + } + + iFs.Close(); + + if (iUploadBuffer) + { + delete iUploadBuffer; + iUploadBuffer = NULL; + } + } + +/** + * Private constructor. First phase construction + * + */ +CT_RSocketData::CT_RSocketData() +: iSocket(NULL), + iActiveCallback(NULL), + iActCallConnectSocket(NULL), + iActCallShutDownSocket(NULL), + iSocketOpened(EFalse), + iSocketStarted(EFalse), + iAsyncErrorIndex(0), + iDownloadBuffer(NULL), + iUploadBuffer(NULL), + iHttpResponseHeader(), + iDownloadThroughput(0.0), + iFs(), + iUploadThroughput(0.0), + itotalReceived(0) + { + + } + +/** + * Second phase construction + * + * @internalComponent + * + * @return N/A + * + * @pre None + * @post None + * + * @leave system wide error + */ +void CT_RSocketData::ConstructL() + { + const TInt KDefaultBufferSize = 4096; + TInt err(KErrNone); + iSocket = new (ELeave) RSocket(); + iActiveCallback = CActiveCallback::NewL(*this); + iActCallConnectSocket = CActiveCallback::NewL(*this); + iActCallShutDownSocket = CActiveCallback::NewL(*this); + iDownloadBuffer = HBufC8::NewL( KDefaultBufferSize); + iUploadBuffer = HBufC8::NewL(KDefaultBufferSize); + err = iFs.Connect(); + if(err != KErrNone) + { + SetError(err); + } + } + + +/** + * 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; + } + + + +/** + * Process a command read from the Ini file + * @param aCommand The command to process + * @param aSection The section get from the *.ini file of the project T_Wlan + * @param aAsyncErrorIndex Command index for async calls to returns errors to + * @return TBool ETrue if the command is process + * @leave system wide error + * + */ +TBool CT_RSocketData::DoCommandL(const TTEFFunction& aCommand, const TTEFSectionName& aSection, const TInt aAsyncErrorIndex) + { + TBool ret = ETrue; + if(aCommand == KCmdOpen ) + { + DoCmdOpen(aSection); + } + else if(aCommand == KCmdConnect) + { + DoCmdConnect(aSection,aAsyncErrorIndex); + } + else if(aCommand == KCmdDownloadSendHTTPGet) + { + DoCmdDownloadSendHTTPGet(aSection,aAsyncErrorIndex); + } + else if(aCommand == KCmdRecvOneOrMore) + { + DoCmdRecvOneOrMore(aSection); + } + else if(aCommand == KCmdUploadSendHTTPPost) + { + DoCmdUploadSendHTTPPost(aSection); + } + else if(aCommand == KCmdShutdown) + { + DoCmdShutdown(aAsyncErrorIndex); + } + else if(aCommand == KCmdClose) + { + DoCmdClose(); + } + else if(aCommand == KCmdHttpGet) + { + DoCmdHttpGet(); + } + else if(aCommand == KCmdCheckSupportedRates) + { + DoCmdCheckSupportedRates(aSection); + } + else + { + ERR_PRINTF1(_L("Unknown command.")); + ret = EFalse; + } + return ret; + } + + + + +/** + * Open the Socket from RSocket. The errors are management with SetError() and SetBlockResult(). + * @param aSection Section in the ini file for this command. + * @return + */ +void CT_RSocketData::DoCmdOpen(const TTEFSectionName& aSection) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdOpen")); + TBool dataOk = ETrue; + + TPtrC connectionName; + if(! GetStringFromConfig(aSection, KConnection, connectionName)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KConnection); + SetBlockResult(EFail); + dataOk = EFalse; + } + + TPtrC socketServName; + if(! GetStringFromConfig(aSection, KSocketServ, socketServName)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KSocketServ); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if (dataOk) + { + INFO_PRINTF1(_L("Opening a TCP/IP socket")); + + RConnection* rConnection = static_cast(GetDataObjectL(connectionName)); + RSocketServ* rSocketServ = static_cast(GetDataObjectL(socketServName)); + + if(rConnection != NULL && rSocketServ != NULL) + { + TInt error = iSocket->Open( *rSocketServ, KAfInet, KSockStream, KProtocolInetTcp, *rConnection ); + + if(error == KErrNone) + { + iSocketOpened = ETrue; + } + else + { + ERR_PRINTF2(_L("Socket opening failed [%d]"), error); + SetError(error); + } + } + else + { + if(rConnection == NULL) + { + ERR_PRINTF2(_L("rConnection is NULL: %S"),rConnection); + SetBlockResult(EFail); + } + + if(rSocketServ == NULL) + { + INFO_PRINTF2(_L("rSocketServ is NULL: %S"),rSocketServ); + SetBlockResult(EFail); + } + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdOpen")); + } + +/** + * Command to Connect a Socket of RSocket. + * @param aSection Section to read from the ini file + * @param aAsyncErrorIndex Command index for async calls to returns errors to + * @return + */ +void CT_RSocketData::DoCmdConnect(const TTEFSectionName& aSection, const TInt aAsyncErrorIndex) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdConnect")); + TBool dataOk = ETrue; + + //Getting from the .ini the IP Address + TPtrC aIpAddr; + if(!GetStringFromConfig( aSection, KAddress, aIpAddr )) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KAddress); + SetBlockResult(EFail); + dataOk = EFalse; + } + + //Getting the port from the file ini + TInt aPort; + if(!GetIntFromConfig( aSection, KPort,aPort )) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KPort); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if(dataOk) + { + // Set the IP Address + TInetAddr inetAddr; + TInt err = inetAddr.Input( aIpAddr ) ; + if(err == KErrNone) + { + INFO_PRINTF2(_L("Remote IP: %S"), &aIpAddr ); + INFO_PRINTF2( _L("Port: %d"), aPort ); + // Set the port + inetAddr.SetPort( aPort ); + // Connect an IP through the Port 80 + iSocket->Connect( inetAddr, iActCallConnectSocket->iStatus ); + iActCallConnectSocket->Activate(aAsyncErrorIndex); + IncOutstanding(); + } + else + { + ERR_PRINTF2(_L("inetAddr.Input( aIpAddr ) Failed with error %d"), err); + SetError(err); + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdConnect")); + } + +/** + * Command to send the HTTP Get, using the socket Write. + * @param aSection Section to read from the ini file + * @param aAsyncErrorIndex Command index for async calls to returns errors to + * @return + */ +void CT_RSocketData::DoCmdDownloadSendHTTPGet(const TTEFSectionName& aSection, const TInt aAsyncErrorIndex ) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdDownloadSendHTTPGet")); + TBool dataOk = ETrue; + + // Read params from the ini file + TPtrC aHost; + if(!GetStringFromConfig( aSection, KHostS, aHost)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KHostS); + SetBlockResult(EFail); + dataOk = EFalse; + } + + TPtrC aFilename; + if(!GetStringFromConfig( aSection, KFile, aFilename )) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KFile); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if (dataOk) + { + const TInt KMaxHostNameLength(256); + if( aHost.Length() > KMaxHostNameLength ) + { + ERR_PRINTF1(_L("Host is too long, cannot send HTTP request")); + SetBlockResult(EFail); + } + else if( aFilename.Length() > KMaxFileName ) + { + ERR_PRINTF1(_L("Filename is too long, cannot send HTTP request")); + SetBlockResult(EFail); + } + else + { + INFO_PRINTF1(_L("Create HTTP GET request")); + // Buffer that will hold the request. + TBuf8< sizeof( KHTTPGET ) + + sizeof( KHTTPSeparator ) + + KMaxFileName + + sizeof( KHTTPSeparator ) + + sizeof( KHTTPSuffix ) + + sizeof( KLineFeed ) + + sizeof( KHosts ) + + KMaxHostNameLength + + sizeof( KEmptyLine ) > request; + // Construct the final request. + request.Copy( KHTTPGET ); + request.Append( KHTTPSeparator ); + request.Append( aFilename ); + request.Append( KHTTPSeparator ); + request.Append( KHTTPSuffix ); + request.Append( KLineFeed ); + request.Append( KHosts ); + request.Append( aHost ); + request.Append( KEmptyLine ); + + INFO_PRINTF1(_L("Write to socket")); + // Send the request through socket + iSocket->Write(request, iActiveCallback->iStatus); + iActiveCallback->Activate(aAsyncErrorIndex); + IncOutstanding(); + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdDownloadSendHTTPGet")); + } + +/** + * Command to receive an HTTP Response for Upload and Download of files. + * @param aSection Section to read from the ini file + * @return + */ +void CT_RSocketData::DoCmdRecvOneOrMore(const TTEFSectionName& aSection) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdRecvOneOrMore")); + TBool dataOk = ETrue; + + // Read from the ini file + TPtrC aFilename; + if(!GetStringFromConfig( aSection, KSave,aFilename )) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KSave); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if (dataOk) + { + RFile file; + TInt error = KErrNone; + + //if KNullFile then Upload + TBool discardData = ( aFilename == KNullFile); + INFO_PRINTF2(_L("File and path to Download: %S"),&aFilename); + if( !discardData ) + { + INFO_PRINTF1( _L("Data is not discarded, creating file") ); + error = file.Replace( iFs, aFilename, EFileShareAny|EFileWrite ); + } + else + { + INFO_PRINTF1( _L("Discarding downloaded data") ); + } + + if( error == KErrNone ) + { + TSockXfrLength received; + TInt totalReceived = 0; + TInt contentReceived = 0; + TInt timedReceived = 0; + TInt contentLength = 0; + TRequestStatus status; + TPtr8 downloadBufferPtr( iDownloadBuffer->Des() ); + + downloadBufferPtr.SetMax(); + INFO_PRINTF2( _L("Using buffer size [%d]"), downloadBufferPtr.MaxSize() ); + + INFO_PRINTF1(_L("Set time stamps for download")); + TTime endTime; + TTime startTime; + + INFO_PRINTF1( _L("Receiving data")); + + // Let's assume that we receive a HTTP header first + TBool header( ETrue ); + TBool timerStarted( EFalse ); + TBool failure = EFalse; // a flag to delete multiple returns + + iHttpResponseHeader.Zero(); + // receive until RecvOneOrMore fails or all content is received + do + { + if( !timerStarted && !header) + { + startTime.HomeTime(); + endTime.HomeTime(); + timerStarted = ETrue; + } + + iSocket->RecvOneOrMore( downloadBufferPtr, 0, status, received ); + User::WaitForRequest( status ); + if( !header ) + { + timedReceived += received(); + } + + if( KErrNone == status.Int() ) + { + // Check if we are still receiving the HTTP header + if( header ) + { + //Increase httpResponseheader size if needed + if(iHttpResponseHeader.Length() + downloadBufferPtr.Length() > iHttpResponseHeader.MaxLength()) + { + error = iHttpResponseHeader.ReAlloc(iHttpResponseHeader.MaxLength() + KHttpHeaderBufferIncrement); + if(error != KErrNone) + { + ERR_PRINTF2( _L("iHttpResponseHeader.ReAlloc(...) Failed with error %d"), error); + SetError( error ); + failure = ETrue; + break; + } + } + + //Append the donwloaded content to headerbuffer + iHttpResponseHeader.Append(downloadBufferPtr); + TInt headerEndIndex = iHttpResponseHeader.Find( KHeaderEndMark ); + if( headerEndIndex != KErrNotFound ) + { + INFO_PRINTF1( _L("Header end mark found")); + //Parse Content-Length field and extract content length + TInt contentLengthStart = iHttpResponseHeader.Find( KContentLengthField ); + //If Content-Length field is found + if( contentLengthStart != KErrNotFound ) + { + INFO_PRINTF1(_L("Content-Length field found from HTTP response")); + contentLengthStart += KContentLengthField().Length(); + TPtrC8 contentLengthDes; + contentLengthDes.Set(iHttpResponseHeader.Mid( contentLengthStart )); + TInt contentLengthEnd = contentLengthDes.Find( KFieldEnd ); + contentLengthDes.Set(contentLengthDes.Mid(0, contentLengthEnd)); + TLex8 lex; + lex.Assign( contentLengthDes ); + lex.Val(contentLength); + INFO_PRINTF2( _L("Content-Length: [%d]"), contentLength ); + } + else + { + INFO_PRINTF1( _L("No Content-Length field found from HTTP response")); + INFO_PRINTF1( _L("Assuming Content-Length: 0")); + contentLength = 0; + file.Close(); + error = iFs.Delete(aFilename); + if(error != KErrNone) + { + INFO_PRINTF3(_L("Error [%d] for delete the file %S"), &aFilename,error); + SetError(error); + failure = ETrue; + break; + } + ERR_PRINTF2(_L("File %S was not found"), &aFilename); + SetBlockResult(EFail); + failure = ETrue; + break; + } + // Header was found + headerEndIndex += KHeaderEndMark().Length(); + //Convert the headerEndIndex in httpResponseheader to index in downloadBuffer + headerEndIndex -= totalReceived; + //Delete remaining parts of the HTTP header from the download buffer + downloadBufferPtr.Delete( 0, headerEndIndex ); + header = EFalse; + } + } + + // Increase the total received amount as we receive more data. + // Note: received data count also counts headers, this is taken + // into account in timing (startTime) + totalReceived += received(); + if(!header) + { + contentReceived += downloadBufferPtr.Length(); + } + + if( !discardData ) + { + error = file.Write( *iDownloadBuffer ); + if( KErrNone != error ) + { + ERR_PRINTF2( _L("Failed to write local file [%d]"), error ); + file.Close(); + SetError(error); + failure = ETrue; + break; + } + } + } + else + { + INFO_PRINTF1(_L("Set end time")); + endTime.HomeTime(); + INFO_PRINTF2( _L("Receiving err [%d]"), status.Int()); + break; + } + } + while( KErrNone == status.Int() && contentReceived < contentLength ); + + if (!failure) + { + endTime.HomeTime(); + INFO_PRINTF2( _L("Received total of [%d] bytes (inc headers)"), totalReceived ); + INFO_PRINTF2( _L("Content received [%d] bytes"), contentReceived ); + + //Set this printing optional + //Print only if any amount of datatransfer was timed (skipped in the case of very short data transfers) + if( timerStarted ) + { + INFO_PRINTF1(_L("Calculate duration of the transfer")); + TTimeIntervalMicroSeconds duration = endTime.MicroSecondsFrom( startTime ); + INFO_PRINTF2( _L("Duration for the timed data transfer was [%Ld] microseconds"), duration.Int64() ); + INFO_PRINTF2( _L("Received [%d] bytes during timed data transfer"), timedReceived); + iDownloadThroughput = ThroughputInMegaBits( duration, timedReceived ); + } + else + { + INFO_PRINTF1( _L("Data transfer too short for throughput calculation")); + } + + // We allow any response to our reply at the moment. + if( !discardData ) + { + file.Close(); + } + } + } + else + { + ERR_PRINTF2( _L("Failed to open local file [%d]"), error ); + SetError(error); + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdRecvOneOrMore")); + } + +/** + * Create an HTTP Post for uploading files. + * @param aSection Section to read from the ini file + * @return + */ +void CT_RSocketData::DoCmdUploadSendHTTPPost(const TTEFSectionName& aSection) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdUploadSendHTTPPost")); + TBool dataOk = ETrue; + + INFO_PRINTF1( _L("Write to socket")); + + TPtrC aFilename; + if(!GetStringFromConfig(aSection,KFile,aFilename)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KFile); + SetBlockResult(EFail); + dataOk = EFalse; + } + + TPtrC fileServer; + if(!GetStringFromConfig(aSection,KFileServer,fileServer)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KFileServer); + SetBlockResult(EFail); + dataOk = EFalse; + } + + TPtrC clientID; + if(!GetStringFromConfig(aSection,KClientID,clientID)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KClientID); + SetBlockResult(EFail); + dataOk = EFalse; + } + + TPtrC serverScript; + if(!GetStringFromConfig(aSection,KServerScript,serverScript)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KServerScript); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if (dataOk) + { + const TInt KMaxTag = 256; + // KHeaderWithoutData will change if you alter the header in any way that changes the + // amount of characters in it! SO REMEMBER to calclulate header size again. + const TInt KHeaderWithoutData = 200; + TBuf8 request; + TRequestStatus status; + + CreateHTTPHeaderStart(request, ReadFileSizeL(aFilename),fileServer, clientID, serverScript); + + iSocket->Write( request,status); + User::WaitForRequest( status ); + if(status.Int() == KErrNone) + { + INFO_PRINTF1( _L("HTTP POST request send, sending payload next")); + // Send file to iSocket + SendFileToSocketL(aFilename); + request.SetLength( 0 ); + CreateHTTPHeaderEnd(request); + + // Send the rest of the header + INFO_PRINTF1(_L("Sending boundary end")); + iSocket->Write( request, status ); + User::WaitForRequest( status ); + if(status.Int() != KErrNone) + { + ERR_PRINTF2(_L("CT_RSocketData::DoCmdUploadSendHTTPPost: iSocket->Write( request,status) Failed with error %d"), status.Int()); + SetError(status.Int()); + } + } + else + { + ERR_PRINTF2(_L("CT_RSocketData::DoCmdUploadSendHTTPPost: iSocket->Write( request,status) Failed with error %d"), status.Int()); + SetError(status.Int()); + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdUploadSendHTTPPost")); + } + +/** + * Create or build the header for POST. + * @param aRequest Descriptor with a lenght of 456 that contain the parameters for the POST + * @param aDataSize Size of the file + * @return + */ +void CT_RSocketData::CreateHTTPHeaderStart(TDes8& aRequest, TInt aDataSize,TDesC& aFileServer, TDesC& clientID,TDesC& serverScript) + { + // Manually created HTTP Post request is difficult to maintain. + // Request and server responce is logged into file during test run. + + // KHeaderWithoutData will change if you alter the header in any way + // that changes the amount of characters in it! SO REMEMBER to calclulate + // header size again. + const TInt KHeaderWithoutData = 200; + INFO_PRINTF1( _L("Set socket remote name")); + TSockAddr address; + iSocket->RemoteName( address ); + + // Construct request + aRequest.Append(KHTTPPOST); + aRequest.Append(KHTTPSeparator); + aRequest.Append(serverScript); + aRequest.Append(KHTTPSeparator); + aRequest.Append(KHTTPSuffix); + aRequest.Append(KLineBreak); + + aRequest.Append(KHosts); + aRequest.Append(KHTTPSeparator); + aRequest.Append(address); + aRequest.Append(KLineBreak); + + aRequest.Append(KFrom); + aRequest.Append(KHTTPSeparator); + aRequest.Append(clientID); + aRequest.Append(KLineBreak); + + aRequest.Append(KContentType); + aRequest.Append(KHTTPSeparator); + aRequest.Append(KMultipartType); + aRequest.Append(KHTTPSeparator); + aRequest.Append(KBoundary); + aRequest.Append(KLineBreak); + + aRequest.Append(KContentLength); + aRequest.Append(KHTTPSeparator); + // aRequest size + size of the data to be sent. Server must know how much + // data is coming. + aRequest.AppendNum(KHeaderWithoutData+aDataSize); + aRequest.Append(KLineBreak); + + // extra line break + aRequest.Append(KLineBreak); + + aRequest.Append(KBoundaryStart); + aRequest.Append(KLineBreak); + + aRequest.Append(KContentDisposition); + aRequest.Append(KHTTPSeparator); + aRequest.Append(KDisposition); + aRequest.Append(KBackS); + aRequest.Append(aFileServer); + aRequest.Append(KBackS); + aRequest.Append(KLineBreak); + + aRequest.Append(KContentType); + aRequest.Append(KHTTPSeparator); + aRequest.Append(KOctetType); + aRequest.Append(KLineBreak); + + aRequest.Append(KLineBreak); + } + +/** + * Send aFilename parameter to the Socket with RSocket::Write + * @param aFilename name of the file send to the Socket + * @return + */ +void CT_RSocketData::SendFileToSocketL(const TDesC& aFilename) + { + TInt err(KErrNone); + TPtr8 buffer( iUploadBuffer->Des() ); + buffer.SetMax(); + INFO_PRINTF2( _L("Using buffer size [%d]"), buffer.MaxSize() ); + TInt bytesSent = 0; + + INFO_PRINTF1( _L("Open file")); + RFile file; + + err = file.Open(iFs, aFilename, EFileShareAny|EFileRead); + + if(err == KErrNone) + { + CleanupClosePushL( file ); + INFO_PRINTF1(_L("Read file size")); + TInt fileSize = ReadFileSizeL(aFilename); + + INFO_PRINTF1( _L("Set time stamps for upload")); + TTime endTime; + endTime.HomeTime(); + TTime startTime; + startTime.HomeTime(); + + INFO_PRINTF1( _L("Send file")); + // Loop while enough bytes are sent to socket + while( bytesSent < fileSize ) + { + TInt err = file.Read( buffer ); + + if( err == KErrEof ) + { + INFO_PRINTF1(_L("File sending finished")); + INFO_PRINTF2( _L("Upload buffer length is [%d]"), buffer.Length()); + break; + } + else if( err != KErrNone ) + { + ERR_PRINTF2( _L("Failed to read file [%d]"), err ); + SetError( err ); + break; + } + + TRequestStatus status(KRequestPending); + iSocket->Write( buffer, status ); + User::WaitForRequest( status ); + err = status.Int(); + if(err != KErrNone) + { + ERR_PRINTF2(_L("CT_RSocketData::SendFileToSocketL:iSocket->Write(...) Fail [%d] "),err); + SetError(err); + break; + } + + bytesSent += ( buffer.Length() ); + } + + if (err == KErrNone || err == KErrEof) + { + INFO_PRINTF1( _L("Set end time")); + endTime.HomeTime(); + INFO_PRINTF2( _L("Sent [%d] bytes to server"), bytesSent); + + INFO_PRINTF1( _L("Calculate duration of the transfer")); + TTimeIntervalMicroSeconds duration = endTime.MicroSecondsFrom( startTime ); + INFO_PRINTF2( _L("Duration for the data transfer was [%Ld] microseconds"), duration.Int64() ); + iUploadThroughput = ThroughputInMegaBits( duration, bytesSent ); + CleanupStack::PopAndDestroy( &file ); + } + } + else + { + ERR_PRINTF2(_L("CT_RSocket::SendFileToSocketL::file.Open(...) Failed with error %d"), err); + SetError(err); + } + } + +/** + * Calculated the throughput based on duration of a data transfer and total transferred bytes. + * @param aDuration Duration of the transfer + * @param aBytes Total transferred 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; + } + +/** + * Read the lenght of the file (aFileName) + * @param aFileName file to read the lenght + * @return + */ +TInt CT_RSocketData::ReadFileSizeL(const TDesC& aFilename) + { + RFile file; + TInt error = file.Open(iFs, aFilename, EFileShareAny|EFileRead); + if ( error != KErrNone) + { + ERR_PRINTF2( _L("Failed to open local file [%d]"), error); + SetError(error); + return error; + } + + TInt fileSize = 0; + error = file.Size(fileSize); + + if (error!= KErrNone) + { + ERR_PRINTF2(_L("Failed to read file size [%d]"), error); + file.Close(); + SetError(error); + return error; + } + + file.Close(); + return fileSize; + } + +/** + * Build the final header to POST for uploading files + * @param aRequest Descriptor with 456 of lenght that contain the final POST request + * @return + */ +void CT_RSocketData::CreateHTTPHeaderEnd(TDes8& aRequest) + { + //TRequestStatus status; + aRequest.SetLength( 0 ); + //Create the rest of the header data + aRequest.Append( KLineBreak ); + aRequest.Append( KBoundaryEnd ); + aRequest.Append( KLineBreak ); + } + + +/** + * Make a HTTP request to the socket + * @param + * @return + */ +void CT_RSocketData::DoCmdHttpGet() + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdHttpGet")); + + TInt err(KErrNone); + //Constant for creating a HTTP request. + const TInt KHTTPSize = 128; + // Buffer that will hold the request. + TBuf8 request; + // Construct the final request. + request.Append( KGETHTTP ); + + INFO_PRINTF1( _L("Write to socket") ); + TRequestStatus status( KRequestPending ); + iSocket->Write( request, status); + User::WaitForRequest( status ); + INFO_PRINTF2( _L("CT_RSocketData::DoCmdHttpGet: Write done: [%d]"), status.Int() ); + err = status.Int(); + + if(err == KErrNone) + { + INFO_PRINTF1( _L("CT_RSocketData::DoCmdHttpGet: Receive from socket") ); + // receive until RecvOneOrMore fails + do + { + RecvOneOrMore(status); + } + while( status.Int() == KErrNone ); + + INFO_PRINTF2( _L("CT_RSocketData::DoCmdHttpGet: Receiving finished. Received [%d] bytes in total"), itotalReceived ); + + // Currently all error codes returned by the server are accepted. + // Should only KErrEof be accepted? + INFO_PRINTF2( _L("Ignoring error code from RSocket::RecvOneOrMore [%d]"), status.Int()); + } + else + { + ERR_PRINTF2(_L("CT_RSocketData::DoCmdHttpGet: iSocket.Write(...) Failed with error %d"), err); + SetError(err); + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdHttpGet")); + } + +/** + * Receive data from a remote host. + * @param status Indicates the complexion status of the request + * @return + */ +void CT_RSocketData::RecvOneOrMore(TRequestStatus &status) + { + TInt err(KErrNone); + // Create variables for receive buffer and received data counting variables. + const TInt KBufferSize(1024); + TBuf8 buffer; + TSockXfrLength received; + iSocket->RecvOneOrMore( buffer, 0, status, received); + User::WaitForRequest( status ); + err = status.Int(); + if( err == KErrNone ) + { + INFO_PRINTF2( _L("CWlanTestWrapper: Received [%d] bytes"), received() ); + itotalReceived += received(); + } + else if( err == KErrEof ) + { + INFO_PRINTF1(_L("End of File reached")); + } + else + { + ERR_PRINTF2(_L("RecvOneOrMore async call failed with error %d"), err); + SetError(err); + } + } + + + +/** + * Check the supported rates for the IAP. + * @param aSection Section to read from the ini file + * @return + */ +void CT_RSocketData::DoCmdCheckSupportedRates(const TTEFSectionName& aSection) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdCheckSupportedRates")); + TBool dataOk = ETrue; + + // Read from the ini file + TInt aRate; + if(!GetIntFromConfig(aSection,KARates,aRate)) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KARates); + SetBlockResult(EFail); + dataOk = EFalse; + } + + // Check if a scan has been made + TPtrC iScanInfoName; + if(!GetStringFromConfig(aSection,KScanInfo,iScanInfoName )) + { + ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KScanInfo); + SetBlockResult(EFail); + dataOk = EFalse; + } + + if (dataOk) + { + CWlanScanInfo* iScanInfo = static_cast(GetDataObjectL(iScanInfoName)); + + // Check if a scan has been made + if( iScanInfo != NULL ) + { + const TUint8 KTemp80211SupRatesId = 1; + const TUint8 KTemp80211SupRatesMaxLen = 18; + // Scan info gives data as "information elements" + TUint8 ieLen(0); + const TUint8* ieData(0); + + TInt err = iScanInfo->InformationElement( KTemp80211SupRatesId, ieLen, &ieData ); + + // Check supported rate if the information element was available + if(err == KErrNone) + { + TBuf8 supRates8; + supRates8.Copy( ieData, ieLen ); + TBool supported = CheckSupportedRates( supRates8, aRate ); + if(!supported) + { + ERR_PRINTF2( _L("%d rate not supportedRates"), aRate ); + SetError(KErrNotSupported); + } + } + else + { + ERR_PRINTF2( _L("err: [%d]"), err ); + SetError(err); + } + } + else + { + ERR_PRINTF1(_L("Failed to get CWlanScanInfo object")); + SetBlockResult(EFail); + } + } + + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdCheckSupportedRates")); + } + +/** + * Review if the rate its supported. + * @param aSupportedRates Rate to calculate and if match with the desired rate + * @param aRate rate to verify if is supporrted, The rate to be checked in 0.5Mb/s units. + * Ie. 2 = 2 * 0.5Mb/s = 1Mb/s. + * @return Etrue if the rate is supported + */ +TBool CT_RSocketData::CheckSupportedRates(const TDesC8& aSupportedRates, const TUint8 aRate) + { + // Supported rates information element format is the following: + // | element id (1 octet) | length (1 octet) | supported rates (1-8 octets) | + // where each octet of supported rates contains one supported rate in + // units of 500 kb/s. The first bit of supported rates field is always 1 + // if the rate belongs to the BSSBasicRateSet, if the rate does not belong + // to the BSSBasicRateSet the first bit is 0. + + // For example Supported rates information element with value + // 0x01,0x02,0x82,0x84 + // would mean that BSSBasicRateSet rates 1Mb/s and 2Mb/s are supported + + TBool supported( EFalse ); + + for ( TInt i( 0 ); i < aSupportedRates.Length(); i++ ) + { + TUint8 rate = aSupportedRates[i] & KBasicRateMask; + if( rate == aRate ) supported = ETrue; + //INFO_PRINTF2( _L("speed rate [%d]"), rate); + switch( rate ) + { + case K80211Rate1Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 1Mbit") ); + break; + case K80211Rate2Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 2Mbit") ); + break; + case K80211Rate5Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 5Mbit") ); + break; + case K80211Rate11Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 11Mbit") ); + break; + case K80211Rate12Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 12Mbit") ); + break; + case K80211Rate18Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 18Mbit") ); + break; + case K80211Rate22Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 22Mbit") ); + break; + case K80211Rate24Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 24Mbit") ); + break; + case K80211Rate36Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 36Mbit") ); + break; + case K80211Rate48Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 48Mbit") ); + break; + case K80211Rate54Mbit: + INFO_PRINTF1( _L("AP can support Speed Rate 54Mbit") ); + break; + + default: + break; + } + } + + return supported; + } + +/** + * Shutdown the socket (RSocket::Shutdown). + * @param aAsyncErrorIndex Command index for async calls to returns errors to + * @return + */ +void CT_RSocketData::DoCmdShutdown( const TInt aAsyncErrorIndex) + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdShutdown")); + INFO_PRINTF1(_L("Starting to shutdown Socket")); + iSocket->Shutdown( RSocket::ENormal, iActCallShutDownSocket->iStatus); + iActCallShutDownSocket->Activate(aAsyncErrorIndex); + IncOutstanding(); + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdShutdown")); + } +/** + * Helper function calling from the destroyer. + * @param + * @return + */ +void CT_RSocketData::Shutdown() + { + TInt err(KErrNone); + TRequestStatus status; + iSocket->Shutdown(RSocket::ENormal, status); + User::WaitForRequest( status ); + err = status.Int(); + if( err != KErrNone ) + { + ERR_PRINTF2( _L("CT_RSocketData::Shutdown(): error[%d]"), err); + SetError(err); + } + } + +/** + * Close de socket. + * @param + * @return + */ +void CT_RSocketData::DoCmdClose() + { + INFO_PRINTF1(_L("*START* CT_RSocketData::DoCmdClose")); + Close(); + INFO_PRINTF1(_L("*END* CT_RSocketData::DoCmdClose")); + } +/** + * Helper function to close the socket. + * @param + * @return + */ +void CT_RSocketData::Close() + { + iSocket->Close(); + iSocketOpened = EFalse; + }