diff -r 000000000000 -r dfb7c4ff071f datacommsserver/esockserver/test/TS_MultiHoming/CEchoSocket.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datacommsserver/esockserver/test/TS_MultiHoming/CEchoSocket.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,879 @@ +// Copyright (c) 2002-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: +// @file CEchoSocket.cpp +// This contains the CEchoSocket class implementation and its saftey timer, CSafety +// +// + +/** + @file +*/ + +#include "CEchoSocket.h" + +CEchoSocket::CEchoSocket() : CActive(EPriorityNormal), + iSockErr(KErrNone), + iPacketSize(CTS_MultiHomingStep::PACKET_SIZE), + iPacketsToSend(CTS_MultiHomingStep::NUM_OF_PACKETS), + iRecvdGood(0), + iProtocol(KProtocolInetUdp), + iUDPTolerance(CTS_MultiHomingStep::UDP_TOLERANCE), + iPtrRecvd(0,0), + iPtrRecvdThisRead(0,0), + iPtrWritn(0,0), + iConsecRecvTimeOuts(0), + iIsListener(EFalse) + { + } + +CEchoSocket::~CEchoSocket() + { + Cancel(); + delete iWritebuf; + delete iReadbufThisRead; + delete iReadbuf; + delete iSafety; + + } + +CEchoSocket* CEchoSocket::NewL() + { + + CEchoSocket* self = new(ELeave) CEchoSocket; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + CEnhancedScheduler::Add(self); + return self; + } + + +void CEchoSocket::ConstructL() + { + iSafety = CSafety::NewL(this); + + iWritebuf = HBufC8::NewMaxL(CTS_MultiHomingStep::MAX_PACKET_SIZE); + iPtrWritn.Set(iWritebuf->Des()); + iReadbuf = HBufC8::NewMaxL(CTS_MultiHomingStep::MAX_PACKET_SIZE); + iPtrRecvd.Set(iReadbuf->Des()); + iReadbufThisRead = HBufC8::NewMaxL(CTS_MultiHomingStep::MAX_PACKET_SIZE); + iPtrRecvdThisRead.Set(iReadbufThisRead->Des()); + } + +void CEchoSocket::RunL() + { + + switch (iState) + { + case EInitialised: + if(iIsListener) + { + iAcceptedConnection.Open( (iTConnection->iSocketServ)); + + iSocket.Accept(iAcceptedConnection, iStatus); + iState = EReady; + SetActive(); + } + else + { + if (KProtocolInetTcp == iProtocol) + { + ConnectTcp(); + iOwnerStep->StepLog(_L("Connecting TCP %S:%i"),&iName, iSockNum); + } + else if (KProtocolInetUdp == iProtocol) + { + BindUdp(); + iOwnerStep->StepLog(_L("Binding UDP %S:%i"), &iName, iSockNum); + } + } + break; + + case EReady: + iSafety->Cancel(); + + if (iStatus == KErrNone) + { + if(iIsListener) + { + RecvDataTcpListen(); + } + else + { + SendData(); + } + } + else + { + iOwnerStep->StepLog(KErrConnectFailed,&iName,iSockNum, iStatus.Int()); + SetComplete(); + } + break; + + case ESentData: + if (iStatus == KErrNone) + { + if(iIsListener) + { + RecvDataTcpListen(); + } + else + { + RecvData(); + } + } + else + { + iOwnerStep->StepLog(KErrSendFailed, &iName, iSockNum, iStatus.Int()); + SetComplete(); // Couldn't send, so bit of a problem... + } + break; + + case ERecvdData: + iSafety->Cancel(); + if(iIsListener && iStatus == KErrEof) + { + SetComplete(); + } + else if(iStatus == KErrNone) + { + TInt err = KErrNone; + // Reset our consecutive count + iConsecRecvTimeOuts = 0; + // Compare sent and received + err = iPtrWritn.Compare(iPtrRecvd); + if (err == KErrNone || iIsListener) + { + iRecvdGood++; + if (iPacketsToSend>0) + if(iIsListener) + SendDataToClient(); + else + SendData(); + else + SetComplete(); + } + else + { + // Try reading again, usualy happens because of a timeout + iOwnerStep->StepLog(KErrPacketsDiff, &iName, iSockNum); + RecvData(); + } + } + else if (KErrCancel == iStatus.Int()) // We cancelled our receive + { + iConsecRecvTimeOuts++; + iOwnerStep->StepLog(_L("Receive timeout on %S:%i,%d"),&iName, iSockNum, + iConsecRecvTimeOuts); + + if (iPacketsToSend > 0 && iConsecRecvTimeOuts < MAX_CONSEC_TIMEOUT) + SendData(); + else + SetComplete(); + } + else + { + TPtrC errorText = CLog::EpocErrorToText(iStatus.Int()); + iOwnerStep->StepLog(KErrRecvFailed, &iName, iSockNum, &errorText); + SetComplete(); + } + break; + + + case EComplete: + iOwnerStep->iOwnerSuite->iScheduler->DecCount(); + if(0 == iOwnerStep->iOwnerSuite->iScheduler->GetCount()) + CEnhancedScheduler::Stop(); + break; + + default: + iOwnerStep->StepLog(KTxtWhatHappened); + break; + + } + // Error handling of iStatus... + + + } + + + + +void CEchoSocket::DoCancel() + { + iSocket.CancelAll(); + // Close is handles in set complete + //iSocket.Close(); + } + +TInt CEchoSocket::Echo(const TInetAddr& aDest, const TInetAddr& aSrc, + const TInt& aSize, const TInt& aPackets, + const TUint& aProto, const TInt& aTol, + TConnDetails* aConn, const TInt& aSockNum, + const TBool aIsListener, CTS_MultiHomingStep* aStep) +/** + * Creates an Echo socket and runs it to completion or error + * @param aSockServ The socket server to attach to + * @param aDest The destination IP address + * @param aSize The packet size to use in bytes + * @param aPackets The number of packets to send + * @param aProto The protocol to use + * @param aTol The UDP data tolerance level + * @return Error value for initialisation stage + */ + { + __ASSERT_ALWAYS(!IsActive(), User::Panic(KTxtCEchoSocket,KErrAlreadyExists)); + __ASSERT_ALWAYS(aSize <= CTS_MultiHomingStep::MAX_PACKET_SIZE, User::Panic(KTxtCEchoSocket,KErrOverflow)); + + // Remember the config + iDestAddr = aDest; + iSrcAddr = aSrc; + iPacketSize = aSize; + iPacketsToSend = aPackets; + iPackets = aPackets; + iProtocol = aProto; + iUDPTolerance = aTol; + iOwnerStep = aStep; + iTConnection = aConn; + iSockNum = aSockNum; + + iIsListener = aIsListener; + + TInt err = KErrNone; + + iPtrWritn.SetLength(aSize); + iPtrRecvd.SetLength(aSize); + + + if(iTConnection == 0) + return KErrGeneral; + // Open the socket for implicit or explicit case + if(iTConnection->iConnectionType != TConnDetails::implicitConn) + { + err = iSocket.Open( (iTConnection->iSocketServ), KAfInet, + iProtocol == KProtocolInetTcp ? KSockStream : KSockDatagram, iProtocol, + (iTConnection->iConnection)); + } + else + { + err = iSocket.Open( (iTConnection->iSocketServ), KAfInet, + iProtocol == KProtocolInetTcp ? KSockStream : KSockDatagram, iProtocol); + } + if (err != KErrNone) + return err; // No point going any further... + + iSocket.Name(iName); + + err = iSocket.SetOpt(KSolInetIp, KSoReuseAddr, 1); + // Ignore this error for unbound sockets + err = iSocket.Bind(iSrcAddr); + if(err != KErrNone) + return err; + + if(iProtocol == KProtocolInetTcp) + { + // Disable the nagle algorithm. + iSocket.SetOpt(KSoTcpNoDelay, KSolInetTcp, 1); + } + if(iIsListener) + { + // Accept a single connection + iSocket.Listen(1); + } + + iState = EInitialised; + + iStatus = KRequestPending; + SetActive(); + + // Increment the echosocket counter and client + iOwnerStep->iOwnerSuite->iScheduler->IncCount(); + + TName addrBuf; + iDestAddr.Output(addrBuf); + iOwnerStep->StepLog(KSockDetails,&iName,iSockNum,&addrBuf,iDestAddr.Port(),iPacketsToSend,iPacketSize); + + TRequestStatus* pS = &iStatus; + User::RequestComplete(pS,KErrNone); + + return KErrNone; + } + + + +void CEchoSocket::ConnectTcp() +/** + * Connects a TCP socket to the remote host. + */ + { + __ASSERT_ALWAYS(iProtocol==KProtocolInetTcp, User::Panic(KTxtCEchoSocket,KErrArgument)); + iSocket.Connect(iDestAddr,iStatus); + iSafety->SetSafety(); + iState = EReady; + SetActive(); + } + +void CEchoSocket::BindUdp() +/** + * Binds a socket to its address + */ + { + __ASSERT_ALWAYS(KProtocolInetUdp == iProtocol, User::Panic(KTxtCEchoSocket,KErrArgument)); + + iSocket.Connect(iDestAddr,iStatus); + iSafety->SetSafety(); + iState = EReady; + SetActive(); + } + + + +void CEchoSocket::SendData() +/** + * Sends a packet on the socket and updates state information + */ + { + // Packet data + TBuf8<100> data; + // Write data to socket + if (iProtocol == KProtocolInetTcp) + { + data.Format(_L8("TCP-packet[%S:%d] MultiHoming"), &iName, iPacketsToSend--); + } + else if (iProtocol == KProtocolInetUdp) + { + data.Format(_L8("UDP-packet[%S:%d] MultiHoming"), &iName, iPacketsToSend--); + } + iPtrWritn.Repeat( data ); + + iPtrRecvd.SetLength( iPtrWritn.Length() ); + + iSocket.Send(iPtrWritn,0,iStatus); + + iState = ESentData; + SetActive(); + } + +void CEchoSocket::SendDataToClient() + { + iAcceptedConnection.Send(iPtrRecvd,0,iStatus); + + iState = ESentData; + SetActive(); + } +void CEchoSocket::RecvDataTcpListen() +/** + * Receives data on socket + * + */ + { + // Receive data + iSafety->SetSafety(); + TInt expected = iPtrRecvd.Length(); + iAcceptedConnection.Read(iPtrRecvd, iStatus); + iOwnerStep->StepLog(_L("Receiving Data TCP Listen %S:%i"),&iName, iSockNum); + iState = ERecvdData; + SetActive(); + } + + + +void CEchoSocket::RecvData() +/** + * Receives data on socket + * + */ + { + // Receive data + iSafety->SetSafety(); + TInt expected = iPtrRecvd.Length(); + if(iProtocol == KProtocolInetTcp) + { + iSocket.Read(iPtrRecvd, iStatus); + } + else if(iProtocol == KProtocolInetUdp) + { + iSocket.Recv(iPtrRecvd, 0, iStatus); + } + if(expected != iPtrRecvd.Length()) + { + _LIT(KErrMsg, "%S: Expected to Recv %i octets, actual is %i"); + iOwnerStep->StepLog(KErrMsg, &iName, expected, iPtrRecvd.Length()); + } + iState = ERecvdData; + SetActive(); + } + +TInt CEchoSocket::LogReport(TBool& aPassed, TInt& aNumSent, TInt& aUdpRate) +/** + * Allows a CEchoSocket to pass back its outcome + * @param aPassed Did the test pass? + * @param aUdpRate Percentage of UDP packets dropped + * @return The last error state of the socket + */ + { + __ASSERT_ALWAYS(iState==EComplete,User::Panic(KTxtCEchoSocket,KErrNotReady)); + + aPassed=EFalse; + aNumSent = iPackets; + if (KProtocolInetTcp == iProtocol && iRecvdGood == iPackets) + { + aPassed=ETrue; + aUdpRate=0; + } + else + { + TInt dropped = 100; + if (iPackets != 0) // No div/0 errs thanks... + // nL = nS - nR + // nL/nS = 1 - nR/nS + dropped = 100 - ((100*iRecvdGood) / iPackets); + + if (dropped <= iUDPTolerance) + aPassed=ETrue; + aUdpRate= dropped; + } + return iSockErr; + } + + +void CEchoSocket::SafetyCall() +/** + * Allows the safety timer access, without becoming a friend class. + */ + { + if (iIsListener && (KProtocolInetTcp == iProtocol)) + { + iAcceptedConnection.CancelAll(); + } + + iSocket.CancelAll(); + } +void CEchoSocket::SetComplete() +/** + * Sets the socket to completion status. + */ + { + iSafety->Cancel(); + iSocket.CancelAll(); + iSocket.Close(); + if(iIsListener && (KProtocolInetTcp == iProtocol)) + { + iAcceptedConnection.CancelAll(); + iAcceptedConnection.Close(); + } + + + + + iSockErr = iStatus.Int(); // Record the last error for use by caller. + iStatus = KRequestPending; + iState = EComplete; + if(!IsActive() ) + SetActive(); + TRequestStatus* pS = &iStatus; + User::RequestComplete(pS,KErrNone); + + } + + + + + +CSafety::CSafety() : CActive(EPriorityNormal), iTime(CEchoSocket::SAFETY_TIMEOUT) + { + } + + +CSafety::~CSafety() + { + Cancel(); + iSafety.Close(); + } + +CSafety* CSafety::NewL(CEchoSocket* aOwner) + { + CSafety* self = new(ELeave) CSafety; + CleanupStack::PushL(self); + self->ConstructL(aOwner); + CleanupStack::Pop(); + return self; + } + + +void CSafety::ConstructL(CEchoSocket* aOwner) + { + myOwner=aOwner; + iSafety.CreateLocal(); + CEnhancedScheduler::Add(this); + } + +void CSafety::RunL() + { + myOwner->SafetyCall(); + } + + +void CSafety::DoCancel() + { + iSafety.Cancel(); + } + +void CSafety::SetSafety() + { + __ASSERT_ALWAYS(!IsActive(), User::Panic(KTxtCEchoSocket, KErrAlreadyExists)); + iSafety.After(iStatus, iTime); + SetActive(); + } +CSplitEchoSocket* CSplitEchoSocket::NewL() + { + CSplitEchoSocket* self = new (ELeave)CSplitEchoSocket(); + CleanupStack::PushL(self); + self->ConstructL(); + CEnhancedScheduler::Add(self); + CleanupStack::Pop(self); + return self; + } + +CSplitEchoSocket::CSplitEchoSocket() : CEchoSocket() + { + } + +CSplitEchoSocket::~CSplitEchoSocket() + { + } + +TInt CSplitEchoSocket::Echo(const TInetAddr& aDest, const TInetAddr& aSrc, + const TInt& aSize, const TInt& aPackets, + const TUint& aProto, const TInt& aTol, + TConnDetails* aConn, const TInt& aSockNum, + const TBool aIsListener, CTS_MultiHomingStep* aStep) +/** + * Creates an Echo socket and runs it to completion or error + * @param aSockServ The socket server to attach to + * @param aDest The destination IP address + * @param aSize The packet size to use in bytes + * @param aPackets The number of packets to send + * @param aProto The protocol to use + * @param aTol The UDP data tolerance level + * @return Error value for initialisation stage + */ + { + __ASSERT_ALWAYS(!IsActive(), User::Panic(KTxtCEchoSocket,KErrAlreadyExists)); + __ASSERT_ALWAYS(aSize <= CTS_MultiHomingStep::MAX_PACKET_SIZE, User::Panic(KTxtCEchoSocket,KErrOverflow)); + + // Remember the config + iDestAddr = aDest; + iSrcAddr = aSrc; + iPacketSize = aSize; + iPacketsToSend = aPackets; + iPackets = aPackets; + iProtocol = aProto; + iUDPTolerance = aTol; + iOwnerStep = aStep; + iTConnection = aConn; + iSockNum = aSockNum; + + iIsListener = aIsListener; + + TInt err = KErrNone; + + iPtrWritn.SetLength(aSize); + iPtrRecvd.SetLength(aSize); + + + if(iTConnection == 0) + return KErrGeneral; + // Open the socket for implicit or explicit case + if(iTConnection->iConnectionType != TConnDetails::implicitConn) + { + err = iSocket.Open( (iTConnection->iSocketServ), KAfInet, + iProtocol == KProtocolInetTcp ? KSockStream : KSockDatagram, iProtocol, + (iTConnection->iConnection)); + } + else + { + err = iSocket.Open( (iTConnection->iSocketServ), KAfInet, + iProtocol == KProtocolInetTcp ? KSockStream : KSockDatagram, iProtocol); + } + if (err != KErrNone) + return err; // No point going any further... + + iSocket.Name(iName); + + if(iIsListener) // Don't bind if we are only sending + { + err = iSocket.Bind(iSrcAddr); + iOwnerStep->StepLog(_L("Binding %S:%i"),&iName, iSockNum); + if(err != KErrNone) + return err; + + // Accept a single connection + if (iProtocol == KProtocolInetTcp) + { + iSocket.Listen(1); + iOwnerStep->StepLog(_L("Listening %S:%i"),&iName, iSockNum); + } + } + + iState = EInitialised; + iStatus = KRequestPending; + SetActive(); + + // Increment the echosocket counter and client + iOwnerStep->iOwnerSuite->iScheduler->IncCount(); + + TName addrBuf; + iDestAddr.Output(addrBuf); + iOwnerStep->StepLog(KSockDetails,&iName,iSockNum,&addrBuf,iDestAddr.Port(),iPacketsToSend,iPacketSize); + + TRequestStatus* pS = &iStatus; + User::RequestComplete(pS,KErrNone); + + return KErrNone; + } + + +void CSplitEchoSocket::RunL() + { + switch (iState) + { + case EInitialised: + if (KProtocolInetTcp == iProtocol) + { + if(iIsListener) + { + iAcceptedConnection.Open( (iTConnection->iSocketServ)); + iSocket.Accept(iAcceptedConnection, iStatus); + iOwnerStep->StepLog(_L("Waiting for TCP accept on %S:%i"),&iName, iSockNum); + iSafety->SetSafety(); + iState = EReady; + SetActive(); + } + else + { + ConnectTcp(); + iOwnerStep->StepLog(_L("Connecting TCP %S:%i"),&iName, iSockNum); + } + } + else if (KProtocolInetUdp == iProtocol) + { + if(iIsListener) + { + RecvData(); + } + else + { + BindUdp(); + iOwnerStep->StepLog(_L("Binding UDP %S:%i"), &iName, iSockNum); + } + } + break; + + case EReady: + iSafety->Cancel(); + if (iStatus.Int() == KErrNone) + { + if(iIsListener) + { + if (KProtocolInetTcp == iProtocol) + { + RecvDataTcpListen(); + } + else + { + RecvData(); + } + } + else + { + SendData(); + } + } + else + { + iOwnerStep->StepLog(KErrConnectFailed,&iName,iSockNum, iStatus.Int()); + SetComplete(); + } + break; + + case ESentData: + iSafety->Cancel(); + if (iStatus == KErrNone) + { + if(iIsListener) + { + if (KProtocolInetTcp == iProtocol) + { + RecvDataTcpListen(); + } + else + { + RecvData(); + } + } + else + { + iRecvdGood++; // Fake that we've received all we should (sending socket doesn't receive) + // Blindly send, no receiving + if (iPacketsToSend>0) + { + SendData(); + } + else + { + SetComplete(); + } + } + } + else + { + iOwnerStep->StepLog(KErrSendFailed, &iName, iSockNum, iStatus.Int()); + SetComplete(); // Couldn't send, so bit of a problem... + } + break; + + case ERecvdData: + iSafety->Cancel(); + if(iIsListener && (iStatus.Int() == KErrEof) ) + { + iRecvdGood++; + iStatus = KErrNone; + SetComplete(); + } + else if(iStatus.Int() == KErrNone) + { + // Reset our consecutive count + iConsecRecvTimeOuts = 0; + if (iIsListener) + { + iRecvdGood++; + + if (iPacketsToSend > 0) + { + if(iIsListener) + { + if (KProtocolInetUdp == iProtocol) + { + RecvData(); + } + else + { + RecvDataTcpListen(); + } + } + else + { + SendData(); + } + } + else + { + SetComplete(); + } + } + else + { + // Try reading again, usualy happens because of a timeout + iOwnerStep->StepLog(KErrPacketsDiff, &iName, iSockNum); + RecvData(); + } + } + else if (KErrCancel == iStatus.Int()) // We cancelled our receive + { + iConsecRecvTimeOuts++; + iOwnerStep->StepLog(_L("Receive timeout on %S:%i,%d"),&iName, iSockNum, + iConsecRecvTimeOuts); + + iOwnerStep->StepLog(_L("%d received packets, %d still to send"),iRecvdGood, iPacketsToSend); + + if ( (iPacketsToSend - iUDPTolerance) > 0 && iConsecRecvTimeOuts < MAX_CONSEC_TIMEOUT) + { + if (iIsListener) + { + if (KProtocolInetUdp == iProtocol) + { + RecvData(); + } + else + { + RecvDataTcpListen(); + } + } + else + { + if (KProtocolInetTcp == iProtocol) + SendData(); + } + } + else + { + SetComplete(); + } + } + else + { + TPtrC errorText = CLog::EpocErrorToText(iStatus.Int()); + iOwnerStep->StepLog(KErrRecvFailed, &iName, iSockNum, &errorText); + SetComplete(); + } + break; + + + case EComplete: + iOwnerStep->iOwnerSuite->iScheduler->DecCount(); + if(0 == iOwnerStep->iOwnerSuite->iScheduler->GetCount()) + CEnhancedScheduler::Stop(); + break; + + default: + iOwnerStep->StepLog(KTxtWhatHappened); + break; + + } + } + +void CSplitEchoSocket::RecvData() +/** + * Receives data on socket + * + */ + { + // Receive data + iSafety->SetSafety(); + TInt expected = iPtrRecvd.Length(); + if(iProtocol == KProtocolInetTcp) + { + iSocket.Read(iPtrRecvd, iStatus); + } + else if(iProtocol == KProtocolInetUdp) + { + if (iIsListener) + { + //iSocket.RecvFrom(iPtrRecvd, iSrcAddr, 0, iStatus); + iSocket.Recv(iPtrRecvd, 0, iStatus); + iOwnerStep->StepLog(_L("Receiving UDP Packet...")); + } + else + { + iSocket.Recv(iPtrRecvd, 0, iStatus); + } + } + if (iIsListener) + iPacketsToSend--; // Decrement this + + iState = ERecvdData; + SetActive(); + } +