Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

701 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. DirectPlayConnection
  5. Abstract:
  6. DirectPlayConnection is a wrapper around the direct play interfaces
  7. to just do what is needed for this application. It takes care of
  8. connecting to the remote machine and sending/recieving the connction
  9. paramters.
  10. Author:
  11. Marc Reyhner 7/5/2000
  12. --*/
  13. #include "stdafx.h"
  14. #ifdef TRC_FILE
  15. #undef TRC_FILE
  16. #endif
  17. #define TRC_FILE "rcdpc"
  18. #include "DirectPlayConnection.h"
  19. #include "exception.h"
  20. #include "resource.h"
  21. static BOOL SendLaunchSuccessful(LPDIRECTPLAYLOBBY2 pLobby);
  22. // A structure for passing data to our callback
  23. // function for enumerating the player list.
  24. typedef struct _CALLBACKDATA {
  25. DPID playerID;
  26. BOOL bSet;
  27. } CALLBACKDATA, FAR *LPCALLBACKDATA;
  28. #define DPSYS_CONNECTPARMSMSG 0x0111
  29. typedef struct _DPMSG_CONNECTPARMS
  30. {
  31. DWORD dwType; // Message type
  32. DWORD dwDataSize;
  33. } DPMSG_CONNECTPARMS, FAR *LPDPMSG_CONNECTPARMS;
  34. // Callback function for enumerating the player list.
  35. static BOOL FAR PASCAL
  36. PlayerCallback(
  37. DPID dpId,
  38. DWORD dwPlayerType,
  39. LPCDPNAME lpName,
  40. DWORD dwFlags,
  41. LPVOID lpContext
  42. );
  43. CDirectPlayConnection::CDirectPlayConnection(
  44. )
  45. /*++
  46. Routine Description:
  47. This is the constructor for CDirectPlayConnection. All that
  48. it does is create the direct play lobby.
  49. Arguments:
  50. None
  51. Return Value:
  52. None
  53. --*/
  54. {
  55. HRESULT hr;
  56. DC_BEGIN_FN("CDirectPlayConnection::CDirectPlayConnection");
  57. m_rLobby = NULL;
  58. m_rSettings = NULL;
  59. m_rDirectPlay = NULL;
  60. m_bConnected = FALSE;
  61. m_PlayerID = 0;
  62. hr = CoCreateInstance(CLSID_DirectPlayLobby,NULL,CLSCTX_ALL,
  63. IID_IDirectPlayLobby,(LPVOID*)&m_rLobby);
  64. if (hr != S_OK) {
  65. TRC_ERR((TB,TEXT("Error creating IDirectPlayLobby")));
  66. goto FAILURE;
  67. }
  68. m_hEventHandle = CreateEvent(NULL,FALSE,FALSE,NULL);
  69. if (!m_hEventHandle) {
  70. TRC_ERR((TB,TEXT("Error creating event handle")));
  71. goto FAILURE;
  72. }
  73. DC_END_FN();
  74. return;
  75. FAILURE:
  76. if (m_rLobby) {
  77. m_rLobby->Release();
  78. m_rLobby = NULL;
  79. }
  80. if (m_hEventHandle) {
  81. CloseHandle(m_hEventHandle);
  82. m_hEventHandle = NULL;
  83. }
  84. throw CException(IDS_DPERRORCREATE);
  85. }
  86. CDirectPlayConnection::~CDirectPlayConnection(
  87. )
  88. /*++
  89. Routine Description:
  90. This destroys all the direct play objects that were created.
  91. Arguments:
  92. None
  93. Return Value:
  94. None
  95. --*/
  96. {
  97. DC_BEGIN_FN("CDirectPlayConnection::~CDirectPlayConnection");
  98. if (m_bConnected) {
  99. DisconnectRemoteApplication();
  100. }
  101. if (m_rLobby) {
  102. m_rLobby->Release();
  103. }
  104. if (m_rDirectPlay) {
  105. m_rDirectPlay->Release();
  106. }
  107. if (m_rSettings) {
  108. delete m_rSettings;
  109. }
  110. DC_END_FN();
  111. }
  112. VOID
  113. CDirectPlayConnection::ConnectToRemoteApplication(
  114. )
  115. /*++
  116. Routine Description:
  117. This connects to the remote application. If we were not started
  118. by a lobby application an exception will be thrown at this point.
  119. Arguments:
  120. None
  121. Return Value:
  122. None
  123. --*/
  124. {
  125. DWORD dwSize = 0;
  126. HRESULT hr;
  127. DC_BEGIN_FN("CDirectPlayConnection::ConnectToRemoteApplication");
  128. hr = m_rLobby->GetConnectionSettings(0,NULL,&dwSize);
  129. if (hr != DPERR_BUFFERTOOSMALL) {
  130. TRC_ERR((TB,TEXT("Error getting connection settings size")));
  131. goto FAILURE;
  132. }
  133. m_rSettings = (DPLCONNECTION *)new BYTE [dwSize];
  134. if (!m_rSettings) {
  135. TRC_ERR((TB,TEXT("Out of memory")));
  136. goto FAILURE;
  137. }
  138. hr = m_rLobby->GetConnectionSettings(0,m_rSettings,&dwSize);
  139. if (hr != DP_OK) {
  140. TRC_ERR((TB,TEXT("Error getting connection settings")));
  141. goto FAILURE;
  142. }
  143. /* m_rSettings->lpSessionDesc->dwFlags |= DPSESSION_SECURESERVER;
  144. hr = m_rLobby->SetConnectionSettings(0,0,m_rSettings);
  145. if (hr != DP_OK) {
  146. TRC_ERR((TB,TEXT("Error setting connection settings")));
  147. goto FAILURE;
  148. }*/
  149. hr = m_rLobby->Connect(0,&m_rDirectPlay,NULL);
  150. if (hr != DP_OK) {
  151. TRC_ERR((TB,TEXT("Error connecting to remote application: 0x%8lx"),hr));
  152. goto FAILURE;
  153. }
  154. hr = m_rDirectPlay->CreatePlayer(&m_PlayerID,NULL,m_hEventHandle,NULL,0,0);
  155. if (hr != DP_OK) {
  156. TRC_ERR((TB,TEXT("Error creating player")));
  157. goto FAILURE;
  158. }
  159. m_bConnected = TRUE;
  160. DC_END_FN();
  161. return;
  162. FAILURE:
  163. if (m_rSettings) {
  164. delete m_rSettings;
  165. m_rSettings = NULL;
  166. }
  167. if (m_rDirectPlay) {
  168. m_rDirectPlay->Release();
  169. m_rDirectPlay = NULL;
  170. }
  171. //
  172. // We did a TRC_ERR up where the error was thrown so we won't
  173. // do another here.
  174. //
  175. if (hr == DPERR_NOTLOBBIED) {
  176. throw CException(IDS_DPNOTLOBBIED);
  177. } else {
  178. throw CException(IDS_DPERRORCONNECT);
  179. }
  180. }
  181. VOID
  182. CDirectPlayConnection::DisconnectRemoteApplication(
  183. )
  184. {
  185. DC_BEGIN_FN("CDirectPlayConnection::DisconnectRemoteApplication");
  186. if (!m_bConnected) {
  187. TRC_ERR((TB,TEXT("Not connected to remote application")));
  188. throw CException(IDS_DPNOTCONNECTED);
  189. }
  190. m_rDirectPlay->Close();
  191. m_rDirectPlay->Release();
  192. m_rDirectPlay = NULL;
  193. delete m_rSettings;
  194. m_rSettings = NULL;
  195. m_bConnected = FALSE;
  196. DC_END_FN();
  197. }
  198. VOID
  199. CDirectPlayConnection::SendConnectionParameters(
  200. IN BSTR parms
  201. )
  202. /*++
  203. Routine Description:
  204. This sends the connection parms to the client application
  205. Arguments:
  206. parms - The connection parms for Salem.
  207. Return Value:
  208. None
  209. --*/
  210. {
  211. LPVOID sendBuffer;
  212. DWORD cbSendBuffer;
  213. LPDPMSG_CONNECTPARMS unsecMsg;
  214. DPID otherPlayerID;
  215. HRESULT hr;
  216. DC_BEGIN_FN("CDirectPlayConnection::SendConnectionParameters");
  217. sendBuffer = NULL;
  218. if (!m_bConnected) {
  219. TRC_ERR((TB,TEXT("Not connected to remote application")));
  220. throw CException(IDS_DPNOTCONNECTED);
  221. }
  222. otherPlayerID = xGetOtherPlayerID();
  223. if (m_rSettings->lpSessionDesc->dwFlags & DPSESSION_SECURESERVER) {
  224. hr = m_rDirectPlay->Send(m_PlayerID,otherPlayerID,
  225. DPSEND_ENCRYPTED|DPSEND_GUARANTEED|DPSEND_SIGNED,parms,
  226. (wcslen(parms)+1)*sizeof(OLECHAR));
  227. if (hr != DP_OK) {
  228. TRC_ERR((TB,TEXT("Error sending dp message.")));
  229. throw CException(IDS_DPERRORSEND);
  230. }
  231. } else {
  232. cbSendBuffer = sizeof(DPMSG_CONNECTPARMS) + (wcslen(parms)+1)*sizeof(OLECHAR);
  233. sendBuffer = new BYTE [ cbSendBuffer ];
  234. if (!sendBuffer) {
  235. TRC_ERR((TB,TEXT("Out of memory.")));
  236. throw CException(IDS_DPERRORSEND);
  237. }
  238. unsecMsg = (LPDPMSG_CONNECTPARMS)sendBuffer;
  239. unsecMsg->dwType = DPSYS_CONNECTPARMSMSG;
  240. unsecMsg->dwDataSize = cbSendBuffer - sizeof(DPMSG_CONNECTPARMS);
  241. CopyMemory((LPBYTE)sendBuffer + sizeof(DPMSG_CONNECTPARMS),parms,
  242. unsecMsg->dwDataSize);
  243. hr = m_rDirectPlay->Send(m_PlayerID,otherPlayerID,DPSEND_GUARANTEED,
  244. sendBuffer,cbSendBuffer);
  245. delete sendBuffer;
  246. sendBuffer = NULL;
  247. if (hr != DP_OK) {
  248. TRC_ERR((TB,TEXT("Error sending dp message.")));
  249. throw CException(IDS_DPERRORSEND);
  250. }
  251. }
  252. DC_END_FN();
  253. }
  254. BSTR
  255. CDirectPlayConnection::ReceiveConnectionParameters(
  256. )
  257. /*++
  258. Routine Description:
  259. This reads the connection parms sent by the server. This will
  260. block waiting for the server to send.
  261. Arguments:
  262. None
  263. Return Value:
  264. BSTR - The connection parameters.
  265. --*/
  266. {
  267. BSTR parms = NULL;
  268. DPID otherPlayerID;
  269. LPDPMSG_GENERIC lpMsg;
  270. LPDPMSG_SECUREMESSAGE lpMsgSec = NULL;
  271. LPDPMSG_CONNECTPARMS lpMsgUnsec = NULL;
  272. DWORD dwSize = 0;
  273. DWORD endWaitTime, dwWaitTime;
  274. BOOL bFirstTimeInLoop;
  275. DWORD dwResult;
  276. DC_BEGIN_FN("CDirectPlayConnection::ReceiveConnectionParameters");
  277. if (!m_bConnected) {
  278. TRC_ERR((TB,TEXT("Not connected to remote application")));
  279. throw CException(IDS_DPNOTCONNECTED);
  280. }
  281. otherPlayerID = xGetOtherPlayerID();
  282. endWaitTime = GetTickCount() + GETPARMSTIMEOUT;
  283. bFirstTimeInLoop = TRUE;
  284. while (endWaitTime > GetTickCount()) {
  285. dwWaitTime = endWaitTime - GetTickCount();
  286. if (dwWaitTime <= 0) {
  287. // We hit time between the beginning of the loop
  288. // and now.
  289. break;
  290. }
  291. if (bFirstTimeInLoop) {
  292. bFirstTimeInLoop = FALSE;
  293. } else {
  294. dwResult = WaitForSingleObject(m_hEventHandle,dwWaitTime);
  295. if (dwResult != WAIT_OBJECT_0) {
  296. TRC_ERR((TB,TEXT("Timed waiting for event.")));
  297. goto FAILURE;
  298. }
  299. }
  300. while (lpMsg = xReceiveMessage(0,m_PlayerID,DPRECEIVE_TOPLAYER)) {
  301. if (lpMsg->dwType == DPSYS_SECUREMESSAGE) {
  302. lpMsgSec = (LPDPMSG_SECUREMESSAGE)lpMsg;
  303. if (!(lpMsgSec->dwFlags & (DPSEND_SIGNED|DPSEND_ENCRYPTED))) {
  304. TRC_ERR((TB,TEXT("Message not signed or encrypted.")));
  305. goto FAILURE;
  306. }
  307. parms = (BSTR)new BYTE [lpMsgSec->dwDataSize];
  308. if (!parms) {
  309. TRC_ERR((TB,TEXT("Out of memory")));
  310. goto FAILURE;
  311. }
  312. CopyMemory(parms,lpMsgSec->lpData,lpMsgSec->dwDataSize);
  313. break;
  314. } else if (lpMsg->dwType == DPSYS_CONNECTPARMSMSG) {
  315. lpMsgUnsec = (LPDPMSG_CONNECTPARMS)lpMsg;
  316. parms = (BSTR)new BYTE [lpMsgUnsec->dwDataSize];
  317. if (!parms) {
  318. TRC_ERR((TB,TEXT("Out of memory")));
  319. goto FAILURE;
  320. }
  321. CopyMemory(parms,((PCHAR)lpMsgUnsec) + sizeof(DPMSG_CONNECTPARMS),
  322. lpMsgUnsec->dwDataSize);
  323. break;
  324. } else {
  325. delete lpMsg;
  326. lpMsg = NULL;
  327. }
  328. }
  329. if (lpMsg) {
  330. break;
  331. }
  332. }
  333. if (!lpMsg) {
  334. TRC_ERR((TB,TEXT("No messages ever showed up.")));
  335. goto FAILURE;
  336. }
  337. delete lpMsg;
  338. DC_END_FN();
  339. return parms;
  340. FAILURE:
  341. if (lpMsg) {
  342. delete lpMsg;
  343. }
  344. if (parms) {
  345. delete parms;
  346. }
  347. throw CException(IDS_DPERRORRECEIVE);
  348. }
  349. BOOL
  350. CDirectPlayConnection::IsServer(
  351. )
  352. /*++
  353. Routine Description:
  354. This returns whether or not this is the server.
  355. Arguments:
  356. None
  357. Return Value:
  358. BOOL - Is this the server
  359. --*/
  360. {
  361. DC_BEGIN_FN("CDirectPlayConnection::IsServer");
  362. if (!m_bConnected) {
  363. TRC_ERR((TB,TEXT("Not connected to remote application")));
  364. throw CException(IDS_DPNOTCONNECTED);
  365. }
  366. DC_END_FN();
  367. return (m_rSettings->dwFlags & DPLCONNECTION_CREATESESSION);
  368. }
  369. DPID
  370. CDirectPlayConnection::xGetOtherPlayerID(
  371. )
  372. /*++
  373. Routine Description:
  374. This finds out what the playerID for the remote session is. If the player
  375. has not yet been created we loop waiting for it to be created.
  376. Arguments:
  377. None
  378. Return Value:
  379. None
  380. --*/
  381. {
  382. LPDPMSG_GENERIC lpMsg = NULL;
  383. LPDPMSG_CREATEPLAYERORGROUP lpCreateMsg;
  384. DWORD dwResult;
  385. DWORD dwWaitTime;
  386. DWORD timeOutTime;
  387. DPID otherPlayer = 0;
  388. CALLBACKDATA playerData;
  389. HRESULT hr;
  390. DC_BEGIN_FN("CDirectPlayConnection::xGetOtherPlayerID");
  391. playerData.bSet = FALSE;
  392. hr = m_rDirectPlay->EnumPlayers(NULL,PlayerCallback,&playerData,DPENUMPLAYERS_REMOTE);
  393. if (hr == DP_OK && playerData.bSet) {
  394. DC_END_FN();
  395. return playerData.playerID;
  396. }
  397. timeOutTime = GetTickCount() + GETREMOTEPLAYERTIMEOUT;
  398. while (timeOutTime > GetTickCount()) {
  399. dwWaitTime = timeOutTime - GetTickCount();
  400. if (dwWaitTime <= 0) {
  401. // We hit time between the beginning of the loop
  402. // and now.
  403. break;
  404. }
  405. dwResult = WaitForSingleObject(m_hEventHandle,dwWaitTime);
  406. if (dwResult != WAIT_OBJECT_0) {
  407. TRC_ERR((TB,TEXT("Timed out waiting for event.")));
  408. throw CException(IDS_DPERRORTIMEOUT);
  409. }
  410. while (lpMsg = xReceiveMessage(DPID_SYSMSG,m_PlayerID,
  411. DPRECEIVE_TOPLAYER|DPRECEIVE_FROMPLAYER)) {
  412. if (lpMsg->dwType == DPSYS_CREATEPLAYERORGROUP) {
  413. lpCreateMsg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg;
  414. if (lpCreateMsg->dwPlayerType == DPPLAYERTYPE_PLAYER) {
  415. if (lpCreateMsg->dpId != m_PlayerID) {
  416. otherPlayer = lpCreateMsg->dpId;
  417. break;
  418. }
  419. }
  420. }
  421. delete lpMsg;
  422. }
  423. if (otherPlayer) {
  424. break;
  425. }
  426. }
  427. if (lpMsg) {
  428. delete lpMsg;
  429. }
  430. if (otherPlayer) {
  431. DC_END_FN();
  432. return otherPlayer;
  433. }
  434. TRC_ERR((TB,TEXT("Timed out waiting to find remote player.")));
  435. throw CException(IDS_DPERRORTIMEOUT);
  436. }
  437. static BOOL FAR PASCAL
  438. PlayerCallback(
  439. IN DPID dpId,
  440. IN DWORD dwPlayerType,
  441. IN LPCDPNAME lpName,
  442. IN DWORD dwFlags,
  443. IN OUT LPVOID lpContext
  444. )
  445. /*++
  446. Routine Description:
  447. This is the callback for the direct play player enumeration functin.
  448. We just set what the other playerID is and then return.
  449. Arguments:
  450. None
  451. Return Value:
  452. BOOL - Should we continue the enumeration.
  453. --*/
  454. {
  455. DC_BEGIN_FN("PlayerCallback");
  456. LPCALLBACKDATA data = (LPCALLBACKDATA)lpContext;
  457. data->playerID = dpId;
  458. data->bSet = TRUE;
  459. DC_END_FN();
  460. return FALSE;
  461. }
  462. LPDPMSG_GENERIC
  463. CDirectPlayConnection::xReceiveMessage(
  464. IN DPID from,
  465. IN DPID to,
  466. IN DWORD dwFlags
  467. )
  468. /*++
  469. Routine Description:
  470. This reads the next message for the given from and to addresses.
  471. Arguments:
  472. from - Who the message is from.
  473. to - Who the message is to.
  474. dwFlags - flags for the incoming message.
  475. Return Value:
  476. LPDPMSG_GENERIC - If there was a message.
  477. NULL - There was not a message available.
  478. --*/
  479. {
  480. HRESULT hr;
  481. LPVOID lpMsg;
  482. DWORD dwSize = 0;
  483. DC_BEGIN_FN("CDirectPlayConnection::xReceiveMessage");
  484. hr = m_rDirectPlay->Receive(&from,&to,dwFlags,NULL,&dwSize);
  485. if (hr != DPERR_BUFFERTOOSMALL) {
  486. if (hr == DPERR_NOMESSAGES) {
  487. DC_END_FN();
  488. return NULL;
  489. } else {
  490. TRC_ERR((TB,TEXT("Error receiving message size.")));
  491. goto FAILURE;
  492. }
  493. }
  494. lpMsg = (LPVOID)new BYTE [dwSize];
  495. if (!lpMsg) {
  496. TRC_ERR((TB,TEXT("Out of memory.")));
  497. goto FAILURE;
  498. }
  499. hr = m_rDirectPlay->Receive(&from,&to,dwFlags,lpMsg,&dwSize);
  500. if (hr != DP_OK) {
  501. TRC_ERR((TB,TEXT("Error receiving message.")));
  502. goto FAILURE;
  503. }
  504. DC_END_FN();
  505. return (LPDPMSG_GENERIC)lpMsg;
  506. FAILURE:
  507. if (lpMsg) {
  508. delete lpMsg;
  509. }
  510. throw CException(IDS_DPERRORMSGRECIEVE);
  511. }
  512. static BOOL
  513. SendLaunchSuccessful(
  514. IN OUT LPDIRECTPLAYLOBBY2 pLobby
  515. )
  516. {
  517. HRESULT hr;
  518. DPLMSG_GENERIC msg;
  519. msg.dwType = DPLSYS_DPLAYCONNECTSUCCEEDED;
  520. hr = pLobby->SendLobbyMessage( DPLMSG_STANDARD, 0, &msg, sizeof(msg) );
  521. if ( FAILED(hr) )
  522. {
  523. MessageBox( NULL, TEXT("Send system message failed."), TEXT("Error"), MB_OK |
  524. MB_APPLMODAL );
  525. return false;
  526. }
  527. return true;
  528. }