2246 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			2246 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | //  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.
 |