// 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:
// This contains TE_RConnectionStep class which is
// the base class for all the RConnection multihoming test steps.
// Contains methods which simplify the API to RConnection, RSocket and 
// RHostResolver to be used by derived classes. This abstraction means 
// that the API can continue to evolve as it has done for a while without 
// impacting a large number of test cases - just alter this parent class.
//
//

/**
 @file
*/
#include "TE_RConnectionStep.h"
#include <commdbconnpref.h>
#include <dummynifvar.h>
#include <c32root.h>
#include <comms-infras/esocktestutils.h>
#include <cs_subconparams.h> 
#include <cs_subconevents.h>
#include <ecom/ecom.h>
#include <e32cons.h>
#include <comms-infras/es_commsdataobject.h>
#include <commdbconnpref.h>
#include <commsdattypeinfov1_1.h>
#include <comms-infras/connectionqueryset.h>

#ifdef SYMBIAN_OLD_EXPORT_LOCATION
#include <naptinterface.h>
#else
//after the header file relocation this header won't be exported, so it needs to be a user include.
#include "naptinterface.h"
#endif

#include <simtsy.h>

_LIT(KSimtsyName,"SIM");

TE_RConnectionStep::TE_RConnectionStep()
/**
 * Constructor for TS_RConnectonStep(). Does nothing.
 * @param none
 * @return doesn't it is a constructor
 */
{
}

TE_RConnectionStep::~TE_RConnectionStep()
/**
 * Destructor for TE_RConnectionStep(). Does nothing.
 */
{ 
	CActiveScheduler::Install(NULL);
	delete iScheduler;
}	

enum TVerdict TE_RConnectionStep::doTestStepPreambleL(void)
/**
 * Preamble called before every single test case which is derived from TE_RConnectionStep (unless overridden of course). Sets up addresses and other values to be used by the test code proper. Waits for any remaining interfaces from previous tests to close.
 * @param none
 * @return success (EPass) or failure (EFail) of initialisation
 */
{
	enum TVerdict result = EPass;
	_LIT(KPhbkSyncCMI, "phbsync.cmi");
	if (StartC32WithCMISuppressions(KPhbkSyncCMI) != KErrNone)
    	{
    	return EFail;
    	}
	iScheduler = new(ELeave) CActiveScheduler;
	CActiveScheduler::Install(iScheduler);
	/*
	 * Load the config from the .ini file
	 */

	if (KErrNone != ReadIniFile())
		result = EFail;
	
	iDummyNifSendAddr.SetAddress(KDummyNifLocalAddressBase + KDummyHungryNifReservedHostId);
	iDummyNifSendAddr.SetPort(iEchoPortNum);
	iHungryNifSendAddr.SetAddress(KDummyNifLocalAddressBase + KDummyHungryNifReservedHostId);
	iHungryNifSendAddr.SetPort(iEchoPortNum);
		 	 	
	_LIT(KNaptStatusCheck, "On");
	if (iNaptStatus.Compare(KNaptStatusCheck)!=0)
		{
		// Wait for all of the interfaces to close down
		RSocketServ ss;
		
		ss.Connect();
		CleanupClosePushL(ss);

		if (KErrNone != WaitForAllInterfacesToCloseL(ss))
			{
			INFO_PRINTF1(_L("Previous test case has left connections up that have not closed. Stopping them."));
			TBuf<200> errDesc;
			TInt err;
			if ((err = ESockTestUtils::StopAllInterfaces(errDesc)) == KErrNone)
				result = EPass;
			else
				{
				INFO_PRINTF3(_L("StopAllInterfaces() err=%d\n%S"), err, &errDesc);
				result = EFail;
			}
			}
		ss.Close();
		CleanupStack::Pop();
		}

	return result;
}

enum TVerdict TE_RConnectionStep::doTestStepPostambleL(void)
{
	
	if( iStatus && iStatus->IsActive() )
		{
		iStatus->Cancel();
		}
	delete iStatus;
	iStatus = NULL;
	CActiveScheduler::Install(NULL);
	REComSession::FinalClose();
	
	return EPass;
}

TInt TE_RConnectionStep::ReadIniFile(void)
/**
 * Opens the .ini file, reads the contents into some class members and then closes the file again
 * @return system wide error code
 */
{
	TInt result = KErrNone;

	TPtrC filename(_L("c:\\rconnectiontest.ini"));
	TBuf<64> tempBuf; // 16 is enough for an IP addr and the separating dots
	TPtrC temp(0,NULL);


	// this opens the file and loads everything in
	// LoadConfig(filename);

	// set the IAP values in the class members
	_LIT(KIapSection, "IAP");
	_LIT(KDummyNifIapKey, "DummyNifIapNumber");
	_LIT(KNtRasIapOnlyShortTimerKey, "DummyNifOnlyShortTimerIapNumber");
	_LIT(KDummyNifLongTimeoutIapKey, "DummyNifLongTimeoutIapNumber");
	_LIT(KDummyNifTwoBinderIapKey, "DummyNifTwoBinderIapNumber");
	_LIT(KHungryNifLongTimeoutIapKey, "HungryNifLongTimeoutIapNumber");
	_LIT(KHungryNifIapKey, "HungryNifIapNumber");
	_LIT(KDefaultIapKey, "DefaultIapNumber");
	_LIT(KBadNtRasIapKey, "BadNtRasIapNumber");
	_LIT(KMissingNifIapKey, "MissingNifIapNumber");
	_LIT(KTestNifIapKey, "TestNifIapNumber");
	_LIT(KDummyNifAgentIap, "DummyNifAgentIapNumber");
	_LIT(KSimTSYIap, "SimTSYIapNumber");
	_LIT(KStaticDnsDynamicAddr, "StaticDnsDynamicAddr");

	if (!(GetIntFromConfig(KIapSection, KDummyNifIapKey, iDummyNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KDummyNifLongTimeoutIapKey, iDummyNifLongTimeoutIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KDummyNifTwoBinderIapKey, iDummyNifTwoBinderIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KHungryNifLongTimeoutIapKey, iHungryNifLongTimeoutIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KHungryNifIapKey, iHungryNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KDefaultIapKey, iDefaultIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KNtRasIapOnlyShortTimerKey, iNtRasIapOnlyShortTimer)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KBadNtRasIapKey, iBadNtRasIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KMissingNifIapKey, iMissingNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KTestNifIapKey, iTestNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KDummyNifAgentIap, iDummyNifAgentIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KSimTSYIap, iSimTSYIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KStaticDnsDynamicAddr, iStaticDnsDynamicAddr)))
		result = KErrNotFound;


	// IAP numbers specifically used by the all interface notification tests
	_LIT(KAinIapSection, "AINIAPs");
	_LIT(KSecondHungryNifIapKey, "SecondHungryNifNumber");
	_LIT(KThirdHungryNifIapKey, "ThirdHungryNifNumber");
	_LIT(KSecondDummyNifIapKey, "SecondDummyNifNumber");
	_LIT(KThirdDummyNifIapKey, "ThirdDummyNifNumber");
	_LIT(KFourthDummyNifIapKey, "FourthDummyNifNumber");
	_LIT(KFifthDummyNifIapKey, "FifthDummyNifNumber");
	_LIT(KFNaptPublicIapKey, "NaptPublicIapNumber");
	_LIT(KFNaptPrivateIapKey, "NaptPrivateIapNumber");
	

	if (!(GetIntFromConfig(KAinIapSection, KSecondHungryNifIapKey, iSecondHungryNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KAinIapSection, KThirdHungryNifIapKey, iThirdHungryNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KAinIapSection, KSecondDummyNifIapKey, iSecondDummyNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KAinIapSection, KThirdDummyNifIapKey, iThirdDummyNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KAinIapSection, KFourthDummyNifIapKey, iFourthDummyNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KAinIapSection, KFifthDummyNifIapKey, iFifthDummyNifIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KFNaptPublicIapKey, iNaptPublicIap)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KIapSection, KFNaptPrivateIapKey, iNaptPrivateIap)))
		result = KErrNotFound;

	// set the timeout values in the class members
	_LIT(KTimeoutSection, "Timeouts");
	_LIT(KShortTimeoutKey, "ShortTimeout");
	_LIT(KMediumTimeoutKey, "MediumTimeout");
	_LIT(KLongTimeoutKey, "LongTimeout");
	
	if (!(GetIntFromConfig(KTimeoutSection, KShortTimeoutKey, iShortTimeout)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KTimeoutSection, KMediumTimeoutKey, iMediumTimeout)))
		result = KErrNotFound;
	if (!(GetIntFromConfig(KTimeoutSection, KLongTimeoutKey, iLongTimeout)))
		result = KErrNotFound;
	
	// other general set up stuff
	_LIT(KGeneralSection, "General");
	_LIT(KInterfaceName, "Interface");
	if (!(GetStringFromConfig(KGeneralSection, KInterfaceName, temp)))
		result = KErrNotFound;
	iInterfaceName.Copy(temp);
	
	_LIT(KNameServerAddr, "NameServerAddr");
	if (!GetStringFromConfig(KGeneralSection, KNameServerAddr, temp))
		result = KErrNotFound;
	iNameServerAddr.Input(temp);

	_LIT(KEchoPortKey, "EchoPort");
	if (!(GetIntFromConfig(KGeneralSection, KEchoPortKey, iEchoPortNum)))
		result = KErrNotFound;
	_LIT(KNaptTestServerPort, "NaptTestServerPort");
	if (!(GetIntFromConfig(KGeneralSection, KNaptTestServerPort, iNaptTestServerPort)))
		result = KErrNotFound;

	// set the address which we should connect TCP sockets to (addr of TCP echo server)
	_LIT(KTcpConfigSection, "TCP Config");
	_LIT(KTcpSendAddrKey, "TcpSendAddress");
	if (!GetStringFromConfig(KTcpConfigSection, KTcpSendAddrKey, temp))
		result = KErrNotFound;
	iEchoServerAddr.Input(temp);
	// set it's port to the echo port
	iEchoServerAddr.SetPort(iEchoPortNum);
	
	// Napt
	_LIT(KNaptTestServer, "NaptTestServer");
	if (!GetStringFromConfig(KGeneralSection, KNaptTestServer, temp))
		result = KErrNotFound;
	iNaptTestServAddr.Input(temp);
	// set it's port to the NaptTestServer port
	iNaptTestServAddr.SetPort(iNaptTestServerPort);

	// the name which we will attempt to resolve many many times
	_LIT(KTestNameKey, "TestName");
	if (!GetStringFromConfig(KTcpConfigSection, KTestNameKey, temp))
		result = KErrNotFound;
	iTestName = temp;

	// the address which we will pass in when using GetByAddress()
	_LIT(KLookupAddressKey, "LookupAddress");
	if (!GetStringFromConfig(KGeneralSection, KLookupAddressKey, temp))
		result = KErrNotFound;
	iLookupAddress.Input(temp);
	
	_LIT(KNaptStatus, "NaptStatus");
	if (!GetStringFromConfig(KGeneralSection, KNaptStatus, iNaptStatus))
		result = KErrNotFound;

	return result;
}

