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.
 |