diff options
Diffstat (limited to 'ext/detours/samples/cping/cping.cpp')
-rw-r--r-- | ext/detours/samples/cping/cping.cpp | 2245 |
1 files changed, 2245 insertions, 0 deletions
diff --git a/ext/detours/samples/cping/cping.cpp b/ext/detours/samples/cping/cping.cpp new file mode 100644 index 0000000..4312341 --- /dev/null +++ b/ext/detours/samples/cping/cping.cpp @@ -0,0 +1,2245 @@ +////////////////////////////////////////////////////////////////////////////// +// +// 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. |