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

580 lines
18 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1994 - 1999
//
// File: server.c
//
//--------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////
//
// Filename: server.c
//
// Description: This file contains the source code for IPC performance.
// This module is written using win32 API calls, and will
// generate a console server app.
//
// Authors: Scott Holden (Translator from NT API to win32 API)
// Mahesh Keni (Mahesh wrote this application using mostly
// NT native API calls)
//
/////////////////////////////////////////////////////////////////////////
#include "rawcom.h"
#include "server.h"
/************************************************************************/
// Global variables
/************************************************************************/
struct client Clients[MAXCLIENTS]; // all the client data
HANDLE Threads[MAXCLIENTS];
USHORT NClients = 1; // number of clients
USHORT IPCType = NP; // IPC type
LARGE_INTEGER Timeout; // for the main thread
CHAR Xport[9]; // Xport type Name
USHORT ThreadError = 0;
BOOLEAN Failure = FALSE;
// function pointers for redirecting calls according to Xport types
NTSTATUS (* IPC_Initialize)();
NTSTATUS (* IPC_PerClientInit)();
NTSTATUS (* IPC_Wait_For_Client)();
NTSTATUS (* IPC_Disconnect_Client)();
NTSTATUS (* IPC_Cleanup)();
NTSTATUS (* IPC_Allocate_Memory)();
NTSTATUS (* IPC_DoHandshake)();
NTSTATUS (* IPC_ReadFromIPC)();
NTSTATUS (* IPC_WriteToIPC)();
NTSTATUS (* IPC_XactIO)();
NTSTATUS (* IPC_Deallocate_Memory)();
NTSTATUS (* IPC_ThreadCleanUp)();
// Later all of this should move under an union
// Globals for NamedPipe
//OBJECT_ATTRIBUTES objectAttributes;
//UNICODE_STRING unicodePipeName;
char *pipeName;
ULONG Quotas = 32768; // read/write quota
ULONG PipeType = PIPE_TYPE_MESSAGE; // pipe type
ULONG PipeMode = PIPE_READMODE_MESSAGE; // read mode
ULONG BlockorNot = PIPE_NOWAIT; // non blocking
// Globals for NetBIOS
USHORT LanaCount = 1;
USHORT LanaBase = 0;
USHORT MachineNumber = 1;
UCHAR NameNumber = 1;
CHAR LocalName[NCBNAMSZ];
CHAR RemoteName[NCBNAMSZ];
// GLobals for Sockets
PCHAR ServerName = NULL; // local host ip address
PCHAR HostName = NULL; // local host ip address
int AddrFly;
/************************************************************************/
NTSTATUS
__cdecl main (
IN USHORT argc,
IN PSZ argv[],
IN PSZ envp[])
{
NTSTATUS mstatus;
USHORT Cindex = 0; // client index
//UCHAR NBretcode; // NetBIOS call return code
//USHORT LanaNumber;
// argc, argv, envp; // Shut up the compiler
mstatus = Parse_Cmd_Line(argc, argv);
if (!NT_SUCCESS(mstatus)) {
return(1);
}
// based on the Xport type set up all the function pointers
Setup_Function_Pointers();
// do IPC dependent initializing
mstatus = IPC_Initialize(NClients, HostName, SRV);
if (!NT_SUCCESS(mstatus)) {
return(1);
}
// now create worker threads for handling NetBIOS I/O requests
printf("Creating %s Server threads...", Xport);
for (Cindex = 0; Cindex < NClients; Cindex++) {
// do appropriate per client initialization
mstatus = IPC_PerClientInit(Cindex,SRV);
// use win32 API instead of NT native so that NetBIOS works fine
Clients[Cindex].c_hThHandle = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)&SrvService,
(PUSHORT)&(Clients[Cindex].c_client_num),
0,
(LPDWORD)&(Clients[Cindex].c_ThClientID));
Threads[Cindex] = Clients[Cindex].c_hThHandle; //*get rid of one handle
printf("%d..",Cindex+1);
}
printf("\n");
//The main thread should now wait for all the other threads
if (!mstatus) { // if no error then wait for everyone to sync
mstatus = Wait_For_Client_Threads();
if (!NT_SUCCESS(mstatus)) {
printf ("Failed on wait err=%lx\n",mstatus);
}
}
// now do the cleanup. i.e. clear all memory and close all handles
IPC_Cleanup(NClients);
exit(0);
} // main
/************************************************************************/
/*++
This routine sets up all the function pointers based on Xport type
I could just set one pointer to a function table supporting all the
functions and move all tis initialization in individual init routines.
Will be done in future.
--*/
VOID
Setup_Function_Pointers()
{
// based on Xport type take the action
switch(IPCType) {
case NP:
IPC_Initialize = NMP_Initialize;
IPC_PerClientInit = NMP_PerClientInit;
IPC_Wait_For_Client = NMP_Wait_For_Client;
IPC_Disconnect_Client = NMP_Disconnect_Client;
IPC_Cleanup = NMP_Cleanup;
IPC_Allocate_Memory = NMP_Allocate_Memory;
IPC_DoHandshake = NMP_DoHandshake;
IPC_ReadFromIPC = NMP_ReadFromIPC;
IPC_WriteToIPC = NMP_WriteToIPC;
IPC_XactIO = NMP_XactIO;
IPC_Deallocate_Memory = NMP_Deallocate_Memory;
IPC_ThreadCleanUp = NMP_ThreadCleanUp;
break;
case NB:
IPC_Initialize = NB_Initialize;
IPC_PerClientInit = NB_PerClientInit;
IPC_Cleanup = NB_Cleanup;
IPC_Wait_For_Client = NB_Wait_For_Client;
IPC_Disconnect_Client = NB_Disconnect_Client;
IPC_Allocate_Memory = NB_Allocate_Memory;
IPC_DoHandshake = NB_DoHandshake;
IPC_ReadFromIPC = NB_ReadFromIPC;
IPC_WriteToIPC = NB_WriteToIPC;
IPC_XactIO = NB_XactIO;
IPC_Deallocate_Memory = NB_Deallocate_Memory;
IPC_ThreadCleanUp = NB_ThreadCleanUp;
break;
case SCTCP:
IPC_Initialize = SCTCP_Initialize;
IPC_PerClientInit = SCTCP_PerClientInit;
IPC_Cleanup = SCTCP_Cleanup;
IPC_Wait_For_Client = SCTCP_Wait_For_Client;
IPC_Disconnect_Client = SCTCP_Disconnect_Client;
IPC_Allocate_Memory = SCTCP_Allocate_Memory;
IPC_DoHandshake = SCTCP_DoHandshake;
IPC_ReadFromIPC = SCTCP_ReadFromIPC;
IPC_WriteToIPC = SCTCP_WriteToIPC;
IPC_XactIO = SCTCP_XactIO;
IPC_Deallocate_Memory = SCTCP_Deallocate_Memory;
IPC_ThreadCleanUp = SCTCP_ThreadCleanUp;
break;
case SCXNS:
IPC_Initialize = SCXNS_Initialize;
IPC_PerClientInit = SCXNS_PerClientInit;
IPC_Wait_For_Client = SCXNS_Wait_For_Client;
IPC_Disconnect_Client = SCXNS_Disconnect_Client;
IPC_Cleanup = SCXNS_Cleanup;
IPC_Allocate_Memory = SCXNS_Allocate_Memory;
IPC_DoHandshake = SCXNS_DoHandshake;
IPC_ReadFromIPC = SCXNS_ReadFromIPC;
IPC_WriteToIPC = SCXNS_WriteToIPC;
IPC_XactIO = SCXNS_XactIO;
IPC_Deallocate_Memory = SCXNS_Deallocate_Memory;
IPC_ThreadCleanUp = SCXNS_ThreadCleanUp;
break;
case SCUDP:
IPC_Initialize = SCUDP_Initialize;
IPC_PerClientInit = SCUDP_PerClientInit;
IPC_Wait_For_Client = SCUDP_Wait_For_Client;
IPC_Disconnect_Client = SCUDP_Disconnect_Client;
IPC_Cleanup = SCUDP_Cleanup;
IPC_Allocate_Memory = SCUDP_Allocate_Memory;
IPC_DoHandshake = SCUDP_DoHandshake;
IPC_ReadFromIPC = SCUDP_ReadFromIPC;
IPC_WriteToIPC = SCUDP_WriteToIPC;
IPC_Deallocate_Memory = SCUDP_Deallocate_Memory;
IPC_ThreadCleanUp = SCUDP_ThreadCleanUp;
break;
case SCIPX:
IPC_Initialize = SCIPX_Initialize;
IPC_PerClientInit = SCIPX_PerClientInit;
IPC_Wait_For_Client = SCIPX_Wait_For_Client;
IPC_Disconnect_Client = SCIPX_Disconnect_Client;
IPC_Cleanup = SCIPX_Cleanup;
IPC_Allocate_Memory = SCIPX_Allocate_Memory;
IPC_DoHandshake = SCIPX_DoHandshake;
IPC_ReadFromIPC = SCIPX_ReadFromIPC;
IPC_WriteToIPC = SCIPX_WriteToIPC;
IPC_Deallocate_Memory = SCIPX_Deallocate_Memory;
IPC_ThreadCleanUp = SCIPX_ThreadCleanUp;
break;
case DGNB:
IPC_Initialize = DGNB_Initialize;
IPC_PerClientInit = DGNB_PerClientInit;
IPC_Cleanup = DGNB_Cleanup;
IPC_Wait_For_Client = DGNB_Wait_For_Client;
IPC_Disconnect_Client = DGNB_Disconnect_Client;
IPC_Allocate_Memory = DGNB_Allocate_Memory;
IPC_DoHandshake = DGNB_DoHandshake;
IPC_ReadFromIPC = DGNB_ReadFromIPC;
IPC_WriteToIPC = DGNB_WriteToIPC;
IPC_XactIO = DGNB_XactIO;
IPC_Deallocate_Memory = DGNB_Deallocate_Memory;
IPC_ThreadCleanUp = DGNB_ThreadCleanUp;
break;
default :
// problem here
printf("Incorrect Xport selection\n");
}
}
/************************************************************************/
/*++
This routine makes the main thread wait for all the client threads to
exit.
--*/
NTSTATUS
Wait_For_Client_Threads(VOID)
{
NTSTATUS wstatus;
DWORD MTimeout = INFINITE;
printf("Main thread waiting for Client threads ");
wstatus = WaitForMultipleObjectsEx(NClients,
Threads,
TRUE, // Wait for all objects
MTimeout, // Default timeout
TRUE); // Alertable
printf(".. Wait over with status:%lx\n",wstatus);
if (!NT_SUCCESS(wstatus)) {
printf ("Failed on wait err=%lx\n",wstatus);
}
if (ThreadError) {
printf("Thread Error: %d \n", ThreadError);
}
return wstatus;
}
/************************************************************************/
/*++
This routine is the thread service routine. It first waits for clients to
connect. Then it does a handshake to gather all the test info. Then it
services all requests.
--*/
VOID
SrvService( // provides server service
IN PUSHORT pTindex)
{
NTSTATUS tstatus;
USHORT tCindex;
//UCHAR RetCode;
BOOLEAN keepdoing;
BOOLEAN Terminate;
ULONG RecvLen = 0;
ULONG SendLen = 0;
ULONG Iterations = 0;
BOOLEAN First = TRUE;
tCindex = *pTindex;
keepdoing = TRUE;
ThreadError = 0;
Failure = FALSE;
do { // keep doing the work till it receives 'E' from client
//DbgPrint("Srv:Waiting for a client %d\n",tCindex);
// First post listen for a client's connection request
tstatus = IPC_Wait_For_Client(tCindex);
ThreadError = 1;
FAIL_CHECK(PERFSRV, " Wait for Client" , tstatus);
// now the thread has been connected
// now do the handshake to read the request message
tstatus = IPC_DoHandshake(tCindex,SRV);
ThreadError = 2;
FAIL_CHECK(PERFSRV, " Doing Handshake" , tstatus);
// allocate memory for data buffers and start the I/O
tstatus = IPC_Allocate_Memory(tCindex);
ThreadError = 3;
FAIL_CHECK(PERFSRV, " Memory Allocation" , tstatus);
// check if the client wants to quit.
// Set up number of iterations
Iterations = Clients[tCindex].c_reqbuf.Iterations;
Terminate = FALSE;
First = TRUE;
while (Iterations--) {
if (Clients[tCindex].c_reqbuf.TestCmd = 'P') {
// now the server has to first receive X messages and then
// send Y messages.
MyDbgPrint("Srv:Reading \n");
tstatus = IPC_ReadFromIPC( tCindex, &RecvLen,SRV);
ThreadError = 4;
FAIL_CHECK(PERFSRV, " Read from IPC" , tstatus);
// We can check for recv length and data integrity out here
MyDbgPrint("Srv:Writing \n");
tstatus = IPC_WriteToIPC( tCindex, &SendLen, SRV);
ThreadError = 5;
FAIL_CHECK(PERFSRV, " Read from IPC" , tstatus);
}
else { // for 'U' or 'T' do transct I/O
// We have to do something different for NetBIOS as
// it sould first post a receive and then do RecvSend for
// Other iterations. for Client this works fine as it always
// does send/Recv.
tstatus = IPC_XactIO( tCindex, &SendLen, &RecvLen, SRV,First);
// FAIL_CHECK(PERFSRV, " Xact IPC" , tstatus);
ThreadError = 6;
if (!NT_SUCCESS(tstatus)) {
if ((tstatus != STATUS_PIPE_BROKEN) &&
(tstatus != STATUS_INVALID_PIPE_STATE)) {
//DbgPrint("Error in XactIO: %lx \n", tstatus);
}
break;
}
First = FALSE;
}
}
// now we are done with the current tests so do the cleanup and
// start all over again
tstatus = IPC_Disconnect_Client(tCindex);
ThreadError = 7;
FAIL_CHECK(PERFSRV, " Disconnect Client " , tstatus);
tstatus = IPC_Deallocate_Memory(tCindex);
ThreadError = 8;
FAIL_CHECK(PERFSRV, " Memory Deallocation" , tstatus);
ThreadError = 0;
} while (keepdoing); // till we receive 'E' or bad status
// we should check if we have to deallocate all the buffers.
// Do all the thread cleanup work
tstatus = IPC_ThreadCleanUp(tCindex);
}
/************************************************************************/
VOID
Cleanup(VOID)
{
USHORT Cindex = 0; // client index
NTSTATUS cstatus;
NTSTATUS exitstatus = 0;
for (Cindex = 0; Cindex < NClients; Cindex++) {
// terminate the thread
cstatus = TerminateThread(Clients[Cindex].c_hThHandle, exitstatus);
if (!NT_SUCCESS(cstatus)) {
printf("Failed to terminate thread no:%d err=%lx\n", Cindex,cstatus);
}
}
printf("Terminated All Threads\n");
}
/************************************************************************/
NTSTATUS
Parse_Cmd_Line(USHORT argc, CHAR *argv[])
{
USHORT i;
PCHAR s;
NTSTATUS pstatus = 0L;
BOOLEAN doingok = TRUE;
if (argc > 5) {
printf("Too many arguments \n");
pstatus = -1L;
}
// copy default Xport name : Nmp
strncpy(Xport, NamePipe, 8);
for (i=1; (doingok) && (i< argc); i++) {
s = argv[i];
if ((*s == '/') &&(*(s+2) == ':'))
{
s++;
switch(*s) {
case 'b' :
case 'B' :
LanaBase = (USHORT)atoi(s+2);
break;
case 'c' : // number of Clients
case 'C' :
NClients = (USHORT)atoi(s+2);
break;
case 'h' :
case 'H' :
HostName = (PCHAR) malloc(strlen(s+2)+1);
strcpy(HostName,s+2);
// check for the validity of the address
break;
case 'l' :
case 'L' :
LanaCount = (USHORT)atoi(s+2);
break;
case 'p' : // NamedPipe mode
case 'P' :
switch(*(s+2)) {
case 'm':
case 'M':
PipeType = PIPE_TYPE_MESSAGE;
PipeMode = PIPE_READMODE_MESSAGE;
break;
case 's':
case 'S':
PipeType = PIPE_TYPE_BYTE;
PipeMode = PIPE_READMODE_BYTE;
break;
default:
doingok = FALSE;
break;
}
case 'x' : // Xport Type
case 'X' :
strncpy(Xport, (PUCHAR) (s+2), 8);
if (!_stricmp(Xport,NamePipe)) {
IPCType = NP;
break;
}
if (!_stricmp(Xport,NetBIOS)) {
IPCType = NB;
break;
}
if (!_stricmp(Xport,SocketXNS)) {
IPCType = SCXNS;
AddrFly = AF_NS;
break;
}
if (!_stricmp(Xport,SocketTCP)) {
IPCType = SCTCP;
AddrFly = AF_INET;
break;
}
if (!_stricmp(Xport,UDP)) {
IPCType = SCUDP;
AddrFly = AF_INET;
break;
}
if (!_stricmp(Xport,IPX)) {
IPCType = SCIPX;
AddrFly = AF_NS;
break;
}
if (!_stricmp(Xport,DGNetBIOS)) {
IPCType = DGNB;
break;
}
// bad choice of Xport
doingok = FALSE;
break;
default :
doingok = FALSE;
}
}
else {
doingok = FALSE;
}
}
if (!doingok) {
Usage(argv[0]);
pstatus = -1L;
}
else {
if (((IPCType == SCTCP)|| (IPCType == SCXNS)) && (HostName == NULL)) {
printf("Please enter Host address \n");
pstatus = -1L;
}
}
return(pstatus);
}
/************************************************************************/
VOID Usage(char * PrgName)
{
fprintf(stderr, "Usage: %s [/c: ] [/x: ] \n", PrgName);
fprintf(stderr, " Opt Default Defines\n");
fprintf(stderr, " === ======= =======\n");
fprintf(stderr, " /c: 1 Number of clients\n");
fprintf(stderr, " /x: Nmp Xport(IPC)type\n");
fprintf(stderr, " Nmp/NetB/SockTCP/\n");
fprintf(stderr, " SockXNS/UDP/IPX/DGNetB\n");
fprintf(stderr, " /p: m Nmp : Pip Type m/s\n");
fprintf(stderr, " /l: 0 NetB: lana count\n");
fprintf(stderr, " /b: 0 NetB: lana base\n");
fprintf(stderr, " /h: NULL Server Name/Host IP addr.\n");
}
/************************************************************************/