ZLUDA/ext/detours/samples/cping/cping.cpp

2245 lines
64 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// Module: cping.cpp (cping.exe)
//
// Microsoft Research Detours Package
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// COM Ping text program.
//
#define _RPCRT4_
#define INITGUID
#include <winsock2.h>
#include <objbase.h>
#include <objidl.h>
#include <ocidl.h>
#include <olectl.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma warning(push)
#if _MSC_VER > 1400
#pragma warning(disable:6102 6103) // /analyze warnings
#endif
#include <strsafe.h>
#pragma warning(pop)
#include <winnt.h>
#include <rpc.h>
#include <rpcdcep.h>
#include <detours.h>
#include "iping.h"
// ARM64 ReadTimeStampCounter is a function.
// ARM ReadTimeStampCounter is a declared function but not implemented.
// old IA64: ReadTimeStampCounter nonexisant.
// new IA64: ReadTimeStampCounter is a macro.
// old x86; ReadTimeStampCounter is a function.
// new x86: ReadTimeStampCounter is a macro.
// AMD64: ReadTimeStampCounter is a macro.
#if defined(_ARM64_) || defined(ReadTimeStampCounter)
#define GetTimeStamp() ReadTimeStampCounter()
#elif defined(_X86_) || defined(_AMD64_)
extern "C"
DWORD64
__rdtsc (
VOID
);
#pragma intrinsic(__rdtsc)
#define GetTimeStamp() __rdtsc()
#else
UINT64 GetTimeStamp(void)
{
LARGE_INTEGER a = { 0 };
QueryPerformanceCounter(&a);
return a.QuadPart;
}
#endif
#define BE_VERBOSE
////////////////////////////////////////////////////////// Assertion Handling.
//
#pragma warning(disable:4127) // Many of our asserts are constants.
#ifndef NODEBUG
#undef ASSERT
VOID PingAssertMessage(CONST PCHAR szMsg, CONST PCHAR szFile, ULONG nLine);
#define ASSERT(x) \
do { if (!((int)(x))) { PingAssertMessage(#x, __FILE__, __LINE__); DebugBreak(); }} while (0)
;
#else // NODEBUG
#undef ASSERT
#define ASSERT(x)
#endif // NODEBUG
//////////////////////////////////////////////////////////////////////////////
#define wcssize(x) ((wcslen(x) + 1) * sizeof(WCHAR))
#define strsize(x) ((strlen(x) + 1) * sizeof(CHAR))
extern "C" {
ULONG WINAPI iping_DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
HRESULT STDAPICALLTYPE iping_DllRegisterServer(void);
HRESULT STDAPICALLTYPE iping_DllUnregisterServer(void);
HRESULT STDAPICALLTYPE iping_DllGetClassObject(REFCLSID rclsid,
REFIID riid, PVOID *ppv);
HRESULT STDAPICALLTYPE iping_DllCanUnloadNow(void);
}
STDAPI PingMessage(PCSTR msg, ...);
///////////////////////////////////////////////////////////////////// Globals.
void * g_pBuffer = NULL;
WCHAR g_wzServerName[128];
WCHAR g_wzClientName[128];
ULONG g_cbBufferMax = 262144;
double g_dCyclesPerSecond = 0.0;
double g_dMsPerCycle = 0.0;
double g_dLatency = 0.0;
BOOL g_fSummarize = TRUE;
ULONG g_nFixedToClient = 0;
ULONG g_nFixedToServer = 0;
//////////////////////////////////////////////////////////////////////////////
//
static CHAR s_szMessageBuf[2048];
STDAPI PingMessage(PCSTR msg, ...)
{
HRESULT hr;
double d = 0.0; // Required for FP support
(void)d;
va_list args;
va_start(args, msg);
hr = StringCchVPrintfA(s_szMessageBuf, ARRAYSIZE(s_szMessageBuf), msg, args);
va_end(args);
if (FAILED(hr)) {
return hr;
}
// OutputDebugStringA(s_szMessageBuf);
printf("%s", s_szMessageBuf);
return S_FALSE;
}
VOID PingAssertMessage(CONST PCHAR szMsg, CONST PCHAR szFile, ULONG nLine)
{
PingMessage("%08lx ASSERT(%s) failed in %s, line %d.\n",
GetCurrentThreadId(), szMsg, szFile, nLine);
printf("ASSERT(%s) failed in %s, line %ld.\n", szMsg, szFile, nLine);
}
BOOLEAN CheckResult(HRESULT hr, PCSTR pszMsg, ...)
{
if (FAILED(hr)) {
HRESULT ihr;
va_list args;
va_start(args, pszMsg);
ihr = StringCchVPrintfA(s_szMessageBuf, ARRAYSIZE(s_szMessageBuf), pszMsg, args);
va_end(args);
if (FAILED(ihr)) {
return FALSE;
}
printf(" %-57.57s -> %08lx\n", s_szMessageBuf, hr);
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
#define NTSYSAPI DECLSPEC_IMPORT
#define NTAPI __stdcall
#define NTSTATUS LONG
#define PIO_APC_ROUTINE PVOID
typedef struct
{
NTSTATUS Status;
LONG Information;
} *PIO_STATUS_BLOCK;
NTSTATUS (NTAPI *Real_NtWaitForSingleObject)(HANDLE Handle,
BOOLEAN Alertable,
PLARGE_INTEGER Timeout) = NULL;
NTSTATUS (NTAPI *Real_NtDeviceIoControlFile)(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength) = NULL;
//////////////////////////////////////////////////////////////////////////////
//
static LONG s_nInCall = 0;
static ULONG s_nThread = 0;
enum {
E_MinValue = 0,
E_SleepEx = 1,
E_Proxy,
E_I_RpcGetBuffer,
E_I_RpcSendReceive,
E_I_RpcFreeBuffer,
E_I_RpcSend,
E_I_RpcReceive,
E_I_RpcFreePipeBuffer,
E_I_RpcReallocPipeBuffer,
E_I_RpcRequestMutex,
E_I_RpcClearMutex,
E_I_RpcAllocate,
E_I_RpcFree,
E_I_RpcPauseExecution,
E_I_RpcMonitorAssociation,
E_I_RpcStopMonitorAssociation,
E_Recv,
E_RecvFrom,
E_NtWaitForSingleObject,
E_NtDeviceIoControlFileRecv,
E_NtDeviceIoControlFile,
E_Send,
E_SendTo,
E_NtDeviceIoControlFileSend,
E_DCOM,
E_RPC,
E_UDP,
E_NET,
E_MaxValue,
E_DcomBeg = E_Proxy,
E_DcomEnd = E_Proxy,
E_RpcBeg = E_I_RpcGetBuffer,
E_RpcEnd = E_I_RpcStopMonitorAssociation,
E_UdpBeg = E_Send,
E_UdpEnd = E_NtDeviceIoControlFileSend,
E_NetBeg = E_Recv,
E_NetEnd = E_NtDeviceIoControlFile,
};
PCHAR s_rszRouteNames[E_MaxValue] =
{
"<NULL>",
"SleepEx",
"Proxy",
"I_RpcGetBuffer",
"I_RpcSendReceive",
"I_RpcFreeBuffer",
"I_RpcSend",
"I_RpcReceive",
"I_RpcFreePipeBuffer",
"I_RpcReallocPipeBuffer",
"I_RpcRequestMutex",
"I_RpcClearMutex",
"I_RpcAllocate",
"I_RpcFree",
"I_RpcPauseExecution",
"I_RpcMonitorAssociation",
"I_RpcStopMonitorAssociation",
"Recv",
"RecvFrom",
"NtWaitForSingleObject",
"NtDeviceIoControlRecv",
"NtDeviceIoControlFile",
"Send",
"SendTo",
"NtDeviceIoControlSend",
"DCOM",
"RPC",
"UDP/TCP (Send Only)",
"NET",
};
LONGLONG s_rllCycles[E_MaxValue];
LONGLONG s_rllTotals[E_MaxValue];
LONG s_rllCounts[E_MaxValue];
class CRouteTime
{
public:
inline CRouteTime(LONG nRoute)
{
if (s_nInCall && GetCurrentThreadId() == s_nThread) {
LONGLONG llBeg;
m_nOldRoute = s_nRoute;
m_llOldMinus = s_llMinus;
s_nRoute = m_nRoute = nRoute;
s_rllCounts[m_nRoute]++;
s_llMinus = 0;
ASSERT(m_nRoute != m_nOldRoute);
llBeg = GetTimeStamp();
m_llBeg = llBeg;
}
else {
m_nRoute = 0;
}
}
inline ~CRouteTime()
{
if (m_nRoute) {
LONGLONG llEnd = GetTimeStamp();
llEnd -= m_llBeg;
s_rllTotals[m_nRoute] += llEnd;
s_rllCycles[m_nRoute] += llEnd - s_llMinus;
s_nRoute = m_nOldRoute;
s_llMinus = m_llOldMinus + llEnd;
}
}
inline BOOL Routed()
{
return m_nRoute;
}
public:
ULONG m_nRoute;
ULONG m_nOldRoute;
LONGLONG m_llBeg;
LONGLONG m_llOldMinus;
static ULONG s_nRoute;
static LONGLONG s_llMinus;
};
ULONG CRouteTime::s_nRoute = 0;
LONGLONG CRouteTime::s_llMinus = 0;
VOID ZeroCycles(VOID)
{
for (ULONG n = 0; n < E_MaxValue; n++) {
s_rllCycles[n] = 0;
s_rllTotals[n] = 0;
s_rllCounts[n] = 0;
}
}
VOID DumpCycles(LONG nRoute)
{
if (s_rllCycles[nRoute] != 0 || s_rllTotals[nRoute] != 0) {
printf(";; %-21.21s %10I64d %8.3fms %10I64d %8.3fms :%6ld\n",
s_rszRouteNames[nRoute],
s_rllCycles[nRoute], (double)s_rllCycles[nRoute] * g_dMsPerCycle,
s_rllTotals[nRoute], (double)s_rllTotals[nRoute] * g_dMsPerCycle,
s_rllCounts[nRoute]);
}
}
VOID SummarizeCycles(VOID)
{
ULONG n;
for (n = E_DCOM; n <= E_NET; n++) {
s_rllCycles[n] = 0;
s_rllTotals[n] = 0;
s_rllCounts[n] = 0;
}
for (n = E_DcomBeg; n <= E_DcomEnd; n++) {
s_rllCycles[E_DCOM] += s_rllCycles[n];
s_rllTotals[E_DCOM] += s_rllTotals[n];
}
for (n = E_RpcBeg; n <= E_RpcEnd; n++) {
s_rllCycles[E_RPC] += s_rllCycles[n];
s_rllTotals[E_RPC] += s_rllTotals[n];
}
for (n = E_UdpBeg; n <= E_UdpEnd; n++) {
s_rllCycles[E_UDP] += s_rllCycles[n];
s_rllTotals[E_UDP] += s_rllTotals[n];
}
for (n = E_NetBeg; n <= E_NetEnd; n++) {
s_rllCycles[E_NET] += s_rllCycles[n];
s_rllTotals[E_NET] += s_rllTotals[n];
}
#ifdef BE_VERBOSE
printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
"::::::::::::::::::\n");
printf(":: Protocol Cycles:\n");
DumpCycles(E_DCOM);
DumpCycles(E_RPC);
DumpCycles(E_UDP);
DumpCycles(E_NET);
#endif
s_rllCycles[E_DCOM] /= s_rllCounts[E_DCOM];
s_rllCycles[E_RPC] /= s_rllCounts[E_DCOM];
s_rllCycles[E_UDP] /= s_rllCounts[E_DCOM];
s_rllCycles[E_NET] /= s_rllCounts[E_DCOM];
s_rllTotals[E_DCOM] /= s_rllCounts[E_DCOM];
s_rllTotals[E_RPC] /= s_rllCounts[E_DCOM];
s_rllTotals[E_UDP] /= s_rllCounts[E_DCOM];
s_rllTotals[E_NET] /= s_rllCounts[E_DCOM];
#ifdef BE_VERBOSE
printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
"::::::::::::::::::\n");
printf(":: Protocol Cycles Per DCOM Call:\n");
DumpCycles(E_DCOM);
DumpCycles(E_RPC);
DumpCycles(E_UDP);
DumpCycles(E_NET);
#endif
for (n = 0; n < E_DCOM; n++) {
s_rllCycles[n] = 0;
s_rllTotals[n] = 0;
s_rllCounts[n] = 0;
}
}
//////////////////////////////////////////////////////////////////////////////
//
DWORD (WINAPI * Real_SleepEx)(DWORD dwMilliseconds, BOOL bAlertable)
= SleepEx;
int (WSAAPI * Real_send)(SOCKET s,
const char * buf, int len, int flags)
= send;
int (WSAAPI * Real_sendto)(SOCKET s,
const char * buf, int len, int flags,
const struct sockaddr * to, int tolen)
= sendto;
int (WSAAPI * Real_recv)(SOCKET s, char * buf, int len, int flags)
= recv;
int (WSAAPI * Real_recvfrom)(SOCKET s,char * buf, int len, int flags,
struct sockaddr * from, int * fromlen)
= recvfrom;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcGetBuffer)(RPC_MESSAGE * Message)
= I_RpcGetBuffer;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcSendReceive)(RPC_MESSAGE * Message)
= I_RpcSendReceive;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcFreeBuffer)(RPC_MESSAGE * Message)
= I_RpcFreeBuffer;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcSend)(PRPC_MESSAGE Message)
= I_RpcSend;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcReceive)(PRPC_MESSAGE Message,
unsigned int Size)
= I_RpcReceive;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcFreePipeBuffer)(RPC_MESSAGE * Message)
= I_RpcFreePipeBuffer;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcReallocPipeBuffer)(PRPC_MESSAGE Msg,
unsigned int Size)
= I_RpcReallocPipeBuffer;
void (RPC_ENTRY *
Real_I_RpcRequestMutex)(I_RPC_MUTEX * Mutex)
= I_RpcRequestMutex;
void (RPC_ENTRY *
Real_I_RpcClearMutex)(I_RPC_MUTEX Mutex)
= I_RpcClearMutex;
void * (RPC_ENTRY *
Real_I_RpcAllocate)(unsigned int Size)
= I_RpcAllocate;
void (RPC_ENTRY *
Real_I_RpcFree)(void * Object)
= I_RpcFree;
void (RPC_ENTRY *
Real_I_RpcPauseExecution)(unsigned long Milliseconds)
= I_RpcPauseExecution;
#if _MSC_VER < 1300
RPC_STATUS (RPC_ENTRY *
Real_I_RpcMonitorAssociation)(RPC_BINDING_HANDLE Handle,
PRPC_RUNDOWN RundownRoutine,
void * Context)
= I_RpcMonitorAssociation;
RPC_STATUS (RPC_ENTRY *
Real_I_RpcStopMonitorAssociation)(RPC_BINDING_HANDLE Handle)
= I_RpcStopMonitorAssociation;
#endif
//////////////////////////////////////////////////////////////////////////////
//
static DWORD WINAPI Catch_SleepEx(DWORD dwMilliseconds, BOOL bAlertable)
{
CRouteTime rt(E_SleepEx);
return Real_SleepEx(dwMilliseconds, bAlertable);
}
static int WSAAPI Catch_send(SOCKET s, const char * buf, int len, int flags)
{
CRouteTime rt(E_Send);
return Real_send(s, buf, len, flags);
}
static NTSTATUS NTAPI Catch_NtWaitForSingleObject(HANDLE Handle,
BOOLEAN Alertable,
PLARGE_INTEGER Timeout)
{
CRouteTime rt(E_NtWaitForSingleObject);
if (rt.Routed()) {
//printf("WaitForSingle(%d, %I64d)\n", Alertable, Timeout->QuadPart);
}
return Real_NtWaitForSingleObject(Handle, Alertable, Timeout);
}
#define IO_CONTROL_AFD_SEND_DATAGRAM 0x12023
#define IO_CONTROL_AFD_SEND 0x1201f
#define IO_CONTROL_AFD_RECV_DATAGRAM 0x1201b
#define IO_CONTROL_AFD_RECV 0x12017
static NTSTATUS NTAPI Catch_NtDeviceIoControlFile(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength)
{
if (IoControlCode == IO_CONTROL_AFD_SEND_DATAGRAM ||
IoControlCode == IO_CONTROL_AFD_SEND) {
CRouteTime rt(E_NtDeviceIoControlFileSend);
NTSTATUS NtStatus = Real_NtDeviceIoControlFile(FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength);
if (NtStatus == STATUS_PENDING) {
LARGE_INTEGER li;
li.QuadPart = INFINITE;
Real_NtWaitForSingleObject(Event, FALSE, &li);
NtStatus = IoStatusBlock->Status;
}
return NtStatus;
}
else if (IoControlCode == IO_CONTROL_AFD_RECV_DATAGRAM ||
IoControlCode == IO_CONTROL_AFD_RECV) {
CRouteTime rt(E_NtDeviceIoControlFileRecv);
return Real_NtDeviceIoControlFile(FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength);
}
else {
CRouteTime rt(E_NtDeviceIoControlFile);
if (rt.Routed()) {
printf("IoControlCode: %08lx\n", IoControlCode);
__debugbreak();
}
return Real_NtDeviceIoControlFile(FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength);
}
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcGetBuffer(RPC_MESSAGE * Message)
{
CRouteTime rt(E_I_RpcGetBuffer);
return Real_I_RpcGetBuffer(Message);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcSendReceive(RPC_MESSAGE * Message)
{
CRouteTime rt(E_I_RpcSendReceive);
return Real_I_RpcSendReceive(Message);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcFreeBuffer(RPC_MESSAGE * Message)
{
CRouteTime rt(E_I_RpcFreeBuffer);
return Real_I_RpcFreeBuffer(Message);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcSend(PRPC_MESSAGE Message)
{
CRouteTime rt(E_I_RpcSend);
return Real_I_RpcSend(Message);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcReceive(PRPC_MESSAGE Message, unsigned int Size)
{
CRouteTime rt(E_I_RpcReceive);
return Real_I_RpcReceive(Message, Size);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcFreePipeBuffer(RPC_MESSAGE * Message)
{
CRouteTime rt(E_I_RpcFreePipeBuffer);
return Real_I_RpcFreePipeBuffer(Message);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcReallocPipeBuffer(PRPC_MESSAGE Message,
unsigned int NewSize)
{
CRouteTime rt(E_I_RpcReallocPipeBuffer);
return Real_I_RpcReallocPipeBuffer(Message, NewSize);
}
static void RPC_ENTRY Catch_I_RpcRequestMutex(I_RPC_MUTEX * Mutex)
{
CRouteTime rt(E_I_RpcRequestMutex);
Real_I_RpcRequestMutex(Mutex);
}
static void RPC_ENTRY Catch_I_RpcClearMutex(I_RPC_MUTEX Mutex)
{
CRouteTime rt(E_I_RpcClearMutex);
Real_I_RpcClearMutex(Mutex);
}
static void * RPC_ENTRY Catch_I_RpcAllocate(unsigned int Size)
{
CRouteTime rt(E_I_RpcAllocate);
return Real_I_RpcAllocate(Size);
}
static void RPC_ENTRY Catch_I_RpcFree(void * Object)
{
CRouteTime rt(E_I_RpcFree);
Real_I_RpcFree(Object);
}
static void RPC_ENTRY Catch_I_RpcPauseExecution(unsigned long Milliseconds)
{
CRouteTime rt(E_I_RpcPauseExecution);
Real_I_RpcPauseExecution(Milliseconds);
}
#if _MSC_VER < 1300
static RPC_STATUS RPC_ENTRY Catch_I_RpcMonitorAssociation(RPC_BINDING_HANDLE Handle,
PRPC_RUNDOWN RundownRoutine,
void * Context)
{
CRouteTime rt(E_I_RpcMonitorAssociation);
return Real_I_RpcMonitorAssociation(Handle, RundownRoutine, Context);
}
static RPC_STATUS RPC_ENTRY Catch_I_RpcStopMonitorAssociation(RPC_BINDING_HANDLE Handle)
{
CRouteTime rt(E_I_RpcStopMonitorAssociation);
return Real_I_RpcStopMonitorAssociation(Handle);
}
#endif
static STDMETHODIMP Catch_IPing_Ping(IPing *pip)
{
HRESULT hr;
InterlockedIncrement(&s_nInCall);
{
CRouteTime rt(E_Proxy);
hr = pip->Ping();
}
InterlockedDecrement(&s_nInCall);
return hr;
}
static STDMETHODIMP Catch_IPing_PingToServer(IPing *pip, LPSTR pszString)
{
HRESULT hr;
InterlockedIncrement(&s_nInCall);
{
CRouteTime rt(E_Proxy);
hr = pip->PingToServer(pszString);
}
InterlockedDecrement(&s_nInCall);
return hr;
}
static STDMETHODIMP Catch_IPing_PingToClient(IPing *pip, LPSTR *ppszString)
{
HRESULT hr;
InterlockedIncrement(&s_nInCall);
{
CRouteTime rt(E_Proxy);
hr = pip->PingToClient(ppszString);
}
InterlockedDecrement(&s_nInCall);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
LONG RerouteEntryPoints(VOID)
{
Real_NtWaitForSingleObject
= ((NTSTATUS (NTAPI *)(HANDLE,
BOOLEAN,
PLARGE_INTEGER))
DetourFindFunction("ntdll.dll", "NtWaitForSingleObject"));
Real_NtDeviceIoControlFile
= ((NTSTATUS (NTAPI *)(HANDLE,
HANDLE,
PIO_APC_ROUTINE,
PVOID,
PIO_STATUS_BLOCK,
ULONG,
PVOID,
ULONG,
PVOID,
ULONG))
DetourFindFunction("ntdll.dll", "NtDeviceIoControlFile"));
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_NtWaitForSingleObject,
Catch_NtWaitForSingleObject);
DetourAttach(&(PVOID&)Real_NtDeviceIoControlFile,
Catch_NtDeviceIoControlFile);
DetourAttach(&(PVOID&)Real_SleepEx,
Catch_SleepEx);
DetourAttach(&(PVOID&)Real_send,
Catch_send);
DetourAttach(&(PVOID&)Real_I_RpcGetBuffer,
Catch_I_RpcGetBuffer);
DetourAttach(&(PVOID&)Real_I_RpcSendReceive,
Catch_I_RpcSendReceive);
DetourAttach(&(PVOID&)Real_I_RpcFreeBuffer,
Catch_I_RpcFreeBuffer);
DetourAttach(&(PVOID&)Real_I_RpcSend,
Catch_I_RpcSend);
DetourAttach(&(PVOID&)Real_I_RpcReceive,
Catch_I_RpcReceive);
DetourAttach(&(PVOID&)Real_I_RpcFreePipeBuffer,
Catch_I_RpcFreePipeBuffer);
DetourAttach(&(PVOID&)Real_I_RpcReallocPipeBuffer,
Catch_I_RpcReallocPipeBuffer);
DetourAttach(&(PVOID&)Real_I_RpcRequestMutex,
Catch_I_RpcRequestMutex);
DetourAttach(&(PVOID&)Real_I_RpcClearMutex,
Catch_I_RpcClearMutex);
DetourAttach(&(PVOID&)Real_I_RpcAllocate,
Catch_I_RpcAllocate);
DetourAttach(&(PVOID&)Real_I_RpcFree,
Catch_I_RpcFree);
DetourAttach(&(PVOID&)Real_I_RpcPauseExecution,
Catch_I_RpcPauseExecution);
#if _MSC_VER < 1300
DetourAttach(&(PVOID&)Real_I_RpcMonitorAssociation,
Catch_I_RpcMonitorAssociation);
DetourAttach(&(PVOID&)Real_I_RpcStopMonitorAssociation,
Catch_I_RpcStopMonitorAssociation);
#endif
return DetourTransactionCommit();
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// Classes.
class CNetPingFactory : public IClassFactory
{
public:
CNetPingFactory();
~CNetPingFactory();
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IClassFactory
STDMETHODIMP CreateInstance(LPUNKNOWN punkOuter, REFIID iid, void **ppv);
STDMETHODIMP LockServer(BOOL fLock);
public:
static HRESULT InitSystem(VOID);
static HRESULT FiniSystem(VOID);
static HRESULT InitObject(VOID);
static HRESULT FiniObject(VOID);
static HRESULT Lock(BOOL fLock);
static HRESULT Wait(VOID);
private:
LONG m_cRef;
static HANDLE s_hevtDone;
static LONG s_nObjects;
static LONG s_nLocks;
};
class CNetPingObject : public IPing
{
public:
CNetPingObject();
~CNetPingObject();
// IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IPing
STDMETHODIMP Ping();
STDMETHODIMP PingToServer(LPSTR pszString);
STDMETHODIMP PingToClient(LPSTR *ppszString);
STDMETHODIMP PingToClientSize(ULONG cbOut);
private:
LONG m_cRef;
ULONG m_cbLast;
ULONG m_cbOut;
};
/////////////////////////////////////////////////////////////////////// GUIDs.
DEFINE_GUID(CLSID_NetPingObject,
0xdecdbeed, 0xd1ac, 0x11d1, 0x96, 0xbc, 0x00, 0xaa, 0x00, 0x57, 0x3f, 0xb0);
/////////////////////////////////////////////////////////// Initialize String.
//
void InitializeString(LPSTR pszString, LONG cbSize)
{
ASSERT(cbSize >= 1);
while (cbSize-- > 1) {
*pszString++ = '+';
}
*pszString = '\0';
}
BOOL GetKeyValue(HKEY hRootKey, PWCHAR pwzKey, PWCHAR pwzValueName, PWCHAR pwzValue,
DWORD cbValue)
{
HKEY hKey;
WCHAR wzKey[256];
HRESULT hr;
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), pwzKey);
if (FAILED(hr)) {
return FALSE;
}
if (RegOpenKeyExW(hRootKey, wzKey, 0, KEY_READ, &hKey) != NO_ERROR) {
abort:
pwzValue[0] = '\0';
return FALSE;
}
DWORD nType = 0;
cbValue -= sizeof(WCHAR);
if (RegQueryValueExW(hKey, pwzValueName, 0, &nType, (PBYTE)pwzValue, &cbValue)
!= NO_ERROR || nType != REG_SZ) {
RegCloseKey(hKey);
goto abort;
}
RegCloseKey(hKey);
cbValue /= sizeof(WCHAR);
pwzValue[cbValue] = L'\0';
return TRUE;
}
static BOOLEAN SetKeyAndValue(HKEY hRootKey,
PWCHAR pwzKey, PWCHAR pwzSubkey,
PWCHAR pwzValueName, PWCHAR pwzValue)
{
HKEY hKey;
WCHAR wzKey[256];
HRESULT hr;
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), pwzKey);
if (FAILED(hr)) {
return FALSE;
}
if (pwzSubkey != NULL) {
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), L"\\");
if (FAILED(hr)) {
return FALSE;
}
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), pwzSubkey);
if (FAILED(hr)) {
return FALSE;
}
}
if (RegCreateKeyExW(hRootKey, wzKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS) {
return FALSE;
}
if (pwzValue != NULL) {
RegSetValueExW(hKey, pwzValueName, 0, REG_SZ,
(BYTE *)pwzValue, (DWORD)wcssize(pwzValue));
}
RegCloseKey(hKey);
return TRUE;
}
static BOOLEAN SetKeyAndValue(HKEY hRootKey,
PWCHAR pwzKey, PWCHAR pwzSubkey,
PWCHAR pwzValueName,
PBYTE pbData, ULONG cbData)
{
HKEY hKey;
WCHAR wzKey[256];
HRESULT hr;
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), pwzKey);
if (FAILED(hr)) {
return FALSE;
}
if (pwzSubkey != NULL) {
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), L"\\");
if (FAILED(hr)) {
return FALSE;
}
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), pwzSubkey);
if (FAILED(hr)) {
return FALSE;
}
}
if (RegCreateKeyExW(hRootKey, wzKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS) {
return FALSE;
}
if (pbData != NULL) {
RegSetValueExW(hKey, pwzValueName, 0, REG_BINARY, pbData, cbData);
}
RegCloseKey(hKey);
return TRUE;
}
static void Register(void)
{
WCHAR wzModule[256];
WCHAR wzName[256];
WCHAR wzValue[256];
WCHAR wzClass[48];
WCHAR wzKey[256];
PWCHAR pwz;
HRESULT hr;
BYTE rgEveryone[] = {
0x01,0x00,0x04,0x80,0x34,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x14,0x00,0x00,0x00,0x02,0x00,0x20,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x15,0x00,0x00,0x00,
0xa0,0x65,0xcf,0x7e,0x78,0x4b,0x9b,0x5f,0xe7,0x7c,0x87,0x70,0x32,0x7f,0x00,0x00,
0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x15,0x00,0x00,0x00,0xa0,0x65,0xcf,0x7e,
0x78,0x4b,0x9b,0x5f,0xe7,0x7c,0x87,0x70,0x32,0x7f,0x00,0x00
};
GetModuleFileNameW(NULL, wzModule, sizeof(wzModule)/sizeof(WCHAR));
if ((pwz = wcsrchr(wzModule, '\\')) != NULL) {
hr = StringCchCopyW(wzName, ARRAYSIZE(wzName), pwz + 1);
}
else if ((pwz = wcsrchr(wzModule, ':')) != NULL) {
hr = StringCchCopyW(wzName, ARRAYSIZE(wzName), pwz + 1);
}
else {
hr = StringCchCopyW(wzName, ARRAYSIZE(wzName), wzModule);
}
CheckResult(hr, "IPing_DllRegisterServer");
// printf("Server: %ls / %ls\n", wzModule, wzName);
StringFromGUID2(CLSID_NetPingObject, wzClass, ARRAYSIZE(wzClass));
// printf(" Class: %ls\n", wzClass);
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), L"CLSID\\");
CheckResult(hr, "IPing_DllRegisterServer");
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), wzClass);
CheckResult(hr, "IPing_DllRegisterServer");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, NULL, L"COM Ping Network Server");
hr = StringCchPrintfW(wzValue, ARRAYSIZE(wzValue), L"%ls /s", wzModule);
CheckResult(hr, "IPing_DllRegisterServer");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, L"LocalServer32", NULL, wzValue);
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, L"LaunchPermission", NULL, L"Y");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, L"AppID", wzClass);
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), L"AppID\\");
CheckResult(hr, "IPing_DllRegisterServer");
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), wzClass);
CheckResult(hr, "IPing_DllRegisterServer");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, NULL, L"COM Ping Network Server");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, L"RunAs", L"Interactive User");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, L"AccessPermission",
rgEveryone, sizeof(rgEveryone));
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), L"AppID\\");
CheckResult(hr, "IPing_DllRegisterServer");
hr = StringCchCatW(wzKey, ARRAYSIZE(wzKey), wzName);
CheckResult(hr, "IPing_DllRegisterServer");
SetKeyAndValue(HKEY_CLASSES_ROOT, wzKey, NULL, L"AppID", wzClass);
/////////////////////////////////////////////////// Register Proxy & Stub.
//
iping_DllRegisterServer();
CheckResult(hr, "IPing_DllRegisterServer");
//////////////////////////////////////////////// Register Processor Speed.
//
DWORD cycles = 0;
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), L"Software\\Microsoft\\Detours\\ProcessorCycles");
CheckResult(hr, "IPing_DllRegisterServer");
if (GetKeyValue(HKEY_LOCAL_MACHINE, wzKey, NULL, wzValue, sizeof(wzValue))) {
cycles = _wtoi(wzValue);
printf("[Recorded Cycles/Second: %ld]\n", cycles);
}
if (cycles < 10000) {
LONGLONG llBeg;
LONGLONG llEnd;
printf("[Calibrating Processors...]\r");
LARGE_INTEGER liBeg;
LARGE_INTEGER liEnd;
LARGE_INTEGER liBrk;
LARGE_INTEGER liFrq;
QueryPerformanceFrequency(&liFrq);
QueryPerformanceCounter(&liBeg);
llBeg = GetTimeStamp();
liBrk.QuadPart = liBeg.QuadPart + liFrq.QuadPart * 5;
do {
QueryPerformanceCounter(&liEnd);
llEnd = GetTimeStamp();
} while (liEnd.QuadPart < liBrk.QuadPart);
double secs = (double)(liEnd.QuadPart - liBeg.QuadPart) / (double)liFrq.QuadPart;
double clks = (double)(llEnd - llBeg);
double cycs = clks / secs;
cycles = (DWORD)cycs;
printf("[Measured Cycles/Second: %ld] \n", cycles);
hr = StringCchPrintfW(wzValue, ARRAYSIZE(wzValue), L"%d", cycles);
CheckResult(hr, "IPing_DllRegisterServer");
SetKeyAndValue(HKEY_LOCAL_MACHINE, wzKey, NULL, NULL, wzValue);
}
}
void Unregister(void)
{
///////////////////////////////////////////////// Unregister Proxy & Stub.
//
HRESULT hr = iping_DllUnregisterServer();
if (FAILED(hr)) {
CheckResult(hr, "IPing_DllUnregisterServer");
}
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT GetClockInfo(LONGLONG *pllCyclesPerSecond)
{
WCHAR wzKey[512];
WCHAR wzValue[128];
LONG cbValue;
HRESULT hr;
////////////////////////////////////////////////////////// Check Registry.
cbValue = sizeof(wzValue);
hr = StringCchCopyW(wzKey, ARRAYSIZE(wzKey), L"Software\\Microsoft\\Detours\\ProcessorCycles");
CheckResult(hr, "GetClockInfo");
if (RegQueryValueW(HKEY_LOCAL_MACHINE, wzKey, wzValue, &cbValue) == NO_ERROR) {
*pllCyclesPerSecond = _wtoi(wzValue);
return S_OK;
}
*pllCyclesPerSecond = 1000000;
return E_FAIL;
}
///////////////////////////////////////////////////////// CNetPingFactory.
//
LONG CNetPingFactory::s_nObjects = 0;
LONG CNetPingFactory::s_nLocks = 0;
HANDLE CNetPingFactory::s_hevtDone = NULL;
CNetPingFactory::CNetPingFactory()
{
m_cRef = 1;
}
CNetPingFactory::~CNetPingFactory()
{
m_cRef = 0;
}
ULONG CNetPingFactory::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
ULONG CNetPingFactory::Release(void)
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return 1;
}
HRESULT CNetPingFactory::InitSystem(VOID)
{
s_nObjects = 0;
s_nLocks = 0;
s_hevtDone = CreateEvent(NULL, FALSE, FALSE, NULL);
if (s_hevtDone == NULL) {
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
CheckResult(hr, "Server: CreateEvent");
exit(hr);
}
return S_OK;
}
HRESULT CNetPingFactory::FiniSystem(VOID)
{
if (s_hevtDone != NULL) {
CloseHandle(s_hevtDone);
s_hevtDone = NULL;
}
return S_OK;
}
HRESULT CNetPingFactory::InitObject(VOID)
{
InterlockedIncrement(&s_nObjects);
return S_OK;
}
HRESULT CNetPingFactory::FiniObject(VOID)
{
if (InterlockedDecrement(&s_nObjects) == 0 && s_nLocks == 0)
SetEvent(s_hevtDone);
return S_OK;
}
HRESULT CNetPingFactory::Lock(BOOL fLock)
{
if (fLock) {
InterlockedIncrement(&s_nLocks);
}
else {
if (InterlockedDecrement(&s_nLocks) == 0 && s_nObjects == 0)
SetEvent(s_hevtDone);
}
return S_OK;
}
HRESULT CNetPingFactory::Wait(VOID)
{
DWORD dwWaitResult;
MSG msg;
for (;;) {
dwWaitResult = MsgWaitForMultipleObjects(1, &s_hevtDone,
FALSE, INFINITE,
QS_ALLINPUT);
if (dwWaitResult == WAIT_OBJECT_0) {
ResetEvent(s_hevtDone);
break;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return S_OK;
}
STDMETHODIMP CNetPingFactory::QueryInterface(REFIID riid, void** ppv)
{
if (ppv == NULL) {
return E_INVALIDARG;
}
if (riid == IID_IClassFactory || riid == IID_IUnknown) {
*ppv = (IClassFactory *) this;
AddRef();
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
HRESULT CNetPingFactory::LockServer (BOOL fLock)
{
return Lock(fLock);
}
STDMETHODIMP CNetPingFactory::CreateInstance(LPUNKNOWN punkOuter,
REFIID riid, void** ppv)
{
LPUNKNOWN punk;
HRESULT hr;
*ppv = NULL;
if (punkOuter != NULL) {
return CLASS_E_NOAGGREGATION;
}
printf(" Server: IClassFactory:CreateInstance\n");
punk = new CNetPingObject;
if (punk == NULL) {
return E_OUTOFMEMORY;
}
hr = punk->QueryInterface(riid, ppv);
punk->Release();
return hr;
}
/////////////////////////////////////////////////////////////// CNetPingObject.
//
CNetPingObject::CNetPingObject()
{
m_cRef = 1;
m_cbLast = ~0u;
m_cbOut = 2;
CNetPingFactory::InitObject();
}
CNetPingObject::~CNetPingObject()
{
CNetPingFactory::FiniObject();
}
STDMETHODIMP CNetPingObject::QueryInterface(REFIID riid, void** ppv)
{
if (ppv == NULL) {
return E_INVALIDARG;
}
if (riid == IID_IUnknown || riid == IID_IPing) {
*ppv = (IPing *) this;
AddRef();
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CNetPingObject::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CNetPingObject::Release(void)
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return 1;
}
STDMETHODIMP CNetPingObject::Ping()
{
return S_OK;
}
STDMETHODIMP CNetPingObject::PingToServer(LPSTR pszString)
{
(void)pszString;
return S_OK;
}
STDMETHODIMP CNetPingObject::PingToClient(LPSTR *ppszString)
{
LPSTR pszString = (LPSTR)CoTaskMemAlloc(m_cbOut);
if (pszString == NULL) {
return E_OUTOFMEMORY;
}
CopyMemory(pszString, g_pBuffer, m_cbOut);
*ppszString = pszString;
return S_OK;
}
STDMETHODIMP CNetPingObject::PingToClientSize(ULONG cbOut)
{
if (cbOut < 1) {
return E_INVALIDARG;
}
InitializeString((LPSTR)g_pBuffer, cbOut);
m_cbOut = cbOut;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
class CSampleRecord
{
public:
DOUBLE m_dTime;
FILETIME m_nWhen;
LONG m_cbToClient;
LONG m_cbToServer;
DOUBLE m_dDcom;
DOUBLE m_dRpc;
DOUBLE m_dUdp;
DOUBLE m_dNet;
protected:
static LONG s_cbToClient;
static LONG s_cbToServer;
public:
CSampleRecord();
CSampleRecord(IPing *pIPing, LONG cbToClient, LONG cbToServer);
HRESULT Measure(IPing *pIPing, LONG cbToClient, LONG cbToServer);
HRESULT Write();
double GetTime() { return m_dTime; }
FILETIME GetWhen() { return m_nWhen; }
LONG GetToClient() { return m_cbToClient; }
LONG GetToServer() { return m_cbToServer; }
};
//////////////////////////////////////////////////////////////////////////////
//
LONG CSampleRecord::s_cbToClient = 0;
LONG CSampleRecord::s_cbToServer = 0;
//////////////////////////////////////////////////////////////////////////////
//
CSampleRecord::CSampleRecord()
{
m_dTime = 0;
m_dDcom = 0;
m_dRpc = 0;
m_dUdp = 0;
m_dNet = 0;
}
CSampleRecord::CSampleRecord(IPing *pIPing, LONG cbToClient, LONG cbToServer)
{
Measure(pIPing, cbToClient, cbToServer);
}
HRESULT CSampleRecord::Measure(IPing *pIPing, LONG cbToClient, LONG cbToServer)
{
HRESULT hr;
LONGLONG llBeg;
LONGLONG llEnd;
GetSystemTimeAsFileTime(&m_nWhen);
m_cbToClient = cbToClient;
m_cbToServer = cbToServer;
if (cbToClient == 0 && cbToServer == 0) {
llBeg = GetTimeStamp();
hr = Catch_IPing_Ping(pIPing);
llEnd = GetTimeStamp();
}
else if (cbToClient) {
if (s_cbToClient != cbToClient) {
hr = pIPing->PingToClientSize(cbToClient);
s_cbToClient = cbToClient;
}
LPSTR pszString = NULL;
llBeg = GetTimeStamp();
hr = Catch_IPing_PingToClient(pIPing, &pszString);
llEnd = GetTimeStamp();
if (pszString) {
LONG cb = (LONG)strlen(pszString) + 1;
ASSERT(cb == cbToClient);
CoTaskMemFree(pszString);
pszString = NULL;
}
}
else {
if (s_cbToServer != cbToServer) {
InitializeString((LPSTR)g_pBuffer, cbToServer);
s_cbToServer = cbToServer;
}
llBeg = GetTimeStamp();
hr = Catch_IPing_PingToServer(pIPing, (LPSTR)g_pBuffer);
llEnd = GetTimeStamp();
}
if (FAILED(hr)) {
printf(";; Operation failed: %08lx\n", hr);
exit(999);
}
if (g_fSummarize) {
SummarizeCycles();
m_dDcom = (double)s_rllCycles[E_DCOM] * g_dMsPerCycle;
m_dRpc = (double)s_rllCycles[E_RPC] * g_dMsPerCycle;
m_dUdp = (double)s_rllCycles[E_UDP] * g_dMsPerCycle;
m_dNet = (double)s_rllCycles[E_NET] * g_dMsPerCycle;
}
m_dTime = (double)(llEnd - llBeg) * g_dMsPerCycle;
return S_OK;
}
HRESULT CSampleRecord::Write()
{
SYSTEMTIME st;
FILETIME ft;
FileTimeToLocalFileTime(&m_nWhen, &ft);
FileTimeToSystemTime(&ft, &st);
printf("%02d/%02d %2d:%02d:%02d %6ld %ld %6.3f [ %6.3f %6.3f %6.3f %6.3f ]\n",
st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
m_cbToClient, m_cbToServer, m_dTime,
m_dDcom, m_dRpc, m_dUdp, m_dNet);
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
double NetTest(HKEY hNetwork, IPing *pIPing,
BOOLEAN fToClient, LONG cbPacket, LONG nCount)
{
//////////////////////////////////////////////////////////////////// ToClient.
//
HRESULT hr;
double msAvg = 0.0;
double msMin = 1.0e12;
double msMax = 0.0;
ULONG nMax = 999;
ULONG nMin = 999;
if (fToClient) {
printf(">Client %6ld %6ld ", cbPacket, nCount);
}
else {
printf(">Server %6ld %6ld ", cbPacket, nCount);
}
for (LONG n = 0; n < nCount; n++) {
double ms;
if (fToClient) {
ms = CSampleRecord(pIPing, cbPacket, 0).GetTime();
}
else {
ms = CSampleRecord(pIPing, 0, cbPacket).GetTime();
}
if (ms < 0) {
break;
}
if (msMin > ms) {
msMin = ms;
nMin = n;
}
if (msMax < ms) {
msMax = ms;
nMax = n;
}
msAvg += ms;
}
if (nCount) {
msAvg /= nCount;
}
if (cbPacket == 0) {
g_dLatency = msMin;
}
double mbps = (double)cbPacket / msMin;
mbps *= 8.0 * 1000.0 / 1024.0 / 1024.0;
double mbps2 = (double)cbPacket / (msMin - g_dLatency);
mbps2 *= 8.0 * 1000.0 / 1024.0 / 1024.0;
if (cbPacket == 0) {
mbps2 = 0;
}
if (hNetwork != NULL) {
WCHAR wzKey[64];
WCHAR wzLatency[64];
if (fToClient) {
hr = StringCchPrintfW(wzKey, ARRAYSIZE(wzKey), L"ToClient\\%d", cbPacket);
CheckResult(hr, "NetTest");
}
else {
hr = StringCchPrintfW(wzKey, ARRAYSIZE(wzKey), L"ToServer\\%d", cbPacket);
CheckResult(hr, "NetTest");
}
hr = StringCchPrintfW(wzLatency, ARRAYSIZE(wzLatency), L"%I64d", msAvg);
CheckResult(hr, "NetTest");
RegSetValueW(hNetwork, wzKey, REG_SZ, wzLatency, (DWORD)wcssize(wzLatency));
}
printf("%8.3f %8.3f %8.3f %9.4f %8.3f %9.4f%3ld\n",
msMin,
msAvg,
msMax,
mbps,
msMin - g_dLatency,
mbps2,
nMax);
return mbps;
}
//////////////////////////////////////////////////////////////////////// main.
static WCHAR wzServers[32][64];
static int nServers = 0;
void Sample_Fixed(IPing *pIPing)
{
CSampleRecord csrRecords[512];
LONG nRecords = 0;
HRESULT hr;
double dAvg = 0;
double dMin = 500000.0;
double dMax = 0.0;
double dMinDcom = dMin;
double dMinRpc = dMin;
double dMinUdp = dMin;
double dMinNet = dMin;
for (int i = 0; i < 512; i++) {
CSampleRecord& csr = csrRecords[nRecords++];
hr = csr.Measure(pIPing, g_nFixedToClient, g_nFixedToServer);
double d = csr.GetTime();
if (dMin > d) {
dMin = d;
}
if (dMax < d) {
dMax = d;
}
if (dMinDcom > csr.m_dDcom) {
dMinDcom = csr.m_dDcom;
}
if (dMinRpc > csr.m_dRpc) {
dMinRpc = csr.m_dRpc;
}
if (dMinUdp > csr.m_dUdp) {
dMinUdp = csr.m_dUdp;
}
if (dMinNet > csr.m_dNet) {
dMinNet = csr.m_dNet;
}
dAvg += d;
}
dAvg /= 512;
printf("size: %ld, min: %.3f, max: %.3f avg: %.3f [ %8.3f %8.3f %8.3f %8.3f ]\n",
g_nFixedToClient, dMin, dMax, dAvg, dMinDcom, dMinRpc, dMinUdp, dMinNet);
for (int n = 0; n < nRecords; n++) {
csrRecords[n].Write();
}
}
void Sample_Simple(IPing *pIPing)
{
CSampleRecord csrRecords[512];
LONG nRecords = 0;
HRESULT hr;
for (int cb = 0; cb < 64000; cb = cb ? cb << 1 : 32) {
double n[5];
int i = 0;
for (; i < 5; i++) {
CSampleRecord& csr = csrRecords[nRecords++];
hr = csr.Measure(pIPing, cb, 0);
n[i] = csr.GetTime();
}
double nAvg = 0;
double nApx = 0;
double nMin = n[0];
double nMax = n[0];
for (i = 0; i < 5; i++) {
if (nMin > n[i]) {
nMin = n[i];
}
if (nMax < n[i]) {
nMax = n[i];
}
nAvg += n[i];
}
nApx = nAvg - nMax;
nAvg /= 5;
nApx /= 4;
printf("min: %8.3f ms (%6d) %7.3f%7.3f%7.3f%7.3f%7.3f:%8.3f%8.3f\n",
nMin, cb, n[0], n[1], n[2], n[3], n[4], nAvg, nApx);
}
for (int n = 0; n < nRecords; n++) {
csrRecords[n].Write();
}
}
void Sample_More(IPing *pIPing)
{
CSampleRecord csrRecords[64];
LONG nRecords = 0;
for (int cb = 0; cb < 64000; cb = cb ? cb << 1 : 32) {
int i = 0;
for (; i < 64; i++) {
CSampleRecord& csr = csrRecords[nRecords++];
csr.Measure(pIPing, cb, 0);
}
double nAvg = 0;
double nMin = csrRecords[0].GetTime();
double nMax = csrRecords[0].GetTime();
for (i = 0; i < 64; i++) {
double n = csrRecords[i].GetTime();
if (nMin > n) {
nMin = n;
}
if (nMax < n) {
nMax = n;
}
nAvg += n;
}
nAvg /= i;
printf("min: %8.3f ms (%6d) : %8.3f %8.3f\n",
nMin, cb, nMax, nAvg);
for (int n = 0; n < nRecords; n++) {
csrRecords[n].Write();
}
nRecords = 0;
}
}
void Sample_Less(IPing *pIPing)
{
CSampleRecord csrRecords[16];
LONG nRecords = 0;
for (int cb = 0; cb < 64000; cb = cb ? cb << 1 : 16) {
int i = 0;
for (; i < 16; i++) {
CSampleRecord& csr = csrRecords[nRecords++];
csr.Measure(pIPing, cb, 0);
}
double nAvg = 0;
double nMin = csrRecords[0].GetTime();
double nMax = csrRecords[0].GetTime();
for (i = 0; i < 16; i++) {
double n = csrRecords[i].GetTime();
if (nMin > n) {
nMin = n;
}
if (nMax < n) {
nMax = n;
}
nAvg += n;
}
nAvg /= i;
printf("min: %8.3f ms (%6d) : %8.3f %8.3f\n",
nMin, cb, nMax, nAvg);
for (int n = 0; n < nRecords; n++) {
csrRecords[n].Write();
}
nRecords = 0;
}
}
void Sample_Profile(IPing *pIPing)
{
CSampleRecord csrRecords[64];
double dbZero = 0;
printf("\nPacket_Size_ Min_Latency Max_Latency Avg_Latency "
"Relative_Bnd ___Bandwidth\n");
for (int cb = 0; cb < 256 * 1024;) {
int n = 0;
for (; n < 64; n++) {
CSampleRecord& csr = csrRecords[n];
csr.Measure(pIPing, cb, 0);
}
double dbAvg = 0;
double dbMin = csrRecords[0].GetTime();
double dbMax = csrRecords[0].GetTime();
LONG nMin = 0;
LONG nMax = 0;
for (n = 0; n < 64; n++) {
double db = csrRecords[n].GetTime();
if (dbMin > db) {
dbMin = db;
nMin = n;
}
if (dbMax < db) {
dbMax = db;
nMax = n;
}
dbAvg += db;
}
dbAvg /= n;
if (cb == 0) {
dbZero = dbMin;
}
double dbBnd = 0;
if (dbMin > dbZero) {
dbBnd = ((8 * cb) * 1000.0) / (1024 * 1024);
dbBnd /= dbMin - dbZero;
}
double dbReal = ((8 * cb) * 1000.0) / (1024 * 1024) / dbMin;
printf("%6d bytes %9.3fms %9.3fms %9.3fms %8.3fMbps %8.3fMbps\r",
cb, dbMin, dbMax, dbAvg, dbBnd, dbReal);
csrRecords[nMin].Write();
if (cb < 2048) {
cb++;
}
else if (cb < 4096) {
cb += 2;
}
else if (cb < 8192) {
cb += 8;
}
else if (cb < 16384) {
cb += 32;
}
else {
cb += 128;
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
class CInit
{
public:
CInit(HINSTANCE hinst)
{
m_hinst = hinst;
AllocConsole();
// initialize COM for free-threading
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
CheckResult(hr, "CoInitializeEx");
exit(hr);
}
ULONG ul = iping_DllMain(m_hinst, DLL_PROCESS_ATTACH, NULL);
ASSERT(ul);
}
~CInit()
{
ULONG ul = iping_DllMain(m_hinst, DLL_PROCESS_DETACH, NULL);
ASSERT(ul);
CoUninitialize();
}
private:
HINSTANCE m_hinst;
};
class CInitStub
{
public:
CInitStub()
{
m_dwRegister = ~0u;
IClassFactory *pClassFactory = NULL;
HRESULT hr = iping_DllGetClassObject(IID_IPing,
IID_IUnknown,
(void **)&pClassFactory);
if (FAILED(hr)) {
CheckResult(hr, "IPing_DllGetClassObject");
ASSERT(SUCCEEDED(hr));
}
if (pClassFactory) {
hr = CoRegisterClassObject(IID_IPing,
pClassFactory,
CLSCTX_SERVER,
REGCLS_MULTIPLEUSE,
&m_dwRegister);
if (FAILED(hr)) {
ASSERT(SUCCEEDED(hr));
CheckResult(hr, "CoRegisterClassObject(IID_IPing)\n");
}
pClassFactory->Release();
pClassFactory = NULL;
}
}
~CInitStub()
{
if (m_dwRegister != ~0u) {
CoRevokeClassObject(m_dwRegister);
m_dwRegister = ~0u;
}
}
private:
DWORD m_dwRegister;
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
int __cdecl main(void)
{
CInit cinit(GetModuleHandle(NULL));
int argc;
WCHAR **argv = CommandLineToArgvW(GetCommandLineW(), &argc);
HRESULT hr;
BOOLEAN fUnreg = FALSE;
BOOLEAN fNeedHelp = FALSE;
BOOLEAN fServer = FALSE;
BOOLEAN fLong = FALSE;
BOOLEAN fProfile = FALSE;
BOOLEAN fInstrument = TRUE;
BOOLEAN fFixed = FALSE;
s_nThread = GetCurrentThreadId();
printf("Ping Network Server: [" __DATE__ " " __TIME__ "]\n");
int arg = 1;
for (; arg < argc; arg++) {
if (argv[arg][0] == '-' || argv[arg][0] == '/') {
WCHAR *argn = argv[arg] + 1;
WCHAR *argp = argn;
while (*argp && *argp != ':') {
argp++;
}
if (*argp == ':') {
*argp++ = '\0';
}
switch (argn[0]) {
case 'f': // Fixed
case 'F':
fFixed = TRUE;
g_nFixedToClient = _wtoi(argp);
g_nFixedToServer = 0;
break;
case 'i':
case 'I': // Instrument
fInstrument = !fInstrument;
break;
case 'n': // Null
case 'N':
fFixed = TRUE;
g_nFixedToClient = g_nFixedToServer = 0;
break;
case 'l': // Long-term loop
case 'L':
fLong = !fLong;
break;
case 'p': // Profile Network
case 'P':
fProfile = !fProfile;
break;
case 's': // Server
case 'S':
fServer = !fServer;
break;
case 'u': // Unregister
case 'U':
fUnreg = !fUnreg;
break;
case 'x': // Xtract Data
case 'X':
g_fSummarize = !g_fSummarize;
break;
case '?': // Help
fNeedHelp = TRUE;
break;
case '\0': // Local Host
hr = StringCchCopyW(wzServers[nServers++], ARRAYSIZE(wzServers[nServers++]),
L"localhost");
if (FAILED(hr)) {
return 900;
}
ASSERT(nServers <= 32);
break;
default:
fNeedHelp = TRUE;
printf("Bad argument: %ls\n", argv[arg]);
break;
}
}
else {
hr = StringCchCopyW(wzServers[nServers++], ARRAYSIZE(wzServers[nServers++]), argv[arg]);
if (FAILED(hr)) {
return 900;
}
ASSERT(nServers <= 32);
}
}
if (argc == 1 || (nServers == 0 && !fUnreg && !fServer)) {
fNeedHelp = TRUE;
}
if (fNeedHelp) {
printf("Usage:\n"
" cping [options] [hosts] ..or.. cping [options] /s\n"
"Options:\n"
" /u : Unregister.\n"
" /s : Act as a server, waiting for clients.\n"
" /? : Display this help screen.\n"
"Client Options:\n"
" /l : Long-term loop test. (Default: %3s)\n"
" /p : Profile test. (Default: %3s)\n"
" /n : Null (0 length) test. (Default: Off)\n"
" /f:size : Fixed sized packets. (Default: %3s)\n"
" /x : Xtract detailed DCOM/RPC/NET data. (Default: %3s)\n"
" /i : Toggle instrumentation. (Default: %3s)\n",
fLong ? "On" : "Off",
fProfile ? "On" : "Off",
fFixed ? "On" : "Off",
g_fSummarize ? "Off" : "Off",
fInstrument ? "On" : "Off");
exit(1);
}
//////////////////////////////////////////////////////////////////////////
if (fUnreg) {
Unregister();
}
else {
//////////////////////////////////////////////////////////////////////////////
//
CInitStub cinitstub;
// Register in the registry.
Register();
if (fInstrument) {
RerouteEntryPoints();
}
LONGLONG llCycles;
hr = GetClockInfo(&llCycles);
ASSERT(SUCCEEDED(hr));
g_dCyclesPerSecond = (double)llCycles;
g_dMsPerCycle = (double)1000.0 / (double)llCycles;
g_pBuffer = CoTaskMemAlloc(g_cbBufferMax);
ASSERT(g_pBuffer != NULL);
if (fServer) {
// register the class-object with OLE
CNetPingFactory::InitSystem();
CNetPingFactory *pClassFactory = new CNetPingFactory;
printf("Registering.\n");
DWORD dwRegister;
hr = CoRegisterClassObject(CLSID_NetPingObject, pClassFactory,
CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
printf("Releasing Registered.\n");
pClassFactory->Release();
if (FAILED(hr)) {
CheckResult(hr, "Server: CoRegisterClassObject");
ASSERT(SUCCEEDED(hr));
}
printf(" Server: Waiting <<<Press Ctrl-C to stop.>>>\n");
while (fServer) {
CNetPingFactory::Wait();
}
hr = CoRevokeClassObject(dwRegister);
if (FAILED(hr)) {
CheckResult(hr, "Server: CoRevokeClassObject");
ASSERT(SUCCEEDED(hr));
}
CNetPingFactory::FiniSystem();
}
else if (nServers) {
LONGLONG llBeg;
LONGLONG llEnd;
COSERVERINFO csi;
MULTI_QI mq;
//////////////////////////////////////////////////////////////////
//
printf("Processor Speed: %.0f MHz\n", g_dCyclesPerSecond / 1000000.0);
DWORD dwSize = ARRAYSIZE(g_wzClientName);
GetComputerNameW(g_wzClientName, &dwSize);
printf(";;; %ls - %.0f MHz\n",
g_wzClientName,
g_dCyclesPerSecond / 1000000.0);
for (int n = 0; n < nServers; n++) {
if (g_wzServerName[0] == '\\' && g_wzServerName[1] == '\\') {
hr = StringCchCopyW(g_wzServerName, ARRAYSIZE(g_wzServerName), wzServers[n] + 2);
}
else {
hr = StringCchCopyW(g_wzServerName, ARRAYSIZE(g_wzServerName), wzServers[n]);
}
CheckResult(hr, "Main");
printf("Server: %ls->%ls\n", g_wzClientName, g_wzServerName);
printf(";; %ls %ls\n", g_wzClientName, g_wzServerName);
ZeroMemory(&csi, sizeof(csi));
csi.pwszName = wzServers[n];
// create a remote instance of the object on the argv[1] machine
mq.pIID = &IID_IPing;
mq.pItf = NULL;
mq.hr = S_OK;
llBeg = GetTimeStamp();
hr = CoCreateInstanceEx(CLSID_NetPingObject, NULL, CLSCTX_SERVER,
&csi, 1, &mq);
llEnd = GetTimeStamp();
printf(" CoCreateInstanceEx: %0.4f seconds (%lu ticks)\n",
(double)(llEnd - llBeg)/(double)llCycles,
(ULONG)(llEnd - llBeg));
CheckResult(mq.hr, "CoCreateInstanceEx [mq]");
CheckResult(hr, "CoCreateInstanceEx");
if (FAILED(hr)) {
CheckResult(hr, "CoCreateInstanceEx");
continue;
}
//////////////////////////////////////////////////////////////////
//
IPing *pIPing = (IPing *)mq.pItf;
hr = pIPing->Ping();
if (FAILED(hr)) {
CheckResult(hr, "Ping");
}
ASSERT(SUCCEEDED(hr));
hr = Catch_IPing_Ping(pIPing);
if (FAILED(hr)) {
CheckResult(hr, "Ping");
}
ASSERT(SUCCEEDED(hr));
ZeroCycles();
if (fFixed) {
Sample_Fixed(pIPing);
}
else if (fProfile) {
Sample_Profile(pIPing);
}
else {
Sample_Simple(pIPing);
if (fLong) {
for (;;) {
Sample_More(pIPing);
for (int j = 0; j < 5; j++) {
Sleep(20000);
Sample_Simple(pIPing);
}
Sleep(20000);
for (int i = 0; i < 18; i++) {
Sample_Less(pIPing);
for (int j = 0; j < 3; j++) {
Sleep(20000);
Sample_Simple(pIPing);
}
Sleep(20000);
}
}
}
}
pIPing->Release();
}
}
if (g_pBuffer) {
CoTaskMemFree(g_pBuffer);
g_pBuffer = NULL;
}
Sleep(2);
if (fInstrument && !g_fSummarize && s_rllCounts[E_Proxy]) {
printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
"::::::::::::::::::\n");
printf(":: Instrumented Cycles: _____Function Time__ "
"________Total Time__ : Count\n");
LONG n = E_DCOM;
for (; n < E_MaxValue; n++) {
s_rllCycles[n] = 0;
s_rllTotals[n] = 0;
s_rllCounts[n] = 0;
}
for (n = E_MinValue + 1; n < E_MaxValue; n++) {
DumpCycles(n);
}
printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
"::::::::::::::::::\n");
printf(":: Protocol Cycles:\n");
for (n = E_DcomBeg; n <= E_DcomEnd; n++) {
s_rllCycles[E_DCOM] += s_rllCycles[n];
s_rllTotals[E_DCOM] += s_rllTotals[n];
s_rllCounts[E_DCOM] += s_rllCounts[n];
}
for (n = E_RpcBeg; n <= E_RpcEnd; n++) {
s_rllCycles[E_RPC] += s_rllCycles[n];
s_rllTotals[E_RPC] += s_rllTotals[n];
s_rllCounts[E_RPC] += s_rllCounts[n];
}
for (n = E_UdpBeg; n <= E_UdpEnd; n++) {
s_rllCycles[E_UDP] += s_rllCycles[n];
s_rllTotals[E_UDP] += s_rllTotals[n];
s_rllCounts[E_UDP] += s_rllCounts[n];
}
for (n = E_NetBeg; n <= E_NetEnd; n++) {
s_rllTotals[E_NET] += s_rllCycles[n];
s_rllCycles[E_NET] += s_rllTotals[n];
s_rllCounts[E_NET] += s_rllCounts[n];
}
DumpCycles(E_DCOM);
DumpCycles(E_RPC);
DumpCycles(E_UDP);
DumpCycles(E_NET);
printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
"::::::::::::::::::\n");
printf(":: Protocol Cycles Per DCOM Call:\n");
s_rllCycles[E_DCOM] /= s_rllCounts[E_DCOM];
s_rllCycles[E_RPC] /= s_rllCounts[E_DCOM];
s_rllCycles[E_UDP] /= s_rllCounts[E_DCOM];
s_rllCycles[E_NET] /= s_rllCounts[E_DCOM];
s_rllTotals[E_DCOM] /= s_rllCounts[E_DCOM];
s_rllTotals[E_RPC] /= s_rllCounts[E_DCOM];
s_rllTotals[E_UDP] /= s_rllCounts[E_DCOM];
s_rllTotals[E_NET] /= s_rllCounts[E_DCOM];
DumpCycles(E_DCOM);
DumpCycles(E_RPC);
DumpCycles(E_UDP);
DumpCycles(E_NET);
}
}
return 0;
}
//
///////////////////////////////////////////////////////////////// End of File.