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.

1445 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. Protocol.c
  5. Abstract:
  6. Another Reliable Protocol (on DirectPlay)
  7. Author:
  8. Aaron Ogus (aarono)
  9. Environment:
  10. Win32
  11. Revision History:
  12. Date Author Description
  13. ====== ====== ============================================================
  14. 12/10/96 aarono Original
  15. 05/11/97 aarono convert from C++ COM object to 'C' library
  16. 2/03/98 aarono fixed ProtocolGetCaps for RAW
  17. 2/18/98 aarono changed InitProtocol to work later in connect process
  18. added new API handlers SendEx, GetMessageQueue, stub Cancel
  19. 2/18/98 aarono added Cancel support
  20. 2/19/98 aarono don't hook Shutdown anymore, dplay calls us
  21. explicitly on DP_OPEN (InitProtocol) DP_CLOSE (FiniProtocol)
  22. 2/20/98 aarono B#18827 not pulling cancelled sends from Q properly
  23. 3/5/98 aarono B#18962 allow non-reliable enumsessions reply when using protocol
  24. this avoids a bug where a remote on an invalid IPX net enums us
  25. and we get bogged down with RIPing in the response path. Actually hangs
  26. the machine and sometimes crashes IPX.
  27. 6/6/98 aarono Turn on throttling and windowing
  28. Notes:
  29. All direct calls from DPLAY to the PROTOCOL occur in this file.
  30. --*/
  31. #include <windows.h>
  32. #include <mmsystem.h>
  33. #include <dplay.h>
  34. #include <dplaysp.h>
  35. #include <dplaypr.h>
  36. #include "mydebug.h"
  37. #include "handles.h"
  38. #include "arpd.h"
  39. #include "arpdint.h"
  40. #include "macros.h"
  41. #include "mytimer.h"
  42. /*
  43. Protocol Object Life:
  44. =====================
  45. The protocol object is allocated on the DPLAY interface immediately after
  46. the call to SPInit. The protocol block is allocated and tacked onto the
  47. DPLAY interface. If the object is not allocated, the protocol pointer
  48. will be NULL.
  49. When the SP shutdown handler is called, the protocol object is released,
  50. first making sure that all other structures off of the protocol have
  51. been freed and all memory pools have been freed.
  52. SESSION Life:
  53. =============
  54. Sessions are the structures that support the connection of a pair of
  55. PLAYERS. For each target playerid there is a SESSION structure.
  56. SESSIONS are accessed by converting playerids into indices into a
  57. session array, valid sessions are filled in, invalid or not yet seen
  58. ones are NULL. A session is allocated for every call to the SP
  59. CreatePlayer routine. When a DeletePlayer is received, the session
  60. is freed. There are races to create players and delete players so
  61. the session state is tracked. If the session is not in the OPEN
  62. state, mesages for the session are ABORTED/IGNORED(?). When the
  63. player is being removed, there may be stragling receives, these
  64. are rejected. Any packet received for a non-existent session is
  65. dropped. When a session is being closed, all pending sends are
  66. first completed.
  67. SEND Life:
  68. ==========
  69. STATISTICS Life:
  70. ================
  71. RECEIVE Life:
  72. =============
  73. How we hook in:
  74. ===============
  75. Receive:
  76. --------
  77. HandlePacket in the ISP table has been replaced by the protocol's
  78. ProtocolHandlePacket routine. Each call to HandlePacket comes along
  79. with a pISP, from which we derive the pProtocol. If no pProtocol exits
  80. on the object, then we just call the old HandlePacket routine, otherwise
  81. we examine the packet and do our thing depending on what type of message
  82. it is and/or negotiated session parameters.
  83. Send/CreatePlayer/DeletePlayer/Shutdown:
  84. ----------------------------------------
  85. If we install:
  86. We replace the interface pointers to these SP callbacks with our own and
  87. remember the existing ones. When we are called we do our processing and
  88. then call the handler in the SP. In the case of Send, we may not even
  89. call because we need to packetize the message.
  90. We also replace the packet size information in the SPData structure so that
  91. directplay's packetize and send code won't try to break up messages before
  92. we get them. System messages that we don't handle hopefully don't exceed
  93. the actual maximum frame size, else they will fail on a non-reliable
  94. transport.
  95. */
  96. #ifdef DEBUG
  97. extern VOID My_GlobalAllocInit();
  98. extern VOID My_GlobalAllocDeInit();
  99. #endif
  100. //
  101. // Global pools should only be inited once, this counts opens.
  102. // No lock req'd since calls to spinit serialized in DirectPlay itself.
  103. //
  104. UINT nInitCount = 0;
  105. /*=============================================================================
  106. InitProtocol - initialize the protocol block and hook into the send path.
  107. Description:
  108. After each SP is initialized (in SPInit) this routine is called to
  109. hook the SP callbacks for the protocol. Also the protocol information
  110. for this instance of the protocol is allocated and initialized.
  111. Parameters:
  112. LPSPINITDATA pInitData - initialization block that was passed to the
  113. SP. We use it to hook in.
  114. Return Values:
  115. DP_OK - successfully hooked in.
  116. pProtocol on DIRECTPLAY object points to protocol obj.
  117. DPERR_GENERIC - didn't hook in. Also pProtocol in the DIRECTPLAY
  118. object will be NULL.
  119. -----------------------------------------------------------------------------*/
  120. HRESULT WINAPI InitProtocol(DPLAYI_DPLAY *lpDPlay)
  121. {
  122. PPROTOCOL pProtocol;
  123. HRESULT hr;
  124. #define TABLE_INIT_SIZE 16
  125. #define TABLE_GROW_SIZE 16
  126. #ifdef DEBUG
  127. My_GlobalAllocInit();
  128. #endif
  129. // Allocate the protocol block;
  130. pProtocol=My_GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,sizeof(PROTOCOL));
  131. if(!pProtocol){
  132. hr=DPERR_NOMEMORY;
  133. goto exit;
  134. }
  135. //
  136. // Initialize protocol variables.
  137. //
  138. pProtocol->m_lpDPlay=lpDPlay;
  139. pProtocol->m_lpISP=lpDPlay->pISP;
  140. pProtocol->m_dwSPHeaderSize=lpDPlay->dwSPHeaderSize;
  141. pProtocol->m_nSendThreads=0; // we support any number of send threads!
  142. pProtocol->m_eState=Initializing; // we are initing
  143. InitializeCriticalSection(&pProtocol->m_ObjLock);
  144. InitializeCriticalSection(&pProtocol->m_SPLock);
  145. // Session lookup by ID list.
  146. InitializeCriticalSection(&pProtocol->m_SessionLock);
  147. pProtocol->m_SessionListSize=0;
  148. pProtocol->m_pSessions=NULL;
  149. // GLOBAL SENDQ
  150. InitializeCriticalSection(&pProtocol->m_SendQLock);
  151. InitBilink(&pProtocol->m_GSendQ);
  152. //
  153. // Get Multi-Media Timer Information.
  154. //
  155. if( timeGetDevCaps(&pProtocol->m_timecaps,sizeof(TIMECAPS)) != TIMERR_NOERROR ){
  156. // make em up
  157. ASSERT(0);
  158. pProtocol->m_timecaps.wPeriodMin=5;
  159. pProtocol->m_timecaps.wPeriodMax=10000000;
  160. }
  161. // Send Thread Triggers - waits for Sends, DataGram IDs or Reliable IDs.
  162. pProtocol->m_hSendEvent=CreateEventA(NULL, FALSE, FALSE, NULL);
  163. if(!pProtocol->m_hSendEvent){
  164. ASSERT(0); //TRACE all paths.
  165. hr=DPERR_NOMEMORY;
  166. goto exit1;
  167. }
  168. // Various descriptor pools.
  169. // These can't fail.
  170. if(!nInitCount){
  171. InitializeCriticalSection(&g_SendTimeoutListLock);
  172. InitBilink(&g_BilinkSendTimeoutList);
  173. // only allocated once per process.
  174. InitSendDescs();
  175. InitSendStats();
  176. InitFrameBuffers();
  177. InitBufferManager();
  178. InitBufferPool();
  179. }
  180. InitRcvDescs(pProtocol);
  181. nInitCount++;
  182. //
  183. // Get the datagram frame size from the SP
  184. //
  185. {
  186. DPCAPS Caps;
  187. DPSP_GETCAPSDATA GetCapsData;
  188. memset(&Caps,0,sizeof(DPCAPS));
  189. Caps.dwMaxBufferSize = 0;
  190. Caps.dwSize = sizeof(DPCAPS);
  191. GetCapsData.dwFlags = 0;
  192. GetCapsData.lpCaps = &Caps;
  193. GetCapsData.idPlayer = 0;
  194. GetCapsData.lpISP = lpDPlay->pISP;
  195. CALLSP(lpDPlay->pcbSPCallbacks->GetCaps, &GetCapsData);
  196. pProtocol->m_dwSPMaxFrame=GetCapsData.lpCaps->dwMaxBufferSize;
  197. if(pProtocol->m_dwSPMaxFrame > 1400){
  198. // Necessary since UDP reports huge capacity even though no receiver can
  199. // successfully receive a datagram of that size without throttle.
  200. pProtocol->m_dwSPMaxFrame = 1400;
  201. }
  202. GetCapsData.dwFlags = DPCAPS_GUARANTEED;
  203. hr=CALLSP(lpDPlay->pcbSPCallbacks->GetCaps, &GetCapsData);
  204. if(hr==DP_OK){
  205. pProtocol->m_dwSPMaxGuaranteed=GetCapsData.lpCaps->dwMaxBufferSize;
  206. }
  207. if(!pProtocol->m_dwSPMaxGuaranteed){
  208. pProtocol->m_dwSPMaxGuaranteed=pProtocol->m_dwSPMaxFrame;
  209. }
  210. }
  211. Lock(&pProtocol->m_ObjLock);
  212. //
  213. // Spin up the send thread
  214. //
  215. pProtocol->m_nSendThreads++;
  216. // Need for serialization starts here...
  217. pProtocol->m_hSendThread[0]=CreateThread( NULL,
  218. 4000,
  219. SendThread,
  220. (LPVOID)pProtocol,
  221. 0,
  222. &pProtocol->m_dwSendThreadId[0]);
  223. if(!pProtocol->m_hSendThread[0]){
  224. ASSERT(0); //TRACE all paths.
  225. hr=DPERR_NOMEMORY;
  226. goto exit4;
  227. }
  228. pProtocol->lpHandleTable=InitHandleTable(TABLE_INIT_SIZE,&pProtocol->csHandleTable,TABLE_GROW_SIZE);
  229. if(!pProtocol->lpHandleTable){
  230. goto exit5;
  231. }
  232. pProtocol->m_eState=Running;
  233. Unlock(&pProtocol->m_ObjLock);
  234. hr=DP_OK;
  235. exit:
  236. if(hr==DP_OK){
  237. lpDPlay->pProtocol=(LPPROTOCOL_PART)pProtocol;
  238. } else {
  239. lpDPlay->pProtocol=NULL;
  240. }
  241. return hr;
  242. //exit6: if more init written, may need this.
  243. // FiniHandleTable(pProtocol->lpHandleTable, &pProtocol->csHandleTable);
  244. exit5:
  245. pProtocol->m_eState=ShuttingDown;
  246. SetEvent(pProtocol->m_hSendEvent);
  247. Unlock(&pProtocol->m_ObjLock);
  248. while(pProtocol->m_nSendThreads){
  249. // wait for the send thread to shut off.
  250. Sleep(0);
  251. }
  252. CloseHandle(pProtocol->m_hSendThread[0]);
  253. Lock(&pProtocol->m_ObjLock);
  254. exit4:
  255. Unlock(&pProtocol->m_ObjLock);
  256. //exit3:
  257. FiniRcvDescs(pProtocol);
  258. nInitCount--;
  259. if(!nInitCount){
  260. DeleteCriticalSection(&g_SendTimeoutListLock);
  261. FiniBufferPool();
  262. FiniBufferManager();
  263. FiniFrameBuffers();
  264. FiniSendStats();
  265. FiniSendDescs();
  266. }
  267. //exit2:
  268. CloseHandle(pProtocol->m_hSendEvent);
  269. exit1:
  270. DeleteCriticalSection(&pProtocol->m_SPLock);
  271. DeleteCriticalSection(&pProtocol->m_ObjLock);
  272. DeleteCriticalSection(&pProtocol->m_SessionLock);
  273. DeleteCriticalSection(&pProtocol->m_SendQLock);
  274. My_GlobalFree(pProtocol);
  275. goto exit;
  276. #undef TABLE_INIT_SIZE
  277. #undef TABLE_GROW_SIZE
  278. }
  279. /*=============================================================================
  280. FiniProtocol -
  281. Description:
  282. Parameters:
  283. Return Values:
  284. -----------------------------------------------------------------------------*/
  285. VOID WINAPI FiniProtocol(PPROTOCOL pProtocol)
  286. {
  287. DWORD tmKill;
  288. //
  289. // Kill the send thread.
  290. //
  291. DPF(1,"==>ProtShutdown\n");
  292. Lock(&pProtocol->m_ObjLock);
  293. pProtocol->m_eState=ShuttingDown;
  294. SetEvent(pProtocol->m_hSendEvent);
  295. while(pProtocol->m_nSendThreads){
  296. // wait for the send thread to shut off.
  297. Unlock(&pProtocol->m_ObjLock);
  298. Sleep(0);
  299. Lock(&pProtocol->m_ObjLock);
  300. }
  301. Unlock(&pProtocol->m_ObjLock);
  302. CloseHandle(pProtocol->m_hSendThread[0]);
  303. DPF(1,"SHUTDOWN: Protocol Send Thread ShutDown, waiting for sessions\n");
  304. tmKill=timeGetTime()+60000;
  305. Lock(&pProtocol->m_SessionLock);
  306. while(pProtocol->m_nSessions && (((INT)(tmKill-timeGetTime())) > 0)){
  307. Unlock(&pProtocol->m_SessionLock);
  308. //BUGBUG: race. when m_nSessions dereffed, there
  309. // is a race for the protocol to be freed.
  310. Sleep(0);
  311. Lock(&pProtocol->m_SessionLock);
  312. }
  313. DPF(1,"SHUTDOWN: Sessions All Gone Freeing other objects.\n");
  314. //
  315. // Free the SESSION table
  316. //
  317. if(pProtocol->m_pSessions){
  318. My_GlobalFree(pProtocol->m_pSessions);
  319. pProtocol->m_pSessions=0;
  320. }
  321. Unlock(&pProtocol->m_SessionLock);
  322. DeleteCriticalSection(&pProtocol->m_SendQLock);
  323. DeleteCriticalSection(&pProtocol->m_SessionLock);
  324. DeleteCriticalSection(&pProtocol->m_SPLock);
  325. DeleteCriticalSection(&pProtocol->m_ObjLock);
  326. CloseHandle(pProtocol->m_hSendEvent);
  327. FiniRcvDescs(pProtocol);
  328. nInitCount--;
  329. if(!nInitCount){
  330. // Last one out, turn off the lights...
  331. DeleteCriticalSection(&g_SendTimeoutListLock);
  332. FiniBufferPool();
  333. FiniBufferManager();
  334. FiniFrameBuffers();
  335. FiniSendStats();
  336. FiniSendDescs();
  337. }
  338. FiniHandleTable(pProtocol->lpHandleTable, &pProtocol->csHandleTable);
  339. My_GlobalFree(pProtocol);
  340. #ifdef DEBUG
  341. My_GlobalAllocDeInit();
  342. #endif
  343. }
  344. /*=============================================================================
  345. ProtocolCreatePlayer - Called by DPlay when SP needs to be notified of new
  346. player creation.
  347. Description:
  348. Creates a session for the id. BUGBUG: if local, don't need this?
  349. Also notifies the SP.
  350. Parameters:
  351. Return Values:
  352. -----------------------------------------------------------------------------*/
  353. HRESULT WINAPI ProtocolCreatePlayer(LPDPSP_CREATEPLAYERDATA pCreatePlayerData)
  354. {
  355. DPLAYI_DPLAY *lpDPlay;
  356. PPROTOCOL pProtocol;
  357. HRESULT hr=DP_OK;
  358. lpDPlay=((DPLAYI_DPLAY_INT *)pCreatePlayerData->lpISP)->lpDPlay;
  359. ASSERT(lpDPlay);
  360. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  361. ASSERT(pProtocol);
  362. pProtocol->m_dwIDKey=(DWORD)lpDPlay->lpsdDesc->dwReserved1;
  363. // Creates the session and gets one refcount.
  364. hr=CreateNewSession(pProtocol, pCreatePlayerData->idPlayer);
  365. if(hr==DP_OK){
  366. // Chain the call to the real provider.
  367. Lock(&pProtocol->m_SPLock);
  368. if(lpDPlay->pcbSPCallbacks->CreatePlayer){
  369. hr=CALLSP(lpDPlay->pcbSPCallbacks->CreatePlayer,pCreatePlayerData);
  370. }
  371. Unlock(&pProtocol->m_SPLock);
  372. if(hr!=DP_OK){
  373. PSESSION pSession;
  374. pSession=GetSession(pProtocol,pCreatePlayerData->idPlayer); //adds a ref
  375. if(pSession){
  376. DecSessionRef(pSession); // unGetSession
  377. DecSessionRef(pSession); // blow it away, noone could access yet.
  378. }
  379. }
  380. }
  381. return hr;
  382. }
  383. /*=============================================================================
  384. ProtocolPreNotifyDeletePlayer
  385. Called to tell us a DELETEPLAYER message was enqueued for a particular
  386. player. We need to drop the player NOW!
  387. We don't notify the SP, that will happen when we are called in
  388. ProtocolDeletePlayer later when the pending queue is processed.
  389. Description:
  390. Dereference the session for the player.
  391. Parameters:
  392. Return Values:
  393. -----------------------------------------------------------------------------*/
  394. HRESULT WINAPI ProtocolPreNotifyDeletePlayer(LPDPLAYI_DPLAY this, DPID idPlayer)
  395. {
  396. PPROTOCOL pProtocol;
  397. PSESSION pSession;
  398. HRESULT hr=DP_OK;
  399. pProtocol=(PPROTOCOL)this->pProtocol;
  400. ASSERT(pProtocol);
  401. pSession=GetSession(pProtocol,idPlayer);
  402. DPF(9,"==>Protocol Prenotify Delete Player %x, pSession %x\n",idPlayer, pSession);
  403. if(pSession){
  404. pSession->hClosingEvent=0;
  405. #if 0
  406. //BUGBUG: if you even think about putting this back, also do it in ProtocolDeletePlayer
  407. hClosingEvent=pSession->hClosingEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
  408. if(hClosingEvent){
  409. ResetEvent(hClosingEvent);
  410. }
  411. #endif
  412. Lock(&pProtocol->m_SendQLock);
  413. Lock(&pSession->SessionLock);
  414. switch(pSession->eState)
  415. {
  416. case Open:
  417. TimeOutSession(pSession);
  418. Unlock(&pSession->SessionLock);
  419. Unlock(&pProtocol->m_SendQLock);
  420. DecSessionRef(pSession); // balance GetSession
  421. DecSessionRef(pSession); // balance Creation - may destroy session, and signal event
  422. break;
  423. case Closing:
  424. case Closed:
  425. Unlock(&pSession->SessionLock);
  426. Unlock(&pProtocol->m_SendQLock);
  427. DecSessionRef(pSession); // balance GetSession
  428. break;
  429. }
  430. #if 0
  431. if(hClosingEvent){
  432. // Wait(hClosingEvent);
  433. CloseHandle(hClosingEvent);
  434. } else {
  435. DPF(0,"ProtocolPreNotifyDeletePlayer: couldn't get close event handle--not waiting...\n");
  436. ASSERT(0);
  437. }
  438. #endif
  439. } else {
  440. DPF(0,"ProtocolPreNotifyDeletePlayer: couldn't find session for playerid %x\n",idPlayer);
  441. ASSERT(0);
  442. }
  443. DPF(9,"<==Protocol Prenotify DeletePlayer, hr=%x\n",hr);
  444. return hr;
  445. }
  446. /*=============================================================================
  447. ProtocolDeletePlayer - Called by DPlay when SP needs to be notified of
  448. player deletion.
  449. Description:
  450. Dereference the session for the player. Then notifies the SP.
  451. Parameters:
  452. Return Values:
  453. -----------------------------------------------------------------------------*/
  454. HRESULT WINAPI ProtocolDeletePlayer(LPDPSP_DELETEPLAYERDATA pDeletePlayerData)
  455. {
  456. DPLAYI_DPLAY *lpDPlay;
  457. PPROTOCOL pProtocol;
  458. PSESSION pSession;
  459. HRESULT hr=DP_OK;
  460. //HANDLE hClosingEvent;
  461. lpDPlay=((DPLAYI_DPLAY_INT *)pDeletePlayerData->lpISP)->lpDPlay;
  462. ASSERT(lpDPlay);
  463. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  464. ASSERT(pProtocol);
  465. pSession=GetSession(pProtocol,pDeletePlayerData->idPlayer);
  466. DPF(9,"==>Protocol Delete Player %x, pSession %x\n",pDeletePlayerData->idPlayer, pSession);
  467. if(pSession){
  468. pSession->hClosingEvent=0;
  469. #if 0
  470. //BUGBUG: if you even think about putting this back, also do it in ProtocolPreNotifyDeletePlayer
  471. hClosingEvent=pSession->hClosingEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
  472. if(hClosingEvent){
  473. ResetEvent(hClosingEvent);
  474. }
  475. #endif
  476. Lock(&pProtocol->m_SendQLock);
  477. Lock(&pSession->SessionLock);
  478. switch(pSession->eState)
  479. {
  480. case Open:
  481. TimeOutSession(pSession);
  482. Unlock(&pSession->SessionLock);
  483. Unlock(&pProtocol->m_SendQLock);
  484. DecSessionRef(pSession); // balance GetSession
  485. DecSessionRef(pSession); // balance Creation - may destroy session, and signal event
  486. break;
  487. case Closing:
  488. case Closed:
  489. Unlock(&pSession->SessionLock);
  490. Unlock(&pProtocol->m_SendQLock);
  491. DecSessionRef(pSession); // balance GetSession
  492. break;
  493. }
  494. #if 0
  495. if(hClosingEvent){
  496. // Wait(hClosingEvent);
  497. CloseHandle(hClosingEvent);
  498. } else {
  499. DPF(0,"ProtocolDeletePlayer: couldn't get close event handle--not waiting...\n");
  500. ASSERT(0);
  501. }
  502. #endif
  503. } else {
  504. DPF(0,"ProtocolDeletePlayer: couldn't find session for playerid %x, ok if ProtocolPreNotifyDeletPlayer ran.\n",pDeletePlayerData->idPlayer);
  505. }
  506. DPF(9,"Protocol, deleted player id %x\n",pDeletePlayerData->idPlayer);
  507. DPF(9,"<==ProtocolDeletePlayer, hr=%x\n",hr);
  508. return hr;
  509. }
  510. /*=============================================================================
  511. ProtocolSendEx -
  512. Description:
  513. Parameters:
  514. Return Values:
  515. -----------------------------------------------------------------------------*/
  516. HRESULT WINAPI ProtocolSendEx(LPDPSP_SENDEXDATA pSendData)
  517. {
  518. DPSP_SENDDATA sd;
  519. DPLAYI_DPLAY *lpDPlay;
  520. PPROTOCOL pProtocol;
  521. HRESULT hr=DP_OK;
  522. DWORD dwCommand;
  523. PUCHAR pBuffer;
  524. lpDPlay=((DPLAYI_DPLAY_INT *)pSendData->lpISP)->lpDPlay;
  525. ASSERT(lpDPlay);
  526. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  527. ASSERT(pProtocol);
  528. ASSERT(lpDPlay->dwFlags & DPLAYI_PROTOCOL);
  529. if(pSendData->lpSendBuffers->len >= 8){
  530. pBuffer=pSendData->lpSendBuffers->pData;
  531. if((*((DWORD *)pBuffer)) == SIGNATURE('p','l','a','y')){
  532. dwCommand=GET_MESSAGE_COMMAND((LPMSG_SYSMESSAGE)pBuffer);
  533. switch(dwCommand){
  534. case DPSP_MSG_PACKET2_DATA:
  535. case DPSP_MSG_PACKET2_ACK:
  536. case DPSP_MSG_PACKET:
  537. goto send_non_protocol_message;
  538. break;
  539. default:
  540. break;
  541. }
  542. }
  543. }
  544. // BUGBUG, make Send take the SENDEXDATA struct only.
  545. hr=Send(pProtocol,
  546. pSendData->idPlayerFrom,
  547. pSendData->idPlayerTo,
  548. pSendData->dwFlags,
  549. pSendData->lpSendBuffers,
  550. pSendData->cBuffers,
  551. pSendData->dwPriority,
  552. pSendData->dwTimeout,
  553. pSendData->lpDPContext,
  554. pSendData->lpdwSPMsgID,
  555. TRUE,
  556. NULL); // forces us to be called back in InternalSendComplete, if Send is ASYNC.
  557. return hr;
  558. send_non_protocol_message:
  559. ENTER_DPLAY();
  560. Lock(&pProtocol->m_SPLock);
  561. if(lpDPlay->pcbSPCallbacks->SendEx){
  562. hr=CALLSP(lpDPlay->pcbSPCallbacks->SendEx,pSendData);
  563. } else {
  564. hr=ConvertSendExDataToSendData(lpDPlay, pSendData, &sd);
  565. if(hr==DP_OK){
  566. hr=CALLSP(lpDPlay->pcbSPCallbacks->Send, &sd);
  567. MsgFree(NULL, sd.lpMessage);
  568. }
  569. }
  570. Unlock(&pProtocol->m_SPLock);
  571. LEAVE_DPLAY();
  572. return hr;
  573. }
  574. /*=============================================================================
  575. ProtocolGetMessageQueue -
  576. Description:
  577. Parameters:
  578. Return Values:
  579. -----------------------------------------------------------------------------*/
  580. HRESULT WINAPI ProtocolGetMessageQueue(LPDPSP_GETMESSAGEQUEUEDATA pGetMessageQueueData)
  581. {
  582. #define pData pGetMessageQueueData
  583. DPLAYI_DPLAY *lpDPlay;
  584. PPROTOCOL pProtocol;
  585. PSESSION pSession;
  586. HRESULT hr=DP_OK;
  587. BILINK *pBilink;
  588. PSEND pSend;
  589. DWORD dwNumMsgs;
  590. DWORD dwNumBytes;
  591. lpDPlay=((DPLAYI_DPLAY_INT *)pData->lpISP)->lpDPlay;
  592. ASSERT(lpDPlay);
  593. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  594. ASSERT(pProtocol);
  595. dwNumMsgs=0;
  596. dwNumBytes=0;
  597. if(!pData->idTo && !pData->idFrom){
  598. // just wants totals, I know that!
  599. EnterCriticalSection(&pProtocol->m_SendQLock);
  600. dwNumMsgs = pProtocol->m_dwMessagesPending;
  601. dwNumBytes = pProtocol->m_dwBytesPending;
  602. LeaveCriticalSection(&pProtocol->m_SendQLock);
  603. } else if(pData->idTo){
  604. // Given idTo, walk that target's sendQ
  605. pSession=GetSysSession(pProtocol,pData->idTo);
  606. if(!pSession) {
  607. DPF(0,"GetMessageQueue: NO SESSION for idTo %x, returning INVALIDPLAYER\n",pData->idTo);
  608. hr=DPERR_INVALIDPLAYER;
  609. goto exit;
  610. }
  611. EnterCriticalSection(&pSession->SessionLock);
  612. pBilink=pSession->SendQ.next;
  613. while(pBilink != &pSession->SendQ){
  614. pSend=CONTAINING_RECORD(pBilink, SEND, SendQ);
  615. pBilink=pBilink->next;
  616. if((pSend->idTo==pData->idTo) && (!pData->idFrom || (pSend->idFrom == pData->idFrom))){
  617. dwNumBytes += pSend->MessageSize;
  618. dwNumMsgs += 1;
  619. }
  620. }
  621. LeaveCriticalSection(&pSession->SessionLock);
  622. DecSessionRef(pSession);
  623. } else {
  624. ASSERT(pData->idFrom);
  625. // Geting Queue for a from id, this is most costly
  626. EnterCriticalSection(&pProtocol->m_SendQLock);
  627. pBilink=pProtocol->m_GSendQ.next;
  628. while(pBilink != &pProtocol->m_GSendQ){
  629. pSend=CONTAINING_RECORD(pBilink, SEND, m_GSendQ);
  630. pBilink=pBilink->next;
  631. if(pData->idFrom == pSend->idFrom){
  632. if(!pData->idTo || pData->idTo==pSend->idTo){
  633. dwNumBytes += pSend->MessageSize;
  634. dwNumMsgs += 1;
  635. }
  636. }
  637. }
  638. LeaveCriticalSection(&pProtocol->m_SendQLock);
  639. }
  640. if(pData->lpdwNumMsgs){
  641. *pData->lpdwNumMsgs=dwNumMsgs;
  642. }
  643. if(pData->lpdwNumBytes){
  644. *pData->lpdwNumBytes=dwNumBytes;
  645. }
  646. exit:
  647. return hr;
  648. #undef pData
  649. }
  650. /*=============================================================================
  651. ProtocolCancel -
  652. Description:
  653. Parameters:
  654. Return Values:
  655. -----------------------------------------------------------------------------*/
  656. HRESULT WINAPI ProtocolCancel(LPDPSP_CANCELDATA pCancelData)
  657. {
  658. #define pData pCancelData
  659. DPLAYI_DPLAY *lpDPlay;
  660. PPROTOCOL pProtocol;
  661. HRESULT hr=DP_OK;
  662. DWORD nCancelled=0;
  663. BILINK *pBilink;
  664. BOOL bCancel;
  665. UINT i;
  666. UINT j;
  667. DWORD dwContext;
  668. PSEND pSend;
  669. lpDPlay=((DPLAYI_DPLAY_INT *)pData->lpISP)->lpDPlay;
  670. ASSERT(lpDPlay);
  671. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  672. ASSERT(pProtocol);
  673. EnterCriticalSection(&pProtocol->m_SendQLock);
  674. if(pData->dwFlags) {
  675. // either cancelpriority or cancel all, either way we
  676. // need to scan...
  677. pBilink=pProtocol->m_GSendQ.next;
  678. while(pBilink!=&pProtocol->m_GSendQ){
  679. pSend=CONTAINING_RECORD(pBilink, SEND, m_GSendQ);
  680. pBilink=pBilink->next;
  681. bCancel=FALSE;
  682. Lock(&pSend->SendLock);
  683. switch(pSend->SendState){
  684. case Start:
  685. case WaitingForId:
  686. if(pData->dwFlags & DPCANCELSEND_PRIORITY) {
  687. // Cancel sends in priority range.
  688. if((pSend->Priority <= pData->dwMaxPriority) &&
  689. (pSend->Priority >= pData->dwMinPriority)){
  690. bCancel=TRUE;
  691. }
  692. } else if(pData->dwFlags & DPCANCELSEND_ALL) {
  693. // Cancel all sends that can be.
  694. bCancel=TRUE;
  695. } else {
  696. ASSERT(0); // Invalid flags, should never happen
  697. }
  698. if(bCancel){
  699. if(pSend->SendState == WaitingForId){
  700. if(pSend->dwFlags & DPSEND_GUARANTEED){
  701. InterlockedDecrement(&pSend->pSession->nWaitingForMessageid);
  702. } else {
  703. InterlockedDecrement(&pSend->pSession->nWaitingForDGMessageid);
  704. }
  705. }
  706. nCancelled+=1;
  707. pSend->SendState=Cancelled;
  708. }
  709. break;
  710. default:
  711. DPF(5,"Couldn't cancel send %x in State %d, already sending...\n",pSend,pSend->SendState);
  712. }
  713. Unlock(&pSend->SendLock);
  714. }
  715. } else {
  716. // No flags, therefore we have a list to cancel so lookup
  717. // each send and cancel rather than scanning as above.
  718. // Run through the list, find the sends and lock em 1st, if we find one that doesn't lookup,
  719. // or one not in the start state, then we bail. We then unlock them all.
  720. for(i=0;i<pData->cSPMsgID;i++){
  721. dwContext=(DWORD)((DWORD_PTR)((*pData->lprglpvSPMsgID)[i]));
  722. pSend=(PSEND)ReadHandleTableEntry(&pProtocol->lpHandleTable, &pProtocol->csHandleTable, dwContext);
  723. if(pSend){
  724. Lock(&pSend->SendLock);
  725. if(pSend->SendState != Start && pSend->SendState != WaitingForId){
  726. Unlock(&pSend->SendLock);
  727. hr=DPERR_CANCELFAILED;
  728. break;
  729. }
  730. } else {
  731. hr=DPERR_CANCELFAILED;
  732. break;
  733. }
  734. }
  735. if(hr==DPERR_CANCELFAILED) {
  736. // release all the locks.
  737. for(j=0;j<i;j++){
  738. dwContext=(DWORD)((DWORD_PTR)((*pData->lprglpvSPMsgID)[j]));
  739. pSend=(PSEND)ReadHandleTableEntry(&pProtocol->lpHandleTable, &pProtocol->csHandleTable, dwContext);
  740. ASSERT(pSend);
  741. Unlock(&pSend->SendLock);
  742. }
  743. } else {
  744. // mark the sends cancelled and release all the locks.
  745. for(i=0;i<pData->cSPMsgID;i++){
  746. dwContext=(DWORD)((DWORD_PTR)((*pData->lprglpvSPMsgID)[i]));
  747. pSend=(PSEND)ReadHandleTableEntry(&pProtocol->lpHandleTable, &pProtocol->csHandleTable, dwContext);
  748. ASSERT(pSend);
  749. if(pSend->SendState == WaitingForId){
  750. if(pSend->dwFlags & DPSEND_GUARANTEED){
  751. InterlockedDecrement(&pSend->pSession->nWaitingForMessageid);
  752. } else {
  753. InterlockedDecrement(&pSend->pSession->nWaitingForDGMessageid);
  754. }
  755. }
  756. pSend->SendState=Cancelled;
  757. nCancelled+=1;
  758. Unlock(&pSend->SendLock);
  759. }
  760. }
  761. }
  762. LeaveCriticalSection(&pProtocol->m_SendQLock);
  763. SetEvent(pProtocol->m_hSendEvent);
  764. return hr;
  765. #undef pData
  766. }
  767. /*=============================================================================
  768. ProtocolSend - Send A message synchronously.
  769. Description:
  770. Parameters:
  771. Return Values:
  772. -----------------------------------------------------------------------------*/
  773. DWORD bForceDGAsync=FALSE;
  774. HRESULT WINAPI ProtocolSend(LPDPSP_SENDDATA pSendData)
  775. {
  776. DPLAYI_DPLAY *lpDPlay;
  777. PPROTOCOL pProtocol;
  778. HRESULT hr=DP_OK;
  779. DWORD dwCommand;
  780. DWORD dwPriority;
  781. DWORD dwFlags;
  782. PUCHAR pBuffer;
  783. MEMDESC memdesc;
  784. lpDPlay=((DPLAYI_DPLAY_INT *)pSendData->lpISP)->lpDPlay;
  785. ASSERT(lpDPlay);
  786. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  787. ASSERT(pProtocol);
  788. pBuffer=&(((PUCHAR)(pSendData->lpMessage))[pProtocol->m_dwSPHeaderSize]);
  789. if((*((DWORD *)pBuffer)) == SIGNATURE('p','l','a','y')){
  790. dwCommand=GET_MESSAGE_COMMAND((LPMSG_SYSMESSAGE)pBuffer);
  791. switch(dwCommand){
  792. case DPSP_MSG_PACKET2_DATA:
  793. case DPSP_MSG_PACKET2_ACK:
  794. case DPSP_MSG_ENUMSESSIONSREPLY:
  795. case DPSP_MSG_PACKET:
  796. goto send_non_protocol_message;
  797. break;
  798. default:
  799. break;
  800. }
  801. }
  802. memdesc.pData=((PUCHAR)pSendData->lpMessage)+pProtocol->m_dwSPHeaderSize;
  803. memdesc.len =pSendData->dwMessageSize-pProtocol->m_dwSPHeaderSize;
  804. if(pSendData->dwFlags & DPSEND_HIGHPRIORITY){
  805. pSendData->dwFlags &= ~(DPSEND_HIGHPRIORITY);
  806. dwPriority=0xFFFFFFFE;
  807. } else {
  808. dwPriority=1000;
  809. }
  810. dwFlags = pSendData->dwFlags;
  811. if(bForceDGAsync && !(dwFlags&DPSEND_GUARANTEE)){
  812. // for testing old apps with protocol make datagram sends
  813. // async so that the application doesn't block.
  814. dwFlags |= DPSEND_ASYNC;
  815. }
  816. hr=Send(pProtocol,
  817. pSendData->idPlayerFrom,
  818. pSendData->idPlayerTo,
  819. dwFlags,
  820. &memdesc,
  821. 1,
  822. dwPriority,
  823. 0,
  824. NULL,
  825. NULL,
  826. FALSE,
  827. NULL);
  828. return hr;
  829. send_non_protocol_message:
  830. if((*((DWORD *)pBuffer)) == SIGNATURE('p','l','a','y')){
  831. DPF(9,"Send Message %d Ver %d\n", pBuffer[4]+(pBuffer[5]<<8),pBuffer[6]+(pBuffer[7]<<8));
  832. }
  833. ENTER_DPLAY();
  834. Lock(&pProtocol->m_SPLock);
  835. hr=CALLSP(lpDPlay->pcbSPCallbacks->Send,pSendData);
  836. Unlock(&pProtocol->m_SPLock);
  837. LEAVE_DPLAY();
  838. return hr;
  839. }
  840. /*=============================================================================
  841. GetPlayerLatency - Get Latency for a player
  842. Description:
  843. Parameters:
  844. Return Values:
  845. -----------------------------------------------------------------------------*/
  846. DWORD GetPlayerLatency(LPDPLAYI_DPLAY lpDPlay, DPID idPlayer)
  847. {
  848. PPROTOCOL pProtocol;
  849. PSESSION pSession;
  850. DWORD dwLatency=0; // default, means I don't know latency
  851. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  852. ASSERT(pProtocol);
  853. pSession=GetSession(pProtocol,idPlayer);
  854. DPF(9,"==>Protocol GetPlayer Latency %x, pSession %x\n",idPlayer, pSession);
  855. if(pSession){
  856. Lock(&pSession->SessionLock);
  857. // Protocol Latency is round trip in 24.8 fixed point,
  858. // we net round trip latency divided by 2, so shift right 9.
  859. dwLatency=(pSession->FpLocalAverageLatency)>>(9);
  860. Unlock(&pSession->SessionLock);
  861. DecSessionRef(pSession); // balance GetSession
  862. }
  863. DPF(9,"<==Protocol GetPlayerLatency, returning dwLat=%x\n",dwLatency);
  864. return dwLatency;
  865. }
  866. /*=============================================================================
  867. ProtocolGetCaps - Get Service Provider Capabilities
  868. Description:
  869. Parameters:
  870. Return Values:
  871. -----------------------------------------------------------------------------*/
  872. HRESULT WINAPI ProtocolGetCaps(LPDPSP_GETCAPSDATA pGetCapsData)
  873. {
  874. #define ALL_PROTOCOLCAPS (DPCAPS_SENDPRIORITYSUPPORTED | \
  875. DPCAPS_ASYNCSUPPORTED | \
  876. DPCAPS_SENDTIMEOUTSUPPORTED | \
  877. DPCAPS_ASYNCCANCELSUPPORTED )
  878. DPLAYI_DPLAY *lpDPlay;
  879. PPROTOCOL pProtocol;
  880. HRESULT hr=DP_OK;
  881. lpDPlay=((DPLAYI_DPLAY_INT *)pGetCapsData->lpISP)->lpDPlay;
  882. ASSERT(lpDPlay);
  883. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  884. ASSERT(pProtocol);
  885. // Chain the call to the real provider.
  886. Lock(&pProtocol->m_SPLock);
  887. if(lpDPlay->pcbSPCallbacks->GetCaps){
  888. hr=CALLSP(lpDPlay->pcbSPCallbacks->GetCaps,pGetCapsData);
  889. }
  890. Unlock(&pProtocol->m_SPLock);
  891. // if it fails, this doesn't hurt
  892. if(lpDPlay->dwFlags & DPLAYI_DPLAY_PROTOCOL)
  893. {
  894. // 1 megabyte is lots (says Jamie Osborne)
  895. pGetCapsData->lpCaps->dwMaxBufferSize=0x100000;
  896. pGetCapsData->lpCaps->dwFlags |= ALL_PROTOCOLCAPS;
  897. }
  898. if(pGetCapsData->idPlayer && !pGetCapsData->lpCaps->dwLatency){
  899. // SP refused to guess at latency, so use ours.
  900. pGetCapsData->lpCaps->dwLatency=GetPlayerLatency(lpDPlay, pGetCapsData->idPlayer);
  901. }
  902. return hr;
  903. #undef ALL_PROTOCOLCAPS
  904. }
  905. DWORD ExtractProtocolIds(PUCHAR pInBuffer, PUINT pdwIdFrom, PUINT pdwIdTo)
  906. {
  907. PCHAR pBuffer=pInBuffer;
  908. DWORD dwIdFrom=0;
  909. DWORD dwIdTo=0;
  910. dwIdFrom=*pBuffer&0x7F;
  911. if(*pBuffer&0x80){
  912. pBuffer++;
  913. dwIdFrom=dwIdFrom+((*pBuffer&0x7F)<<7);
  914. if(*pBuffer&0x80){
  915. pBuffer++;
  916. dwIdFrom=dwIdFrom+((*pBuffer&0x7F)<<14);
  917. if(dwIdFrom > 0xFFFF || *pBuffer&0x80){
  918. DPF(0,"INVALID FROM ID %x IN MESSAGE, REJECTING PACKET\n",dwIdFrom);
  919. return 0;
  920. }
  921. }
  922. }
  923. if(dwIdFrom==0xFFFF){
  924. dwIdFrom=0x70;
  925. }
  926. pBuffer++;
  927. dwIdTo=*pBuffer&0x7F;
  928. if(*pBuffer&0x80){
  929. pBuffer++;
  930. dwIdTo=dwIdTo+((*pBuffer&0x7F)<<7);
  931. if(*pBuffer&0x80){
  932. pBuffer++;
  933. dwIdTo=dwIdTo+((*pBuffer&0x7F)<<14);
  934. if(dwIdTo > 0xFFFF || *pBuffer&0x80){
  935. DPF(0,"INVALID TO ID %x IN MESSAGE, REJECTING PACKET\n",dwIdTo);
  936. return 0;
  937. }
  938. }
  939. }
  940. *pdwIdFrom=dwIdFrom;
  941. *pdwIdTo=dwIdTo;
  942. pBuffer++;
  943. // DPF(9, "In ExtractProtocolIds: from %x became %x\n", *(DWORD *)pInBuffer, dwIdFrom);
  944. return (DWORD)(pBuffer-pInBuffer);
  945. }
  946. /*=============================================================================
  947. DP_SP_ProtocolHandleMessage - Packet handler for Dplay protocol
  948. Description:
  949. All messages go through here when the protocol is active. If the
  950. message is not a protocol message, this routine doesn't process
  951. it and returns DPERR_NOTHANDLED to let other layers (probably
  952. PacketizeAndSend) process it.
  953. Parameters:
  954. IDirectPlaySP * pISP - pointer to pISP interface
  955. LPBYTE pReceiveBuffer - a single buffer of data
  956. DWORD dwMessageSize - length of the buffer
  957. LPVOID pvSPHeader - pointer to SP's header used in Reply
  958. Return Values:
  959. Notes:
  960. We don't worry about re-entering DP_SP_HandleMessage since
  961. we are calling only when a receive has completed and we are in the
  962. callback from the SP to directplay, so effectively the SP is
  963. serializing receives for us.
  964. The receive code is actually written to be re-entrant, so if we
  965. ever decide to allow concurrent receive processing the protocol
  966. can handle it.
  967. Protocol messages start with 'P','L','A','Y','0xFF' when not RAW.
  968. DPLAY gets handleMessage first, and hands off to protocol if active.
  969. -----------------------------------------------------------------------------*/
  970. HRESULT DPAPI DP_SP_ProtocolHandleMessage(
  971. IDirectPlaySP * pISP,
  972. LPBYTE pReceiveBuffer,
  973. DWORD dwMessageSize,
  974. LPVOID pvSPHeader)
  975. {
  976. DPLAYI_DPLAY *lpDPlay;
  977. DWORD dwIdFrom, dwIdTo;
  978. PBUFFER pRcvBuffer;
  979. PPROTOCOL pProtocol;
  980. lpDPlay=DPLAY_FROM_INT(pISP);
  981. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  982. if(pProtocol->m_lpDPlay->dwFlags & DPLAYI_DPLAY_PROTOCOL){
  983. // Running in RAW mode there is no dplay header on protocol
  984. // messages. If we see one with a header or we don't receive
  985. // a message large enough to be a protocol message we punt it.
  986. if(dwMessageSize >= 4 &&
  987. (*((DWORD *)pReceiveBuffer)) == SIGNATURE('p','l','a','y'))
  988. {
  989. // Got a system message.
  990. goto handle_non_protocol_message;
  991. }
  992. if( dwMessageSize < 6 ){
  993. goto handle_non_protocol_message;
  994. }
  995. } else {
  996. // this can happen when shutting down.
  997. DPF(0,"Protocol still up, but no bits set, not handling receive (must be shutting down?)");
  998. goto handle_non_protocol_message;
  999. }
  1000. // Hey, this must be ours...
  1001. Lock(&pProtocol->m_ObjLock);
  1002. if(pProtocol->m_eState==Running){ // just a sanity check, we don't depend on it after dropping lock.
  1003. DWORD idLen;
  1004. Unlock(&pProtocol->m_ObjLock);
  1005. idLen = ExtractProtocolIds(pReceiveBuffer,&dwIdFrom,&dwIdTo);
  1006. if(!idLen){
  1007. goto handle_non_protocol_message;
  1008. }
  1009. pRcvBuffer=GetFrameBuffer(dwMessageSize-idLen);
  1010. pRcvBuffer->len=dwMessageSize-idLen;
  1011. memcpy(pRcvBuffer->pData, pReceiveBuffer+idLen,pRcvBuffer->len);
  1012. DPF(9,"DP_SP_ProtocolHandleMessage From %x To %x\n",dwIdFrom,dwIdTo);
  1013. ENTER_DPLAY();
  1014. ProtocolReceive((PPROTOCOL)lpDPlay->pProtocol, (WORD)dwIdFrom, (WORD)dwIdTo, pRcvBuffer,pvSPHeader);
  1015. LEAVE_DPLAY();
  1016. } else {
  1017. Unlock(&pProtocol->m_ObjLock);
  1018. }
  1019. return DP_OK;
  1020. handle_non_protocol_message:
  1021. return DPERR_NOTHANDLED;
  1022. }
  1023. // DP_SP_ProtocolSendComplete is the callback handler for all completions since there is no other
  1024. // way to wrap the completion. When the protocol is not present, this just calls the DPLAY handler
  1025. // immediately.
  1026. VOID DPAPI DP_SP_ProtocolSendComplete(
  1027. IDirectPlaySP * pISP,
  1028. LPVOID lpvContext,
  1029. HRESULT CompletionStatus)
  1030. {
  1031. DPLAYI_DPLAY *lpDPlay;
  1032. PPROTOCOL pProtocol;
  1033. lpDPlay=DPLAY_FROM_INT(pISP);
  1034. if(lpDPlay->pProtocol){
  1035. // BUGBUG: when SP SendEx is used, we have to patch and xlate here.
  1036. // for now, this should never happen.
  1037. DEBUG_BREAK(); // Shouldn't get here yet.
  1038. pProtocol=(PPROTOCOL)lpDPlay->pProtocol;
  1039. DP_SP_SendComplete(pISP, lpvContext, CompletionStatus);
  1040. } else {
  1041. DP_SP_SendComplete(pISP, lpvContext, CompletionStatus);
  1042. }
  1043. }