TInt TE_RConnectionStep::OpenSocketServer(RSocketServ& ss)
/**
 * Opens the socket server that is pointed to
 * @param ss the socket server to open
 * @return system wide error code
 */
    {
    INFO_PRINTF1(_L("Opening Socket server"));
	return (ss.Connect());
    }

void TE_RConnectionStep::CloseSocketServer(RSocketServ& ss)
/**
 * Closes the socket server that is pointed to
 * @param ss the socket server to close
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Closing Socket server"));
	ss.Close(); // Close() inherited from RHandleBase?
}

TInt TE_RConnectionStep::OpenConnection(RConnection& conn, RSocketServ& ss)
/**
 * Open the connection using the socket server too
 * @param conn the connection to open
 * @param ss the socket server within which the connection is to be opened
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Opening Connection"));
	return (conn.Open(ss));
}

TInt TE_RConnectionStep::OpenConnection(RConnection& conn, RSocketServ& ss, TName& name)
/**
 * Open the connection (passing the name provided)
 * @param conn - the connection to open
 * @param ss - the socket server within which the connection is to be opened
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Opening Connection"));
	return (conn.Open(ss, name));
}

TInt TE_RConnectionStep::StartConnection(RConnection& conn)
/**
 * Start a connection using the default comm db settings
 * @param conn the connection to start
 * @return system wide error code
 */
{
	TRequestStatus status;
	conn.Start(status);
	INFO_PRINTF1(_L("Starting Connection"));
	User::WaitForRequest(status);
	return status.Int();
}

TInt TE_RConnectionStep::StartConnectionSynchronous(RConnection& conn)
/**
 * Start a connection using the default comm db settings (using the synchronous call)
 * @param conn - the connection to start
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Starting Connection"));
	return (conn.Start());
}

void TE_RConnectionStep::StartConnectionAsynchronous(RConnection& conn, TRequestStatus& status)
/**
 * Start a connection using the default comm db settings (returning before it completes)
 * @param conn - the connection to start
 * @param system wide error code
 */
{
	INFO_PRINTF1(_L("Starting Connection"));
	conn.Start(status);
}

TInt TE_RConnectionStep::StartConnectionWithOverrides(RConnection& conn, TInt iap)
/**
 * Start a connection on the IAP as specified by the param, do this by 
 * building some database overrides.
 * @param conn - the connection to start
 * @param iap - which IAP to create the connection over
 * @return system wide error code
 */
{
	TRequestStatus status;
	
	TCommDbConnPref prefs;
	prefs.SetIapId(iap);
	prefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
	conn.Start(prefs, status);
	INFO_PRINTF1(_L("Starting Connection with over rides"));
	User::WaitForRequest(status);

	return status.Int();
}

TInt TE_RConnectionStep::StartConnectionWithOverridesSynchronous(RConnection& conn, TInt iap)
/**
 * Start a connection on the IAP as specified by the param, do this by building some 
 * database overrides. Use the synchronous start method
 * @param conn - the connection to start
 * @param iap - which IAP to create the connection over
 * @return system wide error code
 */
{
	TCommDbConnPref prefs;
	prefs.SetIapId(iap);
	INFO_PRINTF1(_L("Starting Connection with over rides"));
	prefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
	return (conn.Start(prefs));
}

void TE_RConnectionStep::StartConnectionWithOverridesAsynchronous(RConnection& conn, TCommDbConnPref& aPrefs, TInt iap, TRequestStatus& status)
/**
 * Start a connection on the IAP as specified by the param - return before it completes
 * @param conn - the connection to start
 * @param iap - which IAP to create the connection over
 * @return system wide error code
 */
{
	aPrefs.SetIapId(iap);
	aPrefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
	INFO_PRINTF1(_L("Starting Connection with over rides"));
	conn.Start(aPrefs, status);
}



void TE_RConnectionStep::CloseConnection(RConnection& conn)
/**
 * Close a connection
 * @param conn the connection to close
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Closing Connection "));
	conn.Close();
}


TInt TE_RConnectionStep::StopConnection(RConnection& conn)
/**
 * Force the connection to stop and remove the interface no matter what other connections are using it
 * @param conn the connection to stop
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Stopping Connection "));
	return (conn.Stop());
}

TInt TE_RConnectionStep::EnumerateConnections(RConnection& conn, TUint& num)
/**
 * Read how many connections (==interfaces?) exist at the moment
 * @param conn - to be used to read the count
 * @param num - on completion holds the number of connections
 * @return system wide error code
 */
{
	return (conn.EnumerateConnections(num));
}

