Leaked source code of windows server 2003
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.

767 lines
24 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Initialize.cpp
  6. * Content: This file contains code to both initialize and shutdown the
  7. * protocol, as well as to Add and Remove service providers
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 11/06/98 ejs Created
  13. * 07/01/2000 masonb Assumed Ownership
  14. *
  15. ****************************************************************************/
  16. #include "dnproti.h"
  17. /*
  18. ** GLOBAL VARIABLES
  19. **
  20. ** There are two kinds of global variables. Instance specific globals
  21. ** (not really global, i know) which are members of the ProtocolData structure,
  22. ** and true globals which are shared among all instances. The following
  23. ** definitions are true globals, such as FixedPools and Timers.
  24. */
  25. CFixedPool ChkPtPool; // Pool of CheckPoint data structure
  26. CFixedPool EPDPool; // Pool of End Point descriptors
  27. CFixedPool MSDPool; // Pool of Message Descriptors
  28. CFixedPool FMDPool; // Pool of Frame Descriptors
  29. CFixedPool RCDPool; // Pool of Receive Descriptors
  30. CFixedPool BufPool; // Pool of buffers to store rcvd frames
  31. CFixedPool MedBufPool;
  32. CFixedPool BigBufPool;
  33. #ifdef DBG
  34. CBilink g_blProtocolCritSecsHeld;
  35. #endif // DBG
  36. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  37. PFNASSERTFUNC g_pfnAssertFunc = NULL;
  38. PFNMEMALLOCFUNC g_pfnMemAllocFunc = NULL;
  39. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  40. //////////////////////////////////
  41. #define CHKPTPOOL_INITED 0x00000001
  42. #define EPDPOOL_INITED 0x00000002
  43. #define MSDPOOL_INITED 0x00000004
  44. #define FMDPOOL_INITED 0x00000008
  45. #define RCDPOOL_INITED 0x00000010
  46. #define BUFPOOL_INITED 0x00000020
  47. #define MEDBUFPOOL_INITED 0x00000040
  48. #define BIGBUFPOOL_INITED 0x00000080
  49. DWORD g_dwProtocolInitFlags = 0;
  50. //////////////////////////////////
  51. /*
  52. ** Pools Initialization
  53. **
  54. ** This procedure should be called once at Dll load
  55. */
  56. #undef DPF_MODNAME
  57. #define DPF_MODNAME "DNPPoolsInit"
  58. BOOL DNPPoolsInit(HANDLE hModule)
  59. {
  60. DPFX(DPFPREP,DPF_CALLIN_LVL, "Enter");
  61. #ifdef DBG
  62. g_blProtocolCritSecsHeld.Initialize();
  63. #endif // DBG
  64. if(!ChkPtPool.Initialize(sizeof(CHKPT), NULL, NULL, NULL, NULL))
  65. {
  66. DNPPoolsDeinit();
  67. return FALSE;
  68. }
  69. g_dwProtocolInitFlags |= CHKPTPOOL_INITED;
  70. if(!EPDPool.Initialize(sizeof(EPD), EPD_Allocate, EPD_Get, EPD_Release, EPD_Free))
  71. {
  72. DNPPoolsDeinit();
  73. return FALSE;
  74. }
  75. g_dwProtocolInitFlags |= EPDPOOL_INITED;
  76. if(!MSDPool.Initialize(sizeof(MSD), MSD_Allocate, MSD_Get, MSD_Release, MSD_Free))
  77. {
  78. DNPPoolsDeinit();
  79. return FALSE;
  80. }
  81. g_dwProtocolInitFlags |= MSDPOOL_INITED;
  82. if(!FMDPool.Initialize(sizeof(FMD), FMD_Allocate, FMD_Get, FMD_Release, FMD_Free))
  83. {
  84. DNPPoolsDeinit();
  85. return FALSE;
  86. }
  87. g_dwProtocolInitFlags |= FMDPOOL_INITED;
  88. if(!RCDPool.Initialize(sizeof(RCD), RCD_Allocate, RCD_Get, RCD_Release, RCD_Free))
  89. {
  90. DNPPoolsDeinit();
  91. return FALSE;
  92. }
  93. g_dwProtocolInitFlags |= RCDPOOL_INITED;
  94. if(!BufPool.Initialize(sizeof(BUF), Buf_Allocate, Buf_Get, NULL, NULL))
  95. {
  96. DNPPoolsDeinit();
  97. return FALSE;
  98. }
  99. g_dwProtocolInitFlags |= BUFPOOL_INITED;
  100. if(!MedBufPool.Initialize(sizeof(MEDBUF), Buf_Allocate, Buf_GetMed, NULL, NULL))
  101. {
  102. DNPPoolsDeinit();
  103. return FALSE;
  104. }
  105. g_dwProtocolInitFlags |= MEDBUFPOOL_INITED;
  106. if(!BigBufPool.Initialize(sizeof(BIGBUF), Buf_Allocate, Buf_GetBig, NULL, NULL))
  107. {
  108. DNPPoolsDeinit();
  109. return FALSE;
  110. }
  111. g_dwProtocolInitFlags |= BIGBUFPOOL_INITED;
  112. return TRUE;
  113. }
  114. /*
  115. ** Pools Deinitialization
  116. **
  117. ** This procedure should be called by DllMain at shutdown time
  118. */
  119. #undef DPF_MODNAME
  120. #define DPF_MODNAME "DNPPoolsDeinit"
  121. void DNPPoolsDeinit()
  122. {
  123. DPFX(DPFPREP,DPF_CALLIN_LVL, "Enter");
  124. if(g_dwProtocolInitFlags & CHKPTPOOL_INITED)
  125. {
  126. ChkPtPool.DeInitialize();
  127. }
  128. if(g_dwProtocolInitFlags & EPDPOOL_INITED)
  129. {
  130. EPDPool.DeInitialize();
  131. }
  132. if(g_dwProtocolInitFlags & MSDPOOL_INITED)
  133. {
  134. MSDPool.DeInitialize();
  135. }
  136. if(g_dwProtocolInitFlags & FMDPOOL_INITED)
  137. {
  138. FMDPool.DeInitialize();
  139. }
  140. if(g_dwProtocolInitFlags & RCDPOOL_INITED)
  141. {
  142. RCDPool.DeInitialize();
  143. }
  144. if(g_dwProtocolInitFlags & BUFPOOL_INITED)
  145. {
  146. BufPool.DeInitialize();
  147. }
  148. if(g_dwProtocolInitFlags & MEDBUFPOOL_INITED)
  149. {
  150. MedBufPool.DeInitialize();
  151. }
  152. if(g_dwProtocolInitFlags & BIGBUFPOOL_INITED)
  153. {
  154. BigBufPool.DeInitialize();
  155. }
  156. g_dwProtocolInitFlags = 0;
  157. }
  158. #undef DPF_MODNAME
  159. #define DPF_MODNAME "DNPProtocolCreate"
  160. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  161. HRESULT DNPProtocolCreate(const XDP8CREATE_PARAMS * const pDP8CreateParams, VOID** ppvProtocol)
  162. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  163. HRESULT DNPProtocolCreate(VOID** ppvProtocol)
  164. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  165. {
  166. ASSERT(ppvProtocol);
  167. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  168. ASSERT(pDP8CreateParams);
  169. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pDP8CreateParams[%p], ppvProtocol[%p]", pDP8CreateParams, ppvProtocol);
  170. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  171. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: ppvProtocol[%p]", ppvProtocol);
  172. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  173. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  174. g_pfnAssertFunc = NULL;
  175. g_pfnMemAllocFunc = NULL;
  176. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  177. if ((*ppvProtocol = MEMALLOC(MEMID_PPD, sizeof(ProtocolData))) == NULL)
  178. {
  179. DPFERR("DNMalloc() failed");
  180. return(E_OUTOFMEMORY);
  181. }
  182. memset(*ppvProtocol, 0, sizeof(ProtocolData));
  183. // The sign needs to be valid by the time DNPProtocolInitialize is called
  184. ((ProtocolData*)*ppvProtocol)->Sign = PPD_SIGN;
  185. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  186. DWORD dwNumToAllocate;
  187. DWORD dwAllocated;
  188. #ifdef _XBOX
  189. #define MAX_FRAME_SIZE 1462 // Note we are hard coding the expected frame size.
  190. #else // ! _XBOX
  191. #define MAX_FRAME_SIZE 1472 // Note we are hard coding the expected frame size.
  192. #endif // ! _XBOX
  193. dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1);
  194. dwAllocated = ChkPtPool.Preallocate(dwNumToAllocate, NULL);
  195. if (dwAllocated < dwNumToAllocate)
  196. {
  197. DPFX(DPFPREP, 0, "Only allocated %u of %u checkpoints!", dwAllocated, dwNumToAllocate);
  198. DNFree(*ppvProtocol);
  199. *ppvProtocol = NULL;
  200. return(E_OUTOFMEMORY);
  201. }
  202. dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1);
  203. dwAllocated = EPDPool.Preallocate(dwNumToAllocate, NULL);
  204. if (dwAllocated < dwNumToAllocate)
  205. {
  206. DPFX(DPFPREP, 0, "Only allocated %u of %u EPDs!", dwAllocated, dwNumToAllocate);
  207. DNFree(*ppvProtocol);
  208. *ppvProtocol = NULL;
  209. return(E_OUTOFMEMORY);
  210. }
  211. dwNumToAllocate = pDP8CreateParams->dwMaxSendsPerPlayer
  212. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  213. dwNumToAllocate += pDP8CreateParams->dwNumSimultaneousEnumHosts;
  214. dwNumToAllocate += 1; // one for a listen operation
  215. dwAllocated = MSDPool.Preallocate(dwNumToAllocate, NULL);
  216. if (dwAllocated < dwNumToAllocate)
  217. {
  218. DPFX(DPFPREP, 0, "Only allocated %u of %u MSDs!", dwAllocated, dwNumToAllocate);
  219. DNFree(*ppvProtocol);
  220. *ppvProtocol = NULL;
  221. return(E_OUTOFMEMORY);
  222. }
  223. dwNumToAllocate = pDP8CreateParams->dwMaxSendsPerPlayer
  224. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  225. // Include the possiblity of having to split a message across multiple frames.
  226. dwNumToAllocate *= pDP8CreateParams->dwMaxMessageSize / MAX_FRAME_SIZE;
  227. dwNumToAllocate += pDP8CreateParams->dwNumSimultaneousEnumHosts;
  228. dwAllocated = FMDPool.Preallocate(dwNumToAllocate, NULL);
  229. if (dwAllocated < dwNumToAllocate)
  230. {
  231. DPFX(DPFPREP, 0, "Only allocated %u of %u FMDs!", dwAllocated, dwNumToAllocate);
  232. DNFree(*ppvProtocol);
  233. *ppvProtocol = NULL;
  234. return(E_OUTOFMEMORY);
  235. }
  236. dwNumToAllocate = pDP8CreateParams->dwMaxReceivesPerPlayer
  237. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  238. dwAllocated = RCDPool.Preallocate(dwNumToAllocate, NULL);
  239. if (dwAllocated < dwNumToAllocate)
  240. {
  241. DPFX(DPFPREP, 0, "Only allocated %u of %u RCDs!", dwAllocated, dwNumToAllocate);
  242. DNFree(*ppvProtocol);
  243. *ppvProtocol = NULL;
  244. return(E_OUTOFMEMORY);
  245. }
  246. if (pDP8CreateParams->dwMaxMessageSize > MAX_FRAME_SIZE)
  247. {
  248. dwNumToAllocate = pDP8CreateParams->dwMaxReceivesPerPlayer
  249. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  250. dwAllocated = BufPool.Preallocate(dwNumToAllocate, NULL);
  251. if (dwAllocated < dwNumToAllocate)
  252. {
  253. DPFX(DPFPREP, 0, "Only allocated %u of %u small receive buffers!", dwAllocated, dwNumToAllocate);
  254. DNFree(*ppvProtocol);
  255. *ppvProtocol = NULL;
  256. return(E_OUTOFMEMORY);
  257. }
  258. if (pDP8CreateParams->dwMaxMessageSize > MEDIUM_BUFFER_SIZE)
  259. {
  260. dwNumToAllocate = pDP8CreateParams->dwMaxReceivesPerPlayer
  261. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  262. dwAllocated = MedBufPool.Preallocate(dwNumToAllocate, NULL);
  263. if (dwAllocated < dwNumToAllocate)
  264. {
  265. DPFX(DPFPREP, 0, "Only allocated %u of %u medium receive buffers!", dwAllocated, dwNumToAllocate);
  266. DNFree(*ppvProtocol);
  267. *ppvProtocol = NULL;
  268. return(E_OUTOFMEMORY);
  269. }
  270. if (pDP8CreateParams->dwMaxMessageSize > LARGE_BUFFER_SIZE)
  271. {
  272. dwNumToAllocate = pDP8CreateParams->dwMaxReceivesPerPlayer
  273. * (pDP8CreateParams->dwMaxNumPlayers - 1);
  274. dwAllocated = BigBufPool.Preallocate(dwNumToAllocate, NULL);
  275. if (dwAllocated < dwNumToAllocate)
  276. {
  277. DPFX(DPFPREP, 0, "Only allocated %u of %u big receive buffers!", dwAllocated, dwNumToAllocate);
  278. DNFree(*ppvProtocol);
  279. *ppvProtocol = NULL;
  280. return(E_OUTOFMEMORY);
  281. }
  282. }
  283. }
  284. } // end if (messages may span multiple frames)
  285. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  286. return DPN_OK;
  287. }
  288. #undef DPF_MODNAME
  289. #define DPF_MODNAME "DNPProtocolDestroy"
  290. VOID DNPProtocolDestroy(VOID* pvProtocol)
  291. {
  292. if (pvProtocol)
  293. {
  294. DNFree(pvProtocol);
  295. }
  296. }
  297. /*
  298. ** Protocol Initialize
  299. **
  300. ** This procedure should be called by DirectPlay at startup time before
  301. ** any other calls in the protocol are made.
  302. */
  303. #undef DPF_MODNAME
  304. #define DPF_MODNAME "DNPProtocolInitialize"
  305. HRESULT DNPProtocolInitialize(HANDLE hProtocolData, PVOID pCoreContext, PDN_PROTOCOL_INTERFACE_VTBL pVtbl,
  306. IDirectPlay8ThreadPoolWork *pDPThreadPoolWork, BOOL bAssumeLANConnections)
  307. {
  308. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pCoreContext[%p], hProtocolData[%p], pVtbl[%p], pDPThreadPoolWork[%p]", hProtocolData, pCoreContext, pVtbl, pDPThreadPoolWork);
  309. // DPFX(DPFPREP,0, "Sizes: endpointdesc[%d], framedesc[%d], messagedesc[%d], protocoldata[%d], recvdesc[%d], spdesc[%d], _MyTimer[%d]", sizeof(endpointdesc), sizeof(framedesc), sizeof(messagedesc), sizeof(protocoldata), sizeof(recvdesc), sizeof(spdesc), sizeof(_MyTimer));
  310. ProtocolData* pPData;
  311. pPData = (ProtocolData*)hProtocolData;
  312. ASSERT_PPD(pPData);
  313. IDirectPlay8ThreadPoolWork_AddRef(pDPThreadPoolWork);
  314. pPData->pDPThreadPoolWork = pDPThreadPoolWork;
  315. pPData->ulProtocolFlags = 0;
  316. pPData->Parent = pCoreContext;
  317. pPData->pfVtbl = pVtbl;
  318. pPData->lSPActiveCount = 0;
  319. pPData->tIdleThreshhold = DEFAULT_KEEPALIVE_INTERVAL; // 60 second keep-alive interval
  320. pPData->dwConnectTimeout = CONNECT_DEFAULT_TIMEOUT;
  321. pPData->dwConnectRetries = CONNECT_DEFAULT_RETRIES;
  322. pPData->dwMaxRecvMsgSize=DEFAULT_MAX_RECV_MSG_SIZE;
  323. pPData->dwSendRetriesToDropLink=DEFAULT_SEND_RETRIES_TO_DROP_LINK;
  324. pPData->dwSendRetryIntervalLimit=DEFAULT_SEND_RETRY_INTERVAL_LIMIT;
  325. pPData->dwNumHardDisconnectSends=DEFAULT_HARD_DISCONNECT_SENDS;
  326. pPData->dwMaxHardDisconnectPeriod=DEFAULT_HARD_DISCONNECT_MAX_PERIOD;
  327. pPData->dwInitialFrameWindowSize = bAssumeLANConnections ?
  328. LAN_INITIAL_FRAME_WINDOW_SIZE : DEFAULT_INITIAL_FRAME_WINDOW_SIZE;
  329. pPData->dwDropThresholdRate = DEFAULT_THROTTLE_THRESHOLD_RATE;
  330. pPData->dwDropThreshold = (32 * DEFAULT_THROTTLE_THRESHOLD_RATE) / 100;
  331. pPData->dwThrottleRate = DEFAULT_THROTTLE_BACK_OFF_RATE;
  332. pPData->fThrottleRate = (100.0 - (FLOAT)DEFAULT_THROTTLE_BACK_OFF_RATE) / 100.0;
  333. DPFX(DPFPREP, 2, "pPData->fThrottleRate [%f]", pPData->fThrottleRate);
  334. #ifdef DBG
  335. pPData->ThreadsInReceive = 0;
  336. pPData->BuffersInReceive = 0;
  337. #endif // DBG
  338. pPData->ulProtocolFlags |= PFLAGS_PROTOCOL_INITIALIZED;
  339. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  340. return DPN_OK;
  341. }
  342. /*
  343. ** Protocol Shutdown
  344. **
  345. ** This procedure should be called at termination time, and should be the
  346. ** last call made to the protocol.
  347. **
  348. ** All SPs should have been removed prior to this call which in turn means
  349. ** that we should not have any sends pending in a lower layer.
  350. */
  351. #undef DPF_MODNAME
  352. #define DPF_MODNAME "DNPProtocolShutdown"
  353. HRESULT DNPProtocolShutdown(HANDLE hProtocolData)
  354. {
  355. ProtocolData* pPData;
  356. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p]", hProtocolData);
  357. pPData = (ProtocolData*)hProtocolData;
  358. ASSERT_PPD(pPData);
  359. ASSERT(pPData->lSPActiveCount == 0);
  360. IDirectPlay8ThreadPoolWork_Release(pPData->pDPThreadPoolWork);
  361. pPData->pDPThreadPoolWork = NULL;
  362. #ifdef DBG
  363. if (pPData->BuffersInReceive != 0)
  364. {
  365. DPFX(DPFPREP,0, "*** %d receive buffers were leaked", pPData->BuffersInReceive);
  366. }
  367. #endif // DBG
  368. pPData->ulProtocolFlags = 0;
  369. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  370. return DPN_OK;
  371. }
  372. /*
  373. ** Add Service Provider
  374. **
  375. ** This procedure is called by Direct Play to bind us to a service provider.
  376. ** We can bind up to 256 service providers at one time, although I would not ever
  377. ** expect to do so. This procedure will fail if Protocol Initialize has not
  378. ** been called.
  379. **
  380. **
  381. ** We check the size of the SP table to make sure we have a slot free. If table
  382. ** is full we double the table size until we reach maximum size. If table cannot grow
  383. ** then we fail the AddServiceProvider call.
  384. */
  385. extern IDP8SPCallbackVtbl DNPLowerEdgeVtbl;
  386. #undef DPF_MODNAME
  387. #define DPF_MODNAME "DNPAddServiceProvider"
  388. HRESULT
  389. DNPAddServiceProvider(HANDLE hProtocolData, IDP8ServiceProvider* pISP,
  390. HANDLE* phSPContext, DWORD dwFlags)
  391. {
  392. ProtocolData* pPData;
  393. PSPD pSPD;
  394. SPINITIALIZEDATA SPInitData;
  395. SPGETCAPSDATA SPCapsData;
  396. HRESULT hr;
  397. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], pISP[%p], phSPContext[%p]", hProtocolData, pISP, phSPContext);
  398. hr = DPN_OK;
  399. pPData = (ProtocolData*)hProtocolData;
  400. ASSERT_PPD(pPData);
  401. if(pPData->ulProtocolFlags & PFLAGS_PROTOCOL_INITIALIZED)
  402. {
  403. if ((pSPD = (PSPD)MEMALLOC(MEMID_SPD, sizeof(SPD))) == NULL)
  404. {
  405. DPFX(DPFPREP,0, "Returning DPNERR_OUTOFMEMORY - couldn't allocate SP Descriptor");
  406. hr = DPNERR_OUTOFMEMORY;
  407. goto Exit;
  408. }
  409. // MAKE THE INITIALIZE CALL TO THE Service Provider... give him our Object
  410. memset(pSPD, 0, sizeof(SPD)); // init to zero
  411. pSPD->LowerEdgeVtable = &DNPLowerEdgeVtbl; // Put Vtbl into the interface Object
  412. pSPD->Sign = SPD_SIGN;
  413. SPInitData.pIDP = (IDP8SPCallback *) pSPD;
  414. SPInitData.dwFlags = dwFlags;
  415. if (DNInitializeCriticalSection(&pSPD->SPLock) == FALSE)
  416. {
  417. DPFX(DPFPREP,0, "Returning DPNERR_OUTOFMEMORY - couldn't initialize SP CS, pSPD[%p]", pSPD);
  418. DNFree(pSPD);
  419. hr = DPNERR_OUTOFMEMORY;
  420. goto Exit;
  421. }
  422. DebugSetCriticalSectionRecursionCount(&pSPD->SPLock, 0);
  423. DebugSetCriticalSectionGroup(&pSPD->SPLock, &g_blProtocolCritSecsHeld);
  424. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  425. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Initialize, pSPD[%p]", pSPD);
  426. if((hr = IDP8ServiceProvider_Initialize(pISP, &SPInitData)) != DPN_OK)
  427. {
  428. if (hr == DPNERR_UNSUPPORTED)
  429. {
  430. DPFX(DPFPREP,1, "SP unsupported, pSPD[%p]", pSPD);
  431. }
  432. else
  433. {
  434. DPFX(DPFPREP,0, "Returning hr=%x - SP->Initialize failed, pSPD[%p]", hr, pSPD);
  435. }
  436. DNDeleteCriticalSection(&pSPD->SPLock);
  437. DNFree(pSPD);
  438. goto Exit;
  439. }
  440. pSPD->blSendQueue.Initialize();
  441. pSPD->blPendingQueue.Initialize();
  442. pSPD->blEPDActiveList.Initialize();
  443. #ifdef DBG
  444. pSPD->blMessageList.Initialize();
  445. #endif // DBG
  446. // MAKE THE SP GET CAPS CALL TO FIND FRAMESIZE AND LINKSPEED
  447. SPCapsData.dwSize = sizeof(SPCapsData);
  448. SPCapsData.hEndpoint = INVALID_HANDLE_VALUE;
  449. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  450. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->GetCaps, pSPD[%p]", pSPD);
  451. if((hr = IDP8ServiceProvider_GetCaps(pISP, &SPCapsData)) != DPN_OK)
  452. {
  453. DPFX(DPFPREP,DPF_CALLOUT_LVL, "SP->GetCaps failed - hr[%x], Calling SP->Close, pSPD[%p]", hr, pSPD);
  454. IDP8ServiceProvider_Close(pISP);
  455. DNDeleteCriticalSection(&pSPD->SPLock);
  456. DPFX(DPFPREP,0, "Returning hr=%x - SP->GetCaps failed, pSPD[%p]", hr, pSPD);
  457. DNFree(pSPD);
  458. goto Exit;
  459. }
  460. pSPD->uiLinkSpeed = SPCapsData.dwLocalLinkSpeed;
  461. pSPD->uiFrameLength = SPCapsData.dwUserFrameSize;
  462. if (pSPD->uiFrameLength < MIN_SEND_MTU)
  463. {
  464. DPFX(DPFPREP,0, "SP MTU isn't large enough to support protocol pSPD[%p] Required MTU[%u] Available MTU[%u] "
  465. "Returning DPNERR_UNSUPPORTED", pSPD, MIN_SEND_MTU, pSPD->uiFrameLength);
  466. IDP8ServiceProvider_Close(pISP);
  467. DNDeleteCriticalSection(&pSPD->SPLock);
  468. DNFree(pSPD);
  469. hr=DPNERR_UNSUPPORTED;
  470. goto Exit;
  471. }
  472. pSPD->uiUserFrameLength = pSPD->uiFrameLength - MAX_SEND_DFRAME_NOCOALESCE_HEADER_SIZE;
  473. DPFX(DPFPREP, 3, "SPD 0x%p frame length = %u, single user frame length = %u.", pSPD, pSPD->uiFrameLength, pSPD->uiUserFrameLength);
  474. // Place new SP in table
  475. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  476. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->AddRef, pSPD[%p]", pSPD);
  477. IDP8ServiceProvider_AddRef(pISP);
  478. pSPD->IISPIntf = pISP;
  479. pSPD->pPData = pPData;
  480. DNInterlockedIncrement(&pPData->lSPActiveCount);
  481. }
  482. else
  483. {
  484. pSPD = NULL;
  485. DPFX(DPFPREP,0, "Returning DPNERR_UNINITIALIZED - DNPProtocolInitialize has not been called");
  486. hr = DPNERR_UNINITIALIZED;
  487. goto Exit;
  488. }
  489. *phSPContext = pSPD;
  490. Exit:
  491. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  492. return hr;
  493. }
  494. /*
  495. ** Remove Service Provider
  496. **
  497. ** It is higher layer's responsibility to make sure that there are no pending commands
  498. ** when this function is called, although we can do a certain amount of cleanup ourselves.
  499. ** For the moment we will ASSERT that everything is in fact finished up.
  500. **
  501. */
  502. #undef DPF_MODNAME
  503. #define DPF_MODNAME "DNPRemoveServiceProvider"
  504. HRESULT DNPRemoveServiceProvider(HANDLE hProtocolData, HANDLE hSPHandle)
  505. {
  506. ProtocolData* pPData;
  507. PSPD pSPD;
  508. PFMD pFMD;
  509. DWORD dwInterval;
  510. #ifdef DBG
  511. PEPD pEPD;
  512. PMSD pMSD;
  513. #endif // DBG
  514. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hSPHandle[%x]", hProtocolData, hSPHandle);
  515. pPData = (ProtocolData*)hProtocolData;
  516. ASSERT_PPD(pPData);
  517. pSPD = (PSPD) hSPHandle;
  518. ASSERT_SPD(pSPD);
  519. // There are several steps to shutdown:
  520. // 1. All Core initiated commands must be cancelled prior to this function being called.
  521. // We will assert in debug that the Core has done this.
  522. // 2. All endpoints must be terminated by the Core prior to this function being called.
  523. // We will assert in debug that the Core has done this.
  524. // Now there are things on the SPD->SendQueue and SPD->PendingQueue that are not owned
  525. // by any Command or Endpoint, and there may also be a SendThread Timer running held
  526. // on SPD->SendHandle. No one else can clean these up, so these are our responsibility
  527. // to clean up here. Items on the queues will be holding references to EPDs, so the
  528. // EPDs will not be able to go away until we do this.
  529. // 3. Cancel SPD->SendHandle Send Timer. This prevents items on the SendQueue from
  530. // being submitted to the SP and moved to the PendingQueue.
  531. // 4. Empty the SendQueue.
  532. // 5. If we fail to cancel the SendHandle Send Timer, wait for it to run and figure out
  533. // that we are going away. We do this after emptying the SendQueue for simplicity
  534. // since the RunSendThread code checks for an empty SendQueue to know if it has work
  535. // to do.
  536. // 6. Wait for all messages to drain from the PendingQueue as the SP completes them.
  537. // 7. Wait for any active EPDs to go away.
  538. // 8. Call SP->Close only after all of the above so that we can ensure that we will make
  539. // no calls to the SP after Close.
  540. Lock(&pSPD->SPLock);
  541. pSPD->ulSPFlags |= SPFLAGS_TERMINATING; // Nothing new gets in...
  542. #ifdef DBG
  543. // Check for uncancelled commands, SPLock held
  544. CBilink* pLink = pSPD->blMessageList.GetNext();
  545. while (pLink != &pSPD->blMessageList)
  546. {
  547. pMSD = CONTAINING_OBJECT(pLink, MSD, blSPLinkage);
  548. ASSERT_MSD(pMSD);
  549. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST);
  550. DPFX(DPFPREP,0, "There are un-cancelled commands remaining on the Command List, Core didn't clean up properly - pMSD[%p], Context[%x]", pMSD, pMSD->Context);
  551. ASSERT(0); // This is fatal, we can't make the guarantees we need to below under these conditions.
  552. pLink = pLink->GetNext();
  553. }
  554. // Check for EPDs that have not been terminated, SPLock still held
  555. pLink = pSPD->blEPDActiveList.GetNext();
  556. while (pLink != &pSPD->blEPDActiveList)
  557. {
  558. pEPD = CONTAINING_OBJECT(pLink, EPD, blActiveLinkage);
  559. ASSERT_EPD(pEPD);
  560. if (!(pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING))
  561. {
  562. DPFX(DPFPREP,0, "There are non-terminated endpoints remaining on the Endpoint List, Core didn't clean up properly - pEPD[%p], Context[%x]", pEPD, pEPD->Context);
  563. ASSERT(0); // This is fatal, we can't make the guarantees we need to below under these conditions.
  564. }
  565. pLink = pLink->GetNext();
  566. }
  567. #endif // DBG
  568. // Clean off the Send Queue, SPLock still held
  569. while(!pSPD->blSendQueue.IsEmpty())
  570. {
  571. pFMD = CONTAINING_OBJECT(pSPD->blSendQueue.GetNext(), FMD, blQLinkage);
  572. ASSERT_FMD(pFMD);
  573. ASSERT_EPD(pFMD->pEPD);
  574. DPFX(DPFPREP,1, "Cleaning FMD off of SendQueue pSPD[%p], pFMD[%p], pEPD[%p]", pSPD, pFMD, pFMD->pEPD);
  575. pFMD->blQLinkage.RemoveFromList();
  576. // RELEASE_EPD will need to have the EPD lock, so we cannot hold the SPLock while calling it.
  577. Unlock(&pSPD->SPLock);
  578. Lock(&pFMD->pEPD->EPLock);
  579. RELEASE_EPD(pFMD->pEPD, "UNLOCK (Releasing Leftover CMD FMD)"); // releases EPLock
  580. RELEASE_FMD(pFMD, "SP Submit");
  581. Lock(&pSPD->SPLock);
  582. }
  583. // In case we failed to cancel the SendHandle Timer above, wait for the send thread to run and figure
  584. // out that we are going away. We want to be outside the SPLock while doing this.
  585. dwInterval = 10;
  586. while(pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)
  587. {
  588. Unlock(&pSPD->SPLock);
  589. IDirectPlay8ThreadPoolWork_SleepWhileWorking(pPData->pDPThreadPoolWork, dwInterval, 0);
  590. dwInterval += 5;
  591. ASSERT(dwInterval < 500);
  592. Lock(&pSPD->SPLock);
  593. }
  594. // Clean off the Pending Queue, SPLock still held
  595. dwInterval = 10;
  596. while (!pSPD->blPendingQueue.IsEmpty())
  597. {
  598. Unlock(&pSPD->SPLock);
  599. IDirectPlay8ThreadPoolWork_SleepWhileWorking(pPData->pDPThreadPoolWork, dwInterval, 0);
  600. dwInterval += 5;
  601. ASSERT(dwInterval < 500);
  602. Lock(&pSPD->SPLock);
  603. }
  604. // By now we are only waiting for the SP to do any final calls to CommandComplete that are needed to take
  605. // our EPD ref count down to nothing. We will wait while the SP does this.
  606. dwInterval = 10;
  607. while(!(pSPD->blEPDActiveList.IsEmpty()))
  608. {
  609. Unlock(&pSPD->SPLock);
  610. IDirectPlay8ThreadPoolWork_SleepWhileWorking(pPData->pDPThreadPoolWork, dwInterval, 0);
  611. dwInterval += 5;
  612. ASSERT(dwInterval < 500);
  613. Lock(&pSPD->SPLock);
  614. }
  615. // By this time everything pending had better be gone!
  616. ASSERT(pSPD->blEPDActiveList.IsEmpty()); // Should not be any Endpoints left
  617. ASSERT(pSPD->blSendQueue.IsEmpty()); // Should not be any frames on sendQ.
  618. ASSERT(pSPD->blPendingQueue.IsEmpty()); // Should not be any frame in SP either
  619. // Leave SPLock for the last time
  620. Unlock(&pSPD->SPLock);
  621. // Now that all frames are cleared out of SP, there should be no more End Points waiting around to close.
  622. // We are clear to tell the SP to go away.
  623. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  624. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Close, pSPD[%p]", pSPD);
  625. IDP8ServiceProvider_Close(pSPD->IISPIntf);
  626. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Release, pSPD[%p]", pSPD);
  627. IDP8ServiceProvider_Release(pSPD->IISPIntf);
  628. // Clean up the SPD object
  629. DNDeleteCriticalSection(&pSPD->SPLock);
  630. DNFree(pSPD);
  631. // Remove the reference of this SP from the main Protocol object
  632. ASSERT(pPData->lSPActiveCount > 0);
  633. DNInterlockedDecrement(&pPData->lSPActiveCount);
  634. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  635. return DPN_OK;
  636. }