|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1994 - 1999
//
// File: np.c
//
//--------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////
//
// Filename: np.c
//
// Description: This file contains common routines for named pipe
// routines for use with IPC raw networl performance
// tests.
// This module is written using win32 API calls.
//
// 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 "np.h"
/*++
NamedPipe function implementations --*/
/************************************************************************/ NTSTATUS NMP_Initialize( IN USHORT NClients, IN PCHAR ServerName, IN USHORT SrvCli) { CHAR TempSrv[256]; // use local pipe name for server or if Name not provided
if (SrvCli || (!ServerName)) { strcpy(TempSrv,PERF_PIPE); } else{ if (!ServerName) { strcpy(TempSrv, RM_PERF_PIPE_PRFX); } else { strcpy(TempSrv, (const char *)ServerName); } strcat(TempSrv, RM_PERF_PIPE_SUFX); } printf("NMP: Pipe name - %s\n", TempSrv); pipeName = _strdup(TempSrv); return(STATUS_SUCCESS); } /************************************************************************/ /*++
This routine is responsible Creating a NamedPipe instance for the given thread.
--*/
NTSTATUS NMP_PerClientInit( IN USHORT CIndex, // client index
IN USHORT SrvCli ) { NTSTATUS pstatus = 0;
if (SrvCli) { // create namedpipe for this client
pstatus = CreateNamedPipeInstance(CIndex); } else { // for Client initialize all the thread parameters
; } return pstatus; }
/************************************************************************/ /*++
This routine is responsible for issueing Listen and waiting till a client is connected. When this routine returns successfully we can assume that a connection is established. --*/
NTSTATUS NMP_Wait_For_Client( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS wstatus; wstatus = ConnectNamedPipe(Clients[CIndex].c_Nmp.c_PipeHandle, NULL);
if (wstatus == FALSE) { printf("Error: ConnectNamedPipe - 0x%08x, %ld\n", GetLastError(), GetLastError()); } return (wstatus); }
/************************************************************************/ /*++
This routine is responsible for issueing Disconnect to close the connection with a client. --*/
NTSTATUS NMP_Disconnect_Client( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS dstatus;
// post a Disconnect
// first find the status of the pipe to make sure that it's empty
dstatus = FlushFileBuffers(Clients[CIndex].c_Nmp.c_PipeHandle); if (dstatus == FALSE) { printf("Error: FlushFileBuffers failed - 0x%08x\n", GetLastError()); } dstatus = DisconnectNamedPipe(Clients[CIndex].c_Nmp.c_PipeHandle); if (dstatus == FALSE) { printf("Error: DisconnectNamedPipe failed - 0x%08x, %ld\n", GetLastError(), GetLastError()); } return dstatus; }
/************************************************************************/ /*++
This routine is responsible for establishing a connection to the server side. When this routine returns successfully we can assume that a connection is established. --*/
NTSTATUS NMP_Connect_To_Server( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS cstatus; DWORD dwPipeMode;
Clients[CIndex].c_Nmp.c_PipeHandle = CreateFile( //connect to the server
pipeName, // address of filename
GENERIC_READ | GENERIC_WRITE, // access mode
0L, // share mode
NULL, // security attributes
OPEN_EXISTING, // create mode
0L, // attributes and flags
NULL); // template file handle
if (Clients[CIndex].c_Nmp.c_PipeHandle == INVALID_HANDLE_VALUE) { printf("Error: CreateFile failed - 0x%08x\n", GetLastError()); cstatus = FALSE; } else { dwPipeMode = PIPE_READMODE_MESSAGE; cstatus = SetNamedPipeHandleState(Clients[CIndex].c_Nmp.c_PipeHandle, // pipe handle
&dwPipeMode, // new pipe mode
NULL, // do not set the max bytes
NULL); // do not set the max time
if (cstatus == FALSE) { printf("Error: SetNamedPipeHandleState failed - 0x%08x\n", GetLastError()); } } return(cstatus); }
/************************************************************************/ /*++
This routine allocates memory required for all the buffers for a client.
--*/
NTSTATUS NMP_Allocate_Memory( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS astatus = STATUS_SUCCESS; ULONG AllocSize;
AllocSize = MAXBUFSIZE; (LPVOID) Clients[CIndex].c_pSendBuf = VirtualAlloc( (LPVOID) Clients[CIndex].c_pSendBuf, (DWORD)AllocSize, (DWORD)MEM_COMMIT, (DWORD)PAGE_READWRITE); sprintf(Clients[CIndex].c_pSendBuf,"Client%d Send Data",CIndex+1); if (Clients[CIndex].c_pSendBuf == NULL) { astatus = GetLastError(); printf("\nVirtual Alloc error\n"); } AllocSize = MAXBUFSIZE; (LPVOID) Clients[CIndex].c_pRecvBuf = VirtualAlloc( (LPVOID) Clients[CIndex].c_pRecvBuf, (DWORD)AllocSize, (DWORD)MEM_COMMIT, (DWORD)PAGE_READWRITE); sprintf(Clients[CIndex].c_pRecvBuf,"Client%d Recv Data",CIndex+1); if (Clients[CIndex].c_pRecvBuf == NULL) { astatus = GetLastError(); printf("\nVirtual Alloc error\n"); } return astatus; } /************************************************************************/ /*++
This routine deallocates memory for a client.
--*/
NTSTATUS NMP_Deallocate_Memory( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS dstatus; ULONG DeallocSize;
DeallocSize = MAXBUFSIZE; dstatus = VirtualFree( (LPVOID) Clients[CIndex].c_pSendBuf, DeallocSize, MEM_DECOMMIT); if (!NT_SUCCESS(dstatus)) { return dstatus; }
DeallocSize = MAXBUFSIZE; dstatus = VirtualFree( (LPVOID) Clients[CIndex].c_pRecvBuf, DeallocSize, MEM_DECOMMIT); if (!NT_SUCCESS(dstatus)) { return dstatus; } return dstatus; } /************************************************************************/ /*++
This routine is responsible for disconnecting a session.
--*/
NTSTATUS NMP_Disconnect_From_Server( IN USHORT CIndex) // client index and namedpipe instance number
{ NTSTATUS dstatus;
dstatus = CloseHandle(Clients[CIndex].c_Nmp.c_PipeHandle);
if (!NT_SUCCESS(dstatus)) { //DbgPrint("Nmp: Error in Disconnect err: %lx \n", dstatus);
} return (dstatus); }
/************************************************************************/ // no need for this function
/*
NTSTATUS NamedPipe_FsControl( IN HANDLE lhandle, IN ULONG FsControlCode, IN PVOID pInBuffer, IN ULONG InBufLen, OUT PVOID pOutBuffer, IN ULONG OutBufLen) {
NTSTATUS lstatus; IO_STATUS_BLOCK ioStatusBlock; DWORD actOutBufLen;
// now post listen on this handle
lstatus = NtFsControlFile ( lhandle, NULL, NULL, NULL, &ioStatusBlock, FsControlCode, // LISTEN or DISCONNECT or TRANSCEIVE maybe PEEK
pInBuffer, InBufLen, pOutBuffer, // Xceive or Peek buffer NULL otherwise
OutBufLen // Xceive or peek buffer length 0L otherwise
);
lstatus = TransactNamedPipe(lhandle, // pipe handle
pInBuffer, // write buffer
InBufLen, // write buffer length
pOutBuffer, // read buffer
OutBufLen, // read buffer length
&actOutBufLen, // the actual number of bytes read from the buffer
NULL); if (lstatus == STATUS_PENDING) { lstatus = WaitForSingleObjectEx(lhandle, INFINITE, TRUE); if (NT_SUCCESS(lstatus)) { lstatus = ioStatusBlock.Status; if (!NT_SUCCESS(lstatus) &&(FsControlCode != FSCTL_PIPE_TRANSCEIVE)) { //DbgPrint("Listen/Disconn/Xceive failed, err=%lx\n", lstatus);
} } else { //DbgPrint("Error in Wait while FsCtrl %lx\n",lstatus);}
} else { if (NT_SUCCESS(lstatus)) { lstatus = ioStatusBlock.Status; } else { //DbgPrint("Error in FSCTL: %lx\n", lstatus);
} }
return(lstatus);
} /*
/************************************************************************/ /*++
This routine does handshake with it's peer. For Server this means receiving request message from a client. For Client it means just the opposite. --*/
NTSTATUS NMP_DoHandshake( IN USHORT CIndex, // client index and namedpipe instance number
IN USHORT SrvCli // if it's a server or client
) { NTSTATUS dstatus; ULONG RWLen; ULONG RWreqLen;
RWreqLen = sizeof(struct reqbuf); // for server do receive for a request buffer
if (SrvCli) { dstatus = ReadNamedPipe( Clients[CIndex].c_Nmp.c_PipeHandle, RWreqLen, (PVOID) &(Clients[CIndex].c_reqbuf), (PULONG) &RWLen); if (!NT_SUCCESS(dstatus)) { //DbgPrint("Nmp: Error in ReadNamedPipe: err:%lx \n", dstatus);
return dstatus; }
} else { // for Client do send of reqbuf size
// Based on TestCmd make changes i.e. 'U'->'P'
dstatus = WriteNamedPipe( Clients[CIndex].c_Nmp.c_PipeHandle, RWreqLen, (PVOID) &(Clients[CIndex].c_reqbuf), (PULONG) &RWLen); if (!NT_SUCCESS(dstatus)) { //DbgPrint("Nmp: Error in WriteNamedPipe: err:%lx \n", dstatus);
return dstatus; } } // check if read/write length is ok
if (RWLen != sizeof(struct reqbuf)) { //DbgPrint("Nmp: Read/WriteNamedPipe Len mismatch: read %ld \n", RWLen);
} // MyDbgPrint("handshake: Sendl:%ld Recvl:%ld \n",Clients[CIndex].c_reqbuf.SendSize,Clients[CIndex].c_reqbuf.RecvSize);
return dstatus; }
/************************************************************************/ /*++
This routine Reads data from IPC. For server it means reading data NumSends times in SendBuffers and for a client NumRecvs times into RecvBuffer.
--*/
NTSTATUS NMP_ReadFromIPC( IN USHORT CIndex, // client index and namedpipe instance number
IN OUT PULONG pReadDone, IN USHORT SrvCli) // if it's a server or client
{ NTSTATUS rstatus; ULONG NumReads; ULONG ReadLen; PCHAR ReadBuf;
if (SrvCli) { // set proper iterations and buffer for Server
NumReads = Clients[CIndex].c_reqbuf.NumSends; ReadBuf = Clients[CIndex].c_pSendBuf; ReadLen = Clients[CIndex].c_reqbuf.SendSize; } else { // for client do proper settings
NumReads = Clients[CIndex].c_reqbuf.NumRecvs; ReadBuf = Clients[CIndex].c_pRecvBuf; ReadLen = Clients[CIndex].c_reqbuf.RecvSize; } while (NumReads--) { rstatus = ReadNamedPipe( Clients[CIndex].c_Nmp.c_PipeHandle, ReadLen, (PVOID) ReadBuf, (PULONG) pReadDone); if (!NT_SUCCESS(rstatus)) { //DbgPrint("Nmp: Error in ReadNamedPipe: err:%lx \n", rstatus);
break; } } return rstatus; } /************************************************************************/ NTSTATUS ReadNamedPipe( IN HANDLE rhandle, IN ULONG rlength, IN OUT PVOID rpbuffer, IN OUT PULONG rpdatalen) { NTSTATUS rstatus; DWORD actRLength;
rstatus = ReadFile( rhandle, // pipe handle
rpbuffer, // buffer to receive reply
rlength, // size of the buffer
&actRLength, // number of bytes read
NULL); // not overlapped
if (rstatus == TRUE) { *rpdatalen = actRLength; } else { if (GetLastError() == ERROR_MORE_DATA) { rstatus = WaitForSingleObjectEx(rhandle, INFINITE, TRUE); if (rstatus == TRUE) { *rpdatalen = actRLength; if (rlength != *rpdatalen) { printf("Error: No. of bytes read != buffer length\n"); } } } } return(rstatus); }
/************************************************************************/ /*++
This routine Writes data to IPC. For server it means writing data NumRecvs times in RecvBuffers and for a client NumSends times into SendBuffer.
--*/
NTSTATUS NMP_WriteToIPC( IN USHORT CIndex, // client index and namedpipe instance number
IN OUT PULONG pWriteDone, IN USHORT SrvCli) // if it's a server or client
{ NTSTATUS wstatus; ULONG NumWrites; ULONG WriteLen; PCHAR WriteBuf;
if (SrvCli) { // set proper iterations and buffer for Server
NumWrites = Clients[CIndex].c_reqbuf.NumRecvs; WriteBuf = Clients[CIndex].c_pRecvBuf; WriteLen = Clients[CIndex].c_reqbuf.RecvSize; } else { // for client do proper settings
NumWrites = Clients[CIndex].c_reqbuf.NumSends; WriteBuf = Clients[CIndex].c_pSendBuf; WriteLen = Clients[CIndex].c_reqbuf.SendSize; } while (NumWrites--) { wstatus = WriteNamedPipe( Clients[CIndex].c_Nmp.c_PipeHandle, WriteLen, (PVOID) WriteBuf, (PULONG) pWriteDone); if (!NT_SUCCESS(wstatus)) { //DbgPrint("Nmp: Error in WriteNamedPipe: err:%lx \n", wstatus);
break; } } return wstatus; }
/************************************************************************/ /*++
This routine does transaction type IO to IPC. This just assumes that both Number of reads and writes are equal and will use Number of reads as it's basis.
--*/
NTSTATUS NMP_XactIO( IN USHORT CIndex, // client index and namedpipe instance number
IN OUT PULONG pReadDone, IN OUT PULONG pWriteDone, IN USHORT SrvCli, // if it's a server or client
IN BOOLEAN FirstIter) // ignore for NamedPipe
{ NTSTATUS xstatus; ULONG NumReads; ULONG ReadLen; PCHAR ReadBuf; ULONG WriteLen; PCHAR WriteBuf; DWORD actReadLen;
NumReads = Clients[CIndex].c_reqbuf.NumRecvs;
if (SrvCli) { // set proper iterations and buffer for Server
ReadBuf = Clients[CIndex].c_pSendBuf; ReadLen = Clients[CIndex].c_reqbuf.SendSize; WriteBuf = Clients[CIndex].c_pRecvBuf; WriteLen = Clients[CIndex].c_reqbuf.RecvSize; } else { // for client do proper settings
ReadBuf = Clients[CIndex].c_pRecvBuf; ReadLen = Clients[CIndex].c_reqbuf.RecvSize; WriteBuf = Clients[CIndex].c_pSendBuf; WriteLen = Clients[CIndex].c_reqbuf.SendSize; } while (NumReads--) { xstatus = TransactNamedPipe(Clients[CIndex].c_Nmp.c_PipeHandle, // pipe name
WriteBuf, // write buffer
WriteLen, // write buffer length
ReadBuf, // read buffer
ReadLen, // read buffer length
&actReadLen, // actual read buffer length
NULL); // not overlapped
if (xstatus == FALSE) { printf("Error: TransactNamedPipe failed - 0x%08x\n", GetLastError()); *pReadDone = 0L; *pWriteDone = 0L; break; } *pReadDone = ReadLen; *pWriteDone = WriteLen; } return xstatus; }
/************************************************************************/ NTSTATUS WriteNamedPipe( IN HANDLE whandle, IN ULONG wlength, IN OUT PVOID wpbuffer, IN OUT PULONG wpdatalen) { NTSTATUS wstatus; DWORD actWLength;
wstatus = WriteFile(whandle, // pipe handle
wpbuffer, // address of data buffer to write to file
wlength, // length of data buffer
&actWLength,// actual length of data read
NULL); // not overlapped
if (wstatus == TRUE) { *wpdatalen = actWLength; } else { if (GetLastError() == ERROR_MORE_DATA) { wstatus = WaitForSingleObjectEx(whandle, INFINITE, TRUE); if (wstatus == TRUE) { *wpdatalen = actWLength; if (wlength != *wpdatalen) { printf("Error: No. of bytes written != buffer length\n"); } } } } return(wstatus); } /************************************************************************/ // this is now a win32 defined function
/*
NTSTATUS DisconnectNamedPipe(IN HANDLE dhandle) {
NTSTATUS wstatus; // IO_STATUS_BLOCK ioStatusBlock;
wstatus = NamedPipe_FsControl( // post DisConnect
dhandle, FSCTL_PIPE_DISCONNECT, NULL, // input buffer
0L, // inbuf len
NULL, // output buffer
0L); // outbuf len
if (!NT_SUCCESS(wstatus)) { //DbgPrint ("Pipe Disconnect failed, err=%lx\n", wstatus);
} return(wstatus); } */
/************************************************************************/ /*++ This routine creates one instance of NamedPipe for a given client.
A client is identified by its index number. --*/
NTSTATUS CreateNamedPipeInstance( IN USHORT Nindex) // client index and namedpipe instance number
{ NTSTATUS nstatus = 0; HANDLE NMPhandle;
NMPhandle = CreateNamedPipe(pipeName, // the given pipe name entered by the user
PIPE_ACCESS_DUPLEX, // GENERIC_READ | GENERIC_WRITE
PIPE_READMODE_MESSAGE | // pipe mode (message...)
PIPE_TYPE_MESSAGE | PIPE_WAIT, NClients, // max number of instances(clients)
Quotas, // max in buffer length
Quotas, // max out buffer length
600000, // 60 second default timeout
NULL); // default security attributes
if (NMPhandle == INVALID_HANDLE_VALUE) { nstatus = GetLastError(); printf ("Failed to Create NamedPipe, err=%lx, %ld\n", nstatus, nstatus); } else { // initialize this client's values
Clients[Nindex].c_Nmp.c_PipeHandle = NMPhandle; Clients[Nindex].c_client_num = Nindex;//index into the Client array
} return(nstatus); } /************************************************************************/ NTSTATUS NMP_Cleanup(VOID) { return STATUS_SUCCESS; } /************************************************************************/
/*++
This routine does a client specific cleanup work. --*/
NTSTATUS NMP_ThreadCleanUp( IN USHORT CIndex) { return STATUS_SUCCESS; } /************************************************************************/
|