TInt TE_RConnectionStep::GetTimeoutValues(RConnection& conn, TTimeoutValues &timeouts)
/**
 * Read the timeout values from commdb
 * @param conn - the connection to read the values from
 * @param timeouts - where to put the timeout vals
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Getting Timeout Values"));
	TInt ret = KErrNone;
	TInt tmp;
	if (KErrNone != (tmp = conn.GetIntSetting(_L("ModemBearer\\LastSessionClosedTimeout"), timeouts.iShortTimeout)))
		ret = tmp;
	if (KErrNone != (tmp = conn.GetIntSetting(_L("ModemBearer\\LastSocketClosedTimeout"), timeouts.iMediumTimeout)))
		ret = tmp;
	if (KErrNone != (tmp = conn.GetIntSetting(_L("ModemBearer\\LastSocketActivityTimeout"), timeouts.iLongTimeout)))
		ret = tmp;

	return ret;
}

TInt TE_RConnectionStep::AttachNormal(RConnection& conn, const TDesC8& info)
/**
 * Attach the connection supplied to the one described by the info
 * @param conn - the connection to be attached to something
 * @param info - the details of the connection to attach to
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Attach Normal"));
	return conn.Attach(info, RConnection::EAttachTypeNormal);
}

TInt TE_RConnectionStep::AttachMonitor(RConnection& conn, const TDesC8& info)
/**
 * Attach the connection supplied to the one described by the info (as a monitor)
 * @param conn - the connection to be attached to something
 * @param info - the details of the connection to attach to
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Attach Monitor"));
	return conn.Attach(info, RConnection::EAttachTypeMonitor);
}

void TE_RConnectionStep::ProgressNotification(RConnection& conn, TRequestStatus& status, 
											  TNifProgressBuf& progress, TUint aSelectedProgress)
/**
 * Request notification when the progress changed to that supplied
 * @param conn - the connection we are interested in the progress of
 * @param status - the status variable which should be updated eventually
 * @param aSelectedProgress - the progress we want
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Progress Notification "));
	conn.ProgressNotification(progress, status, aSelectedProgress);
}

void TE_RConnectionStep::ProgressNotification(RConnection& conn, TRequestStatus& status, 
											  TNifProgressBuf& progress)
/**
 * Request notification of the next progress change
 * @param conn - the connection whose status we are interested in
 * @param status - the status variable that should be updated
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Progress Notification "));
	conn.ProgressNotification(progress, status);
}

void TE_RConnectionStep::CancelProgressNotification(RConnection& conn)
/**
 * Cancel the notification of progress changes
 * @param conn - the connection to cancel progress notification for
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Cancel Connection Progress Notification "));
	conn.CancelProgressNotification();
}

TInt TE_RConnectionStep::Progress(RConnection& conn, TNifProgress& progress)
/**
 * Read the current progress state
 * @param conn - the connection to read the progress of
 * @param progress - where to put the read progress
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Progress"));
	return conn.Progress(progress);
}

TInt TE_RConnectionStep::LastProgressError(RConnection& conn, TNifProgress& progress)
/**
 * Get the last progress error
 * @param conn - the connection we are interested in
 * @param progress - where to put the progress value (the error)
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Connection Last Progress Error"));
	return conn.LastProgressError(progress);
}

TInt TE_RConnectionStep::GetConnectionInfo(RConnection& conn, TUint index, TDes8& aConnectionInfo)
/**
 * Read back the information about a particular connection (using the enumeration functionality)
 * @param conn - the connection to use to access the info
 * @param index - the index of the connection we want to find out about
 * @param aConnectionInfo - where to write the info into
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Get Connection info "));
	return conn.GetConnectionInfo(index, aConnectionInfo);
}

TInt TE_RConnectionStep::GetInfo(RConnection& conn, TPckgBuf<TConnectionInfo>& info)
/**
 * Read the info about this connection from comm db
 * @param conn - the connection to read info about
 * @param info - where to write the info to
 * @return system wide error code
 */
{
	_LIT(KIapTableIdDes, "IAP\\Id" );
	_LIT(KIapTableIapNetworkDes, "IAP\\IAPNetwork" );

	TInt ret = KErrNone;
	ret = conn.GetIntSetting(KIapTableIdDes, info().iIapId);

	const CommsDat::TMDBElementId KIapTableIdFieldId = KCDTIdIAPRecord | KCDTIdRecordTag;
	const CommsDat::TMDBElementId KTapTableIapNetworkId = KCDTIdIAPNetwork;

	if (ret == KErrNone)
		{
		ret = conn.GetIntSetting(KIapTableIapNetworkDes, info().iNetId);
		}

	ESock::XConnectionQuerySet* querySet = NULL;
	if ( ret == KErrNone )
		{
		TRAP(ret, querySet = ESock::XConnectionQuerySet::NewL() );
		}

	if ( ret == KErrNone )
		{
		TRAP(ret, ESock::XUintQuery::NewL(KIapTableIdFieldId, *querySet) );
		}

	if ( ret == KErrNone )
		{
		TRAP(ret, ESock::XUintQuery::NewL(KTapTableIapNetworkId, *querySet) );
		}

	ESock::CConnectionQuerySet* connectionQuerySet = NULL;
	if ( ret == KErrNone )
		{
		TRAP(ret, connectionQuerySet = ESock::CConnectionQuerySet::NewL(querySet) );
		}

	if ( ret == KErrNone )
		{
		querySet = NULL;
		}

	if ( ret == KErrNone )
		{
		ret = conn.GetParameters( *connectionQuerySet );
		}

	if ( ret == KErrNone )
		{
		TBool match = EFalse;
		ESock::XConnectionQuerySet& outputQuerySet = connectionQuerySet->DataObject();
		ESock::XUintQuery* iapTableIdQuery = static_cast<ESock::XUintQuery*>(outputQuerySet.FindQuery( KIapTableIdFieldId ));
		ESock::XUintQuery* iapTableNetworkQuery = static_cast<ESock::XUintQuery*>(outputQuerySet.FindQuery( KTapTableIapNetworkId ));

		match = ( iapTableIdQuery
			&& iapTableNetworkQuery
			&& iapTableIdQuery->Error() == KErrNone
			&& iapTableNetworkQuery->Error() == KErrNone
			&& iapTableIdQuery->IsQueryAnswered()
			&& iapTableNetworkQuery->IsQueryAnswered()
			&& iapTableIdQuery->Data() == info().iIapId
			&& iapTableNetworkQuery->Data() == info().iNetId
			);

		if ( !match )
			{
			ret = KErrGeneral;
			}
		}

	delete querySet;
	delete connectionQuerySet;

	REComSession::FinalClose();
	return ret;
}

TInt TE_RConnectionStep::OpenUdpSocketL(RSocket& sock, RSocketServ& ss)
/**
 * Open a UDP socket within the supplied socket server. No connection is 
 * specified so let the system implicitly decide which to use
 * @param sock - the socket to open
 * @param ss - the socket server
 * @return system wide error code
 */
{
	TInt err = KErrNone;
	TInt ret = KErrNone;
	
	INFO_PRINTF1(_L("Opening Implicit UDP Socket"));

	err = sock.Open(ss, KAfInet, KSockDatagram, KProtocolInetUdp);
	TESTEL(KErrNone == ret, ret);
	if (err != KErrNone)
		ret = err;
	
	err = sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);
	TESTEL(err == KErrNone, err);
	if (err != KErrNone)
		ret = err;

	err = sock.SetLocalPort(iEchoPortNum); 
	TESTEL(err == KErrNone, err);
	if (err != KErrNone)
		ret = err;

	return ret;
}

TInt TE_RConnectionStep::OpenUdpSocketExplicitL(RSocket& sock, RSocketServ& ss, RConnection& conn)
/**
 * Open a UDP socket with the supplied socket server. Associate it 
 * with the specified connection.
 * @param sock - the socket to open
 * @param ss - the socket server
 * @param conn - the connection to associate it with
 * @return system wide error code
 */
{
	TInt err;
	TInt ret = KErrNone;
	INFO_PRINTF1(_L("Opening Explicit UDP Socket"));

	err = sock.Open(ss, KAfInet, KSockDatagram, KProtocolInetUdp, conn);
	TESTEL(KErrNone == err, err);
	if (err != KErrNone)
		ret = err;

	err = sock.SetOpt(KSoReuseAddr, KSolInetIp, 1); 
	TESTEL(err == KErrNone, err);
	if (err != KErrNone)
		ret = err;

	err = sock.SetLocalPort(iEchoPortNum); 
	TESTEL(err == KErrNone, err);
	if (err != KErrNone)
		ret = err;
	
	return ret;
}

void TE_RConnectionStep::DestroyUdpSocket(RSocket& sock)
/**
 * Destroys the supplied socket
 * @param sock - the socket to destroy
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Closing Socket"));
	sock.Close();
}

TInt TE_RConnectionStep::OpenTcpSocket(RSocket& sock, RSocketServ& ss)
/**
 * Open a TCP socket within the supplied socket server. No connection is 
 * specified so let the system implicitly decide which to use
 * @param sock - the socket to open
 * @param ss - the socket server
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Opening Implicit TCP Socket"));
	return (sock.Open(ss, KAfInet, KSockStream, KProtocolInetTcp));
}

TInt TE_RConnectionStep::OpenTcpSocketExplicit(RSocket& sock, RSocketServ& ss, RConnection& conn)
/**
 * Open a TCP socket within the supplied socket server. Associate it with 
 * the specified connection.
 * @param sock - the socket to open
 * @param ss - the socket server
 * @param conn - the connection to associate it with
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Opening Explicit TCP Socket"));
	return (sock.Open(ss, KAfInet, KSockStream, KProtocolInetTcp, conn));
}

TInt TE_RConnectionStep::ConnectTcpSocket(RSocket& sock, TSockAddr& addr)
/**
 * Connect the supplied TCP socket to the destination socket
 * @param sock - the socket to connect up
 * @param addr - the address of the destination to connect up to
 */
{
	TRequestStatus status;
	INFO_PRINTF1(_L("Connecting TCP Socket"));
	sock.Connect(addr, status);
	User::WaitForRequest(status);
	return status.Int();
}

