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.

2879 lines
96 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Backend.cpp
  6. * Content: This file contains the backend (mostly timer- and captive thread-based
  7. * processing for the send pipeline.
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 11/06/98 ejs Created
  13. * 07/01/2000 masonb Assumed Ownership
  14. *
  15. ****************************************************************************/
  16. /*
  17. ** NOTE ABOUT CRITICAL SECTIONS
  18. **
  19. ** It is legal to enter multiple critical sections concurrently, but to avoid
  20. ** deadlocks, they must be entered in the correct order.
  21. **
  22. ** MSD CommandLocks should be entered first. That is, do not attempt to take
  23. ** a command lock with the EPD EPLock held because you may deadlock the protocol.
  24. **
  25. ** ORDER OF PRECEDENCE - Never take a low # lock while holding a higher # lock
  26. **
  27. ** 1 - CommandLock // guards an MSD
  28. ** 2 - EPLock // guards EPD queues (and retry timer stuff)
  29. ** 3 - SPLock // guards SP send queue (and Listen command)
  30. **
  31. ** ANOTHER NOTE ABOUT CRIT SECs
  32. **
  33. ** It is also legal in WIN32 for a thread to take a CritSec multiple times, but in
  34. ** this implementation we will NEVER do that. The debug code will ASSERT that a thread
  35. ** never re-enters a locked critsec even though the OS would allow it.
  36. */
  37. #include "dnproti.h"
  38. PFMD CopyFMD(PFMD, PEPD);
  39. #undef DPF_MODNAME
  40. #define DPF_MODNAME "LockEPD"
  41. #ifdef DEBUG
  42. BOOL LockEPD(PEPD pEPD, PCHAR Buf)
  43. {
  44. #else
  45. BOOL LockEPD(PEPD pEPD)
  46. {
  47. #endif
  48. if (INTER_INC(pEPD) == 0)
  49. {
  50. INTER_DEC(pEPD);
  51. return FALSE;
  52. }
  53. else
  54. {
  55. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, pEPD->lRefCnt);
  56. return TRUE;
  57. }
  58. }
  59. /*
  60. * Called with EPLock held, returns with EPLock released
  61. */
  62. #undef DPF_MODNAME
  63. #define DPF_MODNAME "ReleaseEPD"
  64. #ifdef DEBUG
  65. VOID ReleaseEPD(PEPD pEPD, PCHAR Buf)
  66. {
  67. #else
  68. VOID ReleaseEPD(PEPD pEPD)
  69. {
  70. #endif
  71. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  72. ASSERT(pEPD->lRefCnt >= 0);
  73. // Someone else can come along and call LOCK_EPD or DECREMENT_EPD while we are here
  74. // so the decrement has to be interlocked even though we own the EPLock.
  75. LONG lRefCnt = INTER_DEC(pEPD);
  76. if (lRefCnt == 0 && !(pEPD->ulEPFlags & EPFLAGS_SP_DISCONNECTED))
  77. {
  78. // Make sure no one else does this again
  79. pEPD->ulEPFlags |= EPFLAGS_SP_DISCONNECTED;
  80. SPDISCONNECTDATA Block;
  81. Block.hEndpoint = pEPD->hEndPt;
  82. Block.dwFlags = 0;
  83. Block.pvContext = NULL;
  84. ASSERT(pEPD->hEndPt != INVALID_HANDLE_VALUE);
  85. pEPD->hEndPt = INVALID_HANDLE_VALUE;
  86. Unlock(&pEPD->EPLock);
  87. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->Disconnect - hEndpoint[%x], pSPD[%p]", pEPD, Block.hEndpoint, pEPD->pSPD);
  88. (void) IDP8ServiceProvider_Disconnect(pEPD->pSPD->IISPIntf, &Block);
  89. }
  90. else if (lRefCnt < 0)
  91. {
  92. Unlock(&pEPD->EPLock);
  93. Lock(&pEPD->pSPD->SPLock);
  94. pEPD->blActiveLinkage.RemoveFromList();
  95. Unlock(&pEPD->pSPD->SPLock);
  96. EPDPool->Release(EPDPool, pEPD);
  97. }
  98. else
  99. {
  100. Unlock(&pEPD->EPLock);
  101. }
  102. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, lRefCnt);
  103. }
  104. #undef DPF_MODNAME
  105. #define DPF_MODNAME "DecrementEPD"
  106. #ifdef DEBUG
  107. VOID DecrementEPD(PEPD pEPD, PCHAR Buf)
  108. {
  109. #else
  110. VOID DecrementEPD(PEPD pEPD)
  111. {
  112. #endif
  113. ASSERT(pEPD->lRefCnt > 0);
  114. INTER_DEC(pEPD);
  115. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, pEPD->lRefCnt);
  116. }
  117. #undef DPF_MODNAME
  118. #define DPF_MODNAME "LockMSD"
  119. #ifdef DEBUG
  120. VOID LockMSD(PMSD pMSD, PCHAR Buf)
  121. {
  122. #else
  123. VOID LockMSD(PMSD pMSD)
  124. {
  125. #endif
  126. if(INTER_INC(pMSD) == 0)
  127. {
  128. ASSERT(0);
  129. }
  130. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  131. }
  132. #undef DPF_MODNAME
  133. #define DPF_MODNAME "ReleaseMSD"
  134. #ifdef DEBUG
  135. VOID ReleaseMSD(PMSD pMSD, PCHAR Buf)
  136. {
  137. #else
  138. VOID ReleaseMSD(PMSD pMSD)
  139. {
  140. #endif
  141. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  142. ASSERT(pMSD->lRefCnt >= 0);
  143. if(INTER_DEC(pMSD) < 0)
  144. {
  145. MSDPool->Release(MSDPool, pMSD);
  146. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, -1);
  147. }
  148. else
  149. {
  150. Unlock(&pMSD->CommandLock);
  151. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  152. }
  153. }
  154. #undef DPF_MODNAME
  155. #define DPF_MODNAME "DecrementMSD"
  156. #ifdef DEBUG
  157. VOID DecrementMSD(PMSD pMSD, PCHAR Buf)
  158. {
  159. #else
  160. VOID DecrementMSD(PMSD pMSD)
  161. {
  162. #endif
  163. ASSERT(pMSD->lRefCnt > 0);
  164. INTER_DEC(pMSD);
  165. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  166. }
  167. #undef DPF_MODNAME
  168. #define DPF_MODNAME "LockFMD"
  169. #ifdef DEBUG
  170. VOID LockFMD(PFMD pFMD, PCHAR Buf)
  171. {
  172. #else
  173. VOID LockFMD(PFMD pFMD)
  174. {
  175. #endif
  176. ASSERT(pFMD->lRefCnt > 0); // FMD_Get is the only function that should make this 1
  177. INTER_INC(pFMD);
  178. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, pFMD->lRefCnt);
  179. }
  180. #undef DPF_MODNAME
  181. #define DPF_MODNAME "ReleaseFMD"
  182. #ifdef DEBUG
  183. VOID ReleaseFMD(PFMD pFMD, PCHAR Buf)
  184. {
  185. #else
  186. VOID ReleaseFMD(PFMD pFMD)
  187. {
  188. #endif
  189. ASSERT(pFMD->lRefCnt > 0);
  190. if( INTER_DEC(pFMD) == 0)
  191. {
  192. FMDPool->Release(FMDPool, pFMD);
  193. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, 0);
  194. }
  195. else
  196. {
  197. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, pFMD->lRefCnt);
  198. }
  199. }
  200. /*
  201. ** DNSP Command Complete
  202. **
  203. ** Service Provider calls us here to indicate completion of an asynchronous
  204. ** command. This may be called before the actual command returns, so we must
  205. ** make sure that our Context value is valid and accessible before calling SP.
  206. */
  207. #undef DPF_MODNAME
  208. #define DPF_MODNAME "DNSP_CommandComplete"
  209. HRESULT WINAPI DNSP_CommandComplete(IDP8SPCallback *pIDNSP, HANDLE Handle, HRESULT hr, PVOID Context)
  210. {
  211. PSPD pSPD = (PSPD) pIDNSP;
  212. PFMD pFMD = (PFMD) Context;
  213. PEPD pEPD;
  214. PMSD pMSD;
  215. ASSERT_SPD(pSPD);
  216. DPFX(DPFPREP,9, "COMMAND COMPLETE (%p)", Context);
  217. // If we did not specify a context, then we are not waiting for completion.
  218. if(Context != NULL)
  219. {
  220. switch(pFMD->CommandID)
  221. {
  222. case COMMAND_ID_SEND_DATAGRAM:
  223. {
  224. ASSERT_FMD(pFMD);
  225. ASSERT(pFMD->bSubmitted);
  226. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL);
  227. pEPD = pFMD->pEPD;
  228. ASSERT_EPD(pEPD);
  229. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_SEND_DATAGRAM, pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  230. Lock(&pSPD->SPLock);
  231. pFMD->blQLinkage.RemoveFromList(); // Unlink from SPD Pending Queue
  232. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected bp SP->SPLock
  233. Unlock(&pSPD->SPLock);
  234. pMSD = pFMD->pMSD;
  235. ASSERT_MSD(pMSD);
  236. ASSERT(pMSD->lRefCnt != -1);
  237. Lock(&pMSD->CommandLock);
  238. Lock(&pEPD->EPLock);
  239. pMSD->uiFrameCount--;
  240. pFMD->blMSDLinkage.RemoveFromList(); // Unlink from message
  241. RELEASE_FMD(pFMD, "MSD Frame List"); // release reference from frame list
  242. if(pMSD->uiFrameCount == 0)
  243. {
  244. // There is a race condition while abort is between its two holdings of the lock. If we are completing,
  245. // then we need to let AbortSends know that by clearing this flag.
  246. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ABORT_WILL_COMPLETE);
  247. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing NG, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  248. Unlock(&pEPD->EPLock);
  249. CompleteDatagramSend(pSPD, pMSD, hr); // Datagram completes when SP says its xmited, releases MSDLock
  250. Lock(&pEPD->EPLock);
  251. }
  252. else
  253. {
  254. ASSERT(!pMSD->blFrameList.IsEmpty());
  255. Unlock(&pMSD->CommandLock);
  256. }
  257. RELEASE_EPD(pEPD, "UNLOCK (DG Frame Complete)"); // This releases the EPLock
  258. RELEASE_FMD(pFMD, "SP Submit"); // Release reference on frame from SP submission
  259. break;
  260. }
  261. case COMMAND_ID_SEND_RELIABLE:
  262. case COMMAND_ID_COPIED_RETRY:
  263. {
  264. ASSERT_FMD(pFMD);
  265. ASSERT(pFMD->bSubmitted);
  266. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL);
  267. pEPD = pFMD->pEPD;
  268. ASSERT_EPD(pEPD);
  269. if (pFMD->CommandID == COMMAND_ID_SEND_RELIABLE)
  270. {
  271. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_SEND_RELIABLE, pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  272. }
  273. else
  274. {
  275. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_COPIED_RETRY, pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pFMD->pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  276. }
  277. Lock(&pSPD->SPLock);
  278. pFMD->blQLinkage.RemoveFromList(); // but they dont wait on the PENDING queue
  279. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected bp SP->SPLock
  280. Unlock(&pSPD->SPLock);
  281. pMSD = pFMD->pMSD;
  282. ASSERT_MSD(pMSD);
  283. Lock(&pMSD->CommandLock);
  284. Lock(&pEPD->EPLock);
  285. // We wait for the Frame count to go to zero on reliables before completing them to the Core so that we know we are done
  286. // with the user's buffers.
  287. pMSD->uiFrameCount--; // Protected by EPLock
  288. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count decremented on complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  289. if ((pMSD->CommandID == COMMAND_ID_DISCONNECT || pMSD->CommandID == COMMAND_ID_DISC_RESPONSE) &&
  290. (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT) &&
  291. (pMSD->uiFrameCount == 0)) // Protected by EPLock
  292. {
  293. // There is a race condition while abort is between its two holdings of the lock. If we are completing,
  294. // then we need to let AbortSends know that by clearing this flag.
  295. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ABORT_WILL_COMPLETE);
  296. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing disconnect, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  297. Unlock(&pEPD->EPLock);
  298. CompleteDisconnect(pMSD, pSPD, pEPD); // This releases the CommandLock
  299. Lock(&pEPD->EPLock);
  300. }
  301. else if ((pMSD->ulMsgFlags2 & (MFLAGS_TWO_SEND_COMPLETE|MFLAGS_TWO_ABORT)) && (pMSD->uiFrameCount == 0)) // Protected by EPLock
  302. {
  303. // Remove the MSD from the CompleteSends list
  304. pMSD->blQLinkage.RemoveFromList();
  305. // There is a race condition while abort is between its two holdings of the lock. If we are completing,
  306. // then we need to let AbortSends know that by clearing this flag.
  307. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ABORT_WILL_COMPLETE);
  308. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  309. // See what error code we need to return
  310. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_SEND_COMPLETE)
  311. {
  312. Unlock(&pEPD->EPLock);
  313. CompleteReliableSend(pEPD->pSPD, pMSD, DPN_OK); // This releases the CommandLock
  314. Lock(&pEPD->EPLock);
  315. }
  316. else
  317. {
  318. Unlock(&pEPD->EPLock);
  319. CompleteReliableSend(pEPD->pSPD, pMSD, DPNERR_CONNECTIONLOST); // This releases the CommandLock
  320. Lock(&pEPD->EPLock);
  321. }
  322. }
  323. else
  324. {
  325. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Message not yet complete or frames still out, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  326. Unlock(&pMSD->CommandLock);
  327. }
  328. if (pFMD->CommandID == COMMAND_ID_COPIED_RETRY)
  329. {
  330. DECREMENT_EPD(pFMD->pEPD, "UNLOCK (Rely Frame Complete (Copy))");
  331. }
  332. RELEASE_EPD(pFMD->pEPD, "UNLOCK (Rely Frame Complete)"); // This releases the EPLock
  333. RELEASE_FMD(pFMD, "Final Release on Complete"); // Dec ref count
  334. break;
  335. }
  336. case COMMAND_ID_CONNECT:
  337. {
  338. pMSD = (PMSD) Context;
  339. ASSERT_MSD(pMSD);
  340. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL); // Command can complete before hCommmand is set up
  341. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER);
  342. DPFX(DPFPREP,DPF_CALLIN_LVL, "(%p) CommandComplete called for COMMAND_ID_CONNECT, pMSD[%p], pSPD[%p], Handle[%p], hCommand[%p], hr[%x]", pMSD->pEPD, pMSD, pSPD, Handle, pMSD->hCommand, hr);
  343. Lock(&pMSD->CommandLock); // must do this before clearing IN_SP flag
  344. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); // clear InSP flag
  345. DECREMENT_MSD(pMSD, "SP Ref"); // Dec ref count w/o release lock
  346. CompleteSPConnect((PMSD) Context, pSPD, hr);
  347. break;
  348. }
  349. case COMMAND_ID_CFRAME:
  350. {
  351. ASSERT_FMD(pFMD);
  352. ASSERT(pFMD->bSubmitted);
  353. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL);
  354. pEPD = pFMD->pEPD;
  355. ASSERT_EPD(pEPD);
  356. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_CFRAME, pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pFMD->pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  357. Lock(&pSPD->SPLock);
  358. pFMD->blQLinkage.RemoveFromList(); // Take the frame off of the pending queue
  359. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected bp SP->SPLock
  360. Unlock(&pSPD->SPLock);
  361. Lock(&pEPD->EPLock);
  362. if (pFMD->ulFFlags & FFLAGS_FINAL_ACK)
  363. {
  364. pEPD->ulEPFlags |= EPFLAGS_ACKED_DISCONNECT;
  365. if (pEPD->ulEPFlags & EPFLAGS_DISCONNECT_ACKED)
  366. {
  367. DPFX(DPFPREP,7, "(%p) Final ACK completed and our EOS ACK'd, dropping link", pEPD);
  368. DropLink(pEPD); // Drops EPLock
  369. Lock(&pEPD->EPLock);
  370. }
  371. else
  372. {
  373. DPFX(DPFPREP,7, "(%p) Final ACK completed, still awaiting ACK on our EOS", pEPD);
  374. }
  375. }
  376. RELEASE_EPD(pEPD, "UNLOCK (CFrame Cmd Complete)"); // Release EndPoint before releasing frame, releases EPLock
  377. RELEASE_FMD(pFMD, "Final Release on Complete"); // Release Frame
  378. break;
  379. }
  380. case COMMAND_ID_LISTEN:
  381. {
  382. pMSD = (PMSD) Context;
  383. ASSERT_MSD(pMSD);
  384. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL); // Command can complete before hCommmand is set up
  385. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER);
  386. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_LISTEN, pMSD[%p], pSPD[%p], Handle[%p], hCommand[%p], hr[%x]", pMSD, pSPD, Handle, pMSD->hCommand, hr);
  387. Lock(&pMSD->CommandLock);
  388. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); // clear InSP flag
  389. #ifdef DEBUG
  390. Lock(&pSPD->SPLock);
  391. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  392. {
  393. pMSD->blSPLinkage.RemoveFromList();
  394. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  395. }
  396. Unlock(&pSPD->SPLock);
  397. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  398. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  399. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  400. #endif
  401. // Leave lock while calling into higher layer
  402. Unlock( &pMSD->CommandLock );
  403. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteListenTerminate, hr[%x], Core Context[%p]", pMSD, hr, pMSD->Context);
  404. pSPD->pPData->pfVtbl->CompleteListenTerminate(pSPD->pPData->Parent, pMSD->Context, hr);
  405. // Release the final reference on the MSD AFTER indicating to the Core
  406. Lock(&pMSD->CommandLock);
  407. RELEASE_MSD(pMSD, "SP Ref");
  408. // Base ref will be released when DoCancel completes
  409. break;
  410. }
  411. case COMMAND_ID_ENUM:
  412. {
  413. pMSD = static_cast<PMSD>( Context );
  414. ASSERT_MSD( pMSD );
  415. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL);
  416. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  417. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_ENUM, pMSD[%p], pSPD[%p], Handle[%p], hCommand[%p], hr[%x]", pMSD, pSPD, Handle, pMSD->hCommand, hr);
  418. Lock( &pMSD->CommandLock );
  419. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);
  420. #ifdef DEBUG
  421. Lock( &pSPD->SPLock );
  422. if ( ( pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST ) != 0 )
  423. {
  424. pMSD->blSPLinkage.RemoveFromList();
  425. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  426. }
  427. Unlock( &pSPD->SPLock );
  428. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  429. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  430. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  431. #endif
  432. // Leave lock while calling into higher layer
  433. Unlock( &pMSD->CommandLock );
  434. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteEnumQuery, hr[%x], Core Context[%p]", pMSD, hr, pMSD->Context);
  435. pSPD->pPData->pfVtbl->CompleteEnumQuery(pSPD->pPData->Parent, pMSD->Context, hr);
  436. // Release the final reference on the MSD AFTER indicating to the Core
  437. Lock( &pMSD->CommandLock );
  438. DECREMENT_MSD( pMSD, "SP Ref"); // SP is done
  439. RELEASE_MSD( pMSD, "Release On Complete" ); // Base Reference
  440. break;
  441. }
  442. case COMMAND_ID_ENUMRESP:
  443. {
  444. pMSD = static_cast<PMSD>( Context );
  445. ASSERT_MSD( pMSD );
  446. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL );
  447. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  448. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for COMMAND_ID_ENUMRESP, pMSD[%p], pSPD[%p], Handle[%p], hCommand[%p], hr[%x]", pMSD, pSPD, Handle, pMSD->hCommand, hr);
  449. Lock( &pMSD->CommandLock );
  450. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);
  451. #ifdef DEBUG
  452. Lock( &pSPD->SPLock );
  453. if ( ( pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST ) != 0 )
  454. {
  455. pMSD->blSPLinkage.RemoveFromList();
  456. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  457. }
  458. Unlock( &pSPD->SPLock );
  459. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  460. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  461. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  462. #endif
  463. // Leave lock while calling into higher layer
  464. Unlock( &pMSD->CommandLock );
  465. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteEnumResponse, hr[%x], Core Context[%p], hr[%x]", pMSD, hr, pMSD->Context, hr);
  466. pSPD->pPData->pfVtbl->CompleteEnumResponse(pSPD->pPData->Parent, pMSD->Context, hr);
  467. // Release the final reference on the MSD AFTER indicating to the Core
  468. Lock( &pMSD->CommandLock );
  469. DECREMENT_MSD( pMSD, "SP Ref" ); // SP is done
  470. RELEASE_MSD( pMSD, "Release On Complete" ); // Base Reference
  471. break;
  472. }
  473. default:
  474. {
  475. DPFX(DPFPREP,0, "CommandComplete called with unknown CommandID");
  476. ASSERT(0);
  477. break;
  478. }
  479. } // SWITCH
  480. } // IF NOT NULL CONTEXT
  481. else
  482. {
  483. DPFX(DPFPREP,0, "CommandComplete called with NULL Context");
  484. ASSERT(0);
  485. }
  486. return DPN_OK;
  487. }
  488. /*
  489. ** Update Xmit State
  490. **
  491. ** There are two elements to the remote rcv state delivered in each frame. There is
  492. ** the NSeq number which acknowledges ALL frames with smaller sequence numbers,
  493. ** and there is the bitmask which acknowledges specific frames starting with NSeq+1.
  494. **
  495. ** Frames prior to NSeq can be removed from the SendWindow. Frames acked by bits
  496. ** should be marked as acknowledged, but left in the window until covered by NSeq
  497. ** (because a protocol can renege on bit-acked frames).
  498. **
  499. ** We will walk through the send window queue, starting with the oldest frame,
  500. ** and remove each frame that has been acknowledged by NSeq. As we hit EOM frames,
  501. ** we will indicate SendComplete for the message. If the bitmask is non-zero we may
  502. ** trigger retransmission of the missing frames. I say 'may' because we dont want
  503. ** to send too many retranmissions of the same frame...
  504. **
  505. ** SOME MILD INSANITY: Doing the DropLink code now. There are several places where
  506. ** we release the EPD Locks in the code below, and any time we arent holding the locks
  507. ** someone can start terminating the link. Therefore, whenever we retake either EPD lock
  508. ** (State or SendQ) after yielding them, we must re-verify that EPFLAGS_CONNECTED is still
  509. ** set and be prepared to abort if it is not. Happily, the whole EPD wont go away on us
  510. ** because we have a RefCnt on it, but once CONNECTED has been cleared we dont want to go
  511. ** setting any more timers or submitting frames to the SP.
  512. **
  513. ** RE_WRITE TIME: We can be re-entered while User Sends are being completed. This is okay
  514. ** except for the chance that the second thread would blow through here and hit the rest
  515. ** of CrackSequential before us. CrackSeq would think it got an out of order frame (it had)
  516. ** and would issue a NACK before we could stop him. Easiest solution is to delay the callback
  517. ** of complete sends until the end of the whole receive operation (when we indicate receives
  518. ** for instance). Incoming data should have priority over completing sends anyhow...
  519. **
  520. ** ** ENTERED AND EXITS WITH EPD->EPLOCK HELD **
  521. */
  522. #undef DPF_MODNAME
  523. #define DPF_MODNAME "UpdateXmitState"
  524. VOID
  525. UpdateXmitState(PEPD pEPD, BYTE bNRcv, ULONG RcvMaskLow, ULONG RcvMaskHigh, DWORD tNow)
  526. {
  527. PSPD pSPD = pEPD->pSPD;
  528. PFMD pFMD;
  529. PMSD pMSD;
  530. CBilink *pLink;
  531. UINT tDelay;
  532. UINT uiRTT;
  533. UINT delta;
  534. BOOL ack = FALSE;
  535. BOOL retransmit = FALSE;
  536. BOOL logged_drop = FALSE;
  537. ASSERT_SPD(pSPD);
  538. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  539. if(RcvMaskLow | RcvMaskHigh)
  540. {
  541. DPFX(DPFPREP,7, "(%p) *NACK RCVD* NRcv=%x, MaskL=%x, MaskH=%x", pEPD, bNRcv, RcvMaskLow, RcvMaskHigh);
  542. }
  543. // The caller should have checked this
  544. ASSERT( pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED );
  545. #ifdef DEBUG
  546. // There should always be a timer running on the first frame in window
  547. if(!pEPD->blSendWindow.IsEmpty())
  548. {
  549. pFMD = CONTAINING_RECORD(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  550. ASSERT_FMD(pFMD);
  551. ASSERT(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET);
  552. }
  553. pFMD = NULL;
  554. #endif
  555. // The send window contains a sorted list of frames that we have sent, but have not received ACKs
  556. // for. pEPD->uiUnackedFrames contains the count of items in this list.
  557. while(!pEPD->blSendWindow.IsEmpty())
  558. {
  559. // Grab the first item in the list
  560. pFMD = CONTAINING_RECORD((pLink = pEPD->blSendWindow.GetNext()), FMD, blWindowLinkage);
  561. ASSERT_FMD(pFMD);
  562. // Let's try taking one sample from every group of acknowledgements
  563. // ALWAYS SAMPLE THE HIGHEST NUMBERED FRAME COVERED BY THIS ACK
  564. if(((PDFRAME) pFMD->ImmediateData)->bSeq == (bNRcv - 1))
  565. {
  566. // Don't take sample if frame was retry because we don't know
  567. if(pFMD->uiRetry == 0)
  568. {
  569. uiRTT = tNow - pFMD->tTimestamp[0]; // which instance to correlate the response with
  570. if(uiRTT & 0x80000000)
  571. {
  572. DPFX(DPFPREP,7, "(%p) We calced a negative RTT", pEPD);
  573. uiRTT = 1;
  574. }
  575. UpdateEndPoint(pEPD, uiRTT, pFMD->uiFrameLength, -1, tNow);
  576. }
  577. }
  578. // If bNRcv for the other side is higher than this frame's bSeq, we know the other side has
  579. // seen this frame, so it is ACK'd and we will remove it from the Send Window.
  580. if( (BYTE) ((bNRcv) - (((PDFRAME) pFMD->ImmediateData)->bSeq + 1)) < (BYTE) pEPD->uiUnackedFrames)
  581. {
  582. ASSERT(pFMD->ulFFlags & FFLAGS_IN_SEND_WINDOW);
  583. DPFX(DPFPREP,7, "(%p) Removing Frame %x from send window", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq);
  584. pFMD->blWindowLinkage.RemoveFromList(); // Remove frame from send window
  585. pFMD->ulFFlags &= ~(FFLAGS_IN_SEND_WINDOW); // Clear flag
  586. if(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET)
  587. {
  588. ASSERT(ack == FALSE);
  589. ASSERT(pEPD->RetryTimer != 0);
  590. DPFX(DPFPREP,7, "(%p) Cancelling Retry Timer", pEPD);
  591. if(CancelMyTimer(pEPD->RetryTimer, pEPD->RetryTimerUnique) == DPN_OK)
  592. {
  593. DECREMENT_EPD(pEPD, "UNLOCK (cancel retry timer)"); // SPLock not already held
  594. }
  595. else
  596. {
  597. DPFX(DPFPREP,7, "(%p) Cancelling Retry Timer Failed", pEPD);
  598. }
  599. pEPD->RetryTimer = 0; // This will cause event to be ignored if it runs
  600. pFMD->ulFFlags &= ~(FFLAGS_RETRY_TIMER_SET);
  601. }
  602. pEPD->uiUnackedFrames--; // track size of window
  603. ASSERT(pEPD->uiUnackedFrames <= MAX_RECEIVE_RANGE);
  604. pEPD->uiUnackedBytes -= pFMD->uiFrameLength;
  605. ASSERT(pEPD->uiUnackedBytes <= MAX_RECEIVE_RANGE * pSPD->uiFrameLength);
  606. pEPD->uiBytesAcked += pFMD->uiFrameLength;
  607. // If the frame has been queued for a retry, pull it off
  608. // NOTE: Copied retries of this frame may still be on the retry queue, inefficient to send them out, but okay
  609. if (pFMD->ulFFlags & FFLAGS_RETRY_QUEUED)
  610. {
  611. pFMD->blQLinkage.RemoveFromList();
  612. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  613. ASSERT_MSD(pFMD->pMSD);
  614. pFMD->pMSD->uiFrameCount--; // Protected by EPLock, retries count against outstanding frame count
  615. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Retry frame reference decremented on ACK, pMSD[%p], framecount[%u]", pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  616. DECREMENT_EPD(pEPD, "UNLOCK (Releasing Retry Frame)"); // SPLock not already held
  617. if (pFMD->CommandID == COMMAND_ID_COPIED_RETRY)
  618. {
  619. DECREMENT_EPD(pEPD, "UNLOCK (Copy Complete)"); // SPLock not already held
  620. }
  621. RELEASE_FMD(pFMD, "SP Submit");
  622. if (pEPD->blRetryQueue.IsEmpty())
  623. {
  624. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  625. }
  626. }
  627. // One more send complete
  628. // We will come down this path for Reliables, KeepAlives, and Disconnects
  629. // Datagrams are completed upon send completion and do not wait for an ACK
  630. if((pFMD->CommandID != COMMAND_ID_SEND_DATAGRAM) && (pFMD->ulFFlags & (FFLAGS_END_OF_MESSAGE | FFLAGS_END_OF_STREAM)))
  631. {
  632. pMSD = pFMD->pMSD;
  633. ASSERT_MSD(pMSD);
  634. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Flagging Complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  635. pMSD->ulMsgFlags2 |= MFLAGS_TWO_SEND_COMPLETE; // Mark this complete
  636. if (pMSD->uiFrameCount == 0) // Protected by EPLock
  637. {
  638. pEPD->ulEPFlags |= EPFLAGS_COMPLETE_SENDS;
  639. }
  640. }
  641. RELEASE_FMD(pFMD, "Send Window"); // Release reference for send window
  642. ack = TRUE;
  643. }
  644. else
  645. {
  646. break; // First unacked frame, we can stop checking list
  647. }
  648. } // WHILE (send window not empty)
  649. // At this point we have completed all of the frames ack'd by NRcv. We would now like to re-transmit
  650. // any frames NACK'd by bitmask (and mark the ones ACK'd by bitmask). Now remember, the first frame in
  651. // the window is automatically missing by the implied first zero-bit.
  652. //
  653. // We will retransmit ALL frames that appear to be missing. There may be a timer running on
  654. // the first frame, but only if we did not ACK any frames in the code above (ack == 0).
  655. //
  656. // Hmmm, if the partner has a fat pipeline we could see this bitmap lots of times. We need to make
  657. // sure we don't trigger a retransmission here a quarter-zillion times during the Ack latency period.
  658. // To solve this we will only re-xmit the first time we see this bit. After that, we will have to
  659. // wait around for the next RetryTimeout. I think that's just the way its going to have to be.
  660. //
  661. // OTHER THINGS WE KNOW:
  662. //
  663. // There must be at least two frames remaining in the SendWindow. At minimum, first frame missing (always)
  664. // and then at least one SACK'd frame after.
  665. //
  666. // pLink = first queue element in SendWindow
  667. // pFMD = first frame in SendWindow
  668. //
  669. // We are still Holding EPD->EPLock. It is okay to take SPD->SPLock while holding it.
  670. //
  671. // One More Problem: Since SP has changed its receive buffer logic mis-ordering of frames has become
  672. // quite commonplace. This means that our assumptions about the state of the SendWindow are not necessarily true.
  673. // This means that frames NACKed by bitmask may have been acknowleged by a racing frame. This means that the
  674. // SendWindow may not be in sync with the mask at all. This means we need to synchronize the bitmask with the
  675. // actual send window. This is done by right-shifting the mask for each frame that's been acknowleged since the
  676. // bitmask was minted before beginning the Selective Ack process.
  677. // NOTE: If everything was removed from the Send Window above, then pLink and pFMD will
  678. // be garbage. In that case we would expect the mask to be NULL after adjusting below.
  679. if((RcvMaskLow | RcvMaskHigh)&&(pEPD->uiUnackedFrames > 1))
  680. {
  681. if(bNRcv != ((PDFRAME) pFMD->ImmediateData)->bSeq)
  682. {
  683. // This SACK frame must have been delivered late behind a frame ACKing more stuff. We must get the mask in synch
  684. // with the current send window, and then see if there is still anything this mask is NACKing
  685. // CODEWORK
  686. // MASONB: If this is a late frame, then the newer frame will be a superset of all the info in this one, and this one is
  687. // not useful and can be discarded.
  688. DPFX(DPFPREP,7, "(%p) SACK frame out of sync with local state. (frame)bNRcv=%x, (local)nSeq=%x, ML=%x, MH=%x", pEPD, bNRcv, ((PDFRAME) pFMD->ImmediateData)->bSeq, RcvMaskLow, RcvMaskHigh);
  689. while((RcvMaskLow | RcvMaskHigh) && (bNRcv != ((PDFRAME) pFMD->ImmediateData)->bSeq) )
  690. {
  691. RIGHT_SHIFT_64(RcvMaskHigh, RcvMaskLow); // 64 bit logical shift right
  692. bNRcv++; // shift once for each frame prior to the window
  693. }
  694. DPFX(DPFPREP,7, "(%p) After adjusting, NRCV=%x, ML=%x, MH=%x", pEPD, bNRcv, RcvMaskLow, RcvMaskHigh);
  695. }
  696. if(ack == 0)
  697. {
  698. // If we did NOT Ack a frame, then retry timer is still running
  699. ASSERT(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET);
  700. // We will reset the retry timer since we are retrying now
  701. DPFX(DPFPREP,7, "(%p) Resetting Retry Timer for %dms", pEPD, pEPD->uiRetryTimeout);
  702. if(CancelMyTimer(pEPD->RetryTimer, pEPD->RetryTimerUnique) != DPN_OK)
  703. {
  704. LOCK_EPD(pEPD, "LOCK (cant cancel retry)"); // Could not cancel- therefore we must balance RefCnt
  705. }
  706. SetMyTimer(pEPD->uiRetryTimeout, 100, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique );
  707. }
  708. ASSERT(!(RcvMaskLow | RcvMaskHigh) || (pLink == pEPD->blSendWindow.GetNext()));
  709. // If pLink gets to the end of the list, the receive mask contained more bits than there were
  710. // items in the send window even after it was adjusted. This means the packet was bogus, and
  711. // we have probably hosed our state already, but we will go ahead and attempt to safeguard
  712. // against having an AV by not entering the loop with a bad pFMD from hitting the end of the list.
  713. while((RcvMaskLow | RcvMaskHigh) && pLink != &pEPD->blSendWindow)
  714. {
  715. pFMD = CONTAINING_RECORD(pLink, FMD, blWindowLinkage);
  716. ASSERT_FMD(pFMD);
  717. if((pFMD->ulFFlags & (FFLAGS_NACK_RETRANSMIT_SENT | FFLAGS_RETRY_QUEUED)) == 0)
  718. {
  719. // Check time since last retry was sent
  720. // Don't retry if we *just* sent one...
  721. if(((tNow - pFMD->tTimestamp[pFMD->uiRetry]) > 0)&&(pFMD->uiRetry < (MAX_RETRIES - 1)))
  722. {
  723. ((PDFRAME) pFMD->ImmediateData)->bNRcv = pEPD->bNextReceive; // Use up-to-date ACK info
  724. pFMD->uiRetry++;
  725. pFMD->ulFFlags |= FFLAGS_NACK_RETRANSMIT_SENT;
  726. pFMD->tTimestamp[pFMD->uiRetry] = tNow;
  727. // Unreliable frame!
  728. if(pFMD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  729. {
  730. // When an unreliable frame is NACKed we will not retransmit the data. We will instead send
  731. // a cancel mask telling the receiver to ignore this sequence number.
  732. DPFX(DPFPREP,7, "(%p) SELECTIVE RETRY REQUESTED for UNRELIABLE FRAME Seq=%x", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq);
  733. pEPD->uiUnackedBytes -= pFMD->uiFrameLength;
  734. if(pFMD->uiRetry == 1)
  735. {
  736. pEPD->uiDatagramFramesDropped++; // Only count a datagram drop on the first occurance
  737. pEPD->uiDatagramBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength); // Only user bytes
  738. EndPointDroppedFrame(pEPD, tNow);
  739. }
  740. delta = (BYTE) (pEPD->bNextSend - ((PDFRAME) pFMD->ImmediateData)->bSeq); // Diff between next send and this send.
  741. ASSERT(delta != 0);
  742. ASSERT(delta < (MAX_RECEIVE_RANGE + 1));
  743. if(delta < 33)
  744. {
  745. pEPD->ulSendMask |= (1 << (delta - 1));
  746. }
  747. else
  748. {
  749. pEPD->ulSendMask2 |= (1 << (delta - 33));
  750. }
  751. pFMD->uiFrameLength = 0; // Frame has been credited to the send window, don't want to credit again on ACK
  752. if((pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)==0)
  753. {
  754. pEPD->ulEPFlags |= EPFLAGS_DELAYED_SENDMASK;
  755. if(pEPD->DelayedMaskTimer == 0)
  756. {
  757. DPFX(DPFPREP,7, "(%p) Setting Delayed Ack Timer", pEPD);
  758. SetMyTimer(DELAYED_SEND_TIMEOUT, 0, DelayedAckTimeout, (PVOID) pEPD, &pEPD->DelayedMaskTimer, &pEPD->DelayedMaskTimerUnique);
  759. LOCK_EPD(pEPD, "LOCK (Delayed Mask Timer)");
  760. }
  761. }
  762. }
  763. // Reliable Frame -- Issue a retry of frame
  764. else
  765. {
  766. retransmit = TRUE;
  767. pEPD->uiGuaranteedFramesDropped++; // Keep count of lost frames
  768. pEPD->uiGuaranteedBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength); // Keep count of lost frames
  769. if(pFMD->bSubmitted)
  770. {
  771. // In the heat of battle, its possible that this FMD has not completed from the last
  772. // send. In this case, we will make a temporary copy of the FMD and submit the clone.
  773. // We will mark the clone as a RETRY_COPY which will be immediately freed upon completion,
  774. // and we will leave the retry timestamp in the original FMD.
  775. DPFX(DPFPREP,7, "(%p) SELECTIVE RETRY while FMD busy; Seq=0x%x", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq);
  776. pFMD = CopyFMD(pFMD, pEPD);
  777. }
  778. else
  779. {
  780. DPFX(DPFPREP,7, "(%p) SELECTIVE RETRY Seq=0x%x, FMD=0x%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  781. LOCK_FMD(pFMD, "SP Submit"); // Make sure this frame survives until transmitted
  782. }
  783. // Only call this once per NACK received
  784. if(logged_drop == FALSE)
  785. {
  786. EndPointDroppedFrame(pEPD, tNow);
  787. logged_drop = TRUE;
  788. }
  789. // EPD->EPLock is already held so we can slam frame right into rexmit queue
  790. // If CopyFMD failed we won't have an FMD here
  791. if(pFMD)
  792. {
  793. DPFX(DPFPREP,7, "(%p) Queueing frame on retry queue FMD[%p]", pEPD, pFMD);
  794. LOCK_EPD(pEPD, "LOCK (selective retry frame)");
  795. pEPD->ulEPFlags |= EPFLAGS_RETRIES_QUEUED;
  796. pFMD->ulFFlags |= FFLAGS_RETRY_QUEUED;
  797. ASSERT_MSD(pFMD->pMSD);
  798. pFMD->pMSD->uiFrameCount++; // Protected by EPLock, retries prevent completion until they complete
  799. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count incremented on NACK retry, pMSD[%p], framecount[%u]", pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  800. ASSERT(pFMD->blQLinkage.IsEmpty());
  801. pFMD->blQLinkage.InsertBefore( &pEPD->blRetryQueue); // Place frame on Send queue
  802. }
  803. }
  804. }
  805. else
  806. {
  807. // Last retry was less then 1 ms past -- we will ignore this for now
  808. DPFX(DPFPREP,7, "(%p) ***BLOWING OFF NACK***", pEPD);
  809. // CODEWORK: OR retries exhausted. We should either let only RetryTimeout do all of this work, or make
  810. // this code drop the link in this case.
  811. }
  812. }
  813. pLink = pLink->GetNext(); // Advance pLink to next frame in SendWindow
  814. // Move through bitmask and SendWindow until find missing frame
  815. while(RcvMaskLow & 1)
  816. {
  817. pLink = pLink->GetNext();
  818. RIGHT_SHIFT_64(RcvMaskHigh, RcvMaskLow); // 64 bit logical shift right
  819. }
  820. RIGHT_SHIFT_64(RcvMaskHigh, RcvMaskLow); // 64 bit logical shift right, skip the zero
  821. } // END WHILE (WORK MASKS NON-ZERO)
  822. if(retransmit)
  823. {
  824. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  825. // Stop delayed ack timer
  826. if(pEPD->DelayedAckTimer != 0)
  827. {
  828. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  829. if(CancelMyTimer(pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  830. {
  831. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayAckTimer)"); // SPLock not already held
  832. pEPD->DelayedAckTimer = 0;
  833. }
  834. else
  835. {
  836. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  837. }
  838. }
  839. if((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0)
  840. {
  841. DPFX(DPFPREP,7, "(%p) Scheduling Send", pEPD);
  842. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  843. LOCK_EPD(pEPD, "LOCK (pipeline)");
  844. ScheduleTimerThread(ScheduledSend, pEPD, &pEPD->SendTimer, &pEPD->SendTimerUnique);
  845. }
  846. }
  847. }
  848. // If we acked a frame above and there is more data outstanding then we may need to start a new Retry timer.
  849. //
  850. // Of course, we want to set the timer on whatever frame is the first in the SendWindow.
  851. if( (pEPD->uiUnackedFrames > 0) && (pEPD->RetryTimer == 0))
  852. {
  853. pFMD = CONTAINING_RECORD(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  854. ASSERT_FMD(pFMD);
  855. tDelay = tNow - pFMD->tTimestamp[pFMD->uiRetry]; // How long has this frame been enroute?
  856. tDelay = (tDelay > pEPD->uiRetryTimeout) ? 0 : pEPD->uiRetryTimeout - tDelay; // Calc time remaining for frame
  857. DPFX(DPFPREP,7, "(%p) Setting Retry Timer for %dms on Seq=[%x], FMD=[%p]", pEPD, tDelay, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  858. ASSERT(ack);
  859. LOCK_EPD(pEPD, "LOCK (retry timer)"); // bump RefCnt for timer
  860. SetMyTimer(tDelay, 0, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique );
  861. pFMD->ulFFlags |= FFLAGS_RETRY_TIMER_SET;
  862. }
  863. // See if we need to unblock this session
  864. if((pEPD->uiUnackedFrames < pEPD->uiWindowF) && (pEPD->uiUnackedBytes < pEPD->uiWindowB))
  865. {
  866. pEPD->ulEPFlags |= EPFLAGS_STREAM_UNBLOCKED;
  867. if((pEPD->ulEPFlags & EPFLAGS_SDATA_READY) && ((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0))
  868. {
  869. DPFX(DPFPREP,7, "(%p) UpdateXmit: ReEntering Pipeline", pEPD);
  870. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  871. LOCK_EPD(pEPD, "LOCK (pipeline)");
  872. ScheduleTimerThread(ScheduledSend, pEPD, &pEPD->SendTimer, &pEPD->SendTimerUnique);
  873. }
  874. }
  875. }
  876. /*
  877. ** Complete Datagram Frame
  878. **
  879. ** A datagram frame has been successfully transmitted. Free the descriptor and
  880. ** see if the entire send is ready to complete. Reliable sends are not freed until
  881. ** they are acknowledged, so they must be handled elsewhere.
  882. **
  883. ** ** This is called with the CommandLock in MSD held, returns with it released **
  884. */
  885. #undef DPF_MODNAME
  886. #define DPF_MODNAME "CompleteDatagramSend"
  887. VOID CompleteDatagramSend(PSPD pSPD, PMSD pMSD, HRESULT hr)
  888. {
  889. PEPD pEPD = pMSD->pEPD;
  890. ASSERT_EPD(pEPD);
  891. ASSERT(pMSD->blFrameList.IsEmpty()); // Was this the last frame in the message?
  892. ASSERT(pMSD->uiFrameCount == 0);
  893. ASSERT((pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED)==0);
  894. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  895. Lock(&pEPD->EPLock); // Need EPLock to change MFLAGS_TWO
  896. DPFX(DPFPREP,7, "(%p) DG MESSAGE COMPLETE pMSD=%p", pEPD, pMSD);
  897. pMSD->ulMsgFlags2 |= MFLAGS_TWO_SEND_COMPLETE; // Mark this complete
  898. if(pMSD->TimeoutTimer != NULL)
  899. {
  900. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer", pEPD);
  901. if(CancelMyTimer(pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  902. {
  903. DECREMENT_MSD(pMSD, "Send Timeout Timer");
  904. }
  905. else
  906. {
  907. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer Failed", pEPD);
  908. }
  909. pMSD->TimeoutTimer = NULL;
  910. }
  911. #ifdef DEBUG
  912. Lock(&pSPD->SPLock);
  913. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  914. {
  915. pMSD->blSPLinkage.RemoveFromList(); // Remove MSD from master command list
  916. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  917. }
  918. Unlock(&pSPD->SPLock);
  919. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  920. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  921. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  922. #endif
  923. if(hr == DPNERR_USERCANCEL)
  924. {
  925. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_TIMEDOUT)
  926. {
  927. hr = DPNERR_TIMEDOUT;
  928. }
  929. }
  930. pMSD->blQLinkage.RemoveFromList(); // Remove from CompleteSendQueue
  931. Unlock(&pEPD->EPLock);
  932. Unlock(&pMSD->CommandLock); // Leave the lock before calling into another layer
  933. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteSend for NG, hr[%x], pMSD[%p], Core Context[%p]", pEPD, hr, pMSD, pMSD->Context);
  934. pSPD->pPData->pfVtbl->CompleteSend(pSPD->pPData->Parent, pMSD->Context, hr);
  935. // Release the final reference on the MSD AFTER indicating to the Core
  936. Lock(&pMSD->CommandLock);
  937. // Cancels are allowed to come in until the Completion has returned and they will expect a valid pMSD->pEPD
  938. Lock(&pEPD->EPLock);
  939. pMSD->pEPD = NULL; // We shouldn't be using this after this
  940. RELEASE_EPD(pEPD, "UNLOCK (Complete Send Cmd - DG)"); // Every send command bumps the refcnt, releases EPLock
  941. RELEASE_MSD(pMSD, "Release On Complete"); // Return resources, including all frames, release MSDLock
  942. }
  943. /*
  944. ** Complete Reliable Send
  945. **
  946. ** A reliable send has completed processing. Indicate this
  947. ** to the user and free the resources. This will either take
  948. ** place on a cancel, error, or when ALL of the message's frames
  949. ** have been acknowledged.
  950. **
  951. ** ** This is called with CommandLock in MSD held, and exits with it released **
  952. */
  953. #undef DPF_MODNAME
  954. #define DPF_MODNAME "CompleteReliableSend"
  955. VOID
  956. CompleteReliableSend(PSPD pSPD, PMSD pMSD, HRESULT hr)
  957. {
  958. PEPD pEPD = pMSD->pEPD;
  959. ASSERT_EPD(pEPD);
  960. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  961. ASSERT(pMSD->uiFrameCount == 0);
  962. // NORMAL SEND COMPLETES
  963. if(pMSD->CommandID == COMMAND_ID_SEND_RELIABLE)
  964. {
  965. DPFX(DPFPREP,7, "(%p) Reliable Send Complete pMSD=%p", pEPD, pMSD);
  966. ASSERT((pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED)==0);
  967. if(pMSD->TimeoutTimer != NULL)
  968. {
  969. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer, pMSD[%p]", pEPD, pMSD);
  970. if(CancelMyTimer(pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  971. {
  972. DECREMENT_MSD(pMSD, "Send Timeout Timer");
  973. }
  974. else
  975. {
  976. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer Failed, pMSD[%p]", pEPD, pMSD);
  977. }
  978. pMSD->TimeoutTimer = NULL;
  979. }
  980. // ACK code in UpdateXmitState flags this as COMPLETE when the last of the message is received.
  981. #ifdef DEBUG
  982. Lock(&pSPD->SPLock);
  983. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  984. {
  985. pMSD->blSPLinkage.RemoveFromList(); // Remove MSD from master command list
  986. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  987. }
  988. Unlock(&pSPD->SPLock);
  989. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  990. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  991. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  992. #endif
  993. Unlock(&pMSD->CommandLock); // Leave the lock before calling into another layer
  994. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteSend for G, hr[%x], pMSD[%p], Core Context[%p]", pEPD, hr, pMSD, pMSD->Context);
  995. pSPD->pPData->pfVtbl->CompleteSend(pSPD->pPData->Parent, pMSD->Context, hr);
  996. // Release the final reference on the MSD AFTER indicating to the Core
  997. Lock(&pMSD->CommandLock);
  998. // Cancels are allowed to come in until the Completion has returned and they will expect a valid pMSD->pEPD
  999. Lock(&pEPD->EPLock);
  1000. pMSD->pEPD = NULL; // We shouldn't be using this after this
  1001. RELEASE_EPD(pEPD, "UNLOCK (Complete Send Cmd - Rely)"); // release hold on EPD for this send, releases EPLock
  1002. RELEASE_MSD(pMSD, "Release On Complete"); // Return resources, including all frames
  1003. }
  1004. // END OF STREAM -OR- KEEPALIVE COMPLETES
  1005. else
  1006. {
  1007. // Partner has just ACKed our End Of Stream frame. Doesn't necessarily mean we are done.
  1008. // Both sides need to send (and have acknowledged) EOS frames before the link can be
  1009. // dropped. Therefore, we check to see if we have seen our partner's DISC before
  1010. // releasing the RefCnt on EPD allowing the link to drop. If partner was idle, his EOS
  1011. // might be the same frame which just ack'd us. Luckily, this code will run first so we
  1012. // will not have noticed his EOS yet, and we will not drop right here.
  1013. ASSERT(pMSD->ulMsgFlags2 & (MFLAGS_TWO_END_OF_STREAM | MFLAGS_TWO_KEEPALIVE));
  1014. Lock(&pEPD->EPLock);
  1015. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_KEEPALIVE)
  1016. {
  1017. DPFX(DPFPREP,7, "(%p) Keepalive Complete, pMSD[%p]", pEPD, pMSD);
  1018. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  1019. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST));
  1020. pMSD->pEPD = NULL; // We shouldn't be using this after this
  1021. RELEASE_EPD(pEPD, "UNLOCK (rel KeepAlive)"); // Release ref for this MSD, releases EPLock
  1022. RELEASE_MSD(pMSD, "Release On Complete"); // Done with this message
  1023. }
  1024. else
  1025. {
  1026. DPFX(DPFPREP,7, "(%p) EndOfStream Complete, pMSD[%p]", pEPD, pMSD);
  1027. pEPD->ulEPFlags |= EPFLAGS_DISCONNECT_ACKED;
  1028. if(pEPD->ulEPFlags & EPFLAGS_ACKED_DISCONNECT)
  1029. {
  1030. DPFX(DPFPREP,7, "(%p) EOS has been ACK'd and we've ACK'd partner's EOS, dropping link", pEPD);
  1031. // We are clear to blow this thing down
  1032. Unlock(&pMSD->CommandLock);
  1033. // This will set our state to terminating
  1034. DropLink(pEPD); // This unlocks the EPLock
  1035. }
  1036. else
  1037. {
  1038. // Our Disconnect frame has been acknowledged but we must wait until we see his DISC before
  1039. // completing this command and dropping the connection.
  1040. //
  1041. // We will use the pCommand pointer to track this disconnect command until we see partner's DISC frame
  1042. //
  1043. // ALSO, since our engine has now shutdown, we might wait forever now for the final DISC from partner
  1044. // if he crashes before transmitting it. One final safeguard here is to set a timer which will make sure
  1045. // this doesnt happen. * NOTE * no timer is actually being set here, we're depending on the keepalive
  1046. // timeout, see EndPointBackgroundProcess.
  1047. DPFX(DPFPREP,7, "(%p) EOS has been ACK'd, but we're still ACK'ing partner's disconnect", pEPD);
  1048. ASSERT(pEPD->blHighPriSendQ.IsEmpty());
  1049. ASSERT(pEPD->blNormPriSendQ.IsEmpty());
  1050. ASSERT(pEPD->blLowPriSendQ.IsEmpty());
  1051. // It is possible that something was already in the process of timing out when the disconnect
  1052. // operation starts such that AbortSends gets called and clears this.
  1053. ASSERT(pEPD->pCommand == NULL || pEPD->pCommand == pMSD);
  1054. Unlock(&pEPD->EPLock);
  1055. Unlock(&pMSD->CommandLock);
  1056. }
  1057. }
  1058. }
  1059. }
  1060. /*
  1061. ** Build Data Frame
  1062. **
  1063. ** Setup the actual network packet header for transmission with our current link state info (Seq, NRcv).
  1064. **
  1065. ** ** ENTERED AND EXITS WITH EPD->EPLOCK HELD **
  1066. */
  1067. #undef DPF_MODNAME
  1068. #define DPF_MODNAME "BuildDataFrame"
  1069. VOID BuildDataFrame(PEPD pEPD, PFMD pFMD, DWORD tNow)
  1070. {
  1071. PDFBIG pFrame;
  1072. UINT index = 0;
  1073. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1074. pFrame = (PDFBIG) pFMD->ImmediateData;
  1075. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt;
  1076. pFMD->uiRetry = 0;
  1077. pFrame->bCommand = pFMD->bPacketFlags;
  1078. pFrame->bControl = 0; // this sets retry count to zero as well as clearing flags
  1079. if (pFMD->ulFFlags & FFLAGS_END_OF_STREAM)
  1080. {
  1081. pFrame->bControl |= (PACKET_CONTROL_END_STREAM | PACKET_CONTROL_CORRELATE);
  1082. }
  1083. // See if we are desiring an immediate response
  1084. if(pFMD->ulFFlags & FFLAGS_CHECKPOINT)
  1085. {
  1086. pFrame->bCommand |= PACKET_COMMAND_POLL;
  1087. }
  1088. pFrame->bSeq = pEPD->bNextSend++;
  1089. pFrame->bNRcv = pEPD->bNextReceive; // Acknowledges all previous frames
  1090. DPFX(DPFPREP,7, "(%p) N(S) incremented to %x", pEPD, pEPD->bNextSend);
  1091. // Piggyback NACK notes
  1092. //
  1093. // Since the SP is now frequently mis-ordering frames we are enforcing a back-off period before transmitting a NACK after
  1094. // a packet is received out of order. Therefore we have the Delayed Mask Timer which stalls the dedicated NACK. Now we must
  1095. // also make sure that the new NACK info doesn't get piggybacked too soon. Therefore we will test the tReceiveMaskDelta timestamp
  1096. // before including piggyback NACK info here, and make sure that the mask is at least 5ms old.
  1097. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  1098. {
  1099. if((tNow - pEPD->tReceiveMaskDelta) > 4)
  1100. {
  1101. DPFX(DPFPREP,7, "(%p) Installing NACK in DFRAME Seq=%x, NRcv=%x Low=%x High=%x", pEPD, pFrame->bSeq, pFrame->bNRcv, pEPD->ulReceiveMask, pEPD->ulReceiveMask2);
  1102. if(pEPD->ulReceiveMask)
  1103. {
  1104. pFrame->rgMask[index++] = pEPD->ulReceiveMask;
  1105. pFrame->bControl |= PACKET_CONTROL_SACK_MASK1;
  1106. }
  1107. if(pEPD->ulReceiveMask2)
  1108. {
  1109. pFrame->rgMask[index++] = pEPD->ulReceiveMask2;
  1110. pFrame->bControl |= PACKET_CONTROL_SACK_MASK2;
  1111. }
  1112. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  1113. }
  1114. else
  1115. {
  1116. DPFX(DPFPREP,7, "(%p) DECLINING TO PIGGYBACK NACK WITH SMALL TIME DELTA", pEPD);
  1117. }
  1118. }
  1119. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)
  1120. {
  1121. DPFX(DPFPREP,7, "(%p) Installing SENDMASK in DFRAME Seq=%x, Low=%x High=%x", pEPD, pFrame->bSeq, pEPD->ulSendMask, pEPD->ulSendMask2);
  1122. if(pEPD->ulSendMask)
  1123. {
  1124. pFrame->rgMask[index++] = pEPD->ulSendMask;
  1125. pFrame->bControl |= PACKET_CONTROL_SEND_MASK1;
  1126. pEPD->ulSendMask = 0;
  1127. }
  1128. if(pEPD->ulSendMask2)
  1129. {
  1130. pFrame->rgMask[index++] = pEPD->ulSendMask2;
  1131. pFrame->bControl |= PACKET_CONTROL_SEND_MASK2;
  1132. pEPD->ulSendMask2 = 0;
  1133. }
  1134. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_SENDMASK);
  1135. }
  1136. pFMD->uiImmediateLength = sizeof(DFRAME) + (index * sizeof(ULONG));
  1137. pFMD->tTimestamp[0] = tNow;
  1138. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  1139. // Stop delayed mask timer
  1140. if((pEPD->DelayedMaskTimer != 0)&&((pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)==0))
  1141. {
  1142. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  1143. if(CancelMyTimer(pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  1144. {
  1145. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMaskTimer)"); // SPLock not already held
  1146. pEPD->DelayedMaskTimer = 0;
  1147. }
  1148. else
  1149. {
  1150. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  1151. }
  1152. }
  1153. // Stop delayed ack timer
  1154. if(pEPD->DelayedAckTimer != 0)
  1155. {
  1156. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1157. if(CancelMyTimer(pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  1158. {
  1159. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAckTimer)"); // SPLock not already held
  1160. pEPD->DelayedAckTimer = 0;
  1161. }
  1162. else
  1163. {
  1164. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1165. }
  1166. }
  1167. pFMD->uiFrameLength += pFMD->uiImmediateLength;
  1168. }
  1169. /*
  1170. ** Build Retry Frame
  1171. **
  1172. ** Reinitialize those fields in the packet header that need to be recalculated for a retransmission.
  1173. */
  1174. #undef DPF_MODNAME
  1175. #define DPF_MODNAME "BuildRetryFrame"
  1176. VOID
  1177. BuildRetryFrame(PEPD pEPD, PFMD pFMD)
  1178. {
  1179. PDFMASKS pMasks;
  1180. UINT index = 0;
  1181. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1182. ((PDFRAME) pFMD->ImmediateData)->bNRcv = pEPD->bNextReceive; // Use up-to-date ACK info
  1183. ((PDFRAME) pFMD->ImmediateData)->bControl &= PACKET_CONTROL_END_STREAM; // Preserve EOS bit from original
  1184. ((PDFRAME) pFMD->ImmediateData)->bControl |= PACKET_CONTROL_RETRY; // clamp retry value at size of field in packet
  1185. pMasks = (PDFMASKS) (pFMD->ImmediateData + sizeof(DFRAME)); // pointer to mask space after protocol header
  1186. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  1187. {
  1188. if(pEPD->ulReceiveMask)
  1189. {
  1190. pMasks->rgMask[index++] = pEPD->ulReceiveMask;
  1191. ((PDFRAME) pFMD->ImmediateData)->bControl |= PACKET_CONTROL_SACK_MASK1;
  1192. }
  1193. if(pEPD->ulReceiveMask2)
  1194. {
  1195. pMasks->rgMask[index++] = pEPD->ulReceiveMask2;
  1196. ((PDFRAME) pFMD->ImmediateData)->bControl |= PACKET_CONTROL_SACK_MASK2;
  1197. }
  1198. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  1199. }
  1200. // MUST NOT transmit the SendMasks with a retry because they are based on the CURRENT bNextSend value which is not
  1201. // the N(S) that appears in this frame. We could theoretically shift the mask to agree with this frame's sequence
  1202. // number, but that might shift relevent bits out of the mask. Best thing to do is to let the next in-order send carry
  1203. // the bit-mask or else wait for the timer to fire and send a dedicated packet.
  1204. // PLEASE NOTE -- Although we may change the size of the immediate data below we did not update the FMD->uiFrameLength
  1205. // field. This field is used to credit the send window when the frame is acknowledged, and we would be wise to credit
  1206. // the same value that we debited back when this frame was first sent. We could adjust the debt now to reflect the new
  1207. // size of the frame, but seriously, why bother?
  1208. pFMD->uiImmediateLength = sizeof(DFRAME) + (index * 4);
  1209. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  1210. // Stop delayed ack timer
  1211. if(pEPD->DelayedAckTimer != 0)
  1212. {
  1213. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1214. if(CancelMyTimer(pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  1215. {
  1216. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAckTimer)");
  1217. pEPD->DelayedAckTimer = 0;
  1218. }
  1219. else
  1220. {
  1221. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1222. }
  1223. }
  1224. // Stop delayed mask timer
  1225. if(((pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)==0)&&(pEPD->DelayedMaskTimer != 0))
  1226. {
  1227. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  1228. if(CancelMyTimer(pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  1229. {
  1230. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMaskTimer)"); // SPLock not already held
  1231. pEPD->DelayedMaskTimer = 0;
  1232. }
  1233. else
  1234. {
  1235. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  1236. }
  1237. }
  1238. }
  1239. /*
  1240. ** Service Command Traffic
  1241. **
  1242. ** Presently this transmits all CFrames and Datagrams queued to the specific
  1243. ** Service Provider. We may want to split out the datagrams from this so that
  1244. ** C frames can be given increased send priority but not datagrams. With this
  1245. ** implementation DGs will get inserted into reliable streams along with Cframes.
  1246. ** This may or may not be what we want to do...
  1247. **
  1248. ** WE ENTER AND EXIT WITH SPD->SENDLOCK HELD, although we release it during actual
  1249. ** calls to the SP.
  1250. */
  1251. #undef DPF_MODNAME
  1252. #define DPF_MODNAME "ServiceCmdTraffic"
  1253. VOID ServiceCmdTraffic(PSPD pSPD)
  1254. {
  1255. CBilink *pFLink;
  1256. PFMD pFMD;
  1257. HRESULT hr;
  1258. AssertCriticalSectionIsTakenByThisThread(&pSPD->SPLock, TRUE);
  1259. // WHILE there are frames ready to send
  1260. while((pFLink = pSPD->blSendQueue.GetNext()) != &pSPD->blSendQueue)
  1261. {
  1262. pFLink->RemoveFromList(); // Remove frame from queue
  1263. pFMD = CONTAINING_RECORD(pFLink, FMD, blQLinkage); // get ptr to frame structure
  1264. ASSERT_FMD(pFMD);
  1265. // Place frame on pending queue before making call in case it completes really fast
  1266. ASSERT(!pFMD->bSubmitted);
  1267. pFMD->bSubmitted = TRUE;
  1268. ASSERT(pFMD->blQLinkage.IsEmpty());
  1269. pFMD->blQLinkage.InsertBefore( &pSPD->blPendingQueue); // Place frame on pending queue
  1270. Unlock(&pSPD->SPLock);
  1271. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->SendData for FMD[%p], pSPD[%p]", pFMD->pEPD, pFMD, pSPD);
  1272. /*send*/if((hr = IDP8ServiceProvider_SendData(pSPD->IISPIntf, &pFMD->SendDataBlock)) != DPNERR_PENDING)
  1273. {
  1274. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling our own CommandComplete since SP did not return DPNERR_PENDING - hr[%x], pSPD[%p]", pFMD->pEPD, hr, pSPD);
  1275. (void) DNSP_CommandComplete((IDP8SPCallback *) pSPD, NULL, hr, (PVOID) pFMD);
  1276. }
  1277. Lock(&pSPD->SPLock);
  1278. } // While SENDs are on QUEUE
  1279. }
  1280. /*
  1281. ** Run Send Thread
  1282. **
  1283. ** There is work for this SP's send thread. Keep running until
  1284. ** there is no more work to do.
  1285. **
  1286. ** Who gets first priority, DG or Seq traffic? I will say DG b/c its
  1287. ** advertised as lowest overhead...
  1288. **
  1289. ** Datagram packets get Queued on the SP when they are ready to ship.
  1290. ** Reliable packets are queued on the EPD. Therefore, we will queue the
  1291. ** actual EPD on the SPD when they have reliable traffic to send, and then
  1292. ** we will service individual EPDs from this loop.
  1293. */
  1294. #undef DPF_MODNAME
  1295. #define DPF_MODNAME "RunSendThread"
  1296. VOID RunSendThread(PVOID uID, UINT Unique, PVOID pvUser)
  1297. {
  1298. PSPD pSPD = (PSPD) pvUser;
  1299. ASSERT_SPD(pSPD);
  1300. DPFX(DPFPREP,7, "Send Thread Runs pSPD[%p]", pSPD);
  1301. Lock(&pSPD->SPLock);
  1302. if(!pSPD->blSendQueue.IsEmpty())
  1303. {
  1304. ServiceCmdTraffic(pSPD);
  1305. }
  1306. pSPD->ulSPFlags &= ~(SPFLAGS_SEND_THREAD_SCHEDULED);
  1307. pSPD->SendHandle = NULL;
  1308. Unlock(&pSPD->SPLock);
  1309. }
  1310. /*
  1311. ** Scheduled Send
  1312. **
  1313. ** If this EPD is still unentitled to send, start draining frames. Otherwise transition
  1314. ** link to IDLE state.
  1315. */
  1316. #undef DPF_MODNAME
  1317. #define DPF_MODNAME "ScheduledSend"
  1318. VOID CALLBACK
  1319. ScheduledSend(PVOID uID, UINT Unique, PVOID dwUser)
  1320. {
  1321. PEPD pEPD = (PEPD) dwUser;
  1322. PSPD pSPD = pEPD->pSPD;
  1323. ASSERT_EPD(pEPD);
  1324. ASSERT_SPD(pSPD);
  1325. Lock(&pEPD->EPLock);
  1326. pEPD->SendTimer = 0;
  1327. DPFX(DPFPREP,7, "(%p) Scheduled Send Fires", pEPD);
  1328. ASSERT(pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE);
  1329. // Test that all three flags are set before starting to transmit
  1330. if( (pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) && (
  1331. ((pEPD->ulEPFlags & (EPFLAGS_STREAM_UNBLOCKED | EPFLAGS_SDATA_READY)) == (EPFLAGS_STREAM_UNBLOCKED | EPFLAGS_SDATA_READY))
  1332. || (pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED)))
  1333. {
  1334. ServiceEPD(pEPD->pSPD, pEPD); // releases EPLock
  1335. }
  1336. else
  1337. {
  1338. DPFX(DPFPREP,7, "(%p) Session leaving pipeline", pEPD);
  1339. pEPD->ulEPFlags &= ~(EPFLAGS_IN_PIPELINE);
  1340. RELEASE_EPD(pEPD, "UNLOCK (leaving pipeline, SchedSend done)"); // releases EPLock
  1341. }
  1342. }
  1343. /*
  1344. ** Service EndPointDescriptor
  1345. **
  1346. ** This includes reliable, datagram, and re-transmit
  1347. ** frames. Retransmissions are ALWAYS transmitted first, regardless of the orginal message's
  1348. ** priority. After that datagrams and reliable messages are taken in priority order, in FIFO
  1349. ** order within a priority class.
  1350. **
  1351. ** The number of frames drained depends upon the measured link speed. If the burst gap is
  1352. ** larger then 10ms we will only send one frame, and then scale down the burst gap according
  1353. ** to the fraction of the available byte-window that was used.
  1354. **
  1355. ** CODEWORK-> if they send < 1/8th of the burst allowance, maybe let them send another frame
  1356. **
  1357. ** If the burst gap is small (<10ms) then we will routinely allow multiple sends per burst.
  1358. ** If the burst is not filled precisely we can remember the difference and either credit or debit
  1359. ** the next burst accordingly. Now, we dont want to credit too much or we start to mess up the
  1360. ** throttle concept of spreading out the load. But we can still debit for overloads. Here is
  1361. ** what we'd like to do: If we have almost filled the burst, do not send another max size frame
  1362. ** and create a really big debit. Instead, credit the leftover and maybe an extra will fit next time.
  1363. ** Otherwise, allow us to send into debt (say up to 25% over).
  1364. **
  1365. **
  1366. ** If the pipeline goes idle or the stream gets blocked will we still schedule the next
  1367. ** send. This way if we unblock or un-idle before the gap has expired we will not get to cheat
  1368. ** and defeat the gap. The shell routine above us (ScheduledSend) will take care of removing us
  1369. ** from the pipeline if the next burst gets scheduled and we are still not ready to send.
  1370. **
  1371. **
  1372. ** ** CALLED WITH EPD->EPLock HELD; Returns with EPLock RELEASED **
  1373. */
  1374. #undef DPF_MODNAME
  1375. #define DPF_MODNAME "ServiceEPD"
  1376. VOID ServiceEPD(PSPD pSPD, PEPD pEPD)
  1377. {
  1378. PMSD pMSD;
  1379. PFMD pFMD;
  1380. CBilink *pLink, *pFLink;
  1381. INT iBurstAvail;
  1382. INT iBurstSent = 0;
  1383. INT iDelta;
  1384. INT iHalf, iQuarter, iEighth;
  1385. UINT uiFramesSent = 0;
  1386. UINT uiUseBurstGap;
  1387. HRESULT hr;
  1388. DWORD tNow = GETTIMESTAMP();
  1389. /*
  1390. ** Now we will drain reliable traffic from EPDs on the pipeline list
  1391. */
  1392. // The caller should have checked this
  1393. ASSERT( pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED );
  1394. // Burst Credit can either be positive or negative depending upon how much of our last transmit slice we used
  1395. if(pEPD->uiBurstGap == 0)
  1396. {
  1397. iBurstAvail = 0x7FFFFFFF; // If no packet gap enforced, allow unlimited transmission
  1398. uiUseBurstGap = 0;
  1399. DPFX(DPFPREP,7, "(%p) BEGIN UNLIMITED BURST", pEPD);
  1400. }
  1401. else
  1402. {
  1403. iBurstAvail = pSPD->uiFrameLength + pEPD->iBurstCredit;
  1404. uiUseBurstGap = pEPD->uiBurstGap;
  1405. DPFX(DPFPREP,7, "(%p) BEGIN CONTROLLED BURST: Gap(%d) %d bytes avail (%d Size; %d credit)", pEPD, uiUseBurstGap, iBurstAvail, pSPD->uiFrameLength, pEPD->iBurstCredit);
  1406. }
  1407. // Transmit a burst from this EPD, as long as its unblocked and has data ready. We do not re-init
  1408. // burst counter since any retries sent count against our burst limit
  1409. //
  1410. // This has become more complex now that we are interleaving datagrams and reliable frames. There are two
  1411. // sets of priority-based send queues. The first is combined DG and Reliable and the second is datagram only.
  1412. // when the reliable stream is blocked we will feed from the DG only queues, otherwise we will take from the
  1413. // interleaved queue.
  1414. // This is further complicated by the possibility that a reliable frame can be partially transmitted at any time.
  1415. // So before looking at the interleaved queues we must check for a partially completed reliable send (EPD.pCurrentSend).
  1416. //
  1417. // ** pEPD->EPLock is held **
  1418. while( (((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED) && (pEPD->ulEPFlags & EPFLAGS_SDATA_READY))
  1419. || (pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED))
  1420. && (iBurstSent < iBurstAvail))
  1421. {
  1422. // When burstsize is large we will decrease the next burst gap instead of sending additional
  1423. // frames to fill the burst.
  1424. if((pEPD->uiBurstGap > 10) && (uiFramesSent > 0))
  1425. {
  1426. DPFX(DPFPREP,7, "(%p) Burst Gap is large", pEPD);
  1427. // BurstGap is large enough that we can subdivide it to credit the balance of this burst
  1428. break;
  1429. }
  1430. // Always give preference to shipping retries before new data
  1431. if(pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED)
  1432. {
  1433. pFMD = CONTAINING_RECORD(pEPD->blRetryQueue.GetNext(), FMD, blQLinkage);
  1434. ASSERT_FMD(pFMD);
  1435. pFMD->blQLinkage.RemoveFromList();
  1436. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  1437. if(pEPD->blRetryQueue.IsEmpty())
  1438. {
  1439. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  1440. }
  1441. // pMSD->uiFrameCount will be decremented when this completes
  1442. BuildRetryFrame(pEPD, pFMD); // Place currect state information in retry frame
  1443. DPFX(DPFPREP,7, "(%p) Shipping RETRY frame: Seq=%x, FMD=%p Size=%d", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD, pFMD->uiFrameLength);
  1444. iBurstSent += pFMD->uiFrameLength;
  1445. uiFramesSent++;
  1446. }
  1447. else
  1448. {
  1449. if((pMSD = pEPD->pCurrentSend) != NULL)
  1450. {
  1451. ASSERT_MSD(pMSD);
  1452. pFMD = pEPD->pCurrentFrame; // Get the next frame due to send
  1453. ASSERT_FMD(pFMD);
  1454. ASSERT((pFMD->ulFFlags & FFLAGS_TRANSMITTED)==0);
  1455. }
  1456. else
  1457. {
  1458. if( (pLink = pEPD->blHighPriSendQ.GetNext()) == &pEPD->blHighPriSendQ)
  1459. {
  1460. if( (pLink = pEPD->blNormPriSendQ.GetNext()) == &pEPD->blNormPriSendQ)
  1461. {
  1462. if( (pLink = pEPD->blLowPriSendQ.GetNext()) == &pEPD->blLowPriSendQ)
  1463. {
  1464. break; // All finished sending for now
  1465. }
  1466. }
  1467. }
  1468. pMSD = CONTAINING_RECORD(pLink, MSD, blQLinkage);
  1469. ASSERT_MSD(pMSD);
  1470. #ifdef DEBUG
  1471. ASSERT(pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED);
  1472. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  1473. #endif
  1474. pMSD->blQLinkage.RemoveFromList();
  1475. ASSERT(pEPD->uiQueuedMessageCount > 0);
  1476. --pEPD->uiQueuedMessageCount; // keep count of MSDs on all send queues
  1477. pMSD->ulMsgFlags2 |= MFLAGS_TWO_TRANSMITTING; // We have begun to transmit frames from this Msg
  1478. pEPD->pCurrentSend = pMSD;
  1479. pFMD = pEPD->pCurrentFrame = CONTAINING_RECORD(pMSD->blFrameList.GetNext(), FMD, blMSDLinkage);
  1480. ASSERT_FMD(pFMD);
  1481. ASSERT((pFMD->ulFFlags & FFLAGS_TRANSMITTED)==0);
  1482. pFMD->bPacketFlags |= PACKET_COMMAND_NEW_MSG;
  1483. pMSD->blQLinkage.InsertBefore( &pEPD->blCompleteSendList); // Place this on PendingList now so we can keep track of it
  1484. }
  1485. BuildDataFrame(pEPD, pFMD, tNow); // place current state info in frame
  1486. pFMD->blWindowLinkage.InsertBefore( &pEPD->blSendWindow); // Place at trailing end of send window
  1487. pFMD->ulFFlags |= FFLAGS_IN_SEND_WINDOW;
  1488. LOCK_FMD(pFMD, "Send Window"); // Add reference for send window
  1489. pEPD->uiUnackedBytes += pFMD->uiFrameLength; // Track the unacknowleged bytes in the pipeline
  1490. // We can always go over the limit, but will be blocked until we drop below the limit again.
  1491. if(pEPD->uiUnackedBytes >= pEPD->uiWindowB)
  1492. {
  1493. pEPD->ulEPFlags &= ~(EPFLAGS_STREAM_UNBLOCKED);
  1494. pEPD->ulEPFlags |= EPFLAGS_FILLED_WINDOW_BYTE; // Tells us to increase window if all is well
  1495. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL; // Request immediate reply
  1496. }
  1497. // Count frames in the send window
  1498. if((++pEPD->uiUnackedFrames) >= pEPD->uiWindowF)
  1499. {
  1500. pEPD->ulEPFlags &= ~(EPFLAGS_STREAM_UNBLOCKED);
  1501. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL; // Request immediate reply
  1502. pEPD->ulEPFlags |= EPFLAGS_FILLED_WINDOW_FRAME; // Tells us to increase window if all is well
  1503. }
  1504. // We will only run one retry timer for each EndPt. If we already have one running then do nothing.
  1505. // If there was already a frame in the pipeline it should already have a clock running
  1506. if(pEPD->uiUnackedFrames == 1)
  1507. {
  1508. ASSERT(pEPD->RetryTimer == 0);
  1509. pFMD->ulFFlags |= FFLAGS_RETRY_TIMER_SET; // This one is being measured
  1510. LOCK_EPD(pEPD, "LOCK (set retry timer)"); // bump RefCnt for timer
  1511. DPFX(DPFPREP,7, "(%p) Setting Retry Timer on Seq=0x%x, FMD=%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  1512. SetMyTimer(pEPD->uiRetryTimeout, 0, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique);
  1513. }
  1514. else
  1515. {
  1516. ASSERT(pEPD->RetryTimer != 0);
  1517. }
  1518. LOCK_EPD(pEPD, "LOCK (Send Data Frame)"); // Keep EPD around while xmitting frame
  1519. pFLink = pFMD->blMSDLinkage.GetNext(); // Get next frame in Msg
  1520. // Was this the last frame in Msg?
  1521. if(pFLink == &pMSD->blFrameList)
  1522. {
  1523. // Last frame in message has been sent.
  1524. //
  1525. // We used to setup the next frame now, but with the multi-priority queues it makes more sense to look for the
  1526. // highest priority send when we are ready to send it.
  1527. pEPD->pCurrentSend = NULL;
  1528. pEPD->pCurrentFrame = NULL;
  1529. // When completing a send, set the POLL flag if there are no more sends on the queue
  1530. // Request immediate reply if no more data to send
  1531. if(pEPD->uiQueuedMessageCount == 0)
  1532. {
  1533. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL;
  1534. }
  1535. }
  1536. else
  1537. {
  1538. pEPD->pCurrentFrame = CONTAINING_RECORD(pFLink, FMD, blMSDLinkage);
  1539. ASSERT_FMD(pEPD->pCurrentFrame);
  1540. }
  1541. DPFX(DPFPREP,7, "(%p) Shipping Dataframe: Seq=%x, NRcv=%x FMD=%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, ((PDFRAME) pFMD->ImmediateData)->bNRcv, pFMD);
  1542. uiFramesSent++; // Count frames sent this burst
  1543. iBurstSent += pFMD->uiFrameLength;
  1544. // KEEPING DETAILED STATS REQUIRES EXTRA CONDITIONAL
  1545. if(pFMD->ulFFlags & FFLAGS_RELIABLE)
  1546. {
  1547. pEPD->uiGuaranteedFramesSent++;
  1548. pEPD->uiGuaranteedBytesSent += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  1549. }
  1550. else
  1551. {
  1552. pEPD->uiDatagramFramesSent++;
  1553. pEPD->uiDatagramBytesSent += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  1554. }
  1555. LOCK_FMD(pFMD, "SP Submit"); // Bump RefCnt when submitting Rely Sends
  1556. }
  1557. // PROCEED WITH TRANSMISSION...
  1558. Lock(&pSPD->SPLock);
  1559. ASSERT(!pFMD->bSubmitted);
  1560. pFMD->ulFFlags |= FFLAGS_TRANSMITTED; // Frame will be owned by SP
  1561. pFMD->bSubmitted = TRUE;
  1562. ASSERT(pFMD->blQLinkage.IsEmpty());
  1563. pFMD->blQLinkage.InsertBefore( &pSPD->blPendingQueue); // Place frame on pending queue
  1564. Unlock(&pSPD->SPLock);
  1565. // bSubmitted must not be set to true for a data frame without the EPLock being held, because
  1566. // the retry logic will be checking bSubmitted with only the EPLock held.
  1567. Unlock(&pEPD->EPLock);
  1568. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->SendData for FMD[%p]", pEPD, pFMD);
  1569. /*send*/if((hr = IDP8ServiceProvider_SendData(pSPD->IISPIntf, &pFMD->SendDataBlock)) != DPNERR_PENDING)
  1570. {
  1571. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling our own CommandComplete since SP did not return DPNERR_PENDING", pEPD);
  1572. (void) DNSP_CommandComplete((IDP8SPCallback *) pSPD, NULL, hr, (PVOID) pFMD);
  1573. }
  1574. Lock(&pEPD->EPLock);
  1575. } // WHILE (unblocked, undrained, & bandwidth credit avail)
  1576. if((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED)==0)
  1577. {
  1578. pEPD->uiWindowFilled++; // Count the times we filled the window
  1579. }
  1580. // Clear data-ready flag if everything is sent
  1581. if((pEPD->uiQueuedMessageCount == 0) && (pEPD->pCurrentSend == NULL))
  1582. {
  1583. pEPD->ulEPFlags &= ~(EPFLAGS_SDATA_READY);
  1584. }
  1585. // Determine how much of our transmit allowance we used and either credit or debit our next cycle.
  1586. // However, if we are only crediting one send/burst then we can modify the Gap instead
  1587. iDelta = iBurstAvail - iBurstSent; // Did we send too much or too little
  1588. if(pEPD->uiBurstGap > 10)
  1589. {
  1590. if(iDelta > 0)
  1591. {
  1592. // We did not use our full burst credit to transmit. Therefore we will schedule our next burst early.
  1593. // We will aproximate this with quarters...
  1594. iHalf = iBurstAvail >> 1; // One half allocation
  1595. iQuarter = iBurstAvail >> 2; // One quarter of our allocation
  1596. iEighth = iBurstAvail >> 4; // One Eighth allocation
  1597. // binary search to find which (octile or quartile) our send load falls into
  1598. if(iBurstSent > (iHalf))
  1599. {
  1600. // used over 50% of credit
  1601. if(iBurstSent > (iQuarter + iHalf))
  1602. {
  1603. // used 75 - 100%
  1604. if(iBurstSent > (iBurstAvail - iEighth))
  1605. {
  1606. // Use Full Gap: over 88% used
  1607. }
  1608. else
  1609. {
  1610. uiUseBurstGap -= (uiUseBurstGap >> 3); // subtract 12% from gap
  1611. }
  1612. }
  1613. else
  1614. {
  1615. // used 50 - 75%
  1616. if(iBurstSent > (iHalf + iEighth))
  1617. {
  1618. uiUseBurstGap -= (uiUseBurstGap >> 2); // subtract 25% from gap
  1619. }
  1620. else
  1621. {
  1622. uiUseBurstGap -= ((uiUseBurstGap >> 2) + (uiUseBurstGap >> 3)); // subtract 33% from gap
  1623. }
  1624. }
  1625. }
  1626. else
  1627. {
  1628. // used less then 50% of send credit
  1629. if(iBurstSent > (iQuarter))
  1630. {
  1631. if(iBurstSent > (iQuarter + iEighth))
  1632. {
  1633. // used 25 - 50%
  1634. uiUseBurstGap >>= 1; // subrtact 50% from gap
  1635. }
  1636. else
  1637. {
  1638. uiUseBurstGap -= ((uiUseBurstGap >> 1) + (uiUseBurstGap >> 3)); // subtract 62%
  1639. }
  1640. }
  1641. else
  1642. {
  1643. // used 1 - 25%
  1644. if(iBurstSent > iEighth)
  1645. {
  1646. uiUseBurstGap >>= 2; // subtract 75% from gap
  1647. }
  1648. else
  1649. {
  1650. uiUseBurstGap >>= 3; // subtract 88% from gap
  1651. }
  1652. }
  1653. }
  1654. pEPD->iBurstCredit = 0;
  1655. DPFX(DPFPREP,7, "(%p) Short Burst Completed (%d bytes); Reducing gap from %d to %d", pEPD, iBurstSent, pEPD->uiBurstGap, uiUseBurstGap);
  1656. }
  1657. else if (iDelta < 0)
  1658. {
  1659. DPFX(DPFPREP,7, "(%p) Burst completed with debt of %d bytes", pEPD, iDelta);
  1660. pEPD->iBurstCredit = iDelta; // For large bursts, simply carry extra forward to next cycle
  1661. }
  1662. }
  1663. else if (iDelta < 0)
  1664. {
  1665. DPFX(DPFPREP,7, "(%p) Incurring debt of %d bytes against next burst", pEPD, iDelta);
  1666. pEPD->iBurstCredit = iDelta; // For large bursts, simply carry extra forward to next cycle
  1667. }
  1668. else
  1669. {
  1670. DPFX(DPFPREP,7, "(%p) Short burst interval, dropping left-over burst credit", pEPD);
  1671. // We will drop left-over credit when we are using short burst intervals...
  1672. pEPD->iBurstCredit = 0; // For large bursts, simply carry extra forward to next cycle
  1673. }
  1674. // As commented in procedure-header above, we will remain on the pipeline for one timer-cycle
  1675. // so that if we unblock or un-idle we will not send until the gap is fullfilled.
  1676. if((pEPD->ulEPFlags & (EPFLAGS_SDATA_READY | EPFLAGS_STREAM_UNBLOCKED)) ==
  1677. (EPFLAGS_SDATA_READY | EPFLAGS_STREAM_UNBLOCKED))
  1678. { // IF BOTH flags are set
  1679. DPFX(DPFPREP,7, "(%p) %d frame BURST COMPLETED - Sched next send in %dms, N(Seq)=%x", pEPD, uiFramesSent, uiUseBurstGap, pEPD->bNextSend);
  1680. }
  1681. else if((pEPD->ulEPFlags & EPFLAGS_SDATA_READY)==0)
  1682. {
  1683. DPFX(DPFPREP,7, "(%p) %d frame BURST COMPLETED (%d / %d)- LINK IS IDLE N(Seq)=%x", pEPD, uiFramesSent, pEPD->uiUnackedFrames, pEPD->uiWindowF, pEPD->bNextSend);
  1684. }
  1685. else
  1686. {
  1687. ASSERT((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED)==0);
  1688. DPFX(DPFPREP,7, "(%p) %d frame BURST COMPLETED (%d / %d) - STREAM BLOCKED N(Seq)=%x", pEPD, uiFramesSent, pEPD->uiUnackedFrames, pEPD->uiWindowF, pEPD->bNextSend);
  1689. }
  1690. ASSERT(pEPD->SendTimer == 0);
  1691. if(pEPD->uiBurstGap != 0)
  1692. {
  1693. DPFX(DPFPREP,7, "(%p) Setting Scheduled Send Timer for %d ms", pEPD, uiUseBurstGap);
  1694. SetMyTimer(uiUseBurstGap, 4, ScheduledSend, (PVOID) pEPD, &pEPD->SendTimer, &pEPD->SendTimerUnique);
  1695. Unlock(&pEPD->EPLock);
  1696. }
  1697. else
  1698. {
  1699. DPFX(DPFPREP,7, "(%p) Session leaving pipeline", pEPD);
  1700. pEPD->ulEPFlags &= ~(EPFLAGS_IN_PIPELINE);
  1701. RELEASE_EPD(pEPD, "UNLOCK (leaving pipeline)"); // releases EPLock
  1702. }
  1703. }
  1704. /*
  1705. ** Retry Timeout
  1706. **
  1707. ** Retry timer fires when we have not seen an acknowledgement for a packet
  1708. ** we sent in more then twice (actually 1.25 X) our measured RTT. Actually, that is
  1709. ** just our base calculation. We will also measure empirical ACK times and adjust our timeout
  1710. ** to some multiple of that. Remember that our partner may be delaying his Acks to wait for back-traffic.
  1711. **
  1712. ** Or we can measure avg deviation of Tack and base retry timer on that.
  1713. **
  1714. ** In any case, its time to re-transmit the base frame in our send window...
  1715. **
  1716. ** Important note: Since we can generate retries via bitmask in return traffic, it is possible that
  1717. ** we have just retried when the timer fires.
  1718. **
  1719. ** Note on Locks: Since the retry timer is directly associated with an entry on the EPD SendQueue,
  1720. ** we always protect retry-related operations with the EPD->SPLock. We only hold the EPD->StateLock
  1721. ** when we mess with link state variables (NRcv, DelayedAckTimer).
  1722. */
  1723. #undef DPF_MODNAME
  1724. #define DPF_MODNAME "RetryTimeout"
  1725. #ifdef DEBUG
  1726. LONG g_RetryCount[MAX_RETRIES+1]={0,0,0,0,0,0,0,0,0,0,0};
  1727. #endif
  1728. VOID CALLBACK
  1729. RetryTimeout(PVOID uID, UINT Unique, PVOID dwUser)
  1730. {
  1731. PEPD pEPD = (PEPD) dwUser;
  1732. PFMD pFMD;
  1733. DWORD tNow = GETTIMESTAMP(), tDelta;
  1734. UINT delta;
  1735. ASSERT_EPD(pEPD);
  1736. Lock(&pEPD->EPLock);
  1737. DPFX(DPFPREP,7, "(%p) Retry Timeout fires", pEPD);
  1738. // Make sure link is still active
  1739. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  1740. {
  1741. DPFX(DPFPREP,7, "(%p) Not connected, exiting", pEPD);
  1742. pEPD->RetryTimer = 0;
  1743. RELEASE_EPD(pEPD, "UNLOCK (retry timer not-CONN)"); // Decrement RefCnt for timer, releases EPLock
  1744. return;
  1745. }
  1746. // Its possible when we schedule a new retry timer that the previous timer cannot be cancelled. In this
  1747. // case the timer Handle &| Unique field will be different, and we do not want to run the event.
  1748. // Make sure this isn't a leftover event
  1749. if((pEPD->RetryTimer != uID) || (pEPD->RetryTimerUnique != Unique))
  1750. {
  1751. DPFX(DPFPREP,7, "(%p) Stale retry timer, exiting", pEPD);
  1752. RELEASE_EPD(pEPD, "UNLOCK (stale retry timer)"); // releases EPLock
  1753. return;
  1754. }
  1755. pEPD->RetryTimer = 0;
  1756. // Make sure that we still have transmits in progress
  1757. if(pEPD->uiUnackedFrames > 0)
  1758. {
  1759. ASSERT(!pEPD->blSendWindow.IsEmpty());
  1760. pFMD = CONTAINING_RECORD(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage); // Top frame in window
  1761. ASSERT_FMD(pFMD);
  1762. ASSERT(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET);
  1763. // First we must make sure that the TO'd packet is still hanging around. Since the first packet
  1764. // in the window might have changed while the TO was being scheduled, the easiest thing to do is
  1765. // just recalculate the top packets expiration time and make sure its really stale.
  1766. tDelta = tNow - pFMD->tTimestamp[pFMD->uiRetry]; // When did we last send this frame?
  1767. if(tDelta > pEPD->uiRetryTimeout)
  1768. {
  1769. // Its a genuine timeout. Lets retransmit the frame!
  1770. DPFX(DPFPREP,7, "(%p) RETRY TIMEOUT %d on Seq=%x, pFMD=0x%p", pEPD, (pFMD->uiRetry + 1), ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  1771. // Count a retry
  1772. if(++pFMD->uiRetry > MAX_RETRIES)
  1773. {
  1774. // BOOM! No more retries. We are finished. Link is going DOWN!
  1775. DPFX(DPFPREP,1, "(%p) DROPPING LINK, retries exhausted", pEPD);
  1776. DECREMENT_EPD(pEPD, "UNLOCK (retry timer drop)");// Release reference for this timer
  1777. DropLink(pEPD); // releases EPLock
  1778. return;
  1779. }
  1780. #ifdef DEBUG
  1781. InterlockedIncrement(&g_RetryCount[pFMD->uiRetry]);
  1782. #endif
  1783. // calculate timeout for next retry
  1784. if(pFMD->uiRetry == 1)
  1785. {
  1786. // do a retry at the same timeout - this is games after all.
  1787. tDelta = pEPD->uiRetryTimeout;
  1788. }
  1789. else if (pFMD->uiRetry <= 3)
  1790. {
  1791. // do a couple of linear backoffs - this is a game after all
  1792. tDelta = pEPD->uiRetryTimeout * pFMD->uiRetry;
  1793. }
  1794. else if (pFMD->uiRetry < 8)
  1795. {
  1796. // doh, bad link, bad bad link, do exponential backoffs
  1797. tDelta = pEPD->uiRetryTimeout * (1 << pFMD->uiRetry);
  1798. }
  1799. else
  1800. {
  1801. // don't give up too quickly.
  1802. tDelta = MAX_RETRY_INTERVAL;
  1803. }
  1804. if(tDelta >= MAX_RETRY_INTERVAL)
  1805. {
  1806. // CAP TOTAL DROP TIME AT 50 seconds unless the RTT is huge
  1807. tDelta = MAX(MAX_RETRY_INTERVAL, pEPD->uiRTT);
  1808. }
  1809. // Unreliable frame!
  1810. if(pFMD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  1811. {
  1812. // When an unreliable frame is NACKed we will not retransmit the data. We will instead send
  1813. // a mask so that the other side knows to cancel it.
  1814. DPFX(DPFPREP,7, "(%p) RETRY TIMEOUT for UNRELIABLE FRAME", pEPD);
  1815. // We get to credit the frame as out of the window.
  1816. pEPD->uiUnackedBytes -= pFMD->uiFrameLength;
  1817. // Only count a datagram drop on the first occurance
  1818. if(pFMD->uiRetry == 1)
  1819. {
  1820. pEPD->uiDatagramFramesDropped++;
  1821. pEPD->uiDatagramBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  1822. EndPointDroppedFrame(pEPD, tNow);
  1823. }
  1824. // Diff between next send and this send.
  1825. delta = (pEPD->bNextSend - ((PDFRAME) pFMD->ImmediateData)->bSeq) & 0xFF ;
  1826. ASSERT(delta != 0);
  1827. ASSERT(delta < (MAX_RECEIVE_RANGE + 1));
  1828. if(delta < 33)
  1829. {
  1830. pEPD->ulSendMask |= (1 << (delta - 1));
  1831. }
  1832. else
  1833. {
  1834. pEPD->ulSendMask2 |= (1 << (delta - 33));
  1835. }
  1836. pFMD->uiFrameLength = 0;
  1837. pEPD->ulEPFlags |= EPFLAGS_DELAYED_SENDMASK;
  1838. if(pEPD->DelayedMaskTimer == 0)
  1839. {
  1840. DPFX(DPFPREP,7, "(%p) Setting Delayed Mask Timer", pEPD);
  1841. LOCK_EPD(pEPD, "LOCK (delayed mask timer - send retry)");
  1842. SetMyTimer(DELAYED_SEND_TIMEOUT, 0, DelayedAckTimeout, (PVOID) pEPD, &pEPD->DelayedMaskTimer, &pEPD->DelayedMaskTimerUnique);
  1843. }
  1844. }
  1845. // RELIABLE FRAME -- Send a retry
  1846. else
  1847. {
  1848. pEPD->uiGuaranteedFramesDropped++; // Keep count of lost frames
  1849. pEPD->uiGuaranteedBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength); // Keep count of lost frames
  1850. pFMD->tTimestamp[pFMD->uiRetry] = tNow;
  1851. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  1852. // Stop delayed ack timer
  1853. if(pEPD->DelayedAckTimer != 0)
  1854. {
  1855. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1856. if(CancelMyTimer(pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  1857. {
  1858. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAck)"); // SPLock not already held
  1859. }
  1860. else
  1861. {
  1862. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1863. }
  1864. pEPD->DelayedAckTimer = 0;
  1865. }
  1866. EndPointDroppedFrame(pEPD, tNow);
  1867. if(pFMD->ulFFlags & FFLAGS_RETRY_QUEUED)
  1868. {
  1869. // It's still on the Retry Queue. This should not happen when everything is working
  1870. // properly. Timeouts should be greater then RTT and the BurstGap should be less then RTT.
  1871. DPFX(DPFPREP,1, "(%p) RETRY FIRES WHILE FMD IS STILL IN RETRY QUEUE pFMD=%p", pEPD, pFMD);
  1872. pFMD = NULL;
  1873. }
  1874. else if(pFMD->bSubmitted)
  1875. {
  1876. // Woe on us. We would like to retry a frame that has not been completed by the SP!
  1877. //
  1878. // This will most typically happen when we are debugging which delays processing
  1879. // of the Complete, but it could also happen if the SP is getting hammered. We need
  1880. // to copy the FMD into a temporary descriptor which can be discarded upon completion...
  1881. DPFX(DPFPREP,1,"(%p) RETRYING %p but its still busy. Substituting new FMD", pEPD, pFMD);
  1882. pFMD = CopyFMD(pFMD, pEPD); // We will substitute new FMD in rest of procedure
  1883. }
  1884. else
  1885. {
  1886. DPFX(DPFPREP,7, "(%p) Sending Retry of N(S)=%x, pFMD=0x%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  1887. LOCK_FMD(pFMD, "SP Submit");
  1888. }
  1889. if(pFMD)
  1890. {
  1891. LOCK_EPD(pEPD, "LOCK (retry rely frame)");
  1892. pEPD->ulEPFlags |= EPFLAGS_RETRIES_QUEUED;
  1893. pFMD->ulFFlags |= FFLAGS_RETRY_QUEUED;
  1894. ASSERT_MSD(pFMD->pMSD);
  1895. pFMD->pMSD->uiFrameCount++; // Protected by EPLock, retries prevent completion until they complete
  1896. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "(%p) Frame count incremented on retry timeout, pMSD[%p], framecount[%u]", pEPD, pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  1897. ASSERT(pFMD->blQLinkage.IsEmpty());
  1898. pFMD->blQLinkage.InsertBefore( &pEPD->blRetryQueue); // Place frame on Send queue
  1899. if((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0)
  1900. {
  1901. DPFX(DPFPREP,7, "(%p) Scheduling Send", pEPD);
  1902. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  1903. LOCK_EPD(pEPD, "LOCK (pipeline)");
  1904. ScheduleTimerThread(ScheduledSend, pEPD, &pEPD->SendTimer, &pEPD->SendTimerUnique);
  1905. }
  1906. }
  1907. } // ENDIF RETRY
  1908. }
  1909. else
  1910. {
  1911. tDelta = pEPD->uiRetryTimeout - tDelta;
  1912. }
  1913. DPFX(DPFPREP,7, "(%p) Setting Retry Timer for %d ms", pEPD, tDelta);
  1914. // Dont LOCK_EPD here because we never released the lock from the timer which scheduled us here
  1915. SetMyTimer(tDelta, 20, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique);
  1916. Unlock(&pEPD->EPLock);
  1917. }
  1918. else
  1919. {
  1920. RELEASE_EPD(pEPD, "UNLOCK (RetryTimer no frames out)"); // drop RefCnt since we dont restart timer, releases EPLock
  1921. }
  1922. }
  1923. /*
  1924. ** Copy FMD
  1925. **
  1926. ** This routine allocates a new Frame Descriptor and copies all fields from the provided
  1927. ** FMD into it. All fields except CommandID, RefCnt, and Flags.
  1928. */
  1929. #undef DPF_MODNAME
  1930. #define DPF_MODNAME "CopyFMD"
  1931. PFMD CopyFMD(PFMD pFMD, PEPD pEPD)
  1932. {
  1933. PFMD pNewFMD;
  1934. if((pNewFMD = static_cast<PFMD>( FMDPool->Get(FMDPool) )) == NULL)
  1935. {
  1936. DPFX(DPFPREP,0, "Failed to allocate new FMD");
  1937. return NULL;
  1938. }
  1939. LOCK_EPD(pEPD, "LOCK (CopyFMD)");
  1940. memcpy(pNewFMD, pFMD, sizeof(FMD));
  1941. // Undo the copying of these members
  1942. pNewFMD->blMSDLinkage.Initialize();
  1943. pNewFMD->blQLinkage.Initialize();
  1944. pNewFMD->blWindowLinkage.Initialize();
  1945. pNewFMD->CommandID = COMMAND_ID_COPIED_RETRY;
  1946. pNewFMD->lRefCnt = 1;
  1947. pNewFMD->ulFFlags = 0;
  1948. pNewFMD->bSubmitted = FALSE;
  1949. pNewFMD->lpImmediatePointer = (LPVOID) pNewFMD->ImmediateData;
  1950. pNewFMD->SendDataBlock.pBuffers = (PBUFFERDESC) &pNewFMD->uiImmediateLength;
  1951. pNewFMD->SendDataBlock.pvContext = pNewFMD;
  1952. pNewFMD->SendDataBlock.hCommand = 0;
  1953. ASSERT( pNewFMD->pEPD == pEPD );
  1954. DPFX(DPFPREP,7, "COPYFMD -- replacing FMD %p with copy %p", pFMD, pNewFMD);
  1955. return pNewFMD;
  1956. }
  1957. /*
  1958. ** Send Command Frame
  1959. **
  1960. ** Build a CFrame addressed to the specified EndPoint, and Queue it on the SPD
  1961. ** to be sent.
  1962. **
  1963. ** ** THIS FUNCTION CALLED AND RETURNS WITH EPD->EPLOCK HELD **
  1964. */
  1965. #undef DPF_MODNAME
  1966. #define DPF_MODNAME "SendCommandFrame"
  1967. HRESULT SendCommandFrame(PEPD pEPD, BYTE ExtOpcode, BYTE RspID)
  1968. {
  1969. PSPD pSPD = pEPD->pSPD;
  1970. PFMD pFMD;
  1971. PCFRAME pCFrame;
  1972. PCHKPT pChkPt;
  1973. DWORD tNow = GETTIMESTAMP();
  1974. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1975. // Frame already initialized to 1 buffer
  1976. if((pFMD = static_cast<PFMD>( FMDPool->Get(FMDPool) )) == NULL)
  1977. {
  1978. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD", pEPD);
  1979. return DPNERR_OUTOFMEMORY;
  1980. }
  1981. pFMD->pEPD = pEPD; // Track EPD for RefCnt
  1982. LOCK_EPD(pEPD, "LOCK (Prep Cmd Frame)"); // Bump RefCnt on EPD until send is completed
  1983. pFMD->CommandID = COMMAND_ID_CFRAME;
  1984. pFMD->pMSD = NULL; // this will indicate a NON-Data frame
  1985. pFMD->uiImmediateLength = sizeof(CFRAME); // standard size for C Frames
  1986. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt; // Place address in frame
  1987. pFMD->uiFrameLength = sizeof(CFRAME); // Never have user data in Cframe
  1988. pCFrame = (PCFRAME) pFMD->ImmediateData;
  1989. pCFrame->bCommand = PACKET_COMMAND_CFRAME;
  1990. pCFrame->bExtOpcode = ExtOpcode;
  1991. pCFrame->dwVersion = DNET_VERSION_NUMBER;
  1992. pCFrame->bRspID = RspID;
  1993. pCFrame->dwSessID = pEPD->dwSessID;
  1994. pCFrame->tTimestamp = tNow;
  1995. // If this frame requires a response (or if we are specifically asked to) we will build
  1996. // a Checkpoint structure which will be stored to correlate the eventual response with
  1997. // the original frame.
  1998. if( (pEPD->ulEPFlags & EPFLAGS_CHECKPOINT_INIT)||
  1999. (ExtOpcode == FRAME_EXOPCODE_CONNECT))
  2000. {
  2001. if((pChkPt = static_cast<PCHKPT>( ChkPtPool->Get(ChkPtPool) )) != NULL)
  2002. {
  2003. pChkPt->bMsgID = pEPD->bNextMsgID; // Note next ID in CP structure
  2004. pCFrame->bCommand |= PACKET_COMMAND_POLL; // make this frame a CP
  2005. pEPD->ulEPFlags &= ~EPFLAGS_CHECKPOINT_INIT;
  2006. pChkPt->tTimestamp = tNow;
  2007. pChkPt->blLinkage.InsertBefore( &pEPD->blChkPtQueue);
  2008. }
  2009. else
  2010. {
  2011. DPFX(DPFPREP,0, "(%p) Failed to allocate new CHKPT", pEPD);
  2012. ASSERT(0);
  2013. }
  2014. }
  2015. pCFrame->bMsgID = pEPD->bNextMsgID++; // include MsgID in frame
  2016. Lock(&pSPD->SPLock); // Place SACK frame on send queue
  2017. ASSERT(pFMD->blQLinkage.IsEmpty());
  2018. pFMD->blQLinkage.InsertBefore( &pSPD->blSendQueue);
  2019. if((pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)==0)
  2020. {
  2021. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  2022. pSPD->ulSPFlags |= SPFLAGS_SEND_THREAD_SCHEDULED;
  2023. ScheduleTimerThread(RunSendThread, pSPD, &pSPD->SendHandle, &pSPD->SendHandleUnique);
  2024. }
  2025. Unlock(&pSPD->SPLock);
  2026. return DPN_OK;
  2027. }
  2028. /*
  2029. ** Send Ack Frame
  2030. **
  2031. ** This routine is called to immediately transmit our current receive
  2032. ** state to the indicated EndPoint. This is equivalent to acknowledging
  2033. ** all received frames. We may want to change this routine so that it
  2034. ** will attempt to piggyback the ack if there is data waiting to be sent.
  2035. **
  2036. ** THIS ROUTINE IS CALLED WITH EDP->EPLOCK HELD, BUT RELEASES IT IF DirectFlag IS SET
  2037. */
  2038. #undef DPF_MODNAME
  2039. #define DPF_MODNAME "SendAckFrame"
  2040. VOID SendAckFrame(PEPD pEPD, BOOL DirectFlag, BOOL fFinalAck/* = FALSE*/)
  2041. {
  2042. PSPD pSPD = pEPD->pSPD;
  2043. PFMD pFMD;
  2044. UINT index = 0;
  2045. PSFBIG8 pSackFrame;
  2046. ASSERT_SPD(pSPD);
  2047. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2048. // Frame already initialized to 1 buffer
  2049. if((pFMD = static_cast<PFMD>( FMDPool->Get(FMDPool) )) == NULL)
  2050. {
  2051. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD", pEPD);
  2052. return;
  2053. }
  2054. // We can stop all delayed Ack timers since we are sending full status here.
  2055. if(pEPD->DelayedAckTimer != 0)
  2056. {
  2057. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  2058. if(CancelMyTimer(pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  2059. {
  2060. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAck timer)");
  2061. }
  2062. else
  2063. {
  2064. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  2065. }
  2066. pEPD->DelayedAckTimer = 0;
  2067. }
  2068. if(pEPD->DelayedMaskTimer != 0)
  2069. {
  2070. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  2071. if(CancelMyTimer(pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  2072. {
  2073. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMask timer)");
  2074. }
  2075. else
  2076. {
  2077. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  2078. }
  2079. pEPD->DelayedMaskTimer = 0;
  2080. }
  2081. if (fFinalAck)
  2082. {
  2083. pFMD->ulFFlags |= FFLAGS_FINAL_ACK;
  2084. }
  2085. pFMD->pEPD = pEPD; // Track EPD for RefCnt
  2086. LOCK_EPD(pEPD, "LOCK (SendAckFrame)"); // Bump RefCnt on EPD until send is completed
  2087. pFMD->CommandID = COMMAND_ID_CFRAME;
  2088. pFMD->pMSD = NULL; // this will indicate a NON-Data frame
  2089. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt;
  2090. // Now that DG and S have been merged, there are no longer 3 flavors of ACK frame. We are back to only
  2091. // one flavor that may or may not have detailed response info on one frame. Actually, I think we can
  2092. // always include response info on the last ack'd frame.
  2093. pSackFrame = (PSFBIG8) pFMD->ImmediateData;
  2094. pSackFrame->bCommand = PACKET_COMMAND_CFRAME;
  2095. pSackFrame->bExtOpcode = FRAME_EXOPCODE_SACK;
  2096. pSackFrame->bNSeq = pEPD->bNextSend;
  2097. pSackFrame->bNRcv = pEPD->bNextReceive;
  2098. pSackFrame->bFlags = 0;
  2099. pSackFrame->bReserved1 = 0;
  2100. pSackFrame->bReserved2 = 0;
  2101. pSackFrame->tTimestamp = pEPD->tLastDataFrame;
  2102. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  2103. {
  2104. DPFX(DPFPREP,7, "(%p) SENDING SACK WITH *NACK* N(R)=%x Low=%x High=%x", pEPD, pEPD->bNextReceive, pEPD->ulReceiveMask, pEPD->ulReceiveMask2);
  2105. if(pEPD->ulReceiveMask)
  2106. {
  2107. pSackFrame->rgMask[index++] = pEPD->ulReceiveMask;
  2108. pSackFrame->bFlags |= SACK_FLAGS_SACK_MASK1;
  2109. }
  2110. if(pEPD->ulReceiveMask2)
  2111. {
  2112. pSackFrame->rgMask[index++] = pEPD->ulReceiveMask2;
  2113. pSackFrame->bFlags |= SACK_FLAGS_SACK_MASK2;
  2114. }
  2115. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  2116. }
  2117. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)
  2118. {
  2119. DPFX(DPFPREP,7, "(%p) SENDING SACK WITH SEND MASK N(S)=%x Low=%x High=%x", pEPD, pEPD->bNextSend, pEPD->ulSendMask, pEPD->ulSendMask2);
  2120. if(pEPD->ulSendMask)
  2121. {
  2122. pSackFrame->rgMask[index++] = pEPD->ulSendMask;
  2123. pSackFrame->bFlags |= SACK_FLAGS_SEND_MASK1;
  2124. pEPD->ulSendMask = 0;
  2125. }
  2126. if(pEPD->ulSendMask2)
  2127. {
  2128. pSackFrame->rgMask[index++] = pEPD->ulSendMask2;
  2129. pSackFrame->bFlags |= SACK_FLAGS_SEND_MASK2;
  2130. pEPD->ulSendMask2 = 0;
  2131. }
  2132. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_SENDMASK);
  2133. }
  2134. pFMD->uiImmediateLength = sizeof(SACKFRAME8) + (index * sizeof(ULONG));
  2135. pFMD->uiFrameLength = pFMD->uiImmediateLength;
  2136. pSackFrame->bFlags |= SACK_FLAGS_RESPONSE; // time fields are always valid now
  2137. ASSERT(pEPD->bLastDataSeq == (BYTE) (pEPD->bNextReceive - 1));
  2138. pSackFrame->bRetry = pEPD->bLastDataRetry;
  2139. DPFX(DPFPREP,7, "(%p) SEND SACK FRAME N(Rcv)=%x, EPD->LDRetry=%d, pFrame->Retry=%d pFMD=%p", pEPD, pEPD->bNextReceive, pEPD->bLastDataRetry, pSackFrame->bRetry, pFMD);
  2140. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE);
  2141. // We can either schedule a worker thread to do the send or else we can do the work ourselves.
  2142. // The DirectFlag tells us whether we are in a time-crit section, like processing
  2143. // receive data, or whether we are free to call the SP ourselves.
  2144. Lock(&pSPD->SPLock); // Place SACK frame on send queue
  2145. ASSERT(pFMD->blQLinkage.IsEmpty());
  2146. pFMD->blQLinkage.InsertBefore( &pSPD->blSendQueue);
  2147. if(DirectFlag)
  2148. {
  2149. // ServiceCmdTraffic will call into the SP so we must not hold the EPD lock
  2150. Unlock(&pEPD->EPLock);
  2151. ServiceCmdTraffic(pSPD); // Called with SPLock held
  2152. }
  2153. else
  2154. {
  2155. if((pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)==0)
  2156. {
  2157. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  2158. pSPD->ulSPFlags |= SPFLAGS_SEND_THREAD_SCHEDULED;
  2159. ScheduleTimerThread(RunSendThread, pSPD, &pSPD->SendHandle, &pSPD->SendHandleUnique);
  2160. }
  2161. }
  2162. Unlock(&pSPD->SPLock);
  2163. }
  2164. /*
  2165. ** Delayed Ack Timeout
  2166. **
  2167. ** We are waiting for a chance to piggyback a reliable frame acknowledgement,
  2168. ** but the sands have run out. Its time to send a dedicated Ack now.
  2169. */
  2170. #undef DPF_MODNAME
  2171. #define DPF_MODNAME "DelayedAckTimeout"
  2172. VOID CALLBACK DelayedAckTimeout(PVOID uID, UINT uMsg, PVOID dwUser)
  2173. {
  2174. PEPD pEPD = (PEPD) dwUser;
  2175. ASSERT_EPD(pEPD);
  2176. Lock(&pEPD->EPLock);
  2177. DPFX(DPFPREP,7, "(%p) Delayed Ack Timer fires", pEPD);
  2178. if((pEPD->DelayedAckTimer == uID)&&(pEPD->DelayedAckTimerUnique == uMsg))
  2179. {
  2180. pEPD->DelayedAckTimer = 0;
  2181. }
  2182. else if((pEPD->DelayedMaskTimer == uID)&&(pEPD->DelayedMaskTimerUnique == uMsg))
  2183. {
  2184. pEPD->DelayedMaskTimer = 0;
  2185. }
  2186. else
  2187. {
  2188. // Stale timer, ignore
  2189. DPFX(DPFPREP,7, "(%p) Stale Delayed Ack Timer, ignoring", pEPD);
  2190. RELEASE_EPD(pEPD, "UNLOCK (DelayedAck complete)"); // release reference for timer, releases EPLock
  2191. return;
  2192. }
  2193. if( (pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) && (pEPD->ulEPFlags & (EPFLAGS_DELAY_ACKNOWLEDGE | EPFLAGS_DELAYED_NACK | EPFLAGS_DELAYED_SENDMASK)))
  2194. {
  2195. SendAckFrame(pEPD, 0);
  2196. }
  2197. RELEASE_EPD(pEPD, "UNLOCK (DelayedAck complete)"); // release reference for timer, releases EPLock
  2198. }
  2199. /*
  2200. ** Send Keep Alive
  2201. **
  2202. ** When we have not received anything from an endpoint in a long time (default 60 sec)
  2203. ** will will initiate a checkpoint to make sure that the partner is still connected. We do
  2204. ** this by inserting a zero-data frame into the reliable pipeline. Thereby, the standard
  2205. ** timeout & retry mechanisms will either confirm or drop the link as appropriate. Logic above
  2206. ** this routine will have already verified that we are not already sending reliable traffic, which
  2207. ** would eliminate the need for a keep alive frame.
  2208. **
  2209. ** *** EPD->EPLock is held on Entry and return
  2210. */
  2211. #undef DPF_MODNAME
  2212. #define DPF_MODNAME "SendKeepAlive"
  2213. VOID
  2214. SendKeepAlive(PEPD pEPD)
  2215. {
  2216. PFMD pFMD;
  2217. PMSD pMSD;
  2218. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2219. if(pEPD->ulEPFlags & EPFLAGS_KEEPALIVE_RUNNING)
  2220. {
  2221. DPFX(DPFPREP,7, "Ignoring duplicate KeepAlive");
  2222. return;
  2223. }
  2224. pEPD->ulEPFlags |= EPFLAGS_KEEPALIVE_RUNNING;
  2225. if( (pMSD = static_cast<PMSD>( MSDPool->Get(MSDPool) )) == NULL)
  2226. {
  2227. DPFX(DPFPREP,0, "(%p) Failed to allocate new MSD");
  2228. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  2229. return;
  2230. }
  2231. pMSD->uiFrameCount = 1;
  2232. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Initialize Frame count, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  2233. pMSD->ulMsgFlags2 |= MFLAGS_TWO_KEEPALIVE;
  2234. if((pFMD = static_cast<PFMD>( FMDPool->Get(FMDPool) )) == NULL)
  2235. {
  2236. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD");
  2237. Lock(&pMSD->CommandLock); // An MSD must be locked to be released
  2238. RELEASE_MSD(pMSD, "Release On FMD Get Failed");
  2239. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  2240. return;
  2241. }
  2242. pMSD->pEPD = pEPD;
  2243. pMSD->pSPD = pEPD->pSPD;
  2244. LOCK_EPD(pEPD, "LOCK (SendKeepAlive)"); // Add a reference for this checkpoint
  2245. pFMD->ulFFlags |= FFLAGS_CHECKPOINT | FFLAGS_END_OF_MESSAGE;
  2246. pFMD->bPacketFlags = PACKET_COMMAND_DATA | PACKET_COMMAND_RELIABLE | PACKET_COMMAND_SEQUENTIAL | PACKET_COMMAND_END_MSG;
  2247. pFMD->uiFrameLength = 0; // No user data in this frame
  2248. pFMD->blMSDLinkage.InsertAfter( &pMSD->blFrameList); // Attach frame to MSD
  2249. pFMD->pMSD = pMSD; // Link frame back to message
  2250. pFMD->pEPD = pEPD;
  2251. pFMD->CommandID = COMMAND_ID_SEND_RELIABLE;
  2252. pMSD->CommandID = COMMAND_ID_KEEPALIVE; // Mark MSD for completion handling
  2253. pMSD->ulSendFlags = DN_SENDFLAGS_RELIABLE | DN_SENDFLAGS_LOW_PRIORITY; // Priority is LOW so all previously submitted traffic will be sent
  2254. DPFX(DPFPREP,7,"(%p) Sending KEEPALIVE", pEPD);
  2255. EnqueueMessage(pMSD, pEPD); // Insert this message into the stream
  2256. }
  2257. /*
  2258. ** Perform Checkpoint
  2259. **
  2260. ** We would like to take a measurement of Round-Trip latency using the
  2261. ** reliable pipeline. We either need to mark the next outgoing frame in our
  2262. ** SendQ with a POLL bit OR we need to create a special purpose frame if
  2263. ** the pipeline is idle.
  2264. **
  2265. ** We have a routine (above) which will insert a special frame, so THIS
  2266. ** procedure will check for an idle link and either call out or mark the
  2267. ** next frame.
  2268. **
  2269. ** ** CALLED AND RETURNS WITH EPD->EPLOCK HELD
  2270. */
  2271. #undef DPF_MODNAME
  2272. #define DPF_MODNAME "PerformCheckpoint"
  2273. VOID
  2274. PerformCheckpoint(PEPD pEPD)
  2275. {
  2276. DPFX(DPFPREP,7,"(%p) Performing Checkpoint", pEPD);
  2277. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2278. if(pEPD->ulEPFlags & EPFLAGS_SDATA_READY)
  2279. {
  2280. ASSERT(pEPD->pCurrentFrame != NULL); // DATA_READY flag means pCurrentFrame is valid
  2281. pEPD->pCurrentFrame->ulFFlags |= FFLAGS_CHECKPOINT;
  2282. }
  2283. else
  2284. { // We do not have data in our pipeline
  2285. SendKeepAlive(pEPD); // Keepalive doubles as a checkpoint
  2286. }
  2287. }
  2288. /*
  2289. ** Endpoint Background Process
  2290. **
  2291. ** This routine is run for each active endpoint every minute or so. This will initiate
  2292. ** a KeepAlive exchange if the link has been idle since the last run of the procedure. We
  2293. ** will also look for expired timeouts and perhaps this will be an epoch delimiter for links
  2294. ** in a STABLE state of being.
  2295. **
  2296. */
  2297. #undef DPF_MODNAME
  2298. #define DPF_MODNAME "EndPointBackgroundProcess"
  2299. VOID CALLBACK
  2300. EndPointBackgroundProcess(PVOID uID, UINT Unique, PVOID dwUser)
  2301. {
  2302. PEPD pEPD = (PEPD) dwUser;
  2303. DWORD tNow = GETTIMESTAMP();
  2304. DWORD dwIdleInterval;
  2305. DPFX(DPFPREP,7, "(%p) BACKGROUND PROCESS for EPD; RefCnt=%d; WindowF=%d; WindowB=%d",
  2306. pEPD, pEPD->lRefCnt, pEPD->uiWindowF, pEPD->uiWindowBIndex);
  2307. Lock(&pEPD->EPLock);
  2308. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  2309. {
  2310. DPFX(DPFPREP,7, "Killing Background Process, endpoint is not connected. Flags = 0x%x", pEPD->ulEPFlags);
  2311. pEPD->BGTimer = 0;
  2312. RELEASE_EPD(pEPD, "UNLOCK (release BG timer)"); // release reference for this timer, releases EPLock
  2313. return;
  2314. }
  2315. dwIdleInterval = pEPD->pSPD->pPData->tIdleThreshhold;
  2316. // Do we need to start a KeepAlive cycle?
  2317. if( ((pEPD->ulEPFlags & (EPFLAGS_SDATA_READY | EPFLAGS_KEEPALIVE_RUNNING))==0) &&
  2318. ((tNow - pEPD->tLastPacket) > dwIdleInterval))
  2319. {
  2320. // We are not sending data and we havent heard from our partner in a long time.
  2321. // We will send a keep alive packet which he must respond to. We will insert a
  2322. // NULL data packet into the reliable stream so ack/retry mechanisms will either
  2323. // clear the keep-alive or else timeout the link.
  2324. //
  2325. // There's also the special case where we've started a graceful disconnect and
  2326. // our request has been acknowledged, but somehow our partner's got lost.
  2327. // There currently is no timer set for that, so if we detect the link in that
  2328. // condition, our keepalive will almost certainly fail; the other side knows
  2329. // we're shutting down, so has probably already dropped the link and wouldn't
  2330. // respond. So to prevent the person from having to wait for the entire idle
  2331. // timeout _plus_ reliable message timeout, just drop the link now.
  2332. if (pEPD->ulEPFlags & EPFLAGS_DISCONNECT_ACKED)
  2333. {
  2334. // If all three parts happened, why is the link still up!?
  2335. ASSERT(! (pEPD->ulEPFlags & EPFLAGS_ACKED_DISCONNECT));
  2336. DPFX(DPFPREP,1, "(%p) EPD has been waiting for partner disconnect for %u ms (idle threshold = %u ms), dropping link.",
  2337. pEPD, (tNow - pEPD->tLastPacket), dwIdleInterval);
  2338. // We don't need to reschedule a timer, so clear it. This also prevents
  2339. // drop link from trying to cancel the one we're in now. That error is
  2340. // ignored, but no point in doing it.
  2341. pEPD->BGTimer = 0;
  2342. DECREMENT_EPD(pEPD, "UNLOCK (release BGTimer)");
  2343. // Since we're just hanging out waiting for partner to send his disconnect,
  2344. // he's probably gone now. Drop the link.
  2345. DropLink(pEPD); // releases EPLock
  2346. return;
  2347. }
  2348. else if (!(pEPD->ulEPFlags & EPFLAGS_SENT_DISCONNECT))
  2349. {
  2350. DPFX(DPFPREP,5, "(%p) Sending KEEPALIVE...", pEPD);
  2351. SendKeepAlive(pEPD);
  2352. }
  2353. else
  2354. {
  2355. // The EndOfStream message will either get ACK'd or timeout, we allow no further sends, even KeepAlives
  2356. DPFX(DPFPREP,5, "(%p) KeepAlive timeout fired, but we have already sent an EndOfStream, ignoring", pEPD);
  2357. }
  2358. }
  2359. // Reschedule next interval
  2360. // Cap the background process interval at this value.
  2361. if (dwIdleInterval > ENDPOINT_BACKGROUND_INTERVAL)
  2362. dwIdleInterval = ENDPOINT_BACKGROUND_INTERVAL;
  2363. DPFX(DPFPREP,7, "(%p) Setting Endpoint Background Timer for %u ms", pEPD, dwIdleInterval);
  2364. SetMyTimer(dwIdleInterval, 1000, EndPointBackgroundProcess, (PVOID) pEPD, &pEPD->BGTimer, &pEPD->BGTimerUnique);
  2365. Unlock(&pEPD->EPLock);
  2366. }