windows-nt/Source/XPSP1/NT/com/rpc/perf/rpcrt/client/client.c
2020-09-26 16:20:57 +08:00

884 lines
21 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1994 - 1999
Module Name:
Client.c
Abstract:
Client side of basic RPC performance test.
Author:
Mario Goertzel (mariogo) 31-Mar-1994
Revision History:
--*/
#include <rpcperf.h>
#include <rpcrt.h>
#ifdef MAC
extern void _cdecl PrintToConsole(const char *lpszFormat, ...) ;
extern unsigned long ulSecurityPackage ;
#else
#define PrintToConsole printf
unsigned long ulSecurityPackage = RPC_C_AUTHN_WINNT ;
#endif
// Usage
const char *USAGE = "-n <threads> -a <authnlevel> -s <server> -t <protseq> -w <wait_method>\n"
"Server controls iterations, test cases, and compiles the results.\n"
"AuthnLevel: none, connect, call, pkt, integrity, privacy.\n"
"Default threads=1, authnlevel=none\n";
#define CHECK_RET(status, string) if (status)\
{ PrintToConsole("%s failed -- %lu (0x%08X)\n", string,\
(unsigned long)status, (unsigned long)status);\
return (status); \
}
#ifdef WIN98
RPC_DISPATCH_TABLE DummyDispatchTable =
{
1, NULL
};
RPC_SERVER_INTERFACE DummyInterfaceInformation =
{
sizeof(RPC_SERVER_INTERFACE),
{{1,2,2,{3,3,3,3,3,3,3,3}},
{1,1}},
{{1,2,2,{3,3,3,3,3,3,3,3}},
{0,0}},
&DummyDispatchTable,
0,
NULL,
NULL,
NULL,
0
};
#endif
RPC_STATUS DoRpcBindingSetAuthInfo(handle_t Binding)
{
if (AuthnLevel != RPC_C_AUTHN_LEVEL_NONE)
return RpcBindingSetAuthInfo(Binding,
NULL,
AuthnLevel,
ulSecurityPackage,
NULL,
RPC_C_AUTHZ_NONE);
else
return(RPC_S_OK);
}
//
// Test wrappers
//
unsigned long DoNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
NullCall(*b);
return (FinishTiming());
}
unsigned long DoNICall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
NICall(*b);
return (FinishTiming());
}
unsigned long DoWrite1K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Write1K(*b,p);
return (FinishTiming());
}
unsigned long DoRead1K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Read1K(*b,p);
return (FinishTiming());
}
unsigned long DoWrite4K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Write4K(*b,p);
return (FinishTiming());
}
unsigned long DoRead4K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Read4K(*b,p);
return (FinishTiming());
}
unsigned long DoWrite32K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Write32K(*b,p);
return (FinishTiming());
}
unsigned long DoRead32K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
StartTime();
while(i--)
Read32K(*b,p);
return (FinishTiming());
}
unsigned long DoContextNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
unsigned long Time;
PERF_CONTEXT pContext = OpenContext(*b);
StartTime();
while(i--)
ContextNullCall(pContext);
Time = FinishTiming();
CloseContext(&pContext);
return (Time);
}
unsigned long DoFixedBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
unsigned long status;
unsigned long Time;
char *stringBinding;
char *ep = GetFixedEp(*b);
handle_t binding;
RpcBindingFree(b);
RpcStringBindingCompose(0,
Protseq,
NetworkAddr,
ep,
0,
&stringBinding);
MIDL_user_free(ep);
StartTime();
while(i--)
{
RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding);
CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding);
}
Time = FinishTiming();
//
// Restore binding for the rest of the test.
//
RpcBindingFromStringBinding(stringBinding, b);
NullCall(*b);
NullCall(*b);
RpcStringFree(&stringBinding);
return (Time);
}
unsigned long DoReBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
unsigned long status;
unsigned long Time;
char *stringBinding;
char *ep = GetFixedEp(*b);
handle_t binding;
RpcStringBindingCompose(0,
Protseq,
NetworkAddr,
ep,
0,
&stringBinding);
MIDL_user_free(ep);
StartTime();
while(i--)
{
RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding);
CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding);
}
Time = FinishTiming();
RpcStringFree(&stringBinding);
return (Time);
}
unsigned long DoDynamicBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
unsigned long status;
unsigned long Time;
char *stringBinding;
handle_t binding;
RpcBindingFree(b);
RpcStringBindingCompose(0,
Protseq,
NetworkAddr,
0,
0,
&stringBinding);
StartTime();
while(i--)
{
RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding);
CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding);
}
Time = FinishTiming();
//
// Restore binding for test to use.
//
RpcBindingFromStringBinding(stringBinding, b);
NullCall(*b);
NullCall(*b);
RpcStringFree(&stringBinding);
return (Time);
}
void AsyncProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent)
{
// no-op
}
void AsyncCallbackProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent)
{
// wake up our thread
// in hThread we actually keep an event
HANDLE hEvent = pAsync->u.APC.hThread;
SetEvent(hEvent);
}
void NotifyProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent)
{
// no-op
}
unsigned long DoAsyncNullCallWithEvent(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b,
long i, char __RPC_FAR *p)
{
HANDLE hEvent = pAsync->u.hEvent;
RPC_STATUS RpcStatus;
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
pAsync->NotificationType = RpcNotificationTypeEvent;
pAsync->u.hEvent = hEvent;
AsyncNullCall(pAsync, *b);
WaitForSingleObject(hEvent, INFINITE);
RpcAsyncCompleteCall(pAsync, NULL);
}
return (FinishTiming());
}
unsigned long DoAsyncNullCallWithApc(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b,
long i, char __RPC_FAR *p)
{
RPC_STATUS RpcStatus;
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
pAsync->NotificationType = RpcNotificationTypeApc;
pAsync->u.APC.NotificationRoutine = AsyncProc;
pAsync->u.APC.hThread = 0;
AsyncNullCall(pAsync, *b);
SleepEx(INFINITE, TRUE);
RpcAsyncCompleteCall(pAsync, NULL);
}
return (FinishTiming());
}
unsigned long DoAsyncNullCallWithCallback(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b,
long i, char __RPC_FAR *p)
{
RPC_STATUS RpcStatus;
HANDLE hEvent;
unsigned long nTiming;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!hEvent)
{
printf("CreateEvent failed: %ld\n", GetLastError());
return 0;
}
#ifdef WIN98
// under Win9x, the client needs a running server to use callback
// notifications. This assumption is Ok, since only OLE uses
// callbacks, and in OLE every process is both client and server
RpcStatus = RpcServerUseProtseqEp("ncalrpc", 1, "dummy", NULL);
if (RpcStatus != RPC_S_OK)
return 0;
RpcStatus = RpcServerRegisterIf(&DummyInterfaceInformation, NULL, NULL);
if (RpcStatus != RPC_S_OK)
return 0;
RpcStatus = RpcServerListen(1, 2, TRUE);
if (RpcStatus != RPC_S_OK)
return 0;
#endif
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
pAsync->NotificationType = RpcNotificationTypeCallback;
pAsync->u.NotificationRoutine = AsyncCallbackProc;
// just a little bit of a hack. We know that the we cannot use
// the hEvent data member of u as we wished, because it occupies
// the same memory location as the callback routine, so we
// use the APC.hThread member which occupies the same DWORD
pAsync->u.APC.hThread = hEvent;
AsyncNullCall(pAsync, *b);
WaitForSingleObject(hEvent, INFINITE);
RpcAsyncCompleteCall(pAsync, NULL);
}
CloseHandle(hEvent);
nTiming = FinishTiming();
#ifdef WIN98
RpcStatus = RpcMgmtStopServerListening(NULL);
if (RpcStatus == RPC_S_OK)
{
RpcMgmtWaitServerListen();
}
#endif
return nTiming;
}
unsigned long DoAsyncNullCallWithNone(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b,
long i, char __RPC_FAR *p)
{
RPC_STATUS RpcStatus;
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
pAsync->NotificationType = RpcNotificationTypeNone;
AsyncNullCall(pAsync, *b);
// make sure we catch even the slightest variations in performance. Loop all the time ...
while (RpcAsyncGetCallStatus(pAsync) == RPC_S_ASYNC_CALL_PENDING)
;
RpcAsyncCompleteCall(pAsync, NULL);
}
return (FinishTiming());
}
unsigned long DoAsyncNullCallWithHwnd(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b,
long i, char __RPC_FAR *p)
{
RPC_STATUS RpcStatus;
HWND hWnd = pAsync->u.HWND.hWnd;
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
pAsync->NotificationType = RpcNotificationTypeHwnd;
pAsync->u.HWND.hWnd = hWnd;
pAsync->u.HWND.Msg = PERF_TEST_NOTIFY;
AsyncNullCall(pAsync, *b);
PumpMessage();
RpcAsyncCompleteCall(pAsync, NULL);
}
return (FinishTiming());
}
unsigned long DoAsyncNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p)
{
RPC_ASYNC_STATE asyncState;
RPC_STATUS RpcStatus;
BOOL fCallComplete = FALSE;
RpcStatus = RpcAsyncInitializeHandle(&asyncState, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
asyncState.NotificationType = NotificationType;
switch (NotificationType)
{
case RpcNotificationTypeEvent:
asyncState.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (asyncState.u.hEvent == NULL)
{
printf("CreateEvent failed: %ld\n", GetLastError());
return 0;
}
return DoAsyncNullCallWithEvent(&asyncState, b, i, p);
case RpcNotificationTypeApc:
return DoAsyncNullCallWithApc(&asyncState, b, i, p);
case RpcNotificationTypeNone:
return DoAsyncNullCallWithNone(&asyncState, b, i, p);
case RpcNotificationTypeHwnd:
asyncState.u.HWND.hWnd = CreateSTAWindow("Noname");
if (asyncState.u.HWND.hWnd == NULL)
{
printf("CreateEvent failed: %ld\n", GetLastError());
return 0;
}
asyncState.u.HWND.Msg = PERF_TEST_NOTIFY;
return DoAsyncNullCallWithHwnd(&asyncState, b, i, p);
case RpcNotificationTypeCallback:
return DoAsyncNullCallWithCallback(&asyncState, b, i, p);
default:
printf("Invalid Notification option\n");
return FALSE;
}
}
unsigned long DoAsyncSTANullCall(handle_t __RPC_FAR * b, HWND hWnd, long i, char __RPC_FAR *p)
{
RPC_STATUS RpcStatus;
RPC_ASYNC_STATE asyncState;
StartTime();
while(i--)
{
RpcStatus = RpcAsyncInitializeHandle(&asyncState, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK)
{
printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError());
return 0;
}
asyncState.NotificationType = RpcNotificationTypeCallback;
asyncState.u.NotificationRoutine = NotifyProc;
AsyncSTANullCall(&asyncState, *b);
PumpMessage();
RpcAsyncCompleteCall(&asyncState, NULL);
}
return (FinishTiming());
}
static const unsigned long (*TestTable[TEST_MAX])(handle_t __RPC_FAR *, long, char __RPC_FAR *) =
{
DoNullCall,
DoNICall,
DoWrite1K,
DoRead1K,
DoWrite4K,
DoRead4K,
DoWrite32K,
DoRead32K,
DoContextNullCall,
DoFixedBinding,
DoReBinding,
DoDynamicBinding,
DoAsyncNullCall
#ifdef WIN98
, DoAsyncSTANullCall
#endif
};
//
// Worker calls the correct tests. Maybe multithreaded on NT
//
unsigned long Worker(unsigned long l)
{
unsigned long status;
unsigned long lTest;
long lIterations, lClientId;
unsigned long lTime;
char __RPC_FAR *pBuffer;
char __RPC_FAR *stringBinding;
handle_t binding;
#ifdef WIN98
BOOL fIsPortseqWmsg;
HWND hWnd;
HWND hServerWnd;
DWORD dwServerTid;
#endif
#ifdef WIN98
if (strcmp(Protseq, "mswmsg") == 0)
{
fIsPortseqWmsg = TRUE;
hWnd = CreateSTAWindow("Perf Client");
if (hWnd == NULL)
{
printf("Couldn't create STA window: %ld\n", GetLastError());
return 0;
}
status = I_RpcServerStartListening(hWnd);
if (status != RPC_S_OK)
{
printf("Failed to I_RpcServerStartListening: %ld\n", status);
return 0;
}
}
else
fIsPortseqWmsg = FALSE;
#endif
pBuffer = MIDL_user_allocate(32*1024L);
if (pBuffer == 0)
{
PrintToConsole("Out of memory!");
return 1;
}
status =
RpcStringBindingCompose(0,
Protseq,
NetworkAddr,
Endpoint,
0,
&stringBinding);
CHECK_RET(status, "RpcStringBindingCompose");
status =
RpcBindingFromStringBinding(stringBinding, &binding);
CHECK_RET(status, "RpcBindingFromStringBinding");
status =
DoRpcBindingSetAuthInfo(binding);
CHECK_RET(status, "RpcBindingSetAuthInfo");
RpcStringFree(&stringBinding);
#ifdef WIN98
if (fIsPortseqWmsg == TRUE)
{
while (TRUE)
{
hServerWnd = FindWindow(NULL, "Perf Server");
if (hServerWnd)
{
dwServerTid = (DWORD)GetWindowLong(hServerWnd, GWL_USERDATA);
break;
}
printf(".");
Sleep(100);
}
status = I_RpcBindingSetAsync(binding, NULL, dwServerTid);
if (status != RPC_S_OK)
{
printf("Failed to I_RpcBindingSetAsync: %ld\n", status);
return 0;
}
PrintToConsole("(%ld iterations of case %ld: ", 10000, 13);
lTime = DoAsyncSTANullCall(&binding, hWnd, 10000, pBuffer);
PrintToConsole("%ld mseconds)\n",
lTime
);
return RPC_S_OK;
}
#endif
RpcTryExcept
{
status =
BeginTest(binding, &lClientId);
}
RpcExcept(1)
{
PrintToConsole("First call failed %ld (%08lx)\n",
(unsigned long)RpcExceptionCode(),
(unsigned long)RpcExceptionCode());
goto Cleanup;
}
RpcEndExcept
if (status == PERF_TOO_MANY_CLIENTS)
{
PrintToConsole("Too many clients, I'm exiting\n");
goto Cleanup ;
}
CHECK_RET(status, "ClientConnect");
PrintToConsole("Client %ld connected\n", lClientId);
do
{
status = NextTest(binding, (TEST_TYPE *)&lTest, &lIterations);
if (status == PERF_TESTS_DONE)
{
goto Cleanup;
}
CHECK_RET(status, "NextTest");
PrintToConsole("(%ld iterations of case %ld: ", lIterations, lTest);
RpcTryExcept
{
lTime = ( (TestTable[lTest])(&binding, lIterations, pBuffer));
PrintToConsole("%ld mseconds)\n",
lTime
);
status =
EndTest(binding, lTime);
CHECK_RET(status, "EndTest");
}
RpcExcept(1)
{
PrintToConsole("\nTest case %ld raised exception %lu (0x%08lX)\n",
lTest,
(unsigned long)RpcExceptionCode(),
(unsigned long)RpcExceptionCode());
status = RpcExceptionCode();
}
RpcEndExcept
}
while(status == 0);
Cleanup:
RpcBindingFree(&binding) ;
return status;
}
//
// The Win32 main starts worker threads, otherwise we just call the worker.
//
#ifdef WIN32
int __cdecl
main (int argc, char **argv)
{
char option;
unsigned long status, i;
HANDLE *pClientThreads;
#ifdef WIN98
BOOL fIsPortseqWmsg;
#endif
ParseArgv(argc, argv);
PrintToConsole("Authentication Level is: %s\n", AuthnLevelStr);
if (Options[0] < 0)
Options[0] = 1;
InitAllocator();
#ifdef WIN98
if (strcmp(Protseq, "mswmsg") == 0)
{
fIsPortseqWmsg = TRUE;
status = RpcServerUseProtseqEp(Protseq, 1, "Perf Client", NULL);
if (status != RPC_S_OK)
{
printf("Failed to use protseq: %ld\n", status);
return 3;
}
}
else
fIsPortseqWmsg = FALSE;
#endif
pClientThreads = MIDL_user_allocate(sizeof(HANDLE) * Options[0]);
for(i = 0; i < (unsigned long)Options[0]; i++)
{
pClientThreads[i] = CreateThread(0,
0,
(LPTHREAD_START_ROUTINE)Worker,
0,
0,
&status);
if (pClientThreads[i] == 0)
ApiError("CreateThread", GetLastError());
}
status = WaitForMultipleObjects(Options[0],
pClientThreads,
TRUE, // Wait for all client threads
INFINITE);
if (status == WAIT_FAILED)
{
ApiError("WaitForMultipleObjects", GetLastError());
}
PrintToConsole("TEST DONE\n");
return(0);
}
#else // !WIN32
#ifdef WIN
#define main c_main
// We need the following to force the linker to load WinMain from the
// Windows STDIO library
extern int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
static int (PASCAL *wm_ptr)(HANDLE, HANDLE, LPSTR, int) = WinMain;
#endif
#ifndef MAC
#ifndef FAR
#define FAR __far
#endif
#else
#define FAR
#define main c_main
#endif
int main (int argc, char FAR * FAR * argv)
{
#ifndef MAC
ParseArgv(argc, argv);
#endif
Worker(0);
PrintToConsole("TEST DONE\n");
return(0);
}
#endif // NTENV