599 lines
14 KiB
C
599 lines
14 KiB
C
// 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 (c) 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_PKT_PRIVACY;
|
|
|
|
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);
|
|
}
|
|
|