TInt TE_RConnectionStep::ConnectFourTcpSockets(RSocket& sock1, RSocket& sock2, RSocket& sock3, RSocket& sock4, TSockAddr& dest)
/**
 * Connect the supplied TCP sockets to the destination socket
 * @param sock1 - the first of the sockets to connect up
 * @param sock2 - the second of the sockets to connect up
 * @param sock3 - the third of the sockets to connect up
 * @param sock4 - the fourth of the sockets to connect up
 * @param dest - the address of the destination to connect up to
 */
{
	TRequestStatus status[4];
	INFO_PRINTF1(_L("Connecting TCP Socket"));
	sock1.Connect(dest, status[0]);
	INFO_PRINTF1(_L("Connecting TCP Socket"));
	sock2.Connect(dest, status[1]);
	INFO_PRINTF1(_L("Connecting TCP Socket"));
	sock3.Connect(dest, status[2]);
	INFO_PRINTF1(_L("Connecting TCP Socket"));
	sock4.Connect(dest, status[3]);

	// To avoid stray events we need (a) four signals and (b) all four sockets to have completed - as always it doesn't matter if the
	// four signals aren't actually from these sockets, eg if lower priority things are completing
	TInt signalsOutstanding = 4;
	TBool allConnected;
	do
		{
		User::WaitForAnyRequest();
		--signalsOutstanding;
		allConnected = (status[0].Int() != KRequestPending) && (status[1].Int() != KRequestPending) &&
							(status[2].Int() != KRequestPending) && (status[3].Int() != KRequestPending);
		} while(signalsOutstanding > 0 || !allConnected);

	// If other requests complete while we're waiting for ours then have to re-add their signals
	while(signalsOutstanding < 0)
		{
		TRequestStatus status;
		TRequestStatus* dummyStatus = &status;
		User::RequestComplete(dummyStatus, KErrNone);
		++signalsOutstanding;
		}

	if (status[0].Int() != KErrNone)
		return status[0].Int();
	if (status[1].Int() != KErrNone)
		return status[1].Int();
	if (status[2].Int() != KErrNone)
		return status[2].Int();
	if (status[3].Int() != KErrNone)
		return status[3].Int();

	return KErrNone;
}

TInt TE_RConnectionStep::DestroyTcpSocket(RSocket& sock)
/**
 * Destroys the supplied socket
 * @param sock - the socket to destroy
 * @return system wide error code
 */
{
	TRequestStatus status;
	INFO_PRINTF1(_L("Shutting down TCP Socket"));
	sock.Shutdown(RSocket::EImmediate, status);
	User::WaitForRequest(status);
	sock.Close();

	return status.Int();
}

TInt TE_RConnectionStep::OpenNullSocket(RSocket& sock, RSocketServ& ss)
/**
 * Open a socket but not associated to any protocol
 * @param sock - the socket to open
 * @param ss - the socket server to use
 * @return system wide error code
 */
{
	INFO_PRINTF1(_L("Open Null Socket"));
	return (sock.Open(ss));
}

TInt TE_RConnectionStep::TransferSocket(RSocket& source, RSocket& target, RSocketServ& ss)
/**
 * Transfer a socket to another socket
 * @param source - the socket to transfer from
 * @param target - the socket to transfer to
 * @param ss - the socket server the original socket is in
 * @return system wide error code
 */
{
	//-- note that RSocket::Transfer() operation since 8.1b shall be additionally enabled by 
	//-- setting KSOEnableTransfer socket option with appropriate capabilities set for the 
	//-- process that "pulls" the socket. It shall be done before calling this function.
	TName name;

	source.Name(name);

	return target.Transfer(ss, name);
}


TInt TE_RConnectionStep::OpenHostResolver(RHostResolver& hr, RSocketServ& ss)
/**
 * Open a host resolver within the supplied socket server. No connection is 
 * specified sp let the system decide which to use
 * @param hr - the host resolver to open
 * @param ss - the socket server to use
 * @return system wide error code
 */
{
	return (hr.Open(ss, KAfInet, KProtocolInetTcp));
}

TInt TE_RConnectionStep::OpenHostResolverExplicit(RHostResolver& hr, RSocketServ& ss, RConnection& conn)
/**
 * Open a host resolver within the supplied socket server. Associate it with 
 * the specified connection
 * @param hr - the host resolver to open
 * @param ss - the socket server to use
 * @param conn - the connection to associate it with
 * @return system wide error code
 */
{
	return (hr.Open(ss, KAfInet, KProtocolInetUdp, conn));
}

TInt TE_RConnectionStep::MakeNameRequest(RHostResolver& hr, const TDesC& aName)
/**
 * Make a name request
 * @param hr - the host resolver to make the request with
 * @param aName - the name to resolve
 * @return system wide error code
 */
{	
	TRequestStatus status;
	TNameEntry result;
	INFO_PRINTF1(_L("Performing Asynchronous GetByName()"));
	hr.GetByName(aName, result, status);
	User::WaitForRequest(status);

	return status.Int();
}

TInt TE_RConnectionStep::MakeSynchronousNameRequest(RHostResolver& hr, const TDesC& aName)
/**
 * Make a name request using the synchronous method
 * @param hr - the host resolver to make the request with
 * @param aName - the name to resolve
 * @return system wide error code
 */
{
	TNameEntry result;
	INFO_PRINTF1(_L("Performing Synchronous GetByName()"));
	return (hr.GetByName(aName, result));
}

TInt TE_RConnectionStep::MakeAddressRequest(RHostResolver& hr, const TSockAddr& addr)
/**
 * Make a request FOR a name using GetByAddress()
 * @param hr - the host resolver to use
 * @param addr - the address to pass in
 * @return system wide error code
 */
{
	TRequestStatus status;
	TNameEntry name;
	INFO_PRINTF1(_L("Performing Asynchronous GetByAddress()"));
	hr.GetByAddress(addr, name, status);
	User::WaitForRequest(status);

	return status.Int();
}

TInt TE_RConnectionStep::MakeSynchronousAddressRequest(RHostResolver& hr, const TSockAddr& addr)
/**
 * Make a request FOR a name using GetByAddress() [use the synchronous version]
 * @param hr - the host resolver to use
 * @param addr - the address to pass in
 * @return system wide error code
 */
{
	TNameEntry name;
	INFO_PRINTF1(_L("Performing Synchronous GetByAddress()"));
	return (hr.GetByAddress(addr, name));
}

void TE_RConnectionStep::DestroyHostResolver(RHostResolver& hr)
/**
 * Destroy the supplied host resolver
 * @param hr - the host resolver to destroy
 * @return system wide error code
 */
{
	hr.Close();
}

TInt TE_RConnectionStep::SendUdpData(RSocket& aSock, TSockAddr& aDest, TUint aPayloadSize)
/**
 * Send UDP data (an ICMP packet) over the socket specified to the address specified.
 * @param aSock The socket to use for the send
 * @param aDest The destination to send the data to
 * @param aPayloadSize The size of the packet to send
 * @return system wide error code
 */
{
	TBuf8<KMaxBufferLength> buffer;
	TRequestStatus status;

	// construct an ICMP packet to send on the socket
	buffer.SetMax();
	buffer.FillZ();
	buffer[0] = (TUint8) 0x08; // ICMP type = 8
	buffer[1] = (TUint8) 0x00; // ICMP code = 0
	buffer[2] = (TUint8) 0xF7; // ICMP checksum high byte
	buffer[3] = (TUint8) 0xFF; // ICMP checksum low byte
	buffer[13] = (TUint8) 0xFE;
	// NB the rest of the buffer is zero
	// hence the checksum (0xFFFF - 0x800) since 0x8
	// is the only non-zero element of the buffer

	// set the length of the data to be sent to that specified (payload size!)
	buffer.SetLength(aPayloadSize);

	// send the data out over the socket
	aSock.SendTo(buffer, aDest, 0, status);
	User::WaitForRequest(status);

	return status.Int();
}

TInt TE_RConnectionStep::RecvUdpData(RSocket& aSock, TSockAddr& aDest, TUint aPayloadSize)
/**
 * Receive UDP packet from the network
 * @param aSock The socket to receive the packet on
 * @param aDest The address to receive the packet from
 * @param aPayloadSize The size of the packet to receive
 * @return system wide error code
 */
{
	TBuf8<KMaxBufferLength> buffer;
	TRequestStatus status;
	TInt timeoutInSecs = 10;
	RTimer timer;
	TRequestStatus timerStatus;

	// Create a timer so that we dont rely on being errored by esock alone
	TInt ret;
	if ((ret = timer.CreateLocal()) != KErrNone)
	{
		INFO_PRINTF2(_L("RTimer::CreateLocal() returned %d"), ret);
		timer.Close(); // from looking at impl shouldn't do any harm to call Close() here
		return ret;
	}

	timer.After(timerStatus, timeoutInSecs * 1000000);

	buffer.Zero();
	buffer.SetLength(aPayloadSize);

	aSock.RecvFrom(buffer, aDest, 0, status);
	User::WaitForRequest(status, timerStatus);

	// Timer expired, cancel the read
	if(timerStatus != KRequestPending)
		{
		aSock.CancelAll();
		User::WaitForRequest(status);
		timer.Close();
		return KErrTimedOut;
		}
	// otherwise cancel the timer
	timer.Cancel();
	User::WaitForRequest(timerStatus);
	timer.Close();

	// don't use TESTEL here as the test case may be expecting us to fail and that's ok...
	if (status != KErrNone)
		return status.Int();
	else
	{   // check that what we sent is what we got back
		// if the receive times out and we access buffer we get a panic
		TEST(buffer[0] == 0x08);
		TEST(buffer[1] == 0x00);
		TEST(buffer[2] == 0xF7);
		TEST(buffer[3] == 0xFF);
	}

	return KErrNone;
}

