1168 lines
33 KiB
C
1168 lines
33 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
}
|