diff -r 000000000000 -r dfb7c4ff071f datacommsserver/esockserver/test/protocols/pdummy/PDUMMY.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datacommsserver/esockserver/test/protocols/pdummy/PDUMMY.CPP Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,2471 @@ +// Copyright (c) 1997-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 +#include "ES_DUMMY.H" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pdummy.h" + + +#ifdef _DEBUG +// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module +// (if it could happen through user error then you should give it an explicit, documented, category + code) +_LIT(KSpecAssert_ESockTestPDUMMY, "ESockTestPDUMMY."); +#endif + +const TInt KPDummyDefaultGranularity=0xA; // Default number of incoming messages the protocol can queue up + +//--------------------------------------------------------------------------------------------------------- + + +CAsyncSocketErrorer* CAsyncSocketErrorer::NewL(MSocketNotify& aSocket,TInt aErrorCode,TUint aOpMask, + CDummyProtocol * apProtocols, CDummyProvd* aOwner,const TDesC8* aListenData ) + { + return new(ELeave) CAsyncSocketErrorer(aSocket, aErrorCode, aOpMask,apProtocols,aOwner,aListenData); + } + +CAsyncSocketErrorer::CAsyncSocketErrorer(MSocketNotify& aSocket, TInt aErrorCode, TUint aOpMask, + CDummyProtocol* apProtocols, CDummyProvd* aOwner, const TDesC8* aListenData): + CActive(KMaxTInt), + iSocket(aSocket), + iErrorCode(aErrorCode), + iOpMask(aOpMask), + ipProtocols(apProtocols), + iOwner(aOwner), + iListenData(aListenData) + { + CActiveScheduler::Add(this); + SetActive(); + TRequestStatus* p = &iStatus; + User::RequestComplete(p, KErrNone); + } + +void CAsyncSocketErrorer::RunL() + { + CDummyProvd* p = NULL; + if ( iErrorCode == KErrNone ) + { + TRAP(iErrorCode,p = CDummyProvd::NewL(*ipProtocols);); + if (iErrorCode) + { + iOpMask = MSocketNotify::EErrorFatal; + } + } + if ( iErrorCode == KErrNone ) + { + if(iListenData) + { + iSocket.ConnectComplete(*p, *iListenData); + } + else + { + iSocket.ConnectComplete(*p); + } + } + else + { + iSocket.Error(iErrorCode,iOpMask); + } + iOwner->DestroyAsyncErrorer(); // ie "delete this" + } + +CAsyncSocketErrorer::~CAsyncSocketErrorer() + { + Cancel(); + } + +void CAsyncSocketErrorer::DoCancel() + { + } + +//--------------------------------------------------------------------------------------------------------- + +NONSHARABLE_CLASS(CDummyProvd::CFlowOnTimer): public CTimer + { +public: + static CFlowOnTimer* NewL(CDummyProvd& aProvd, MSocketNotify& aSocketNotify); + virtual ~CFlowOnTimer(); + + virtual void RunL(); + +private: + CFlowOnTimer(CDummyProvd& aProvd, MSocketNotify& aSocket); + + CDummyProvd& iProvd; + MSocketNotify& iSocketNotify; + }; + + +CDummyProvd::CFlowOnTimer* CDummyProvd::CFlowOnTimer::NewL(CDummyProvd& aProvd, MSocketNotify& aSocketNotify) + { + CFlowOnTimer* self = new(ELeave) CFlowOnTimer(aProvd, aSocketNotify); + CleanupStack::PushL(self); + self->ConstructL(); + CActiveScheduler::Add(self); + CleanupStack::Pop(self); + return self; + } + +CDummyProvd::CFlowOnTimer::CFlowOnTimer(CDummyProvd& aProvd, MSocketNotify& aSocketNotify) + : CTimer(CActive::EPriorityStandard), iProvd(aProvd), iSocketNotify(aSocketNotify) + { + } + + +CDummyProvd::CFlowOnTimer::~CFlowOnTimer() + { + Cancel(); + } + +void CDummyProvd::CFlowOnTimer::RunL() + { + iProvd.iFlowOffWriteTimeout = 0; + iSocketNotify.CanSend(); + } + +enum TDPanic + { + EBadProtocol, + EBadCall, + ENotBound, + ENotStarted, + EInterfaceNotDeleted, + EIdAndNoHolder, + EIfAndHolder, + ETestPanic + }; + +// RTest test(_L("Dummy protocol")); + +LOCAL_C void Panic(TDPanic aPanic) +// +// Panic the Protocol +// + { + + User::Panic(_L("Dummy Prot"),aPanic); + } + +extern "C" + { + IMPORT_C CProtocolFamilyBase* InstallDummy(void); // Force export + + EXPORT_C CProtocolFamilyBase * InstallDummy(void) + // + // Create a new protocol family + // + { + return CDProtocolFamily::NewL(); + } + } + +CDProtocolFamily* CDProtocolFamily::NewL() +// +// +// + { + CDProtocolFamily* pf = new (ELeave) CDProtocolFamily(); + CleanupStack::PushL(pf); + pf->ConstructL(); + CleanupStack::Pop(); + return pf; + } + +void CDProtocolFamily::ConstructL() +// +// +// + { + // Force a fail on Memory tests + char* ptr=new(ELeave) char; + delete ptr; + + } + +CDProtocolFamily::CDProtocolFamily() : CProtocolFamilyBase() + { + iProtocolDescs[0].iAddrFamily=KDummyAddrFamily; + iProtocolDescs[0].iSockType=KSockDatagram; + iProtocolDescs[0].iProtocol=KDummyOne; + iProtocolDescs[0].iVersion=TVersion(KDummyMajor,KDummyMinor,KDummyBuild); + iProtocolDescs[0].iByteOrder=EBigEndian; + // KSIRequiresOwnerInfo is required to ensure that SetOption(KSoSetPlatSecApi) is issued to + // TransportFlowShim for NoBearer() testing. + iProtocolDescs[0].iServiceInfo=kDDatagramServiceInfo|KSIPeekData|KSIRequiresOwnerInfo; + iProtocolDescs[0].iSecurity=KSocketNoSecurity; + iProtocolDescs[0].iMessageSize=0x300; + iProtocolDescs[0].iName=KDummyOneName; + iProtocolDescs[0].iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains; + iProtocolDescs[0].iNamingServices=KNSNameResolution|KNSServiceResolution|KNSInfoDatabase; + iProtocolDescs[0].iNumSockets=100; + + iProtocolDescs[1].iAddrFamily=KDummyAddrFamily; + iProtocolDescs[1].iSockType=KSockStream; + iProtocolDescs[1].iProtocol=KDummyTwo; + iProtocolDescs[1].iVersion=TVersion(KDummyMajor,KDummyMinor,KDummyBuild); + iProtocolDescs[1].iByteOrder=EBigEndian; + iProtocolDescs[1].iServiceInfo=KDStreamServiceInfo; + iProtocolDescs[1].iSecurity=KSocketNoSecurity; + iProtocolDescs[1].iMessageSize=KSocketMessageSizeIsStream; + iProtocolDescs[1].iName=KDummyTwoName; + iProtocolDescs[1].iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains; + iProtocolDescs[1].iNamingServices=0; + iProtocolDescs[1].iNumSockets=100; + + iProtocolDescs[2].iAddrFamily=KDummyAddrFamily; + iProtocolDescs[2].iSockType=KSockSeqPacket; + iProtocolDescs[2].iProtocol=KDummyThree; + iProtocolDescs[2].iVersion=TVersion(KDummyMajor,KDummyMinor,KDummyBuild); + iProtocolDescs[2].iByteOrder=EBigEndian; + iProtocolDescs[2].iServiceInfo=KSIReliable|KSIInOrder|KSIDatagram|KSIGracefulClose|KSIBroadcast|KSIQOS|KSICanReconnect|KSIConnectData|KSIDisconnectData; + iProtocolDescs[2].iSecurity=KSocketNoSecurity; + iProtocolDescs[2].iMessageSize=KSocketMessageSizeNoLimit; + iProtocolDescs[2].iName=KDummyThreeName; + iProtocolDescs[2].iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains|ETransport|EPreferDescriptors|EUseCanSend; + iProtocolDescs[2].iNamingServices=0; + iProtocolDescs[2].iNumSockets=100; + + iProtocolDescs[3].iAddrFamily=KDummyAddrFamily; + iProtocolDescs[3].iSockType=KSockStream; + iProtocolDescs[3].iProtocol=KDummyFour; + iProtocolDescs[3].iVersion=TVersion(KDummyMajor,KDummyMinor,KDummyBuild); + iProtocolDescs[3].iByteOrder=EBigEndian; + iProtocolDescs[3].iServiceInfo=KDStreamServiceInfo; + iProtocolDescs[3].iSecurity=KSocketNoSecurity; + iProtocolDescs[3].iMessageSize=KSocketMessageSizeIsStream; + iProtocolDescs[3].iName=KDummyFourName; + iProtocolDescs[3].iServiceTypeInfo=ESocketSupport|ENeedMBufs; + iProtocolDescs[3].iNamingServices=0; + iProtocolDescs[3].iNumSockets=100; + + iProtocolDescs[4].iAddrFamily=KDummyAddrFamily; + iProtocolDescs[4].iSockType=KSockDatagram; + iProtocolDescs[4].iProtocol=KDummyFive; + iProtocolDescs[4].iVersion=TVersion(KDummyMajor,KDummyMinor,KDummyBuild); + iProtocolDescs[4].iByteOrder=EBigEndian; + iProtocolDescs[4].iServiceInfo=kDDatagramServiceInfo|KSIPeekData; + iProtocolDescs[4].iSecurity=KSocketNoSecurity; + iProtocolDescs[4].iMessageSize=KSocketMessageSizeNoLimit; + iProtocolDescs[4].iName=KDummyFiveName; + iProtocolDescs[4].iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains; + iProtocolDescs[4].iNamingServices=KNSNameResolution|KNSServiceResolution|KNSInfoDatabase; + iProtocolDescs[4].iNumSockets=100; + + __DECLARE_NAME(_S("CDProtocolFamily")); + } + +#pragma warning( disable : 4100 ) + +TInt CDProtocolFamily::Install() + { + // Force a fail on Memory tests + char* ptr=new char; + if (!ptr) + return KErrNoMemory; + delete ptr; + return KErrNone; + } + +TInt CDProtocolFamily::Remove() + { + return KErrNone; + } + +TUint CDProtocolFamily::ProtocolList(TServerProtocolDesc *& aProtocolDescPointer) + { + + aProtocolDescPointer=new TServerProtocolDesc[KPDummyNumProtocols]; + if (!aProtocolDescPointer) + return 0; + + Mem::Copy(aProtocolDescPointer, iProtocolDescs, sizeof(TServerProtocolDesc)*KPDummyNumProtocols); + + TRAP_IGNORE(Nif::CheckInstalledMBufManagerL();) + + return KPDummyNumProtocols; + }; + +CProtocolBase * CDProtocolFamily::NewProtocolL(TUint /* aSockType */,TUint aProtocol) + { + + CDummyProtocol* p=CDummyProtocol::NewL(aProtocol, &iProtocolDescs[aProtocol-1]); + return p; + } + + +//--------------------------------------------------------------------------------------------------------- + + +CServProviderBase * CDummyProtocol::NewSAPL(TUint /*aProtocol*/) + { + return CDummyProvd::NewL(*this); + } + + +CHostResolvProvdBase* CDummyProtocol::NewHostResolverL() + { + return CDatagramHostResolver::NewL(); + } + +CServiceResolvProvdBase* CDummyProtocol::NewServiceResolverL() + { + return CDatagramServResolver::NewL(); + } + +CNetDBProvdBase* CDummyProtocol::NewNetDatabaseL() + { + return CDatagramNetDataBase::NewL(); + } + +CDummyProtocol::~CDummyProtocol() + { + for (TInt i=0;iClose(); + } + } + + +void CDummyProtocol::InitL(TDesC& /*aTag*/) + { + // Force a fail on Memory tests + char* ptr=new(ELeave) char; + delete ptr; + } + +void CDummyProtocol::BindL(CProtocolBase* /*aProtocol*/, TUint /*anId*/) + { + // Force a fail on Memory tests + char* ptr=new(ELeave) char; + delete ptr; + } + +void CDummyProtocol::BindToL(CProtocolBase* aProtocol) + { + // Force a fail on Memory tests + char* ptr=new(ELeave) char; + delete ptr; + iProtocols.AppendL(aProtocol); + aProtocol->Open(); + } + + +void CDummyProtocol::StartL(void) + { + // Force a fail on Memory tests + char* ptr=new(ELeave) char; + delete ptr; + iIsStarted=ETrue; + } + +TInt CDummyProtocol::Send(RMBufChain &,CProtocolBase* /*aSourceProtocol*/) + { + return 1; + } + +TInt CDummyProtocol::Send(TDes8 &, TSockAddr* /*to*/,TSockAddr* /*from*/,CProtocolBase* /*aSourceProtocol*/) + { + return 1; + } + +void CDummyProtocol::Process(RMBufChain &,CProtocolBase* /*aSourceProtocol*/) + { + } + +void CDummyProtocol::Process(TDes8 & ,TSockAddr* /*from*/,TSockAddr* /*to*/,CProtocolBase* /*aSourceProtocol*/) + { + } + +void CDummyProtocol::Identify(TServerProtocolDesc *aDesc) const + { + Mem::Copy(aDesc, iProtoDesc, sizeof(TServerProtocolDesc)); + } + +TInt CDummyProtocol::GetOption(TUint level,TUint,TDes8&,CProtocolBase* /*aSourceProtocol*/) + { + + if(level==KNifOptLevel) + { + return KErrNotSupported; + } + return KErrNone; + } + +TInt CDummyProtocol::SetOption(TUint /*level*/,TUint /*name*/,const TDesC8& /*option*/,CProtocolBase* /*aSourceProtocol*/) + { + return KErrNone; + } + +void CDummyProtocol::Error(TInt /*anerror*/,CProtocolBase* /*aSourceProtocol*/) + { + } + + +EXPORT_C CDummyProtocol *CDummyProtocol::NewL(TInt aType, TServerProtocolDesc* aProtoDesc) + { + + CDummyProtocol* p=0; + switch (aType) + { + case KDummyOne: + case KDummyTwo: + case KDummyFive: + p=new (ELeave) CDummyProtocol(aProtoDesc); + break; + + case KDummyThree: + case KDummyFour: + p=new (ELeave) CInterfaceProtocol(aProtoDesc); + break; + + default: + p=(CDummyProtocol*)0xABCD; // keep lint happy + Panic(EBadProtocol); + } + p->iType=aType; + return p; + } + + +EXPORT_C CDummyProtocol::CDummyProtocol(TServerProtocolDesc* aProtoDesc) + + :CProtocolBase(),iProtoDesc(aProtoDesc),iProtocols(0x16) + { + __DECLARE_NAME(_S("CDummyProtocol")); + iIsStarted=EFalse; + } + + +/* exported functions that are used to exercise ProtocolBase functionality +*/ +EXPORT_C TInt CDummyProtocol::ProtocolBaseBind(CProtocolBase* aProt, TUint aId) + // expected to Panic(EDoesNotBindBelow); + { + TRAPD(ret, CProtocolBase::BindL(aProt, aId)); + return ret; + } + + +EXPORT_C TInt CDummyProtocol::ProtocolBaseBindTo(CProtocolBase* aProt) + // expected to Panic(EDoesNotBindAbove); + { + TRAPD(ret, CProtocolBase::BindToL(aProt)); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseError(CProtocolBase* aProt) + // expected to Panic(EErrorCallNotHandled) + { + CProtocolBase::Error(KErrNone, aProt); + return KErrNone; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseGetOption(TUint aLevel, TUint aName, TDes8& aBuf, CProtocolBase* aProt) + { + // expected to return KErrNotSupported + TInt ret = CProtocolBase::GetOption(aLevel,aName,aBuf,aProt); + __ASSERT_DEBUG(ret == KErrNotSupported, User::Panic(KSpecAssert_ESockTestPDUMMY, 1)); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseNewHostResolver() + // expected to panic with Fault(EBadHostResolver); + { + TRAPD(ret, CProtocolBase::NewHostResolverL()); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseNewNetDatabase() + // expected to panic with Fault(EBadNetDBRequest) + { + TRAPD(ret, CProtocolBase::NewNetDatabaseL()); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseNewSAP(TUint aProt) + // expected to panic with Fault(EOddSock) + { + TRAPD(ret, CProtocolBase::NewSAPL(aProt)); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseNewServiceResolver() + // expected to panic with Fault(EBadServiceResolver) + { + TRAPD(ret, CProtocolBase::NewServiceResolverL()); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseProcess(RMBufChain &aChain, CProtocolBase* aProt) + // expected to panic with Panic(ECantProcessMbufs) + { + CProtocolBase::Process(aChain, aProt); + return KErrNone; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseSend(RMBufChain &aChain, CProtocolBase* aProt) + // expected to panic with Panic(ECantSendMBufs); + { + TInt ret = CProtocolBase::Send(aChain, aProt); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseSetOption(TUint aLevel, TUint aName, TDes8& aBuf, CProtocolBase* aProt) + // expected to return KErrNotSupported + { + TInt ret = CProtocolBase::SetOption(aLevel, aName, aBuf, aProt); + __ASSERT_DEBUG(ret == KErrNotSupported, User::Panic(KSpecAssert_ESockTestPDUMMY, 2)); + return ret; + } + +EXPORT_C TInt CDummyProtocol::ProtocolBaseSendWithAddress(TDes8& aBuf,TSockAddr* aTo ,TSockAddr* aFrom, CProtocolBase* aProt) + // expected to panic with Panic(ECantSendMBufs); + { + TInt ret = CProtocolBase::Send(aBuf, aTo, aFrom, aProt); + return ret; + } + + +EXPORT_C TInt CDummyProtocol::ProtocolBaseProcessWithAddress(TDes8& aBuf, TSockAddr* aFrom, TSockAddr* aTo, CProtocolBase* aProt) + // expected to panic with Panic(ECantProcessMbufs) + { + CProtocolBase::Process(aBuf, aFrom, aTo, aProt); + return KErrNone; + } + +//--------------------------------------------------------------------------------------------------------- + +CDummyProvd *CDummyProvd::NewL(CDummyProtocol &aProtocol) + { + CDummyProvd *sp=new(ELeave) CDummyProvd(aProtocol); + CleanupStack::PushL(sp); + sp->ConstructL(); + CleanupStack::Pop(sp); + return sp; + + } + +void CDummyProvd::ConstructL() + { + iDataArray = new (ELeave) CArrayFixFlat(KPDummyDefaultGranularity); + iChain.AllocL(128); + } + +TInt CDummyProvd::NoBearerCB(TAny* aArg) +/** +Issue a NoBearer() upcall to ESock. + */ + { + CDummyProvd* This = static_cast(aArg); + // Scoped NoBearer() prevents a connection from being started by ESock - a side-effect we aren't interested in. + _LIT8(KScoped, "scoped"); + This->iSocket->NoBearer(KScoped()); + return KErrNone; + } + +CDummyProvd::CDummyProvd(CDummyProtocol &aProtocol) : + iCancelIoctl(EFalse), + iFlowOffWriteTimeout(0), + iErrNoMBufs(EFalse), + iNoBearerCB(TCallBack(NoBearerCB, this), EPriorityNormal) + { + __DECLARE_NAME(_S("CDummyProvd")); + iIsBound=EFalse; + iProtocol=&aProtocol; + iCompleteIoctl = FALSE; + iConnectCompleteState = ETrue; + iConnectPending = EFalse; + } + +CDummyProvd::~CDummyProvd() +// + + { + if (iDataArray) + { + TInt c = iDataArray->Count(); + TInt i; + for (i=0; i < c; ++i) + { + iDataArray->At(i).Free(); + } + delete iDataArray; + } + + iListenData.Close(); + iChain.Free(); + delete iFlowOnTimer; + } + +void CDummyProvd::DestroyAsyncErrorer() + { + delete iAsyncErrorer; + iAsyncErrorer = NULL; + } + + +void CDummyProvd::LocalName(TSockAddr& anAddr) const + { + anAddr=iAddr; + } + +TInt CDummyProvd::SetLocalName(TSockAddr& anAddr) + { + iAddr=anAddr; + iIsBound=ETrue; + return KErrNone; + } + +void CDummyProvd::RemName(TSockAddr& /*anAddr*/)const + { + } + +TInt CDummyProvd::SetRemName(TSockAddr& /*anAddr*/) + { + return KErrNone; + } + +TInt CDummyProvd::GetOption(TUint aLevel, TUint aName, TDes8& anOption) const + { + if(aLevel==KNifOptLevel) + { + return iProtocol->GetOption(aLevel, aName, anOption, 0); + } + else + { + switch(aName) + { + case KDummyOptionSetBlockConnect: + { + TBool blockedConnect = !iConnectCompleteState; + const TUint8* opt = reinterpret_cast(&blockedConnect); + anOption.Copy(opt,sizeof(blockedConnect)); + return KErrNone; + } + case KDummyOptionSetErrorNextWrite: + { + anOption.Copy(reinterpret_cast(&iErrorForNextWrite), sizeof(iErrorForNextWrite)); + return KErrNone; + } + case KDummyOptionSetErrorNextShutdown: + { + anOption.Copy(reinterpret_cast(&iErrorForNextShutdown), sizeof(iErrorForNextShutdown)); + return KErrNone; + } + case KDummyOptionSetErrorNextConnect: + { + anOption.Copy(reinterpret_cast(&iErrorForNextConnect), sizeof(iErrorForNextConnect)); + return KErrNone; + } + case KDummyOptionGetMBufFreeSpace: + { + RMBufAllocator mBufAllocator; + TInt availableBytes = mBufAllocator.BytesAvailable(); + anOption.Copy(reinterpret_cast(&availableBytes), sizeof(availableBytes)); + return KErrNone; + } + default: + return KErrNotSupported; + } + } + } + +TInt CDummyProvd::SetOption(TUint level,TUint name,const TDesC8& anOption) + { + switch(name) + { + case KDummyOptionSetErrorNextListen: + iListenErrorCode=*(TInt*)&anOption[0]; + break; + case KDummyOptionSetConnectComplete: + __ASSERT_DEBUG(!iAsyncErrorer, User::Panic(KSpecAssert_ESockTestPDUMMY, 3)); // to support multiple outstanding would need a list + { + TInt ret = KErrNone; + if (iListenData.Length()) + { + TRAP(ret,iAsyncErrorer = CAsyncSocketErrorer::NewL(*iSocket, KErrNone,0, iProtocol, this, &iListenData)); + } + else + { + TRAP(ret,iAsyncErrorer = CAsyncSocketErrorer::NewL(*iSocket,KErrNone,0,iProtocol,this,NULL)); + } + return ret; + } + case KDummyOptionSetBlockConnect: + return SetBlockedConnect(anOption); + case KDummyOptionSetBlockConnectData: + { + TBool opt = *reinterpret_cast(anOption.Ptr()); + if (!opt) + { + iListenData.Create(KConnectCompleteData()); + } + else + { + iConnectPending = ETrue; + } + return SetBlockedConnect(anOption); + } + case KDummyOptionSetIocltComplete: + if (iCompleteIoctl) + { + iSocket->IoctlComplete(NULL); + iCompleteIoctl = EFalse; + } + break; + case KDummyOptionSetErrorNextWrite: + return OptToErr(anOption,iErrorForNextWrite); + case KDummyOptionSetErrorNextShutdown: + return OptToErr(anOption,iErrorForNextShutdown); + case KDummyOptionSetErrorNextConnect: + return OptToErr(anOption,iErrorForNextConnect); + + case KDummyOptionSetFlowOffWrite: + { + if (anOption.Length() != sizeof(TBool)) + return KErrArgument; + + iFlowOffWrite = *reinterpret_cast(anOption.Ptr()); + if (!iFlowOffWrite) + iSocket->CanSend(); + } + break; + + + case KDummyOptionSetTimedFlowOffWrite: + { + if (anOption.Length() != sizeof(TInt)) + return KErrArgument; + + iFlowOffWriteTimeout = *reinterpret_cast(anOption.Ptr()); + if (iFlowOffWriteTimeout > 0) + { + if (!iFlowOnTimer) + { + TRAPD(ret, iFlowOnTimer = CFlowOnTimer::NewL(*this, *iSocket)); + if (ret) + return ret; + } + } + else if (iFlowOffWriteTimeout == 0) + { + delete iFlowOnTimer; + iFlowOnTimer = NULL; + } + else + return KErrArgument; + } + break; + + case KDummyOptionSetGobbleMBufs: + { + iErrNoMBufs = ETrue; + return GobbleMBufs(); + } + + case KDummyOptionSetFreeMBufs: + { + iErrNoMBufs = EFalse; + FreeMBufs(); + break; + } + + case KDummyOptionSetFreeSomeMBufs: + { + iErrNoMBufs = EFalse; + FreeMBufs(level); + break; + } + + + case KDummyOptionLeakMemory: + { + for(TUint i = 0; i < level; ++i) + { + (void) new TInt; // deliberately leak the allocs + } + return KErrNone; + } + + case KDummyOptionIssueNoBearer: + { + // Issue a NoBearer() upcall. We are testing the behaviour whereby NoBearer() is called + // outside the context of any pending IPC. We use an async callback to ensure that the current + // SetOption() IPC is completed by ESock before the NoBearer() upcall. + iNoBearerCB.Call(); + return KErrNone; + } + + default: + return KErrNotSupported; + } + return KErrNone; + } + +TInt CDummyProvd::GobbleMBufs() +// Eat all the available mBufs in the mBuf pool + { + RMBufAllocator allocator; + RMBufChain aChain; + TInt size = allocator.NextMBufSize(0); + while (size != KErrNotFound) + { + TInt ret = KErrNone; + while (ret == KErrNone) + { + TRAP(ret, aChain.AllocL(size)); + iChain.Append(aChain); + } + size = allocator.NextMBufSize(size); + } + + TInt length = iChain.Length(); + RDebug::Print(_L("Out of MBuf Memory... Total MBuf memory in use %d"), length); + TInt numBufs = iChain.NumBufs(); + RDebug::Print(_L("Out of MBuf Memory... Total MBufs in use %d"), numBufs); + return numBufs; + } + +void CDummyProvd::FreeMBufs() +// Free All the MBufs that were allocated by GobbleMBufs + { + if(iChain.IsEmpty()) + { + return; + } + iChain.Free(); + TInt length = iChain.Length(); + RDebug::Print(_L("MBufMemory De-Allocated... Total MBuf memory in use %d"), length); + } + +void CDummyProvd::FreeMBufs(TUint aNumber) +// Free aNumber of mBufs that were allocated by GobbleMBufs + { + if(iChain.IsEmpty()) + { + return; + } + TInt length = 0; + while (aNumber-- > 0) + { + TInt length = iChain.Length(); + if (length == 0) + { + break; + } + TInt trimOffset = length - iChain.Last()->Size(); + iChain.TrimEnd(trimOffset); + } + length = iChain.Length(); + RDebug::Print(_L("MBufMemory De-Allocated... Total MBuf memory in use %d"), length); + } + + +TInt CDummyProvd::OptToErr(const TDesC8 &aOption, TInt &aRes) + { + if (aOption.Length() != sizeof(TInt)) + { + return KErrCorrupt; + } + const TInt &opt = *reinterpret_cast(aOption.Ptr()); + if (opt > KErrNone) + { + return KErrCorrupt; + } + aRes = opt; + return KErrNone; + } + +TInt CDummyProvd::SetBlockedConnect(const TDesC8 &anOption) + { + if (anOption.Length() != sizeof(TBool)) + { + return KErrCorrupt; + } + TBool opt = *reinterpret_cast(anOption.Ptr()); + if (opt != TRUE && opt != FALSE) + { + return KErrCorrupt; + } + iConnectCompleteState = !opt; + if (iConnectCompleteState && iConnectPending) + { + if (iErrorForNextConnect != KErrNone) + { + iSocket->Error(iErrorForNextConnect, MSocketNotify::EErrorConnect); + iErrorForNextConnect = KErrNone; + return KErrNone; + } + if (iListenData.Length()) + { + iSocket->ConnectComplete(iListenData); + } + else + { + iSocket->ConnectComplete(); + } + iConnectPending = EFalse; + } + return KErrNone; + } + +void CDummyProvd::Ioctl(TUint /*level*/,TUint name,TDes8* anOption) + { + switch (name) + { + case KDummyIoctlCheckBound: + if (!iIsBound) + Panic(ENotBound); + iSocket->IoctlComplete(NULL); + break; + case KDummyIoctlCheckStarted: + if (!iProtocol->IsStarted()) + Panic(ENotStarted); + iSocket->IoctlComplete(NULL); + break; + case KDummyIoctlIgnore: + iCancelIoctl=EFalse; + break; + case KDummyIoctlCancelled: + if(iCancelIoctl) + { + iSocket->IoctlComplete(NULL); + } + else + { + iSocket->Error(KErrNotFound,MSocketNotify::EErrorIoctl); + } + break; + case KDummyIoctlPanicProtocolModule: + Panic(ETestPanic); + iSocket->IoctlComplete(NULL); //Should never get here + break; + case KDummyIocltNonCompleting: //Ioclt never send back a complete message + iCompleteIoctl = TRUE; + break; + case KDummyIoctBlockHardOnClose: + iBlockOnClose = TRUE; + iSocket->IoctlComplete(NULL); + break; + + case KDummyIoctlSlowIoctlReturn: + iSocket->IoctlComplete(NULL); + User::After(100000); + break; + case KDummyIoctlHangIoctlReturn: + iSocket->IoctlComplete(NULL); + HangModule(); + break; + case KDummyIocltJustComplete: + iSocket->IoctlComplete(NULL); + break; + case KDummyIocltRemoteDisconnect: + if (anOption) + { + TBuf8<40> tmp(*anOption); + iSocket->Disconnect(tmp); + } + else + { + iSocket->Disconnect(); + } + iSocket->IoctlComplete(NULL); + break; + + case KDummyIoctlCompleteWithData: + { + TBuf8<64> ioctlBuffer(KIoctlData()); + iSocket->IoctlComplete( &ioctlBuffer ); + } + + break; + default: + iSocket->Error(KErrNotSupported,MSocketNotify::EErrorIoctl); + } + } + +void CDummyProvd::CancelIoctl(TUint /*aLevel*/,TUint /*aName*/) + { + iCancelIoctl=ETrue; + } + +TInt CDummyProvd::Write(RMBufChain& aData,TUint aOptions, TSockAddr*) + { + if (iFlowOffWriteTimeout > 0) + { + __ASSERT_DEBUG(iFlowOffWriteTimeout, User::Panic(KSpecAssert_ESockTestPDUMMY, 4)); + iFlowOnTimer->After(iFlowOffWriteTimeout); + return 0; + } + + if (iFlowOffWrite) + return 0; + + if (aOptions==KSockWriteUrgent) + { + iSocket->Error(KErrNotSupported); + return 0; + } + if (iErrorForNextWrite != KErrNone) + { + iSocket->Error(iErrorForNextWrite, MSocketNotify::EErrorSend); + iErrorForNextWrite = KErrNone; + return 0; + } + + // From opposite angle, we dont need a new chain if it is a stream + // we just append to the existing, unless there isn't an existing... + if(iDataArray->Count()==0 || IsTransportType(KSockDatagram)) + { + RMBufChain chain; + TRAPD(ret, iDataArray->AppendL(chain)); + if(ret!=KErrNone) + return ret; + } + + iDataArray->At(iDataArray->Count()-1).Append(aData); + + // Gotta save the length of the chain before calling + // NewData, as it could be changed after the call + // (We need to be re-entrant). + TInt consumed; + if(IsTransportType(KSockStream)) + { + consumed = iDataArray->At(iDataArray->Count()-1).Length(); + } + else + { + consumed = 1; + } + + if(!iInputStopped) + { + if(IsTransportType(KSockDatagram)) + iSocket->NewData(1); + else + iSocket->NewData(consumed); + } + + return consumed; + } + +TUint CDummyProvd::Write(const TDesC8& aDesc, TUint options, TSockAddr* anAddr) + { + if (iFlowOffWriteTimeout > 0) + { + __ASSERT_DEBUG(iFlowOffWriteTimeout, User::Panic(KSpecAssert_ESockTestPDUMMY, 5)); + iFlowOnTimer->After(iFlowOffWriteTimeout); + return 0; + } + + if (iFlowOffWrite) + return 0; + + RMBufChain chain; + TRAPD(r,chain.CreateL(aDesc)); + if (r != KErrNone) + { + return r; + } + + TInt ret = Write(chain, options, anAddr); + if (ret<0) + { + return 0; + } + return ret; + } + +TBool CDummyProvd::IsTransportType(TUint aType) + { + TServerProtocolDesc info; + iProtocol->Identify(&info); + return (info.iSockType==aType); + } + +void CDummyProvd::GetData(TDes8& aDesc,TUint aOptions,TSockAddr* aAddr) + { + RMBufChain chain; + GetData(chain,aDesc.MaxLength(),aOptions, aAddr); + aDesc.SetMax(); + chain.CopyOut(aDesc); + chain.Free(); + } + +TInt CDummyProvd::GetData(RMBufChain& aData,TUint aLength, TUint aOptions,TSockAddr* aAddr) + { + __ASSERT_DEBUG(iDataArray->Count()>0, User::Panic(KSpecAssert_ESockTestPDUMMY, 6)); + TInt res = KErrNone; + + // If KSockReadPeek we copy the whole bally lot instead of moving it out. + if((aOptions&KSockReadPeek)==KSockReadPeek) + { + TInt err; + // For datagram, copy all datagram else copy just aLength + if(!IsTransportType(KSockDatagram)) + { + TRAP(err, iDataArray->At(0).CopyL(aData, 0, aLength)); +// iDataArray->At(0).TrimStart(aLength); + } + else + { + TRAP(err, iDataArray->At(0).CopyL(aData)); +// iDataArray->At(0).TrimStart(aData.Length()); + } + if(res==KErrNone) + { + iSocket->NewData(1); + } + else + { + iDataArray->At(0).Free(); + } + } + else // Not KSockReadPeek + { + // Move datablock to receiving chain + aData.Assign(iDataArray->At(0)); + + // For non-datagram types exact only amount of bytes + // if they have more than asked for + // so we move some of the data back to our array + if( !IsTransportType(KSockDatagram) && + (((TUint)aData.Length())>aLength) ) + { + // Put the tail back into our array for another good time + TRAP(res, aData.SplitL(aLength, iDataArray->At(0))); + // If it didnt work, save data internally again and return error + if(res!=KErrNone) + { + iDataArray->At(0).Assign(aData); + } + } + } + + // No errors? Return number of bytes copied (stream) or 1 (dgram) + if(res==KErrNone) + { + if(IsTransportType(KSockStream)) + { + res = aData.Length(); + } + else + { + res = 1; + } + } + else // else report mbuf shortage + { + res=KErrNoMBufs; + } + + // Cleanup possibly unused chain + if(iDataArray->At(0).Length()==0) + iDataArray->Delete(0); + + // Copy the TSockAddr if requested + if ( aAddr ) + { + const TUint KProxyAddrFamily=0x20000; + TSockAddr addr(KProxyAddrFamily); + aAddr->Copy(addr); + } + return res; + } + + +void CDummyProvd::ActiveOpen(void) + { + if (iErrorForNextConnect != KErrNone) + { + iSocket->Error(iErrorForNextConnect, MSocketNotify::EErrorConnect); + iErrorForNextConnect = KErrNone; + return; + } + if (iConnectCompleteState) + { + iSocket->ConnectComplete(); + } + else + { + if(iListenData.Length()) + { + iListenData.Close(); + } + iConnectPending = ETrue; + } + } + +void CDummyProvd::ActiveOpen(const TDesC8& aConnectionData) + { + if (iErrorForNextConnect != KErrNone) + { + iSocket->Error(iErrorForNextConnect, MSocketNotify::EErrorConnect); + iErrorForNextConnect = KErrNone; + return; + } + if (iConnectCompleteState) + { + iSocket->ConnectComplete(aConnectionData); + } + else + { + if(iListenData.Length()) + { + iListenData.Close(); + } + iListenData.Create(aConnectionData); + iConnectPending = ETrue; + } + } + +TInt CDummyProvd::PassiveOpen(TUint /*aQue*/) + { +// test.Printf(_L("CDummyProvd::Open\n")); + if(iListenErrorCode) + {// We're going to error this call, but can't do it synchonously. + // Do it with an AO of max prio, so we know it will happen next +// iSocket->Error(iListenErrorCode);// Error all operations + __ASSERT_DEBUG(!iAsyncErrorer, User::Panic(KSpecAssert_ESockTestPDUMMY, 7)); // to support multiple outstanding would need a list + TRAPD(err, iAsyncErrorer = CAsyncSocketErrorer::NewL(*iSocket,iListenErrorCode,MSocketNotify::EErrorConnect,0,this,NULL)); + iListenErrorCode=KErrNone; + return err; + } + return KErrNone; + } + +TInt CDummyProvd::PassiveOpen(TUint /*aQue*/, const TDesC8& aConnectionData) + { + iListenData.Close(); + TInt ret = iListenData.Create(aConnectionData); + if (ret != KErrNone) + { + return ret; + } + if(iListenErrorCode) + {// We're going to error this call, but can't do it synchonously. + // Do it with an AO of max prio, so we know it will happen next +// iSocket->Error(iListenErrorCode);// Error all operations + __ASSERT_DEBUG(!iAsyncErrorer, User::Panic(KSpecAssert_ESockTestPDUMMY, 8)); // to support multiple outstanding would need a list + TRAPD(err, iAsyncErrorer = CAsyncSocketErrorer::NewL(*iSocket, iListenErrorCode, MSocketNotify::EErrorConnect, 0, this, &aConnectionData)); + iListenErrorCode=KErrNone; + return err; + } + return KErrNone; + } + + +void CDummyProvd::Shutdown(TCloseType anOption) + { + if (iErrorForNextShutdown != KErrNone) + { + iSocket->Error(iErrorForNextShutdown, MSocketNotify::EErrorClose); + iErrorForNextShutdown = KErrNone; + return; + } + if (iBlockOnClose) + { + HangModule(); + } + DestroyAsyncErrorer(); + + if(anOption==EStopInput) + iInputStopped=ETrue; + if(anOption==EStopOutput) + { + + TInt c = iDataArray->Count(); + TInt i; + for (i=0; i < c; ++i) + { + iDataArray->At(i).Free(); + } + iDataArray->Reset(); + + + _LIT8(KEndOfData, "End of Data"); + RMBufChain datachain; + TRAPD(res, iDataArray->AppendL(datachain)); + + if(res!=KErrNone) + iSocket->Error(KErrNoMemory); + else + { + TRAPD(res, iDataArray->At(0).CreateL(KEndOfData)); + + if(res!=KErrNone) + iSocket->Error(KErrNoMemory); + else + { + if(IsTransportType(KSockDatagram)) + { + iSocket->NewData(1); + } + else + { + iSocket->NewData(iDataArray->At(0).Length()); + } + iSocket->NewData(KNewDataEndofData); + } + } + } + if (anOption==ENormal) + iSocket->CanClose(); + } + +void CDummyProvd::Start() +// +// +// + { + } + +void CDummyProvd::Shutdown(TCloseType /*anOption*/,const TDesC8 &/*aDisconnectData*/) + { + Panic(EBadCall); + } + +void CDummyProvd::AutoBind( void ) + { +// test.Printf(_L("CDummyProvd::AutoBind\n")); + iIsBound=ETrue; + + } +void CDummyProvd::HangModule(void) + { + TInt val; + TInt shutdownVal; + RProperty hangProp; + TRequestStatus hangStat; + + hangProp.Attach(KDummyUid,KDummyTerminationProperty); + hangProp.Subscribe(hangStat); + hangProp.Get(shutdownVal); + val = shutdownVal + 1; + hangProp.Set(val); + + while (val > shutdownVal) + { + User::WaitForRequest(hangStat); + hangProp.Subscribe(hangStat); + hangProp.Get(val); + } + hangProp.Set(shutdownVal - 1); + hangProp.Cancel(); + User::WaitForRequest(hangStat); + hangProp.Close(); + } + +// + +TInt CDummyProvd::SecurityCheck(MProvdSecurityChecker* /*aChecker*/) +/** +Perform a security policy check on the client process (default implementation). +*/ + { + return KErrNone; + } + + +//--------------------------------------------------------------------------------------------------------- + +#pragma warning( default : 4100) + +CDatagramHostResolver::CDatagramHostResolver() +// +// +// + { + __DECLARE_NAME(_S("CDatagramHostResolver")); + } + +CDatagramHostResolver::~CDatagramHostResolver() +{ + delete ipDNSQueryProcessor; +} + +CDatagramHostResolver* CDatagramHostResolver::NewL() +// +// Make a new resolver +// + { + + CDatagramHostResolver* self = new(ELeave) CDatagramHostResolver(); + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + + return self; + } + +void CDatagramHostResolver::ConstructL() +{ + //-- construct DNS Query processor + ipDNSQueryProcessor = CDNSQueryProcessor::NewL(); +} + +void CDatagramHostResolver::CancelCurrentOperation() +// +// +// + { + //-- cancel possible pending DNS Query processor request + if(ipDNSQueryProcessor) + ipDNSQueryProcessor->Cancel(); + } + + +void CDatagramHostResolver::GetByName(TNameRecord &aName) +// +// +// + { + + if(aName.iName==_L("DontComplete")) + return; + + aName.iAddr.SetFamily(KDummyAddrFamily); + aName.iAddr.SetPort(0); + if(aName.iFlags==0) + { + aName.iName=_L("Name One"); + aName.iFlags=0; + iNotify->QueryComplete(KErrNone); + } + else if(aName.iFlags==1) + { + aName.iName=_L("Name Two"); + aName.iFlags=0; + iNotify->QueryComplete(KErrNone); + } + else if(aName.iFlags==4) + { + aName.iName=_L("Name Five"); + aName.iFlags=0; + iNotify->QueryComplete(KErrNone); + } + else + iNotify->QueryComplete(KErrEof); + } + +void CDatagramHostResolver::GetByAddress(TNameRecord &aName) +// +// +// + { + + aName.iName=_L(""); + if(aName.iFlags==0) + { + aName.iAddr.SetPort(10); + aName.iFlags=0; + iNotify->QueryComplete(KErrNone); + } + else if(aName.iFlags==1) + { + aName.iAddr.SetPort(11); + aName.iFlags=0; + iNotify->QueryComplete(KErrNone); + } + else + iNotify->QueryComplete(KErrEof); + } + +void CDatagramHostResolver::SetHostName(TDes & aNameBuf) +// +// +// + { + if(aNameBuf!=_L("Tara")) + iNotify->QueryComplete(KErrNotSupported); + else + iNotify->QueryComplete(KErrNone); + } + +void CDatagramHostResolver::GetHostName(TDes &aNameBuf) +// +// +// + { + aNameBuf=_S("PDummyHostName"); + iNotify->QueryComplete(KErrNone); + } + +/** +* Implementation "Query" function for CHostResolver. Simulates Query(...) behaviour, checks query data validity +* and forges query response that shall be checked at client side. +* +* @param aQryBuf descriptor representing query data. +* @param aResBuf descriptor representing query response data. +* @param aCounter query sequential number counter. From the client's point of view it will be 0 for "Query" call +* and increased by 1 for each "QueryGetNext" call. +* @note for aCounter > 0 data in aQryBuf may be invalid. +*/ +void CDatagramHostResolver::Query(const TDesC8& aQryBuf, TDes8& aResBuf, TInt aCounter) +{ + + //-- convert 1st parameter to the reference to TDnsQuery. + //-- Actually, for pdummy.prt and tcpip6.prt aQryBuf is a reference to the TDnsQueryBuf indeed, + //-- but for the RHostresolver and CHostResolver protocol independency all the data passes like references to + //-- the raw buffers. + const TDnsQuery &dnsQry = * (reinterpret_cast (aQryBuf.Ptr())); + + //-- set Query proccessor notifier. + //-- On request completion Query processor will call iNotify->QueryComplete(); + ipDNSQueryProcessor->SetNotifier(iNotify); + + //-- process and complete query, calling iNotify->QueryComplete() later + ipDNSQueryProcessor->ProcessQuery(dnsQry, aResBuf, aCounter); +} + + +TInt CDatagramHostResolver::SetOption(TUint /*aLevel*/, TUint /*aName*/, const TDesC8 &/*anOption*/) +// +// +// + { + return (KErrNotSupported); + } + + + +TInt CDatagramHostResolver::SecurityCheck(MProvdSecurityChecker* /*aChecker*/) +/** +Perform a security policy check on the client process (default implementation). +*/ + { + return KErrNone; + } + +CDatagramServResolver::CDatagramServResolver() +// +// +// + { + __DECLARE_NAME(_S("CDatagramServResolver")); + } + +CDatagramServResolver* CDatagramServResolver::NewL() +// +// +// + { + return new(ELeave) CDatagramServResolver; + } + +void CDatagramServResolver::CancelCurrentOperation() +// +// +// + { + // were always synchronous so don't actually do anything + } + +void CDatagramServResolver::GetByName(const TDesC & aNameBuf,TInt32 & aPortNum) + +// +// +// + { + + if(aNameBuf!=_L("DummyName")) + { + iNotify->QueryComplete(KErrNotFound); + return; + } + aPortNum=64; + iNotify->QueryComplete(KErrNone); + } + +void CDatagramServResolver::GetByNumber(TDes & aNameBuf,TInt32 aPortNum) +// +// +// + { + + if(aPortNum==66) // for testing cancel + { + return; + } + + if(aPortNum!=21) + { + iNotify->QueryComplete(KErrNotFound); + return; + } + aNameBuf=_S("DummyService"); + iNotify->QueryComplete(KErrNone); + } + +void CDatagramServResolver::RegisterService(const TDesC & aNameBuf,TInt32 aPortNum) +// +// Register a new service with the net database +// + { + + if(aNameBuf!=_L("Simpson") || aPortNum!=500) + { + iNotify->QueryComplete(KErrNotFound); + return; + } + iNotify->QueryComplete(KErrNone); + } + +void CDatagramServResolver::RemoveService(const TDesC & aNameBuf,TInt32 aPortNum) +// +// remove a service registered with the database +// + { + + if(aNameBuf!=_L("Colt") || aPortNum!=45) + { + iNotify->QueryComplete(KErrNotFound); + return; + } + iNotify->QueryComplete(KErrNone); + } + + +TInt CDatagramServResolver::SecurityCheck(MProvdSecurityChecker* /*aChecker*/) +/** +Perform a security policy check on the client process (default implementation). +*/ + { + return KErrNone; + } +//--------------------------------------------------------------------------------------------------------- + +CDNSQueryProcessor::CDNSQueryProcessor() + :CActive(0) +{ + iDnsNotifier = NULL; + iCompleteResult = KErrNotSupported; + + //-- initialize seed for random delay generator + TTime currTime; + currTime.UniversalTime(); + iRndSeed = currTime.Int64(); +} + +CDNSQueryProcessor::~CDNSQueryProcessor() +{ + Cancel(); + iDelayTimer.Close(); +} + +CDNSQueryProcessor* CDNSQueryProcessor::NewL() +{ + CDNSQueryProcessor* self = new(ELeave) CDNSQueryProcessor; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + + return self; +} + +void CDNSQueryProcessor::ConstructL(void) +{ + User::LeaveIfError(iDelayTimer.CreateLocal()); + CActiveScheduler::Add(this); +} + +void CDNSQueryProcessor::DoCancel() +{ + iDelayTimer.Cancel(); +} + +void CDNSQueryProcessor::RunL() +{ + //-- complete esock's request + if(iDnsNotifier) + iDnsNotifier->QueryComplete(iCompleteResult); +} + +/** +* cancels pending request and completes with aResultCode +* +* @param aResultCode completion code, which will be passed to the Esock +*/ +void CDNSQueryProcessor::CompleteImmediately(TInt aResultCode) +{ + iCompleteResult = aResultCode; + CompleteImmediately(); +} + +/** +* cancels pending request and completes with code iCompleteResult +*/ +void CDNSQueryProcessor::CompleteImmediately() +{ + Cancel(); + + SetActive(); + + TRequestStatus* pStat = &iStatus; + User::RequestComplete(pStat, iCompleteResult); +} + +/** +* set up timer for a random delay between KMinDelay and KMaxDelay +* Used to similate queries processing +*/ +void CDNSQueryProcessor::SetQryProcessDelay() +{ + const TInt KMinDelay = 200000; //-- minimal delay, 200 ms + const TInt KMaxDelay = 600000; //-- maximal delay, 600 ms + + iDelayTimer.Cancel(); + iDelayTimer.After(iStatus, KMinDelay+(Math::Rand(iRndSeed) % (KMaxDelay-KMinDelay))); +} + + +/** +* process query. Checks query type and calls appropriate query processor function. +* @param aQry ref. to the query data +* @param aResBuf descriptor representing query response data. Will be initialized here. +* @param aCounter queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::ProcessQuery(const TDnsQuery& aQry, TDes8& aResBuf, TInt aCounter) +{ + + if(aCounter < 0) + {//-- invalid parameter + CompleteImmediately(KErrCorrupt); + return; + } + + if(aCounter == 0) + {//-- this is the "Query" call, not "QueryGetNext()", store query type for future use + iCurrQryType = aQry.Type(); + } + + switch(iCurrQryType) + { + + case KDnsRRTypeA: + //-- process query of A type, treating aResBuf as a reference to TDnsRespABuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespABuf)) + { //-- there is no room in aResBuf to place there TDnsRespSRV structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespA)); + //-- use placement new operator to construct object of our class in the chunk of memory + //-- in aResBuf (which is already allocated by server) + TDnsRespA *pRespA = new((TAny*)aResBuf.Ptr())TDnsRespA; + QryProcessA(aQry, *pRespA, aCounter); //-- process query and complete request. + } + break; + + case KDnsRRTypeSRV: + //-- process query of SRV type, treating aResBuf as a reference to TDnsRespSRVBuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespSRVBuf)) + { //-- there is no room in aResBuf to place there TDnsRespSRV structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespSRV)); + //-- use placement new operator to construct object of our class in the chunk of memory + //-- in aResBuf (which is already allocated by server) + //-- aResBuf shall be considered as a TPckgBuf, we will also need to set a length of the aResBuf descriptor + TDnsRespSRV *pRespSRV = new((TAny*)aResBuf.Ptr())TDnsRespSRV; + QryProcessSRV(aQry, *pRespSRV, aCounter);//-- process query and complete request. + + + } + + break; + + + case KDnsRRTypePTR: + //-- process query of PTR type, treating aResBuf as a reference to TDnsRespPTRBuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespPTRBuf)) + { //-- there is no room in aResBuf to place there TDnsRespPTRBuf structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespPTR)); + + TDnsRespPTR *pRespPTR = new((TAny*)aResBuf.Ptr())TDnsRespPTR; + QryProcessPTR(aQry, *pRespPTR, aCounter);//-- process query and complete request. + + } + break; + + case KDnsRRTypeNAPTR: + //-- process query of NAPTR type, treating aResBuf as a reference to TDnsRespNAPTRBuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespNAPTRBuf)) + { //-- there is no room in aResBuf to place there TDnsRespNAPTRBuf structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespNAPTR)); + + TDnsRespNAPTR *pRespNAPTR = new((TAny*)aResBuf.Ptr())TDnsRespNAPTR; + QryProcessNAPTR(aQry, *pRespNAPTR, aCounter);//-- process query and complete request. + } + break; + + case KDnsRRTypeMX: + //-- process query of MX type, treating aResBuf as a reference to TDnsRespMXBuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespMXBuf)) + { //-- there is no room in aResBuf to place there TDnsRespMXBuf structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespMX)); + + TDnsRespMX *pRespMX = new((TAny*)aResBuf.Ptr())TDnsRespMX; + QryProcessMX(aQry, *pRespMX, aCounter);//-- process query and complete request. + } + break; + + + case KDnsRRTypeAAAA: + //-- process query of AAAA type, treating aResBuf as a reference to TDnsRespAAAABuf + if((TUint)aResBuf.MaxSize() < sizeof(TDnsRespAAAABuf)) + { //-- there is no room in aResBuf to place there TDnsRespMXBuf structure + CompleteImmediately(KErrNoMemory); + } + else + { + aResBuf.SetLength(sizeof(TDnsRespAAAA)); + + TDnsRespAAAA *pRespAAAA = new((TAny*)aResBuf.Ptr())TDnsRespAAAA; + QryProcessAAAA(aQry, *pRespAAAA, aCounter);//-- process query and complete request. + } + break; + + + default: + //-- Query of unknown type + CompleteImmediately(KErrNotSupported); + break; + } // switch + +} + +/** +* process A query. Checks query data and forges query result. +* @param aQry ref. to the A query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessA(const TDnsQuery& aQry, TDnsRespA& aQryResult, TInt aCounter) +{ + TInetAddr addr; + + switch(aCounter) + { + //-- query counter is 0, so it is "Query" call + case 0: + + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + if( aQry.Class() != KDnsRRClassIN || //-- Query class shall be IN + aQry.Type() != KDnsRRTypeA || //-- Query type shall be KDnsRRTypeA + aQry.Data().CompareF(_L8("http://www.sample.net/")) != 0 + ) + { + CompleteImmediately(KErrCorrupt); + return; + } + + //-- resolve domain name, forge "A" query result that will be checked on the client side. + addr.Input(_L("192.168.40.4")); + + aQryResult.SetHostAddress(addr); + aQryResult.SetRRTtl(0x121212); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + + break; + + //-- query counter is 1, so it is the first "QueryGetNext" call. + case 1: + + //-- resolve domain name, forge "A" query result that will be checked on the client side. + addr.Input(_L("177.123.221.251")); + + aQryResult.SetHostAddress(addr); + aQryResult.SetRRTtl(0x112233); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + + break; + + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + + } + +} + +/** +* process SRV query. Checks query data and forges query result. +* @param aQry ref. to the SRV query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessSRV (const TDnsQuery& aQry, TDnsRespSRV& aQryResult, TInt aCounter) +{ + + switch(aCounter) + { + case 0: //-- query counter is 0, so it is "Query" call + + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + //-- see also RFC 2782 + + if(aQry.Class() != KDnsRRClassIN || //-- Query class shall be IN + aQry.Type() != KDnsRRTypeSRV || //-- Query type shall be KDnsRRTypeSRV + aQry.Data().CompareF(_L8("_ldap._tcp.example.com")) != 0) + { + CompleteImmediately(KErrCorrupt); + return; + } + + //-- forge a SRV query result that will be checked on the client side. + aQryResult.SetRRTtl(0x123456); + + aQryResult.SetPriority(384); //-- priority + aQryResult.SetWeight(784); //-- weight + aQryResult.SetPort(123); //-- port + aQryResult.SetTarget(_L8("old-slow-box"));//-- target + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + break; + + case 1: + //-- query counter is 1, so it is the first "QueryGetNext" call. + //-- Forge a "SRV" query next result that will be checked on the client side. + aQryResult.SetRRTtl(0x123765); + + aQryResult.SetPriority(236); //-- priority + aQryResult.SetWeight(962); //-- weight + aQryResult.SetPort(125); //-- port + aQryResult.SetTarget(_L8("new-fast-box"));//-- target + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + break; + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + }// switch +} + +/** +* process PTR query. Checks query data and forges query result. +* @param aQry ref. to the PTR query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessPTR (const TDnsQuery& aQry, TDnsRespPTR& aQryResult, TInt aCounter) +{ + switch(aCounter) + { + case 0: //-- query counter is 0, so it is "Query" call + { + + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + if(aQry.Class() != KDnsRRClassIN || //-- Query class shall be IN + aQry.Type() != KDnsRRTypePTR) //-- Query type shall be KDnsRRTypePTR + { + CompleteImmediately(KErrCorrupt); + return; + } + + //-- check Inet Address passes by test from client side + const TInetAddr& inetAddr = (const TInetAddr&)aQry.Data(); + + TInetAddr expInetAddr; + expInetAddr.Input(_L("192.111.22.77")); + + if(! inetAddr.CmpAddr(expInetAddr)) + { + CompleteImmediately(KErrCorrupt); + return; + } + + //-- resolve address, forge "PTR" query result that will be checked on the client side. + aQryResult.SetHostName(_L8("http://www.CDatagramHostResolver_QryProcessPTR.response/")); + aQryResult.SetRRTtl(0x223441); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + } + break; + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + + } + +} + +/** +* process NAPTR query. Checks query data and forges query result. +* @param aQry ref. to the NAPTR query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessNAPTR (const TDnsQuery& aQry, TDnsRespNAPTR& aQryResult, TInt aCounter) +{ + switch(aCounter) + { + case 0: //-- query counter is 0, so it is "Query" call + { + + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + if(aQry.Class() != KDnsRRClassIN || //-- Query class shall be IN + aQry.Type() != KDnsRRTypeNAPTR || //-- Query type shall be KDnsRRTypeNAPTR + aQry.Data().CompareF(_L8("http://www.foo_bar.ru/")) != 0) + { + CompleteImmediately(KErrCorrupt); + return; + } + + + //-- forge "NAPTR" query result that will be checked on the client side. + aQryResult.SetRRTtl(0x2673411); + aQryResult.SetOrder(123); + aQryResult.SetPref(99); + + aQryResult.SetFlags(_L8("SAUP")); + aQryResult.SetService(_L8("http+I2R")); + aQryResult.SetRegexp(_L8("!£%^^&($%£$~~## !!!!!")); + aQryResult.SetReplacement(_L8("www.next-name.it")); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + } + break; + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + + } + +} + +/** +* process MX query. Checks query data and forges query result. +* @param aQry ref. to the MX query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessMX (const TDnsQuery& aQry, TDnsRespMX& aQryResult, TInt aCounter) +{ + switch(aCounter) + { + case 0: //-- query counter is 0, so it is "Query" call + { + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + + if(aQry.Class() != KDnsRRClassIN || //-- Query class shall be IN + aQry.Type() != KDnsRRTypeMX || //-- Query type shall be KDnsRRTypeMX + aQry.Data().CompareF(_L8("http://www.gooooooogle.ru/")) != 0) + { + CompleteImmediately(KErrCorrupt); + return; + } + + + //-- forge "MX" query result that will be checked on the client side. + aQryResult.SetRRTtl(0xdead); + + aQryResult.SetPref(345); + aQryResult.SetHostName(_L8("c.example.org")); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + } + break; + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + + } + +} + +/** +* process AAAA query. Checks query data and forges query result. +* @param aQry ref. to the AAAA query data +* @param aQryResult ref. to the destination query result buffer. +* @param aCounter - queries counter. It is 0 for "Query" call and increased each "QueryGetNext" call +*/ +void CDNSQueryProcessor::QryProcessAAAA(const TDnsQuery& aQry, TDnsRespAAAA& aQryResult, TInt aCounter) +{ + TInetAddr addr; + + switch(aCounter) + { + case 0: //-- query counter is 0, so it is "Query" call + { + + //-- check query data, it shall be set properly in the test case that calls RHostResolver::Query(...) + if(aQry.Class() != KDnsRRClassIN || + aQry.Type() != KDnsRRTypeAAAA || + aQry.Data().CompareF(_L8("http://www.sample_AAAA.net/")) != 0) + { + CompleteImmediately(KErrCorrupt); + return; + } + + //-- forge "AAAA" query result that will be checked on the client side. + + //-- resolve domain name, forge "A" query result that will be checked on the client side. + addr.Input(_L("2001:618:400:6a:0:0:0:abc")); + aQryResult.SetHostAddress(addr); + aQryResult.SetRRTtl(0xbeef); + + SetCompletionCode(KErrNone); + + //-- simulate processing random delay and complete the request later + SetQryProcessDelay(); + SetActive(); + } + break; + + default: + //-- query counter is greater than 0, let's not support more than one "QueryGetNext" call + CompleteImmediately(KErrNotFound); + break; + + } + +} + + +//--------------------------------------------------------------------------------------------------------- + +void CDatagramNetDataBase::Query(TDes8& aBuffer) +// +// Ctor +// + { + aBuffer.Capitalize(); + iNotify->QueryComplete(KErrNone); + } + +void CDatagramNetDataBase::Add(TDes8& aBuffer) +// +// Ctor +// + { + + // Query not completed because its cancelled by the test code + if(aBuffer==_L8("Rabbit")) + iCount=10; + else + iNotify->QueryComplete(KErrNotSupported); + } + +void CDatagramNetDataBase::Remove(TDes8& aBuffer) +// +// Ctor +// + { + + + if(aBuffer==_L8("Rabbit") && iCount==20) + iNotify->QueryComplete(KErrNone); + else + iNotify->QueryComplete(KErrNotFound); + } + +void CDatagramNetDataBase::CancelCurrentOperation() +// +// +// + { + + if(iCount==10) + iCount=20; + } + +CDatagramNetDataBase* CDatagramNetDataBase::NewL() +// +// Ctor +// + { + return new(ELeave)CDatagramNetDataBase; + } + +CDatagramNetDataBase::CDatagramNetDataBase() +// +// Ctor +// + { + __DECLARE_NAME(_S("CDatagramNetDataBase")); + } + + +TInt CDatagramNetDataBase::SecurityCheck(MProvdSecurityChecker* /*aChecker*/) +/** +Perform a security policy check on the client process (default implementation). +*/ + { + return KErrNone; + } + +//--------------------------------------------------------------------------------------------------------- + +CInterfaceProtocol::CInterfaceProtocol(TServerProtocolDesc* aProtoDesc):CDummyProtocol(aProtoDesc) + { + iInterfaces.SetOffset(_FOFF(CIfHolder, iLink)); + } + +CInterfaceProtocol::~CInterfaceProtocol() +// +// Dtor +// + { + + __ASSERT_DEBUG(iInterfaces.IsEmpty(), Panic(EInterfaceNotDeleted)); + } + +TInt CInterfaceProtocol::GetOption(TUint level,TUint name,TDes8 &anOption,CProtocolBase* /*aSourceProtocol*/) +// +// Extra options +// + { + + if(level==KNifOptLevel) + { + TInt ret; + + if(name==KNifOptGetNifIfUser) + { + TNifIfUser ifuser; + ifuser() = this; + anOption.Copy(ifuser); + return KErrNone; + } + else if(name==1) + { + TRAP(ret, StartAutoInterfaceL();) + return ret; + } + else if(name==2) + { + if(iInterfaceName.Length()) + Nif::Stop(iInterfaceName); + return KErrNone; + } + else if(name==3) + { + TRAP(ret, Nif::StartL(iInterfaceName);) + return ret; + } + else if(name==4) + { + TNifProgress* p = (TNifProgress*)anOption.Ptr(); + anOption.SetLength(sizeof(TNifProgress)); + TRAP(ret, Nif::ProgressL(*p, iInterfaceName);) + return ret; + } + else if(name==5) + { + if(iInterfaces.IsEmpty()) + return KErrNotFound; + Nif::Stop(iInterfaces.First(), iInterfaces.First()->iIf); + return KErrNone; + } + else if(name==6) + { + if(iInterfaces.IsEmpty()) + return KErrNotFound; + TNifProgress* p = (TNifProgress*)anOption.Ptr(); + anOption.SetLength(sizeof(TNifProgress)); + TRAP(ret, Nif::ProgressL(*p, iInterfaces.First(), iInterfaces.First()->iIf);) + return ret; + } + } + return KErrNotSupported; + } + +void CInterfaceProtocol::StartAutoInterfaceL() + { + + // Create holder + CIfHolder* h; + h = new (ELeave) CIfHolder(*this); + CleanupStack::PushL(h); + Nif::BindL(*this, h, iInterfaceName); + CleanupStack::Pop(); + } + +void CInterfaceProtocol::IfUserBindFailure(TInt, TAny* aId) + { + + // Find the interface which went down + TDblQueIter iter(iInterfaces); + CIfHolder* h = 0; + while((h=iter++)!=0) + { + if(aId==h) + { + delete h; + break; + } + } + __ASSERT_ALWAYS(h, Panic(EIdAndNoHolder)); + } + +void CInterfaceProtocol::IfUserNewInterfaceL(CNifIfBase* aIf, TAny* aId) + { + + // If Id try to find it + CIfHolder* h; + if(aId) + { + TDblQueIter iter(iInterfaces); + while((h=iter++)!=0) + { + if(aId==h) + break; + } + __ASSERT_ALWAYS(h, Panic(EIdAndNoHolder)); + if (h==0) + { // will never get in here as will have panic-ed above + h = (CIfHolder*)0xABCD; // keep lint happy + } + } + else // create a new holder + h = new (ELeave) CIfHolder(*this); + + h->iIf=aIf; + CleanupStack::PushL(h); + aIf->BindL(this); + CleanupStack::Pop(); + } + +void CInterfaceProtocol::IfUserInterfaceDown(TInt aError, CNifIfBase* aIf) + { + + if (aError == KErrLinkConfigChanged) + { + return; + } + + // Interface has gone down so delete it from our records + TDblQueIter iter(iInterfaces); + CIfHolder* h = 0; + while((h=iter++)!=0) + { + if(aIf==h->iIf) + { + delete h; + break; + } + } + __ASSERT_ALWAYS(h, Panic(EIdAndNoHolder)); + } + +CProtocolBase* CInterfaceProtocol::IfUserProtocol() + { + return this; + } + +void CInterfaceProtocol::IfUserOpenNetworkLayer() + { + iInterfaceCount++; + Open(); + } + +void CInterfaceProtocol::IfUserCloseNetworkLayer() + { + iInterfaceCount--; + Close(); + } + +TBool CInterfaceProtocol::IfUserIsNetworkLayerActive() + { + return (RefCount()-iInterfaceCount>0); + } + +void CInterfaceProtocol::Close() + { + if(RefCount()-iInterfaceCount<=0) + { + Nif::NetworkLayerClosed(*this); + } + CProtocolBase::Close(); + } + +CIfHolder::CIfHolder(CInterfaceProtocol& aProt) + { + aProt.iInterfaces.AddLast(*this); + } + +CIfHolder::~CIfHolder() + { + iLink.Deque(); + } + +