TInt TE_RConnectionStep::TestUdpDataPathL(RSocket& aSock, TSockAddr& aDest, TUint aPayloadSize)
/**
 * Sends data to the address specified (dest) and expects to receive it looped back unchanged
 * @param aSock The socket to send the data over (and receive it over)
 * @param aDest The destination to send the traffic to
 * @param aPayloadSize The amount of data to sent (defaults to KBufferLength)
 * @return system wide error code
 */
{
	TInt err;
	INFO_PRINTF1(_L("Sending UDP Data"));
	err = SendUdpData(aSock, aDest, aPayloadSize);
	if (err != KErrNone)
		return err;

	INFO_PRINTF1(_L("Receiving UDP Data"));
	err = RecvUdpData(aSock, aDest, aPayloadSize);
	// don't use TESTEL here as the test case may be expecting us to fail and that's ok...
	return err;
}

TInt TE_RConnectionStep::SendTcpData(RSocket& aSock)
/**
 * Send TCP data over the socket specified to the address specified.
 * @param aSock The socket to use for the send
 * @param aPayloadSize The size of the packet to send
 * @return system wide error code
 */
{
	TRequestStatus status;
	TBuf8<KBufferLength> buffer;

	// build some data to send
	buffer.SetMax();
	buffer.FillZ();
	buffer[0] = (TUint8) 0x08; // ICMP type = 8;
	buffer[1] = (TUint8) 0x00; // ICMP code = 0;
	buffer[2] = (TUint8) 0xF7; // ICMP checksum high byte
	buffer[3] = (TUint8) 0xFF; // ICMP checksum low byte

	// send the data
	aSock.Send(buffer, 0, status);
	User::WaitForRequest(status);

	return status.Int();
}

TInt TE_RConnectionStep::RecvTcpData(RSocket& aSock)
/**
 * Receive TCP packet from the network
 * @param aSock The socket to receive the packet on
 * @param aPayloadSize The size of the packet to receive
 * @return system wide error code
 */
{
	TRequestStatus status;
	TBuf8<KBufferLength> buffer;
	buffer.Zero();

	// hopefully get the same data back that was sent
	aSock.Recv(buffer, 0, status);
	User::WaitForRequest(status);

	if (status != KErrNone)
		return status.Int();
	else
	{	// check that what we sent is what we got back
		// if the receive times out and we access the buffer we get a panic
		TEST(buffer[0] == 0x08);
		TEST(buffer[1] == 0x00);
		TEST(buffer[2] == 0xF7);
		TEST(buffer[3] == 0xFF);
	}

	return KErrNone;
}

TInt TE_RConnectionStep::TestTcpDataPathL(RSocket& sock)
/**
 * Sends data and expects to receive it looped back unchanged
 * @param sock The socket to send the data over (and receive it over)
 * @param aPayloadSize The amount of data to sent (defaults to KBufferLength)
 * @return system wide error code
 * @note there is no address parameter, the socket must already be connected
 */
{
	TInt err;

	err = SendTcpData(sock);
	if (err != KErrNone)
		return err;

	err = RecvTcpData(sock);

	return err;
}

TInt TE_RConnectionStep::NumberOfInterfacesL(RSocketServ& ss)
/**
 * Return a count of interfaces in this socket server.
 * Can be used even if this socket server has no open connections (because it 
 * temporarily opens one!).
 * @param ss - the interesting socket server to count in
 * @return number of interfaces, or it might leave
 */
{
	TInt err;
	RConnection conn;
	TUint numOfConnections;

	err = OpenConnection(conn, ss);
	TESTEL(KErrNone == err, err);
	CleanupClosePushL(conn);

	err = EnumerateConnections(conn, numOfConnections);
	TESTEL(KErrNone == err, err);

	CloseConnection(conn);
	CleanupStack::Pop();

	return numOfConnections;
}

TInt TE_RConnectionStep::TimeUntilRequestComplete(TRequestStatus& status, TTimeIntervalSeconds& timeElapsed)
/**
 * Wait for the status to change. Count how long it takes.
 * @param status - the status which we need to wait for it to change
 * @param timeElapsed - the time it took (in seconds)
 * @return system wide error code
 */
{
	TTime time1, time2;

	time1.HomeTime();

	User::WaitForRequest(status);
		
	time2.HomeTime();
	time2.SecondsFrom(time1, timeElapsed);

	return (status.Int());
}

TInt TE_RConnectionStep::RequestInterfaceDownL(RConnection& conn, RSocketServ& ss)
/**
 * Sends a special packet to the dummy nif telling it to signal that the interface is down
 * @param conn The connection to signal
 * @param ss The socket server that the connection is within
 * @return system wide error code
 */
{
	TInt err = KErrNone;
	TRequestStatus status;

	TBuf8<KBufferLength> buffer;

	RSocket sock;
	TInetAddr dest;

	err = OpenUdpSocketExplicitL(sock, ss, conn);
	TESTEL(KErrNone == err, err);
	CleanupClosePushL(sock);

	//err = sock.SetLocalPort(KDummyNifCmdPort);
	//TESTEL(KErrNone == err, err);

	dest.SetAddress(KDummyNifLocalAddressBase + 4);
	dest.SetPort(KDummyNifCmdPort);

	buffer.SetMax();
	buffer.FillZ();
	buffer[0] = (TUint8) KForceDisconnect;

	sock.SendTo(buffer, dest, 0, status);
	User::WaitForRequest(status);
	TESTEL(KErrNone == status.Int(), status.Int());

	buffer.Zero();
	// I expect some sort of response
	// this fails - possibly ok as the interface might have gone already??
	//sock.RecvFrom(buffer, dest, 0, status);
	//User::WaitForRequest(status);
	//TESTEL(KErrNone == status.Int(), status.Int());

	DestroyUdpSocket(sock);
	CleanupStack::Pop();

	return err;
}

TInt TE_RConnectionStep::RequestSetStausL(RConnection& conn, RSocketServ& ss, TSubConnectionUniqueId aSubConnId)
/**
 * Sends a special packet to the dummy nif allowing the setting of the connection progress
 * @param conn The connection to signal
 * @param ss The socket server that the connection is within
 * @return system wide error code
 */
{
	TInt err = KErrNone;
	TRequestStatus status;

	TBuf8<KBufferLength> buffer;

	RSocket sock;
	TInetAddr dest;

	err = OpenUdpSocketExplicitL(sock, ss, conn);
	TESTEL(KErrNone == err, err);
	CleanupClosePushL(sock);

	dest.SetAddress(KDummyNifLocalAddressBase + 4);
	dest.SetPort(KDummyNifCmdPort);

	buffer.SetMax();
	buffer.FillZ();
	buffer[0] = (TUint8) KForceFinishedSelection;
	buffer[1] = (TUint8) aSubConnId;
	
	sock.SendTo(buffer, dest, 0, status);
	User::WaitForRequest(status);
	TESTEL(KErrNone == status.Int(), status.Int());

	buffer.Zero();

	DestroyUdpSocket(sock);
	CleanupStack::Pop();

	return err;
}


TInt TE_RConnectionStep::WaitForAllInterfacesToCloseL(RSocketServ& ss, TTimeIntervalSeconds aMaxSecsToWait)
/*
 * Sit around waiting for all the interfaces to die (essentially poll every now 
 * and again until there are zero interfaces in this socket server left)
 * @param ss Socket Server session to use
 * @param aMaxSecsToWait maximum number of seconds to wait for the interface to come down.
 * @return system wide error code
 */
	{
	TInt err;
	TUint numOfConnections;
	TInt count = 0;
	const TInt KOneSecond = 1000000;

	RConnection conn;

	err = OpenConnection(conn, ss);
	TESTEL(KErrNone == err, err);
	CleanupClosePushL(conn);

	err = EnumerateConnections(conn, numOfConnections);
	TESTEL(KErrNone == err, err);

	while ((0 != numOfConnections) && (count < aMaxSecsToWait.Int()))
	{
		count++;
		User::After(KOneSecond); // wait a bit, a second sounds good
		err = EnumerateConnections(conn, numOfConnections);
	}

	CloseConnection(conn);
	CleanupStack::Pop();

	if (numOfConnections != 0)
		{
		return KErrTimedOut;
		}

	return KErrNone;
	}

