// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1995 - 1998 Microsoft Corporation. All Rights Reserved.
//
// MODULE: client.c
//
// PURPOSE: This program is a command line oriented
// demonstration of the Simple RPC service sample.
//
// FUNCTIONS:
// main(int argc, char **argv);
// StartTime()
// EndTime();
// DoTimings();
//
// COMMENTS:
//
// AUTHOR:
// Mario Goertzel - RPC Development
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <rpc.h>
#include "rpcsvc.h"
void Usage(void)
{
printf("Usage:\n"
"\t-n <server addr> - Defaults to local machine\n"
"\t-t <protseq> - Defaults to ncalrpc (fast, local only)\n"
"\t-i <iterations> - Defaults to 100\n"
"\t-s <security lvl> - Default none, range none (1) to privacy (6)\n"
);
return;
}
//
// FUNCTIONS: StartTime()
// EndTime()
//
// USAGE:
// StartTime();
// // Do some work.
// mseconds = EndTime();
//
// RETURN VALUE:
// Milliseconds between StartTime() and EndTime() calls.
LARGE_INTEGER Time;
void StartTime(void)
{
QueryPerformanceCounter(&Time);
}
ULONG EndTime()
{
LARGE_INTEGER liDiff;
LARGE_INTEGER liFreq;
QueryPerformanceCounter(&liDiff);
liDiff.QuadPart -= Time.QuadPart;
liDiff.QuadPart *= 1000; // Adjust to milliseconds, shouldn't overflow...
(void)QueryPerformanceFrequency(&liFreq);
return ((ULONG)(liDiff.QuadPart / liFreq.QuadPart));
}
//
// FUNCTION: DoTimings
//
// PURPOSE: Calls and times various RPC calls.
// (Avoid cluttering up main())
//
// PARAMETERS:
// Binding - Binding to the server.
// iIterations - Number of times to make each call.
//
// RETURN VALUE:
// n/a
//
//
void DoTimings(RPC_BINDING_HANDLE Binding,
UINT iIterations)
{
ULONG mseconds;
UINT i;
RPC_STATUS status;
byte bBuffer[4096];
ULONG lBufferLength;
ULONG lBufferSize;
// Time Pings() (void calls)
StartTime();
for(i = iIterations; i; i--)
{
status = Ping(Binding);
if (status != RPC_S_OK)
goto Cleanup;
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - void calls.\n", iIterations, mseconds);
// Time [in] buffer's
//
lBufferLength = BUFFER_SIZE;
lBufferSize = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferIn1(Binding, bBuffer, lBufferLength, lBufferSize);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer in (1).\n", iIterations, mseconds);
lBufferLength = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferIn3(Binding, bBuffer, lBufferLength);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer in (2).\n", iIterations, mseconds);
lBufferLength = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferIn3(Binding, bBuffer, lBufferLength);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer in (3).\n", iIterations, mseconds);
// Time [out] buffer's
lBufferLength = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferOut1(Binding, bBuffer, &lBufferLength);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer out (1).\n", iIterations, mseconds);
lBufferLength = BUFFER_SIZE;
lBufferSize = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferOut2(Binding, bBuffer, lBufferSize, &lBufferLength);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer out (2).\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
BUFFER Buffer;
Buffer.BufferLength = 0;
Buffer.Buffer = 0;
status = BufferOut3(Binding, &Buffer);
if (status != RPC_S_OK)
{
goto Cleanup;
}
MIDL_user_free(Buffer.Buffer);
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer out (3).\n", iIterations, mseconds);
lBufferLength = BUFFER_SIZE;
StartTime();
for(i = iIterations; i; i--)
{
status = BufferOut4(Binding, bBuffer, &lBufferLength);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 100 byte buffer out (4).\n", iIterations, mseconds);
// Time arrays of structures
{
struct BAD1 abad1[50];
struct BAD2 abad2[50];
struct GOOD agood[50];
for (i = 0; i < 50; i++)
{
abad2[i].e = (BAD_ENUM)i % 4 + 1;
agood[i].e = (GOOD_ENUM)i % 4 + 5;
}
StartTime();
for(i = iIterations; i; i--)
{
status = StructsIn1(Binding, &abad1[0]);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - 2 mod 4 aligned structs.\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
status = StructsIn2(Binding, &abad2[0]);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - structs with an enum.\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
status = StructsIn3(Binding, &agood[0]);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - structs with v1_enum.\n", iIterations, mseconds);
}
// Linked lists
{
LIST list;
PLIST plist = &list;
for (i = 0; i < LIST_SIZE - 1; i++)
{
plist->pNext = MIDL_user_allocate(sizeof(LIST));
plist->data = i;
if (plist->pNext == 0)
{
status = RPC_S_OUT_OF_MEMORY;
goto Cleanup;
}
plist = plist->pNext;
}
plist->data = i;
plist->pNext = 0;
StartTime();
for(i = iIterations; i; i--)
{
status = ListIn(Binding, &list);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - [in] linked list.\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
status = ListOut1(Binding, &list);
if (status != RPC_S_OK)
{
goto Cleanup;
}
// Freeing the list here would cause all the elements
// to be allocated again on the next call.
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - [out] linked list (1).\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
status = ListOut2(Binding, &list);
if (status != RPC_S_OK)
{
goto Cleanup;
}
// Freeing the list here would cause all the elements
// to be allocated again on the next call.
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - [out] linked list (2).\n", iIterations, mseconds);
// Free allocated elements of the list.
plist = list.pNext;
while(plist)
{
PLIST tmp = plist;
plist = plist->pNext;
MIDL_user_free(tmp);
}
}
// Unions
{
BAD_UNION badunionArray[UNION_ARRAY_LEN];
GOOD_UNION goodunion;
ARM_ONE armone;
ULONG ulArray[UNION_ARRAY_LEN];
goodunion.Tag = 1;
goodunion.u.pOne = &armone;
armone.DataLength = UNION_ARRAY_LEN;
armone.Data = ulArray;
for(i = 0; i < UNION_ARRAY_LEN; i++)
{
ulArray[i] = i;
badunionArray[i].Tag = 1;
badunionArray[i].u.ulData = i;
}
StartTime();
for(i = iIterations; i; i--)
{
status = UnionCall1(Binding, UNION_ARRAY_LEN, badunionArray);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - [in] array of unions.\n", iIterations, mseconds);
StartTime();
for(i = iIterations; i; i--)
{
status = UnionCall2(Binding, &goodunion);
if (status != RPC_S_OK)
{
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - [in] union of arrays.\n", iIterations, mseconds);
}
// Time pings() (null calls) which impersonate the client.
StartTime();
for(i = iIterations; i; i--)
{
status = CheckSecurity(Binding);
if (status != RPC_S_OK)
{
if (status == RPC_S_ACCESS_DENIED)
{
printf("Access denied, try -s 2 or higher.\n");
return;
}
goto Cleanup;
}
}
mseconds = EndTime();
printf("%4d calls in %8d milliseconds - void call w/ impersonation\n", iIterations, mseconds);
Cleanup:
if (status != RPC_S_OK)
{
printf("Call failed - %d\n", status);
}
return;
}
//
// FUNCTION: main
//
// PURPOSE: Parses arguments and binds to the server.
//
// PARAMETERS:
// argc - number of command line arguments
// argv - array of command line arguments
//
// RETURN VALUE:
// Program exit code.
//
//
int main(int argc, char *argv[])
{
char *serverAddress = NULL;
char *protocol = "ncalrpc";
UINT iIterations = 100;
unsigned char *stringBinding;
RPC_BINDING_HANDLE Binding;
RPC_STATUS status;
ULONG SecurityLevel = RPC_C_AUTHN_LEVEL_NONE;
argc--;
argv++;
while(argc)
{
if ( argv[0][0] != '-'
&& argv[0][0] != '/')
{
Usage();
return(1);
}
switch(argv[0][1])
{
case 'n':
if (argc < 2)
{
Usage();
return(1);
}
serverAddress = argv[1];
argc--;
argv++;
break;
case 't':
if (argc < 2)
{
Usage();
return(1);
}
protocol = argv[1];
argc--;
argv++;
break;
case 'i':
if (argc < 2)
{
Usage();
return(1);
}
iIterations = atoi(argv[1]);
argc--;
argv++;
break;
case 's':
if (argc < 2)
{
Usage();
return(1);
}
SecurityLevel = atoi(argv[1]);
if (SecurityLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
{
Usage();
return(1);
}
argc--;
argv++;
break;
default:
Usage();
return(1);
break;
}
argc--;
argv++;
}
status = RpcStringBindingCompose(0,
protocol,
serverAddress,
0,
0,
&stringBinding);
if (status != RPC_S_OK)
{
printf("RpcStringBindingCompose failed - %d\n", status);
return(1);
}
status = RpcBindingFromStringBinding(stringBinding, &Binding);
if (status != RPC_S_OK)
{
printf("RpcBindingFromStringBinding failed - %d\n", status);
return(1);
}
status =
RpcBindingSetAuthInfo(Binding,
0,
SecurityLevel,
RPC_C_AUTHN_WINNT,
0,
0
);
if (status != RPC_S_OK)
{
printf("RpcBindingSetAuthInfo failed - %d\n", status);
return(1);
}
status = Ping(Binding);
if (status != RPC_S_OK)
{
printf("Ping failed - %d\n", status);
}
printf("Connected.\n");
//
// Call and time various RPC calls.
//
DoTimings(Binding, iIterations);
// Cleanup
status = RpcBindingFree(&Binding);
// ASSERT(status == RPC_S_OK):
status = RpcStringFree(&stringBinding);
// ASSERT(status == RPC_S_OK);
return(0);
}
void * __RPC_USER MIDL_user_allocate(size_t size)
{
return(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size));
}
void __RPC_USER MIDL_user_free( void *pointer)
{
HeapFree(GetProcessHeap(), 0, pointer);
}