datacommsserver/esockserver/test/TE_ESockSSA/src/TestStepESockSSA.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/test/TE_ESockSSA/src/TestStepESockSSA.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,400 @@
+// Copyright (c) 2005-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:
+//
+
+// EPOC includes
+#include <e32base.h>
+#include <e32property.h>
+#include <es_sock.h>
+#include <in_sock.h>
+#include <c32root.h>
+
+// Test system includes
+#include "TestStepESockSSA.h"
+#include "blocker.h"
+#include "ES_DUMMY.H"
+
+
+RMultipleWait::RMultipleWait(TInt aInitialCount)
+: iCount(aInitialCount)
+	{
+	iOwnerThread.Open(RThread().Id());
+	}
+	
+void RMultipleWait::Close()
+	{
+	iOwnerThread.Close();
+	inherited::Close();
+	}
+	
+void RMultipleWait::Signal(TInt aDelta)
+	{
+	inherited::Wait();
+	iCount += aDelta;
+	iOwnerThread.RequestSignal();
+	inherited::Signal();
+	}
+	
+void RMultipleWait::Wait()
+	{
+	while(iCount < 0)
+		{
+		User::WaitForAnyRequest();
+		}
+	inherited::Wait();
+	--iCount;
+	inherited::Signal();
+	}
+
+CTestStepESockSSA::CTestStepESockSSA()
+	{
+	}
+
+CTestStepESockSSA::~CTestStepESockSSA()
+	{
+	}
+
+void CTestStepESockSSA::SetDummyBlocking()
+	{
+	// Set the blocking state, so that when the blocking module is loaded it will block
+	TSecurityPolicy nullPolicy(ECapability_None);
+	TInt err = RProperty::Define(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, RProperty::EInt, nullPolicy, nullPolicy);
+	if(err == KErrNone || err == KErrAlreadyExists)
+		{
+		RProperty::Set(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, CBlockerChannelHandler::EStateBlock);
+		}
+	}
+
+void CTestStepESockSSA::ClearDummyBlocking()
+	{
+	// Set the blocking state, so that when the blocking module is loaded it will block
+	TSecurityPolicy nullPolicy(ECapability_None);
+	TInt err = RProperty::Define(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, RProperty::EInt, nullPolicy, nullPolicy);
+	if(err == KErrNone || err == KErrAlreadyExists)
+		{
+		RProperty::Set(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, CBlockerChannelHandler::EStateRelease);
+		}
+	}
+
+void CTestStepESockSSA::DoDataThreadL(TDataThreadControl& aControl)
+	{
+	User::LeaveIfError(aControl.iSession.Connect());
+
+	// Wait for blocker to start blocking; we can then create an IP socket as it will have already loaded
+	RProperty blockProp;
+	TInt err = blockProp.Attach(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey);
+	if(err == KErrNone)
+		{
+		TRequestStatus status;
+		do
+			{
+			blockProp.Subscribe(status);
+			TInt blockState;
+			err = blockProp.Get(blockState);
+			if(err != KErrNone || blockState >= CBlockerChannelHandler::EStateBlocking)
+				{
+				blockProp.Cancel();
+				}
+			User::WaitForRequest(status);
+			} while(status == KErrNone);
+		blockProp.Close();
+		}
+	
+	switch(aControl.iRequest)
+		{
+	case TDataThreadControl::ESocketOpen:
+		{
+		RSocket sock;
+		User::LeaveIfError(sock.Open(aControl.iSession, KAfInet, KSockDatagram, KProtocolInetUdp));
+		sock.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = sock.Open(aControl.iSession, KDummyOneName);		// should block
+		sock.Close();
+		break;
+		}
+	case TDataThreadControl::EHostResolverOpen:
+		{
+		RHostResolver hr;
+		hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp);
+		hr.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = hr.Open(aControl.iSession, KDummyAddrFamily, KDummyOne);		// should block
+		hr.Close();
+		break;
+		}
+	case TDataThreadControl::EHostResolverOpenMulti:
+		{
+		RHostResolver hr;
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = hr.Open(aControl.iSession, KDummyAddrFamily, KDummyOne);		// should block
+		hr.Close();
+		break;
+		}
+	case TDataThreadControl::EServiceResolverOpen:
+		{
+		RServiceResolver sr;
+		sr.Open(aControl.iSession, KAfInet, KSockDatagram, KProtocolInetUdp);
+		sr.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = sr.Open(aControl.iSession, KDummyAddrFamily, KSockDatagram, KDummyOne);		// should block
+		sr.Close();
+		break;
+		}
+	case TDataThreadControl::ENetDBOpen:
+		{
+		RNetDatabase ndb;
+		ndb.Open(aControl.iSession, KAfInet, KProtocolInetUdp);
+		ndb.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = ndb.Open(aControl.iSession, KDummyAddrFamily, KDummyOne);		// should block
+		ndb.Close();
+		break;
+		}
+	case TDataThreadControl::ENumProtocols:
+		{
+		TUint numOfProtocols;
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = aControl.iSession.NumProtocols(numOfProtocols);		// should block
+		break;
+		}
+	case TDataThreadControl::EGetProtocolInfo:
+		{
+		TUint absentIndex = 99;
+		TProtocolDesc protocolDesc;
+		RHostResolver hr;
+		hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp);
+		hr.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = aControl.iSession.GetProtocolInfo(absentIndex, protocolDesc);		// should block
+		break;
+		}
+	case TDataThreadControl::EFindProtocol:
+		{
+		_LIT(KAbsentProtocolName,"NoSuchProtocol");
+		TProtocolDesc protocolDesc;
+		RHostResolver hr;
+		hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp);
+		hr.Close();
+		aControl.iBlocked = ETrue;
+		aControl.iBlockSemaphore.Signal(1);
+		aControl.iResult = aControl.iSession.FindProtocol(KAbsentProtocolName(), protocolDesc);		// should block
+		break;
+		}
+	default:
+		ASSERT(0);
+		}
+	}
+
+TInt CTestStepESockSSA::DataThreadEntry(TDataThreadControl& aControl)
+	{
+	CTrapCleanup* cleanupStack = CTrapCleanup::New();
+	if(!cleanupStack)
+		{
+		return KErrNoMemory;
+		}
+	TRAPD(err, DoDataThreadL(aControl));
+	// Signal that the thread is exiting. If we got here by a Leave() we still need to signal the control thread
+	aControl.iBlockSemaphore.Signal(1);
+
+	delete cleanupStack;
+	return err;
+	}
+
+TInt CTestStepESockSSA::CreateDataThread(TDataThreadControl::TRequestType aRequest, TDataThreadControl& aControl)
+	{
+	aControl.iRequest = aRequest;
+	aControl.iResult = KRequestPending;
+	aControl.iBlocked = EFalse;
+	return aControl.iThread.Create(KNullDesC, reinterpret_cast<TThreadFunction>(CTestStepESockSSA::DataThreadEntry), 8192, NULL, &aControl);
+	}
+
+TVerdict CTestStepESockSSA::WaitForDataThreadsToBlock(TDataThreadControl* aThreads, TInt aNumThreads)
+	{
+	TVerdict verdict = EPass;
+	Logger().WriteFormat(_L("Resuming %d data thread(s) & waiting for blocking"), aNumThreads);
+	for(TInt i = 0; i < aNumThreads; ++i)
+		{
+		aThreads[i].iThread.Resume();
+		User::After(1000000);
+		Logger().WriteFormat(_L("Data thread: #%d %d %d"), i, aThreads[i].iThread.ExitReason(), aThreads[i].iBlocked);
+		}
+	
+	aThreads[0].iBlockSemaphore.Wait();	// blocks until all data threads signal. If it hangs forever then check if one died
+	User::After(KBlockedRequestIssueDelay);
+	// Check whether all data threads have blocked
+	for(TInt i = 0; i < aNumThreads; ++i)
+		{
+		if(!aThreads[i].iBlocked)
+			{
+			Logger().WriteFormat(_L("ERROR: Data thread #%d never got to block"), i);
+			verdict =  EFail;
+			}
+		else if(aThreads[i].iResult != KRequestPending)
+			{
+			Logger().WriteFormat(_L("ERROR: Data thread #%d went past block with %d"), i, aThreads[i].iResult);
+			verdict = EFail;
+			}
+		}
+	return verdict;
+	}
+
+TVerdict CTestStepESockSSA::WaitForDataThreadsToComplete(TDataThreadControl* aThreads, TInt aNumThreads)
+	{
+	TVerdict verdict = EPass;
+	Logger().WriteFormat(_L("Resuming ESOCK boot & waiting for %d data thread(s) to complete"), aNumThreads);
+	aThreads[0].iBlockSemaphore.Signal(- aNumThreads + 1);
+	ClearDummyBlocking();
+	aThreads[0].iBlockSemaphore.Wait();	// blocks until all data threads signal. If it hangs forever then check if one died
+
+	User::After(KBlockedRequestCompletionDelay);
+	// Check whether all data threads completed their requests properly
+	for(TInt i = 0; i < aNumThreads; ++i)
+		{
+		if(aThreads[i].iResult != aThreads[i].iExpectedResult)
+			{
+			Logger().WriteFormat(_L("ERROR: Data thread #%d completed with %d, expected %d"), i, aThreads[i].iResult, aThreads[i].iExpectedResult);
+			verdict = EFail;
+			}
+		}
+	return verdict;
+	}
+
+void CTestStepESockSSA::UnloadBlockerL()
+	{
+	// Unload the blocker module if it's there
+	Logger().WriteFormat(_L("Unloading blocker module"));
+	TAutoClose<RRootServ> rootserver;
+	User::LeaveIfError(rootserver.iObj.Connect());
+	rootserver.PushL();
+	TRequestStatus status;
+	TCFModuleName blockerName(KBlockerCPMName);
+	rootserver.iObj.UnloadCpm(status, blockerName, EGraceful);
+	User::WaitForRequest(status);
+	rootserver.Pop();
+	Logger().WriteFormat(_L("Request completed with %d"), status.Int());
+	}
+
+void CTestStepESockSSA::KillC32Start()
+	{
+	// Start by looking for the running configurator and kill it if found. The caller
+	// needs the appropriate capability to do this
+
+	RDebug::Printf("Finding existing configurator process.");	
+	_LIT(KC32StartName, "*");
+	TInt result;
+	TBool configuratorWasPresent;
+	TInt count = 0;
+	const TInt KMaxKillRetry = 10;
+	do 
+		{
+		configuratorWasPresent = EFalse;
+		TFullName fn;
+		TFindProcess fp(KC32StartName);
+		while(fp.Next(fn) == KErrNone)
+			{
+			RProcess proc;
+			result = proc.Open(fn);
+			if(result == KErrNone)
+				{
+				TUidType type = proc.Type();
+				if(type[2] == TUid::Uid(KUidC32StartProcess) && proc.ExitType() == EExitPending) 
+					{
+					// Kill the existing configurator process.
+					RDebug::Print(_L("Opened existing configurator process \"%S\""), &fn);
+					TRequestStatus status;
+					proc.Logon(status);
+					proc.Kill(KErrNone);
+					RDebug::Printf("Killed process.");
+					User::WaitForRequest(status);
+					TExitType exitType = proc.ExitType();
+					
+					// Create a timer in case some other entity holds an open handle on the
+					// configurator which prevents the kernel from destroying it.  We timeout
+					// after one second.
+					TAutoClose<RTimer> timer;
+					if(timer.iObj.CreateLocal() == KErrNone)
+						{
+						// Request destruction notification so we know when it is safe to start
+						// the process again.
+						TRequestStatus destructionStatus;
+						proc.NotifyDestruction(destructionStatus);
+						proc.Close();
+					
+						enum{ KProcessDestructionTimeout = 1000000 };
+  					
+						TRequestStatus timerStatus;
+						timer.iObj.After(timerStatus, KProcessDestructionTimeout);
+						
+						// Wait for the process to be destroyed or for the timeout.
+						User::WaitForRequest(destructionStatus, timerStatus);
+						if(timerStatus.Int() == KRequestPending)
+							{
+							timer.iObj.Cancel();
+							User::WaitForRequest(timerStatus);
+							}
+						else
+							{
+							User::CancelMiscNotifier(destructionStatus);
+							User::WaitForRequest(destructionStatus);
+			
+							RDebug::Printf("Existing configurator process has still not been destroyed after %f.0s", KProcessDestructionTimeout / 1000000.0);
+							}
+						}
+					else
+						{
+						proc.Close();
+						}
+						
+					RDebug::Printf("Process logon completed with %d, exitType %d", status.Int(), exitType);
+					configuratorWasPresent = ETrue;
+					}
+				else
+					{
+					proc.Close();	
+					}
+				}
+			}
+		} while(configuratorWasPresent && ++count < KMaxKillRetry);
+
+		if (count >= KMaxKillRetry)
+			{
+			RDebug::Printf("KillC32Start - Cannot kill the configurator process, we will try continue and hope all is well");
+			}
+		
+	// Restart the boot sequence from scratch - the configurator reads this.
+	RProperty::Set(KUidSystemCategory, KUidC32StartPropertyKey.iUid, EReset);
+	}
+
+TVerdict CTestStepESockSSA::doTestStepPreambleL()
+	{
+	SetDummyBlocking();
+	RProperty ::Set(KUidSystemCategory, KUidC32StartPropertyKey.iUid, EReset);
+	UnloadBlockerL();
+	KillC32Start();
+	return EPass;
+	}
+
+TVerdict CTestStepESockSSA::doTestStepPostambleL()
+	{
+	UnloadBlockerL();
+	return EPass;
+	}
+