void TE_RConnectionStep::PerformDummyStartAttachOperationsL(RSocketServ& ss, TPckgBuf<TConnectionInfo>& info)
/*
 * Do some attached and starts. One monitor, one normal and one actual interface.
 * Close in two different orders.
 * @param ss - the socket server to do this in
 * @param info - some info
 * @return system wide error code
 */
{
	TInt err;

	RConnection conn1, conn2, conn3;

	TInt count;

	for (count=0; count<2; count++)
	{
		// attach one as a monitor
		err = OpenConnection(conn1, ss);
		TESTEL(KErrNone == err, err);
		CleanupClosePushL(conn1);
		err = AttachMonitor(conn1, info);
		TESTEL(KErrNone == err, err);

		// attach one normally
		err = OpenConnection(conn2, ss);
		TESTEL(KErrNone == err, err);
		CleanupClosePushL(conn2);
		err = AttachNormal(conn2, info);
		TESTEL(KErrNone == err, err);

		// create an actual interface (maybe?)
		err = OpenConnection(conn3, ss);
		TESTEL(KErrNone == err, err);
		CleanupClosePushL(conn3);
		err = StartConnectionWithOverrides(conn3, iDummyNifIap);
		TESTEL(KErrNone == err, err);

		if (count == 0)
		{
			// On first time thru close the interfaces in reverse order
			CloseConnection(conn3);
			CleanupStack::Pop();
			CloseConnection(conn2);
			CleanupStack::Pop();
			CloseConnection(conn1);
			CleanupStack::Pop();
		}
		else
		{
			// Second time thru close in a different order (fwd order)
			CloseConnection(conn1);
			CleanupStack::Pop(3);
			CleanupClosePushL(conn3); // sneaky.... put them back on in the 
			CleanupClosePushL(conn2); // order that is easier for us below...
			CloseConnection(conn2);
			CleanupStack::Pop();
			CloseConnection(conn3);
			CleanupStack::Pop();
		}
	}
}

void TE_RConnectionStep::AllInterfaceNotification(RConnection& conn, TRequestStatus& status, TDes8& aNotification)
/**
 * Requests all interface notification
 * @param conn The connection to use to request notification
 * @param status Asynchronous status of the request
 * @param aNotification The descriptor which the notification is to be written into
 * @return nothing
 */
	{
	conn.AllInterfaceNotification(aNotification, status);
	}

void TE_RConnectionStep::CancelAllInterfaceNotificationL(RConnection& conn)
/**
 * Cancels outstanding request for all interface notification
 * @param conn The connection on which to cancel the request
 * @return nothing
 */
	{
	conn.CancelAllInterfaceNotification();
	}

void TE_RConnectionStep::CheckInterfaceNotificationL(TRequestStatus& status, TInterfaceNotificationBuf& info, TConnInterfaceState interfaceState, RConnection* sourceConnection)
/**
 * Checks for particular connection interface state
 * @param status Asynchronous status of request
 * @param info Buffer which info will be written into
 * @param interfaceState Also will be updated and then monitored
 * @param sourceConnection Connection which all this relates to
 * @return nothing
 */
	// checks for particular connection interface state
	{
	// wait for completion - to ensure that monitoring actually occurs
	User::WaitForRequest(status);

	// check request completed OK
	TESTEL(status.Int() == KErrNone, status.Int());

	// check connection state is as expected
	TESTEL(info().iState == interfaceState, info().iState);

	if(NULL != sourceConnection)
		{
		CheckConnectionInfoL(*sourceConnection,info().iConnectionInfo);
		}
	}

void TE_RConnectionStep::CheckConnectionInfoL(RConnection& connection, TConnectionInfo& info)
/**
 * Checks connection info with the expected
 * @param connection The connection all this relates to
 * @param info The info to compare with the actual settings for connection
 * @return nothing
 */
	{
	TInt err;
	TUint32 connIapId;
	TUint32 connNetId;

	// get settings for the connection
	err = connection.GetIntSetting(_L("IAP\\Id"), connIapId);
	TESTEL(err == KErrNone, err);
	err = connection.GetIntSetting(_L("IAP\\IAPNetwork"), connNetId);
	TESTEL(err == KErrNone, err);

	// check IAP Id matches
	TESTEL(info.iIapId == connIapId, info.iIapId);
	// check Network Id matches
	TESTEL(info.iNetId == connNetId, info.iNetId);
	}

TInt TE_RConnectionStep::EnumerateClients(RConnection& aConn, TUint aIndex, TUint& aCount)
/*
 * Count how many clients there are
 * @param aConn The connection to use to enumerate the clients
 * @param aIndex The index to use
 * @param aCount The count of how many clients there are
 * @return system wide error code
 */
	{

	TInt err(KErrNone);

	TConnEnumArgBuf args;
	args().iIndex = aIndex;
	err = aConn.Control(KCOLConnection, KCoEnumerateConnectionClients, args);
	aCount = args().iCount;
	
	return err;
	}

TInt TE_RConnectionStep::GetConnectionClientInfo(RConnection& aConn, TUint aIndex, TConnectionClientInfo& aClientInfo)
/**
 * Get the information about a client
 * @param aConn The connection to use
 * @param aIndex The index to use
 * @param aClientInfo Where to write the information to
 * @return system wide error code
 */
	{

	TInt err(KErrNone);

	TConnGetClientInfoArgBuf args;
	args().iIndex = aIndex;
	err = aConn.Control(KCOLConnection, KCoGetConnectionClientInfo, args);
	aClientInfo = args().iClientInfo;

	return err;
	}

TInt TE_RConnectionStep::EnumerateSockets(RConnection& aConn, TUint aIndex, TUint& aCount)
/**
 * Count how many sockets there are
 * @param aConn The connection to use
 * @param aIndex The index to use
 * @param aCount The count of how many sockets there are
 * @return system wide error code
 */
	{

	TInt err(KErrNone);

	TConnEnumArgBuf args;
	args().iIndex = aIndex;
	err = aConn.Control(KCOLConnection, KCoEnumerateConnectionSockets, args);
	aCount = args().iCount;

	return err;
	}

TInt TE_RConnectionStep::GetConnectionSocketInfo(RConnection& aConn, TUint aIndex, TConnectionSocketInfo& aSocketInfo)
/**
 * Get the information about a socket
 * @param aConn The connection to use
 * @param aIndex The index to use
 * @param aSocketInfo Where to write the information to
 * @return system wide error code
 */
	{

	TInt err(KErrNone);

	TConnGetSocketInfoArgBuf args;
	args().iIndex = aIndex;
	err = aConn.Control(KCOLConnection, KCoGetConnectionSocketInfo, args);
	aSocketInfo = args().iSocketInfo;

	return err;
	}
	
TInt TE_RConnectionStep::LoadNapt(RSocket& aNaptsock,RSocket& aTestServSock, RSocketServ& aSockServer)
/**
 * Load Napt.Provide TInterfaceLockInfo information 
 * @param naptsock - the napt socket to open
 * @param ss - the socket server
 * @param testServSock - socket connected to test server
 * @return system wide error code
 */
	{
	const TInt netMaskLength   = 8;
    TInt err(KErrNone);
     	
    err = aNaptsock.Open(aSockServer,_L("napt"));
    if(err != KErrNone)
    	{
      	INFO_PRINTF2(_L("Load NAPT failed with error: %d."),err);
      	return err;
		}
            
    _LIT(KInterfaceName,"ipcp::comm");
    _LIT(KInterfaceName1,"eth");
    TUint32 testaddr = GetInterfaceAddress(aTestServSock,KInterfaceName());
     	     
    TPckgBuf <TInterfaceLockInfo> info;    
	info().iPublicIap  = iNaptPublicIap;  
	info().iPrivateIap = iNaptPrivateIap;  
    TInetAddr::Cast	(info().iPrivateIp).SetV4MappedAddress(iNaptTestServAddr.Address()); 
    TInetAddr::Cast(info().iPublicIp).SetV4MappedAddress(testaddr) ; 
    info().iNetmaskLength = netMaskLength; 
    info().iIfIndex = GetInterfaceIndexL(aTestServSock, KInterfaceName1());
#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION	
 	info().iUplinkAccess = ETrue;
#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
    
	err = aNaptsock.SetOpt(KSoNaptSetup,KSolNapt,info);
	if(err != KErrNone)
    	{
      	INFO_PRINTF2(_L("Set Option for NAPT failed with error: %d."),err);
      	return err;
		} 
	return err;
	}

TInt TE_RConnectionStep::ProdQoSL(RConnection& aConn, RSocketServ& aSs)
/**
 * If you want to use the primary context on a NIF, GUQoS will drop the first packet you send (as it won't yet be aware of the primary). So call this method which sends a packet (thus prodding GUQoS into life).
 * @param aConn A connection to send the packet over (should really be an interface supporting multiple contexts!)
 * @param aSs A socket server within which the connection was created
 * @return system wide error code
 */
{
	TInt err;
	RSocket sock;

	err = OpenUdpSocketExplicitL(sock, aSs, aConn);
	TESTEL(KErrNone == err, err);

	err = SendUdpData(sock, iEchoServerAddr, KSmallBufferLength);
	TESTEL(KErrNone == err, err);
	CleanupClosePushL(sock);

	DestroyUdpSocket(sock);
	CleanupStack::Pop(&sock);

	User::After(KOneSecondDelay);

	return err; // will always be KErrNone if we reach here
}

