mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
821 lines
21 KiB
821 lines
21 KiB
#include <bvtcmn.h>
|
|
|
|
ULONG GlobalCount = 0;
|
|
RPC_STATUS GlobalStatus = RPC_S_OK;
|
|
|
|
RPC_CLIENT_INTERFACE BVTClientInterfaceInfo =
|
|
{
|
|
sizeof(RPC_CLIENT_INTERFACE),
|
|
{{9,8,8,{0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7}},
|
|
{1,1}},
|
|
{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},
|
|
{2,0}},
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
typedef struct {
|
|
enum { INVALID = 0xBAD,
|
|
CALL = 0xBABE,
|
|
CALLNCALL = 0xBEEF,
|
|
CANCEL = 0xDEAD} Type;
|
|
ULONG Count;
|
|
ULONG Thread;
|
|
RPC_BINDING_HANDLE Handle;
|
|
} BVT_BLOCKING_CONTEXT;
|
|
|
|
RPC_BINDING_HANDLE GlobalBinding = 0;
|
|
|
|
RPC_STATUS TestCall(RPC_BINDING_HANDLE Binding,
|
|
long *inout,
|
|
BVT_BLOCKING_CONTEXT *Context)
|
|
{
|
|
RPC_MESSAGE Message;
|
|
RPC_STATUS Status;
|
|
|
|
Message.Handle = Binding;
|
|
Message.BufferLength = 8;
|
|
Message.ProcNum = 0 | RPC_FLAGS_VALID_BIT;
|
|
Message.RpcInterfaceInformation = &BVTClientInterfaceInfo;
|
|
Message.RpcFlags = 0;
|
|
|
|
Status = I_RpcGetBuffer(&Message);
|
|
if ( !EQUAL(Status, RPC_S_OK) )
|
|
return Status;
|
|
|
|
*(unsigned long *)Message.Buffer = Message.BufferLength;
|
|
*((unsigned long *)Message.Buffer+1) = *inout;
|
|
|
|
Print("Thread %d starting a call: %s %s %s %s \n",
|
|
Context->Thread,
|
|
((*inout & BVT_ASYNC) ? "Async ": ""),
|
|
((*inout & BVT_INPUT_SYNC) ? "Input sync ": ""),
|
|
((*inout & BVT_SLEEP) ? "Sleepy ": ""),
|
|
((*inout & BVT_RAISE_EXCEPTION) ? "Exception ": ""));
|
|
|
|
if (*inout & BVT_ASYNC)
|
|
{
|
|
Message.RpcFlags |= RPCFLG_ASYNCHRONOUS;
|
|
}
|
|
else
|
|
if (*inout & BVT_INPUT_SYNC)
|
|
{
|
|
Message.RpcFlags |= RPCFLG_INPUT_SYNCHRONOUS;
|
|
}
|
|
|
|
Status = I_RpcAsyncSendReceive(&Message, Context);
|
|
|
|
if (Status != RPC_S_OK)
|
|
return(Status);
|
|
|
|
if (! (*inout & BVT_ASYNC) )
|
|
{
|
|
|
|
EQUAL(Message.Buffer != 0, 1);
|
|
EQUAL(Message.BufferLength >= 8, 1);
|
|
EQUAL( *(unsigned long *)Message.Buffer, Message.BufferLength);
|
|
|
|
*inout = *((unsigned long *)Message.Buffer+1);
|
|
}
|
|
|
|
Status = I_RpcFreeBuffer(&Message);
|
|
|
|
EQUAL(Status, RPC_S_OK );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
RPC_STATUS __RPC_USER BVTBlockingHook(
|
|
IN void *RpcWindowHandle,
|
|
IN void *Context)
|
|
{
|
|
MSG msg;
|
|
RPC_STATUS Status;
|
|
BVT_BLOCKING_CONTEXT LocalContext;
|
|
long param;
|
|
BVT_BLOCKING_CONTEXT *BlockingContext = (BVT_BLOCKING_CONTEXT *)Context;
|
|
|
|
EQUAL((BlockingContext != 0), 1);
|
|
|
|
DbgPrint("(blocking, thread %d, hwnd 0x%04x, type 0x%08x, count %d)\n",
|
|
BlockingContext->Thread,
|
|
RpcWindowHandle,
|
|
BlockingContext->Type,
|
|
BlockingContext->Count);
|
|
|
|
if (BlockingContext->Type == INVALID)
|
|
{
|
|
EQUAL("Blocking hook called with an invalid context\n", 0);
|
|
}
|
|
|
|
if (BlockingContext->Type == CANCEL)
|
|
{
|
|
BlockingContext->Count--;
|
|
if (BlockingContext->Count == 0)
|
|
{
|
|
Print("Thread: %d, call cancelled\n", BlockingContext->Thread);
|
|
return(BVT_CALL_CANCELLED);
|
|
}
|
|
}
|
|
|
|
if (BlockingContext->Type == CALLNCALL)
|
|
{
|
|
if (BlockingContext->Handle == 0)
|
|
{
|
|
EQUAL(0, "Internal error, null binding");
|
|
return BVT_INTERNAL_ERROR;
|
|
}
|
|
|
|
DbgPrint("Starting call within a call\n");
|
|
|
|
param = 42;
|
|
LocalContext.Type = CALL;
|
|
LocalContext.Count = 0;
|
|
LocalContext.Thread = BlockingContext->Thread;
|
|
LocalContext.Handle = BlockingContext->Handle;
|
|
|
|
Status =
|
|
TestCall(LocalContext.Handle, ¶m, &LocalContext);
|
|
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL(param, 42 + 666);
|
|
}
|
|
|
|
if (PeekMessage(&msg, 0, 0, 0, TRUE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
else
|
|
BvtSleep(200);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
typedef enum {
|
|
|
|
// These commands change state affecting the next call
|
|
|
|
Sleepy, // Server will block during the next call
|
|
Exception, // Server will raise an exception during the next call
|
|
Pause, // Server will pause the its thread and loop for 3 seconds
|
|
Count, // Count value is reset to 'GlobalCount'
|
|
SetStatus, // Set expected status of future MakeCalls.
|
|
InputSync, // Next call will be INPUT_SYNC
|
|
Async, // Next call will be ASYNC
|
|
Standard, // Next call will not be INPUT_SYNC or ASYNC
|
|
|
|
// These commands change the binding handle used by the thread
|
|
|
|
Bind, // Thread creates a new binding (free's old if any)
|
|
GlobalBind, // Thread will use the global binding (free existing)
|
|
|
|
|
|
// These commands call the server in different ways
|
|
|
|
MakeCall, // Actually call the sever
|
|
CallWithinCall, // Call and call again when the blocking hook is called.
|
|
CancelCall, // Call and cancel it after Count blocking hook calls.
|
|
|
|
// Kills the thread
|
|
|
|
Exit // Free binding and exit
|
|
|
|
} THREAD_COMMANDS;
|
|
|
|
HANDLE ThreadReadyEvents[4] = {0};
|
|
HANDLE ThreadGoEvents[4] = {0};
|
|
THREAD_COMMANDS ThreadCases[4] = {0};
|
|
|
|
void ThreadWorker(unsigned long Thread)
|
|
{
|
|
THREAD_COMMANDS Case;
|
|
unsigned long param = Thread;
|
|
char *StringBinding;
|
|
RPC_STATUS Status;
|
|
BVT_BLOCKING_CONTEXT LocalContext;
|
|
BOOL LastBindingGlobal = 0;
|
|
int CallCount = Thread * 100;
|
|
RPC_STATUS ExpectedStatus = RPC_S_OK;
|
|
|
|
LocalContext.Thread = Thread;
|
|
LocalContext.Handle = 0;
|
|
LocalContext.Count = 0;
|
|
LocalContext.Type = INVALID;
|
|
|
|
DbgPrint("Thread %d ready\n", Thread);
|
|
|
|
for(;;)
|
|
{
|
|
SetEvent(ThreadReadyEvents[Thread]);
|
|
WaitForSingleObject(ThreadGoEvents[Thread], INFINITE);
|
|
|
|
Case = ThreadCases[Thread];
|
|
|
|
switch(Case)
|
|
{
|
|
case Sleepy:
|
|
param += SLEEP_PERIOD;
|
|
param |= BVT_SLEEP;
|
|
break;
|
|
case Async:
|
|
param = ++CallCount;
|
|
param |= BVT_ASYNC;
|
|
break;
|
|
case InputSync:
|
|
param = ++CallCount;
|
|
param |= BVT_INPUT_SYNC;
|
|
break;
|
|
case Standard:
|
|
param = ++CallCount;
|
|
break;
|
|
case Exception:
|
|
param |= BVT_RAISE_EXCEPTION;
|
|
break;
|
|
case Pause:
|
|
param |= BVT_PAUSE_THREAD;
|
|
break;
|
|
case SetStatus:
|
|
ExpectedStatus = GlobalStatus;
|
|
break;
|
|
case Count:
|
|
LocalContext.Count = GlobalCount;
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////
|
|
case Bind:
|
|
|
|
if ( LocalContext.Handle != 0 && LastBindingGlobal == 0)
|
|
{
|
|
Print("Thread %d rebinding\n", Thread);
|
|
Status = RpcBindingFree(&LocalContext.Handle);
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL(LocalContext.Handle, 0);
|
|
}
|
|
else
|
|
{
|
|
Print("Thread %d bound\n", Thread);
|
|
}
|
|
|
|
LastBindingGlobal = 0;
|
|
|
|
Status =
|
|
RpcStringBindingCompose(0, Protseq, 0, ServerEndpoint, 0, &StringBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Status =
|
|
RpcBindingFromStringBinding(StringBinding, &LocalContext.Handle);
|
|
EQUAL(Status, ("RpcBindingFromStringBinding", RPC_S_OK));
|
|
|
|
Status = I_RpcBindingSetAsync(LocalContext.Handle,
|
|
BVTBlockingHook);
|
|
EQUAL(Status, ("I_RpcBindingSetAsync", RPC_S_OK));
|
|
|
|
break;
|
|
///////////////////////////////////////////////////////
|
|
case MakeCall:
|
|
|
|
if (LocalContext.Handle == 0)
|
|
{
|
|
EQUAL(0, "Internal error");
|
|
break;
|
|
}
|
|
|
|
LocalContext.Type = CALL;
|
|
|
|
Status = TestCall(LocalContext.Handle, ¶m, &LocalContext);
|
|
|
|
EQUAL(Status, ExpectedStatus);
|
|
|
|
// Async calls, in param is not modified.
|
|
if (param & BVT_ASYNC)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ExpectedStatus)
|
|
{
|
|
// Failure case, out params not set.
|
|
break;
|
|
}
|
|
|
|
// Out value should be CallCount + 666 + Sleep periods (if any)
|
|
|
|
do {
|
|
if (param == CallCount + 666)
|
|
break;
|
|
param -= SLEEP_PERIOD;
|
|
}
|
|
while(param - SLEEP_PERIOD < param);
|
|
|
|
EQUAL(param, CallCount + 666);
|
|
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////
|
|
case CancelCall:
|
|
|
|
if (LocalContext.Handle == 0)
|
|
{
|
|
EQUAL(0, "Internal error");
|
|
break;
|
|
}
|
|
|
|
LocalContext.Type = CANCEL;
|
|
|
|
Status = TestCall(LocalContext.Handle, ¶m, &LocalContext);
|
|
|
|
if ( Status != BVT_CALL_CANCELLED
|
|
&& Status != RPC_S_SERVER_UNAVAILABLE)
|
|
{
|
|
EQUAL(Status, (ULONG)"Unexpected status from cancelled call");
|
|
}
|
|
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
case GlobalBind:
|
|
|
|
if ( LocalContext.Handle != 0 && LastBindingGlobal == 0)
|
|
{
|
|
Print("Thread %d closing old handle and using global\n", Thread);
|
|
Status = RpcBindingFree(&LocalContext.Handle);
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL(LocalContext.Handle, 0);
|
|
}
|
|
else
|
|
{
|
|
Print("Thread %d switching to GlobalBinding\n", Thread);
|
|
}
|
|
|
|
LastBindingGlobal = 1;
|
|
|
|
EQUAL( (GlobalBinding != 0), 1);
|
|
|
|
LocalContext.Handle = GlobalBinding;
|
|
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
case CallWithinCall:
|
|
|
|
LocalContext.Type = CALLNCALL;
|
|
|
|
if ( LocalContext.Handle == 0
|
|
|| param & BVT_ASYNC
|
|
|| param & BVT_INPUT_SYNC )
|
|
{
|
|
EQUAL(0, "Internal error");
|
|
break;
|
|
}
|
|
|
|
Status = TestCall(LocalContext.Handle, ¶m, &LocalContext);
|
|
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
// Out value should be CallCount + 666 + Sleep periods (if any)
|
|
|
|
do {
|
|
if (param == CallCount + 666)
|
|
break;
|
|
param -= SLEEP_PERIOD;
|
|
}
|
|
while(param - SLEEP_PERIOD < param);
|
|
|
|
EQUAL(param, CallCount + 666);
|
|
|
|
break;
|
|
|
|
case Exit:
|
|
CloseHandle(ThreadReadyEvents[Thread]);
|
|
CloseHandle(ThreadGoEvents[Thread]);
|
|
|
|
if (LocalContext.Handle)
|
|
{
|
|
Status =
|
|
RpcBindingFree(&LocalContext.Handle);
|
|
EQUAL(Status, RPC_S_OK);
|
|
}
|
|
|
|
DbgPrint("Thread %d done\n", Thread);
|
|
|
|
return;
|
|
|
|
default:
|
|
EQUAL(Case, (ULONG)"Invalid state in thread");
|
|
}
|
|
|
|
} // forever //
|
|
}
|
|
|
|
|
|
void RunThread(ULONG Thread, THREAD_COMMANDS Case)
|
|
{
|
|
DWORD Status;
|
|
|
|
for(;;)
|
|
{
|
|
Status =
|
|
WaitForSingleObject(ThreadReadyEvents[Thread], 10000);
|
|
|
|
if (Status != WAIT_TIMEOUT)
|
|
break;
|
|
|
|
Print("Thread %d is taking his time...\n", Thread);
|
|
}
|
|
|
|
ThreadCases[Thread] = Case;
|
|
|
|
SetEvent(ThreadGoEvents[Thread]);
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
RPC_STATUS Status;
|
|
RPC_BINDING_HANDLE Binding;
|
|
char *StringBinding;
|
|
LONG param;
|
|
int i;
|
|
int Threads = 4;
|
|
BVT_BLOCKING_CONTEXT LocalContext;
|
|
|
|
ParseArgs(argc, argv);
|
|
|
|
Status =
|
|
RpcStringBindingCompose(0, Protseq, 0, ServerEndpoint, 0, &StringBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Status =
|
|
RpcBindingFromStringBinding(StringBinding, &Binding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Status =
|
|
RpcStringFree(&StringBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Status =
|
|
RpcBindingToStringBinding(Binding, &StringBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Print("MwWmsg BVT Client using %s\n", StringBinding);
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
DbgPrint("Regular call (default blocking hook)\n");
|
|
|
|
LocalContext.Type = CALL;
|
|
LocalContext.Thread = 10;
|
|
LocalContext.Handle = Binding;
|
|
|
|
param = 1;
|
|
Status = TestCall(Binding, ¶m, &LocalContext);
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL(param, 1 + 666);
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
// Free the binding handle so I test first call cases.
|
|
|
|
Status = RpcBindingFree(&Binding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
for(i = 0; i < Threads; i++)
|
|
{
|
|
HANDLE CurrentThread;
|
|
ULONG Id;
|
|
|
|
ThreadReadyEvents[i] = CreateEvent(0, FALSE, FALSE, 0);
|
|
ThreadGoEvents[i] = CreateEvent(0, FALSE, FALSE, 0);
|
|
|
|
EQUAL( (ThreadReadyEvents[i] != 0), 1);
|
|
EQUAL( (ThreadGoEvents[i] != 0), 1);
|
|
|
|
CurrentThread = CreateThread(0,
|
|
0x1000,
|
|
(LPTHREAD_START_ROUTINE)ThreadWorker,
|
|
(LPVOID)i,
|
|
0,
|
|
&Id);
|
|
|
|
EQUAL( (CurrentThread != 0), 1);
|
|
|
|
CloseHandle(CurrentThread);
|
|
}
|
|
|
|
BvtSleep(1000);
|
|
Print("Threads started\n");
|
|
|
|
// Bind first thread
|
|
RunThread(0, Bind);
|
|
|
|
// A standard call on first thread
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// A call within a call on first thread
|
|
RunThread(0, Standard);
|
|
RunThread(0, CallWithinCall);
|
|
|
|
// A standard sleepy call on first thread
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// a couple expection cases.
|
|
RunThread(0, Standard);
|
|
GlobalStatus = BVT_EXCEPTION;
|
|
|
|
// Exception in regular call
|
|
RunThread(0, SetStatus);
|
|
RunThread(0, Exception);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Sleepy Exception in regular call
|
|
RunThread(0, Standard);
|
|
RunThread(0, Exception);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
|
|
// reset status
|
|
GlobalStatus = RPC_S_OK;
|
|
RunThread(0, SetStatus);
|
|
|
|
// Start several sleepy async calls
|
|
for(i = 0; i < 3; i++)
|
|
{
|
|
RunThread(0, Async);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
}
|
|
|
|
// Call, will block until async's complete
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// InputSync call
|
|
RunThread(0, InputSync);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Exception case
|
|
GlobalStatus = BVT_EXCEPTION;
|
|
RunThread(0, SetStatus);
|
|
|
|
// Sleepy & exception InputSync call
|
|
RunThread(0, InputSync);
|
|
RunThread(0, Exception);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Async exceptions will not be reported on client.
|
|
RunThread(0, Async);
|
|
GlobalStatus = RPC_S_OK;
|
|
|
|
// Exception async call
|
|
RunThread(0, SetStatus);
|
|
RunThread(0, Exception);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Sleepy exception async call
|
|
RunThread(0, Async);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, Exception);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Call - wait for asyncs to be processed
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Bind Second Thread
|
|
RunThread(1, Bind);
|
|
|
|
// Make a standard call
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Start sleepy calls on both threads; processed serially.
|
|
RunThread(0, Standard);
|
|
RunThread(1, Standard);
|
|
RunThread(0, Sleepy);
|
|
RunThread(1, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Send sleepy asyncs from both threads
|
|
RunThread(0, Async);
|
|
RunThread(1, Async);
|
|
RunThread(0, Sleepy);
|
|
RunThread(1, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Input sync call should arrive between the async calls
|
|
RunThread(0, InputSync);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Won't run until the async calls to complete
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Rebind both threads and make input sync calls
|
|
RunThread(0, Bind);
|
|
RunThread(1, Bind);
|
|
RunThread(0, InputSync);
|
|
RunThread(1, InputSync);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Create and bind to global binding handle
|
|
|
|
Status =
|
|
RpcBindingFromStringBinding(StringBinding, &GlobalBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL( (GlobalBinding != 0), 1);
|
|
|
|
RunThread(0, GlobalBind);
|
|
RunThread(1, GlobalBind);
|
|
|
|
// Make standard calls (using the same global binding)
|
|
RunThread(0, Standard);
|
|
RunThread(1, Standard);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Switch one thread back a thread binding
|
|
|
|
RunThread(0, Bind);
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Call with global (only one user)
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Reset bindings
|
|
RunThread(0, Bind);
|
|
RunThread(1, Bind);
|
|
|
|
// Nobody is using GlobalBinding anymore.
|
|
Status =
|
|
RpcBindingFree(&GlobalBinding);
|
|
EQUAL( (Status == RPC_S_OK) + (GlobalBinding == 0), 2);
|
|
|
|
// A thread takes the 'first call on binding async path'
|
|
RunThread(0, Async);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Two threads each taking the 'first call on binding async' path
|
|
RunThread(0, Async);
|
|
RunThread(1, Async);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Wait for async's to finish
|
|
RunThread(1, Standard);
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Cancel a standard call during while waiting
|
|
|
|
RunThread(0, Async);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, MakeCall);
|
|
|
|
GlobalCount = 4;
|
|
RunThread(0, Standard);
|
|
RunThread(0, Sleepy);
|
|
RunThread(0, Count);
|
|
// CancelCall knows the status
|
|
RunThread(0, CancelCall);
|
|
|
|
// Wait for cancelled response to be processed.
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Clear thread 1's binding handle reference
|
|
RunThread(1, Bind);
|
|
|
|
// Cancel a call during bind
|
|
GlobalCount = 1;
|
|
RunThread(0, Bind);
|
|
RunThread(0, Standard);
|
|
RunThread(0, Count);
|
|
// CancelCall knows the status
|
|
RunThread(0, CancelCall);
|
|
|
|
// Wait for cancelled response to be processed.
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Cancel a call during bind
|
|
|
|
GlobalCount = 2;
|
|
RunThread(0, Bind);
|
|
RunThread(0, Standard);
|
|
RunThread(0, Count);
|
|
// CancelCall knowns the status
|
|
RunThread(0, CancelCall);
|
|
|
|
// Wait for cancelled response to be processed.
|
|
RunThread(0, Standard);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Pause the server
|
|
|
|
RunThread(0, Standard);
|
|
RunThread(0, Pause);
|
|
RunThread(0, MakeCall);
|
|
|
|
// Thread 0 won't return for 3 seconds, in the mean time the
|
|
// server's thread will be paused.
|
|
|
|
GlobalStatus = RPC_S_NOT_LISTENING;
|
|
RunThread(1, SetStatus);
|
|
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
RunThread(1, InputSync);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Async won't fail on client.
|
|
|
|
GlobalStatus = RPC_S_OK;
|
|
RunThread(1, SetStatus);
|
|
|
|
RunThread(1, Async);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Rebind thread
|
|
|
|
RunThread(1, Bind);
|
|
|
|
GlobalStatus = RPC_S_NOT_LISTENING;
|
|
RunThread(1, SetStatus);
|
|
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Unconnected async won't fail on client.
|
|
|
|
GlobalStatus = RPC_S_OK;
|
|
RunThread(1, SetStatus);
|
|
|
|
RunThread(1, Async);
|
|
RunThread(1, MakeCall);
|
|
|
|
RunThread(0, Standard); // Will wait for pause call to complete
|
|
RunThread(0, MakeCall); // Should work now.
|
|
|
|
GlobalStatus = RPC_S_OK;
|
|
RunThread(1, SetStatus);
|
|
|
|
RunThread(1, Standard);
|
|
RunThread(1, MakeCall);
|
|
|
|
// Done with the test.
|
|
|
|
BvtSleep(1000);
|
|
Print("Stopping threads\n");
|
|
RunThread(0, Exit);
|
|
RunThread(1, Exit);
|
|
RunThread(2, Exit);
|
|
RunThread(3, Exit);
|
|
BvtSleep(1000);
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
DbgPrint("Standard call to stop the server\n");
|
|
|
|
Status =
|
|
RpcBindingFromStringBinding(StringBinding, &Binding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
param = 1234; // stop's the server
|
|
Status = TestCall(Binding, ¶m, &LocalContext);
|
|
|
|
EQUAL(Status, RPC_S_OK);
|
|
EQUAL(param, 1234 + 666);
|
|
|
|
Status =
|
|
RpcBindingFree(&Binding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
Status =
|
|
RpcStringFree(&StringBinding);
|
|
EQUAL(Status, RPC_S_OK);
|
|
|
|
if (ErrorCount)
|
|
Print("Failures: %d\n", ErrorCount);
|
|
else
|
|
Print("Passed\n");
|
|
|
|
return 0;
|
|
}
|
|
|