windows-nt/Source/XPSP1/NT/com/rpc/perf/datatran/server/server.c

1168 lines
33 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (C) Microsoft Corporation, 1994 - 1999
Module Name:
Server.c
Abstract:
Server side of RPC runtime performance test.
Author:
Mario Goertzel (mariogo) 31-Mar-1994
Revision History:
--*/
#include <rpcperf.h>
#include <assert.h>
#include <DataTran.h>
#include <DTCommon.h>
// Usage
const char *USAGE =
"[-i iterations] [-l logfile] [-n Clients] [-n MinThreads]\n"
"\t\t[-c ChunkSize] [-z size] [-d FtpRoot] [-w WwwRoot] [-n case] *\n"
" Clients - default 1\n"
" MinThreads - default 3\n"
" FtpRoot - root directory for ftp\n"
" required for FTP tests\n"
" WwwRoot - root diretory for Http\n"
" required for HTTP tests\n"
" Size - default 50k,100k,200k,400k\n"
" ChunkSize - default 4000,8192,32768\n"
" filename - you may specify a file to transfer (not implemented yet)\n\n"
" Cases, you may specify up to five, default is all:\n"
" 0: Write using RPC\n"
" 1: Read using RPC\n"
" 2: Write using RPC Pipes\n"
" 3: Read using RPC Pipes\n"
" 4: Write using FTP (InternetReadFile)\n"
" 5: Read using FTP (InternetWriteFile)\n"
" 6: Write using HTTP Get\n"
" 7: Read using HTTP Put\n"
" 8: Write using RPC with File I/O\n"
" 9: Read using RPC with File I/O\n"
" 10: Write using RPC Pipes with File I/O\n"
" 11: Read using RPC Pipes with File I/O\n"
" 12: Write using FTP\n"
" 13: Read using FTP\n"
" 14: Write using FTP (InternetReadFile) with File I/O\n"
" 15: Read using FTP (InternetWriteFile) with File I/O\n"
" 16: Write using HTTP Get with File I/O\n"
" 17: Read using HTTP Put\n"
"\n"
" Note: Results are milliseconds/call/client\n"
;
//
// Globals making it easier.
//
int CurrentChunkIndex;
int CurrentTotalIndex;
int CurrentCase;
char TestCases[TEST_MAX];
char *pFtpRoot = NULL; // Root Directory used for FTP
char *pWwwRoot = NULL; // Root Directory used for HTTP
//
// If this is non-NULL, then use this file instead of creating
// temporary ones. Not implemented...
//
char *pFileName = 0;
long CurrentIter;
unsigned long *Results;
long Clients, ActiveClients, ClientsLeft;
CRITICAL_SECTION CritSec;
HANDLE GoEvent = 0;
HANDLE DoneEvent = 0;
char *TestNames[TEST_MAX] =
{
"S to C RPC : %9ld / %7ld",
"C to S RPC : %9ld / %7ld",
"S to C Pipes : %9ld / %7ld",
"C to S Pipes : %9ld / %7ld",
"S to C FTP1 : %9ld / %7ld",
"C to S FTP1 : %9ld / %7ld",
"S to C HTTP : %9ld / %7ld",
"C to S HTTP : %9ld / %7ld",
"S to C RPC w/File : %9ld / %7ld",
"C to S RPC w/File : %9ld / %7ld",
"S to C Pipes w/File : %9ld / %7ld",
"C to S Pipes w/File : %9ld / %7ld",
"S to C FTP w/File : %9ld / %7ld",
"C to S FTP w/File : %9ld / %7ld",
"S to C FTP1 w/File : %9ld / %7ld",
"C to S FTP1 w/File : %9ld / %7ld",
"S to C HTTP w/File : %9ld / %7ld",
"C to S HTTP w/File : %9ld / %7ld"
};
//
// These arrays are NULL terminated. Don't let the last entry get used!
//
unsigned long ChunkSizes[10] = {4000, 8192, 32*1024L, 0, 0, 0, 0, 0, 0, 0};
unsigned long TotalSizes[10] = {50L*1024L, 100L*1024L, 200L*1024L, 400L*1024L, 0,
0, 0, 0, 0, 0};
///////////////////////////////////////////////////////////////////////////////
/*++
FUNCTION: DTParseArgv
DESCRIPTION: Parses arguments
--*/
static void DTParseArgv(int argc, char **argv)
{
int fMissingParm = 0;
char *Name = *argv;
char option;
int options_count;
int totalsize_count = 0;
int chunksize_count = 0;
for(options_count = 0; options_count < 7; options_count++)
Options[options_count] = -1;
options_count = 0;
argc--;
argv++;
while(argc)
{
if (**argv != '/' &&
**argv != '-')
{
printf("Invalid switch: %s\n", *argv);
argc--;
argv++;
}
else
{
option = argv[0][1];
argc--;
argv++;
// Most switches require a second command line arg.
if (argc < 1)
fMissingParm = 1;
switch(option)
{
case 'e':
Endpoint = *argv;
argc--;
argv++;
break;
case 't':
Protseq = *argv;
argc--;
argv++;
break;
case 's':
NetworkAddr = *argv;
argc--;
argv++;
break;
case 'i':
Iterations = atoi(*argv);
argc--;
argv++;
if (Iterations == 0)
Iterations = 10;
break;
case 'm':
MinThreads = atoi(*argv);
argc--;
argv++;
if (MinThreads == 0)
MinThreads = 1;
break;
case 'a':
AuthnLevelStr = *argv;
argc--;
argv++;
break;
case 'n':
if (options_count < 7)
{
Options[options_count] = atoi(*argv);
options_count++;
}
else
printf("Maximum of seven -n switchs, extra ignored.\n");
argc--;
argv++;
break;
case 'l':
LogFileName = *argv;
argc--;
argv++;
break;
#ifdef __RPC_WIN16__
case 'y':
RpcWinSetYieldInfo(0, FALSE, 0, 0);
fMissingParm = 0;
break;
#endif
case 'z':
if (totalsize_count < 9)
{
TotalSizes[totalsize_count++] = atol(*argv);
TotalSizes[totalsize_count] = 0;
}
else printf("Maximum of 9 -z switches, extra ignored.\n");
argc--;
argv++;
break;
case 'c':
if (chunksize_count < 9)
{
ChunkSizes[chunksize_count++] = atoi(*argv);
ChunkSizes[chunksize_count] = 0;
}
else printf("Maximum of 9 -c switches, extra ignored.\n");
argc--;
argv++;
break;
case 'd':
pFtpRoot = *argv;
argc--;
argv++;
break;
case 'w':
pWwwRoot = *argv;
argc--;
argv++;
break;
default:
fMissingParm = 0;
printf("Usage: %s: %s\n", Name, USAGE);
exit(0);
break;
}
if (fMissingParm)
{
printf("Invalid switch %s, missing required parameter\n", *argv);
}
}
} // while argc
// determine the security level
if (strcmp("none", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
else if (strcmp("connect", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
else if (strcmp("call", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_CALL;
else if (strcmp("pkt", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_PKT;
else if (strcmp("integrity", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
else if (strcmp("privacy", AuthnLevelStr) == 0)
AuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
else
{
printf("%s is NOT a valid authentication level, default is NONE\n", AuthnLevelStr);
}
#if 0
printf("Config: %s:%s[%s]\n"
"Iterations: %d\n"
"Server threads %d\n"
"Options: %d %d %d\n",
Protseq, NetworkAddr, Endpoint, Iterations, MinThreads,
Options[0], Options[1], Options[2]);
#endif
#ifdef WIN32
printf("Process ID: %d\n", GetCurrentProcessId());
#else
#endif
return;
}
/////////////////////////////////////////////////////////////////////
// Figure out what we're testing and start listening.
//
int __cdecl
main (int argc, char **argv)
{
unsigned int MinThreads;
unsigned long i, status;
RPC_BINDING_VECTOR *pBindingVector;
DTParseArgv(argc, argv);
MinThreads = 3;
ClientsLeft = Clients = 1;
ActiveClients = 0;
Iterations = 1;
if (Options[0] > 0) ClientsLeft = Clients = Options[0]; // Clients
Results = MIDL_user_allocate(4 * Clients);
if (Options[1] > 0) MinThreads = Options[1]; // MinThreads
if (Options[2] < 0)
{
memset(TestCases, 1, TEST_MAX); // Default: Run all tests
//
// HTTP PUT doesn't work. Don't do these tests by default.
//
TestCases[RECV_BUFFER_HTTP] = 0;
TestCases[RECV_FILE_HTTP] = 0;
//
// Don't do internet tests if the
// -d or the -w switches aren't set appropriately
//
if (NULL == pFtpRoot)
{
TestCases[SEND_BUFFER_FTP1] = 0;
TestCases[RECV_BUFFER_FTP1] = 0;
TestCases[SEND_FILE_FTP] = 0;
TestCases[RECV_FILE_FTP] = 0;
TestCases[SEND_FILE_FTP1] = 0;
TestCases[RECV_FILE_FTP1] = 0;
}
if (NULL == pWwwRoot)
{
TestCases[SEND_BUFFER_HTTP] = 0;
TestCases[RECV_BUFFER_HTTP] = 0;
TestCases[SEND_FILE_HTTP] = 0;
TestCases[RECV_FILE_HTTP] = 0;
}
}
else // else run specified tests
{
memset(TestCases, 0, TEST_MAX);
for(i = 2; i < 7; i++)
{
if ( (Options[i] < 0) || (Options[i] >= TEST_MAX) ) break;
TestCases[Options[i]] = 1;
}
}
//
// See make sure that there are tests to run
// and set CurrentCase to the first one.
//
CurrentCase = 0;
for(i = 0; i < TEST_MAX; i++)
{
if (TestCases[i])
{
CurrentCase = i;
break;
}
}
if ( (pFileName == 0) && (i == TEST_MAX))
{
printf("No test cases selected!\n");
return 1;
}
if (ChunkSizes[0] == 0)
{
printf("Chunk Size must be non-zero.\n");
return 1;
}
if ( (pFileName == 0) && (TotalSizes[0] == 0))
{
printf("Total Size must be non-zero.\n");
return 1;
}
CurrentIter = Iterations;
if (CurrentIter == 0) CurrentIter = 1;
CurrentChunkIndex = 0;
CurrentTotalIndex = 0;
InitializeCriticalSection(&CritSec);
GoEvent = CreateEvent(0,
TRUE,
FALSE,
0);
DoneEvent = CreateEvent(0,
TRUE,
FALSE,
0);
//
// Actually start the server
//
printf("FTP Directory: %s\n", (0 == pFtpRoot ? "<NONE>": pFtpRoot));
printf("WWW Directory: %s\n", (0 == pWwwRoot ? "<NONE>": pWwwRoot));
if (Endpoint)
{
status = RpcServerUseProtseqEp(Protseq, 100, Endpoint, 0);
CHECK_STATUS(status, "RpcServerUseProtseqEp");
}
else
{
char *string_binding;
status = RpcServerUseProtseq(Protseq, 100, 0);
CHECK_STATUS(status, "RpcServerUseProtseqEp");
status = RpcServerInqBindings(&pBindingVector);
CHECK_STATUS(status, "RpcServerInqBindings");
status = RpcEpRegister(DataTranPerf_v1_0_s_ifspec,
pBindingVector,
0,
0);
CHECK_STATUS(status, "RpcEpRegister");
status = RpcBindingToStringBinding(pBindingVector->BindingH[0],
&string_binding);
CHECK_STATUS(status, "RpcBindingToStringBinding");
status = RpcStringBindingParse(string_binding,
0, 0, 0, &Endpoint, 0);
CHECK_STATUS(status, "RpcStringBindingParse");
printf("Listening to %s:[%s]\n\n", Protseq, Endpoint);
}
status = RpcServerRegisterIf(DataTranPerf_v1_0_s_ifspec,0,0);
CHECK_STATUS(status, "RpcServerRegisterIf");
status = RpcServerRegisterAuthInfo(NULL,
RPC_C_AUTHN_WINNT,
NULL,
NULL);
CHECK_STATUS(status, "RpcServerRegisterAuthInfo");
printf("Base Iterations: %d, Clients %d, MinThreads %d\n",
Iterations,
Clients,
MinThreads);
printf("Server listening\n");
status = RpcServerListen(MinThreads, 100, 0);
CHECK_STATUS(status, "RpcServerListen");
printf("This doesn't stop listening..hmm\n");
}
/********************************************************************
* Control APIs that the client(s) call to sync on test cases, iterations
* and to report results.
********************************************************************/
error_status_t
BeginTest(handle_t b,
long *ClientId)
{
long status = 0;
EnterCriticalSection(&CritSec);
if (ActiveClients < Clients)
{
ActiveClients++;
*ClientId = ActiveClients;
}
else
{
status = PERF_TOO_MANY_CLIENTS;
}
LeaveCriticalSection(&CritSec);
return status;
}
//---------------------------------------------------------
error_status_t
NextTest(handle_t b,
TEST_TYPE *Test,
long *Iters,
long *Length,
long *ChunkSize)
{
long wait = 1;
long done = 0;
int i;
EnterCriticalSection(&CritSec);
*Test = CurrentCase;
*Iters = CurrentIter;
*ChunkSize = ChunkSizes[CurrentChunkIndex];
*Length = TotalSizes[CurrentTotalIndex];
ClientsLeft--;
if (CurrentCase == TEST_MAX)
{
done = 1;
}
if (ClientsLeft == 0)
{
//
// Let all the waiting clients go
//
wait = 0;
ResetEvent(DoneEvent);
SetEvent(GoEvent);
}
LeaveCriticalSection(&CritSec);
if (wait)
{
WaitForSingleObject(GoEvent, INFINITE);
}
if (done)
{
if (ClientsLeft == 0)
{
// I'm the last client, sleep and then reset for
// a new set of clients. Sleep avoids a race (usually).
Sleep(1000);
//
// Reset CurrentCase
//
for(i = 0; i < TEST_MAX; i++)
{
if (TestCases[i])
{
CurrentCase = i;
break;
}
}
CurrentIter = Iterations;
if (CurrentIter == 0) CurrentIter = 1;
ActiveClients = 0;
ClientsLeft = Clients;
ResetEvent(GoEvent);
ResetEvent(DoneEvent);
}
return PERF_TESTS_DONE;
}
return 0;
}
//---------------------------------------------------------
error_status_t
EndTest(handle_t b,
unsigned long mseconds)
{
long status, i;
long wait = 1;
char szTempString[80];
EnterCriticalSection(&CritSec);
Results[ClientsLeft] = mseconds;
ClientsLeft++;
if (ClientsLeft == Clients)
{
// All clients have finished
// Report results
if (pFileName == 0)
{
sprintf(szTempString,
TestNames[CurrentCase],
TotalSizes[CurrentTotalIndex],
ChunkSizes[CurrentChunkIndex]),
printf("| % 3d | %-40s | % 4d |",
CurrentCase,
szTempString,
CurrentIter
);
}
else
{
printf("Liar! The filename option ain't implemented yet");
exit(0);
}
for(i = 0; i < Clients; i++)
printf(" % 7d.%03d |",
Results[i] / CurrentIter,
Results[i] % CurrentIter * 1000 / CurrentIter
);
printf("\n");
//
// Find next case...
//
for(i = CurrentCase + 1; i < TEST_MAX; i++)
if (TestCases[i])
{
CurrentCase = i;
break;
}
if (i == TEST_MAX)
{
if (ChunkSizes[++CurrentChunkIndex] == 0)
{
CurrentChunkIndex = 0;
if (TotalSizes[++CurrentTotalIndex] == 0)
{
//
// This tells NextTest that we're done.
//
CurrentCase = TEST_MAX;
printf("TEST DONE\n");
}
}
if (TEST_MAX != CurrentCase)
{
int i;
//
// Go back to the first case.
//
for(i = 0; i < TEST_MAX; i++)
{
if (TestCases[i])
{
CurrentCase = i;
break;
}
}
}
}
CurrentIter = Iterations;
if (CurrentIter == 0) CurrentIter = 1;
//
// We're setup for the next test (or to finish) let the clients go.
//
wait = 0;
ResetEvent(GoEvent);
SetEvent(DoneEvent);
}
LeaveCriticalSection(&CritSec);
if (wait)
WaitForSingleObject(DoneEvent, INFINITE);
return 0;
}
//---------------------------------------------------------
//
// For fixed endpoint and re-bind test case
//
unsigned char *GetFixedEp(handle_t h)
{
char *r;
r = malloc(strlen(Endpoint) + 1);
strcpy(r, Endpoint);
return (unsigned char *)r;
}
void GetServerName (handle_t b,
unsigned long int BufferSize,
unsigned char *szServer)
{
if (FALSE == GetComputerName (szServer, &BufferSize))
{
*szServer = 0;
}
}
//===================================================================
// File Context Stuff
//===================================================================
typedef struct
{
HANDLE hFile;
TCHAR FileName[MAX_PATH];
} DT_S_FILE_HANDLE;
//---------------------------------------------------------
DT_FILE_HANDLE RemoteOpen (handle_t b, unsigned long ulLength)
/*++
FUNCTION: RemoteOpen
DESCRIPTION: Opens a temporary file and return a handle to client
--*/
{
DT_S_FILE_HANDLE *pFileContext = NULL;
pFileContext = (DT_S_FILE_HANDLE *)MIDL_user_allocate(sizeof(DT_S_FILE_HANDLE));
if (pFileContext == NULL)
{
printf("RemoteOpen: Out of memory!\n");
return (DT_FILE_HANDLE) NULL;
}
//
// If Length is zero, the file is opened for receive from the client.
// So we use the prefix FSR (Server Receive); otherwise we use FSS.
//
CreateTempFile (NULL,
(0 == ulLength ? TEXT("FSR") : TEXT("FSS")),
ulLength,
(LPTSTR) pFileContext->FileName);
pFileContext->hFile = CreateFile ((LPTSTR) pFileContext->FileName,
(ulLength == 0 ? GENERIC_WRITE : GENERIC_READ),
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (pFileContext->hFile == INVALID_HANDLE_VALUE)
{
printf("RemoteOpen: Cannot create temp file!\n");
MIDL_user_free (pFileContext);
return (DT_FILE_HANDLE) NULL;
}
return ((DT_FILE_HANDLE) pFileContext);
}
//---------------------------------------------------------
DT_FILE_HANDLE RemoteCreateFtpFile (handle_t Binding,
boolean f_StoC,
unsigned long ulLength,
unsigned long ulBufferSize,
unsigned char *szRemotePath)
{
DT_S_FILE_HANDLE *pFileContext = NULL;
unsigned long iTheFileName;
//
// Is the FTP Root directory specified?
//
if (NULL == pFtpRoot)
{
printf("RemoteCreateFtpFile: FTP Root Path not set.\n");
return (DT_FILE_HANDLE) NULL;
}
//
// Allocate memory for the context handle
//
pFileContext = (DT_S_FILE_HANDLE *)MIDL_user_allocate(sizeof(DT_S_FILE_HANDLE));
if (pFileContext == NULL)
{
printf("RemoteCreateFtpFile: Out of memory!\n");
return (DT_FILE_HANDLE) NULL;
}
//
// This file is dealt with by the FTP server, so we don't need a handle to it.
// However, we need the file name so we can delete it later.
//
pFileContext->hFile = INVALID_HANDLE_VALUE;
//
// Create a temp file to be sent to the client
//
if (FALSE == CreateTempFile (pFtpRoot,
(TRUE == f_StoC ? TEXT("FSS") : TEXT("FSR")),
(TRUE == f_StoC ? ulLength : 0),
pFileContext->FileName))
{
MIDL_user_free (pFileContext);
return (DT_FILE_HANDLE) NULL;
}
//
// We want to tell the client the actual filename only - no path.
//
for (iTheFileName = lstrlen (pFileContext->FileName)-1;
iTheFileName>=0;
iTheFileName--)
{
if (pFileContext->FileName[iTheFileName] == (TCHAR)'\\')
{
break;
}
}
if ((ulBufferSize + iTheFileName ) < (unsigned long)lstrlen (pFileContext->FileName))
{
printf("RemoteCreateFtpFile: Buffer Size too small to hold path.\n");
MIDL_user_free (pFileContext);
return ((DT_FILE_HANDLE) NULL);
}
lstrcpy (szRemotePath, &(pFileContext->FileName[iTheFileName]));
return ((DT_FILE_HANDLE) pFileContext);
}
//---------------------------------------------------------
DT_FILE_HANDLE RemoteCreateHttpFile (handle_t Binding,
boolean f_StoC,
unsigned long ulLength,
unsigned long ulBufferSize,
unsigned char *szRemotePath)
{
DT_S_FILE_HANDLE *pFileContext = NULL;
unsigned long iTheFileName;
//
// Is the FTP Root directory specified?
//
if (NULL == pWwwRoot)
{
printf("RemoteCreateHttpFile: WWW Root Path not set.\n");
return (DT_FILE_HANDLE) NULL;
}
//
// Allocate memory for the context handle
//
pFileContext = (DT_S_FILE_HANDLE *)MIDL_user_allocate(sizeof(DT_S_FILE_HANDLE));
if (pFileContext == NULL)
{
printf("RemoteCreateHttpFile: Out of memory!\n");
return (DT_FILE_HANDLE) NULL;
}
//
// This file is dealt with by the HTTP server, so we don't need a handle to it.
// However, we need the file name so we can delete it later.
//
pFileContext->hFile = INVALID_HANDLE_VALUE;
//
// Create a temp file to be sent to the client
//
if (FALSE == CreateTempFile (pWwwRoot,
(TRUE == f_StoC ? TEXT("FSS") : TEXT("FSR")),
(TRUE == f_StoC ? ulLength : 0),
pFileContext->FileName))
{
MIDL_user_free (pFileContext);
return (DT_FILE_HANDLE) NULL;
}
//
// We want to tell the client the actual filename only - no path.
//
for (iTheFileName = lstrlen (pFileContext->FileName)-1;
iTheFileName>=0;
iTheFileName--)
{
if (pFileContext->FileName[iTheFileName] == (TCHAR)'\\')
{
break;
}
}
if ((ulBufferSize + iTheFileName ) < (unsigned long)lstrlen (pFileContext->FileName))
{
printf("RemoteCreateHttpFile: Buffer Size too small to hold path.\n");
MIDL_user_free (pFileContext);
return ((DT_FILE_HANDLE) NULL);
}
lstrcpy (szRemotePath, &(pFileContext->FileName[iTheFileName]));
if ((TCHAR)'\\' == szRemotePath[0])
{
szRemotePath[0] = (TCHAR)'/';
}
return ((DT_FILE_HANDLE) pFileContext);
}
//---------------------------------------------------------
void RemoteResetFile (DT_FILE_HANDLE phContext)
{
assert (NULL != phContext);
if (INVALID_HANDLE_VALUE != ((DT_S_FILE_HANDLE *)phContext)->hFile)
{
SetFilePointer (((DT_S_FILE_HANDLE *)phContext)->hFile,
0,
NULL,
FILE_BEGIN);
}
}
//---------------------------------------------------------
void __RPC_USER DT_FILE_HANDLE_rundown(DT_FILE_HANDLE phContext)
{
if (phContext)
{
if (((DT_S_FILE_HANDLE *)phContext)->hFile != INVALID_HANDLE_VALUE)
CloseHandle(((DT_S_FILE_HANDLE *)phContext)->hFile);
MIDL_user_free (phContext);
}
}
//---------------------------------------------------------
void RemoteClose (DT_FILE_HANDLE *pp, boolean fDelete)
{
assert ( (NULL != *pp) &&
(NULL != **(DT_S_FILE_HANDLE **)pp)
);
if (INVALID_HANDLE_VALUE != (*(DT_S_FILE_HANDLE **)pp)->hFile)
{
CloseHandle((*(DT_S_FILE_HANDLE **)pp)->hFile);
}
if (TRUE == fDelete)
{
DeleteFile((*(DT_S_FILE_HANDLE **)pp)->FileName);
}
MIDL_user_free(*pp);
*pp = NULL;
}
//===================================================================
// Memory Handle stuff
// - Each thread that uses the pipes tests will need a buffer
// to push or pull data. This is achieved through this memory
// context handle.
//===================================================================
typedef struct
{
unsigned char __RPC_FAR *pPtr;
unsigned long ulLength;
} DT_S_MEM_HANDLE;
//---------------------------------------------------------
DT_MEM_HANDLE RemoteAllocate (handle_t h, unsigned long ulLength)
{
DT_S_MEM_HANDLE *pMemContext = NULL;
pMemContext = (DT_S_MEM_HANDLE *)MIDL_user_allocate(sizeof(DT_S_MEM_HANDLE));
if (pMemContext == NULL)
{
printf("RemoteAllocate: Out of memory!\n");
return (DT_FILE_HANDLE) NULL;
}
pMemContext->pPtr = (unsigned char __RPC_FAR *)MIDL_user_allocate(ulLength);
if (pMemContext->pPtr == NULL)
{
printf("RemoteAllocate: Out of memory!\n");
MIDL_user_free (pMemContext);
return (DT_FILE_HANDLE) NULL;
}
pMemContext->ulLength = ulLength;
return (DT_MEM_HANDLE) pMemContext;
}
//---------------------------------------------------------
void __RPC_USER DT_MEM_HANDLE_rundown(DT_MEM_HANDLE phContext)
{
printf("DT_MEM_HANDLE_rundown Entered\n");
if (phContext)
{
if (((DT_S_MEM_HANDLE *)phContext)->pPtr != NULL)
MIDL_user_free(((DT_S_MEM_HANDLE *)phContext)->pPtr);
MIDL_user_free (phContext);
}
printf("DT_MEM_HANDLE_rundown Exited\n");
}
//---------------------------------------------------------
void RemoteFree (DT_MEM_HANDLE *pMemContext)
{
assert( ((*(DT_S_MEM_HANDLE **)pMemContext) != NULL) &&
((*(DT_S_MEM_HANDLE **)pMemContext)->pPtr != NULL)
);
//
// Free the block of memory
//
MIDL_user_free ((*(DT_S_MEM_HANDLE **)pMemContext)->pPtr);
(*(DT_S_MEM_HANDLE **)pMemContext)->pPtr = NULL;
//
// Then free the handle itself!
//
MIDL_user_free (*pMemContext);
*pMemContext = (DT_MEM_HANDLE) NULL;
}
//===================================================================
// Regular RPCs
//===================================================================
void C_to_S_Buffer (handle_t h, unsigned long int BufferSize, byte Buffer[])
{
return;
}
//---------------------------------------------------------
void S_to_C_Buffer (handle_t h, unsigned long int BufferSize, byte Buffer[])
{
return;
}
//---------------------------------------------------------
void C_to_S_BufferWithFile (handle_t h,
DT_FILE_HANDLE pContext,
unsigned long int BufferSize,
byte Buffer[])
{
long dwBytesWritten;
WriteFile(((DT_S_FILE_HANDLE *)pContext)->hFile,
Buffer,
BufferSize,
&dwBytesWritten,
NULL);
}
//---------------------------------------------------------
long S_to_C_BufferWithFile (handle_t h,
DT_FILE_HANDLE pContext,
unsigned long int BufferSize,
byte Buffer[])
{
unsigned long dwBytesRead;
ReadFile(((DT_S_FILE_HANDLE *)pContext)->hFile,
Buffer,
BufferSize,
&dwBytesRead,
NULL);
return dwBytesRead;
}
//===================================================================
// RPC Pipes
//===================================================================
void S_to_C_Pipe(handle_t h,
UCHAR_PIPE ThePipe,
unsigned long ulLength,
DT_MEM_HANDLE pMemHandle)
{
unsigned long dwBytesSent;
while (ulLength >= ((DT_S_MEM_HANDLE *)pMemHandle)->ulLength)
{
(ThePipe.push) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
((DT_S_MEM_HANDLE *)pMemHandle)->ulLength);
ulLength -= ((DT_S_MEM_HANDLE *)pMemHandle)->ulLength;
}
if (ulLength != 0)
{
(ThePipe.push) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
ulLength);
}
(ThePipe.push) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
0);
}
//---------------------------------------------------------
void C_to_S_Pipe (handle_t h,
UCHAR_PIPE ThePipe,
DT_MEM_HANDLE pMemHandle)
{
unsigned long nBytesReceived;
for(;;)
{
(ThePipe.pull) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
((DT_S_MEM_HANDLE *)pMemHandle)->ulLength,
&nBytesReceived);
if (nBytesReceived == 0) break;
}
}
//---------------------------------------------------------
void S_to_C_PipeWithFile (handle_t h,
UCHAR_PIPE ThePipe,
DT_FILE_HANDLE pContext,
DT_MEM_HANDLE pMemHandle)
{
unsigned long dwBytesRead;
for(;;)
{
ReadFile(((DT_S_FILE_HANDLE *)pContext)->hFile,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
((DT_S_MEM_HANDLE *)pMemHandle)->ulLength,
&dwBytesRead,
NULL);
(ThePipe.push) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
dwBytesRead);
if (dwBytesRead == 0) break;
}
}
//---------------------------------------------------------
void C_to_S_PipeWithFile (handle_t h,
UCHAR_PIPE ThePipe,
DT_FILE_HANDLE pContext,
DT_MEM_HANDLE pMemHandle)
{
unsigned long nBytesReceived;
unsigned long dwBytesWritten;
for(;;)
{
(ThePipe.pull) (ThePipe.state,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
((DT_S_MEM_HANDLE *)pMemHandle)->ulLength,
&nBytesReceived);
if (nBytesReceived == 0) break;
WriteFile(((DT_S_FILE_HANDLE *)pContext)->hFile,
((DT_S_MEM_HANDLE *)pMemHandle)->pPtr,
nBytesReceived,
&dwBytesWritten,
NULL);
}
}