/**
 * Waits idefinitely until a relevant (specified) progress notification is received. 
 * All other progress notifications are ignored.
 * On return, aProgress contains the requested progress.
 * @param aConn A connection to wait on for a progress.
 * @param aStatus progress notification request status.
 * @param aProgress a buffer for the relevant progress.
 * @param aRelevantProgress a progress to wait for.
 */
void TE_RConnectionStep::WaitForRelevantProgress(RConnection& aConn, TNifProgressBuf& aProgress, TInt aRelevantProgress)
	{
	TRequestStatus reqStatus;
		
	for(;;) // WINS compiler generates a warning if while(ETrue) is used.
		{
		aConn.ProgressNotification(aProgress, reqStatus);
		User::WaitForRequest(reqStatus);				
		if(aRelevantProgress == aProgress().iStage)
			{	
			break;			
			}
		}
	}
	
TUint32 TE_RConnectionStep::GetInterfaceAddress(RSocket& sock,const TDesC& aFName)
/**
 * Get interface gloabal Ip Address
 * @param sock - socket connection
 * @param aFName - interface name
 * @return Ip address
 */
{ 
	TName address;
	TBool isSiteLocal,isLinkLocal;
	TInt retVal = -1;
	
	TPckgBuf<TSoInetInterfaceInfo> info; 
	 
 	retVal = sock.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
 	TESTEL(retVal == KErrNone, retVal);
 	
    retVal = sock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info);
    TESTEL(retVal == KErrNone, retVal);
            
   	while(retVal==KErrNone)
		 {
	 	 info().iAddress.Output(address);
				
		 isSiteLocal = info().iAddress.IsSiteLocal();	
		 isLinkLocal = info().iAddress.IsLinkLocal();
	
		 TInt str = info().iName.Find(aFName);
		 if((str == KErrNone) && (isSiteLocal == EFalse) && (isLinkLocal == EFalse))
		    {
	         INFO_PRINTF2(_L("Interface address obtained: %S."),&address);
		     break;
			}
		  
		  retVal = sock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info);
	      }

	return info().iAddress.Address();
}

TUint32 TE_RConnectionStep::GetInterfaceIndexL(RSocket& sock,const TDesC& aFName)
/**
 * Get interface index
 * @param sock - socket connection
 * @param aFName - interface name
 * @return Interface index
 */
{ 
    TPckgBuf<TSoInetInterfaceInfo> interfaceInfo; 
    TPckgBuf<TSoInetIfQuery> queryInfo;
    
    TName address;
    TInt retVal = KErrNotFound;

    retVal = sock.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
    TESTEL(retVal == KErrNone, retVal);
    
    retVal = sock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, interfaceInfo);
    TESTEL(retVal == KErrNone, retVal);
            
    while(retVal==KErrNone)
         {
         TInt str = interfaceInfo().iName.Find(aFName);
         if(str == KErrNone)
            {
            queryInfo().iName = interfaceInfo().iName;
            break;
            }
          retVal = sock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, interfaceInfo);
          }
    TESTEL(retVal == KErrNone, retVal);
    
    retVal = sock.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, queryInfo);
    TESTEL(retVal == KErrNone, retVal);
    
    return queryInfo().iIndex;
}



/*
 * Now the stuff for the peculiar tests that need to use QoS
 */

TE_RConnectionQoSStep::TE_RConnectionQoSStep() : TE_RConnectionStep()
/**
 * Constructor for TE_RConnectionQoSStep, an abstract class derived from by any steps dealing with QoS. Must use two phase construction.
 */
{
}

void TE_RConnectionQoSStep::Log( TRefByValue<const TDesC16> format, ... )
	{
	VA_LIST aList;
	VA_START( aList, format );

	// decode formated data for display on console
	TBuf <MAX_LOG_LINE_LENGTH> LineBuf;
	LineBuf.AppendFormatList( format, aList );

	INFO_PRINTF1(LineBuf);

	VA_END( aList ); 
	}





TE_RConnectionQoSStep::TS_QosChannel::TS_QosChannel(TE_RConnectionQoSStep& aTestStep)
:iTestStep(aTestStep)
/**
 * Constructor for TE_RConnectionQoSStep, an abstract class derived from by any steps dealing with QoS. Must use two phase construction.
 */
{
}


TE_RConnectionQoSStep::TS_QosChannel::~TS_QosChannel()
/**
 * Destructor for ~TS_QosChannel
 */
{
}

void TE_RConnectionQoSStep::TS_QosChannel::ConstructL()
/**
 * Second phase constructor for TE_RConnectionQoSStep derived classes.
 * @param none
 * @return nothing
 */
{
}


TInt TE_RConnectionQoSStep::TS_QosChannel::Open(RSocketServ& aServer, RConnection& aConnection)
{
	return iChannel.Open(aServer, RSubConnection::ECreateNew, aConnection);
}


TInt TE_RConnectionQoSStep::TS_QosChannel::Add(RSocket aSocket)
{
	TRequestStatus subconnReqStat;
	iChannel.Add(aSocket, subconnReqStat);
	User::WaitForRequest(subconnReqStat);
	return subconnReqStat.Int();
}

TInt TE_RConnectionQoSStep::TS_QosChannel::Close()
{
	iChannel.Close();
	REComSession::FinalClose();
	return KErrNone;
}

