ClientStage.cpp
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:10k
源码类别:

模拟服务器

开发平台:

C/C++

  1. #include "ClientStage.h"
  2. #include "KSG_EncodeDecode.h"
  3. #include <time.h>
  4. #include "Utils.h"
  5. #include "Exception.h"
  6. using OnlineGameLib::Win32::CIOBuffer;
  7. using OnlineGameLib::Win32::CException;
  8. using OnlineGameLib::Win32::Output;
  9. using OnlineGameLib::Win32::CCriticalSection;
  10. using OnlineGameLib::Win32::CWin32Exception;
  11. /*
  12.  * Get client factory interface
  13.  */
  14. STDAPI CreateInterface( REFIID riid, void **ppv )
  15. {
  16. HRESULT hr = E_NOINTERFACE;
  17. if ( IID_IClientFactory == riid )
  18. {
  19. CClientFactory *pObject = new CClientFactory;
  20. *ppv = reinterpret_cast< void * > ( dynamic_cast< IClientFactory * >( pObject ) );
  21. if ( *ppv )
  22. {
  23. reinterpret_cast< IUnknown * >( *ppv )->AddRef();
  24. hr = S_OK;
  25. }
  26. }
  27. if ( FAILED( hr ) )
  28. {
  29. *ppv = NULL;
  30. }
  31. return ( HRESULT )( hr );
  32. }
  33. static unsigned gs_holdrand = time(NULL);
  34. static inline unsigned _Rand()
  35. {
  36.     gs_holdrand = gs_holdrand * 214013L + 2531011L;
  37.      
  38.     return gs_holdrand;
  39. }
  40. static inline void RandMemSet(int nSize, unsigned char *pbyBuffer)
  41. {
  42.     _ASSERT(nSize);
  43.     _ASSERT(pbyBuffer);
  44.     while (nSize--)
  45.     {
  46.         *pbyBuffer++ = (unsigned char)_Rand();
  47.     }
  48. }
  49. /*
  50.  * class CGameClient
  51.  */
  52. CGameClient::CGameClient( size_t maxFreeBuffers, 
  53. size_t maxFreeBuffers_Cache,
  54. size_t bufferSize_Cache /*= 8192*/,
  55. size_t bufferSize /*= 1024*/ )
  56. : OnlineGameLib::Win32::CSocketClient( maxFreeBuffers, bufferSize )
  57. , m_theCacheAllocator( bufferSize_Cache, maxFreeBuffers_Cache )
  58. , m_lRefCount( 0 )
  59. , m_pfnCallbackClientEvent( NULL )
  60. {
  61. m_pReadBuffer = m_theCacheAllocator.Allocate();
  62. m_pRecvBuffer = m_theCacheAllocator.Allocate();
  63. }
  64. CGameClient::~CGameClient()
  65. {
  66. m_pReadBuffer->Release();
  67. m_pRecvBuffer->Release();
  68. }
  69. STDMETHODIMP CGameClient::Startup()
  70. {
  71. HRESULT hr = E_FAIL;
  72. try
  73. {
  74. Start();
  75. hr = S_OK;
  76. }
  77. catch( const CException &e )
  78. {
  79. Output( _T("CGameClient::Startup Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  80. }
  81. catch(...)
  82. {
  83. Output( _T("CGameClient::Startup - Unexpected exception") );
  84. }
  85. return hr;
  86. }
  87. STDMETHODIMP CGameClient::Cleanup()
  88. {
  89. HRESULT hr = E_FAIL;
  90. try
  91. {
  92. StopConnections();
  93. WaitForShutdownToComplete();
  94. hr = S_OK;
  95. }
  96. catch( const CException &e )
  97. {
  98. Output( _T("CConnectManager::Cleanup Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  99. }
  100. catch(...)
  101. {
  102. Output( _T("CConnectManager::Cleanup Unexpected exception") );
  103. }
  104. return hr;
  105. }
  106. STDMETHODIMP CGameClient::ConnectTo(
  107. const char * const &pAddressToConnectServer, 
  108. unsigned short usPortToConnectServer )
  109. {
  110. HRESULT hr = E_FAIL;
  111. try
  112. {
  113. Connect( pAddressToConnectServer, usPortToConnectServer );
  114. if ( StartConnections() )
  115. {
  116. hr = S_OK;
  117. }
  118. }
  119. catch( const CException &e )
  120. {
  121. Output( _T("Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  122. }
  123. catch(...)
  124. {
  125. Output( _T("Unexpected exception") );
  126. }
  127. return hr;
  128. }
  129. STDMETHODIMP CGameClient::RegisterMsgFilter( 
  130. LPVOID lpParam, 
  131. CALLBACK_CLIENT_EVENT pfnEventNotify )
  132. {
  133. m_lpCallBackParam = lpParam;
  134. m_pfnCallbackClientEvent = pfnEventNotify;
  135. return S_OK;
  136. }
  137. STDMETHODIMP CGameClient::SendPackToServer(
  138. const void * const pData,
  139. const size_t &datalength )
  140. {
  141. static const size_t s_len_protocol = sizeof( WORD );
  142. if ( !pData || 0 == datalength )
  143. {
  144. return E_FAIL;
  145. }
  146. CIOBuffer *pBuffer = Allocate();
  147. /*
  148.  * Add package header
  149.  */
  150. const size_t headlength = s_len_protocol + datalength;
  151. pBuffer->AddData( reinterpret_cast< const char * >( &headlength ), s_len_protocol );
  152. unsigned uOldKey = m_uClientKey;
  153. pBuffer->AddData( reinterpret_cast< const char* const >( pData ), datalength );
  154. _ASSERT(m_uKeyMode == 0);
  155. KSG_EncodeBuf(
  156. datalength,
  157. (unsigned char *)(pBuffer->GetBuffer() + s_len_protocol),
  158.         &m_uClientKey
  159. );
  160. Write( pBuffer );
  161. pBuffer->Release();
  162. return S_OK;
  163. }
  164. STDMETHODIMP_( const void * ) CGameClient::GetPackFromServer( size_t &datalength )
  165. {
  166. CCriticalSection::Owner locker( m_csReadAction );
  167. m_pReadBuffer->Empty();
  168. m_pRecvBuffer = ProcessDataStream( m_pRecvBuffer );
  169. const BYTE *pPackData = m_pReadBuffer->GetBuffer();
  170. datalength = m_pReadBuffer->GetUsed();
  171. return reinterpret_cast<const char*>( pPackData );
  172. }
  173. STDMETHODIMP CGameClient::Shutdown()
  174. {
  175. StopConnections();
  176. return S_OK;
  177. }
  178. STDMETHODIMP CGameClient::QueryInterface( REFIID riid, void** ppv )
  179. {
  180. /*
  181.  * By definition all COM objects support the IUnknown interface
  182.  */
  183. if( riid == IID_IUnknown )
  184. {
  185. AddRef();
  186. *ppv = dynamic_cast< IUnknown * >( this );
  187. }
  188. else if ( riid == IID_IESClient )
  189. {
  190. AddRef();
  191. *ppv = dynamic_cast< IClient * >( this );
  192. }
  193. else
  194. {
  195. *ppv = NULL;
  196. return E_NOINTERFACE;
  197. }
  198. return S_OK;
  199. }
  200.     
  201. STDMETHODIMP_(ULONG) CGameClient::AddRef()
  202. {
  203. return InterlockedIncrement( &m_lRefCount );
  204. }
  205. STDMETHODIMP_(ULONG) CGameClient::Release()
  206. {
  207. if ( InterlockedDecrement( &m_lRefCount ) > 0 )
  208. {
  209. return m_lRefCount;
  210. }
  211. delete this;
  212. return 0L;
  213. }
  214. void CGameClient::ProcessCommand( const OnlineGameLib::Win32::CIOBuffer *pBuffer)
  215. {
  216. static const size_t s_len_protocol = sizeof( WORD );
  217. const BYTE *pPackData = pBuffer->GetBuffer();
  218. const size_t used = pBuffer->GetUsed();
  219. if ( used <= s_len_protocol )
  220. {
  221.         return;
  222. }
  223. _ASSERT(m_uKeyMode == 0);
  224. KSG_DecodeBuf(
  225. used - s_len_protocol, 
  226. (unsigned char *)( pPackData + s_len_protocol ), 
  227. &m_uServerKey
  228. );
  229.     m_pReadBuffer->AddData( ( const BYTE * )( pPackData + s_len_protocol ), used - s_len_protocol );
  230. }
  231. size_t CGameClient::GetMinimumMessageSize() const
  232. {
  233. static size_t length = sizeof( WORD ) + sizeof( BYTE );
  234. /*
  235.      * The smallest possible command we accept is a byte onlye package
  236.  */
  237. return length;
  238. }
  239. size_t CGameClient::GetMessageSize( 
  240. const OnlineGameLib::Win32::CIOBuffer *pBuffer ) const
  241. {
  242. const BYTE *pData = pBuffer->GetBuffer();   
  243. const size_t used = pBuffer->GetUsed();
  244. WORD wHeadLen = ( WORD )( *( WORD * )( pData ) );
  245. return ( size_t )( wHeadLen );
  246. }
  247. OnlineGameLib::Win32::CIOBuffer *CGameClient::ProcessDataStream( 
  248. OnlineGameLib::Win32::CIOBuffer *pBuffer)
  249. {
  250. const size_t used = pBuffer->GetUsed();
  251. if ( used >= GetMinimumMessageSize() )
  252. {
  253. const size_t messageSize = GetMessageSize( pBuffer );
  254. if ( messageSize == 0 )
  255. {
  256. /*
  257.  * havent got a complete message yet.
  258.  * we null terminate our messages in the buffer, so we need to reserve
  259.  * a byte of the buffer for this purpose...
  260.  */
  261. if ( used == ( pBuffer->GetSize() - 1 ) )
  262. {
  263. Output( _T("Too much data!") );
  264. /*
  265.  * Write this message and then shutdown the sending side of the socket.
  266.  */
  267. Output( "found error and close this connection!" );
  268. Shutdown();
  269. /*
  270.  * throw the rubbish away
  271.  */
  272. pBuffer->Empty();
  273. }
  274. }
  275. else if ( used == messageSize )
  276. {
  277. Output( _T("Got a complete message and begin to process it") );
  278. /*
  279.  * we have a whole, distinct, message
  280.  */
  281. ProcessCommand( pBuffer );
  282. pBuffer->Empty();
  283. }
  284. else if (used > messageSize)
  285. {
  286. Output(_T("Got message plus extra data"));
  287. /*
  288.  * we have a message, plus some more data
  289.  * 
  290.  * allocate a new buffer, copy the extra data into it and try again...
  291.  */
  292. OnlineGameLib::Win32::CIOBuffer *pMessage = pBuffer->SplitBuffer( messageSize );
  293. ProcessCommand( pMessage );
  294. pMessage->Release();
  295. }
  296. }
  297. /*
  298.  * Reissue a read into the same buffer to collect more data
  299.  */
  300. return pBuffer;
  301. }
  302. void CGameClient::OnStartConnections()
  303. {
  304. if ( m_pfnCallbackClientEvent )
  305. {
  306. m_pfnCallbackClientEvent( m_lpCallBackParam, enumServerConnectCreate );
  307. }
  308. }
  309. void CGameClient::OnStopConnections()
  310. {
  311. if ( m_pfnCallbackClientEvent )
  312. {
  313. m_pfnCallbackClientEvent( m_lpCallBackParam, enumServerConnectClose );
  314. }
  315. }
  316. void CGameClient::ReadCompleted( OnlineGameLib::Win32::CIOBuffer *pBuffer )
  317. {
  318. try
  319. {
  320. const BYTE *pPackData = pBuffer->GetBuffer();
  321. size_t used = pBuffer->GetUsed();
  322. if (used > 0)
  323. {
  324. CCriticalSection::Owner locker( m_csReadAction );
  325. m_pRecvBuffer->AddData( reinterpret_cast< const char * >( pPackData ), used );
  326. }
  327. pBuffer->Empty();
  328. }
  329. catch(const CException &e)
  330. {
  331. Output( _T("ReadCompleted - Exception - ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  332. StopConnections();
  333. }
  334. catch(...)
  335. {
  336. Output( _T("ReadCompleted - Unexpected exception") );
  337. StopConnections();
  338. }
  339. }
  340. CClientFactory::CClientFactory()
  341. : m_lRefCount( 0 ),
  342. m_bufferSize( 0 )
  343. {
  344. }
  345. CClientFactory::~CClientFactory()
  346. {
  347. }
  348. STDMETHODIMP CClientFactory::SetEnvironment( const size_t &bufferSize )
  349. {
  350. m_bufferSize = bufferSize;
  351. return S_OK;
  352. }
  353. STDMETHODIMP CClientFactory::CreateClientInterface( REFIID riid, void** ppv )
  354. {
  355. HRESULT hr = E_NOINTERFACE;
  356. if ( IID_IESClient == riid )
  357. {
  358. const size_t bufferSize = ( m_bufferSize > 0 ) ? m_bufferSize : ( 1024 * 4 );
  359. CGameClient *pObject = new CGameClient( 2, 2, bufferSize, 1024 );
  360. *ppv = reinterpret_cast< void * > ( dynamic_cast< IClient * >( pObject ) );
  361. if ( *ppv )
  362. {
  363. reinterpret_cast< IUnknown * >( *ppv )->AddRef();
  364. hr = S_OK;
  365. }
  366. }
  367. if ( FAILED( hr ) )
  368. {
  369. *ppv = NULL;
  370. }
  371. return ( HRESULT )( hr );
  372. }
  373. STDMETHODIMP CClientFactory::QueryInterface( REFIID riid, void** ppv )
  374. {
  375. /*
  376.  * By definition all COM objects support the IUnknown interface
  377.  */
  378. if( riid == IID_IUnknown )
  379. {
  380. AddRef();
  381. *ppv = dynamic_cast< IUnknown * >( this );
  382. }
  383. else if ( riid == IID_IClientFactory )
  384. {
  385. AddRef();
  386. *ppv = dynamic_cast< IClientFactory * >( this );
  387. }
  388. else
  389. {
  390. *ppv = NULL;
  391. return E_NOINTERFACE;
  392. }
  393. return S_OK;
  394. }
  395.     
  396. STDMETHODIMP_(ULONG) CClientFactory::AddRef()
  397. {
  398. return ::InterlockedIncrement( &m_lRefCount );
  399. }
  400. STDMETHODIMP_(ULONG) CClientFactory::Release()
  401. {
  402. if ( ::InterlockedDecrement( &m_lRefCount ) > 0 )
  403. {
  404. return m_lRefCount;
  405. }
  406. delete this;
  407. return 0L;
  408. }