--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nettools/conntest/Engine/SocketsWrite.cpp Thu Dec 17 08:39:25 2009 +0200
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2006-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: CSocketsWrite is an active object which implements data
+ * sending through an already open socket using UDP or TCP
+ *
+ */
+
+// INCLUDE FILES
+#include <e32svr.h>
+
+#include "SocketsWrite.h"
+#include "TimeOutTimer.h"
+#include "ConnTest.pan"
+#include "uinotify.h"
+#include "Utils.h"
+#include "conntest.hrh"
+#include "datasendnotifyhandler.h"
+
+// CONSTANTS
+static const TInt KTimeOut = 30000000; // 30 seconds time-out
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::NewL(MUINotify& aConsole, RSocket& aSocket, MDataSendNotifyHandler& aSendHandler)
+// EPOC two phased constructor
+// ---------------------------------------------------------
+//
+CSocketsWrite* CSocketsWrite::NewL( MUINotify& aConsole,
+ RSocket& aSocket,
+ MDataSendNotifyHandler& aSendHandler )
+ {
+ CSocketsWrite* self = CSocketsWrite::NewLC(aConsole, aSocket, aSendHandler);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::NewLC(MUINotify& aConsole, RSocket& aSocket, MDataSendNotifyHandler& aSendHandler)
+// EPOC two phased constructor
+// ---------------------------------------------------------
+//
+CSocketsWrite* CSocketsWrite::NewLC( MUINotify& aConsole,
+ RSocket& aSocket,
+ MDataSendNotifyHandler& aSendHandler )
+ {
+ CSocketsWrite* self = new (ELeave) CSocketsWrite(aConsole, aSocket, aSendHandler);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::CSocketsWrite(MUINotify& aConsole, RSocket& aSocket, MDataSendNotifyHandler& aSendHandler)
+// Constructor
+// ---------------------------------------------------------
+//
+CSocketsWrite::CSocketsWrite( MUINotify& aConsole,
+ RSocket& aSocket,
+ MDataSendNotifyHandler& aSendHandler ):
+ CActive(EPriorityStandard),
+ iSocket(aSocket),
+ iConsole(aConsole),
+ iPackets(0),
+ iPacketSize(0),
+ iReqBodySubmitBufferPtr(0,0),
+ iSendHandler(aSendHandler)
+ {
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::~CSocketsWrite()
+// Destructor
+// ---------------------------------------------------------
+//
+CSocketsWrite::~CSocketsWrite()
+ {
+ Cancel();
+ delete iReqBodySubmitBuffer;
+ delete iTimer;
+ iTimer = NULL;
+ if(iTransferBuffer)
+ {
+ delete iTransferBuffer;
+ iTransferBuffer = NULL;
+ }
+ if(iWriteBuffer)
+ {
+ delete iWriteBuffer;
+ iWriteBuffer = NULL;
+ }
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::ConstructL()
+// EPOC two-phased constructor
+// ---------------------------------------------------------
+//
+void CSocketsWrite::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+
+ iTransferBuffer = HBufC8::NewL(KMaxSendBuffer);
+ iWriteBuffer = HBufC8::NewL(KMaxSendBuffer);
+
+ iTimeOut = KTimeOut;
+ iTimer = CTimeOutTimer::NewL(10, *this);
+ iWriteStatus = EWaiting;
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::RunL()
+// Called when request has completed.
+// ---------------------------------------------------------
+//
+void CSocketsWrite::RunL()
+ {
+ if(!iFlood)
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::RunL - iStatus = %d"), iStatus.Int());
+ }
+ // Active object request complete handler
+ if (iStatus == KErrNone)
+ {
+ switch(iWriteStatus)
+ {
+ // Character has been written to socket
+ case ESending:
+ if(!iFlood)
+ SendNextPacket();
+ else
+ DoFloodWrite();
+ break;
+ default:
+ User::Panic(KPanicSocketsWrite, EConnTestBadStatus);
+ break;
+ };
+ }
+ else
+ {
+ // Error: pass it up to user interface
+ iTimer->Cancel();
+ TBuf<50> err;
+ err.Format(_L("\nCSocketsWrite error %d\n"), iStatus.Int());
+ //iConsole.ErrorNotify(_L("\nCSocketsWrite error"), iStatus.Int());
+ iConsole.PrintNotify(err);
+ iWriteStatus = ECommsFailed;
+ }
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::DoCancel()
+// Cancel ongoing requests.
+// ---------------------------------------------------------
+//
+void CSocketsWrite::DoCancel()
+ {
+ RDebug::Print(_L("CSocketsWrite::DoCancel"));
+
+ // Cancel asychronous write request
+ iSocket.CancelWrite();
+
+ iTimer->Cancel();
+ }
+
+
+// ---------------------------------------------------------
+// CSocketsWrite::IssueWriteL()
+// Add data into buffer for sending.
+// ---------------------------------------------------------
+//
+void CSocketsWrite::IssueWriteL(const TDesC8& aData, TInetAddr* aAddress, TUint aProtocol)
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::IssueWriteL - aData.Length = %d"), aData.Length());
+
+ iFlood = EFalse;
+ iAddress = aAddress;
+ iProtocol = aProtocol;
+
+ // Write data to a stream socket
+ if ((aData.Length() + iTransferBuffer->Length()) > iTransferBuffer->Des().MaxLength())
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::IssueWriteL - data doesn't fit in the transferbuffer"));
+ RDebug::Print( _L(
+ "ConnTest: CSocketsWrite::IssueWriteL - data length = %d, buffer length = %d, buffer max length = %d"),
+ aData.Length(), iTransferBuffer->Length(), iTransferBuffer->Des().MaxLength() );
+ // Not enough space in buffer
+ User::Leave(KErrOverflow);
+ }
+
+ // Add new data to buffer
+ iTransferBuffer->Des().Append(aData);
+
+ if (!IsActive())
+ {
+ SendNextPacket();
+ }
+ }
+
+// ---------------------------------------------------------
+// CSocketsWrite::IssueWriteL()
+// Flood data over socket
+// ---------------------------------------------------------
+//
+void CSocketsWrite::IssueWriteL( const TDesC8& aData,
+ TInetAddr* aAddress,
+ TUint aProtocol,
+ TInt aCount )
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::IssueWriteL - flood, packet count=%d"), aCount);
+ RDebug::Print(_L("ConnTest: CSocketsWrite::IssueWriteL - aData.Length = %d"), aData.Length());
+ iFlood = ETrue;
+ iCount = 0;
+ iPackets = aCount;
+ iPacketSize = aData.Length();
+
+ iAddress = aAddress;
+ iProtocol = aProtocol;
+
+ // Write data to a stream socket
+ if (aData.Length() > iTransferBuffer->Des().MaxLength())
+ {
+ // Not enough space in buffer
+ User::Leave(KErrOverflow);
+ }
+
+ // Add new data to buffer
+ iTransferBuffer->Des().Zero();
+ iTransferBuffer->Des().Append(aData);
+ iWriteBuffer->Des().Copy(*iTransferBuffer);
+ if (!IsActive())
+ {
+ DoFloodWrite();
+ }
+ }
+
+// -------------------------------------------------------------------------
+// CSocketsWrite::IssueWriteL()
+// Add data into buffer for sending POST request, initializes body data.
+// -------------------------------------------------------------------------
+//
+void CSocketsWrite::IssueWriteL( const TDesC8& aData,
+ TInetAddr* aAddress,
+ TUint aProtocol,
+ TInt aPacketSize,
+ TInt aPackets )
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::IssueWriteL - aData.Length = %d"), aData.Length());
+ iFlood = EFalse;
+
+ iPackets = aPackets;
+ iPacketSize = aPacketSize;
+
+ delete iReqBodySubmitBuffer;
+ iReqBodySubmitBuffer = NULL;
+ iReqBodySubmitBuffer = HBufC8::NewMaxL(KSendDataSize);
+ iReqBodySubmitBufferPtr.Set(iReqBodySubmitBuffer->Des());
+
+ // Create body chunk
+ Utils::CreateDataChunk(iReqBodySubmitBufferPtr, iPacketSize);
+ iDataChunkCount = 0;
+
+ IssueWriteL(aData, aAddress, aProtocol);
+ }
+
+// ---------------------------------------------------------
+// CSocketsWrite::SendNextPacket()
+// Write data from buffer to socket.
+// ---------------------------------------------------------
+//
+void CSocketsWrite::SendNextPacket()
+ {
+ RDebug::Print(_L("ConnTest: CSocketsWrite::SendNextPacket - iTransferBuffer.Length = %d, iPackets = %d"), iTransferBuffer->Length(), iPackets);
+
+ iTimer->Cancel(); // Cancel TimeOut timer
+ iWriteStatus = EWaiting;
+
+ if (iTransferBuffer->Length() > 0)
+ {
+ // Move data from transfer buffer to actual write buffer
+ iWriteBuffer->Des().Copy(*iTransferBuffer);
+ iTransferBuffer->Des().Zero();
+
+ switch(iProtocol)
+ {
+ case KProtocolInetTcp:
+ iSocket.Write(*iWriteBuffer, iStatus); // Initiate actual write
+ break;
+
+ case KProtocolInetUdp:
+ iSocket.SendTo(*iWriteBuffer, *iAddress, 0, iStatus);
+ break;
+ }
+ iSendHandler.NotifySend(iWriteBuffer->Length());
+ // Request timeout
+ iTimer->After(iTimeOut);
+ SetActive();
+ iWriteStatus = ESending;
+ }
+ else if(iPackets)
+ {
+ // We are sending body data, i.e. this is POST request
+ if(iDataChunkCount == 0)
+ {
+ iConsole.PrintNotify(_L("Sending body...\n"));
+ iSentBytes = 0;
+ iStartTime.UniversalTime();
+ }
+
+ TBool noMoreData = iDataChunkCount < iPackets ? EFalse : ETrue;
+ ++iDataChunkCount;
+
+ if(noMoreData)
+ {
+ // Throughput calculation
+ TBuf8<128> b(_L8("Body sent\n"));
+ Utils::CalculateThroughput(b, iStartTime, iSentBytes);
+
+ b.Append(_L("\n\n"));
+ iConsole.PrintNotify(b);
+
+ iPackets = 0;
+ iPacketSize = 0;
+ iSentBytes = 0;
+
+ return;
+ }
+
+ iSentBytes += iReqBodySubmitBufferPtr.Length();
+ iSocket.Write(iReqBodySubmitBufferPtr, iStatus);
+ SetActive();
+ iWriteStatus = ESending;
+
+ }
+ }
+
+// ---------------------------------------------------------
+// CSocketsWrite::DoFloodWrite()
+// Floods the data to the socket
+// ---------------------------------------------------------
+//
+void CSocketsWrite::DoFloodWrite()
+ {
+ //RDebug::Print(_L("ConnTest: CSocketsWrite::DoFloodWrite: %d"),iCount); // eats CPU
+ iTimer->Cancel(); // Cancel TimeOut timer
+ iWriteStatus = EWaiting;
+ if (iCount != iPackets)
+ {
+ if( iTransferBuffer->Length() > 0)
+ {
+ switch(iProtocol)
+ {
+ case KProtocolInetTcp:
+ iSocket.Write(*iWriteBuffer, iStatus); // Initiate actual write
+ break;
+
+ case KProtocolInetUdp:
+ {
+ TUint32* seqNumberPointer = (TUint32*)(iTransferBuffer->Des().Ptr());
+ *seqNumberPointer = ByteOrder::Swap32( iCount ); // put sequence number into to the packet
+ iSocket.SendTo(*iTransferBuffer, *iAddress, 0, iStatus);
+ break;
+ }
+ default:
+ iConsole.ErrorNotify(_L("Unsupproted protocol\n\n"),KErrNotSupported );
+ return;
+ }
+
+ iCount++;
+ iTimer->After(iTimeOut);
+ SetActive();
+ iWriteStatus = ESending;
+ }
+ }
+ else
+ {
+ iTransferBuffer->Des().Zero();
+ iWriteBuffer->Des().Zero();
+ iSendHandler.NotifySend(iPacketSize*iPackets);
+ iFlood = EFalse;
+ iCount = 0;
+ iPackets = 0;
+ iPacketSize = 0;
+ }
+ }
+
+// ---------------------------------------------------------
+// CSocketsWrite::TimerExpired()
+// Timeout, show error notification.
+// ---------------------------------------------------------
+//
+void CSocketsWrite::TimerExpired()
+ {
+ Cancel();
+ iWriteStatus = ECommsFailed;
+ iConsole.ErrorNotify(_L("Write operation timed out\n"), KErrTimedOut);
+ }
+