TInt TE_RConnectionQoSStep::TS_QosChannel::SetQoSParametersL()
/**
 * Set up a standard set of QoS parameters to be used by derived classes
 * @param aParameters Where to write the standard parameters to
 * @return system wide error code
 */
{
	TInt err = KErrNone;
	//------------------------------------
	//1. Initialise QoS params structure;
	//------------------------------------
	//create a container for QoS sub connection parameters (Param bundle takes ownership)
	RSubConParameterBundle subconnParams;
	CleanupClosePushL(subconnParams);

	CSubConParameterFamily* family = CSubConParameterFamily::NewL(subconnParams, KSubConQoSFamily);

	//create the generic set
	CSubConQosGenericParamSet* subConQosGenParSet = CSubConQosGenericParamSet::NewL(*family, CSubConParameterFamily::ERequested);
	
	//Qos mapping extracted from ipcpr.cpp MapGenericParamsFromESockToPRTL(...)

	//1. TokenRateUplink
	//NO MAPPING for subConQosGenParSet->SetTokenRateUplink(1024);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetTokenRateUplink(TUint32 aRate);

	//2. TokenBucketSizeUplink
	//Mapping based on:
	//	TInt uplinkBandwidth = generic->GetUplinkBandwidth();
	//  params.SetTokenBucketSizeUplink((TUint32)uplinkBandwidth);
	subConQosGenParSet->SetUplinkBandwidth(896);
	
	//3. MaxTransferRateUplink
	//Mapping based on:
	//  TInt upLinkMaximumBurstSize = generic->GetUpLinkMaximumBurstSize();
	//  params.SetMaxTransferRateUplink((TUint32)upLinkMaximumBurstSize);
	subConQosGenParSet->SetUpLinkMaximumBurstSize(1024);
	
	//4. MaxPacketSizeUplink
	//Mapping based on:
	//	TInt upLinkMaximumPacketSize = generic->GetUpLinkMaximumPacketSize();
	//	params.SetMaxPacketSizeUplink((TUint32)upLinkMaximumPacketSize);
	subConQosGenParSet->SetUpLinkMaximumPacketSize(735);
	
	//5. MinPolicedUnitUplink
	//Mapping based on:
	//	TInt upLinkDelayVariation = generic->GetUpLinkDelayVariation();
	//	params.SetMinPolicedUnitUplink((TUint32)upLinkDelayVariation);
	subConQosGenParSet->SetUpLinkDelayVariation(0);
	
	//6. DelayUplink
	//Mapping based on:
	//	TInt upLinkDelay = generic->GetUpLinkDelay();
	//	params.SetDelayUplink((TUint32)upLinkDelay);
	subConQosGenParSet->SetUpLinkDelay(0);

	//7. PriorityUplink
	//Mapping based on:
	//	TInt upLinkPriority = generic->GetUpLinkPriority();
	//	params.SetPriorityUplink((TUint16)upLinkPriority);
	subConQosGenParSet->SetUpLinkPriority(3);
	
	//8. DropModeUplink
	//NO MAPPING for subConQosGenParSet->SetDropModeUplink(KPfqosDropTail);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetDropModeUplink(TUint8 aDropMode);

	//9. TokenRateDownlink
	//NO MAPPING for subConQosGenParSet->SetTokenRateDownlink(1024);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetTokenRateDownlink(TUint32 aRate);
	
	//10. TokenBucketSizeDownlink
	//Mapping based on:
	//	TInt downlinkBandwidth = generic->GetDownlinkBandwidth();
	//	params.SetTokenBucketSizeDownlink((TUint32)downlinkBandwidth);
	subConQosGenParSet->SetDownlinkBandwidth(768);
	
	//11. MaxTransferRateDownlink
	//Mapping based on:
	//	TInt downLinkMaximumBurstSize = generic->GetDownLinkMaximumBurstSize();
	//	params.SetMaxTransferRateDownlink((TUint32)downLinkMaximumBurstSize);
	subConQosGenParSet->SetDownLinkMaximumBurstSize(1024);
	
	//12. MaxPacketSizeDownlink
	//Mapping based on:
	//	TInt downLinkMaximumPacketSize = generic->GetDownLinkMaximumPacketSize();
	//	params.SetMaxPacketSizeDownlink((TUint32)downLinkMaximumPacketSize);
	subConQosGenParSet->SetDownLinkMaximumPacketSize(512);
	
	//13. MinPolicedUnitDownlink
	//Mapping based on:
	//	TInt downLinkDelayVariation = generic->GetDownLinkDelayVariation();
	//	params.SetMinPolicedUnitDownlink((TUint32)downLinkDelayVariation);
	subConQosGenParSet->SetDownLinkDelayVariation(300);
	
	//14. DelayDownlink
	//Mapping based on:
	//	TInt downLinkDelay = generic->GetDownLinkDelay();
	//	params.SetDelayDownlink((TUint32)downLinkDelay);
	subConQosGenParSet->SetDownLinkDelay(200);
	
	//15. PriorityDownlink
	//Mapping based on:
	//	TInt downLinkPriority = generic->GetDownLinkPriority();
	//	params.SetPriorityDownlink((TUint16)downLinkPriority);
	subConQosGenParSet->SetDownLinkPriority(128);
	
	//16. DropModeDownlink
	//NO MAPPING for subConQosGenParSet->SetDropModeDownlink(KPfqosDropTail);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetDropModeDownlink(TUint8 aDropMode);
	
	//17. AdaptationPriority
	//NO MAPPING for subConQosGenParSet->SetAdaptationPriority(KQoSLowestPriority);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetAdaptationPriority(TUint8 aPriority);
	
	//17. AdaptationPriority
	//NO MAPPING for subConQosGenParSet->SetAdaptMode(EFalse);
	//mapping commented out from MapGenericParamsFromESockToPRTL:
	//params.SetAdaptMode(TBool aCanAdapt);
	
	//------------------------------------
	//2. Subscribe for QoS Params notification
	//------------------------------------
	TNotificationEventBuf subconnNotifBuf;
	TRequestStatus subconnReqStat;
	RSubConnection::TEventFilter subconnEventFilter(
				    KSubConnGenericEventsImplUid,
				    KSubConGenericEventParamsGranted | 
				    KSubConGenericEventParamsChanged |
				    KSubConGenericEventParamsRejected );
	iChannel.EventNotification(subconnNotifBuf, 
				&subconnEventFilter, 1, subconnReqStat);

	//------------------------------------
	//3. Set the QoS Parameters
	//------------------------------------
	User::LeaveIfError(iChannel.SetParameters(subconnParams));

	//------------------------------------
	//4. Receive & Process the event (expecting KSubConGenericEventParamsGranted)
	//------------------------------------
	User::WaitForRequest(subconnReqStat);
	User::LeaveIfError(subconnReqStat.Int());

	
	switch (subconnNotifBuf.Id())
	{
	case KSubConGenericEventParamsGranted:
			iTestStep.Log(_L("CSubConGenericEventParamsGranted received"));
			break;
		case KSubConGenericEventParamsChanged:
			iTestStep.Log(_L("CSubConGenericEventParamsChanged received"));
			break;
		case KSubConGenericEventParamsRejected:
			iTestStep.Log(_L("CSubConGenericEventParamsRejected received"));
			err = KErrNotSupported;
			break;
		default:
			iTestStep.Log(_L("unknown event received.  Id=%d"),subconnNotifBuf.Id());
			err = KErrNotSupported;
			break;
	}

	subconnParams.Close();
	CleanupStack::Pop(&subconnParams);

	return err;
}

 
CStatus::CStatus():CActive(0)
{
	CActiveScheduler::Add(this);
	SetActive();
}

CStatus::~CStatus()
{
	Cancel();
}

TInt TE_RConnectionSimTsyDataStep::NTRasThreadFunction(TAny* /*aThreadData*/)
	{
	_LIT(KCsyName,"LOOPBACK.CSY");
	_LIT(KPortName,"LOOPBACK::1");
	_LIT8(KServerText,"SERVER");

	CTrapCleanup* cleanup = CTrapCleanup::New();
	if (!cleanup)
		{
		return KErrNoMemory;
		}

	RCommServ commServ;
	TInt ret = commServ.Connect();
	if (KErrNone != ret)
		{
		return ret;
		}
	
	ret = commServ.LoadCommModule(KCsyName);
	if(KErrNone == ret)
		{
		RComm comm;
		ret = comm.Open(commServ, KPortName, ECommShared);
		if(KErrNone == ret)
			{
			TBuf8<6> readBuf;
			TRequestStatus stat0;
			comm.Read(stat0, readBuf);
			User::WaitForRequest(stat0);

			comm.Write(stat0, KServerText);
			User::WaitForRequest(stat0);
			}
		comm.Close();
		}
	commServ.Close();
	delete cleanup;
	return ret;
	}

TInt TE_RConnectionSimTsyDataStep::StartNTRasSimulation()
	{
	const TInt KStackSize=0x8000;
	const TInt KHeapSize=0x8000;
	const TInt KMaxHeapSize=0x80000;
	TInt res = KErrNone ;
	_LIT(KNtRasName,"NTRasEmulation");

	RThread t;
	res=t.Create(KNtRasName, NTRasThreadFunction,
					KStackSize,KHeapSize,KMaxHeapSize,NULL);
	t.Resume();
	t.Close();

	return res;
	}

enum TVerdict TE_RConnectionSimTsyDataStep::doTestStepPreambleL()
	{
	_LIT(KPhbkSyncCMI, "phbsync.cmi");
	if (StartC32WithCMISuppressions(KPhbkSyncCMI) != KErrNone)
    	{
    	return EFail;
    	}
				
	// Wait for all of the interfaces to close down		 
	RSocketServ ss;		
	User::LeaveIfError(ss.Connect());
	CleanupClosePushL(ss);

	if (KErrNone != WaitForAllInterfacesToCloseL(ss))
		{
		INFO_PRINTF1(_L("Previous test case has left connections up that have not closed. Stopping them."));
		TBuf<200> errDesc;
		TInt err;
		if ((err = ESockTestUtils::StopAllInterfaces(errDesc)) != KErrNone)
			{
			INFO_PRINTF3(_L("StopAllInterfaces() err=%d\n%S"), err, &errDesc);
			CleanupStack::PopAndDestroy(&ss);
			return EFail;
			}			
		}	
	CleanupStack::PopAndDestroy(&ss);	
	
	TInt ret = RProperty::Set(KUidPSSimTsyCategory, KPSSimTsyTestNumber, 0);
	if (ret != KErrNone)
		{
		INFO_PRINTF1(_L("Failed resetting"));
		User::Leave(ret);
		}

	ret = iTelServer.Connect();
	if (ret!=KErrNone)
		{
		INFO_PRINTF1(_L("Failed to connect to telephony server"));
		User::Leave(ret);
		}
	
   	ret=iTelServer.LoadPhoneModule(KSimtsyName);
	if (ret!=KErrNone)
		{
		INFO_PRINTF1(_L("Failed to load phone module"));
		iTelServer.Close();
		User::Leave(ret);
		}

	ret=iPhone.Open(iTelServer,KPhoneName) ;
	if (ret!=KErrNone)
		{
		INFO_PRINTF1(_L("Failed to open phone module"));
		iTelServer.UnloadPhoneModule(KSimtsyName);
		iTelServer.Close();
		User::Leave(ret);
		}
	ret=iPhone.Initialise();
	if (ret!=KErrNone)
		{
		INFO_PRINTF1(_L("Failed to initialise the phone"));
		iPhone.Close();
		iTelServer.UnloadPhoneModule(KSimtsyName);
		iTelServer.Close();
		User::Leave(ret);
		}

	RPhone::TCaps phoneCaps;
	ret = iPhone.GetCaps(phoneCaps) ;
	if ((KErrNone != ret) || !(phoneCaps.iFlags & RPhone::KCapsData))
		{
		INFO_PRINTF2(_L("This phone does not support data calls (caps=0x%x)"), phoneCaps.iFlags);
		iPhone.Close();
		iTelServer.UnloadPhoneModule(KSimtsyName);
		iTelServer.Close();
		User::Leave(ret);
		}

	return TestStepResult();
	}

enum TVerdict TE_RConnectionSimTsyDataStep::doTestStepPostambleL()
	{
	REComSession::FinalClose();
	iPhone.Close();
	iTelServer.UnloadPhoneModule(KSimtsyName);
	iTelServer.Close();

	__UHEAP_MARKEND;
	return TestStepResult();	
	}

