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.

570 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 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. LPFPOOL ChkPtPool = NULL; // Pool of CheckPoint data structure
  26. LPFPOOL EPDPool = NULL; // Pool of End Point descriptors
  27. LPFPOOL MSDPool = NULL; // Pool of Message Descriptors
  28. LPFPOOL FMDPool = NULL; // Pool of Frame Descriptors
  29. LPFPOOL RCDPool = NULL; // Pool of Receive Descriptors
  30. LPFPOOL BufPool = NULL; // Pool of buffers to store rcvd frames
  31. LPFPOOL MedBufPool = NULL;
  32. LPFPOOL BigBufPool = NULL;
  33. LONG g_lProtocolObjects = 0;
  34. DNCRITICAL_SECTION g_csProtocolGlobal;
  35. BOOL g_fTimerInited = FALSE;
  36. /*
  37. ** Pools Initialization
  38. **
  39. ** This procedure should be called once at Dll load
  40. */
  41. #undef DPF_MODNAME
  42. #define DPF_MODNAME "DNPPoolsInit"
  43. BOOL DNPPoolsInit()
  44. {
  45. DPFX(DPFPREP,DPF_CALLIN_LVL, "Enter");
  46. if (DNInitializeCriticalSection(&g_csProtocolGlobal) == FALSE)
  47. {
  48. return FALSE;
  49. }
  50. if((ChkPtPool = FPM_Create(sizeof(CHKPT), NULL, NULL, NULL, NULL)) == NULL)
  51. {
  52. DNPPoolsDeinit();
  53. return FALSE;
  54. }
  55. if((EPDPool = FPM_Create(sizeof(EPD), EPD_Allocate, EPD_Get, EPD_Release, EPD_Free)) == NULL)
  56. {
  57. DNPPoolsDeinit();
  58. return FALSE;
  59. }
  60. if((MSDPool = FPM_Create(sizeof(MSD), MSD_Allocate, MSD_Get, MSD_Release, MSD_Free)) == NULL)
  61. {
  62. DNPPoolsDeinit();
  63. return FALSE;
  64. }
  65. if((FMDPool = FPM_Create(sizeof(FMD), FMD_Allocate, FMD_Get, FMD_Release, FMD_Free)) == NULL)
  66. {
  67. DNPPoolsDeinit();
  68. return FALSE;
  69. }
  70. if((RCDPool = FPM_Create(sizeof(RCD), RCD_Allocate, RCD_Get, RCD_Release, RCD_Free)) == NULL)
  71. {
  72. DNPPoolsDeinit();
  73. return FALSE;
  74. }
  75. if((BufPool = FPM_Create(sizeof(BUF), Buf_Allocate, Buf_Get, NULL, NULL)) == NULL)
  76. {
  77. DNPPoolsDeinit();
  78. return FALSE;
  79. }
  80. if((MedBufPool = FPM_Create(sizeof(MEDBUF), Buf_Allocate, Buf_GetMed, NULL, NULL)) == NULL)
  81. {
  82. DNPPoolsDeinit();
  83. return FALSE;
  84. }
  85. if((BigBufPool = FPM_Create(sizeof(BIGBUF), Buf_Allocate, Buf_GetBig, NULL, NULL)) == NULL)
  86. {
  87. DNPPoolsDeinit();
  88. return FALSE;
  89. }
  90. if (FAILED(TimerInit()))
  91. {
  92. DNPPoolsDeinit();
  93. return FALSE;
  94. }
  95. g_fTimerInited = TRUE;
  96. return TRUE;
  97. }
  98. /*
  99. ** Pools Deinitialization
  100. **
  101. ** This procedure should be called by DllMain at shutdown time
  102. */
  103. #undef DPF_MODNAME
  104. #define DPF_MODNAME "DNPPoolsDeinit"
  105. void DNPPoolsDeinit()
  106. {
  107. DPFX(DPFPREP,DPF_CALLIN_LVL, "Enter");
  108. if (g_fTimerInited)
  109. {
  110. TimerDeinit();
  111. g_fTimerInited = FALSE;
  112. }
  113. DNDeleteCriticalSection(&g_csProtocolGlobal);
  114. if(ChkPtPool != NULL)
  115. {
  116. ChkPtPool->Fini(ChkPtPool);
  117. ChkPtPool = NULL;
  118. }
  119. if(EPDPool != NULL)
  120. {
  121. EPDPool->Fini(EPDPool);
  122. EPDPool = NULL;
  123. }
  124. if(MSDPool != NULL)
  125. {
  126. MSDPool->Fini(MSDPool);
  127. MSDPool = NULL;
  128. }
  129. if(FMDPool != NULL){
  130. FMDPool->Fini(FMDPool);
  131. FMDPool = NULL;
  132. }
  133. if(RCDPool != NULL)
  134. {
  135. RCDPool->Fini(RCDPool);
  136. RCDPool = NULL;
  137. }
  138. if(BufPool != NULL)
  139. {
  140. BufPool->Fini(BufPool);
  141. BufPool = NULL;
  142. }
  143. if(MedBufPool != NULL)
  144. {
  145. MedBufPool->Fini(MedBufPool);
  146. MedBufPool = NULL;
  147. }
  148. if(BigBufPool != NULL)
  149. {
  150. BigBufPool->Fini(BigBufPool);
  151. BigBufPool = NULL;
  152. }
  153. }
  154. /*
  155. ** Protocol Initialize
  156. **
  157. ** This procedure should be called by DirectPlay at startup time before
  158. ** any other calls in the protocol are made.
  159. */
  160. #undef DPF_MODNAME
  161. #define DPF_MODNAME "DNPProtocolInitialize"
  162. HRESULT DNPProtocolInitialize(PVOID pCoreContext, PProtocolData pPData, PDN_PROTOCOL_INTERFACE_VTBL pVtbl)
  163. {
  164. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pCoreContext[%p], pPData[%p], pVtbl[%p]", pCoreContext, pPData, pVtbl);
  165. // 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));
  166. DNEnterCriticalSection(&g_csProtocolGlobal);
  167. g_lProtocolObjects++;
  168. if (g_lProtocolObjects == 1)
  169. {
  170. // We are the first, create everything
  171. DPFX(DPFPREP,5, "Initializing timers");
  172. if (FAILED(InitTimerWorkaround()))
  173. {
  174. DPFX(DPFPREP,0, "Protocol timer package failed to initialize");
  175. g_lProtocolObjects--;
  176. DNLeaveCriticalSection(&g_csProtocolGlobal);
  177. return DPNERR_GENERIC;
  178. }
  179. }
  180. DNLeaveCriticalSection(&g_csProtocolGlobal);
  181. pPData->ulProtocolFlags = 0;
  182. pPData->Parent = pCoreContext;
  183. pPData->pfVtbl = pVtbl;
  184. pPData->Sign = PD_SIGN;
  185. pPData->lSPActiveCount = 0;
  186. srand(GETTIMESTAMP());
  187. pPData->dwNextSessID = rand() | (rand() << 16); // build a 32 bit value out of two 16 bit values
  188. pPData->tIdleThreshhold = DEFAULT_KEEPALIVE_INTERVAL; // 60 second keep-alive interval
  189. pPData->dwConnectTimeout = CONNECT_DEFAULT_TIMEOUT;
  190. pPData->dwConnectRetries = CONNECT_DEFAULT_RETRIES;
  191. #ifdef DEBUG
  192. pPData->ThreadsInReceive = 0;
  193. pPData->BuffersInReceive = 0;
  194. #endif
  195. pPData->ulProtocolFlags |= PFLAGS_PROTOCOL_INITIALIZED;
  196. return DPN_OK;
  197. }
  198. /*
  199. ** Protocol Shutdown
  200. **
  201. ** This procedure should be called at termination time, and should be the
  202. ** last call made to the protocol.
  203. **
  204. ** All SPs should have been removed prior to this call which in turn means
  205. ** that we should not have any sends pending in a lower layer.
  206. */
  207. #undef DPF_MODNAME
  208. #define DPF_MODNAME "DNPProtocolShutdown"
  209. HRESULT DNPProtocolShutdown(PProtocolData pPData)
  210. {
  211. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p]", pPData);
  212. DNEnterCriticalSection(&g_csProtocolGlobal);
  213. g_lProtocolObjects--;
  214. if (g_lProtocolObjects == 0)
  215. {
  216. // We are the last, destroy everything
  217. DPFX(DPFPREP,5, "Destroying timers");
  218. FiniTimerWorkaround();
  219. }
  220. DNLeaveCriticalSection(&g_csProtocolGlobal);
  221. if(pPData->lSPActiveCount != 0)
  222. {
  223. DPFX(DPFPREP,0, "Returning DPNERR_INVALIDCOMMAND - There are still active SPs, DNPRemoveSP wasn't called");
  224. return DPNERR_INVALIDCOMMAND; // Must remove Service Providers first
  225. }
  226. #ifdef DEBUG
  227. if (pPData->BuffersInReceive != 0)
  228. {
  229. DPFX(DPFPREP,0, "*** %d receive buffers were leaked", pPData->BuffersInReceive);
  230. }
  231. #endif
  232. pPData->ulProtocolFlags = 0;
  233. return DPN_OK;
  234. }
  235. /*
  236. ** Add Service Provider
  237. **
  238. ** This procedure is called by Direct Play to bind us to a service provider.
  239. ** We can bind up to 256 service providers at one time, although I would not ever
  240. ** expect to do so. This procedure will fail if Protocol Initialize has not
  241. ** been called.
  242. **
  243. **
  244. ** We check the size of the SP table to make sure we have a slot free. If table
  245. ** is full we double the table size until we reach maximum size. If table cannot grow
  246. ** then we fail the AddServiceProvider call.
  247. */
  248. extern IDP8SPCallbackVtbl DNPLowerEdgeVtbl;
  249. #undef DPF_MODNAME
  250. #define DPF_MODNAME "DNPAddServiceProvider"
  251. HRESULT DNPAddServiceProvider(PProtocolData pPData, IDP8ServiceProvider *pISP, HANDLE *pContext)
  252. {
  253. PSPD pSPD=0;
  254. SPINITIALIZEDATA SPInitData;
  255. SPGETCAPSDATA SPCapsData;
  256. HRESULT hr;
  257. *pContext = NULL;
  258. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], pISP[%p], pContext[%p]", pPData, pISP, pContext);
  259. if(pPData->ulProtocolFlags & PFLAGS_PROTOCOL_INITIALIZED)
  260. {
  261. if ((pSPD = (PSPD)DNMalloc(sizeof(SPD))) == NULL)
  262. {
  263. DPFX(DPFPREP,0, "Returning DPNERR_OUTOFMEMORY - couldn't allocate SP Descriptor");
  264. return DPNERR_OUTOFMEMORY;
  265. }
  266. // MAKE THE INITIALIZE CALL TO THE Service Provider... give him our Object
  267. memset(pSPD, 0, sizeof(SPD)); // init to zero
  268. pSPD->LowerEdgeVtable = &DNPLowerEdgeVtbl; // Put Vtbl into the interface Object
  269. pSPD->Sign = SPD_SIGN;
  270. SPInitData.pIDP = (IDP8SPCallback *) pSPD;
  271. SPInitData.dwFlags = 0;
  272. if (DNInitializeCriticalSection(&pSPD->SPLock) == FALSE)
  273. {
  274. DPFX(DPFPREP,0, "Returning DPNERR_OUTOFMEMORY - couldn't initialize SP CS, pSPD[%p]", pSPD);
  275. DNFree(pSPD);
  276. return DPNERR_OUTOFMEMORY;
  277. }
  278. DebugSetCriticalSectionRecursionCount(&pSPD->SPLock, 0);
  279. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Initialize, pSPD[%p]", pSPD);
  280. if((hr = IDP8ServiceProvider_Initialize(pISP, &SPInitData)) != DPN_OK)
  281. {
  282. DPFX(DPFPREP,0, "Returning hr=%x - SP->Initialize failed, pSPD[%p]", hr, pSPD);
  283. DNDeleteCriticalSection(&pSPD->SPLock);
  284. DNFree(pSPD);
  285. return hr;
  286. }
  287. pSPD->blSendQueue.Initialize();
  288. pSPD->blPendingQueue.Initialize();
  289. pSPD->blEPDActiveList.Initialize();
  290. #ifdef DEBUG
  291. pSPD->blMessageList.Initialize();
  292. #endif
  293. // MAKE THE SP GET CAPS CALL TO FIND FRAMESIZE AND LINKSPEED
  294. SPCapsData.dwSize = sizeof(SPCapsData);
  295. SPCapsData.hEndpoint = INVALID_HANDLE_VALUE;
  296. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->GetCaps, pSPD[%p]", pSPD);
  297. if((hr = IDP8ServiceProvider_GetCaps(pISP, &SPCapsData)) != DPN_OK)
  298. {
  299. DPFX(DPFPREP,DPF_CALLOUT_LVL, "SP->GetCaps failed - hr[%x], Calling SP->Close, pSPD[%p]", hr, pSPD);
  300. IDP8ServiceProvider_Close(pISP);
  301. DNDeleteCriticalSection(&pSPD->SPLock);
  302. DPFX(DPFPREP,0, "Returning hr=%x - SP->GetCaps failed, pSPD[%p]", hr, pSPD);
  303. DNFree(pSPD);
  304. return hr;
  305. }
  306. pSPD->uiLinkSpeed = SPCapsData.dwLocalLinkSpeed;
  307. pSPD->uiFrameLength = SPCapsData.dwUserFrameSize;
  308. pSPD->uiUserFrameLength = pSPD->uiFrameLength - DNP_MAX_HEADER_SIZE;
  309. // Place new SP in table
  310. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->AddRef, pSPD[%p]", pSPD);
  311. IDP8ServiceProvider_AddRef(pISP);
  312. pSPD->IISPIntf = pISP;
  313. pSPD->pPData = pPData;
  314. InterlockedIncrement(&pPData->lSPActiveCount);
  315. }
  316. else
  317. {
  318. DPFX(DPFPREP,0, "Returning DPNERR_UNINITIALIZED - DNPProtocolInitialize has not been called");
  319. return DPNERR_UNINITIALIZED;
  320. }
  321. *pContext = pSPD;
  322. return DPN_OK;
  323. }
  324. /*
  325. ** Remove Service Provider
  326. **
  327. ** It is higher layer's responsibility to make sure that there are no pending commands
  328. ** when this function is called, although we can do a certain amount of cleanup ourselves.
  329. ** For the moment will we ASSERT that everything is in fact finished up.
  330. **
  331. ** SPTable stuff... Since we use the table slot as the SP identiier, we must not compact
  332. ** the SP table upon removal. Therefore, we must have a way of validating the SP index, and
  333. ** we may not want to re-use table slots after an SP is removed. Since we have virtually
  334. ** unlimited space in the table, and SPs are generally not intended to be transitory, its
  335. ** probably safe to invalidate the old table slot and just keep increasing the IDs.
  336. */
  337. #undef DPF_MODNAME
  338. #define DPF_MODNAME "DNPRemoveServiceProvider"
  339. HRESULT DNPRemoveServiceProvider(PProtocolData pPData, HANDLE hSPHandle)
  340. {
  341. PSPD pSPD = NULL;
  342. PEPD pEPD;
  343. PMSD pMSD;
  344. PFMD pFMD;
  345. pSPD = (PSPD) hSPHandle;
  346. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], hSPHandle[%x]", pPData, hSPHandle);
  347. if(pSPD == NULL)
  348. {
  349. DPFX(DPFPREP,0, "Returning DPNERR_INVALIDOBJECT - SP Handle is NULL");
  350. return DPNERR_INVALIDOBJECT;
  351. }
  352. // There are several steps to shutdown:
  353. // 1. All Core initiated commands must be cancelled prior to this function being called.
  354. // We will assert in debug that the Core has done this.
  355. // 2. All endpoints must be terminated by the Core prior to this function being called.
  356. // We will assert in debug that the Core has done this.
  357. // Now there are things on the SPD->SendQueue and SPD->PendingQueue that are not owned
  358. // by any Command or Endpoint, and there may also be a SendThread Timer running held
  359. // on SPD->SendHandle. No one else can clean these up, so these are our responsibility
  360. // to clean up here. Items on the queues will be holding references to EPDs, so the
  361. // EPDs will not be able to go away until we do this.
  362. // 3. Cancel SPD->SendHandle Send Timer. This prevents items on the SendQueue from
  363. // being submitted to the SP and moved to the PendingQueue.
  364. // 4. Empty the SendQueue.
  365. // 5. If we fail to cancel the SendHandle Send Timer, wait for it to run and figure out
  366. // that we are going away. We do this after emptying the SendQueue for simplicity
  367. // since the RunSendThread code checks for an empty SendQueue to know if it has work
  368. // to do.
  369. // 6. Wait for all messages to drain from the PendingQueue as the SP completes them.
  370. // 7. Wait for any active EPDs to go away.
  371. // 8. Call SP->Close only after all of the above so that we can ensure that we will make
  372. // no calls to the SP after Close.
  373. Lock(&pSPD->SPLock);
  374. pSPD->ulSPFlags |= SPFLAGS_TERMINATING; // Nothing new gets in...
  375. #ifdef DEBUG
  376. // Check for uncancelled commands, SPLock held
  377. CBilink* pLink = pSPD->blMessageList.GetNext();
  378. while (pLink != &pSPD->blMessageList)
  379. {
  380. pMSD = CONTAINING_RECORD(pLink, MSD, blSPLinkage);
  381. ASSERT_MSD(pMSD);
  382. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST);
  383. 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);
  384. ASSERT(0); // This is fatal, we can't make the guarantees we need to below under these conditions.
  385. pLink = pLink->GetNext();
  386. }
  387. // Check for EPDs that have not been terminated, SPLock still held
  388. pLink = pSPD->blEPDActiveList.GetNext();
  389. while (pLink != &pSPD->blEPDActiveList)
  390. {
  391. pEPD = CONTAINING_RECORD(pLink, EPD, blActiveLinkage);
  392. ASSERT_EPD(pEPD);
  393. if (!(pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING))
  394. {
  395. 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);
  396. ASSERT(0); // This is fatal, we can't make the guarantees we need to below under these conditions.
  397. }
  398. pLink = pLink->GetNext();
  399. }
  400. #endif
  401. // See if we still have a Send Event pending, SPLock still held
  402. if(pSPD->SendHandle != NULL)
  403. {
  404. DPFX(DPFPREP,1, "Shutting down with send event still pending, cancelling, pSPD=[%p]", pSPD);
  405. if(CancelMyTimer(pSPD->SendHandle, pSPD->SendHandleUnique) == DPN_OK)
  406. {
  407. pSPD->SendHandle = NULL;
  408. pSPD->ulSPFlags &= ~(SPFLAGS_SEND_THREAD_SCHEDULED);
  409. }
  410. else
  411. {
  412. DPFX(DPFPREP,1, "Failed to cancel send event", pSPD);
  413. }
  414. }
  415. // Clean off the Send Queue, SPLock still held
  416. while(!pSPD->blSendQueue.IsEmpty())
  417. {
  418. pFMD = CONTAINING_RECORD(pSPD->blSendQueue.GetNext(), FMD, blQLinkage);
  419. ASSERT_FMD(pFMD);
  420. ASSERT_EPD(pFMD->pEPD);
  421. DPFX(DPFPREP,1, "Cleaning FMD off of SendQueue pSPD[%p], pFMD[%p], pEPD[%p]", pSPD, pFMD, pFMD->pEPD);
  422. pFMD->blQLinkage.RemoveFromList();
  423. // RELEASE_EPD will need to have the EPD lock, so we cannot hold the SPLock while calling it.
  424. Unlock(&pSPD->SPLock);
  425. Lock(&pFMD->pEPD->EPLock);
  426. RELEASE_EPD(pFMD->pEPD, "UNLOCK (Releasing Leftover CMD FMD)"); // releases EPLock
  427. RELEASE_FMD(pFMD, "SP Submit");
  428. Lock(&pSPD->SPLock);
  429. }
  430. // In case we failed to cancel the SendHandle Timer above, wait for the send thread to run and figure
  431. // out that we are going away. We want to be outside the SPLock while doing this.
  432. while(pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)
  433. {
  434. Unlock(&pSPD->SPLock);
  435. Sleep(0); // Give up our time slice
  436. Lock(&pSPD->SPLock);
  437. }
  438. // Clean off the Pending Queue, SPLock still held
  439. while (!pSPD->blPendingQueue.IsEmpty())
  440. {
  441. Unlock(&pSPD->SPLock);
  442. Sleep(0); // Give up our time slice
  443. Lock(&pSPD->SPLock);
  444. }
  445. // By now we are only waiting for the SP to do any final calls to CommandComplete that are needed to take
  446. // our EPD ref count down to nothing. We will wait while the SP does this.
  447. while(!(pSPD->blEPDActiveList.IsEmpty()))
  448. {
  449. Unlock(&pSPD->SPLock);
  450. Sleep(0); // Give up our time slice
  451. Lock(&pSPD->SPLock);
  452. }
  453. // By this time everything pending had better be gone!
  454. ASSERT(pSPD->blEPDActiveList.IsEmpty()); // Should not be any Endpoints left
  455. ASSERT(pSPD->blSendQueue.IsEmpty()); // Should not be any frames on sendQ.
  456. ASSERT(pSPD->blPendingQueue.IsEmpty()); // Should not be any frame in SP either
  457. // Leave SPLock for the last time
  458. Unlock(&pSPD->SPLock);
  459. // Now that all frames are cleared out of SP, there should be no more End Points waiting around to close.
  460. // We are clear to tell the SP to go away.
  461. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Close, pSPD[%p]", pSPD);
  462. IDP8ServiceProvider_Close(pSPD->IISPIntf);
  463. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->Release, pSPD[%p]", pSPD);
  464. IDP8ServiceProvider_Release(pSPD->IISPIntf);
  465. // Clean up the SPD object
  466. DNDeleteCriticalSection(&pSPD->SPLock);
  467. DNFree(pSPD);
  468. // Remove the reference of this SP from the main Protocol object
  469. ASSERT(pPData->lSPActiveCount > 0);
  470. InterlockedDecrement(&pPData->lSPActiveCount);
  471. return DPN_OK;
  472. }