diff -r 000000000000 -r af10295192d8 networkingtestandutils/networkingunittest/dummynif/dummynif.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkingtestandutils/networkingunittest/dummynif/dummynif.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,586 @@ +// 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: +// Implementation of dummyNif. +// +// + +/** + @file + @internalTechnology +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dummynifvar.h" +#include "dummynif.h" + +/* + * This sections defines a whole load of constants etc... not very exciting + */ + +_LIT(KDummyIfLogFolder, "dummynif"); +_LIT(KDummyIfLogFile, "dummynif.txt"); +_LIT(KEndOfLine, "\n"); + +/* + * The Link class + */ + +CDummyIfLink::CDummyIfLink(CNifIfFactory& aFactory) + : CNifIfLink(aFactory), + iFactory(&aFactory) + { + CDummyIfLog::Printf(_L("CDummyIfLink::CDummyIfLink()")); + } + +CDummyIfLink::~CDummyIfLink() + { + TimerDelete(); + } + +CDummyIfFactory& CDummyIfLink::Factory() + { + return static_cast(*iFactory); + } + +void CDummyIfLink::Info(TNifIfInfo& aInfo) const + { + FillInInfo(aInfo, (TAny*) this); + } + +void CDummyIfLink::FillInInfo(TNifIfInfo& aInfo, TAny* aPtr) + { + aInfo.iProtocolSupported=0; + aInfo.iVersion = TVersion(1,1,1); + aInfo.iFlags = KNifIfIsBase | KNifIfIsLink | KNifIfUsesNotify | KNifIfCreatedByFactory; + aInfo.iName = _L("dummyiflink"); + aInfo.iName.AppendFormat(_L("[0x%08x]"), aPtr); + aInfo.iFlags |= KNifIfCreatesBinder; + } + +TInt CDummyIfLink::Send(RMBufChain& /*aPdu*/, TAny* /*aSource*/) + { + // Not used - just for satisfying pure virtual + return KDummyNifSendOkay; + } + +TInt CDummyIfLink::Start() + { + // NOTE: according to the NAF docs the sequence should really be StartSending(), then LinkLayerUp() then Progress() + // for DNS to work. However, as this dummy NIF doesn't support DNS, the sequence is okay as it stands. + // + CDummyIfLog::Write(_L("CDummyIfLink::Start()")); + + iNotify->IfProgress(KLinkLayerOpen, KErrNone); + iNotify->LinkLayerUp(); + if (iNifIf4) + iNifIf4->iProtocol->StartSending((CProtocolBase*)iNifIf4); + if (iNifIf6) + { + // setup static DNS configuration if required + iNifIf6->StaticDnsConfiguration(); + + iNifIf6->iProtocol->StartSending((CProtocolBase*)iNifIf6); + } + return KErrNone; + } + +void CDummyIfLink::TimerComplete(TInt) + { + iNotify->LinkLayerDown(KErrTimedOut, MNifIfNotify::EDisconnect); + } + +void CDummyIfLink::AuthenticateComplete(TInt aResult) + { + iNotify->IfProgress(5, aResult); + } + +void CDummyIfLink::Stop(TInt aError, MNifIfNotify::TAction aAction) + { + CDummyIfLog::Printf(_L("CDummyIfLink::Stop(aError %d, TAction %d)"), aError, aAction); + iNotify->IfProgress(KLinkLayerClosed, aError); + iNotify->LinkLayerDown(aError, aAction); + } + +void CDummyIfLink::BindL(TAny *aId) + { + CDummyIfLog::Printf(_L("CDummyIfLink::BindL(aId %x)"), aId); + } + +CNifIfBase* CDummyIfLink::GetBinderL(const TDesC& aName) +{ + CDummyIfLog::Printf(_L("CDummyIfLink::GetBinderL(%S)"), &aName); + + _LIT(KDescIp6, "ip6"); + if (aName.CompareF(KDescIp6) == 0) + { + iNifIf6 = new(ELeave) CDummyIf6(*this); + return iNifIf6; + } + else + { // ip4 + iNifIf4 = new(ELeave) CDummyIf4(*this); + return iNifIf4; + } +} + +TInt CDummyIfLink::Notification(TAgentToNifEventType aEvent,void* aInfo) + { + if (aEvent!=EAgentToNifEventTypeDisableTimers) + return KErrUnknown; + if (aInfo!=NULL) + return KErrUnknown; + + return KErrNone; + } + +void CDummyIfLink::Restart(CNifIfBase*) + {} + +/** +Sets the cached value of Nifman Idle timeout to the specified value. + +@param aTimeoutToSet the idle timeout to update. One of: + LastSessionClosedTimeout + LastSocketClosedTimeout + LastSocketActivityTimeout +@param aTimeoutValueBuf a package buffer containing the new value for the timeout specified by aTimeoutToSet +@return KErrNone on success, or a system wide error code. +*/ +TInt CDummyIfLink::SetNifmanIdleTimeout(const TDesC& aTimeoutToSet, const TDes8& aTimeoutValueBuf) + { + ASSERT(aTimeoutToSet.Compare(TPtrC(LAST_SESSION_CLOSED_TIMEOUT)) == 0 || + aTimeoutToSet.Compare(TPtrC(LAST_SOCKET_CLOSED_TIMEOUT)) == 0 || + aTimeoutToSet.Compare(TPtrC(LAST_SOCKET_ACTIVITY_TIMEOUT)) == 0); + + if(!aTimeoutValueBuf.Ptr()) // NULL pointer provided. + { + CDummyIfLog::Printf(_L("CDummyIfLink::SetNifmanIdleTimeout timeoutToSet[%S]: NULL pointer provided where timeout value expected. Returning KErrAgument[-6]"), &aTimeoutToSet); + return KErrArgument; + } + // + // Extract the argument value and set the appropriate timeout. + // + const TInt KNewTimeoutValue = + *( + reinterpret_cast(aTimeoutValueBuf.Ptr()) + ); + TInt setErr = iNotify->WriteInt(aTimeoutToSet, KNewTimeoutValue); + CDummyIfLog::Printf(_L("CDummyIfLink::SetNifmanIdleTimeout [%S] to [%d]. WriteInt Error [%d]"), &aTimeoutToSet, KNewTimeoutValue, setErr); + return setErr; + } + +/** +Controls the Interface. +Capability to change LastSocketActivityTimeout on the fly (in CDMA Mobile IP) + +@param aLevel option level. Must be KCOLInterface. +@param aName option name. One of: + KTestSoDummyNifSetLastSessionClosedTimeout - updates the LastSessionClosed timeout + KTestSoDummyNifSetLastSocketClosedTimeout - updates the LastSocketClosed timeout + KTestSoDummyNifSetLastSocketActivityTimeout - updates the LastSocketActivity timeout +@param aOption package buffer containing the TInt value to set the timeout to. +@return KErrNone on success, or a system-wide error code. Common errors are: + KErrNotSupported if the provided option level is not of the type KCOLInterface + KErrNotSupported if the provided option name is not supported (not implemented) + KErrArgument if the argument is unacceptable (e.g. aOption carries NULL) +*/ +TInt CDummyIfLink::Control(TUint aLevel,TUint aName,TDes8& aOption, TAny* /* aSource */) + { + TInt colErr(KErrNotSupported); + + if(KCOLInterface == aLevel) // The only level supported. + { + switch(aName) + { + // Support for testing updating of Nifman Idle timeouts via CNifAgentRef::WriteInt + // When called, the specified timeout is set to the provided value + case KTestSoDummyNifSetLastSessionClosedTimeout: + colErr = SetNifmanIdleTimeout(TPtrC(LAST_SESSION_CLOSED_TIMEOUT), aOption); + break; + case KTestSoDummyNifSetLastSocketClosedTimeout: + colErr = SetNifmanIdleTimeout(TPtrC(LAST_SOCKET_CLOSED_TIMEOUT), aOption); + break; + case KTestSoDummyNifSetLastSocketActivityTimeout: + colErr = SetNifmanIdleTimeout(TPtrC(LAST_SOCKET_ACTIVITY_TIMEOUT), aOption); + break; + default: + ; + } + } + // Log Option Name in a readable form by removing User Read bit. + const TInt KOptionName = aName & ~KConnReadUserDataBit; + CDummyIfLog::Printf(_L("CDummyIfLink::Control Level [%d], Name [%d], Raw Name [%d]. Error [%d]"), aLevel, KOptionName, aName, colErr); + return colErr; + } + + +/* + * The IPv4 interface binder class + */ + +CDummyIf4::CDummyIf4(CDummyIfLink& aLink) + : CNifIfBase(aLink) + { + CDummyIfLog::Printf(_L("CDummyIf4::CDummyIf4()")); + + iLink = &aLink; + iLink->Factory().SetDripReceiver(TCallBack(DrainNextDrips, this)); + + // generate my local ip address (ip4) - vals potentially will be overwritten by any derived classes + iLocalAddressBase = KDummyNifLocalAddressBase; // also used later in control method + iLocalAddress = iLocalAddressBase + ((TUint32)this)%255; + + iIfName.Format(_L("dummynif[0x%08x]"), this); + } + +CDummyIf4::~CDummyIf4() + { + iLink->Factory().SetDripReceiver(TCallBack()); + } + +void CDummyIf4::BindL(TAny *aId) + { + CDummyIfLog::Printf(_L("CDummyIf4::BindL(aId %x)"), aId); + if(iProtocol) + User::Leave(KErrAlreadyExists); + iProtocol = (CProtocolBase*)aId; + } + +TInt CDummyIf4::Send(RMBufChain& aPdu, TAny*) + { + Recv(aPdu); + return 1; + } + +TInt CDummyIf4::State() + { + return EIfUp; + } + +void CDummyIf4::UpdateHeaders(TInet6HeaderIP4* aIp4, TInet6HeaderUDP* aUdp) +/** +Update the IPv4 and UDP headers to allow the packet to be looped back. +*/ +{ + // swap over the destination and source addresses + TUint32 temp; + temp = aIp4->SrcAddr(); + aIp4->SetSrcAddr(aIp4->DstAddr()); + aIp4->SetDstAddr(temp); + + // we've changed the ip hdr so need to recalculate the ip hdr checksum + aIp4->SetChecksum(0); + aIp4->SetChecksum(TChecksum::ComplementedFold(TChecksum::Calculate((TUint16*)aIp4, aIp4->HeaderLength()))); + + // also want to set the udp checksum to zero cos it will be wrong now that we have + // changed the ip hdr - just set to zero and it is ignored + aUdp->SetChecksum(0); + +} + +void CDummyIf4::Recv(RMBufChain& aPdu) + { + + TInt res; + TBool drop = EFalse; + + // this received data has already been looped back... + // get the ip header from the RMBufChain + TInet6HeaderIP4* ip4 = (TInet6HeaderIP4*) aPdu.First()->Next()->Ptr(); + if(ip4->Protocol() == KProtocolInetUdp) + { + // get the udp header as well - assume only udp traffic here + TInet6HeaderUDP* udp = (TInet6HeaderUDP*) ip4->EndPtr(); + + TUint8* subConn = udp->EndPtr()+1; + + CDummyIfLog::Printf(_L("CDummyIf4::Recv(...): UDP length %d, src port %d, dst port %d"), + udp->Length(), udp->SrcPort(), udp->DstPort()); + + // depending on the contents, pass it on up thru the stack + // or maybe do something else + + // use the destination port number to decide whether or not the payload is a command + TUint dstPort = udp->DstPort(); + if (KDummyNifCmdPort == dstPort) + { + // let's use the first payload byte as the command byte + switch (*(udp->EndPtr())) + { + case KForceDisconnect: + CDummyIfLog::Printf(_L("KForceDisconnect command")); + // do some action + iNotify->IfProgress(KLinkLayerClosed, KErrCommsLineFail); + iNotify->LinkLayerDown(KErrCommsLineFail, MNifIfNotify::EDisconnect); + // no return code so all we can do is respond with what we got + UpdateHeaders(ip4, udp); + break; + + case KForceReconnect: + CDummyIfLog::Printf(_L("KForceReconnect command")); + // do some action + iNotify->IfProgress(KLinkLayerClosed, KErrCommsLineFail); + iNotify->LinkLayerDown(KErrCommsLineFail, MNifIfNotify::EReconnect); + // no return code so all we can do is respond with what we got + UpdateHeaders(ip4, udp); + break; + + case KSendNotification: + CDummyIfLog::Printf(_L("KSendNotification command")); + res = iNotify->Notification(ENifToAgentEventTypeQueryIsDialIn); + //let's write the result in the next byte of the reply + if (res == KErrNotSupported) + udp->EndPtr()[1] = (unsigned char) KErrNone; + else + udp->EndPtr()[1] = (unsigned char) KErrGeneral; // this will lose it's sign :-( + + UpdateHeaders(ip4, udp); + break; + case KForceFinishedSelection: + CDummyIfLog::Printf(_L("KForceFinishedSelection command")); + // force subConn into KFinishedSelection State + iNotify->IfProgress(*subConn, KFinishedSelection, KErrNone); + + UpdateHeaders(ip4, udp); + break; + default: + CDummyIfLog::Printf(_L("Unknown command - ignoring it")); + drop = ETrue; + // unknown command, just ignore this packet??? + } + } + else + { // just echo the packet back to the original sender + + // update the headers (addresses, checksums etc) + UpdateHeaders(ip4, udp); + // now process it (pass up the stack) + } + } + else if(ip4->Protocol() == KProtocolInetTcp) + { + // swap over the destination and source addresses + TUint32 origSrc = ip4->SrcAddr(); + TUint32 origDst = ip4->DstAddr(); + ip4->SetSrcAddr(origDst); + ip4->SetDstAddr(origSrc); + ip4->SetChecksum(0); + ip4->SetChecksum(TChecksum::ComplementedFold(TChecksum::Calculate((TUint16*)ip4, ip4->HeaderLength()))); + } + else + { + CDummyIfLog::Printf(_L("CDummyIf4::Recv(...): IPv4 length %d, protocol %d [passing through]"), ip4->TotalLength(), ip4->Protocol()); + } + if(drop) + { + aPdu.Free(); + } + else + { + if(KDelaySlots > 0) + { + iLink->Factory().AddDrip(aPdu.First()); + aPdu.Init(); + } + else + { + iProtocol->Process(aPdu, (CProtocolBase*)this); + } + } + } + +TInt CDummyIf4::DrainNextDrips(TAny* aSelf) + { + CDummyIf4* self = (CDummyIf4*) aSelf; + RMBuf* next; + while((next = self->iLink->Factory().GetDrip()) != NULL) + { + RMBufChain pdu(next); + self->iProtocol->Process(pdu, (CProtocolBase*)self); + } + return 0; + } + + +void CDummyIf4::Info(TNifIfInfo& aInfo) const + { + aInfo.iVersion = TVersion(1,1,1); + aInfo.iFlags = KNifIfIsBase | KNifIfUsesNotify | KNifIfCreatedByLink; + aInfo.iName.Copy(iIfName); + aInfo.iProtocolSupported = 0; + } + +TInt CDummyIf4::Control(TUint aLevel, TUint aName, TDes8& aOption, TAny* /* aSource */) + { + CDummyIfLog::Printf(_L("CDummyIf::Control(aLevel %x, aName %x, ...)"), aLevel, aName); + + if (aLevel==KSOLInterface) + { + switch (aName) + { + case KSoIfInfo: + { + TSoIfInfo& opt = *(TSoIfInfo*)aOption.Ptr(); + + _LIT(KName, "MyName"); + opt.iName.Copy(KName); + opt.iFeatures = KIfCanBroadcast | KIfCanMulticast; + opt.iMtu = 1500; + opt.iSpeedMetric = 0; + return KErrNone; + } + + case KSoIfHardwareAddr: + return KErrNotSupported; + + case KSoIfConfig: + { + TSoInetIfConfig& opt = *(TSoInetIfConfig*)aOption.Ptr(); + if (opt.iFamily!=KAfInet) + return KErrNotSupported; + + TUint32 address; + const TInt KPort = 65; + + opt.iConfig.iAddress.SetAddress(iLocalAddress); + opt.iConfig.iAddress.SetPort(KPort); + + // network mask + opt.iConfig.iNetMask.Input(KNetworkMask); + opt.iConfig.iNetMask.SetPort(KPort); + + // broadcast address + address = iLocalAddressBase + KBroadcastAddressSuffix; + opt.iConfig.iBrdAddr.SetAddress(address); + opt.iConfig.iBrdAddr.SetPort(KPort); + + // default gateway + address = iLocalAddressBase + KDefaultGatewayAddressSuffix; + opt.iConfig.iDefGate.SetAddress(address); + opt.iConfig.iDefGate.SetPort(KPort); + + // primary DNS, just make same as default gateway + opt.iConfig.iNameSer1.SetAddress(address); + opt.iConfig.iNameSer1.SetPort(KPort); + + // secondary DNS + address = iLocalAddressBase + KSecondaryDnsAddressSuffix; + opt.iConfig.iNameSer2.SetAddress(address); + opt.iConfig.iNameSer2.SetPort(KPort); + + return KErrNone; + } + + case KSoIfCompareAddr: + if(((TInetAddr&)aOption).Address()!=iLocalAddress) + return KErrBadName; + return KErrNone; + + case KSoIfGetConnectionInfo: + TSoIfConnectionInfo& opt = *(TSoIfConnectionInfo*)aOption.Ptr(); + TInt err = KErrNone; + TBuf<2*KCommsDbSvrMaxColumnNameLength+1> fieldName; + _LIT(KSlashChar, "\\"); + + fieldName.Copy(TPtrC(IAP)); + fieldName.Append(KSlashChar); + fieldName.Append(TPtrC(COMMDB_ID)); + if ((err = iNotify->ReadInt(fieldName, opt.iIAPId)) != KErrNone) + return err; + + fieldName.Copy(TPtrC(IAP)); + fieldName.Append(KSlashChar); + fieldName.Append(TPtrC(IAP_NETWORK)); + if ((err = iNotify->ReadInt(fieldName, opt.iNetworkId)) != KErrNone) + return err; + + return KErrNone; + } + } + return KErrNotSupported; + } + +TInt CDummyIf4::Notification(TAgentToNifEventType /*aEvent*/, void * /*aInfo*/) + { + return KErrNone; + } + +void CDummyIfLog::Write(const TDesC& aDes) +// +// Write aText to the log +// + { + + RFileLogger::Write(KDummyIfLogFolder(), KDummyIfLogFile(), EFileLoggingModeAppend, aDes); + } + +void CDummyIfLog::Printf(TRefByValue aFmt,...) +// +// Write a mulitple argument list to the log, trapping and ignoring any leave +// + { + + VA_LIST list; + VA_START(list,aFmt); + RFileLogger::WriteFormat(KDummyIfLogFolder(), KDummyIfLogFile(), EFileLoggingModeAppend, aFmt, list); + } + +void CDummyIfLog::HexDump(const TText* aHeader, const TText* aMargin, const TUint8* aPtr, TInt aLen, TInt aWidth) + { + + TBuf<0x100> buf; + TInt i = 0; + const TText* p = aHeader; + while (aLen>0) + { + TInt n = aLen>aWidth ? aWidth : aLen; + if (p!=NULL) + { + _LIT(string1,"%s%04x : "); + buf.AppendFormat(string1, p, i); + } + TInt j; + _LIT(string2,"%02x "); + for (j=0; j126 ? '.' : aPtr[i+j]); + buf.Append(KEndOfLine); + Write(buf); + buf.SetLength(0); + aLen -= n; + i += n; + p = aMargin; + } + } + +