windows-nt/Source/XPSP1/NT/sdktools/relstat/server/rssvc.c
2020-09-26 16:20:57 +08:00

727 lines
23 KiB
C

//
// Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
//
// MODULE: server.c
//
// PURPOSE: Implements the body of the Relstat RPC service
//
// FUNCTIONS:
// Called by service.c:
// ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
// ServiceStop( );
//
// Called by RPC:
//
// COMMENTS: The ServerStart and ServerStop functions implemented here are
// prototyped in service.h. The other functions are RPC manager
// functions prototypes in relstat.h
//
//
// AUTHOR: Anitha Panapakkam
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <srvfsctl.h>
#include <tchar.h>
#include <rpc.h>
#include "service.h"
#include "relstat.h"
//
// RPC configuration.
//
// This service listens to all the protseqs listed in this array.
// This should be read from the service's configuration in the
// registery.
TCHAR *ProtocolArray[] = { TEXT("ncalrpc"),
TEXT("ncacn_ip_tcp"),
TEXT("ncacn_np"),
TEXT("ncadg_ip_udp")
};
#define BUFFER_SIZE2 256*1024
// Used in RpcServerUseProtseq, for some protseqs
// this is used as a hint for buffer size.
ULONG ProtocolBuffer = 3;
// Use in RpcServerListen(). More threads will increase performance,
// but use more memory.
ULONG MinimumThreads = 3;
BOOLEAN
CheckFilters (
PSYSTEM_POOLTAG TagInfo,
LPCSTR szTag
);
//
// FUNCTION: ServiceStart
//
// PURPOSE: Actual code of the service
// that does the work.
//
// PARAMETERS:
// dwArgc - number of command line arguments
// lpszArgv - array of command line arguments
//
// RETURN VALUE:
// none
//
// COMMENTS:
// Starts the service listening for RPC requests.
//
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
{
UINT i;
RPC_BINDING_VECTOR *pbindingVector = 0;
RPC_STATUS status;
BOOL fListening = FALSE;
///////////////////////////////////////////////////
//
// Service initialization
//
//
// Use protocol sequences (protseqs) specified in ProtocolArray.
//
for(i = 0; i < sizeof(ProtocolArray)/sizeof(TCHAR *); i++)
{
// Report the status to the service control manager.
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
return;
status = RpcServerUseProtseq(ProtocolArray[i],
ProtocolBuffer,
0);
if (status == RPC_S_OK)
{
fListening = TRUE;
}
}
if (!fListening)
{
// Unable to listen to any protocol!
//
AddToMessageLog(TEXT("RpcServerUseProtseq() failed\n"));
return;
}
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
return;
// Register the services interface(s).
//
status = RpcServerRegisterIf(RelstatRPCService_ServerIfHandle, // from relstat.h
0,
0);
if (status != RPC_S_OK)
return;
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
return;
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
//
status = RpcServerInqBindings(&pbindingVector);
if (status != RPC_S_OK)
{
return;
}
status = RpcEpRegister(RelstatRPCService_ServerIfHandle, // from rpcsvc.h
pbindingVector,
0,
0);
if (status != RPC_S_OK)
{
return;
}
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
return;
// Enable NT LM Security Support Provider (NtLmSsp service)
//
status = RpcServerRegisterAuthInfo(0,
RPC_C_AUTHN_WINNT,
0,
0
);
if (status != RPC_S_OK)
{
return;
}
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
return;
// Start accepting client calls.
//
status = RpcServerListen(MinimumThreads,
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // rpcdce.h
TRUE); // don't block.
if (status != RPC_S_OK)
{
return;
}
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0)) // wait hint
return;
//
// End of initialization
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
//
// Cleanup
//
// RpcMgmtWaitServerListen() will block until the server has
// stopped listening. If this service had something better to
// do with this thread, it would delay this call until
// ServiceStop() had been called. (Set an event in ServiceStop()).
//
status = RpcMgmtWaitServerListen();
// ASSERT(status == RPC_S_OK)
// Remove entries from the endpoint mapper database.
//
RpcEpUnregister(RelstatRPCService_ServerIfHandle, // from rpcsvc.h
pbindingVector,
0);
// Delete the binding vector
//
RpcBindingVectorFree(&pbindingVector);
//
////////////////////////////////////////////////////////////
return;
}
//
// FUNCTION: ServiceStop
//
// PURPOSE: Stops the service
//
// PARAMETERS:
// none
//
// RETURN VALUE:
// none
//
// COMMENTS:
// If a ServiceStop procedure is going to
// take longer than 3 seconds to execute,
// it should spawn a thread to execute the
// stop code, and return. Otherwise, the
// ServiceControlManager will believe that
// the service has stopped responding.
//
VOID ServiceStop()
{
// Stop's the server, wakes the main thread.
RpcMgmtStopServerListening(0);
}
error_status_t
RelStatProcessInfo(
handle_t h,
LONG Pid,
ULONG *pNumberOfProcesses,
PRELSTAT_PROCESS_INFO *ppRelStatProcessInfo)
{
PSYSTEM_PROCESS_INFORMATION pProcessInfo = NULL;
PRELSTAT_PROCESS_INFO pProcessArray = NULL;
ULONG TotalOffset=0;
ULONG NumberOfProcesses = 1; //atleast one process
ULONG NumAlloc = 0;
ULONG i,index,dwMatches = 0;
PBYTE pProcessBuffer = NULL;
NTSTATUS Status= STATUS_INFO_LENGTH_MISMATCH;
DWORD ByteCount = 32768; //TODO : tune it on a "typical system"
DWORD RequiredByteCount = 0;
BOOL fCheck = FALSE;
HANDLE hProcess; // process handle
//two iterations of NtQuerySystemInformation will happen
//can see if there is any other way to allocate a big buffer.
while ( Status == STATUS_INFO_LENGTH_MISMATCH)
{
//
// Allocate a buffer
//
pProcessBuffer = MIDL_user_allocate(ByteCount);
if (pProcessBuffer == NULL)
{
Status = STATUS_NO_MEMORY;
*pNumberOfProcesses = 0;
*ppRelStatProcessInfo = NULL;
break;
}
//
// Perform process enumeration.
//
Status = NtQuerySystemInformation( SystemProcessInformation,
(PVOID)pProcessBuffer,
ByteCount,
&RequiredByteCount );
if (Status == STATUS_INFO_LENGTH_MISMATCH)
{
ByteCount = RequiredByteCount+4096;
if (pProcessBuffer)
LocalFree(pProcessBuffer);
}
}
if (Status == STATUS_SUCCESS)
{
//walk the returned buffer to get the # of processes
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
TotalOffset = 0;
//client has specified a Pid
if (Pid >= 0)
fCheck = TRUE;
while(pProcessInfo->NextEntryOffset != 0)
{
if ((fCheck == TRUE) &&
(PtrToLong(pProcessInfo->UniqueProcessId) == Pid))
{
//Pid matched. exit from the while loop
// no need to count the processes anymore
//fExit = TRUE;
dwMatches++;
break;
}
NumberOfProcesses++;
TotalOffset += pProcessInfo->NextEntryOffset;
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
&pProcessBuffer[TotalOffset];
}
printf("Num Processes = %ul, Matches %d \n",NumberOfProcesses,
dwMatches);
if (dwMatches > 0)
NumAlloc = dwMatches;
else
NumAlloc = NumberOfProcesses;
pProcessArray = MIDL_user_allocate(NumAlloc *
sizeof (RELSTAT_PROCESS_INFO));
if (pProcessArray == NULL)
{
printf("No memory for pProcessArray\n");
Status = STATUS_NO_MEMORY;
LocalFree(pProcessBuffer);
pProcessBuffer = NULL;
}
else
{
RtlZeroMemory(pProcessArray, NumAlloc *
sizeof(RELSTAT_PROCESS_INFO));
Status = STATUS_SUCCESS;
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
TotalOffset = 0;
//walk the returned buffer and copy to pProcessArray
for(i=0;i<NumberOfProcesses;i++)
{
if (dwMatches > 0)
{
if(PtrToLong(pProcessInfo->UniqueProcessId) != Pid)
goto End;
else
index = dwMatches-1;
}
else
index = i;
pProcessArray[index].NumberOfThreads = pProcessInfo->NumberOfThreads;
pProcessArray[index].CreateTime = pProcessInfo->CreateTime;
pProcessArray[index].UserTime = pProcessInfo->UserTime;
pProcessArray[index].KernelTime = pProcessInfo->KernelTime;
//create a null terminated imagename string
pProcessArray[index].szImageName = MIDL_user_allocate((pProcessInfo->ImageName.Length+1)*2);
if (pProcessInfo->ImageName.Length > 0)
{
wcsncpy(pProcessArray[index].szImageName,
pProcessInfo->ImageName.Buffer,
pProcessInfo->ImageName.Length);
}
pProcessArray[index].szImageName[pProcessInfo->ImageName.Length] = L'\0';
pProcessArray[index].BasePriority = pProcessInfo->BasePriority;
pProcessArray[index].UniqueProcessId = PtrToLong(pProcessInfo->UniqueProcessId);
pProcessArray[index].InheritedFromUniqueProcessId = PtrToLong(pProcessInfo->InheritedFromUniqueProcessId);
pProcessArray[index].HandleCount = pProcessInfo->HandleCount;
pProcessArray[index].SessionId = pProcessInfo->SessionId;
pProcessArray[index].PeakVirtualSize = pProcessInfo->PeakVirtualSize;
pProcessArray[index].VirtualSize = pProcessInfo->VirtualSize;
pProcessArray[index].PageFaultCount = pProcessInfo->PageFaultCount;
pProcessArray[index].PeakWorkingSetSize = pProcessInfo->PeakWorkingSetSize;
pProcessArray[index].WorkingSetSize = pProcessInfo->WorkingSetSize;
pProcessArray[index].QuotaPeakPagedPoolUsage = pProcessInfo->QuotaPeakPagedPoolUsage;
pProcessArray[index].QuotaPagedPoolUsage = pProcessInfo->QuotaPagedPoolUsage;
pProcessArray[index].QuotaPeakNonPagedPoolUsage = pProcessInfo->QuotaPeakNonPagedPoolUsage;
pProcessArray[index].QuotaNonPagedPoolUsage = pProcessInfo->QuotaNonPagedPoolUsage;
pProcessArray[index].PagefileUsage = pProcessInfo->PagefileUsage;
pProcessArray[index].PeakPagefileUsage = pProcessInfo->PeakPagefileUsage;
pProcessArray[index].PrivatePageCount = pProcessInfo->PrivatePageCount;
pProcessArray[index].ReadOperationCount = pProcessInfo->ReadOperationCount;
pProcessArray[index].WriteOperationCount = pProcessInfo->WriteOperationCount;
pProcessArray[index].OtherOperationCount = pProcessInfo->OtherOperationCount;
pProcessArray[index].ReadTransferCount = pProcessInfo->ReadTransferCount;
pProcessArray[index].WriteTransferCount = pProcessInfo->WriteTransferCount;
pProcessArray[index].OtherTransferCount = pProcessInfo->OtherTransferCount;
pProcessArray[index].GdiHandleCount = 0;
hProcess= OpenProcess( PROCESS_QUERY_INFORMATION,
FALSE,
PtrToUlong(pProcessInfo->UniqueProcessId) );
if( hProcess ) {
pProcessArray[index].GdiHandleCount = GetGuiResources( hProcess, GR_GDIOBJECTS );
pProcessArray[index].UsrHandleCount= GetGuiResources( hProcess, GR_USEROBJECTS );
CloseHandle( hProcess );
}
End:
TotalOffset += pProcessInfo->NextEntryOffset;
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pProcessBuffer[TotalOffset];
} //end of for loop
} //end of else
} //end of if
if (NT_SUCCESS(Status))
{
*pNumberOfProcesses = NumAlloc;
*ppRelStatProcessInfo = pProcessArray;
//print some debug messages
printf("Query system info passed\n");
printf("%d number of processes \n",*pNumberOfProcesses);
/*
for(i=0; i< *pNumberOfProcesses; i++)
{
printf("%d%10u%10u%10u%10u%10u%10u%10u\n",
pProcessArray[i].UniqueProcessId,
pProcessArray[i].WorkingSetSize,
pProcessArray[i].QuotaPagedPoolUsage,
pProcessArray[i].QuotaNonPagedPoolUsage,
pProcessArray[i].PagefileUsage,
pProcessArray[i].PrivatePageCount,
pProcessArray[i].HandleCount,
pProcessArray[i].NumberOfThreads);
}
*/
}
else
{
*pNumberOfProcesses = 0;
*ppRelStatProcessInfo = NULL;
if (pProcessArray)
LocalFree(pProcessArray);
pProcessArray = NULL;
printf("Query system info failed\n");
}
if (pProcessBuffer)
LocalFree(pProcessBuffer);
pProcessBuffer = NULL;
//print a debug message to catch errors in case of marshalling or anything
//else
printf("Fine before return\n");
return (RtlNtStatusToDosError(Status));
}
error_status_t
RelStatPoolTagInfo(
handle_t h,
LPSTR szPoolTag,
ULONG *pNumberOfPoolTags,
PRELSTAT_POOLTAG_INFO *ppRelStatPoolTagInfo)
{
PSYSTEM_POOLTAG_INFORMATION PoolInfo;
#define BUFFER_SIZE 128*1024
UCHAR CurrentBuffer[BUFFER_SIZE];
NTSTATUS Status; // status from NT api
ULONG i;
PRELSTAT_POOLTAG_INFO pPoolTagArray=NULL;
PRELSTAT_POOLTAG_INFO pPoolTagMatchArray=NULL;
BOOLEAN filter = FALSE;
DWORD dwMatchCount = 0;
printf("Filter specified is %S \n", szPoolTag);
Status = NtQuerySystemInformation(
SystemPoolTagInformation,
CurrentBuffer,
BUFFER_SIZE,
NULL
);
PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
printf("Query Info returned %x\n",Status);
if (szPoolTag) //check to see if pooltag filter specified
filter = TRUE;
if(NT_SUCCESS(Status) && (PoolInfo->Count > 0))
{
printf("%u Number of Tags \n",PoolInfo->Count);
pPoolTagArray = MIDL_user_allocate(PoolInfo->Count *
sizeof(SYSTEM_POOLTAG));
if (!pPoolTagArray)
{
Status = STATUS_NO_MEMORY;
printf("System out of memory for pooltaginfo\n");
}
else
{
for(i=0 ; i < PoolInfo->Count ; i++)
{
if (filter && !CheckFilters(&PoolInfo->TagInfo[i],szPoolTag))
continue;
memcpy(pPoolTagArray[dwMatchCount].Tag, PoolInfo->TagInfo[i].Tag, 4);
pPoolTagArray[dwMatchCount].PagedAllocs = PoolInfo->TagInfo[i].PagedAllocs;
pPoolTagArray[dwMatchCount].PagedFrees = PoolInfo->TagInfo[i].PagedFrees;
pPoolTagArray[dwMatchCount].PagedUsed = PoolInfo->TagInfo[i].PagedUsed;
pPoolTagArray[dwMatchCount].NonPagedAllocs =PoolInfo->TagInfo[i].NonPagedAllocs;
pPoolTagArray[dwMatchCount].NonPagedFrees = PoolInfo->TagInfo[i].NonPagedFrees;
pPoolTagArray[dwMatchCount].NonPagedUsed = PoolInfo->TagInfo[i].NonPagedUsed;
dwMatchCount++;
//need to include union info
}
}
}
if (NT_SUCCESS(Status))
{
if ((filter) && (dwMatchCount < PoolInfo->Count))
{
//allocate and copy only the matched pooltags
pPoolTagMatchArray = MIDL_user_allocate(dwMatchCount *
sizeof(SYSTEM_POOLTAG));
if (!pPoolTagMatchArray)
{
Status = STATUS_NO_MEMORY;
printf("System out of memory for pooltaginfo matches\n");
}
for(i=0;i<dwMatchCount;i++)
{
memcpy(pPoolTagMatchArray[i].Tag, pPoolTagArray[i].Tag,4);
pPoolTagMatchArray[i].PagedAllocs = pPoolTagArray[i].PagedAllocs;
pPoolTagMatchArray[i].PagedFrees = pPoolTagArray[i].PagedFrees;
pPoolTagMatchArray[i].PagedUsed = pPoolTagArray[i].PagedUsed;
pPoolTagMatchArray[i].NonPagedAllocs = pPoolTagArray[i].NonPagedAllocs;
pPoolTagMatchArray[i].NonPagedFrees = pPoolTagArray[i].NonPagedFrees;
pPoolTagMatchArray[i].NonPagedUsed = pPoolTagArray[i].NonPagedUsed;
}
*ppRelStatPoolTagInfo = pPoolTagMatchArray;
*pNumberOfPoolTags = dwMatchCount;
printf("RelStatPoolTagInfo returned TRUE \n");
printf("%u Number of Tags \n",*pNumberOfPoolTags);
MIDL_user_free(pPoolTagArray);
}
else
{ // no filter specified or all the tags need to be sent
*ppRelStatPoolTagInfo = pPoolTagArray;
*pNumberOfPoolTags = PoolInfo->Count;
printf("RelStatPoolTagInfo returned TRUE \n");
printf("%u Number of Tags \n",*pNumberOfPoolTags);
}
}
else
{
*ppRelStatPoolTagInfo = NULL;
*pNumberOfPoolTags = 0;
printf("RelStatPoolTagInfo returned FALSE %x \n",Status);
}
return (RtlNtStatusToDosError(Status));
// return ( (NT_SUCCESS(*pResult))?TRUE : FALSE);
}
error_status_t
RelStatBuildNumber(handle_t h,
ULONG* ulBuildNumber)
{
OSVERSIONINFO osVer;
osVer.dwOSVersionInfoSize = sizeof(osVer);
if (GetVersionEx(&osVer))
{
*ulBuildNumber = osVer.dwBuildNumber;
return ERROR_SUCCESS;
}
return RtlNtStatusToDosError(GetLastError());
}
error_status_t
RelStatTickCount(handle_t h,
ULONG* ulTickCount)
{
*ulTickCount = GetTickCount();
return ERROR_SUCCESS;
}
BOOLEAN
CheckSingleFilter (
PCHAR Tag,
LPCSTR Filter
)
{
ULONG i;
CHAR tc;
CHAR fc;
for ( i = 0; i < 4; i++ ) {
tc = *Tag++;
fc = *Filter++;
if ( fc == '*' ) return TRUE;
if ( fc == '?' ) continue;
if ( tc != fc ) return FALSE;
}
return TRUE;
}
BOOLEAN
CheckFilters (
PSYSTEM_POOLTAG TagInfo,
LPCSTR szTag
)
{
BOOLEAN pass = FALSE;
ULONG i;
PCHAR tag;
tag = TagInfo->Tag;
if ( CheckSingleFilter( tag, szTag ))
pass = TRUE;
return pass;
}
//
// FUNCTIONS: MIDL_user_allocate and MIDL_user_free
//
// PURPOSE: Used by stubs to allocate and free memory
// in standard RPC calls. Not used when
// [enable_allocate] is specified in the .acf.
//
//
// PARAMETERS:
// See documentations.
//
// RETURN VALUE:
// Exceptions on error. This is not required,
// you can use -error allocation on the midl.exe
// command line instead.
//
//
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);
}