networkingtestandutils/networkingunittest/dummynif/dummynif.cpp
changeset 0 af10295192d8
child 5 1422c6cd3f0c
--- /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 <comms-infras/nifif.h>
+#include <nifvar.h>
+#include <nifutl.h>
+#include <es_mbuf.h>
+#include <nifmbuf.h>
+#include <in_iface.h>
+#include <comms-infras/commsdebugutility.h>
+#include <connectprog.h>
+
+#include <in_chk.h>
+#include <in_sock.h>
+#include <tcp_hdr.h>
+
+#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<CDummyIfFactory&>(*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<const TInt*>(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<const TDesC> 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; j<n; j++)
+			buf.AppendFormat(string2, aPtr[i+j]);
+		_LIT(string3,"   ");
+		while (j++<KHexDumpWidth)
+			buf.Append(string3);
+		_LIT(string4," ");
+		buf.Append(string4);
+		_LIT(string5,"%c");
+		for (j=0; j<n; j++)
+			buf.AppendFormat(string5, aPtr[i+j]<32 || aPtr[i+j]>126 ? '.' : aPtr[i+j]);
+		buf.Append(KEndOfLine);
+		Write(buf);
+		buf.SetLength(0);
+		aLen -= n;
+		i += n;
+		p = aMargin;
+		}
+	}
+
+