home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / Maze / MazeCommon / dplay8client.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  27.6 KB  |  846 lines

  1. //----------------------------------------------------------------------------
  2. // File: dplay8client.cpp
  3. //
  4. // Desc: see main.cpp
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <windows.h>
  9. #include <d3dx.h>
  10. #include <process.h>
  11. #include <tchar.h>
  12. #include <assert.h>
  13. #include <dxerr8.h>
  14. #include <stdio.h>
  15. #include <dplay8.h>
  16. #include <dpaddr.h>
  17. #include "DummyConnector.h"
  18. #include "StressMazeGUID.h"
  19. #include "DXUtil.h"
  20. #include "MazeApp.h"
  21. #include "DPlay8Client.h"
  22.  
  23.  
  24. #define DPMAZESERVER_PORT       2309
  25.       
  26.  
  27.  
  28.  
  29. //-----------------------------------------------------------------------------
  30. // Name: 
  31. // Desc: 
  32. //-----------------------------------------------------------------------------
  33. CDPlay8Client::CDPlay8Client()
  34. {
  35.     m_dwNumSessions = 0;
  36.     
  37.     m_wActiveThreadCount = 0;
  38.     m_wMaxThreadCount = 0;
  39.     m_fAvgThreadCount = 0;
  40.     m_fAvgThreadTime  = 0;
  41.     m_fMaxThreadTime  = 0;
  42.  
  43.     m_pClient       = NULL;
  44.     m_pDPlay        = NULL;
  45.     m_dpnhEnum      = NULL;
  46.     m_bSessionLost  = TRUE;
  47.     m_dwSessionLostReason = DISCONNNECT_REASON_UNKNOWN;
  48.  
  49.     for( DWORD dwIndex = 0; dwIndex < MAX_SESSIONS; dwIndex++ )
  50.     {
  51.         m_pHostAddresses[dwIndex] = NULL;
  52.         m_pDeviceAddresses[dwIndex] = NULL;
  53.     }
  54.  
  55.     InitializeCriticalSection( &m_csLock );
  56.     InitializeCriticalSection( &m_csThreadCountLock );
  57. }
  58.  
  59. //-----------------------------------------------------------------------------
  60. // Name: 
  61. // Desc: 
  62. //-----------------------------------------------------------------------------
  63. CDPlay8Client::~CDPlay8Client()
  64. {
  65.     DeleteCriticalSection( &m_csLock );
  66.     DeleteCriticalSection( &m_csThreadCountLock );
  67. }
  68.  
  69.  
  70. //-----------------------------------------------------------------------------
  71. // Name: 
  72. // Desc: 
  73. //-----------------------------------------------------------------------------
  74. HRESULT CDPlay8Client::Init(MazeConfig* pMazeConfig)
  75. {
  76.     HRESULT hr;
  77.     
  78.     
  79.     m_MazeConfig = pMazeConfig;
  80.  
  81.     Shutdown();
  82.  
  83.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Client, NULL, 
  84.                                        CLSCTX_ALL, IID_IDirectPlay8Client,
  85.                                        (LPVOID*) &m_pDPlay ) ) )
  86.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  87.  
  88.     if( FAILED( hr = m_pDPlay->Initialize( this, StaticReceiveHandler, 0 ) ) )
  89.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  90.  
  91.     // If between Range, attempt to set SPThreads.
  92.     if((m_MazeConfig->dwSPThreads >= MIN_SP_THREADS) && (m_MazeConfig->dwSPThreads <= MAX_SP_THREADS))
  93.     {
  94.         SetNumSPThreads(m_MazeConfig->dwSPThreads);
  95.     }
  96.  
  97.     // If less than MAX, set our SP Buffer.
  98.     if(m_MazeConfig->dwSPBufferSize <= MAX_SP_BUFFER)
  99.     {
  100.         SetSPBuffer(m_MazeConfig->dwSPBufferSize);
  101.     }
  102.     
  103.     m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME );
  104.     m_bSessionLost  = TRUE;
  105.     m_dwNumSessions = 0;
  106.  
  107.     return S_OK;
  108. }
  109.  
  110. //-----------------------------------------------------------------------------
  111. // Name: 
  112. // Desc: 
  113. //-----------------------------------------------------------------------------
  114. DWORD CDPlay8Client::GetNumSPThreads()
  115. {
  116.  
  117.     HRESULT             hr = DPN_OK;
  118.  
  119.     DPN_SP_CAPS         dnSPCaps;
  120.     DWORD               dwFlags = NULL;
  121.     DWORD               dwNumSPThreads = NULL;
  122.  
  123.     DXTRACE_MSG( TEXT("Attempting to Get SP Thread Count.") );
  124.  
  125.     dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
  126.     
  127.     hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  128.     if(hr != DPN_OK)
  129.     {
  130.         DXTRACE_ERR( TEXT("GetSPCaps error"), hr );
  131.         dwNumSPThreads = 0;
  132.     }
  133.     else
  134.     {
  135.         dwNumSPThreads = dnSPCaps.dwNumThreads;
  136.     }
  137.  
  138.     return dwNumSPThreads;
  139.  
  140. }
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: 
  145. // Desc: 
  146. //-----------------------------------------------------------------------------
  147. void CDPlay8Client::SetNumSPThreads(DWORD dwNumSPThreads)
  148. {
  149.     HRESULT             hr = DPN_OK;
  150.     
  151.     DPN_SP_CAPS         dnSPCaps;
  152.     DWORD               dwFlags = NULL;
  153.  
  154.     dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
  155.     hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  156.     if(hr == DPN_OK)
  157.     {
  158.         if((dwNumSPThreads >= MIN_SP_THREADS) && (dwNumSPThreads <= MAX_SP_THREADS))
  159.         {
  160.             dnSPCaps.dwNumThreads = dwNumSPThreads;
  161.             
  162.             // Attempt to set the number of SP Threads.
  163.             hr = m_pDPlay->SetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  164.             if(hr != DPN_OK)
  165.             {
  166.                 DXTRACE_ERR( TEXT("SetSPCaps error."), hr );
  167.             }
  168.         }
  169.     }
  170.     else
  171.     {
  172.         DXTRACE_ERR( TEXT("GetSPCaps error."), hr );
  173.     }
  174.  
  175. }
  176.  
  177. //-----------------------------------------------------------------------------
  178. // Name: 
  179. // Desc: 
  180. //-----------------------------------------------------------------------------
  181. DWORD CDPlay8Client::GetSPBuffer()
  182. {
  183.  
  184.     HRESULT             hr = DPN_OK;
  185.  
  186.     DPN_SP_CAPS         dnSPCaps;
  187.     DWORD               dwFlags = NULL;
  188.     DWORD               dwSPBufferSize = NULL;
  189.  
  190.     DXTRACE_MSG( TEXT("Attempting to Get SP Buffer Size.") );
  191.  
  192.     dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
  193.     
  194.     hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  195.     if(hr != DPN_OK)
  196.     {
  197.         DXTRACE_ERR( TEXT("GetSPCaps error"), hr );
  198.         dwSPBufferSize = 0xffffffff;
  199.     }
  200.     else
  201.     {
  202.         dwSPBufferSize = dnSPCaps.dwSystemBufferSize;
  203.     }
  204.  
  205.     return dwSPBufferSize;
  206.  
  207. }
  208.  
  209.  
  210. //-----------------------------------------------------------------------------
  211. // Name: 
  212. // Desc: 
  213. //-----------------------------------------------------------------------------
  214. void CDPlay8Client::SetSPBuffer(DWORD dwSPBufferSize)
  215. {
  216.     HRESULT             hr = DPN_OK;
  217.     
  218.     DPN_SP_CAPS         dnSPCaps;
  219.     DWORD               dwFlags = NULL;
  220.  
  221.     dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
  222.     hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  223.     if(hr == DPN_OK)
  224.     {
  225.         if(dwSPBufferSize <= MAX_SP_BUFFER)
  226.             dnSPCaps.dwSystemBufferSize = dwSPBufferSize;
  227.  
  228.         // Attempt to set the number of SP Threads.
  229.         hr = m_pDPlay->SetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
  230.         if(hr != DPN_OK)
  231.         {
  232.             DXTRACE_ERR( TEXT("SetSPCaps error."), hr );
  233.         }
  234.     }
  235.     else   // !GetSPCase != DPN_OK
  236.     {
  237.         DXTRACE_ERR( TEXT("GetSPCaps error."), hr );
  238.     }
  239.  
  240. }
  241.  
  242.  
  243. //-----------------------------------------------------------------------------
  244. // Name: 
  245. // Desc: 
  246. //-----------------------------------------------------------------------------
  247. void CDPlay8Client::Shutdown()
  248. {
  249.     for( DWORD dwIndex = 0; dwIndex < MAX_SESSIONS; dwIndex++ )
  250.     {
  251.         SAFE_RELEASE( m_pHostAddresses[dwIndex] );
  252.         SAFE_RELEASE( m_pDeviceAddresses[dwIndex] );
  253.     }
  254.  
  255.     if( m_dpnhEnum != NULL )
  256.     {
  257.         // Cancel the enumeration if its in progress, and ignore any errors
  258.         m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
  259.         m_dpnhEnum = NULL;
  260.     }
  261.  
  262.     if( m_pDPlay != NULL )
  263.         m_pDPlay->Close(0);
  264.  
  265.     SAFE_RELEASE( m_pDPlay );
  266.     m_bSessionLost  = TRUE;
  267.     m_dwNumSessions = 0;
  268. }
  269.  
  270.  
  271.  
  272.  
  273. //-----------------------------------------------------------------------------
  274. // Name: 
  275. // Desc: 
  276. //-----------------------------------------------------------------------------
  277. HRESULT CDPlay8Client::StartSessionEnum( const TCHAR* ipaddress )
  278. {
  279.     if( NULL == m_pDPlay )
  280.         return E_FAIL;
  281.  
  282.     DPN_APPLICATION_DESC   dpnAppDesc;
  283.     IDirectPlay8Address*   pDP8AddressHost  = NULL;
  284.     IDirectPlay8Address*   pDP8AddressLocal = NULL;
  285.     WCHAR*                 wszHostName      = NULL;
  286.     HRESULT                hr;
  287.     DWORD                  dwPort;
  288.  
  289.     m_dwNumSessions = 0;
  290.  
  291.     if( m_dpnhEnum != NULL )
  292.     {
  293.         // If an enumeration is already running, cancel 
  294.         // it and start a new one.  Ignore any errors from CancelAsyncOperation
  295.         m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
  296.         m_dpnhEnum = NULL;
  297.     }
  298.  
  299.     // Create the local device address object
  300.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  301.                                        CLSCTX_ALL, IID_IDirectPlay8Address,
  302.                                        (LPVOID*) &pDP8AddressLocal ) ) )
  303.     {
  304.         DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  305.         goto LCleanup;
  306.     }
  307.  
  308.     // Set IP service provider
  309.     if( FAILED( hr = pDP8AddressLocal->SetSP( &CLSID_DP8SP_TCPIP ) ) )
  310.     {
  311.         DXTRACE_ERR( TEXT("SetSP"), hr );
  312.         goto LCleanup;
  313.     }
  314.  
  315.  
  316.     // Create the remote host address object
  317.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  318.                                        CLSCTX_ALL, IID_IDirectPlay8Address,
  319.                                        (LPVOID*) &pDP8AddressHost ) ) )
  320.     {
  321.         DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  322.         goto LCleanup;
  323.     }
  324.  
  325.     // Set IP service provider
  326.     if( FAILED( hr = pDP8AddressHost->SetSP( &CLSID_DP8SP_TCPIP ) ) )
  327.     {
  328.         DXTRACE_ERR( TEXT("SetSP"), hr );
  329.         goto LCleanup;
  330.     }
  331.  
  332.     // Maze uses a fixed port, so add it to the host address
  333.     dwPort = DPMAZESERVER_PORT;
  334.     hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT, 
  335.                                       &dwPort, sizeof(dwPort),
  336.                                       DPNA_DATATYPE_DWORD );
  337.     if( FAILED(hr) )
  338.     {
  339.         DXTRACE_ERR( TEXT("AddComponent"), hr );
  340.         goto LCleanup;
  341.     }
  342.  
  343.     // Set the remote host name (if provided)
  344.     if( ipaddress != NULL && ipaddress[0] != 0 )
  345.     {
  346.         wszHostName = new WCHAR[_tcslen(ipaddress)+1];
  347.  
  348.         DXUtil_ConvertGenericStringToWide( wszHostName, ipaddress );
  349.  
  350.         hr = pDP8AddressHost->AddComponent( DPNA_KEY_HOSTNAME, wszHostName, 
  351.                                             (wcslen(wszHostName)+1)*sizeof(WCHAR), 
  352.                                             DPNA_DATATYPE_STRING );
  353.         if( FAILED(hr) )
  354.         {
  355.             DXTRACE_ERR( TEXT("AddComponent"), hr );
  356.             goto LCleanup;
  357.         }
  358.     }
  359.  
  360.     ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) );
  361.     dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
  362.     dpnAppDesc.guidApplication = StressMazeAppGUID;
  363.  
  364.     // Enumerate all StressMazeApp hosts running on IP service providers
  365.     hr = m_pDPlay->EnumHosts( &dpnAppDesc, pDP8AddressHost, 
  366.                               pDP8AddressLocal, NULL, 
  367.                               0, INFINITE, 0, INFINITE, NULL, 
  368.                               &m_dpnhEnum, 0 );
  369.     if( hr != DPNERR_PENDING && FAILED(hr) )
  370.     {
  371.         DXTRACE_ERR_NOMSGBOX( TEXT("EnumHosts"), hr );
  372.         goto LCleanup;
  373.     }
  374.  
  375. LCleanup:
  376.     SAFE_RELEASE( pDP8AddressHost);
  377.     SAFE_RELEASE( pDP8AddressLocal );
  378.     SAFE_DELETE( wszHostName );
  379.  
  380.     return hr;
  381. }
  382.  
  383.  
  384.  
  385.  
  386. //-----------------------------------------------------------------------------
  387. // Name: 
  388. // Desc: 
  389. //-----------------------------------------------------------------------------
  390. HRESULT CDPlay8Client::StopSessionEnum()
  391. {
  392.     if( NULL == m_pDPlay )
  393.         return E_FAIL;
  394.  
  395.     // If an enumeration is already running, cancel it and ignore
  396.     // any errors from CancelAsyncOperation
  397.     if( m_dpnhEnum != NULL )
  398.     {
  399.         m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
  400.         m_dpnhEnum = NULL;
  401.     }
  402.  
  403.     return S_OK;
  404. }
  405.  
  406.  
  407.  
  408.  
  409. //-----------------------------------------------------------------------------
  410. // Name: 
  411. // Desc: 
  412. //-----------------------------------------------------------------------------
  413. BOOL CDPlay8Client::EnumSessionCallback( const DPN_APPLICATION_DESC *pdesc, 
  414.                                          IDirectPlay8Address* pDP8AddressHost,
  415.                                          IDirectPlay8Address* pDP8AddressDevice )
  416. {
  417.     if( NULL == m_pDPlay )
  418.         return DPN_OK;
  419.  
  420.     EnterCriticalSection( &m_csLock );
  421.  
  422.     if( m_dwNumSessions < MAX_SESSIONS )
  423.     {
  424.         // Search for existing record for this session, if 
  425.         // there is one, break this loop so we just update
  426.         // the current entry.
  427.         for( DWORD dwIndex = 0; dwIndex < m_dwNumSessions; dwIndex++ )
  428.         {
  429.             if( m_Sessions[dwIndex].guidInstance == pdesc->guidInstance )
  430.                 break;
  431.         }
  432.         
  433.         memcpy( &m_Sessions[dwIndex], pdesc, sizeof( DPN_APPLICATION_DESC ) );
  434.  
  435.         // Copy pDP8AddressHost to m_pHostAddresses[dwIndex]
  436.         SAFE_RELEASE( m_pHostAddresses[dwIndex] );
  437.         pDP8AddressHost->QueryInterface( IID_IDirectPlay8Address, 
  438.                                          (LPVOID*) &m_pHostAddresses[dwIndex] );
  439.  
  440.         // Copy pDP8AddressDevice to m_pDeviceAddresses[dwIndex]
  441.         SAFE_RELEASE( m_pDeviceAddresses[dwIndex] );
  442.         pDP8AddressDevice->QueryInterface( IID_IDirectPlay8Address, 
  443.                                          (LPVOID*) &m_pDeviceAddresses[dwIndex] );
  444.  
  445.         if( pdesc->pwszSessionName != NULL )
  446.         {
  447.             DXUtil_ConvertWideStringToGeneric( m_szSessionNames[dwIndex], 
  448.                                                pdesc->pwszSessionName );
  449.         }
  450.         else
  451.         {
  452.             _tcscpy( m_szSessionNames[dwIndex], TEXT("Untitled") );
  453.         }
  454.  
  455.         if( m_dwNumSessions == dwIndex )
  456.             m_dwNumSessions++;
  457.     }
  458.  
  459.     LeaveCriticalSection( &m_csLock );
  460.  
  461.     return DPN_OK;
  462. }
  463.  
  464.  
  465.  
  466.  
  467. //-----------------------------------------------------------------------------
  468. // Name: 
  469. // Desc: 
  470. //-----------------------------------------------------------------------------
  471. HRESULT CDPlay8Client::JoinSession( DWORD num )
  472. {
  473.     HRESULT hr;
  474.     IDirectPlay8Address* pHostAddress = NULL;
  475.     IDirectPlay8Address* pDeviceAddress = NULL;
  476.  
  477.     if( m_pDPlay == NULL )
  478.         return E_FAIL;
  479.  
  480.     DXTRACE( TEXT("MazeClient: Trying to connect to server\n") );
  481.  
  482.     DPN_APPLICATION_DESC dpnAppDesc;
  483.     ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) );
  484.     dpnAppDesc.dwSize          = sizeof( DPN_APPLICATION_DESC );
  485.     dpnAppDesc.guidApplication = StressMazeAppGUID;
  486.     dpnAppDesc.guidInstance    = m_Sessions[num].guidInstance;
  487.  
  488.     EnterCriticalSection( &m_csLock );
  489.     
  490.     // Copy the host and device address pointers, and addref them.
  491.     // If this is not done, then there is a rare chance that 
  492.     // EnumSessionCallback() may be called during the Connect() call 
  493.     // and destory the address before DirectPlay gets a chance to copy them.
  494.     pHostAddress = m_pHostAddresses[num];
  495.     pHostAddress->AddRef();
  496.  
  497.     pDeviceAddress = m_pDeviceAddresses[num];
  498.     pDeviceAddress->AddRef();
  499.  
  500.     LeaveCriticalSection( &m_csLock );
  501.  
  502.     // Connect to the remote host
  503.     // The enumeration is automatically canceled after Connect is called 
  504.     if( FAILED( hr = m_pDPlay->Connect( &dpnAppDesc,        // Application description
  505.                                         pHostAddress,       // Session host address
  506.                                         pDeviceAddress,     // Address of device used to connect to the host
  507.                                         NULL, NULL,         // Security descriptions & credientials (MBZ in DPlay8)
  508.                                         NULL, 0,            // User data & its size
  509.                                         NULL,               // Asynchronous connection context (returned with DPNMSG_CONNECT_COMPLETE in async handshaking)
  510.                                         NULL,               // Asynchronous connection handle (used to cancel connection process)
  511.                                         DPNOP_SYNC ) ) )    // Connect synchronously
  512.     {
  513.         if( hr == DPNERR_NORESPONSE || hr == DPNERR_ABORTED )
  514.             goto LCleanup; // These are possible if the server exits while joining 
  515.  
  516.         if( hr == DPNERR_INVALIDINSTANCE )
  517.             goto LCleanup; // This is possible if the original server exits and another server comes online while we are connecting
  518.  
  519.         DXTRACE_ERR_NOMSGBOX( TEXT("Connect"), hr );
  520.         goto LCleanup;
  521.     }
  522.  
  523.     m_bSessionLost = FALSE;
  524.     
  525.     DXTRACE( TEXT("MazeClient: Connected to server.  Enum automatically canceled\n") );
  526.  
  527.     UpdateConnectionInfo();
  528.     m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME );
  529.  
  530.  
  531. LCleanup:
  532.     SAFE_RELEASE( pHostAddress );
  533.     SAFE_RELEASE( pDeviceAddress );
  534.  
  535.     return hr;
  536. }
  537.  
  538.  
  539.  
  540.  
  541. //-----------------------------------------------------------------------------
  542. // Name: 
  543. // Desc: 
  544. //-----------------------------------------------------------------------------
  545. HRESULT CDPlay8Client::SendPacket( void* pData, DWORD dwSize, 
  546.                                    BOOL bGuaranteed, DWORD dwTimeout )
  547. {
  548.     if( NULL == m_pDPlay )
  549.         return S_OK;
  550.  
  551.     DPNHANDLE  hAsync;
  552.     DWORD      dwFlags;
  553.     DPNHANDLE* phAsync;
  554.  
  555.     if( bGuaranteed )
  556.     {
  557.         // If we are guaranteed then we must specify
  558.         // DPNSEND_NOCOMPLETE and pass in non-null for the 
  559.         // pvAsyncContext
  560.         dwFlags = DPNSEND_GUARANTEED;
  561.     }
  562.     else
  563.     {
  564.         // If we aren't guaranteed then we can
  565.         // specify DPNSEND_NOCOMPLETE.  And when 
  566.         // DPNSEND_NOCOMPLETE is on pvAsyncContext
  567.         // must be NULL.
  568.         dwFlags = DPNSEND_NOCOMPLETE;
  569.     }
  570.     
  571.     // Must pass in a value for the Asyn handle. Will be thrown when proc completes.
  572.     phAsync = &hAsync;
  573.  
  574.     DPN_BUFFER_DESC dpnBufferDesc;
  575.     dpnBufferDesc.dwBufferSize = dwSize;
  576.     dpnBufferDesc.pBufferData = (PBYTE) pData;
  577.  
  578.     // Update the throughput counter
  579.     m_dwThroughputBytes += dwSize;
  580.  
  581.     // DirectPlay will tell via the message handler 
  582.     // if there are any severe errors, so ignore any errors 
  583.     m_pDPlay->Send( &dpnBufferDesc, 1, dwTimeout, 
  584.                     NULL, phAsync, dwFlags );
  585.  
  586.     return S_OK;
  587. }
  588.  
  589.  
  590.  
  591.  
  592. //-----------------------------------------------------------------------------
  593. // Name: 
  594. // Desc: 
  595. //-----------------------------------------------------------------------------
  596. HRESULT CDPlay8Client::StaticReceiveHandler( void *pvContext, DWORD dwMessageType, 
  597.                                              void *pvMessage )
  598. {
  599.     CDPlay8Client* pThisObject = (CDPlay8Client*) pvContext;
  600.  
  601.     return pThisObject->ReceiveHandler( pvContext, dwMessageType, pvMessage );
  602. }
  603.  
  604.  
  605.  
  606. //-----------------------------------------------------------------------------
  607. // Name: 
  608. // Desc: 
  609. //-----------------------------------------------------------------------------
  610. HRESULT CDPlay8Client::ReceiveHandler( void *pvContext, DWORD dwMessageType, 
  611.                                        void *pvMessage )
  612. {
  613.      // Increment our Active Thread Counter.
  614.     EnterCriticalSection( &m_csThreadCountLock );
  615.  
  616.     //Get the time when we entered the Message Handler
  617.     FLOAT fStartTime = DXUtil_Timer( TIMER_GETAPPTIME );
  618.  
  619.     m_wActiveThreadCount++;
  620.  
  621.     if(m_wActiveThreadCount > m_wMaxThreadCount)
  622.         m_wMaxThreadCount = m_wActiveThreadCount;
  623.  
  624.     
  625.     // Calculate an average.
  626.     FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount;
  627.     m_fAvgThreadCount += fdiff/8;
  628.     
  629.     LeaveCriticalSection( &m_csThreadCountLock );
  630.  
  631.     
  632.     switch( dwMessageType )
  633.     {
  634.         case DPN_MSGID_RECEIVE:
  635.         {
  636.             PDPNMSG_RECEIVE pRecvData = (PDPNMSG_RECEIVE) pvMessage;
  637.  
  638.             // Update the throughput counter
  639.             m_dwThroughputBytes += pRecvData->dwReceiveDataSize;
  640.  
  641.             if( m_pClient != NULL )
  642.             {
  643.                 m_pClient->OnPacket( pRecvData->dpnidSender, 
  644.                                      pRecvData->pReceiveData, 
  645.                                      pRecvData->dwReceiveDataSize );
  646.             }
  647.             break;
  648.         }
  649.         
  650.         case DPN_MSGID_TERMINATE_SESSION:
  651.         {
  652.             m_dwSessionLostReason = DISCONNNECT_REASON_UNKNOWN;
  653.             PDPNMSG_TERMINATE_SESSION pTermMsg = (PDPNMSG_TERMINATE_SESSION) pvMessage;
  654.  
  655.             // The MazeServer passes a DWORD in pvTerminateData if 
  656.             // it disconnected us, otherwise it will be null.
  657.             if( pTermMsg->pvTerminateData != NULL )
  658.             {
  659.                 DWORD* pdw = (DWORD*) pTermMsg->pvTerminateData;
  660.                 m_dwSessionLostReason = *pdw;
  661.             }
  662.  
  663.             if( m_pClient != NULL )
  664.                 m_pClient->OnSessionLost( m_dwSessionLostReason );
  665.  
  666.             // Now that the session is lost we need to restart DirectPlay by calling
  667.             // Close() and Init() on m_pDPlay, however this can not be 
  668.             // done in the DirectPlay message callback, so the main thread will
  669.             // do this when IsSessionLost() returns TRUE
  670.             m_bSessionLost = TRUE;
  671.             break;
  672.         }
  673.  
  674.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  675.         {
  676.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumResponse = (PDPNMSG_ENUM_HOSTS_RESPONSE) pvMessage;
  677.  
  678.             EnumSessionCallback( pEnumResponse->pApplicationDescription, 
  679.                                  pEnumResponse->pAddressSender,
  680.                                  pEnumResponse->pAddressDevice );
  681.             break;
  682.         }
  683.     }
  684.  
  685.  
  686.     EnterCriticalSection( &m_csThreadCountLock );
  687.     
  688.     m_wActiveThreadCount-- ;
  689.     
  690.     // Calculate an average.
  691.  
  692.     FLOAT fDiffTime = ( DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime ) - m_fAvgThreadTime;
  693.     m_fAvgThreadTime += fDiffTime/8;
  694.  
  695.     //Get the Max time in the thread.
  696.     if ( fDiffTime > m_fMaxThreadTime )
  697.     {
  698.         m_fMaxThreadTime = fDiffTime;
  699.     }
  700.     
  701.     LeaveCriticalSection( &m_csThreadCountLock );
  702.  
  703.     return S_OK;
  704. }
  705.  
  706.  
  707. //-----------------------------------------------------------------------------
  708. // Name: 
  709. // Desc: 
  710. //-----------------------------------------------------------------------------
  711. HRESULT CDPlay8Client::UpdateConnectionInfo()
  712. {
  713.     if( NULL == m_pDPlay )
  714.         return E_FAIL;
  715.  
  716.     // Update the DPN_CONNECTION_INFO every 1/2 second...
  717.     float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
  718.     if( fCurTime - m_fLastUpdateConnectInfoTime > 0.5f )
  719.     {
  720.         // Call GetConnectionInfo to get DirectPlay stats about connection 
  721.         ZeroMemory( &m_dpnConnectionInfo, sizeof(DPN_CONNECTION_INFO) );
  722.         m_dpnConnectionInfo.dwSize = sizeof(DPN_CONNECTION_INFO);
  723.         m_pDPlay->GetConnectionInfo( &m_dpnConnectionInfo, 0 );
  724.  
  725.         // Call GetSendQueueInfo to get DirectPlay stats about messages
  726.         m_pDPlay->GetSendQueueInfo( &m_dwHighPriMessages, &m_dwHighPriBytes, 
  727.                                     DPNGETSENDQUEUEINFO_PRIORITY_HIGH );
  728.         m_pDPlay->GetSendQueueInfo( &m_dwNormalPriMessages, &m_dwNormalPriBytes, 
  729.                                     DPNGETSENDQUEUEINFO_PRIORITY_NORMAL );
  730.         m_pDPlay->GetSendQueueInfo( &m_dwLowPriMessages, &m_dwLowPriBytes, 
  731.                                     DPNGETSENDQUEUEINFO_PRIORITY_LOW );
  732.  
  733.         m_fLastUpdateConnectInfoTime = fCurTime;
  734.     }
  735.  
  736.     return S_OK;
  737. }
  738.  
  739.  
  740.  
  741.  
  742. //-----------------------------------------------------------------------------
  743. // Name: 
  744. // Desc: 
  745. //-----------------------------------------------------------------------------
  746. DWORD CDPlay8Client::GetThroughputBPS()
  747. {
  748.     static float s_fLastThroughputBPSTime = DXUtil_Timer( TIMER_GETAPPTIME );
  749.     float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
  750.     if( fCurTime - s_fLastThroughputBPSTime > 1.0f )
  751.     {
  752.         m_fThroughputBPS         = (float) m_dwThroughputBytes / (fCurTime - s_fLastThroughputBPSTime);
  753.  
  754.         s_fLastThroughputBPSTime = fCurTime;
  755.         m_dwThroughputBytes      = 0;
  756.     }
  757.  
  758.     return (DWORD) m_fThroughputBPS;
  759. }
  760.  
  761.  
  762.  
  763.  
  764. //-----------------------------------------------------------------------------
  765. // Name: 
  766. // Desc: 
  767. //-----------------------------------------------------------------------------
  768. DWORD CDPlay8Client::GetRoundTripLatencyMS()
  769. {
  770.     UpdateConnectionInfo();
  771.     return m_dpnConnectionInfo.dwRoundTripLatencyMS;
  772. }
  773.  
  774.  
  775.  
  776.  
  777. //-----------------------------------------------------------------------------
  778. // Name: 
  779. // Desc: 
  780. //-----------------------------------------------------------------------------
  781. HRESULT CDPlay8Client::GetConnectionInfo( TCHAR* strConnectionInfo )
  782. {
  783.     UpdateConnectionInfo();
  784.  
  785.     _stprintf( strConnectionInfo, 
  786.                TEXT("     Thread Count: Current=%d Avg= %.2f Max=%d\n")      \
  787.                TEXT("     Thread Time:  Avg= %.4f Max=%.4f(s)\n")      \
  788.                                                                         \
  789.                TEXT("     Round Trip Latency MS=%dms\n")                      \
  790.                TEXT("     Throughput BPS: Current=%d Peak=%d\n")              \
  791.                                                                         \
  792.                TEXT("     Messages Received=%d\n")                            \
  793.                                                                         \
  794.                TEXT("     Sent: GB=%d GP=%d NGB=%d NGP=%d\n")                 \
  795.                TEXT("     Received: GB=%d GP=%d NGB=%d NGP=%d\n")             \
  796.                                                                         \
  797.                TEXT("     Messages Transmitted: HP=%d NP=%d LP=%d\n")         \
  798.                TEXT("     Messages Timed Out: HP=%d NP=%d LP=%d\n")           \
  799.                                                                         \
  800.                TEXT("     Retried: GB=%d GP=%d\n")                            \
  801.                TEXT("     Dropped: NGB=%d NGP=%d\n")                          \
  802.                                                                         \
  803.                TEXT("     Send Queue Messages: HP=%d NP=%d LP=%d\n")          \
  804.                TEXT("     Send Queue Bytes: HP=%d NP=%d LP=%d\n"),            \
  805.                                                                         \
  806.                                                                         \
  807.                                                                         \
  808.                m_wActiveThreadCount, m_fAvgThreadCount, m_wMaxThreadCount,
  809.                m_fAvgThreadTime, m_fMaxThreadTime,
  810.                m_dpnConnectionInfo.dwRoundTripLatencyMS, 
  811.                m_dpnConnectionInfo.dwThroughputBPS, 
  812.                m_dpnConnectionInfo.dwPeakThroughputBPS,
  813.  
  814.                m_dpnConnectionInfo.dwMessagesReceived,
  815.  
  816.                m_dpnConnectionInfo.dwBytesSentGuaranteed,
  817.                m_dpnConnectionInfo.dwPacketsSentGuaranteed,
  818.                m_dpnConnectionInfo.dwBytesSentNonGuaranteed,
  819.                m_dpnConnectionInfo.dwPacketsSentNonGuaranteed,
  820.  
  821.                m_dpnConnectionInfo.dwBytesReceivedGuaranteed,
  822.                m_dpnConnectionInfo.dwPacketsReceivedGuaranteed,
  823.                m_dpnConnectionInfo.dwBytesReceivedNonGuaranteed,
  824.                m_dpnConnectionInfo.dwPacketsReceivedNonGuaranteed,
  825.  
  826.                m_dpnConnectionInfo.dwMessagesTransmittedHighPriority,
  827.                m_dpnConnectionInfo.dwMessagesTransmittedNormalPriority,
  828.                m_dpnConnectionInfo.dwMessagesTransmittedLowPriority,
  829.  
  830.                m_dpnConnectionInfo.dwMessagesTimedOutHighPriority,
  831.                m_dpnConnectionInfo.dwMessagesTimedOutNormalPriority,
  832.                m_dpnConnectionInfo.dwMessagesTimedOutLowPriority,
  833.  
  834.                m_dpnConnectionInfo.dwBytesRetried,
  835.                m_dpnConnectionInfo.dwPacketsRetried,
  836.  
  837.                m_dpnConnectionInfo.dwBytesDropped,
  838.                m_dpnConnectionInfo.dwPacketsDropped,
  839.  
  840.                m_dwHighPriMessages, m_dwNormalPriMessages, m_dwLowPriMessages, 
  841.                m_dwHighPriBytes, m_dwNormalPriBytes, m_dwLowPriBytes
  842.                );
  843.  
  844.     return S_OK;
  845. }
  846.