563 lines
15 KiB
C
563 lines
15 KiB
C
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Rtclnt.c
|
|
|
|
Abstract:
|
|
|
|
Client side of basic RPC scale performance test.
|
|
|
|
Author:
|
|
|
|
Mario Goertzel (mariogo) 31-Mar-1994
|
|
|
|
Revision History:
|
|
|
|
18/7/96 [MarioGo] - Cloned from rpcrt test
|
|
|
|
--*/
|
|
|
|
#include <rpcperf.h>
|
|
#include <rpcrt.h>
|
|
|
|
#ifdef MAC
|
|
extern void _cdecl PrintToConsole(const char *lpszFormat, ...) ;
|
|
extern unsigned long ulSecurityPackage ;
|
|
#else
|
|
#define PrintToConsole printf
|
|
extern unsigned long ulSecurityPackage;
|
|
#endif
|
|
|
|
// Usage
|
|
|
|
const char *USAGE = "-n <threads> -a <authnlevel> -s <server> -t <protseq>\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";
|
|
|
|
|
|
unsigned long gInSize = 500 - IN_ADJUSTMENT;
|
|
unsigned long gOutSize = 500 - OUT_ADJUSTMENT;
|
|
|
|
#ifdef STATS
|
|
// exported by RPCRT4
|
|
void I_RpcGetStats(DWORD *pdwStat1, DWORD *pdwStat2, DWORD *pdwStat3, DWORD *pdwStat4);
|
|
#endif
|
|
|
|
// Error stuff
|
|
|
|
#define CHECK_RET(status, string) if (status)\
|
|
{ PrintToConsole("%s failed -- %lu (0x%08X)\n", string,\
|
|
(unsigned long)status, (unsigned long)status);\
|
|
return (status); }
|
|
|
|
RPC_STATUS DoRpcBindingSetAuthInfo(handle_t Binding)
|
|
{
|
|
if (AuthnLevel != RPC_C_AUTHN_LEVEL_NONE)
|
|
return RpcBindingSetAuthInfoA(Binding,
|
|
ServerPrincipalName,
|
|
AuthnLevel,
|
|
ulSecurityPackage,
|
|
NULL,
|
|
RPC_C_AUTHZ_NONE);
|
|
else
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
//
|
|
// Test wrappers
|
|
//
|
|
|
|
unsigned long DoNullCall(handle_t *pb, char *stringBinding, unsigned long c, char __RPC_FAR *p)
|
|
{
|
|
unsigned long status;
|
|
unsigned long calls = 0;
|
|
|
|
do
|
|
{
|
|
status = NullCall(*pb, c);
|
|
calls++;
|
|
|
|
}
|
|
while (status == 0);
|
|
|
|
if (status != PERF_TESTS_DONE)
|
|
{
|
|
RpcRaiseException(status);
|
|
}
|
|
|
|
return(calls);
|
|
}
|
|
|
|
unsigned long DoMaybeCall(handle_t *pb, char *stringBinding, unsigned long c, char __RPC_FAR *p)
|
|
{
|
|
unsigned long calls = 0;
|
|
|
|
for(calls = 10000; calls; calls--)
|
|
{
|
|
MaybeCall(*pb, c);
|
|
}
|
|
|
|
return(10000);
|
|
}
|
|
|
|
|
|
unsigned long DoNICall(handle_t *pb, char *stringBinding, unsigned long c, char __RPC_FAR *p)
|
|
{
|
|
unsigned long status;
|
|
unsigned long calls = 0;
|
|
|
|
do
|
|
{
|
|
status = NICall(*pb, c);
|
|
calls++;
|
|
|
|
}
|
|
while (status == 0);
|
|
|
|
if (status != PERF_TESTS_DONE)
|
|
{
|
|
RpcRaiseException(status);
|
|
}
|
|
|
|
return(calls);
|
|
}
|
|
|
|
unsigned long DoBufferCall(handle_t *pb, char *stringBinding, unsigned long c, char __RPC_FAR *p)
|
|
{
|
|
unsigned long status;
|
|
unsigned long calls = 0;
|
|
|
|
do
|
|
{
|
|
RpcTryExcept
|
|
{
|
|
status = BufferCall(*pb, c, gInSize, p, gOutSize, p);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
PrintToConsole("\nException %lu (0x%08lX)\n",
|
|
(unsigned long)RpcExceptionCode(),
|
|
(unsigned long)RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
calls++;
|
|
|
|
}
|
|
while (status != PERF_TESTS_DONE);
|
|
|
|
if (status != PERF_TESTS_DONE)
|
|
{
|
|
RpcRaiseException(status);
|
|
}
|
|
|
|
return(calls);
|
|
}
|
|
|
|
unsigned long DoBindCall(handle_t *pb, char *stringBinding, unsigned long c, char __RPC_FAR *p)
|
|
{
|
|
unsigned long status;
|
|
unsigned long calls = 0;
|
|
|
|
do
|
|
{
|
|
status = RpcBindingFree(pb);
|
|
if (status)
|
|
{
|
|
break;
|
|
}
|
|
|
|
status = RpcBindingFromStringBindingA(stringBinding, pb);
|
|
if (status)
|
|
{
|
|
break;
|
|
}
|
|
|
|
status = NullCall(*pb, c);
|
|
|
|
calls++;
|
|
}
|
|
while (status == 0);
|
|
|
|
if (status != PERF_TESTS_DONE)
|
|
{
|
|
RpcRaiseException(status);
|
|
}
|
|
|
|
return(calls);
|
|
}
|
|
|
|
|
|
static const unsigned long (*TestTable[TEST_MAX])(handle_t *pb, char *stringBinding, unsigned long, char __RPC_FAR *) =
|
|
{
|
|
DoNullCall,
|
|
DoNICall,
|
|
DoBufferCall,
|
|
DoMaybeCall,
|
|
DoBindCall
|
|
};
|
|
|
|
//
|
|
// Worker calls the correct tests. Maybe multithreaded on NT
|
|
//
|
|
|
|
unsigned long Worker(unsigned long l)
|
|
{
|
|
unsigned long status;
|
|
unsigned long Test;
|
|
unsigned long ClientId;
|
|
unsigned long InSize, OutSize;
|
|
unsigned long Time, Calls;
|
|
char __RPC_FAR *pBuffer;
|
|
char __RPC_FAR *stringBinding;
|
|
handle_t binding;
|
|
RPC_STATUS RpcErr;
|
|
int Retries;
|
|
|
|
pBuffer = MIDL_user_allocate(128*1024L);
|
|
if (pBuffer == 0)
|
|
{
|
|
PrintToConsole("Out of memory!");
|
|
return 1;
|
|
}
|
|
|
|
status =
|
|
RpcStringBindingComposeA(0,
|
|
Protseq,
|
|
NetworkAddr,
|
|
Endpoint,
|
|
0,
|
|
&stringBinding);
|
|
CHECK_RET(status, "RpcStringBindingCompose");
|
|
|
|
status =
|
|
RpcBindingFromStringBindingA(stringBinding, &binding);
|
|
CHECK_RET(status, "RpcBindingFromStringBinding");
|
|
|
|
status =
|
|
DoRpcBindingSetAuthInfo(binding);
|
|
CHECK_RET(status, "RpcBindingSetAuthInfo");
|
|
|
|
Retries = 15;
|
|
|
|
do
|
|
{
|
|
status = BeginTest(binding, &ClientId, &Test, &InSize, &OutSize);
|
|
|
|
if (status == PERF_TOO_MANY_CLIENTS)
|
|
{
|
|
PrintToConsole("Too many clients, I'm exiting\n");
|
|
goto Cleanup ;
|
|
}
|
|
|
|
Retries --;
|
|
if ((status == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0))
|
|
{
|
|
PrintToConsole("Server too busy - retrying ...\n");
|
|
}
|
|
}
|
|
while ((status == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0));
|
|
|
|
if (status)
|
|
{
|
|
RPC_STATUS Status2;
|
|
RPC_ERROR_ENUM_HANDLE EnumHandle;
|
|
|
|
Status2 = RpcErrorStartEnumeration(&EnumHandle);
|
|
if (Status2 == RPC_S_ENTRY_NOT_FOUND)
|
|
{
|
|
CHECK_RET(status, "ClientConnect");
|
|
}
|
|
else if (Status2 != RPC_S_OK)
|
|
{
|
|
PrintToConsole("Couldn't get EEInfo: %d\n", Status2);
|
|
CHECK_RET(status, "ClientConnect");
|
|
}
|
|
else
|
|
{
|
|
RPC_EXTENDED_ERROR_INFO ErrorInfo;
|
|
int Records;
|
|
BOOL Result;
|
|
BOOL CopyStrings = TRUE;
|
|
PVOID Blob;
|
|
size_t BlobSize;
|
|
BOOL fUseFileTime = TRUE;
|
|
SYSTEMTIME *SystemTimeToUse;
|
|
SYSTEMTIME SystemTimeBuffer;
|
|
|
|
Status2 = RpcErrorGetNumberOfRecords(&EnumHandle, &Records);
|
|
if (Status2 == RPC_S_OK)
|
|
{
|
|
PrintToConsole("Number of records is: %d\n", Records);
|
|
}
|
|
|
|
while (Status2 == RPC_S_OK)
|
|
{
|
|
ErrorInfo.Version = RPC_EEINFO_VERSION;
|
|
ErrorInfo.Flags = 0;
|
|
ErrorInfo.NumberOfParameters = 4;
|
|
if (fUseFileTime)
|
|
{
|
|
ErrorInfo.Flags |= EEInfoUseFileTime;
|
|
}
|
|
|
|
Status2 = RpcErrorGetNextRecord(&EnumHandle, CopyStrings, &ErrorInfo);
|
|
if (Status2 == RPC_S_ENTRY_NOT_FOUND)
|
|
{
|
|
RpcErrorResetEnumeration(&EnumHandle);
|
|
break;
|
|
}
|
|
else if (Status2 != RPC_S_OK)
|
|
{
|
|
PrintToConsole("Couldn't finish enumeration: %d\n", Status2);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
if (ErrorInfo.ComputerName)
|
|
{
|
|
PrintToConsole("ComputerName is %S\n", ErrorInfo.ComputerName);
|
|
if (CopyStrings)
|
|
{
|
|
Result = HeapFree(GetProcessHeap(), 0, ErrorInfo.ComputerName);
|
|
ASSERT(Result);
|
|
}
|
|
}
|
|
PrintToConsole("ProcessID is %d\n", ErrorInfo.ProcessID);
|
|
if (fUseFileTime)
|
|
{
|
|
Result = FileTimeToSystemTime(&ErrorInfo.u.FileTime, &SystemTimeBuffer);
|
|
ASSERT(Result);
|
|
SystemTimeToUse = &SystemTimeBuffer;
|
|
}
|
|
else
|
|
SystemTimeToUse = &ErrorInfo.u.SystemTime;
|
|
|
|
PrintToConsole("System Time is: %d/%d/%d %d:%d:%d:%d\n",
|
|
SystemTimeToUse->wMonth,
|
|
SystemTimeToUse->wDay,
|
|
SystemTimeToUse->wYear,
|
|
SystemTimeToUse->wHour,
|
|
SystemTimeToUse->wMinute,
|
|
SystemTimeToUse->wSecond,
|
|
SystemTimeToUse->wMilliseconds);
|
|
PrintToConsole("Generating component is %d\n", ErrorInfo.GeneratingComponent);
|
|
PrintToConsole("Status is %d\n", ErrorInfo.Status);
|
|
PrintToConsole("Detection location is %d\n", (int)ErrorInfo.DetectionLocation);
|
|
PrintToConsole("Flags is %d\n", ErrorInfo.Flags);
|
|
PrintToConsole("NumberOfParameters is %d\n", ErrorInfo.NumberOfParameters);
|
|
for (i = 0; i < ErrorInfo.NumberOfParameters; i ++)
|
|
{
|
|
switch(ErrorInfo.Parameters[i].ParameterType)
|
|
{
|
|
case eeptAnsiString:
|
|
PrintToConsole("Ansi string: %s\n", ErrorInfo.Parameters[i].u.AnsiString);
|
|
if (CopyStrings)
|
|
{
|
|
Result = HeapFree(GetProcessHeap(), 0, ErrorInfo.Parameters[i].u.AnsiString);
|
|
ASSERT(Result);
|
|
}
|
|
break;
|
|
|
|
case eeptUnicodeString:
|
|
PrintToConsole("Unicode string: %S\n", ErrorInfo.Parameters[i].u.UnicodeString);
|
|
if (CopyStrings)
|
|
{
|
|
Result = HeapFree(GetProcessHeap(), 0, ErrorInfo.Parameters[i].u.UnicodeString);
|
|
ASSERT(Result);
|
|
}
|
|
break;
|
|
|
|
case eeptLongVal:
|
|
PrintToConsole("Long val: %d\n", ErrorInfo.Parameters[i].u.LVal);
|
|
break;
|
|
|
|
case eeptShortVal:
|
|
PrintToConsole("Short val: %d\n", (int)ErrorInfo.Parameters[i].u.SVal);
|
|
break;
|
|
|
|
case eeptPointerVal:
|
|
PrintToConsole("Pointer val: %d\n", ErrorInfo.Parameters[i].u.PVal);
|
|
break;
|
|
|
|
case eeptNone:
|
|
PrintToConsole("Truncated\n");
|
|
break;
|
|
|
|
default:
|
|
PrintToConsole("Invalid type: %d\n", ErrorInfo.Parameters[i].ParameterType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Status2 = RpcErrorSaveErrorInfo(&EnumHandle, &Blob, &BlobSize);
|
|
CHECK_RET(Status2, "RpcErrorSaveErrorInfo");
|
|
RpcErrorClearInformation();
|
|
RpcErrorEndEnumeration(&EnumHandle);
|
|
Status2 = RpcErrorLoadErrorInfo(Blob, BlobSize, &EnumHandle);
|
|
CHECK_RET(Status2, "RpcErrorLoadErrorInfo");
|
|
}
|
|
}
|
|
|
|
CHECK_RET(status, "ClientConnect");
|
|
|
|
if (InSize > IN_ADJUSTMENT)
|
|
{
|
|
InSize -= IN_ADJUSTMENT;
|
|
}
|
|
else
|
|
{
|
|
InSize = 0;
|
|
}
|
|
|
|
if (OutSize > OUT_ADJUSTMENT)
|
|
{
|
|
OutSize -= OUT_ADJUSTMENT;
|
|
}
|
|
else
|
|
{
|
|
OutSize = 0;
|
|
}
|
|
|
|
gInSize = InSize;
|
|
gOutSize = OutSize;
|
|
|
|
PrintToConsole("Client %ld connected\n", ClientId);
|
|
|
|
Retries = 15;
|
|
|
|
do
|
|
{
|
|
RpcTryExcept
|
|
{
|
|
RpcErr = RPC_S_OK;
|
|
|
|
Time = GetTickCount();
|
|
|
|
Calls = ( (TestTable[Test])(&binding, stringBinding, ClientId, pBuffer) );
|
|
|
|
Time = GetTickCount() - Time;
|
|
|
|
Dump("Completed %d calls in %d ms\n"
|
|
"%d T/S or %3d.%03d ms/T\n\n",
|
|
Calls,
|
|
Time,
|
|
(Calls * 1000) / Time,
|
|
Time / Calls,
|
|
((Time % Calls) * 1000) / Calls
|
|
);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
RpcErr = (unsigned long)RpcExceptionCode();
|
|
PrintToConsole("\nException %lu (0x%08lX)\n",
|
|
RpcErr, RpcErr);
|
|
}
|
|
RpcEndExcept
|
|
Retries --;
|
|
if ((RpcErr == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0))
|
|
{
|
|
PrintToConsole("Server too busy - retrying ...\n");
|
|
}
|
|
}
|
|
while ((RpcErr == RPC_S_SERVER_UNAVAILABLE) && (Retries > 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;
|
|
DWORD dwStat1, dwStat2, dwStat3, dwStat4;
|
|
|
|
InitAllocator();
|
|
|
|
ulSecurityPackage = RPC_C_AUTHN_WINNT;
|
|
ParseArgv(argc, argv);
|
|
|
|
PrintToConsole("Authentication Level is: %s\n", AuthnLevelStr);
|
|
|
|
if (Options[0] < 0)
|
|
Options[0] = 1;
|
|
|
|
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());
|
|
}
|
|
|
|
#ifdef STATS
|
|
I_RpcGetStats(&dwStat1, &dwStat2, &dwStat3, &dwStat4);
|
|
printf("Stats are: %ld, %ld, %ld, %ld\n", dwStat1, dwStat2, dwStat3, dwStat4);
|
|
#endif
|
|
|
|
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
|
|
|