aboutsummaryrefslogtreecommitdiffhomepage
path: root/samples/cping
diff options
context:
space:
mode:
Diffstat (limited to 'samples/cping')
-rw-r--r--samples/cping/Makefile130
-rw-r--r--samples/cping/ReadMe.Txt47
-rw-r--r--samples/cping/cping.cpp2245
-rw-r--r--samples/cping/cping.dat0
-rw-r--r--samples/cping/iping.idl23
5 files changed, 2445 insertions, 0 deletions
diff --git a/samples/cping/Makefile b/samples/cping/Makefile
new file mode 100644
index 0000000..cc99a09
--- /dev/null
+++ b/samples/cping/Makefile
@@ -0,0 +1,130 @@
+##############################################################################
+##
+## Makefile for Detours Test Programs.
+##
+## Microsoft Research Detours Package
+##
+## Copyright (c) Microsoft Corporation. All rights reserved.
+##
+
+!include ..\common.mak
+
+LIBS=$(LIBS) \
+ kernel32.lib \
+ user32.lib \
+ shell32.lib \
+ uuid.lib \
+ ole32.lib \
+ rpcrt4.lib \
+ advapi32.lib \
+ wsock32.lib \
+
+# RpcProxy.h uses #ifdef WIN32.
+
+!if "$(DETOURS_TARGET_PROCESSOR)" == "ARM"
+CFLAGS = $(CFLAGS) /D_WIN32_WINNT=0x0500
+!else
+CFLAGS = $(CFLAGS) /D_WIN32_WINNT=0x0400
+!endif
+
+CFLAGS = $(CFLAGS) /Fd$(OBJD)\vc.pdb \
+ /DCONST_VTABLE \
+ /DCOBJMACROS -DWIN32 -DNT
+
+C__FLAGS=-DENTRY_PREFIX=iping_ -DREGISTER_PROXY_DLL
+CPPFLAGS=
+
+##############################################################################
+
+.SUFFIXES: .c .cpp .h .idl .obj .res .rc
+
+{$(OBJD)}.c{$(OBJD)}.obj:
+ $(CC) $(CFLAGS:/W4=/W3) $(C__FLAGS) /I$(OBJD) /Fo$(OBJD)\ /c $<
+
+!ifdef DETOURS_ANALYZE
+.cpp{$(OBJD)}.obj:
+ $(CC) $(CFLAGS) $(CPPFLAGS) /I$(OBJD) /Fo$(OBJD)\ /c $<
+!else
+.cpp{$(OBJD)}.obj::
+ $(CC) $(CFLAGS) $(CPPFLAGS) /I$(OBJD) /Fo$(OBJD)\ /c $<
+!endif
+
+.rc{$(OBJD)}.res:
+ rc /nologo /Fo$@ .\$(*B).rc
+
+##############################################################################
+##
+C__FLAGS=-DENTRY_PREFIX=iping_ -DREGISTER_PROXY_DLL
+CPPFLAGS=
+
+
+MIDLFLAGS=/nologo /Oif /no_format_opt
+
+!IF "$(DETOURS_TARGET_PROCESSOR)" == "X86"
+MIDLFLAGS=$(MIDLFLAGS) /no_robust /win32
+!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "IA64"
+MIDLFLAGS=$(MIDLFLAGS) /ia64
+!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "X64"
+MIDLFLAGS=$(MIDLFLAGS) /x64
+!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM"
+MIDLFLAGS=$(MIDLFLAGS) /arm32
+!ELSEIF "$(DETOURS_TARGET_PROCESSOR)" == "ARM64"
+MIDLFLAGS=$(MIDLFLAGS) /arm64
+!ENDIF
+
+OBJS = \
+ $(OBJD)\cping.obj \
+ \
+ $(OBJD)\iping_i.obj \
+ $(OBJD)\iping_p.obj \
+ $(OBJD)\iping_d.obj \
+
+##############################################################################
+
+all: dirs \
+ $(BIND)\cping.exe \
+!IF $(DETOURS_SOURCE_BROWSING)==1
+ $(OBJD)\cping.bsc
+!ENDIF
+
+##############################################################################
+
+clean:
+ -del iping.h *.c *.obj *.sbr *~ 2>nul
+ -del $(BIND)\cping.* 2>nul
+ -rmdir /q /s $(OBJD) 2>nul
+
+realclean: clean
+ -rmdir /q /s $(OBJDS) 2>nul
+
+##############################################################################
+
+dirs:
+ @if not exist $(BIND) mkdir $(BIND) && echo. Created $(BIND)
+ @if not exist $(OBJD) mkdir $(OBJD) && echo. Created $(OBJD)
+
+$(OBJD)\cping.bsc : $(OBJS)
+ bscmake /v /n /o $@ $(OBJS:.obj=.sbr)
+
+$(BIND)\cping.exe : $(OBJS) $(DEPS)
+ cl $(CFLAGS) /Fe$@ $(OBJS) /link $(LINKFLAGS) \
+ /subsystem:console $(LIBS)
+
+$(OBJD)\cping.obj: cping.cpp $(OBJD)\iping.h
+
+##############################################################################
+##
+$(OBJD)\iping.h $(OBJD)\iping_d.c $(OBJD)\iping_i.c $(OBJD)\iping_p.c : iping.idl
+ midl $(MIDLFLAGS) /out $(OBJD) /prefix all iping_ /dlldata iping_d.c iping.idl
+
+$(OBJD)\iping_i.obj: $(OBJD)\iping_i.c
+$(OBJD)\iping_p.obj: $(OBJD)\iping_p.c $(OBJD)\iping.h
+$(OBJD)\iping_d.obj: $(OBJD)\iping_d.c
+
+##############################################################################
+
+test: $(BIND)\cping.exe
+ start $(BIND)\cping.exe /s
+ $(BIND)\cping.exe /p localhost
+
+################################################################# End of File.
diff --git a/samples/cping/ReadMe.Txt b/samples/cping/ReadMe.Txt
new file mode 100644
index 0000000..fea1095
--- /dev/null
+++ b/samples/cping/ReadMe.Txt
@@ -0,0 +1,47 @@
+Microsoft Research Detours Package
+==============================================================================
+4/2/98
+
+* Instrumentation:
+ Read Pentium cycle counter
+
+* PC configuration:
+ DCOM/TCP, Windows NT Server 4.0,
+ between two 300MHz Pentium boxes,
+ Ethernet connecction
+
+* Client test program:
+ HRESULT get(SHORT, SHORT, LONG*)
+ average over 1,000 calls
+ midl /Oicf
+
+* Results:
+ get() {
+ <-- (1)
+ IRpcChannelBuffer::SendReceive()) {
+ <-- (2)
+ I_RpcSendReceive() {
+ <-- (3)
+ send(soc, )
+ <-- (4)
+ NtWaitForSingleObject(soc, )
+ <-- (5)
+ } // end of RPC layer
+ <-- (6)
+ } // end of channel object
+ <-- (7)
+ } // end of client call
+ Average number
+ of Pentium cycles
+ (1) NDR marshaling overhead (2 SHORTs) 13 K
+ (No! of which 11K from GetBuffer,
+ of which 6.2K from I_RpcGetBuffer()!)
+ (2) Channel object one-way (send) overhead 1.0 K
+ (3) RPC layer one-way (send) overhead 5.3 K
+ (4) TCP + all server work 200 K
+ (5) RPC layer one-way (recv) overhead 5.1 K
+ (6) Channel object one-way (recv) overhead 2.2 K
+ (7) NDR unmarshaling overhead (2 LONGs) 4.2 K
+
+ (*) send() only 17 K
+ TOTAL CYCLES for client get(): 230 K
diff --git a/samples/cping/cping.cpp b/samples/cping/cping.cpp
new file mode 100644
index 0000000..4312341
--- /dev/null
+++ b/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.
diff --git a/samples/cping/cping.dat b/samples/cping/cping.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/cping/cping.dat
diff --git a/samples/cping/iping.idl b/samples/cping/iping.idl
new file mode 100644
index 0000000..6713e50
--- /dev/null
+++ b/samples/cping/iping.idl
@@ -0,0 +1,23 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// Module: iping.idl (cping.exe - COM Ping)
+//
+// Microsoft Research Detours Package
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+import "objidl.idl";
+import "oaidl.idl";
+import "oleidl.idl";
+
+
+[object, uuid(decdbeef-d1ac-11d1-96bc-00aa00573fb0), pointer_default(unique)]
+interface IPing : IUnknown
+{
+ HRESULT Ping(void);
+ HRESULT PingToServer([in] LPSTR pszString);
+ HRESULT PingToClient([out] LPSTR *ppszString);
+ HRESULT PingToClientSize([in] ULONG cbOut);
+};
+//
+///////////////////////////////////////////////////////////////// End of File.