Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.
// 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 the License "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:
// e32test\system\t_svr_connect.cpp
// Overview:
// Tests correct operation of server when interleaving connect/disconnect/
// other messages and creating the user-side session object (setting the
// session cookie) in interesting manners.
// Tests that clients/servers are panicked when performing illegal operations
// w.r.t. server connection, i.e. a client thread may not send more than one
// connect message simultaneously, nor may it send another connect message
// once a connect message has been successfully completed. Similarly, a server
// may not set the cookie twice nor may it set the cookie to be NULL. Also, a
// server may only set the cookie from a connect message and from no other.
// API Information:
// RServer2
// Details:
// - Test asynchronous server connect in various ways. Verify results
// are as expected.
// - Test illegal client/server behaviour. Verify threads are panicked,
// as expected.
// Platforms/Drives/Compatibility:
// All.
// Assumptions/Requirement/Pre-requisites:
// None.
// Failures and causes:
// Failure of this test would be caused by an incorrect modification of
// the internal client/server mechanism in the kernel.
// Base Port information:
// This is a unit test of the client/server mechanism within the kernel.
// It should be invariant to base ports. If the kernel proper has not been
// modified, this test should not fail with any new base port.
//
//
#include <e32test.h>
#include "../misc/int_svr_calls.h"
#include <e32kpan.h>
_LIT(KTestName, "t_svr_connect");
LOCAL_D RTest test(KTestName);
LOCAL_D RTest test_client(KTestName);
LOCAL_D RTest test_server(KTestName);
_LIT(KServerName, "t_svr_connect");
_LIT8(KServerName8, "t_svr_connect");
_LIT(KMainThread, "main thread");
_LIT(KServerThread, "server thread");
_LIT(KClientThread, "client thread");
_LIT(KClientThread2, "client thread2");
_LIT(KClientThread3, "client thread3");
class RTestServer : public RSessionBase
{
public:
inline static TInt CreateSession(TInt aMsgSlots) { return SessionCreate(KServerName8,aMsgSlots,NULL,EIpcSession_Sharable); }
};
// Messages to send:
//
// connect, 1
// a.n.other, 2
// disconnect 3
//
// Things to do in the server:
//
// recieve connect 4
// set cookie 5
// complete connect 6
// receive a.n.other 7
// complete a.n.other 8
// receive disconnect 9
// complete disconnect 10
//
enum TMsgType
{
EConnect = -1,
EDisConnect = -2,
EANOther = 1,
EANOther2 = 2,
EMsgCount = 4
};
enum TServerControl
{
EReceiveMsg = 0,
EReceiveBlocked = 1,
EWaitForReceive = 2,
ESetCookie = 3,
ESetNullCookie = 4,
ECompleteMsg = 5,
EServerDie = 6
};
enum TClientControl
{
ESendMsg = 0,
EWaitMsg = 1,
ECreateSession = 2,
EClientDie = 3,
ESetCritical = 4
};
static TMsgType TheMsgType;
static TServerControl TheServerControl;
static TClientControl TheClientControl;
static RSemaphore ServerSemaphore;
static RSemaphore ClientSemaphore;
static RSemaphore TaskCompletionSemaphore;
static RMessage2 Msgs[EMsgCount];
static RServer2 Server;
static RThread ServerThread;
static RThread ClientThread;
static RTestServer ServerHandle;
static TRequestStatus ConnectStatus;
static TRequestStatus ANOtherStatus;
static TRequestStatus ANOther2Status;
static TRequestStatus ServerReceiveStatus;
static TInt TheNumberOfMsgSlots;
static TInt ErrorExpected;
static User::TCritical CriticalLevel;
static const TAny* const KSessionCookie = (const TAny*)0x12345;
static TRequestStatus* volatile KNullReference = 0;
void DoServerAction();
void DoClientAction();
TInt Index();
TInt TestThreadServer(TAny*)
{
test_server(Server.CreateGlobal(KServerName) == KErrNone);
RThread::Rendezvous(KErrNone);
for (;;)
{
ServerSemaphore.Wait();
DoServerAction();
TaskCompletionSemaphore.Signal();
}
}
TInt Index()
{
switch (TheMsgType)
{
case EConnect:
return 0;
case EDisConnect:
return 3;
case EANOther:
return 1;
case EANOther2:
return 2;
default:
return -1;
};
}
TRequestStatus& RequestStatus()
{
switch (TheMsgType)
{
case EConnect:
return ConnectStatus;
case EANOther:
return ANOtherStatus;
case EANOther2:
return ANOther2Status;
default:
User::Invariant();
};
return *(TRequestStatus*)KNullReference;
}
void DoServerAction()
{
switch (TheServerControl)
{
case EReceiveMsg:
{
RMessage2& msg = Msgs[Index()];
Server.Receive(msg);
test_server(msg.Function() == TheMsgType);
}
break;
case EReceiveBlocked:
{
RMessage2& msg = Msgs[Index()];
Server.Receive(msg, ServerReceiveStatus);
test_server(ServerReceiveStatus.Int() == KRequestPending);
}
break;
case EWaitForReceive:
{
User::WaitForRequest(ServerReceiveStatus);
test_server(ServerReceiveStatus.Int() == KErrNone);
test_server(Msgs[Index()].Function() == TheMsgType);
}
break;
case ESetCookie:
{
SetSessionPtr(Msgs[Index()].Handle(), KSessionCookie);
}
break;
case ESetNullCookie:
{
SetSessionPtr(Msgs[Index()].Handle(), NULL);
}
break;
case ECompleteMsg:
{
Msgs[Index()].Complete(KErrNone);
}
break;
case EServerDie:
{
User::Exit(0);
}
break;
default:
{
}
break;
};
}
void StartServer()
{
ServerThread.Create(KServerThread, TestThreadServer, KDefaultStackSize, 4096, 4096, NULL);
TRequestStatus started;
ServerThread.Rendezvous(started);
ServerThread.Resume();
User::WaitForRequest(started);
test(started.Int() == KErrNone);
}
void StopServer()
{
TRequestStatus logon;
ServerThread.Logon(logon);
TheServerControl = EServerDie;
ServerSemaphore.Signal();
User::WaitForRequest(logon);
test(logon.Int() == KErrNone);
CLOSE_AND_WAIT(ServerThread);
}
TInt TestThreadClient(TAny*)
{
RThread::Rendezvous(KErrNone);
for (;;)
{
ClientSemaphore.Wait();
DoClientAction();
TaskCompletionSemaphore.Signal();
}
}
void DoClientAction()
{
switch (TheClientControl)
{
case ESendMsg:
{
if (TheMsgType == EDisConnect)
ServerHandle.Close();
else
SessionSend(ServerHandle.Handle(), TheMsgType, NULL, &RequestStatus());
}
break;
case EWaitMsg:
{
User::WaitForRequest(RequestStatus());
}
break;
case ECreateSession:
{
TInt err = ServerHandle.SetReturnedHandle(RTestServer::CreateSession(TheNumberOfMsgSlots));
if (err != ErrorExpected)
{
test_client.Printf(_L("Error returned = %d\n"),err);
test_client(EFalse,__LINE__);
}
}
break;
case EClientDie:
{
User::SetCritical(User::ENotCritical);
User::Exit(0);
}
break;
case ESetCritical:
{
User::SetCritical(CriticalLevel);
break;
}
default:
{
}
break;
};
}
// I'm lazy and I haven't completed all the IPC the client thread does,
// so even when the client thread panics, the DObject is still kept alive
// until the server goes away. Therefore if I want another client I rename.
void StartClient(const TDesC& aName)
{
ClientThread.Create(aName, TestThreadClient, KDefaultStackSize, 4096, 4096, NULL);
TRequestStatus started;
ClientThread.Rendezvous(started);
ClientThread.Resume();
User::WaitForRequest(started);
test(started.Int() == KErrNone);
}
void StartClient()
{
StartClient(KClientThread);
}
void StopClient()
{
TRequestStatus logon;
ClientThread.Logon(logon);
TheClientControl = EClientDie;
ClientSemaphore.Signal();
User::WaitForRequest(logon);
test(logon.Int() == KErrNone);
CLOSE_AND_WAIT(ClientThread);
}
void CreateSemaphores()
{
TInt err = ServerSemaphore.CreateLocal(0);
test(err == KErrNone);
err = ClientSemaphore.CreateLocal(0);
test(err == KErrNone);
err = TaskCompletionSemaphore.CreateLocal(0);
test(err == KErrNone);
}
void CloseSemaphores()
{
ServerSemaphore.Close();
ClientSemaphore.Close();
TaskCompletionSemaphore.Close();
}
void CreateSession(TInt aErrorExpected=KErrNone, TInt aMsgSlots=-1)
{
TheClientControl = ECreateSession;
TheNumberOfMsgSlots = aMsgSlots;
ErrorExpected=aErrorExpected;
ClientSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void SendMsg(TMsgType aType)
{
TheClientControl = ESendMsg;
TheMsgType = aType;
ClientSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void SendMsg_NoWait(TMsgType aType)
{
TheClientControl = ESendMsg;
TheMsgType = aType;
ClientSemaphore.Signal();
}
void WaitMsg(TMsgType aType)
{
TheClientControl = EWaitMsg;
TheMsgType = aType;
ClientSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void ReceiveBlocked(TMsgType aType)
{
TheServerControl = EReceiveBlocked;
TheMsgType = aType;
ServerSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void WaitForReceive(TMsgType aType)
{
TheServerControl = EWaitForReceive;
TheMsgType = aType;
ServerSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void ReceiveMsg(TMsgType aType)
{
TheServerControl = EReceiveMsg;
TheMsgType = aType;
ServerSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void CompleteMsg(TMsgType aType)
{
TheServerControl = ECompleteMsg;
TheMsgType = aType;
ServerSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void SetCookie()
{
TheServerControl = ESetCookie;
TheMsgType = EConnect;
ServerSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void SetCookie_NoWait()
{
TheServerControl = ESetCookie;
TheMsgType = EConnect;
ServerSemaphore.Signal();
}
void SetNullCookie()
{
TheServerControl = ESetNullCookie;
TheMsgType = EConnect;
ServerSemaphore.Signal();
}
void SetBadCookie(TMsgType aType)
{
TheServerControl = ESetCookie;
test(aType != EConnect);
TheMsgType = aType;
ServerSemaphore.Signal();
}
void SetClientCritical(User::TCritical aCritical)
{
TheClientControl = ESetCritical;
CriticalLevel=aCritical;
ClientSemaphore.Signal();
TaskCompletionSemaphore.Wait();
}
void Test1()
{
test.Next(_L("Create session with test server"));
CreateSession();
test.Next(_L("Send connect message"));
SendMsg(EConnect);
test.Next(_L("Send A.N.Other message"));
SendMsg(EANOther);
test.Next(_L("Sending disconnect message"));
SendMsg(EDisConnect);
test.Next(_L("Receive A.N.Other message"));
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
test.Next(_L("Receive disconnect message"));
ReceiveMsg(EDisConnect);
test.Next(_L("Check the session has gone"));
test(Msgs[Index()].Session() == NULL);
test.Next(_L("Set up receive for next test"));
ReceiveBlocked(EConnect);
}
void Test2()
{
test.Next(_L("Create session with test server"));
CreateSession();
test.Next(_L("Send connect message"));
SendMsg(EConnect);
test.Next(_L("Send A.N.Other message"));
SendMsg(EANOther);
test.Next(_L("Receive connect message"));
WaitForReceive(EConnect);
test(Msgs[Index()].Session() == NULL);
test.Next(_L("Receive A.N.Other message"));
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
test.Next(_L("Sending disconnect message"));
SendMsg(EDisConnect);
test.Next(_L("Await disconnect message"));
ReceiveBlocked(EDisConnect);
test.Next(_L("Set cookie"));
SetCookie();
test.Next(_L("Check disconnect message received"));
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
test.Next(_L("Complete connect message"));
CompleteMsg(EConnect);
}
void Test2a()
{
CreateSession();
SendMsg(EConnect);
SendMsg(EANOther);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveBlocked(EDisConnect);
CompleteMsg(EConnect);
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == NULL);
}
void Test2b()
{
CreateSession();
SendMsg(EConnect);
SendMsg(EANOther);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test3()
{
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SendMsg(EANOther);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveBlocked(EDisConnect);
SetCookie();
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
CompleteMsg(EConnect);
}
void Test3a()
{
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SendMsg(EANOther);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveBlocked(EDisConnect);
CompleteMsg(EConnect);
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == NULL);
}
void Test3b()
{
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
SendMsg(EANOther);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test4()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
SendMsg(EANOther2);
SendMsg(EDisConnect);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == NULL);
}
void Test5()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
SendMsg(EANOther2);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == NULL);
ReceiveBlocked(EANOther);
}
void Test6()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
SendMsg(EANOther2);
WaitForReceive(EANOther);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveBlocked(EDisConnect);
SetCookie();
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
CompleteMsg(EConnect);
}
void Test6a()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
SendMsg(EANOther2);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == NULL);
SendMsg(EDisConnect);
ReceiveBlocked(EDisConnect);
CompleteMsg(EConnect);
WaitForReceive(EDisConnect);
test(Msgs[Index()].Session() == NULL);
}
void Test6b()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
SendMsg(EANOther2);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test7()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EANOther2);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test8()
{
CreateSession();
SendMsg(EANOther);
SendMsg(EConnect);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
SendMsg(EANOther2);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test9()
{
CreateSession();
SendMsg(EANOther);
ReceiveMsg(EANOther);
test(Msgs[Index()].Session() == NULL);
SendMsg(EConnect);
ReceiveMsg(EConnect);
test(Msgs[Index()].Session() == NULL);
SetCookie();
SendMsg(EANOther2);
ReceiveMsg(EANOther2);
test(Msgs[Index()].Session() == KSessionCookie);
SendMsg(EDisConnect);
ReceiveMsg(EDisConnect);
test(Msgs[Index()].Session() == KSessionCookie);
}
void Test10()
{
// Try connecting with too many message slots
// (Check for DEF091903 regression)
CreateSession(KErrArgument, 1000);
}
_LIT(KKernExec, "KERN-EXEC");
void CheckClientDeath(TInt aReason)
{
TRequestStatus logon;
ClientThread.Logon(logon);
User::WaitForRequest(logon);
test(ClientThread.ExitType() == EExitPanic);
test(ClientThread.ExitCategory() == KKernExec);
test(ClientThread.ExitReason() == aReason);
ClientThread.Close();
ClientThread.SetHandle(KNullHandle);
}
void CheckServerDeath(TInt aReason)
{
TRequestStatus logon;
ServerThread.Logon(logon);
User::WaitForRequest(logon);
test(ServerThread.ExitType() == EExitPanic);
test(ServerThread.ExitCategory() == KKernExec);
test(ServerThread.ExitReason() == aReason);
CLOSE_AND_WAIT(ServerThread);
ServerThread.SetHandle(KNullHandle);
}
void TestNaughty()
{
TBool jit = User::JustInTime();
User::SetJustInTime(EFalse);
SetClientCritical(User::ENotCritical);
test.Next(_L("Two connect msgs at once is naughty"));
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
SetCookie();
SendMsg_NoWait(EConnect);
CheckClientDeath(ERequestAlreadyPending);
StartClient(KClientThread2);
test.Next(_L("Another connect message after a sucessful connect msg is naughty"));
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
SetCookie();
CompleteMsg(EConnect);
SendMsg_NoWait(EConnect);
CheckClientDeath(ESessionAlreadyConnected);
StartClient(KClientThread3);
test.Next(_L("A null session cookie is naughty"));
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
SetNullCookie();
CheckServerDeath(ESessionNullCookie);
StartServer();
test.Next(_L("Setting the session cookie twice is naughty"));
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
SetCookie();
SetCookie_NoWait();
CheckServerDeath(ESessionCookieAlreadySet);
StartServer();
test.Next(_L("Trying to set the session cookie from a non-connect message is naughty"));
CreateSession();
SendMsg(EConnect);
ReceiveMsg(EConnect);
SendMsg(EANOther);
ReceiveMsg(EANOther);
SetBadCookie(EANOther);
CheckServerDeath(ESessionInvalidCookieMsg);
StartServer();
User::SetJustInTime(jit);
}
TInt E32Main()
{
User::RenameThread(KMainThread);
__UHEAP_MARK;
test.Title();
test.Start(_L("Creating semaphores"));
CreateSemaphores();
test.Next(_L("Starting test server"));
StartServer();
test.Next(_L("Starting test client"));
StartClient();
SetClientCritical(User::EProcessCritical);
// test combinations of receiving messages with messages sent by the client in the
// correct order (w.r.t to each other, but not necessarily to when messages are received)
test.Next(_L("Sending in order"));
test.Next(_L("1"));
Test1();
test.Next(_L("2"));
Test2();
test.Next(_L("2a"));
Test2a();
test.Next(_L("2b"));
Test2b();
test.Next(_L("3"));
Test3();
test.Next(_L("3a"));
Test3a();
test.Next(_L("3b"));
Test3b();
// test combinations of receiving messages with messages sent by the client in the
// wrong order (w.r.t to each other, but not necessarily to when messages are received)
test.Next(_L("Sending out of order"));
test.Next(_L("4"));
Test4();
test.Next(_L("5"));
Test5();
test.Next(_L("6"));
Test6();
test.Next(_L("6a"));
Test6a();
test.Next(_L("6b"));
Test6b();
test.Next(_L("7"));
Test7();
test.Next(_L("8"));
Test8();
test.Next(_L("9"));
Test9();
test.Next(_L("10"));
Test10();
test.Next(_L("Test other naughty behaviour is trapped"));
TestNaughty();
test.Next(_L("Stopping test client"));
StopClient();
test.Next(_L("Stopping test server"));
StopServer();
test.Next(_L("Closing semaphores"));
CloseSemaphores();
test.End();
test.Close();
__UHEAP_MARKEND;
return KErrNone;
}