CLIENT.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 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); 
}