Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3896 lines
139 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2002 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 DBG
  42. VOID LockEPD(PEPD pEPD, PTSTR Buf)
  43. {
  44. #else // DBG
  45. VOID LockEPD(PEPD pEPD)
  46. {
  47. #endif // DBG
  48. if (INTER_INC(pEPD) == 0)
  49. {
  50. ASSERT(0);
  51. }
  52. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, pEPD->lRefCnt);
  53. DNASSERTX(pEPD->lRefCnt < 10000, 2);
  54. }
  55. /*
  56. * Called with EPLock held, returns with EPLock released
  57. */
  58. #undef DPF_MODNAME
  59. #define DPF_MODNAME "ReleaseEPD"
  60. #ifdef DBG
  61. VOID ReleaseEPD(PEPD pEPD, PTSTR Buf)
  62. {
  63. #else // DBG
  64. VOID ReleaseEPD(PEPD pEPD)
  65. {
  66. #endif // DBG
  67. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  68. ASSERT(pEPD->lRefCnt >= 0);
  69. // Someone else can come along and call LOCK_EPD or DECREMENT_EPD while we are here
  70. // so the decrement has to be interlocked even though we own the EPLock.
  71. LONG lRefCnt = INTER_DEC(pEPD);
  72. if (lRefCnt == 0 && !(pEPD->ulEPFlags & EPFLAGS_SP_DISCONNECTED))
  73. {
  74. // Make sure no one else does this again
  75. pEPD->ulEPFlags |= EPFLAGS_SP_DISCONNECTED;
  76. SPDISCONNECTDATA Block;
  77. Block.hEndpoint = pEPD->hEndPt;
  78. Block.dwFlags = 0;
  79. Block.pvContext = NULL;
  80. Unlock(&pEPD->EPLock);
  81. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  82. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->Disconnect - hEndpoint[%x], pSPD[%p]", pEPD, Block.hEndpoint, pEPD->pSPD);
  83. (void) IDP8ServiceProvider_Disconnect(pEPD->pSPD->IISPIntf, &Block);
  84. }
  85. else if (lRefCnt < 0)
  86. {
  87. Unlock(&pEPD->EPLock);
  88. Lock(&pEPD->pSPD->SPLock);
  89. pEPD->blActiveLinkage.RemoveFromList();
  90. Unlock(&pEPD->pSPD->SPLock);
  91. EPDPool.Release(pEPD);
  92. }
  93. else
  94. {
  95. Unlock(&pEPD->EPLock);
  96. }
  97. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, lRefCnt);
  98. }
  99. #undef DPF_MODNAME
  100. #define DPF_MODNAME "DecrementEPD"
  101. #ifdef DBG
  102. VOID DecrementEPD(PEPD pEPD, PTSTR Buf)
  103. {
  104. #else // DBG
  105. VOID DecrementEPD(PEPD pEPD)
  106. {
  107. #endif // DBG
  108. ASSERT(pEPD->lRefCnt > 0);
  109. INTER_DEC(pEPD);
  110. DPFX(DPFPREP,DPF_EP_REFCNT_LVL, "(%p) %s, RefCnt: %d", pEPD, Buf, pEPD->lRefCnt);
  111. }
  112. #undef DPF_MODNAME
  113. #define DPF_MODNAME "LockMSD"
  114. #ifdef DBG
  115. VOID LockMSD(PMSD pMSD, PTSTR Buf)
  116. {
  117. #else // DBG
  118. VOID LockMSD(PMSD pMSD)
  119. {
  120. #endif // DBG
  121. if(INTER_INC(pMSD) == 0)
  122. {
  123. ASSERT(0);
  124. }
  125. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  126. }
  127. #undef DPF_MODNAME
  128. #define DPF_MODNAME "ReleaseMSD"
  129. #ifdef DBG
  130. VOID ReleaseMSD(PMSD pMSD, PTSTR Buf)
  131. {
  132. #else // DBG
  133. VOID ReleaseMSD(PMSD pMSD)
  134. {
  135. #endif // DBG
  136. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  137. ASSERT(pMSD->lRefCnt >= 0);
  138. if(INTER_DEC(pMSD) < 0)
  139. {
  140. MSDPool.Release(pMSD);
  141. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, -1);
  142. }
  143. else
  144. {
  145. Unlock(&pMSD->CommandLock);
  146. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  147. }
  148. }
  149. #undef DPF_MODNAME
  150. #define DPF_MODNAME "DecrementMSD"
  151. #ifdef DBG
  152. VOID DecrementMSD(PMSD pMSD, PTSTR Buf)
  153. {
  154. #else // DBG
  155. VOID DecrementMSD(PMSD pMSD)
  156. {
  157. #endif // DBG
  158. ASSERT(pMSD->lRefCnt > 0);
  159. INTER_DEC(pMSD);
  160. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pMSD, Buf, pMSD->lRefCnt);
  161. }
  162. #undef DPF_MODNAME
  163. #define DPF_MODNAME "LockFMD"
  164. #ifdef DBG
  165. VOID LockFMD(PFMD pFMD, PTSTR Buf)
  166. {
  167. #else // DBG
  168. VOID LockFMD(PFMD pFMD)
  169. {
  170. #endif // DBG
  171. ASSERT(pFMD->lRefCnt > 0); // FMD_Get is the only function that should make this 1
  172. INTER_INC(pFMD);
  173. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, pFMD->lRefCnt);
  174. }
  175. #undef DPF_MODNAME
  176. #define DPF_MODNAME "ReleaseFMD"
  177. #ifdef DBG
  178. VOID ReleaseFMD(PFMD pFMD, PTSTR Buf)
  179. {
  180. #else // DBG
  181. VOID ReleaseFMD(PFMD pFMD)
  182. {
  183. #endif // DBG
  184. ASSERT(pFMD->lRefCnt > 0);
  185. if( INTER_DEC(pFMD) == 0)
  186. {
  187. FMDPool.Release(pFMD);
  188. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, 0);
  189. }
  190. else
  191. {
  192. DPFX(DPFPREP,DPF_REFCNT_LVL, "(%p) %s, RefCnt: %d", pFMD, Buf, pFMD->lRefCnt);
  193. }
  194. }
  195. /*
  196. ** DNSP Command Complete
  197. **
  198. ** Service Provider calls us here to indicate completion of an asynchronous
  199. ** command. This may be called before the actual command returns, so we must
  200. ** make sure that our Context value is valid and accessible before calling SP.
  201. */
  202. #undef DPF_MODNAME
  203. #define DPF_MODNAME "DNSP_CommandComplete"
  204. HRESULT WINAPI DNSP_CommandComplete(IDP8SPCallback *pIDNSP, HANDLE Handle, HRESULT hr, PVOID Context)
  205. {
  206. PSPD pSPD = (PSPD) pIDNSP;
  207. PFMD pFMD = (PFMD) Context;
  208. PEPD pEPD;
  209. PMSD pMSD;
  210. CBilink* pbl;
  211. ASSERT_SPD(pSPD);
  212. ASSERT(Context);
  213. DBG_CASSERT(OFFSETOF(FMD, CommandID) == OFFSETOF(MSD, CommandID));
  214. DPFX(DPFPREP,9, "COMMAND COMPLETE (%p, ID = %u)", Context, pFMD->CommandID);
  215. switch(pFMD->CommandID)
  216. {
  217. case COMMAND_ID_SEND_COALESCE:
  218. case COMMAND_ID_COPIED_RETRY_COALESCE:
  219. {
  220. ASSERT_FMD(pFMD);
  221. ASSERT( pFMD->bSubmitted );
  222. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL );
  223. pEPD = pFMD->pEPD;
  224. ASSERT_EPD(pEPD);
  225. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  226. Lock(&pSPD->SPLock);
  227. pFMD->blQLinkage.RemoveFromList();
  228. Unlock(&pSPD->SPLock);
  229. Lock(&pEPD->EPLock);
  230. // Complete all of the individual frames.
  231. pbl = pFMD->blCoalesceLinkage.GetNext();
  232. while (pbl != &pFMD->blCoalesceLinkage)
  233. {
  234. PFMD pFMDInner = CONTAINING_OBJECT(pbl, FMD, blCoalesceLinkage);
  235. ASSERT_FMD(pFMDInner);
  236. // It's likely that the DNSP_CommandComplete call below or an acknowledgement
  237. // received shortly thereafter will complete the send for real and pull it out of
  238. // the coalescence list. We must grab a pointer to the next item in the list
  239. // before we drop the lock and complete the frame.
  240. ASSERT(pbl->GetNext() != pbl);
  241. pbl = pbl->GetNext();
  242. Unlock(&pEPD->EPLock);
  243. (void) DNSP_CommandComplete((IDP8SPCallback *) pSPD, NULL, hr, pFMDInner);
  244. Lock(&pEPD->EPLock);
  245. }
  246. // Set the submitted flag for the coalesce header after all the subframes are complete
  247. // because we drop the EPD for each subframe.
  248. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected by EPLock
  249. if (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE)
  250. {
  251. DECREMENT_EPD(pEPD, "UNLOCK (Rely Frame Complete (Copy Coalesce))");
  252. }
  253. RELEASE_EPD(pEPD, "UNLOCK (Coalesce Frame Complete)"); // This releases the EPLock
  254. RELEASE_FMD(pFMD, "Coalesce SP submit release on complete"); // Dec ref count
  255. break;
  256. }
  257. case COMMAND_ID_SEND_DATAGRAM:
  258. case COMMAND_ID_SEND_RELIABLE:
  259. case COMMAND_ID_COPIED_RETRY:
  260. {
  261. ASSERT_FMD(pFMD);
  262. ASSERT( pFMD->bSubmitted );
  263. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL );
  264. pEPD = pFMD->pEPD;
  265. ASSERT_EPD(pEPD);
  266. DPFX(DPFPREP,DPF_CALLIN_LVL, "CommandComplete called for MSD[%p], pEPD[%p], pFMD[%p], Handle[%p], hCommand[%p], hr[%x]", pFMD->pMSD, pEPD, pFMD, Handle, pFMD->SendDataBlock.hCommand, hr);
  267. Lock(&pSPD->SPLock);
  268. pFMD->blQLinkage.RemoveFromList(); // but they dont wait on the PENDING queue
  269. Unlock(&pSPD->SPLock);
  270. pMSD = pFMD->pMSD;
  271. ASSERT_MSD(pMSD);
  272. Lock(&pMSD->CommandLock);
  273. Lock(&pEPD->EPLock);
  274. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected by EPLock
  275. // 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
  276. // with the user's buffers.
  277. pMSD->uiFrameCount--; // Protected by EPLock
  278. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count decremented on complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  279. if (pMSD->uiFrameCount == 0) // Protected by EPLock
  280. {
  281. if (pFMD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  282. {
  283. // Datagrams are complete as soon as all of their frames are sent
  284. // NOTE: This is done again in CompleteDatagramSend...
  285. pMSD->ulMsgFlags2 |= MFLAGS_TWO_SEND_COMPLETE;
  286. }
  287. if (pMSD->ulMsgFlags2 & (MFLAGS_TWO_SEND_COMPLETE|MFLAGS_TWO_ABORT))
  288. {
  289. // There is a race condition while abort is between its two holdings of the lock. If we are completing,
  290. // then we need to let AbortSends know that by clearing this flag.
  291. if (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT_WILL_COMPLETE)
  292. {
  293. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ABORT_WILL_COMPLETE);
  294. // It is important that we not pull pMSD->blQLinkage off the list in this case since AbortSends is
  295. // using that to hold it on a temporary list. If we do pull it off, AbortSends will not release
  296. // its reference on the MSD and it will leak.
  297. }
  298. else
  299. {
  300. // Remove the MSD from the CompleteSends list in the normal case
  301. pMSD->blQLinkage.RemoveFromList();
  302. }
  303. if (pFMD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  304. {
  305. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing Nonreliable frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  306. Unlock(&pEPD->EPLock);
  307. CompleteDatagramSend(pSPD, pMSD, hr); // Releases MSDLock
  308. Lock(&pEPD->EPLock);
  309. }
  310. else if ((pMSD->CommandID == COMMAND_ID_DISCONNECT || pMSD->CommandID == COMMAND_ID_DISC_RESPONSE) &&
  311. (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT))
  312. {
  313. // We got all the pieces we needed to finish a disconnect off earlier, but there were frames
  314. // still outstanding (probably from retries). Now that all the frames are done, we can complete
  315. // this disconnect operation.
  316. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing disconnect, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  317. Unlock(&pEPD->EPLock);
  318. CompleteDisconnect(pMSD, pSPD, pEPD); // This releases the CommandLock
  319. Lock(&pEPD->EPLock);
  320. }
  321. else
  322. {
  323. ASSERT(pFMD->CommandID == COMMAND_ID_SEND_RELIABLE || pFMD->CommandID == COMMAND_ID_COPIED_RETRY);
  324. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing Reliable frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  325. // See what error code we need to return
  326. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_SEND_COMPLETE)
  327. {
  328. Unlock(&pEPD->EPLock);
  329. CompleteReliableSend(pEPD->pSPD, pMSD, DPN_OK); // This releases the CommandLock
  330. Lock(&pEPD->EPLock);
  331. }
  332. else
  333. {
  334. Unlock(&pEPD->EPLock);
  335. CompleteReliableSend(pEPD->pSPD, pMSD, DPNERR_CONNECTIONLOST); // This releases the CommandLock
  336. Lock(&pEPD->EPLock);
  337. }
  338. }
  339. }
  340. else
  341. {
  342. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Message not yet complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  343. Unlock(&pMSD->CommandLock);
  344. }
  345. }
  346. else
  347. {
  348. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frames still outstanding, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  349. Unlock(&pMSD->CommandLock);
  350. }
  351. if (pFMD->CommandID == COMMAND_ID_COPIED_RETRY)
  352. {
  353. // In case this was a coalesced retry, remove it from the list because copied coalesced retries don't
  354. // get true completions of their own (protected by EPD lock). Copied coalesced retries don't keep
  355. // a reference to their containing header since they complete at the same time.
  356. ASSERT(pFMD->pCSD == NULL);
  357. pFMD->blCoalesceLinkage.RemoveFromList();
  358. DECREMENT_EPD(pFMD->pEPD, "UNLOCK (Rely Frame Complete (Copy))");
  359. }
  360. RELEASE_EPD(pFMD->pEPD, "UNLOCK (Frame Complete)"); // This releases the EPLock
  361. RELEASE_FMD(pFMD, "SP Submit release on complete"); // Dec ref count
  362. break;
  363. }
  364. case COMMAND_ID_CONNECT:
  365. {
  366. pMSD = (PMSD) Context;
  367. ASSERT_MSD(pMSD);
  368. ASSERT(pMSD->hCommand == Handle || pMSD->hCommand == NULL); // Command can complete before hCommmand is set up
  369. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER);
  370. 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);
  371. CompleteSPConnect((PMSD) Context, pSPD, hr);
  372. break;
  373. }
  374. case COMMAND_ID_CFRAME:
  375. {
  376. ASSERT_FMD(pFMD);
  377. ASSERT( pFMD->bSubmitted );
  378. ASSERT( pFMD->SendDataBlock.hCommand == Handle || pFMD->SendDataBlock.hCommand == NULL );
  379. pEPD = pFMD->pEPD;
  380. ASSERT_EPD(pEPD);
  381. 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);
  382. Lock(&pSPD->SPLock);
  383. pFMD->blQLinkage.RemoveFromList(); // Take the frame off of the pending queue
  384. #pragma BUGBUG(vanceo, "EPD lock is not held?")
  385. pFMD->bSubmitted = FALSE; // bSubmitted flag is protected bp SP->SPLock
  386. Unlock(&pSPD->SPLock);
  387. Lock(&pEPD->EPLock);
  388. //if that was the last send in a sequence of hard disconnect frames then we've just completed a hard
  389. //disconnect and should indicate that plus drop the link
  390. if (pFMD->ulFFlags & FFLAGS_FINAL_HARD_DISCONNECT)
  391. {
  392. DPFX(DPFPREP,7, "(%p) Final HARD_DISCONNECT completed", pEPD);
  393. CompleteHardDisconnect(pEPD);
  394. //above call drops the ep lock
  395. Lock(&pEPD->EPLock);
  396. }
  397. else if (pFMD->ulFFlags & FFLAGS_FINAL_ACK)
  398. {
  399. pEPD->ulEPFlags |= EPFLAGS_ACKED_DISCONNECT;
  400. // It is okay if our disconnect hasn't completed in the SP yet, the frame count code will handle that.
  401. // Note that this would be an abnormal case to have the SP not have completed the frame, but an ACK
  402. // for it to have already arrived, but it is certainly possible.
  403. if (pEPD->ulEPFlags & EPFLAGS_DISCONNECT_ACKED)
  404. {
  405. DPFX(DPFPREP,7, "(%p) Final ACK completed and our EOS ACK'd, dropping link", pEPD);
  406. DropLink(pEPD); // Drops EPLock
  407. Lock(&pEPD->EPLock);
  408. }
  409. else
  410. {
  411. DPFX(DPFPREP,7, "(%p) Final ACK completed, still awaiting ACK on our EOS", pEPD);
  412. }
  413. }
  414. RELEASE_EPD(pEPD, "UNLOCK (CFrame Cmd Complete)"); // Release EndPoint before releasing frame, releases EPLock
  415. RELEASE_FMD(pFMD, "Final Release on Complete"); // Release Frame
  416. break;
  417. }
  418. case COMMAND_ID_LISTEN:
  419. #ifndef DPNBUILD_NOMULTICAST
  420. case COMMAND_ID_LISTEN_MULTICAST:
  421. #endif // ! DPNBUILD_NOMULTICAST
  422. {
  423. pMSD = (PMSD) Context;
  424. ASSERT_MSD(pMSD);
  425. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL ); // Command can complete before hCommmand is set up
  426. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  427. 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);
  428. Lock(&pMSD->CommandLock);
  429. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); // clear InSP flag
  430. #ifdef DBG
  431. Lock(&pSPD->SPLock);
  432. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  433. {
  434. pMSD->blSPLinkage.RemoveFromList();
  435. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  436. }
  437. Unlock(&pSPD->SPLock);
  438. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  439. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  440. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  441. #endif // DBG
  442. // Leave lock while calling into higher layer
  443. Unlock( &pMSD->CommandLock );
  444. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  445. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteListenTerminate, hr[%x], Core Context[%p]", pMSD, hr, pMSD->Context);
  446. pSPD->pPData->pfVtbl->CompleteListenTerminate(pSPD->pPData->Parent, pMSD->Context, hr);
  447. // Release the final reference on the MSD AFTER indicating to the Core
  448. Lock(&pMSD->CommandLock);
  449. RELEASE_MSD(pMSD, "SP Ref");
  450. // Base ref will be released when DoCancel completes
  451. break;
  452. }
  453. case COMMAND_ID_ENUM:
  454. {
  455. pMSD = static_cast<PMSD>( Context );
  456. ASSERT_MSD( pMSD );
  457. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL );
  458. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  459. 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);
  460. Lock( &pMSD->CommandLock );
  461. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);
  462. #ifdef DBG
  463. Lock( &pSPD->SPLock );
  464. if ( ( pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST ) != 0 )
  465. {
  466. pMSD->blSPLinkage.RemoveFromList();
  467. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  468. }
  469. Unlock( &pSPD->SPLock );
  470. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  471. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  472. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  473. #endif // DBG
  474. // Leave lock while calling into higher layer
  475. Unlock( &pMSD->CommandLock );
  476. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  477. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteEnumQuery, hr[%x], Core Context[%p]", pMSD, hr, pMSD->Context);
  478. pSPD->pPData->pfVtbl->CompleteEnumQuery(pSPD->pPData->Parent, pMSD->Context, hr);
  479. // Release the final reference on the MSD AFTER indicating to the Core
  480. Lock( &pMSD->CommandLock );
  481. DECREMENT_MSD( pMSD, "SP Ref"); // SP is done
  482. RELEASE_MSD( pMSD, "Release On Complete" ); // Base Reference
  483. break;
  484. }
  485. case COMMAND_ID_ENUMRESP:
  486. {
  487. pMSD = static_cast<PMSD>( Context );
  488. ASSERT_MSD( pMSD );
  489. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL );
  490. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  491. 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);
  492. Lock( &pMSD->CommandLock );
  493. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);
  494. #ifdef DBG
  495. Lock( &pSPD->SPLock );
  496. if ( ( pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST ) != 0 )
  497. {
  498. pMSD->blSPLinkage.RemoveFromList();
  499. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  500. }
  501. Unlock( &pSPD->SPLock );
  502. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  503. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  504. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  505. #endif // DBG
  506. // Leave lock while calling into higher layer
  507. Unlock( &pMSD->CommandLock );
  508. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  509. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteEnumResponse, hr[%x], Core Context[%p], hr[%x]", pMSD, hr, pMSD->Context, hr);
  510. pSPD->pPData->pfVtbl->CompleteEnumResponse(pSPD->pPData->Parent, pMSD->Context, hr);
  511. // Release the final reference on the MSD AFTER indicating to the Core
  512. Lock( &pMSD->CommandLock );
  513. DECREMENT_MSD( pMSD, "SP Ref" ); // SP is done
  514. RELEASE_MSD( pMSD, "Release On Complete" ); // Base Reference
  515. break;
  516. }
  517. #ifndef DPNBUILD_NOMULTICAST
  518. case COMMAND_ID_CONNECT_MULTICAST_RECEIVE:
  519. case COMMAND_ID_CONNECT_MULTICAST_SEND:
  520. {
  521. void *pvContext = NULL;
  522. pMSD = static_cast<PMSD>( Context );
  523. ASSERT_MSD( pMSD );
  524. ASSERT( pMSD->hCommand == Handle || pMSD->hCommand == NULL );
  525. ASSERT( pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER );
  526. DPFX(DPFPREP,DPF_CALLIN_LVL, "(%p) CommandComplete called for COMMAND_ID_MULTICAST_CONNECT, pMSD[%p], pSPD[%p], Handle[%p], hCommand[%p], hr[%x]", pMSD->pEPD, pMSD, pSPD, Handle, pMSD->hCommand, hr);
  527. Lock(&pMSD->CommandLock); // must do this before clearing IN_SP flag
  528. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); // clear InSP flag
  529. #ifdef DBG
  530. Lock( &pSPD->SPLock );
  531. if ( ( pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST ) != 0 )
  532. {
  533. pMSD->blSPLinkage.RemoveFromList();
  534. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  535. }
  536. Unlock( &pSPD->SPLock );
  537. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  538. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  539. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  540. #endif // DBG
  541. pEPD = pMSD->pEPD;
  542. if (pEPD)
  543. {
  544. //
  545. // We will pass up the endpoint if it exists and remove the EPD reference from the MSD and vice versa
  546. //
  547. ASSERT_EPD(pEPD);
  548. Lock(&pEPD->EPLock);
  549. ASSERT(pEPD->pCommand == pMSD);
  550. pEPD->pCommand = NULL;
  551. DECREMENT_MSD(pMSD, "EPD Ref"); // Release Reference from EPD
  552. Unlock(&pEPD->EPLock);
  553. pMSD->pEPD = NULL;
  554. }
  555. // Leave lock while calling into higher layer
  556. Unlock( &pMSD->CommandLock );
  557. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  558. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteMulticastConnect, hr[%x], Core Context[%p], endpoint [%x]", pMSD, hr, pMSD->Context, pMSD->hListenEndpoint);
  559. pSPD->pPData->pfVtbl->CompleteMulticastConnect(pSPD->pPData->Parent, pMSD->Context, hr, pEPD, &pvContext);
  560. if (pEPD)
  561. {
  562. Lock(&pEPD->EPLock);
  563. pEPD->Context = pvContext;
  564. Unlock(&pEPD->EPLock);
  565. }
  566. // Release the final reference on the MSD AFTER indicating to the Core
  567. Lock( &pMSD->CommandLock );
  568. DECREMENT_MSD( pMSD, "SP Ref" ); // SP is done
  569. RELEASE_MSD( pMSD, "Release On Complete" ); // Base Reference
  570. break;
  571. }
  572. #endif // DPNBUILD_NOMULTICAST
  573. default:
  574. {
  575. DPFX(DPFPREP,0, "CommandComplete called with unknown CommandID");
  576. ASSERT(0);
  577. break;
  578. }
  579. } // SWITCH
  580. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  581. return DPN_OK;
  582. }
  583. /*
  584. ** Update Xmit State
  585. **
  586. ** There are two elements to the remote rcv state delivered in each frame. There is
  587. ** the NSeq number which acknowledges ALL frames with smaller sequence numbers,
  588. ** and there is the bitmask which acknowledges specific frames starting with NSeq+1.
  589. **
  590. ** Frames prior to NSeq can be removed from the SendWindow. Frames acked by bits
  591. ** should be marked as acknowledged, but left in the window until covered by NSeq
  592. ** (because a protocol can renege on bit-acked frames).
  593. **
  594. ** We will walk through the send window queue, starting with the oldest frame,
  595. ** and remove each frame that has been acknowledged by NSeq. As we hit EOM frames,
  596. ** we will indicate SendComplete for the message. If the bitmask is non-zero we may
  597. ** trigger retransmission of the missing frames. I say 'may' because we dont want
  598. ** to send too many retranmissions of the same frame...
  599. **
  600. ** SOME MILD INSANITY: Doing the DropLink code now. There are several places where
  601. ** we release the EPD Locks in the code below, and any time we arent holding the locks
  602. ** someone can start terminating the link. Therefore, whenever we retake either EPD lock
  603. ** (State or SendQ) after yielding them, we must re-verify that EPFLAGS_CONNECTED is still
  604. ** set and be prepared to abort if it is not. Happily, the whole EPD wont go away on us
  605. ** because we have a RefCnt on it, but once CONNECTED has been cleared we dont want to go
  606. ** setting any more timers or submitting frames to the SP.
  607. **
  608. ** RE_WRITE TIME: We can be re-entered while User Sends are being completed. This is okay
  609. ** except for the chance that the second thread would blow through here and hit the rest
  610. ** of CrackSequential before us. CrackSeq would think it got an out of order frame (it had)
  611. ** and would issue a NACK before we could stop him. Easiest solution is to delay the callback
  612. ** of complete sends until the end of the whole receive operation (when we indicate receives
  613. ** for instance). Incoming data should have priority over completing sends anyhow...
  614. **
  615. ** ** ENTERED AND EXITS WITH EPD->EPLOCK HELD **
  616. */
  617. #undef DPF_MODNAME
  618. #define DPF_MODNAME "UpdateXmitState"
  619. VOID
  620. UpdateXmitState(PEPD pEPD, BYTE bNRcv, ULONG RcvMaskLow, ULONG RcvMaskHigh, DWORD tNow)
  621. {
  622. PSPD pSPD;
  623. PFMD pFMD, pRealFMD;
  624. PMSD pMSD;
  625. CBilink *pLink;
  626. UINT tDelay;
  627. UINT uiRTT;
  628. BOOL ack;
  629. BOOL fRemoveRetryRef;
  630. pSPD = pEPD->pSPD;
  631. ASSERT_SPD(pSPD);
  632. ack = FALSE;
  633. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  634. if(RcvMaskLow | RcvMaskHigh)
  635. {
  636. DPFX(DPFPREP,7, "(%p) *NACK RCVD* NRcv=%x, MaskL=%x, MaskH=%x", pEPD, bNRcv, RcvMaskLow, RcvMaskHigh);
  637. }
  638. // The caller should have checked this
  639. ASSERT( pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED );
  640. #ifdef DBG
  641. // There should always be a timer running on the first frame in window
  642. if(!pEPD->blSendWindow.IsEmpty())
  643. {
  644. pFMD = CONTAINING_OBJECT(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  645. ASSERT_FMD(pFMD);
  646. ASSERT(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET);
  647. }
  648. pFMD = NULL;
  649. #endif // DBG
  650. // The send window contains a sorted list of frames that we have sent, but have not received ACKs
  651. // for. pEPD->uiUnackedFrames contains the count of items in this list.
  652. while(!pEPD->blSendWindow.IsEmpty())
  653. {
  654. // Grab the first item in the list
  655. pFMD = CONTAINING_OBJECT((pLink = pEPD->blSendWindow.GetNext()), FMD, blWindowLinkage);
  656. ASSERT_FMD(pFMD);
  657. // Let's try taking one sample from every group of acknowledgements
  658. // ALWAYS SAMPLE THE HIGHEST NUMBERED FRAME COVERED BY THIS ACK
  659. if(!(RcvMaskLow | RcvMaskHigh) &&
  660. ((PDFRAME) pFMD->ImmediateData)->bSeq == (bNRcv - 1))
  661. {
  662. // Update the bHighestAck member and take a new RTT
  663. if ((BYTE)(((PDFRAME) pFMD->ImmediateData)->bSeq - pEPD->bHighestAck) <= MAX_RECEIVE_RANGE)
  664. {
  665. pEPD->bHighestAck = ((PDFRAME) pFMD->ImmediateData)->bSeq;
  666. DPFX(DPFPREP, 7, "(%p) Highest ACK is now: %x", pEPD, pEPD->bHighestAck);
  667. uiRTT = tNow - pFMD->dwFirstSendTime;
  668. ASSERT(!(uiRTT & 0x80000000));
  669. UpdateEndPoint(pEPD, uiRTT, tNow);
  670. }
  671. }
  672. // If bNRcv for the other side is higher than this frame's bSeq, we know the other side has
  673. // seen this frame, so it is ACK'd and we will remove it from the Send Window.
  674. if((BYTE)((bNRcv) - (((PDFRAME) pFMD->ImmediateData)->bSeq + 1)) < (BYTE) pEPD->uiUnackedFrames)
  675. {
  676. ASSERT(pFMD->ulFFlags & FFLAGS_IN_SEND_WINDOW);
  677. DPFX(DPFPREP,7, "(%p) Removing Frame %x (0x%p, fflags=0x%x) from send window (unacked frames 1/%u, bytes %u/%u)",
  678. pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD, pFMD->ulFFlags, pEPD->uiUnackedFrames, pFMD->uiFrameLength, pEPD->uiUnackedBytes);
  679. pFMD->blWindowLinkage.RemoveFromList(); // Remove frame from send window
  680. pFMD->ulFFlags &= ~(FFLAGS_IN_SEND_WINDOW); // Clear flag
  681. //
  682. // Mark successful transmission of this frame in drop mask
  683. //
  684. if (pEPD->dwDropBitMask)
  685. {
  686. if (pEPD->dwDropBitMask & 0x80000000)
  687. {
  688. pEPD->uiDropCount--;
  689. }
  690. pEPD->dwDropBitMask = pEPD->dwDropBitMask << 1;
  691. DPFX(DPFPREP,7, "(%p) Drop Count %d, Drop Bit Mask 0x%lx", pEPD,pEPD->uiDropCount,pEPD->dwDropBitMask);
  692. }
  693. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  694. if(!(pEPD->ulEPFlags2 & EPFLAGS2_DEBUG_NO_RETRIES))
  695. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  696. {
  697. if(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET)
  698. {
  699. ASSERT(ack == FALSE);
  700. ASSERT(pEPD->RetryTimer != 0);
  701. DPFX(DPFPREP,7, "(%p) Cancelling Retry Timer", pEPD);
  702. if(CancelProtocolTimer(pSPD, pEPD->RetryTimer, pEPD->RetryTimerUnique) == DPN_OK)
  703. {
  704. DECREMENT_EPD(pEPD, "UNLOCK (cancel retry timer)"); // SPLock not already held
  705. }
  706. else
  707. {
  708. DPFX(DPFPREP,7, "(%p) Cancelling Retry Timer Failed", pEPD);
  709. }
  710. pEPD->RetryTimer = 0; // This will cause event to be ignored if it runs
  711. pFMD->ulFFlags &= ~(FFLAGS_RETRY_TIMER_SET);
  712. }
  713. }
  714. pEPD->uiUnackedFrames--; // track size of window
  715. ASSERT(pEPD->uiUnackedFrames <= MAX_RECEIVE_RANGE);
  716. pEPD->uiUnackedBytes -= pFMD->uiFrameLength;
  717. ASSERT(pEPD->uiUnackedBytes <= MAX_RECEIVE_RANGE * pSPD->uiFrameLength);
  718. pEPD->uiBytesAcked += pFMD->uiFrameLength;
  719. // If the frame has been queued for a retry, pull it off
  720. // NOTE: Copied retries of this frame may still be on the retry queue, inefficient to send them out, but okay
  721. if (pFMD->ulFFlags & FFLAGS_RETRY_QUEUED)
  722. {
  723. pFMD->blQLinkage.RemoveFromList();
  724. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  725. fRemoveRetryRef = TRUE;
  726. DECREMENT_EPD(pEPD, "UNLOCK (Releasing Retry Frame)"); // SPLock not already held
  727. if ((pFMD->CommandID == COMMAND_ID_COPIED_RETRY) ||
  728. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  729. {
  730. DECREMENT_EPD(pEPD, "UNLOCK (Copy Complete)"); // SPLock not already held
  731. }
  732. RELEASE_FMD(pFMD, "SP Submit");
  733. if (pEPD->blRetryQueue.IsEmpty())
  734. {
  735. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  736. }
  737. }
  738. else
  739. {
  740. fRemoveRetryRef = FALSE;
  741. }
  742. // Get the first FMD to work with
  743. if ((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) ||
  744. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  745. {
  746. pRealFMD = CONTAINING_OBJECT(pFMD->blCoalesceLinkage.GetNext(), FMD, blCoalesceLinkage);
  747. ASSERT_FMD(pRealFMD);
  748. // If there were no reliable frames coalesced, then the list might be empty.
  749. #ifdef DBG
  750. if (pRealFMD == pFMD)
  751. {
  752. ASSERT((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) && (! (pFMD->ulFFlags & FFLAGS_RELIABLE)));
  753. }
  754. #endif // DBG
  755. }
  756. else
  757. {
  758. pRealFMD = pFMD;
  759. }
  760. // For each FMD in the message, inform it of the ACK
  761. while(TRUE)
  762. {
  763. if (pRealFMD->tAcked == -1)
  764. {
  765. pRealFMD->tAcked = tNow;
  766. }
  767. if (fRemoveRetryRef)
  768. {
  769. pMSD = pRealFMD->pMSD;
  770. ASSERT_MSD(pMSD);
  771. pMSD->uiFrameCount--; // Protected by EPLock, retries count against outstanding frame count
  772. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Retry frame reference decremented on ACK, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  773. // If this is a coalesced subframe, remove the EPD and FMD references as well.
  774. if (pRealFMD != pFMD)
  775. {
  776. DECREMENT_EPD(pEPD, "UNLOCK (retry rely frame coalesce)");
  777. RELEASE_FMD(pRealFMD, "SP retry submit (coalesce)");
  778. }
  779. }
  780. // One more send complete
  781. // We will come down this path for Reliables, KeepAlives, and Disconnects
  782. // Datagrams are completed upon send completion and do not wait for an ACK
  783. if((pRealFMD->CommandID != COMMAND_ID_SEND_DATAGRAM) && (pRealFMD->ulFFlags & (FFLAGS_END_OF_MESSAGE | FFLAGS_END_OF_STREAM)))
  784. {
  785. if (pRealFMD->CommandID != COMMAND_ID_SEND_COALESCE)
  786. {
  787. ASSERT(pRealFMD->CommandID != COMMAND_ID_COPIED_RETRY_COALESCE);
  788. pMSD = pRealFMD->pMSD;
  789. ASSERT_MSD(pMSD);
  790. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Flagging Complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  791. pMSD->ulMsgFlags2 |= MFLAGS_TWO_SEND_COMPLETE; // Mark this complete
  792. if (pMSD->uiFrameCount == 0) // Protected by EPLock
  793. {
  794. pEPD->ulEPFlags |= EPFLAGS_COMPLETE_SENDS;
  795. }
  796. }
  797. else
  798. {
  799. // Should only happen for all-datagram coalesced sends (see above).
  800. ASSERT(pRealFMD == pFMD);
  801. }
  802. }
  803. else
  804. {
  805. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "ACK for frame 0x%p, command ID %u, flags 0x%08x", pRealFMD, pRealFMD->CommandID, pRealFMD->ulFFlags);
  806. }
  807. // If this is a coalesced packet, get the next FMD to work with
  808. pRealFMD = CONTAINING_OBJECT(pRealFMD->blCoalesceLinkage.GetNext(), FMD, blCoalesceLinkage);
  809. ASSERT_FMD(pRealFMD);
  810. if (pRealFMD == pFMD)
  811. {
  812. break;
  813. }
  814. }
  815. RELEASE_FMD(pFMD, "Send Window"); // Release reference for send window
  816. ack = TRUE;
  817. }
  818. else
  819. {
  820. break; // First unacked frame, we can stop checking list
  821. }
  822. } // WHILE (send window not empty)
  823. // At this point we have completed all of the frames ack'd by NRcv. We would now like to re-transmit
  824. // any frames NACK'd by bitmask (and mark the ones ACK'd by bitmask). Now remember, the first frame in
  825. // the window is automatically missing by the implied first zero-bit.
  826. //
  827. // We will retransmit ALL frames that appear to be missing. There may be a timer running on
  828. // the first frame, but only if we did not ACK any frames in the code above (ack == 0).
  829. //
  830. // Hmmm, if the partner has a fat pipeline we could see this bitmap lots of times. We need to make
  831. // sure we don't trigger a retransmission here a quarter-zillion times during the Ack latency period.
  832. // To solve this we will only re-xmit the first time we see this bit. After that, we will have to
  833. // wait around for the next RetryTimeout. I think that's just the way its going to have to be.
  834. //
  835. // OTHER THINGS WE KNOW:
  836. //
  837. // There must be at least two frames remaining in the SendWindow. At minimum, first frame missing (always)
  838. // and then at least one SACK'd frame after.
  839. //
  840. // pLink = first queue element in SendWindow
  841. // pFMD = first frame in SendWindow
  842. //
  843. // We are still Holding EPD->EPLock. It is okay to take SPD->SPLock while holding it.
  844. //
  845. // One More Problem: Since SP has changed its receive buffer logic mis-ordering of frames has become
  846. // quite commonplace. This means that our assumptions about the state of the SendWindow are not necessarily true.
  847. // This means that frames NACKed by bitmask may have been acknowleged by a racing frame. This means that the
  848. // SendWindow may not be in sync with the mask at all. This means we need to synchronize the bitmask with the
  849. // actual send window. This is done by right-shifting the mask for each frame that's been acknowleged since the
  850. // bitmask was minted before beginning the Selective Ack process.
  851. // NOTE: If everything was removed from the Send Window above, then pLink and pFMD will
  852. // be garbage. In that case we would expect the mask to be NULL after adjusting below.
  853. if((RcvMaskLow | RcvMaskHigh) &&
  854. (pEPD->uiUnackedFrames > 1) &&
  855. (bNRcv == ((PDFRAME) pFMD->ImmediateData)->bSeq) // Check for old ACK, no useful data
  856. )
  857. {
  858. ASSERT(pLink == pEPD->blSendWindow.GetNext());
  859. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  860. if(!(pEPD->ulEPFlags2 & EPFLAGS2_DEBUG_NO_RETRIES))
  861. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  862. {
  863. // See if the first frame in the window has already been retried
  864. if(pFMD->uiRetry == 0)
  865. {
  866. // Receiving a frame later than the first one in the window tells us that the
  867. // first frame in the window should have been received by now. We will
  868. // cut short the retry timer and only wait a little longer in case the frame
  869. // is here but got indicated out of order. If the retry timer had less
  870. // than 10ms to go, no big deal, we will just add a small amount of delay to it.
  871. DPFX(DPFPREP,7, "(%p) Resetting Retry Timer for 10ms", pEPD);
  872. if (pEPD->RetryTimer)
  873. {
  874. if(CancelProtocolTimer(pSPD, pEPD->RetryTimer, pEPD->RetryTimerUnique) == DPN_OK)
  875. {
  876. DECREMENT_EPD(pEPD, "UNLOCK (cancel retry timer)"); // SPLock not already held
  877. }
  878. else
  879. {
  880. DPFX(DPFPREP,7, "(%p) Cancelling Retry Timer Failed", pEPD);
  881. }
  882. }
  883. LOCK_EPD(pEPD, "LOCK (retry timer - nack quick set)"); // Could not cancel- therefore we must balance RefCnt
  884. ScheduleProtocolTimer(pSPD, 10, 5, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique );
  885. pFMD->ulFFlags |= FFLAGS_RETRY_TIMER_SET;
  886. }
  887. }
  888. // If pLink gets to the end of the list, the receive mask contained more bits than there were
  889. // items in the send window even after it was adjusted. This means the packet was bogus, and
  890. // we have probably hosed our state already, but we will go ahead and attempt to safeguard
  891. // against having an AV by not entering the loop with a bad pFMD from hitting the end of the list.
  892. while((RcvMaskLow | RcvMaskHigh) && pLink != &pEPD->blSendWindow)
  893. {
  894. pFMD = CONTAINING_OBJECT(pLink, FMD, blWindowLinkage);
  895. ASSERT_FMD(pFMD);
  896. pLink = pLink->GetNext(); // Advance pLink to next frame in SendWindow
  897. // Only update on the highest frame
  898. if ((RcvMaskLow|RcvMaskHigh) == 1)
  899. {
  900. // Update the bHighestAck member
  901. if ((BYTE)(((PDFRAME) pFMD->ImmediateData)->bSeq - pEPD->bHighestAck) <= MAX_RECEIVE_RANGE)
  902. {
  903. pEPD->bHighestAck = ((PDFRAME) pFMD->ImmediateData)->bSeq;
  904. DPFX(DPFPREP, 7, "(%p) Highest ACK is now: %x", pEPD, pEPD->bHighestAck);
  905. uiRTT = tNow - pFMD->dwFirstSendTime;
  906. ASSERT(!(uiRTT & 0x80000000));
  907. UpdateEndPoint(pEPD, uiRTT, tNow);
  908. }
  909. pFMD = NULL; // Make sure we don't use it again
  910. }
  911. RIGHT_SHIFT_64(RcvMaskHigh, RcvMaskLow); // 64 bit logical shift right, skip the zero
  912. } // END WHILE (WORK MASKS NON-ZERO)
  913. }
  914. // If we acked a frame above and there is more data outstanding then we may need to start a new Retry timer.
  915. //
  916. // Of course, we want to set the timer on whatever frame is the first in the SendWindow.
  917. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  918. if(!(pEPD->ulEPFlags2 & EPFLAGS2_DEBUG_NO_RETRIES))
  919. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  920. {
  921. if( (pEPD->uiUnackedFrames > 0) && (pEPD->RetryTimer == 0))
  922. {
  923. ASSERT(ack);
  924. pFMD = CONTAINING_OBJECT(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  925. ASSERT_FMD(pFMD);
  926. tDelay = tNow - pFMD->dwLastSendTime; // How long has this frame been enroute?
  927. tDelay = (tDelay > pEPD->uiRetryTimeout) ? 0 : pEPD->uiRetryTimeout - tDelay; // Calc time remaining for frame
  928. DPFX(DPFPREP,7, "(%p) Setting Retry Timer for %dms on Seq=[%x], FMD=[%p]", pEPD, tDelay, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  929. LOCK_EPD(pEPD, "LOCK (retry timer)"); // bump RefCnt for timer
  930. ScheduleProtocolTimer(pSPD, tDelay, 0, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique );
  931. pFMD->ulFFlags |= FFLAGS_RETRY_TIMER_SET;
  932. }
  933. }
  934. // See if we need to unblock this session
  935. if((pEPD->uiUnackedFrames < pEPD->uiWindowF) && (pEPD->uiUnackedBytes < pEPD->uiWindowB))
  936. {
  937. pEPD->ulEPFlags |= EPFLAGS_STREAM_UNBLOCKED;
  938. if((pEPD->ulEPFlags & EPFLAGS_SDATA_READY) && ((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0))
  939. {
  940. // NOTE: We can get in here if we ack'd something above OR if GrowSendWindow grew the
  941. // window as a result of calling UpdateEndpoint.
  942. DPFX(DPFPREP,7, "(%p) UpdateXmit: ReEntering Pipeline", pEPD);
  943. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  944. LOCK_EPD(pEPD, "LOCK (pipeline)");
  945. ScheduleProtocolWork(pSPD, ScheduledSend, pEPD);
  946. }
  947. }
  948. else
  949. {
  950. // Make sure that there is at least 1 frame unacked. We can't assert that the unacked byte count
  951. // is at least 1 because datagrams have their byte count subtracted when RetryTimeout fires.
  952. ASSERT(pEPD->uiUnackedFrames > 0);
  953. }
  954. }
  955. /*
  956. ** Complete Datagram Frame
  957. **
  958. ** A datagram frame has been successfully transmitted. Free the descriptor and
  959. ** see if the entire send is ready to complete. Reliable sends are not freed until
  960. ** they are acknowledged, so they must be handled elsewhere.
  961. **
  962. ** ** This is called with the CommandLock in MSD held, returns with it released **
  963. */
  964. #undef DPF_MODNAME
  965. #define DPF_MODNAME "CompleteDatagramSend"
  966. VOID CompleteDatagramSend(PSPD pSPD, PMSD pMSD, HRESULT hr)
  967. {
  968. PEPD pEPD = pMSD->pEPD;
  969. ASSERT_EPD(pEPD);
  970. PFMD pFMD = CONTAINING_OBJECT(pMSD->blFrameList.GetNext(), FMD, blMSDLinkage);
  971. ASSERT_FMD(pFMD);
  972. ASSERT(pMSD->uiFrameCount == 0);
  973. #ifdef DBG
  974. ASSERT((pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED)==0);
  975. #endif // DBG
  976. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  977. Lock(&pEPD->EPLock); // Need EPLock to change MFLAGS_TWO
  978. DPFX(DPFPREP,7, "(%p) DG MESSAGE COMPLETE pMSD=%p", pEPD, pMSD);
  979. pMSD->ulMsgFlags2 |= MFLAGS_TWO_SEND_COMPLETE; // Mark this complete
  980. if(pMSD->TimeoutTimer != NULL)
  981. {
  982. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer", pEPD);
  983. if(CancelProtocolTimer(pSPD, pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  984. {
  985. DECREMENT_MSD(pMSD, "Send Timeout Timer");
  986. }
  987. else
  988. {
  989. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer Failed", pEPD);
  990. }
  991. pMSD->TimeoutTimer = NULL;
  992. }
  993. #ifdef DBG
  994. Lock(&pSPD->SPLock);
  995. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  996. {
  997. pMSD->blSPLinkage.RemoveFromList(); // Remove MSD from master command list
  998. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  999. }
  1000. Unlock(&pSPD->SPLock);
  1001. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  1002. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  1003. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  1004. #endif // DBG
  1005. if(hr == DPNERR_USERCANCEL)
  1006. {
  1007. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_TIMEDOUT)
  1008. {
  1009. hr = DPNERR_TIMEDOUT;
  1010. }
  1011. }
  1012. // If this was a coalesced send, remove it from the list (protected by EPD lock).
  1013. if (pFMD->pCSD != NULL)
  1014. {
  1015. ASSERT(pFMD->blCoalesceLinkage.IsListMember(&pFMD->pCSD->blCoalesceLinkage));
  1016. pFMD->blCoalesceLinkage.RemoveFromList();
  1017. RELEASE_FMD(pFMD->pCSD, "Coalesce linkage (datagram complete)");
  1018. pFMD->pCSD = NULL;
  1019. }
  1020. Unlock(&pEPD->EPLock);
  1021. Unlock(&pMSD->CommandLock); // Leave the lock before calling into another layer
  1022. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  1023. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteSend for NG, hr[%x], pMSD[%p], Core Context[%p]", pEPD, hr, pMSD, pMSD->Context);
  1024. pSPD->pPData->pfVtbl->CompleteSend(pSPD->pPData->Parent, pMSD->Context, hr, -1, 0);
  1025. // Release the final reference on the MSD AFTER indicating to the Core
  1026. Lock(&pMSD->CommandLock);
  1027. // Cancels are allowed to come in until the Completion has returned and they will expect a valid pMSD->pEPD
  1028. Lock(&pEPD->EPLock);
  1029. pMSD->pEPD = NULL; // We shouldn't be using this after this
  1030. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  1031. RELEASE_MSD(pMSD, "Release On Complete"); // Return resources, including all frames, release MSDLock
  1032. RELEASE_EPD(pEPD, "UNLOCK (Complete Send Cmd - DG)"); // Every send command bumps the refcnt, releases EPLock
  1033. }
  1034. /*
  1035. ** Complete Reliable Send
  1036. **
  1037. ** A reliable send has completed processing. Indicate this
  1038. ** to the user and free the resources. This will either take
  1039. ** place on a cancel, error, or when ALL of the message's frames
  1040. ** have been acknowledged.
  1041. **
  1042. ** ** This is called with CommandLock in MSD held, and exits with it released **
  1043. */
  1044. #undef DPF_MODNAME
  1045. #define DPF_MODNAME "CompleteReliableSend"
  1046. VOID
  1047. CompleteReliableSend(PSPD pSPD, PMSD pMSD, HRESULT hr)
  1048. {
  1049. PEPD pEPD = pMSD->pEPD;
  1050. ASSERT_EPD(pEPD);
  1051. PFMD pFMD = CONTAINING_OBJECT(pMSD->blFrameList.GetNext(), FMD, blMSDLinkage);
  1052. ASSERT_FMD(pFMD);
  1053. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  1054. ASSERT(pMSD->uiFrameCount == 0);
  1055. // NORMAL SEND COMPLETES
  1056. if(pMSD->CommandID == COMMAND_ID_SEND_RELIABLE)
  1057. {
  1058. DPFX(DPFPREP,7, "(%p) Reliable Send Complete pMSD=%p", pEPD, pMSD);
  1059. #ifdef DBG
  1060. ASSERT((pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED)==0);
  1061. #endif // DBG
  1062. if(pMSD->TimeoutTimer != NULL)
  1063. {
  1064. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer, pMSD[%p]", pEPD, pMSD);
  1065. if(CancelProtocolTimer(pSPD, pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  1066. {
  1067. DECREMENT_MSD(pMSD, "Send Timeout Timer");
  1068. }
  1069. else
  1070. {
  1071. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer Failed, pMSD[%p]", pEPD, pMSD);
  1072. }
  1073. pMSD->TimeoutTimer = NULL;
  1074. }
  1075. // ACK code in UpdateXmitState flags this as COMPLETE when the last of the message is received.
  1076. #ifdef DBG
  1077. Lock(&pSPD->SPLock);
  1078. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)
  1079. {
  1080. pMSD->blSPLinkage.RemoveFromList(); // Remove MSD from master command list
  1081. pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
  1082. }
  1083. Unlock(&pSPD->SPLock);
  1084. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_COMPLETED_TO_CORE));
  1085. pMSD->ulMsgFlags1 |= MFLAGS_ONE_COMPLETED_TO_CORE;
  1086. pMSD->CallStackCoreCompletion.NoteCurrentCallStack();
  1087. #endif // DBG
  1088. Unlock(&pMSD->CommandLock); // Leave the lock before calling into another layer
  1089. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  1090. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->CompleteSend for G, hr[%x], pMSD[%p], Core Context[%p], RTT[%d], RetryCount[%d]", pEPD, hr, pMSD, pMSD->Context, pFMD->tAcked == -1 ? -1 : pFMD->tAcked - pFMD->dwFirstSendTime, pFMD->uiRetry);
  1091. pSPD->pPData->pfVtbl->CompleteSend(pSPD->pPData->Parent, pMSD->Context, hr, pFMD->tAcked == -1 ? -1 : pFMD->tAcked - pFMD->dwFirstSendTime, pFMD->uiRetry);
  1092. // Release the final reference on the MSD AFTER indicating to the Core
  1093. Lock(&pMSD->CommandLock);
  1094. // Cancels are allowed to come in until the Completion has returned and they will expect a valid pMSD->pEPD
  1095. Lock(&pEPD->EPLock);
  1096. pMSD->pEPD = NULL; // We shouldn't be using this after this
  1097. // If this was a coalesced send, remove it from the list (protected by EPD lock).
  1098. if (pFMD->pCSD != NULL)
  1099. {
  1100. ASSERT(pFMD->blCoalesceLinkage.IsListMember(&pFMD->pCSD->blCoalesceLinkage));
  1101. pFMD->blCoalesceLinkage.RemoveFromList();
  1102. RELEASE_FMD(pFMD->pCSD, "Coalesce linkage (reliable complete)");
  1103. pFMD->pCSD = NULL;
  1104. }
  1105. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  1106. RELEASE_MSD(pMSD, "Release On Complete"); // Return resources, including all frames
  1107. RELEASE_EPD(pEPD, "UNLOCK (Complete Send Cmd - Rely)"); // release hold on EPD for this send, releases EPLock
  1108. }
  1109. // END OF STREAM -OR- KEEPALIVE COMPLETES
  1110. else
  1111. {
  1112. // Partner has just ACKed our End Of Stream frame. Doesn't necessarily mean we are done.
  1113. // Both sides need to send (and have acknowledged) EOS frames before the link can be
  1114. // dropped. Therefore, we check to see if we have seen our partner's DISC before
  1115. // releasing the RefCnt on EPD allowing the link to drop. If partner was idle, his EOS
  1116. // might be the same frame which just ack'd us. Luckily, this code will run first so we
  1117. // will not have noticed his EOS yet, and we will not drop right here.
  1118. ASSERT(pMSD->ulMsgFlags2 & (MFLAGS_TWO_END_OF_STREAM | MFLAGS_TWO_KEEPALIVE));
  1119. Lock(&pEPD->EPLock);
  1120. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_KEEPALIVE)
  1121. {
  1122. DPFX(DPFPREP,7, "(%p) Keepalive Complete, pMSD[%p]", pEPD, pMSD);
  1123. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  1124. #ifdef DBG
  1125. ASSERT(!(pMSD->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST));
  1126. #endif // DBG
  1127. pMSD->pEPD = NULL; // We shouldn't be using this after this
  1128. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  1129. RELEASE_MSD(pMSD, "Release On Complete"); // Done with this message, releases MSDLock
  1130. RELEASE_EPD(pEPD, "UNLOCK (rel KeepAlive)"); // Release ref for this MSD, releases EPLock
  1131. }
  1132. else
  1133. {
  1134. DPFX(DPFPREP,7, "(%p) EndOfStream Complete, pMSD[%p]", pEPD, pMSD);
  1135. pEPD->ulEPFlags |= EPFLAGS_DISCONNECT_ACKED;
  1136. // It is okay if our disconnect hasn't completed in the SP yet, the frame count code will handle that.
  1137. // Note that this would be an abnormal case to have the SP not have completed the frame, but an ACK
  1138. // for it to have already arrived, but it is certainly possible.
  1139. if(pEPD->ulEPFlags & EPFLAGS_ACKED_DISCONNECT)
  1140. {
  1141. DPFX(DPFPREP,7, "(%p) EOS has been ACK'd and we've ACK'd partner's EOS, dropping link", pEPD);
  1142. // We are clear to blow this thing down
  1143. Unlock(&pMSD->CommandLock);
  1144. // This will set our state to terminating
  1145. DropLink(pEPD); // This unlocks the EPLock
  1146. }
  1147. else
  1148. {
  1149. // Our Disconnect frame has been acknowledged but we must wait until we see his DISC before
  1150. // completing this command and dropping the connection.
  1151. //
  1152. // We will use the pCommand pointer to track this disconnect command until we see partner's DISC frame
  1153. //
  1154. // ALSO, since our engine has now shutdown, we might wait forever now for the final DISC from partner
  1155. // if he crashes before transmitting it. One final safeguard here is to set a timer which will make sure
  1156. // this doesnt happen. * NOTE * no timer is actually being set here, we're depending on the keepalive
  1157. // timeout, see EndPointBackgroundProcess.
  1158. DPFX(DPFPREP,7, "(%p) EOS has been ACK'd, but we're still ACK'ing partner's disconnect", pEPD);
  1159. ASSERT(pEPD->blHighPriSendQ.IsEmpty());
  1160. ASSERT(pEPD->blNormPriSendQ.IsEmpty());
  1161. ASSERT(pEPD->blLowPriSendQ.IsEmpty());
  1162. // It is possible that something was already in the process of timing out when the disconnect
  1163. // operation starts such that AbortSends gets called and clears this.
  1164. ASSERT(pEPD->pCommand == NULL || pEPD->pCommand == pMSD);
  1165. Unlock(&pEPD->EPLock);
  1166. Unlock(&pMSD->CommandLock);
  1167. }
  1168. }
  1169. }
  1170. }
  1171. /*
  1172. ** Build Data Frame
  1173. **
  1174. ** Setup the actual network packet header for transmission with our current link state info (Seq, NRcv).
  1175. **
  1176. ** ** ENTERED AND EXITS WITH EPD->EPLOCK HELD **
  1177. */
  1178. #undef DPF_MODNAME
  1179. #define DPF_MODNAME "BuildDataFrame"
  1180. UNALIGNED ULONGLONG * BuildDataFrame(PEPD pEPD, PFMD pFMD, DWORD tNow)
  1181. {
  1182. PSPD pSPD = pEPD->pSPD;
  1183. PDFRAME pFrame;
  1184. UINT index = 0;
  1185. //if we need a full signature for the frame to be computed we track a pointer to its location
  1186. //in the header using this var. We return this to the caller, allowwing them to tweak the data frame
  1187. //after we've built and before it writes in the final sig
  1188. UNALIGNED ULONGLONG * pullFullSig=NULL;
  1189. //if we're build a coalesced frame we use this to hold the first reliable sub-frame we stick into it
  1190. //(if there is one at all). This is then used if the frame is a candidate to modify the local secret
  1191. PFMD pReliableFMD=NULL;
  1192. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1193. pFrame = (PDFRAME) pFMD->ImmediateData;
  1194. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt;
  1195. pFMD->uiRetry = 0;
  1196. pFrame->bCommand = pFMD->bPacketFlags;
  1197. pFrame->bControl = 0; // this sets retry count to zero as well as clearing flags
  1198. if (pFMD->ulFFlags & FFLAGS_END_OF_STREAM)
  1199. {
  1200. pFrame->bControl |= PACKET_CONTROL_END_STREAM;
  1201. //for pre dx9 protocol then we also have to flip a bit which indicates to receiver we want an immediate ack
  1202. //for dx9 onwards we always assume that anyway for EOS
  1203. if ((pEPD->ulEPFlags2 & EPFLAGS2_SUPPORTS_SIGNING)==0)
  1204. {
  1205. pFrame->bControl |= PACKET_CONTROL_CORRELATE;
  1206. }
  1207. }
  1208. // See if we are desiring an immediate response
  1209. if(pFMD->ulFFlags & FFLAGS_CHECKPOINT)
  1210. {
  1211. pFrame->bCommand |= PACKET_COMMAND_POLL;
  1212. }
  1213. pFrame->bSeq = pEPD->bNextSend++;
  1214. pFrame->bNRcv = pEPD->bNextReceive; // Acknowledges all previous frames
  1215. DPFX(DPFPREP,7, "(%p) N(S) incremented to %x", pEPD, pEPD->bNextSend);
  1216. // Piggyback NACK notes
  1217. //
  1218. // Since the SP is now frequently mis-ordering frames we are enforcing a back-off period before transmitting a NACK after
  1219. // a packet is received out of order. Therefore we have the Delayed Mask Timer which stalls the dedicated NACK. Now we must
  1220. // also make sure that the new NACK info doesn't get piggybacked too soon. Therefore we will test the tReceiveMaskDelta timestamp
  1221. // before including piggyback NACK info here, and make sure that the mask is at least 5ms old.
  1222. ULONG * rgMask=(ULONG * ) (pFrame+1);
  1223. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  1224. {
  1225. if((tNow - pEPD->tReceiveMaskDelta) > 4)
  1226. {
  1227. 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);
  1228. if(pEPD->ulReceiveMask)
  1229. {
  1230. rgMask[index++] = pEPD->ulReceiveMask;
  1231. pFrame->bControl |= PACKET_CONTROL_SACK_MASK1;
  1232. }
  1233. if(pEPD->ulReceiveMask2)
  1234. {
  1235. rgMask[index++] = pEPD->ulReceiveMask2;
  1236. pFrame->bControl |= PACKET_CONTROL_SACK_MASK2;
  1237. }
  1238. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  1239. }
  1240. else
  1241. {
  1242. DPFX(DPFPREP,7, "(%p) DECLINING TO PIGGYBACK NACK WITH SMALL TIME DELTA", pEPD);
  1243. }
  1244. }
  1245. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)
  1246. {
  1247. DPFX(DPFPREP,7, "(%p) Installing SENDMASK in DFRAME Seq=%x, Low=%x High=%x", pEPD, pFrame->bSeq, pEPD->ulSendMask, pEPD->ulSendMask2);
  1248. if(pEPD->ulSendMask)
  1249. {
  1250. rgMask[index++] = pEPD->ulSendMask;
  1251. pFrame->bControl |= PACKET_CONTROL_SEND_MASK1;
  1252. pEPD->ulSendMask = 0;
  1253. }
  1254. if(pEPD->ulSendMask2)
  1255. {
  1256. rgMask[index++] = pEPD->ulSendMask2;
  1257. pFrame->bControl |= PACKET_CONTROL_SEND_MASK2;
  1258. pEPD->ulSendMask2 = 0;
  1259. }
  1260. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_SENDMASK);
  1261. }
  1262. pFMD->uiImmediateLength = sizeof(DFRAME) + (index * sizeof(ULONG));
  1263. pFMD->dwFirstSendTime = tNow;
  1264. pFMD->dwLastSendTime = tNow;
  1265. //if we're fast signing the link we can stuff the local secret straight in after the masks
  1266. if (pEPD->ulEPFlags2 & EPFLAGS2_FAST_SIGNED_LINK)
  1267. {
  1268. *((UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength))=pEPD->ullCurrentLocalSecret;
  1269. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  1270. }
  1271. //otherwise if we're full signing it we need to reserve a zero'd out space for the sig and then return the offset
  1272. //to this sig. Just before sending the frame we'll then compute the hash and stuff it into this space
  1273. else if (pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK)
  1274. {
  1275. pullFullSig=(UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength);
  1276. *pullFullSig=0;
  1277. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  1278. }
  1279. if (pFMD->CommandID == COMMAND_ID_SEND_COALESCE)
  1280. {
  1281. COALESCEHEADER* paCoalesceHeaders;
  1282. DWORD dwNumCoalesceHeaders;
  1283. BUFFERDESC* pBufferDesc;
  1284. CBilink* pLink;
  1285. FMD* pRealFMD;
  1286. pFrame->bControl |= PACKET_CONTROL_COALESCE;
  1287. ASSERT(pFMD->SendDataBlock.dwBufferCount == 1);
  1288. ASSERT(pFMD->uiFrameLength == 0);
  1289. // Add in coalesce headers and copy the buffer descs for all of the subframes.
  1290. paCoalesceHeaders = (COALESCEHEADER*) (pFMD->ImmediateData + pFMD->uiImmediateLength);
  1291. dwNumCoalesceHeaders = 0;
  1292. pBufferDesc = pFMD->rgBufferList;
  1293. pLink = pFMD->blCoalesceLinkage.GetNext();
  1294. while (pLink != &pFMD->blCoalesceLinkage)
  1295. {
  1296. pRealFMD = CONTAINING_OBJECT(pLink, FMD, blCoalesceLinkage);
  1297. ASSERT_FMD(pRealFMD);
  1298. ASSERT((pRealFMD->CommandID == COMMAND_ID_SEND_DATAGRAM) || (pRealFMD->CommandID == COMMAND_ID_SEND_RELIABLE));
  1299. pRealFMD->dwFirstSendTime = tNow;
  1300. pRealFMD->dwLastSendTime = tNow;
  1301. //if we see a reliable subframe then hold onto a pointer to it. We may need its contents to modify
  1302. //the local secret next time we wrap the sequence space
  1303. if (pReliableFMD==NULL && pRealFMD->CommandID == COMMAND_ID_SEND_RELIABLE)
  1304. {
  1305. pReliableFMD=pRealFMD;
  1306. }
  1307. memcpy(&paCoalesceHeaders[dwNumCoalesceHeaders], pRealFMD->ImmediateData, sizeof(COALESCEHEADER));
  1308. ASSERT(dwNumCoalesceHeaders < MAX_USER_BUFFERS_IN_FRAME);
  1309. dwNumCoalesceHeaders++;
  1310. // Change the immediate data buffer desc to point to a zero padding buffer if this packet
  1311. // needs to be DWORD aligned, otherwise remove the immediate data pointer since we
  1312. // don't use it.
  1313. ASSERT(pRealFMD->SendDataBlock.pBuffers == (PBUFFERDESC) &pRealFMD->uiImmediateLength);
  1314. ASSERT(pRealFMD->SendDataBlock.dwBufferCount > 1);
  1315. ASSERT(pRealFMD->lpImmediatePointer == (pRealFMD->ImmediateData + 4));
  1316. ASSERT(*((DWORD*) pRealFMD->lpImmediatePointer) == 0);
  1317. if ((pFMD->uiFrameLength & 3) != 0)
  1318. {
  1319. pRealFMD->uiImmediateLength = 4 - (pFMD->uiFrameLength & 3);
  1320. }
  1321. else
  1322. {
  1323. pRealFMD->uiImmediateLength = 0;
  1324. pRealFMD->SendDataBlock.pBuffers = pRealFMD->rgBufferList;
  1325. pRealFMD->SendDataBlock.dwBufferCount--;
  1326. }
  1327. memcpy(pBufferDesc, pRealFMD->SendDataBlock.pBuffers, (pRealFMD->SendDataBlock.dwBufferCount * sizeof(BUFFERDESC)));
  1328. pBufferDesc += pRealFMD->SendDataBlock.dwBufferCount;
  1329. // Assert that this fits in pFMD->rgBufferList (use -1 because pFMD->ImmediateData doesn't count)
  1330. ASSERT((pFMD->SendDataBlock.dwBufferCount - 1) + pRealFMD->SendDataBlock.dwBufferCount <= MAX_USER_BUFFERS_IN_FRAME);
  1331. pFMD->SendDataBlock.dwBufferCount += pRealFMD->SendDataBlock.dwBufferCount;
  1332. ASSERT(pFMD->uiImmediateLength + sizeof(COALESCEHEADER) <= sizeof(pFMD->ImmediateData));
  1333. pFMD->uiImmediateLength += sizeof(COALESCEHEADER);
  1334. ASSERT(pFMD->uiFrameLength + pRealFMD->uiImmediateLength + pRealFMD->uiFrameLength < pSPD->uiUserFrameLength);
  1335. pFMD->uiFrameLength += pRealFMD->uiImmediateLength + pRealFMD->uiFrameLength;
  1336. pLink = pLink->GetNext();
  1337. }
  1338. ASSERT(dwNumCoalesceHeaders > 0);
  1339. paCoalesceHeaders[dwNumCoalesceHeaders - 1].bCommand |= PACKET_COMMAND_END_COALESCE;
  1340. // If there's an odd number of coalescence headers, add zero padding so data starts
  1341. // with DWORD alignment.
  1342. DBG_CASSERT(sizeof(COALESCEHEADER) == 2);
  1343. if ((dwNumCoalesceHeaders & 1) != 0)
  1344. {
  1345. *((WORD*) (&paCoalesceHeaders[dwNumCoalesceHeaders])) = 0;
  1346. pFMD->uiImmediateLength += 2;
  1347. }
  1348. }
  1349. else if ((pFMD->pMSD->CommandID == COMMAND_ID_KEEPALIVE) &&
  1350. (pEPD->ulEPFlags2 & EPFLAGS2_SUPPORTS_SIGNING))
  1351. {
  1352. //if we've got a link that could be using signed then we need to send one of the new type of keep alives
  1353. //that includes the session identity as data
  1354. *((DWORD * ) (pFMD->ImmediateData+pFMD->uiImmediateLength))=pEPD->dwSessID;
  1355. pFMD->uiImmediateLength+=sizeof(DWORD);
  1356. //flip the bit that marks this frame as a keep alive
  1357. pFrame->bControl |= PACKET_CONTROL_KEEPALIVE;
  1358. }
  1359. pFMD->uiFrameLength += pFMD->uiImmediateLength;
  1360. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  1361. // Stop delayed mask timer
  1362. if((pEPD->DelayedMaskTimer != 0)&&((pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)==0))
  1363. {
  1364. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  1365. if(CancelProtocolTimer(pSPD, pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  1366. {
  1367. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMaskTimer)"); // SPLock not already held
  1368. pEPD->DelayedMaskTimer = 0;
  1369. }
  1370. else
  1371. {
  1372. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  1373. }
  1374. }
  1375. // Stop delayed ack timer
  1376. if(pEPD->DelayedAckTimer != 0)
  1377. {
  1378. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1379. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  1380. {
  1381. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAckTimer)"); // SPLock not already held
  1382. pEPD->DelayedAckTimer = 0;
  1383. }
  1384. else
  1385. {
  1386. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1387. }
  1388. }
  1389. //if we've just built a reliable frame and we're fully signing the link then its a potential candidate for
  1390. //being used to modify the local secret
  1391. if ((pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK) && (pFrame->bCommand & PACKET_COMMAND_RELIABLE) &&
  1392. ((pFrame->bControl & PACKET_CONTROL_KEEPALIVE)==0) && (pFrame->bSeq<pEPD->byLocalSecretModifierSeqNum))
  1393. {
  1394. //for a coalesced frame we'll have taken a pointer to the first reliable subframe we stored in it
  1395. //otherwise we'll just use the existing frame
  1396. if (pReliableFMD==NULL)
  1397. {
  1398. DNASSERT(pFMD->CommandID != COMMAND_ID_SEND_COALESCE);
  1399. pReliableFMD=pFMD;
  1400. }
  1401. pEPD->byLocalSecretModifierSeqNum=pFrame->bSeq;
  1402. //slight complication here is that a coalesced FMD may not have an immediate header, and hence its buffer count
  1403. //will simply reflect the number of user data buffers. Hence, we test for this case and adjust accordingly
  1404. //We only want to modify the secret using the reliable user data
  1405. pEPD->ullLocalSecretModifier=GenerateLocalSecretModifier(pReliableFMD->rgBufferList,
  1406. (pReliableFMD->uiImmediateLength == 0) ? pReliableFMD->SendDataBlock.dwBufferCount :
  1407. pReliableFMD->SendDataBlock.dwBufferCount-1);
  1408. }
  1409. return pullFullSig;
  1410. }
  1411. /*
  1412. ** Build Retry Frame
  1413. **
  1414. ** Reinitialize those fields in the packet header that need to be recalculated for a retransmission.
  1415. **
  1416. ** Called and returns with EP lock held
  1417. */
  1418. #undef DPF_MODNAME
  1419. #define DPF_MODNAME "BuildRetryFrame"
  1420. UNALIGNED ULONGLONG * BuildRetryFrame(PEPD pEPD, PFMD pFMD)
  1421. {
  1422. PSPD pSPD = pEPD->pSPD;
  1423. ULONG * rgMask;
  1424. UINT index = 0;
  1425. PDFRAME pDFrame=(PDFRAME) pFMD->ImmediateData;
  1426. //if we need a full signature for the frame to be computed we track a pointer to its location
  1427. //in the header using this var. We return this to the caller, allowing them to tweak the data in the
  1428. //packet before writing in the final sig.
  1429. UNALIGNED ULONGLONG * pullFullSig=NULL;
  1430. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1431. pDFrame->bNRcv = pEPD->bNextReceive; // Use up-to-date ACK info
  1432. //preserve the current EOS, coalescence and keep alive/correlate flags. All the sack and send masks are cleared
  1433. pDFrame->bControl &= PACKET_CONTROL_END_STREAM | PACKET_CONTROL_COALESCE | PACKET_CONTROL_KEEPALIVE;
  1434. //tag packet as a retry
  1435. pDFrame->bControl |= PACKET_CONTROL_RETRY;
  1436. //take a pointer to memory immediately after the dframe header. This is where
  1437. //we'll store our ack masks
  1438. rgMask = (ULONG *) (pDFrame+1);
  1439. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  1440. {
  1441. if(pEPD->ulReceiveMask)
  1442. {
  1443. rgMask[index++] = pEPD->ulReceiveMask;
  1444. pDFrame->bControl |= PACKET_CONTROL_SACK_MASK1;
  1445. }
  1446. if(pEPD->ulReceiveMask2)
  1447. {
  1448. rgMask[index++] = pEPD->ulReceiveMask2;
  1449. pDFrame->bControl |= PACKET_CONTROL_SACK_MASK2;
  1450. }
  1451. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  1452. }
  1453. // MUST NOT transmit the SendMasks with a retry because they are based on the CURRENT bNextSend value which is not
  1454. // the N(S) that appears in this frame. We could theoretically shift the mask to agree with this frame's sequence
  1455. // number, but that might shift relevent bits out of the mask. Best thing to do is to let the next in-order send carry
  1456. // the bit-mask or else wait for the timer to fire and send a dedicated packet.
  1457. // PLEASE NOTE -- Although we may change the size of the immediate data below we did not update the FMD->uiFrameLength
  1458. // field. This field is used to credit the send window when the frame is acknowledged, and we would be wise to credit
  1459. // the same value that we debited back when this frame was first sent. We could adjust the debt now to reflect the new
  1460. // size of the frame, but seriously, why bother?
  1461. pFMD->uiImmediateLength = sizeof(DFRAME) + (index * 4);
  1462. //if we're fast signing the link we can stuff the local secret straight in after the masks
  1463. if (pEPD->ulEPFlags2 & EPFLAGS2_FAST_SIGNED_LINK)
  1464. {
  1465. *((UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength))=pEPD->ullCurrentLocalSecret;
  1466. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  1467. }
  1468. //otherwise if we're full signing it we need to reserve a zero'd out space for the sig and store the offset of where
  1469. //the caller to this function should place the final sig
  1470. else if (pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK)
  1471. {
  1472. pullFullSig=(UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength);
  1473. *pullFullSig=0;
  1474. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  1475. }
  1476. // Rebuild the coalesce header information, since we may have stripped some non-guaranteed data, or we may have just
  1477. // changed the masks and overwritten our previous array.
  1478. if (pDFrame->bControl & PACKET_CONTROL_COALESCE)
  1479. {
  1480. COALESCEHEADER* paCoalesceHeaders;
  1481. DWORD dwNumCoalesceHeaders;
  1482. DWORD dwUserDataSize;
  1483. BUFFERDESC* pBufferDesc;
  1484. CBilink* pLink;
  1485. FMD* pRealFMD;
  1486. // Reset the buffer count back to a single immediate data buffer.
  1487. pFMD->SendDataBlock.dwBufferCount = 1;
  1488. // Add in coalesce headers and copy the buffer descs for all of the subframes.
  1489. paCoalesceHeaders = (COALESCEHEADER*) (pFMD->ImmediateData + pFMD->uiImmediateLength);
  1490. dwNumCoalesceHeaders = 0;
  1491. dwUserDataSize = 0;
  1492. pBufferDesc = pFMD->rgBufferList;
  1493. pLink = pFMD->blCoalesceLinkage.GetNext();
  1494. while (pLink != &pFMD->blCoalesceLinkage)
  1495. {
  1496. pRealFMD = CONTAINING_OBJECT(pLink, FMD, blCoalesceLinkage);
  1497. ASSERT_FMD(pRealFMD);
  1498. // Datagrams get pulled out of the list as soon as they complete sending, and if the frame
  1499. // hadn't finished sending when the retry timeout occurred we would have made a copy.
  1500. // So we shouldn't see any datagrams here.
  1501. ASSERT((pRealFMD->CommandID == COMMAND_ID_SEND_RELIABLE) || (pRealFMD->CommandID == COMMAND_ID_COPIED_RETRY));
  1502. ASSERT(! pRealFMD->bSubmitted);
  1503. pRealFMD->bSubmitted = TRUE;
  1504. memcpy(&paCoalesceHeaders[dwNumCoalesceHeaders], pRealFMD->ImmediateData, sizeof(COALESCEHEADER));
  1505. ASSERT(dwNumCoalesceHeaders < MAX_USER_BUFFERS_IN_FRAME);
  1506. dwNumCoalesceHeaders++;
  1507. // Change the immediate data buffer desc to point to a zero padding buffer if this packet
  1508. // needs to be DWORD aligned, otherwise remove the immediate data pointer since we
  1509. // don't use it.
  1510. ASSERT(pRealFMD->lpImmediatePointer == (pRealFMD->ImmediateData + 4));
  1511. ASSERT(*((DWORD*) pRealFMD->lpImmediatePointer) == 0);
  1512. if ((dwUserDataSize & 3) != 0)
  1513. {
  1514. if (pRealFMD->SendDataBlock.pBuffers != (PBUFFERDESC) &pRealFMD->uiImmediateLength)
  1515. {
  1516. ASSERT(pRealFMD->SendDataBlock.pBuffers == pRealFMD->rgBufferList);
  1517. pRealFMD->SendDataBlock.pBuffers = (PBUFFERDESC) &pRealFMD->uiImmediateLength;
  1518. pRealFMD->SendDataBlock.dwBufferCount++;
  1519. }
  1520. else
  1521. {
  1522. ASSERT(pRealFMD->SendDataBlock.dwBufferCount > 1);
  1523. }
  1524. pRealFMD->uiImmediateLength = 4 - (dwUserDataSize & 3);
  1525. }
  1526. else
  1527. {
  1528. if (pRealFMD->SendDataBlock.pBuffers != pRealFMD->rgBufferList)
  1529. {
  1530. ASSERT(pRealFMD->SendDataBlock.pBuffers == (PBUFFERDESC) &pRealFMD->uiImmediateLength);
  1531. pRealFMD->SendDataBlock.pBuffers = pRealFMD->rgBufferList;
  1532. pRealFMD->SendDataBlock.dwBufferCount--;
  1533. pRealFMD->uiImmediateLength = 0;
  1534. }
  1535. else
  1536. {
  1537. ASSERT(pRealFMD->SendDataBlock.dwBufferCount >= 1);
  1538. ASSERT(pRealFMD->uiImmediateLength == 0);
  1539. }
  1540. }
  1541. memcpy(pBufferDesc, pRealFMD->SendDataBlock.pBuffers, (pRealFMD->SendDataBlock.dwBufferCount * sizeof(BUFFERDESC)));
  1542. pBufferDesc += pRealFMD->SendDataBlock.dwBufferCount;
  1543. ASSERT((pFMD->SendDataBlock.dwBufferCount - 1) + pRealFMD->SendDataBlock.dwBufferCount <= MAX_USER_BUFFERS_IN_FRAME); // don't include coalesce header frame immediate data
  1544. pFMD->SendDataBlock.dwBufferCount += pRealFMD->SendDataBlock.dwBufferCount;
  1545. ASSERT(pFMD->uiImmediateLength + sizeof(COALESCEHEADER) <= sizeof(pFMD->ImmediateData));
  1546. pFMD->uiImmediateLength += sizeof(COALESCEHEADER);
  1547. ASSERT(dwUserDataSize <= pFMD->uiFrameLength);
  1548. dwUserDataSize += pRealFMD->uiImmediateLength + pRealFMD->uiFrameLength;
  1549. pLink = pLink->GetNext();
  1550. }
  1551. ASSERT(dwNumCoalesceHeaders > 0);
  1552. paCoalesceHeaders[dwNumCoalesceHeaders - 1].bCommand |= PACKET_COMMAND_END_COALESCE;
  1553. // If there's an odd number of coalescence headers, add zero padding so data starts
  1554. // with DWORD alignment.
  1555. DBG_CASSERT(sizeof(COALESCEHEADER) == 2);
  1556. if ((dwNumCoalesceHeaders & 1) != 0)
  1557. {
  1558. *((WORD*) (&paCoalesceHeaders[dwNumCoalesceHeaders])) = 0;
  1559. pFMD->uiImmediateLength += 2;
  1560. }
  1561. }
  1562. else if ((pDFrame->bControl & PACKET_CONTROL_KEEPALIVE) && (pEPD->ulEPFlags2 & EPFLAGS2_SUPPORTS_SIGNING))
  1563. {
  1564. //if we're sending one of the new style keep alives with a session id in it, we need to re-write the session id,
  1565. //since we've potentially altered the length of the various send/ack masks before it
  1566. *((DWORD * ) (pFMD->ImmediateData+pFMD->uiImmediateLength))=pEPD->dwSessID;
  1567. pFMD->uiImmediateLength+=sizeof(DWORD);
  1568. }
  1569. pFMD->bSubmitted = TRUE; // protected by EPLock
  1570. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  1571. // Stop delayed ack timer
  1572. if(pEPD->DelayedAckTimer != 0)
  1573. {
  1574. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1575. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  1576. {
  1577. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAckTimer)");
  1578. pEPD->DelayedAckTimer = 0;
  1579. }
  1580. else
  1581. {
  1582. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1583. }
  1584. }
  1585. // Stop delayed mask timer
  1586. if(((pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)==0)&&(pEPD->DelayedMaskTimer != 0))
  1587. {
  1588. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  1589. if(CancelProtocolTimer(pSPD, pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  1590. {
  1591. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMaskTimer)"); // SPLock not already held
  1592. pEPD->DelayedMaskTimer = 0;
  1593. }
  1594. else
  1595. {
  1596. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  1597. }
  1598. }
  1599. return pullFullSig;
  1600. }
  1601. /*
  1602. ** Build Coalesce Frame
  1603. **
  1604. ** Setup the sub-header for a single frame within a coalesced frame
  1605. **
  1606. ** ** ENTERED AND EXITS WITH EPD->EPLOCK HELD **
  1607. */
  1608. #undef DPF_MODNAME
  1609. #define DPF_MODNAME "BuildCoalesceFrame"
  1610. VOID BuildCoalesceFrame(PFMD pCSD, PFMD pFMD)
  1611. {
  1612. PCOALESCEHEADER pSubFrame;
  1613. pSubFrame = (PCOALESCEHEADER) pFMD->ImmediateData;
  1614. // Make sure the DATA, NEW_MSG, and END_MSG flags are set.
  1615. ASSERT((pFMD->bPacketFlags & (PACKET_COMMAND_DATA | PACKET_COMMAND_NEW_MSG | PACKET_COMMAND_END_MSG)) == (PACKET_COMMAND_DATA | PACKET_COMMAND_NEW_MSG | PACKET_COMMAND_END_MSG));
  1616. // Turn off DATA, NEW_MSG and END_MSG because they are implied for coalesced subframes and we
  1617. // use the same bits for coalesce specific info.
  1618. // Turn off POLL flag, we use that bit for extended size information and it's not meaningful on subframes.
  1619. pSubFrame->bCommand = pFMD->bPacketFlags & ~(PACKET_COMMAND_DATA | PACKET_COMMAND_POLL | PACKET_COMMAND_NEW_MSG | PACKET_COMMAND_END_MSG);
  1620. ASSERT(! (pSubFrame->bCommand & (PACKET_COMMAND_END_COALESCE | PACKET_COMMAND_COALESCE_BIG_1 | PACKET_COMMAND_COALESCE_BIG_2 | PACKET_COMMAND_COALESCE_BIG_3)));
  1621. ASSERT((pFMD->uiFrameLength > 0) && (pFMD->uiFrameLength <= MAX_COALESCE_SIZE));
  1622. // Get the least significant 8 bits of the size.
  1623. pSubFrame->bSize = (BYTE) pFMD->uiFrameLength;
  1624. // Enable the 3 PACKET_COMMAND_COALESCE_BIG flags based on overflow from the size byte.
  1625. pSubFrame->bCommand |= (BYTE) ((pFMD->uiFrameLength & 0x0000FF00) >> 5);
  1626. // Change the immediate data buffer desc to point to a zero padding buffer in case this packet
  1627. // needs to be DWORD aligned.
  1628. ASSERT(pFMD->lpImmediatePointer == pFMD->ImmediateData);
  1629. DBG_CASSERT(sizeof(COALESCEHEADER) <= 4);
  1630. pFMD->lpImmediatePointer = pFMD->ImmediateData + 4;
  1631. *((DWORD*) pFMD->lpImmediatePointer) = 0;
  1632. ASSERT(pFMD->SendDataBlock.pBuffers == (PBUFFERDESC) &pFMD->uiImmediateLength);
  1633. ASSERT(pFMD->SendDataBlock.dwBufferCount > 1);
  1634. pCSD->bPacketFlags |= pFMD->bPacketFlags;
  1635. pCSD->ulFFlags |= pFMD->ulFFlags;
  1636. LOCK_FMD(pCSD, "Coalesce linkage"); // keep the container around until all subframes complete
  1637. pFMD->pCSD = pCSD;
  1638. pFMD->blCoalesceLinkage.InsertBefore(&pCSD->blCoalesceLinkage);
  1639. LOCK_FMD(pFMD, "SP Submit (coalescence)"); // Bump RefCnt when submitting send
  1640. }
  1641. /*
  1642. ** Service Command Traffic
  1643. **
  1644. ** Presently this transmits all CFrames and Datagrams queued to the specific
  1645. ** Service Provider. We may want to split out the datagrams from this so that
  1646. ** C frames can be given increased send priority but not datagrams. With this
  1647. ** implementation DGs will get inserted into reliable streams along with Cframes.
  1648. ** This may or may not be what we want to do...
  1649. **
  1650. ** WE ENTER AND EXIT WITH SPD->SENDLOCK HELD, although we release it during actual
  1651. ** calls to the SP.
  1652. */
  1653. #undef DPF_MODNAME
  1654. #define DPF_MODNAME "ServiceCmdTraffic"
  1655. VOID ServiceCmdTraffic(PSPD pSPD)
  1656. {
  1657. CBilink *pFLink;
  1658. PFMD pFMD;
  1659. HRESULT hr;
  1660. AssertCriticalSectionIsTakenByThisThread(&pSPD->SPLock, TRUE);
  1661. // WHILE there are frames ready to send
  1662. while((pFLink = pSPD->blSendQueue.GetNext()) != &pSPD->blSendQueue)
  1663. {
  1664. pFLink->RemoveFromList(); // Remove frame from queue
  1665. pFMD = CONTAINING_OBJECT(pFLink, FMD, blQLinkage); // get ptr to frame structure
  1666. ASSERT_FMD(pFMD);
  1667. // Place frame on pending queue before making call in case it completes really fast
  1668. #pragma BUGBUG(vanceo, "EPD lock is not held?")
  1669. ASSERT(!pFMD->bSubmitted);
  1670. pFMD->bSubmitted = TRUE;
  1671. ASSERT(pFMD->blQLinkage.IsEmpty());
  1672. pFMD->blQLinkage.InsertBefore( &pSPD->blPendingQueue); // Place frame on pending queue
  1673. Unlock(&pSPD->SPLock);
  1674. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  1675. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->SendData for FMD[%p], pSPD[%p]", pFMD->pEPD, pFMD, pSPD);
  1676. /*send*/if((hr = IDP8ServiceProvider_SendData(pSPD->IISPIntf, &pFMD->SendDataBlock)) != DPNERR_PENDING)
  1677. {
  1678. (void) DNSP_CommandComplete((IDP8SPCallback *) pSPD, NULL, hr, (PVOID) pFMD);
  1679. }
  1680. Lock(&pSPD->SPLock);
  1681. } // While SENDs are on QUEUE
  1682. }
  1683. /*
  1684. ** Run Send Thread
  1685. **
  1686. ** There is work for this SP's send thread. Keep running until
  1687. ** there is no more work to do.
  1688. **
  1689. ** Who gets first priority, DG or Seq traffic? I will say DG b/c its
  1690. ** advertised as lowest overhead...
  1691. **
  1692. ** Datagram packets get Queued on the SP when they are ready to ship.
  1693. ** Reliable packets are queued on the EPD. Therefore, we will queue the
  1694. ** actual EPD on the SPD when they have reliable traffic to send, and then
  1695. ** we will service individual EPDs from this loop.
  1696. */
  1697. #undef DPF_MODNAME
  1698. #define DPF_MODNAME "RunSendThread"
  1699. VOID CALLBACK RunSendThread(void * const pvUser, void * const pvTimerData, const UINT uiTimerUnique)
  1700. {
  1701. PSPD pSPD = (PSPD) pvUser;
  1702. ASSERT_SPD(pSPD);
  1703. DPFX(DPFPREP,7, "Send Thread Runs pSPD[%p]", pSPD);
  1704. Lock(&pSPD->SPLock);
  1705. if(!pSPD->blSendQueue.IsEmpty())
  1706. {
  1707. ServiceCmdTraffic(pSPD);
  1708. }
  1709. pSPD->ulSPFlags &= ~(SPFLAGS_SEND_THREAD_SCHEDULED);
  1710. Unlock(&pSPD->SPLock);
  1711. }
  1712. /*
  1713. ** Scheduled Send
  1714. **
  1715. ** If this EPD is still unentitled to send, start draining frames. Otherwise transition
  1716. ** link to IDLE state.
  1717. */
  1718. #undef DPF_MODNAME
  1719. #define DPF_MODNAME "ScheduledSend"
  1720. VOID CALLBACK
  1721. ScheduledSend(void * const pvUser, void * const pvTimerData, const UINT uiTimerUnique)
  1722. {
  1723. PEPD pEPD = (PEPD) pvUser;
  1724. const SPD* pSPD = pEPD->pSPD;
  1725. ASSERT_EPD(pEPD);
  1726. ASSERT_SPD(pSPD);
  1727. Lock(&pEPD->EPLock);
  1728. pEPD->SendTimer = 0;
  1729. DPFX(DPFPREP,7, "(%p) Scheduled Send Fires", pEPD);
  1730. ASSERT(pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE);
  1731. // Test that all three flags are set before starting to transmit
  1732. if( (pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) && (
  1733. ((pEPD->ulEPFlags & (EPFLAGS_STREAM_UNBLOCKED | EPFLAGS_SDATA_READY)) == (EPFLAGS_STREAM_UNBLOCKED | EPFLAGS_SDATA_READY))
  1734. || (pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED)))
  1735. {
  1736. ServiceEPD(pEPD->pSPD, pEPD); // releases EPLock
  1737. }
  1738. else
  1739. {
  1740. DPFX(DPFPREP,7, "(%p) Session leaving pipeline", pEPD);
  1741. pEPD->ulEPFlags &= ~(EPFLAGS_IN_PIPELINE);
  1742. RELEASE_EPD(pEPD, "UNLOCK (leaving pipeline, SchedSend done)"); // releases EPLock
  1743. }
  1744. }
  1745. #undef DPF_MODNAME
  1746. #define DPF_MODNAME "HandlePerFrameState"
  1747. VOID HandlePerFrameState(PMSD pMSD, PFMD pFMD)
  1748. {
  1749. PEPD pEPD;
  1750. CBilink* pFLink;
  1751. pEPD = pFMD->pEPD;
  1752. LOCK_EPD(pEPD, "LOCK (Send Data Frame)"); // Keep EPD around while xmitting frame
  1753. pFLink = pFMD->blMSDLinkage.GetNext(); // Get next frame in Msg
  1754. // Was this the last frame in Msg?
  1755. if(pFLink == &pMSD->blFrameList)
  1756. {
  1757. // Last frame in message has been sent.
  1758. //
  1759. // We used to setup the next frame now, but with the multi-priority queues it makes more sense to look for the
  1760. // highest priority send when we are ready to send it.
  1761. pEPD->pCurrentSend = NULL;
  1762. pEPD->pCurrentFrame = NULL;
  1763. // When completing a send, set the POLL flag if there are no more sends on the queue
  1764. #ifndef DPNBUILD_NOMULTICAST
  1765. if (!(pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE)))
  1766. #endif // !DPNBUILD_NOMULTICAST
  1767. {
  1768. // Request immediate reply if no more data to send
  1769. if(pEPD->uiQueuedMessageCount == 0)
  1770. {
  1771. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL;
  1772. }
  1773. }
  1774. }
  1775. else
  1776. {
  1777. pEPD->pCurrentFrame = CONTAINING_OBJECT(pFLink, FMD, blMSDLinkage);
  1778. ASSERT_FMD(pEPD->pCurrentFrame);
  1779. }
  1780. ASSERT(!pFMD->bSubmitted);
  1781. pFMD->bSubmitted = TRUE; // Protected by EPLock
  1782. ASSERT(! (pFMD->ulFFlags & FFLAGS_TRANSMITTED));
  1783. pFMD->ulFFlags |= FFLAGS_TRANSMITTED; // Frame will be owned by SP
  1784. }
  1785. #undef DPF_MODNAME
  1786. #define DPF_MODNAME "GetNextEligibleMessage"
  1787. PMSD GetNextEligibleMessage(PEPD pEPD)
  1788. {
  1789. PMSD pMSD;
  1790. CBilink* pLink;
  1791. if( (pLink = pEPD->blHighPriSendQ.GetNext()) == &pEPD->blHighPriSendQ)
  1792. {
  1793. if( (pLink = pEPD->blNormPriSendQ.GetNext()) == &pEPD->blNormPriSendQ)
  1794. {
  1795. if( (pLink = pEPD->blLowPriSendQ.GetNext()) == &pEPD->blLowPriSendQ)
  1796. {
  1797. return NULL;
  1798. }
  1799. }
  1800. }
  1801. pMSD = CONTAINING_OBJECT(pLink, MSD, blQLinkage);
  1802. ASSERT_MSD(pMSD);
  1803. return pMSD;
  1804. }
  1805. #undef DPF_MODNAME
  1806. #define DPF_MODNAME "CanCoalesceMessage"
  1807. BOOL CanCoalesceMessage(PEPD pEPD, PMSD pMSD, DWORD * pdwSubFrames, DWORD * pdwBuffers, DWORD * pdwUserFrameLength)
  1808. {
  1809. PFMD pTempFMD;
  1810. DWORD dwAdditionalBuffers;
  1811. DWORD dwAdditionalUserFrameLength;
  1812. DWORD dwComparisonFrameLength;
  1813. if (pMSD->uiFrameCount > 1)
  1814. {
  1815. DPFX(DPFPREP, 3, "(%p) Message 0x%p spans %u frames, declining", pEPD, pMSD, pMSD->uiFrameCount);
  1816. return FALSE;
  1817. }
  1818. pTempFMD = CONTAINING_OBJECT(pMSD->blFrameList.GetNext(), FMD, blMSDLinkage);
  1819. ASSERT_FMD(pTempFMD);
  1820. ASSERT(pTempFMD->blMSDLinkage.GetNext() == &pMSD->blFrameList);
  1821. if (pTempFMD->ulFFlags & FFLAGS_DONT_COALESCE)
  1822. {
  1823. DPFX(DPFPREP, 3, "(%p) Message 0x%p frame 0x%p should not be coalesced (flags 0x%x)", pEPD, pMSD, pTempFMD, pTempFMD->ulFFlags);
  1824. return FALSE;
  1825. }
  1826. if (pTempFMD->uiFrameLength > MAX_COALESCE_SIZE)
  1827. {
  1828. DPFX(DPFPREP, 3, "(%p) Message 0x%p frame 0x%p is %u bytes, declining", pEPD, pMSD, pTempFMD, pTempFMD->uiFrameLength);
  1829. return FALSE;
  1830. }
  1831. // Find out how many buffers currently exist and would need to be added.
  1832. // We may need to pad the end of a previous coalesce framed so that this one is aligned.
  1833. // Keep in mind that dwBufferCount already includes an immediate data header.
  1834. dwAdditionalBuffers = pTempFMD->SendDataBlock.dwBufferCount - 1;
  1835. dwAdditionalUserFrameLength = pTempFMD->uiFrameLength;
  1836. if ((*pdwUserFrameLength & 3) != 0)
  1837. {
  1838. dwAdditionalBuffers++;
  1839. dwAdditionalUserFrameLength += 4 - (*pdwUserFrameLength & 3);
  1840. }
  1841. dwComparisonFrameLength = ((*pdwSubFrames) * sizeof(COALESCEHEADER)) + *pdwUserFrameLength + dwAdditionalUserFrameLength;
  1842. DBG_CASSERT(sizeof(COALESCEHEADER) == 2);
  1843. if ((*pdwSubFrames & 1) != 0)
  1844. {
  1845. dwComparisonFrameLength += 2;
  1846. }
  1847. if ((dwAdditionalBuffers + *pdwBuffers) > MAX_USER_BUFFERS_IN_FRAME)
  1848. {
  1849. DPFX(DPFPREP, 3, "(%p) Message 0x%p frame 0x%p %u buffers + %u existing buffers exceeds max, declining", pEPD, pMSD, pTempFMD, dwAdditionalBuffers, *pdwBuffers);
  1850. return FALSE;
  1851. }
  1852. if (dwComparisonFrameLength > pEPD->pSPD->uiUserFrameLength)
  1853. {
  1854. DPFX(DPFPREP, 3, "(%p) Message 0x%p frame 0x%p %u bytes (%u existing, %u added user bytes) exceeds max frame size %u, declining",
  1855. pEPD, pMSD, pTempFMD, dwComparisonFrameLength, *pdwUserFrameLength, dwAdditionalUserFrameLength, pEPD->pSPD->uiUserFrameLength);
  1856. return FALSE;
  1857. }
  1858. *pdwSubFrames += 1;
  1859. *pdwBuffers += dwAdditionalBuffers;
  1860. *pdwUserFrameLength += dwAdditionalUserFrameLength;
  1861. return TRUE;
  1862. }
  1863. /*
  1864. ** Service EndPointDescriptor
  1865. **
  1866. ** This includes reliable, datagram, and re-transmit
  1867. ** frames. Retransmissions are ALWAYS transmitted first, regardless of the orginal message's
  1868. ** priority. After that datagrams and reliable messages are taken in priority order, in FIFO
  1869. ** order within a priority class.
  1870. **
  1871. ** The number of frames drained depends upon the current window parameters.
  1872. **
  1873. ** If the pipeline goes idle or the stream gets blocked we will still schedule the next
  1874. ** send. This way if we unblock or un-idle before the gap has expired we will not get to cheat
  1875. ** and defeat the gap. The shell routine above us (ScheduledSend) will take care of removing us
  1876. ** from the pipeline if the next burst gets scheduled and we are still not ready to send.
  1877. **
  1878. **
  1879. ** ** CALLED WITH EPD->EPLock HELD; Returns with EPLock RELEASED **
  1880. */
  1881. #undef DPF_MODNAME
  1882. #define DPF_MODNAME "ServiceEPD"
  1883. VOID ServiceEPD(PSPD pSPD, PEPD pEPD)
  1884. {
  1885. PMSD pMSD;
  1886. PFMD pFMD;
  1887. PFMD pCSD = NULL; // Descriptor for coalesence
  1888. DWORD dwSubFrames = 0;
  1889. DWORD dwBuffers = 0;
  1890. DWORD dwUserFrameLength = 0;
  1891. UNALIGNED ULONGLONG * pullFrameSig=NULL;
  1892. #ifdef DBG
  1893. UINT uiFramesSent = 0;
  1894. UINT uiRetryFramesSent = 0;
  1895. UINT uiCoalescedFramesSent = 0;
  1896. #endif // DBG
  1897. HRESULT hr;
  1898. DWORD tNow = GETTIMESTAMP();
  1899. #ifndef DPNBUILD_NOMULTICAST
  1900. PMCASTFRAME pMCastFrame;
  1901. #endif // !DPNBUILD_NOMULTICAST
  1902. /*
  1903. ** Now we will drain reliable traffic from EPDs on the pipeline list
  1904. */
  1905. // The caller should have checked this
  1906. ASSERT( pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED );
  1907. // Burst Credit can either be positive or negative depending upon how much of our last transmit slice we used
  1908. DPFX(DPFPREP,7, "(%p) BEGIN UNLIMITED BURST", pEPD);
  1909. // Transmit a burst from this EPD, as long as its unblocked and has data ready. We do not re-init
  1910. // burst counter since any retries sent count against our burst limit
  1911. //
  1912. // This has become more complex now that we are interleaving datagrams and reliable frames. There are two
  1913. // sets of priority-based send queues. The first is combined DG and Reliable and the second is datagram only.
  1914. // when the reliable stream is blocked we will feed from the DG only queues, otherwise we will take from the
  1915. // interleaved queue.
  1916. // This is further complicated by the possibility that a reliable frame can be partially transmitted at any time.
  1917. // So before looking at the interleaved queues we must check for a partially completed reliable send (EPD.pCurrentSend).
  1918. //
  1919. // ** pEPD->EPLock is held **
  1920. while(((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED) && (pEPD->ulEPFlags & EPFLAGS_SDATA_READY))
  1921. || (pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED))
  1922. {
  1923. // Always give preference to shipping retries before new data
  1924. if(pEPD->ulEPFlags & EPFLAGS_RETRIES_QUEUED)
  1925. {
  1926. pFMD = CONTAINING_OBJECT(pEPD->blRetryQueue.GetNext(), FMD, blQLinkage);
  1927. ASSERT_FMD(pFMD);
  1928. pFMD->blQLinkage.RemoveFromList();
  1929. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  1930. if(pEPD->blRetryQueue.IsEmpty())
  1931. {
  1932. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  1933. }
  1934. // pMSD->uiFrameCount will be decremented when this completes
  1935. pullFrameSig=BuildRetryFrame(pEPD, pFMD); // Place current state information in retry frame
  1936. DPFX(DPFPREP,7, "(%p) Shipping RETRY frame: Seq=%x, FMD=%p Size=%d", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD, pFMD->uiFrameLength);
  1937. #ifdef DBG
  1938. uiFramesSent++;
  1939. uiRetryFramesSent++;
  1940. #endif // DBG
  1941. }
  1942. else
  1943. {
  1944. if((pMSD = pEPD->pCurrentSend) != NULL)
  1945. {
  1946. // We won't allow coalesence for multi-frame messages since they are composed mostly of
  1947. // full frames already.
  1948. ASSERT_MSD(pMSD);
  1949. pFMD = pEPD->pCurrentFrame; // Get the next frame due to send
  1950. DPFX(DPFPREP, 7, "(%p) Continuing multi-frame message 0x%p with frame 0x%p.", pEPD, pMSD, pFMD);
  1951. HandlePerFrameState(pMSD, pFMD);
  1952. }
  1953. else
  1954. {
  1955. pMSD = GetNextEligibleMessage(pEPD);
  1956. if( pMSD == NULL )
  1957. {
  1958. goto EXIT_SEND; // All finished sending for now
  1959. }
  1960. while (TRUE)
  1961. {
  1962. pFMD = CONTAINING_OBJECT(pMSD->blFrameList.GetNext(), FMD, blMSDLinkage);
  1963. ASSERT_FMD(pFMD);
  1964. #ifdef DBG
  1965. ASSERT(pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED);
  1966. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  1967. #endif // DBG
  1968. pMSD->blQLinkage.RemoveFromList();
  1969. ASSERT(pEPD->uiQueuedMessageCount > 0);
  1970. --pEPD->uiQueuedMessageCount; // keep count of MSDs on all send queues
  1971. pMSD->ulMsgFlags2 |= MFLAGS_TWO_TRANSMITTING; // We have begun to transmit frames from this Msg
  1972. pEPD->pCurrentSend = pMSD;
  1973. pEPD->pCurrentFrame = pFMD;
  1974. pFMD->bPacketFlags |= PACKET_COMMAND_NEW_MSG;
  1975. pMSD->blQLinkage.InsertBefore( &pEPD->blCompleteSendList); // Place this on PendingList now so we can keep track of it
  1976. HandlePerFrameState(pMSD, pFMD);
  1977. if (pEPD->ulEPFlags2 & EPFLAGS2_NOCOALESCENCE)
  1978. {
  1979. DPFX(DPFPREP, 1, "(%p) Coalescence is disabled, sending single message in frame", pEPD);
  1980. break;
  1981. }
  1982. #if (! defined(DPNBUILD_NOMULTICAST))
  1983. if (pEPD->ulEPFlags2 & EPFLAGS2_MULTICAST_SEND)
  1984. {
  1985. DPFX(DPFPREP, 7, "(%p) Endpoint is multicast, sending single message in frame", pEPD);
  1986. break;
  1987. }
  1988. ASSERT(! pEPD->ulEPFlags2 & EPFLAGS2_MULTICAST_RECEIVE)
  1989. #endif
  1990. // The first time through we won't have a CSD yet
  1991. if (pCSD == NULL)
  1992. {
  1993. // See if this first message can be coalesced.
  1994. if (!CanCoalesceMessage(pEPD, pMSD, &dwSubFrames, &dwBuffers, &dwUserFrameLength))
  1995. {
  1996. break;
  1997. }
  1998. // Get the next potential message.
  1999. pMSD = GetNextEligibleMessage(pEPD);
  2000. if (pMSD == NULL)
  2001. {
  2002. DPFX(DPFPREP, 7, "(%p) No more messages in queue to coalesce", pEPD);
  2003. break;
  2004. }
  2005. ASSERT_MSD(pMSD);
  2006. // See if the next potential message can be coalesced.
  2007. if (!CanCoalesceMessage(pEPD, pMSD, &dwSubFrames, &dwBuffers, &dwUserFrameLength))
  2008. {
  2009. break;
  2010. }
  2011. if((pCSD = (PFMD)POOLALLOC(MEMID_COALESCE_FMD, &FMDPool)) == NULL)
  2012. {
  2013. // Oh well, we just don't get to coalesce this time
  2014. DPFX(DPFPREP, 0, "(%p) Unable to allocate FMD for coalescing, won't coalesce this round", pEPD);
  2015. break;
  2016. }
  2017. pCSD->CommandID = COMMAND_ID_SEND_COALESCE;
  2018. pCSD->uiFrameLength = 0;
  2019. pCSD->bSubmitted = TRUE;
  2020. pCSD->pMSD = NULL;
  2021. pCSD->pEPD = pEPD;
  2022. LOCK_EPD(pEPD, "LOCK (send data frame coalesce header)"); // Keep EPD around while xmitting frame
  2023. // Attach this individual frame onto the coalescence descriptor
  2024. DPFX(DPFPREP,7, "(%p) Beginning coalesced frame 0x%p with %u bytes in %u buffers from frame 0x%p (flags 0x%x)", pEPD, pCSD, pFMD->uiFrameLength, (pFMD->SendDataBlock.dwBufferCount - 1), pFMD, pFMD->bPacketFlags);
  2025. BuildCoalesceFrame(pCSD, pFMD);
  2026. #ifdef DBG
  2027. uiCoalescedFramesSent++; // Count coalesced frames sent this burst
  2028. #endif // DBG
  2029. }
  2030. else
  2031. {
  2032. ASSERT_FMD(pCSD);
  2033. // Attach this individual frame onto the coalescence descriptor
  2034. DPFX(DPFPREP,7, "(%p) Coalescing frame 0x%p (flags 0x%x) with %u bytes in %u buffers into header 0x%p (subframes=%u, buffers=%u, framelength=%u)", pEPD, pFMD, pFMD->bPacketFlags, pFMD->uiFrameLength, (pFMD->SendDataBlock.dwBufferCount - 1), pCSD, dwSubFrames, dwBuffers, dwUserFrameLength);
  2035. BuildCoalesceFrame(pCSD, pFMD);
  2036. #ifdef DBG
  2037. uiCoalescedFramesSent++; // Count coalesced frames sent this burst
  2038. #endif // DBG
  2039. // Get the next potential message.
  2040. pMSD = GetNextEligibleMessage(pEPD);
  2041. if (pMSD == NULL)
  2042. {
  2043. DPFX(DPFPREP, 7, "(%p) No more messages in queue to coalesce", pEPD);
  2044. break;
  2045. }
  2046. ASSERT_MSD(pMSD);
  2047. // See if the next potential message can be coalesced, too.
  2048. if (!CanCoalesceMessage(pEPD, pMSD, &dwSubFrames, &dwBuffers, &dwUserFrameLength))
  2049. {
  2050. break;
  2051. }
  2052. }
  2053. } // while (attempting to coalesce)
  2054. }
  2055. ASSERT_FMD(pFMD);
  2056. ASSERT(pFMD->bSubmitted);
  2057. // When we get here we either have a single frame to send in pFMD, or
  2058. // multiple frames to coalesce into one frame in pCSD.
  2059. if (pCSD != NULL)
  2060. {
  2061. ASSERT_FMD(pCSD);
  2062. ASSERT(pCSD->bSubmitted);
  2063. pFMD = pCSD;
  2064. }
  2065. #ifndef DPNBUILD_NOMULTICAST
  2066. if (pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE))
  2067. {
  2068. // Build the protocol header for the multicast frame
  2069. pFMD->uiImmediateLength = sizeof(MCASTFRAME);
  2070. pMCastFrame = (PMCASTFRAME)pFMD->ImmediateData;
  2071. pMCastFrame->dwVersion = DNET_VERSION_NUMBER;
  2072. do
  2073. {
  2074. pMCastFrame->dwSessID = DNGetGoodRandomNumber();
  2075. }
  2076. while (pMCastFrame->dwSessID==0);
  2077. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt;
  2078. pFMD->uiFrameLength += pFMD->uiImmediateLength;
  2079. DPFX(DPFPREP,7, "(%p) Shipping Multicast Frame: FMD=%p", pEPD, pFMD);
  2080. }
  2081. else
  2082. #endif // !DPNBUILD_NOMULTICAST
  2083. {
  2084. pullFrameSig=BuildDataFrame(pEPD, pFMD, tNow); // place current state info in frame
  2085. pFMD->blWindowLinkage.InsertBefore( &pEPD->blSendWindow); // Place at trailing end of send window
  2086. pFMD->ulFFlags |= FFLAGS_IN_SEND_WINDOW;
  2087. LOCK_FMD(pFMD, "Send Window"); // Add reference for send window
  2088. pEPD->uiUnackedBytes += pFMD->uiFrameLength; // Track the unacknowleged bytes in the pipeline
  2089. // We can always go over the limit, but will be blocked until we drop below the limit again.
  2090. if(pEPD->uiUnackedBytes >= pEPD->uiWindowB)
  2091. {
  2092. pEPD->ulEPFlags &= ~(EPFLAGS_STREAM_UNBLOCKED);
  2093. pEPD->ulEPFlags |= EPFLAGS_FILLED_WINDOW_BYTE; // Tells us to increase window if all is well
  2094. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL; // Request immediate reply
  2095. }
  2096. // Count frames in the send window
  2097. if((++pEPD->uiUnackedFrames) >= pEPD->uiWindowF)
  2098. {
  2099. pEPD->ulEPFlags &= ~(EPFLAGS_STREAM_UNBLOCKED);
  2100. ((PDFRAME) pFMD->ImmediateData)->bCommand |= PACKET_COMMAND_POLL; // Request immediate reply
  2101. pEPD->ulEPFlags |= EPFLAGS_FILLED_WINDOW_FRAME; // Tells us to increase window if all is well
  2102. }
  2103. // We will only run one retry timer for each EndPt. If we already have one running then do nothing.
  2104. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  2105. if(!(pEPD->ulEPFlags2 & EPFLAGS2_DEBUG_NO_RETRIES))
  2106. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  2107. {
  2108. // If there was already a frame in the pipeline it should already have a clock running
  2109. if(pEPD->uiUnackedFrames == 1)
  2110. {
  2111. ASSERT(pEPD->RetryTimer == 0);
  2112. pFMD->ulFFlags |= FFLAGS_RETRY_TIMER_SET; // This one is being measured
  2113. LOCK_EPD(pEPD, "LOCK (set retry timer)"); // bump RefCnt for timer
  2114. DPFX(DPFPREP,7, "(%p) Setting Retry Timer on Seq=0x%x, FMD=%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  2115. ScheduleProtocolTimer(pSPD, pEPD->uiRetryTimeout, 0, RetryTimeout,
  2116. (PVOID) pEPD, &pEPD->RetryTimer, &pEPD->RetryTimerUnique);
  2117. }
  2118. else
  2119. {
  2120. ASSERT(pEPD->RetryTimer != 0);
  2121. }
  2122. }
  2123. DPFX(DPFPREP,7, "(%p) Shipping Dataframe: Seq=%x, NRcv=%x FMD=%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, ((PDFRAME) pFMD->ImmediateData)->bNRcv, pFMD);
  2124. }
  2125. //track the number of bytes we're about to send
  2126. if(pFMD->ulFFlags & FFLAGS_RELIABLE)
  2127. {
  2128. pEPD->uiGuaranteedFramesSent++;
  2129. pEPD->uiGuaranteedBytesSent += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  2130. }
  2131. else
  2132. {
  2133. // Note that multicast sends will use these values for statistics as will datagrams
  2134. pEPD->uiDatagramFramesSent++;
  2135. pEPD->uiDatagramBytesSent += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  2136. }
  2137. LOCK_FMD(pFMD, "SP Submit"); // Bump RefCnt when submitting send
  2138. }
  2139. ASSERT(pFMD->bSubmitted);
  2140. #ifdef DBG
  2141. uiFramesSent++; // Count frames sent this burst
  2142. #endif // DBG
  2143. //if we're fully signing links we have to generate the sig for this frame
  2144. //we might also have to update our local secret if we've just about to wrap our sequence space
  2145. if (pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK)
  2146. {
  2147. PDFRAME pDFrame=(PDFRAME) pFMD->ImmediateData;
  2148. //since we're fully signed the Build*Frame function must have given us an offset to write
  2149. //the signature into
  2150. DNASSERT(pullFrameSig);
  2151. //if the next frame is a retry then we might have to sign using our old local secret
  2152. if (pDFrame->bControl & PACKET_CONTROL_RETRY)
  2153. {
  2154. //corner case here is when we've already wrapped into the 1st quarter of the send window
  2155. //but this retry had a sequence number in the final quarter of the send window
  2156. if (pEPD->bNextSend<SEQ_WINDOW_1Q && pDFrame->bSeq>=SEQ_WINDOW_3Q)
  2157. {
  2158. *pullFrameSig=GenerateOutgoingFrameSig(pFMD, pEPD->ullOldLocalSecret);
  2159. }
  2160. //otherwise simply sign the retry with the current local secret
  2161. else
  2162. {
  2163. *pullFrameSig=GenerateOutgoingFrameSig(pFMD, pEPD->ullCurrentLocalSecret);
  2164. }
  2165. }
  2166. else
  2167. {
  2168. //for none retries we always sign with the current secret
  2169. *pullFrameSig=GenerateOutgoingFrameSig(pFMD, pEPD->ullCurrentLocalSecret);
  2170. //If this is the last frame in the current sequence space we should evolve our local secret
  2171. if (pDFrame->bSeq==(SEQ_WINDOW_4Q-1))
  2172. {
  2173. pEPD->ullOldLocalSecret=pEPD->ullCurrentLocalSecret;
  2174. pEPD->ullCurrentLocalSecret=GenerateNewSecret(pEPD->ullCurrentLocalSecret, pEPD->ullLocalSecretModifier);
  2175. //reset the message seq num we talk the modifier value from. We'll use the lowest reliable message
  2176. //sent in this next sequence space as the next modifier for the local secret
  2177. pEPD->byLocalSecretModifierSeqNum=SEQ_WINDOW_3Q;
  2178. }
  2179. }
  2180. }
  2181. // We guarantee to the SP that we will never have a zero lead byte
  2182. ASSERT(pFMD->ImmediateData[0] != 0);
  2183. // Make sure anything after the header is DWORD aligned.
  2184. ASSERT((pFMD->uiImmediateLength % 4) == 0);
  2185. // Make sure we're giving the SP something.
  2186. ASSERT(pFMD->uiFrameLength > 0);
  2187. // Make sure we're not giving the SP something it says it can't support.
  2188. ASSERT(pFMD->uiFrameLength <= pSPD->uiFrameLength);
  2189. // bSubmitted must not be set to true for a data frame without the EPLock being held, because
  2190. // the retry logic will be checking bSubmitted with only the EPLock held.
  2191. Unlock(&pEPD->EPLock);
  2192. // PROCEED WITH TRANSMISSION...
  2193. Lock(&pSPD->SPLock);
  2194. ASSERT(pFMD->blQLinkage.IsEmpty());
  2195. pFMD->blQLinkage.InsertBefore( &pSPD->blPendingQueue); // Place frame on pending queue
  2196. Unlock(&pSPD->SPLock);
  2197. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2198. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->SendData for FMD[%p]", pEPD, pFMD);
  2199. /*send*/if((hr = IDP8ServiceProvider_SendData(pSPD->IISPIntf, &pFMD->SendDataBlock)) != DPNERR_PENDING)
  2200. {
  2201. (void) DNSP_CommandComplete((IDP8SPCallback *) pSPD, NULL, hr, (PVOID) pFMD);
  2202. }
  2203. // We don't track coalescence headers in an MSD, so we don't need the initial reference.
  2204. if (pCSD != NULL)
  2205. {
  2206. ASSERT(pCSD == pFMD);
  2207. RELEASE_FMD(pCSD, "Coalescence header local reference");
  2208. pCSD = NULL;
  2209. dwSubFrames = 0;
  2210. dwBuffers = 0;
  2211. dwUserFrameLength = 0;
  2212. }
  2213. Lock(&pEPD->EPLock);
  2214. } // WHILE (unblocked, undrained, & bandwidth credit avail)
  2215. EXIT_SEND:
  2216. ASSERT(pCSD == NULL);
  2217. if((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED)==0)
  2218. {
  2219. pEPD->uiWindowFilled++; // Count the times we filled the window
  2220. }
  2221. // Clear data-ready flag if everything is sent
  2222. if((pEPD->uiQueuedMessageCount == 0) && (pEPD->pCurrentSend == NULL))
  2223. {
  2224. pEPD->ulEPFlags &= ~(EPFLAGS_SDATA_READY);
  2225. }
  2226. // As commented in procedure-header above, we will remain on the pipeline for one timer-cycle
  2227. // so that if we unblock or un-idle we will not send until the gap is fullfilled.
  2228. if((pEPD->ulEPFlags & (EPFLAGS_SDATA_READY | EPFLAGS_STREAM_UNBLOCKED)) == (EPFLAGS_SDATA_READY | EPFLAGS_STREAM_UNBLOCKED))
  2229. { // IF BOTH flags are set
  2230. DPFX(DPFPREP,7, "(%p) %d (%d, %d) frame BURST COMPLETED - Sched next send in %dms, N(Seq)=%x",
  2231. pEPD, uiFramesSent, uiRetryFramesSent, uiCoalescedFramesSent, pEPD->uiBurstGap, pEPD->bNextSend);
  2232. }
  2233. else if((pEPD->ulEPFlags & EPFLAGS_SDATA_READY)==0)
  2234. {
  2235. DPFX(DPFPREP,7, "(%p) %d (%d, %d) frame BURST COMPLETED (%d/%d) - LINK IS IDLE N(Seq)=%x",
  2236. pEPD, uiFramesSent, uiRetryFramesSent, uiCoalescedFramesSent, pEPD->uiUnackedFrames, pEPD->uiWindowF, pEPD->bNextSend);
  2237. }
  2238. else
  2239. {
  2240. ASSERT((pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED) == 0);
  2241. DPFX(DPFPREP,7, "(%p) %d (%d, %d) frame BURST COMPLETED (%d/%d) - STREAM BLOCKED N(Seq)=%x",
  2242. pEPD, uiFramesSent, uiRetryFramesSent, uiCoalescedFramesSent, pEPD->uiUnackedFrames, pEPD->uiWindowF, pEPD->bNextSend);
  2243. }
  2244. ASSERT(pEPD->SendTimer == 0);
  2245. if(pEPD->uiBurstGap != 0)
  2246. {
  2247. DPFX(DPFPREP,7, "(%p) Setting Scheduled Send Timer for %d ms", pEPD, pEPD->uiBurstGap);
  2248. ScheduleProtocolTimer(pSPD, pEPD->uiBurstGap, 4, ScheduledSend, (PVOID) pEPD, &pEPD->SendTimer, &pEPD->SendTimerUnique);
  2249. Unlock(&pEPD->EPLock);
  2250. // NOTE: We still hold the pipeline reference
  2251. }
  2252. else
  2253. {
  2254. DPFX(DPFPREP,7, "(%p) Session leaving pipeline", pEPD);
  2255. pEPD->ulEPFlags &= ~(EPFLAGS_IN_PIPELINE);
  2256. RELEASE_EPD(pEPD, "UNLOCK (leaving pipeline)"); // releases EPLock
  2257. }
  2258. }
  2259. /*
  2260. ** Retry Timeout
  2261. **
  2262. ** Retry timer fires when we have not seen an acknowledgement for a packet
  2263. ** we sent in more then twice (actually 1.25 X) our measured RTT. Actually, that is
  2264. ** just our base calculation. We will also measure empirical ACK times and adjust our timeout
  2265. ** to some multiple of that. Remember that our partner may be delaying his Acks to wait for back-traffic.
  2266. **
  2267. ** Or we can measure avg deviation of Tack and base retry timer on that.
  2268. **
  2269. ** In any case, its time to re-transmit the base frame in our send window...
  2270. **
  2271. ** Important note: Since we can generate retries via bitmask in return traffic, it is possible that
  2272. ** we have just retried when the timer fires.
  2273. **
  2274. ** Note on Locks: Since the retry timer is directly associated with an entry on the EPD SendQueue,
  2275. ** we always protect retry-related operations with the EPD->SPLock. We only hold the EPD->StateLock
  2276. ** when we mess with link state variables (NRcv, DelayedAckTimer).
  2277. */
  2278. #undef DPF_MODNAME
  2279. #define DPF_MODNAME "RetryTimeout"
  2280. #ifdef DBG
  2281. LONG g_RetryCount[MAX_SEND_RETRIES_TO_DROP_LINK+1]={0};
  2282. #endif // DBG
  2283. VOID CALLBACK
  2284. RetryTimeout(void * const pvUser, void * const uID, const UINT Unique)
  2285. {
  2286. PEPD pEPD = (PEPD) pvUser;
  2287. PSPD pSPD = pEPD->pSPD;
  2288. PProtocolData pPData = pSPD->pPData;
  2289. PFMD pFMD;
  2290. DWORD tNow = GETTIMESTAMP(), tDelta;
  2291. UINT delta;
  2292. CBilink *pLink;
  2293. PFMD pRealFMD;
  2294. ASSERT_EPD(pEPD);
  2295. Lock(&pEPD->EPLock);
  2296. DPFX(DPFPREP,7, "(%p) Retry Timeout fires", pEPD);
  2297. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  2298. ASSERT(!(pEPD->ulEPFlags2 & EPFLAGS2_DEBUG_NO_RETRIES));
  2299. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  2300. // Make sure link is still active
  2301. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  2302. {
  2303. DPFX(DPFPREP,7, "(%p) Not connected, exiting", pEPD);
  2304. pEPD->RetryTimer = 0;
  2305. RELEASE_EPD(pEPD, "UNLOCK (retry timer not-CONN)"); // Decrement RefCnt for timer, releases EPLock
  2306. return;
  2307. }
  2308. // Its possible when we schedule a new retry timer that the previous timer cannot be cancelled. In this
  2309. // case the timer Handle &| Unique field will be different, and we do not want to run the event.
  2310. // Make sure this isn't a leftover event
  2311. if((pEPD->RetryTimer != uID) || (pEPD->RetryTimerUnique != Unique))
  2312. {
  2313. DPFX(DPFPREP,7, "(%p) Stale retry timer, exiting", pEPD);
  2314. RELEASE_EPD(pEPD, "UNLOCK (stale retry timer)"); // releases EPLock
  2315. return;
  2316. }
  2317. pEPD->RetryTimer = 0;
  2318. // Make sure that we still have transmits in progress
  2319. if(pEPD->uiUnackedFrames > 0)
  2320. {
  2321. ASSERT(!pEPD->blSendWindow.IsEmpty());
  2322. pFMD = CONTAINING_OBJECT(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage); // Top frame in window
  2323. ASSERT_FMD(pFMD);
  2324. ASSERT(pFMD->ulFFlags & FFLAGS_RETRY_TIMER_SET);
  2325. // First we must make sure that the TO'd packet is still hanging around. Since the first packet
  2326. // in the window might have changed while the TO was being scheduled, the easiest thing to do is
  2327. // just recalculate the top packets expiration time and make sure its really stale.
  2328. tDelta = tNow - pFMD->dwLastSendTime; // When did we last send this frame?
  2329. if(tDelta > pEPD->uiRetryTimeout)
  2330. {
  2331. // Its a genuine timeout. Lets retransmit the frame!
  2332. DPFX(DPFPREP,7, "(%p) RETRY TIMEOUT %d on Seq=%x, pFMD=0x%p", pEPD, (pFMD->uiRetry + 1), ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  2333. // Count a retry
  2334. if(++pFMD->uiRetry > pPData->dwSendRetriesToDropLink)
  2335. {
  2336. // BOOM! No more retries. We are finished. Link is going DOWN!
  2337. DPFX(DPFPREP,1, "(%p) DROPPING LINK, retries exhausted", pEPD);
  2338. DECREMENT_EPD(pEPD, "UNLOCK (retry timer drop)");// Release reference for this timer
  2339. DropLink(pEPD); // releases EPLock
  2340. return;
  2341. }
  2342. #ifdef DBG
  2343. DNInterlockedIncrement(&g_RetryCount[pFMD->uiRetry]);
  2344. #endif // DBG
  2345. // calculate timeout for next retry
  2346. if(pFMD->uiRetry == 1)
  2347. {
  2348. // do a retry at the same timeout - this is games after all.
  2349. tDelta = pEPD->uiRetryTimeout;
  2350. }
  2351. else if (pFMD->uiRetry <= 3)
  2352. {
  2353. // do a couple of linear backoffs - this is a game after all
  2354. tDelta = pEPD->uiRetryTimeout * pFMD->uiRetry;
  2355. }
  2356. else if (pFMD->uiRetry < 8)
  2357. {
  2358. // doh, bad link, bad bad link, do exponential backoffs
  2359. tDelta = pEPD->uiRetryTimeout * (1 << pFMD->uiRetry);
  2360. }
  2361. else
  2362. {
  2363. // don't give up too quickly.
  2364. tDelta = pPData->dwSendRetryIntervalLimit;
  2365. }
  2366. if(tDelta >=pPData->dwSendRetryIntervalLimit)
  2367. {
  2368. // CAP TOTAL DROP TIME AT 50 seconds unless the RTT is huge
  2369. tDelta = _MAX(pPData->dwSendRetryIntervalLimit, pEPD->uiRTT);
  2370. }
  2371. // Unreliable frame!
  2372. if ((pFMD->CommandID == COMMAND_ID_SEND_DATAGRAM) ||
  2373. ((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) && (! (pFMD->ulFFlags & FFLAGS_RELIABLE))))
  2374. {
  2375. // When an unreliable frame is NACKed we will not retransmit the data. We will instead send
  2376. // a mask so that the other side knows to cancel it.
  2377. DPFX(DPFPREP,7, "(%p) RETRY TIMEOUT for UNRELIABLE FRAME", pEPD);
  2378. // We get to credit the frame as out of the window.
  2379. pEPD->uiUnackedBytes -= pFMD->uiFrameLength;
  2380. // Only count a datagram drop on the first occurance
  2381. if(pFMD->uiRetry == 1)
  2382. {
  2383. pEPD->uiDatagramFramesDropped++;
  2384. pEPD->uiDatagramBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength);
  2385. EndPointDroppedFrame(pEPD, tNow);
  2386. }
  2387. // Diff between next send and this send.
  2388. delta = (pEPD->bNextSend - ((PDFRAME) pFMD->ImmediateData)->bSeq) & 0xFF ;
  2389. ASSERT(delta != 0);
  2390. ASSERT(delta < (MAX_RECEIVE_RANGE + 1));
  2391. if(delta < 33)
  2392. {
  2393. pEPD->ulSendMask |= (1 << (delta - 1));
  2394. }
  2395. else
  2396. {
  2397. pEPD->ulSendMask2 |= (1 << (delta - 33));
  2398. }
  2399. pFMD->uiFrameLength = 0;
  2400. pEPD->ulEPFlags |= EPFLAGS_DELAYED_SENDMASK;
  2401. if(pEPD->DelayedMaskTimer == 0)
  2402. {
  2403. DPFX(DPFPREP,7, "(%p) Setting Delayed Mask Timer", pEPD);
  2404. LOCK_EPD(pEPD, "LOCK (delayed mask timer - send retry)");
  2405. ScheduleProtocolTimer(pSPD, DELAYED_SEND_TIMEOUT, 0, DelayedAckTimeout, (PVOID) pEPD,
  2406. &pEPD->DelayedMaskTimer, &pEPD->DelayedMaskTimerUnique);
  2407. }
  2408. }
  2409. // RELIABLE FRAME -- Send a retry
  2410. else
  2411. {
  2412. pEPD->uiGuaranteedFramesDropped++; // Keep count of lost frames
  2413. pEPD->uiGuaranteedBytesDropped += (pFMD->uiFrameLength - pFMD->uiImmediateLength); // Keep count of lost frames
  2414. pFMD->dwLastSendTime = tNow;
  2415. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE); // No longer waiting to send Ack info
  2416. // Stop delayed ack timer
  2417. if(pEPD->DelayedAckTimer != 0)
  2418. {
  2419. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  2420. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  2421. {
  2422. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAck)"); // SPLock not already held
  2423. }
  2424. else
  2425. {
  2426. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  2427. }
  2428. pEPD->DelayedAckTimer = 0;
  2429. }
  2430. EndPointDroppedFrame(pEPD, tNow);
  2431. if(pFMD->ulFFlags & FFLAGS_RETRY_QUEUED)
  2432. {
  2433. // It's still on the Retry Queue. This should not happen when everything is working
  2434. // properly. Timeouts should be greater than RTT and the BurstGap should be less than RTT.
  2435. DPFX(DPFPREP,1, "(%p) RETRY FIRES WHILE FMD IS STILL IN RETRY QUEUE pFMD=%p", pEPD, pFMD);
  2436. pFMD = NULL;
  2437. }
  2438. else if(pFMD->bSubmitted)
  2439. {
  2440. // Woe on us. We would like to retry a frame that has not been completed by the SP!
  2441. //
  2442. // This will most typically happen when we are debugging which delays processing
  2443. // of the Complete, but it could also happen if the SP is getting hammered. We need
  2444. // to copy the FMD into a temporary descriptor which can be discarded upon completion...
  2445. DPFX(DPFPREP,1,"(%p) RETRYING %p but its still busy. Substituting new FMD", pEPD, pFMD);
  2446. pFMD = CopyFMD(pFMD, pEPD); // We will substitute new FMD in rest of procedure
  2447. }
  2448. else
  2449. {
  2450. DPFX(DPFPREP,7, "(%p) Sending Retry of N(S)=%x, pFMD=0x%p", pEPD, ((PDFRAME) pFMD->ImmediateData)->bSeq, pFMD);
  2451. LOCK_FMD(pFMD, "SP retry submit");
  2452. }
  2453. if(pFMD)
  2454. {
  2455. LOCK_EPD(pEPD, "LOCK (retry rely frame)");
  2456. pEPD->ulEPFlags |= EPFLAGS_RETRIES_QUEUED;
  2457. pFMD->ulFFlags |= FFLAGS_RETRY_QUEUED;
  2458. // Increment the frame count for all relevant FMDs.
  2459. if ((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) ||
  2460. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  2461. {
  2462. // Loop through each subframe and update its state.
  2463. pLink = pFMD->blCoalesceLinkage.GetNext();
  2464. while (pLink != &pFMD->blCoalesceLinkage)
  2465. {
  2466. pRealFMD = CONTAINING_OBJECT(pLink, FMD, blCoalesceLinkage);
  2467. ASSERT_FMD(pRealFMD);
  2468. // Datagrams get pulled out of the list as soon as they complete sending, and if the frame
  2469. // hadn't finished sending we would have made a copy above. So we shouldn't see any
  2470. // datagrams here.
  2471. ASSERT((pRealFMD->CommandID == COMMAND_ID_SEND_RELIABLE) || (pRealFMD->CommandID == COMMAND_ID_COPIED_RETRY));
  2472. LOCK_EPD(pEPD, "LOCK (retry rely frame coalesce)");
  2473. // Add a frame reference if it's not a temporary copy.
  2474. if (pRealFMD->CommandID != COMMAND_ID_COPIED_RETRY)
  2475. {
  2476. LOCK_FMD(pRealFMD, "SP retry submit (coalesce)");
  2477. }
  2478. ASSERT_MSD(pRealFMD->pMSD);
  2479. pRealFMD->pMSD->uiFrameCount++; // Protected by EPLock, retries prevent completion until they complete
  2480. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "(%p) Frame count incremented on coalesced retry timeout, pMSD[%p], framecount[%u]", pEPD, pRealFMD->pMSD, pRealFMD->pMSD->uiFrameCount);
  2481. pLink = pLink->GetNext();
  2482. }
  2483. DPFX(DPFPREP, 7, "(0x%p) Coalesced retry frame 0x%p (original was %u bytes in %u buffers).", pEPD, pFMD, pFMD->uiFrameLength, pFMD->SendDataBlock.dwBufferCount);
  2484. #pragma TODO(vanceo, "Would be nice to credit window")
  2485. /*
  2486. // Similar to uncoalesced datagram sends, we get to credit the non-reliable part of this frame
  2487. // as being out of the window. We won't update the nonguaranteed stats, the data was
  2488. // counted in the guaranteed stats update above.
  2489. pEPD->uiUnackedBytes -= uiOriginalFrameLength - pFMD->uiFrameLength;
  2490. ASSERT(pEPD->uiUnackedBytes <= MAX_RECEIVE_RANGE * pSPD->uiFrameLength);
  2491. ASSERT(pEPD->uiUnackedBytes > 0);
  2492. ASSERT(pEPD->uiUnackedFrames > 0);
  2493. */
  2494. }
  2495. else
  2496. {
  2497. ASSERT_MSD(pFMD->pMSD);
  2498. pFMD->pMSD->uiFrameCount++; // Protected by EPLock, retries prevent completion until they complete
  2499. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "(%p) Frame count incremented on retry timeout, pMSD[%p], framecount[%u]", pEPD, pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  2500. }
  2501. ASSERT(pFMD->blQLinkage.IsEmpty());
  2502. pFMD->blQLinkage.InsertBefore( &pEPD->blRetryQueue); // Place frame on Send queue
  2503. if((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0)
  2504. {
  2505. DPFX(DPFPREP,7, "(%p) Scheduling Send", pEPD);
  2506. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  2507. LOCK_EPD(pEPD, "LOCK (pipeline)");
  2508. ScheduleProtocolWork(pSPD, ScheduledSend, pEPD);
  2509. }
  2510. }
  2511. } // ENDIF RETRY
  2512. }
  2513. else
  2514. {
  2515. tDelta = pEPD->uiRetryTimeout - tDelta;
  2516. }
  2517. DPFX(DPFPREP,7, "(%p) Setting Retry Timer for %d ms", pEPD, tDelta);
  2518. // Dont LOCK_EPD here because we never released the lock from the timer which scheduled us here
  2519. pEPD->RetryTimer=uID;
  2520. RescheduleProtocolTimer(pSPD, pEPD->RetryTimer, tDelta, 20, RetryTimeout, (PVOID) pEPD, &pEPD->RetryTimerUnique);
  2521. Unlock(&pEPD->EPLock);
  2522. }
  2523. else
  2524. {
  2525. RELEASE_EPD(pEPD, "UNLOCK (RetryTimer no frames out)"); // drop RefCnt since we dont restart timer, releases EPLock
  2526. }
  2527. }
  2528. /*
  2529. ** Copy FMD
  2530. **
  2531. ** This routine allocates a new Frame Descriptor and copies all fields from the provided
  2532. ** FMD into it. All fields except CommandID, RefCnt, and Flags.
  2533. */
  2534. #undef DPF_MODNAME
  2535. #define DPF_MODNAME "CopyFMD"
  2536. PFMD CopyFMD(PFMD pFMD, PEPD pEPD)
  2537. {
  2538. PFMD pNewFMD;
  2539. CBilink *pLink;
  2540. PFMD pSubFrame;
  2541. PFMD pNewSubFrame;
  2542. if((pNewFMD = (PFMD)(POOLALLOC(MEMID_COPYFMD_FMD, &FMDPool))) == NULL)
  2543. {
  2544. DPFX(DPFPREP,0, "Failed to allocate new FMD");
  2545. return NULL;
  2546. }
  2547. LOCK_EPD(pEPD, "LOCK (CopyFMD)");
  2548. memcpy(pNewFMD, pFMD, sizeof(FMD));
  2549. // Undo the copying of these members
  2550. pNewFMD->blMSDLinkage.Initialize();
  2551. pNewFMD->blQLinkage.Initialize();
  2552. pNewFMD->blWindowLinkage.Initialize();
  2553. pNewFMD->blCoalesceLinkage.Initialize();
  2554. if ((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) ||
  2555. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  2556. {
  2557. pNewFMD->CommandID = COMMAND_ID_COPIED_RETRY_COALESCE;
  2558. // We need to make copies of all the reliable subframes.
  2559. ASSERT(! pFMD->blCoalesceLinkage.IsEmpty());
  2560. pLink = pFMD->blCoalesceLinkage.GetNext();
  2561. while (pLink != &pFMD->blCoalesceLinkage)
  2562. {
  2563. pSubFrame = CONTAINING_OBJECT(pLink, FMD, blCoalesceLinkage);
  2564. ASSERT_FMD(pSubFrame);
  2565. if (pSubFrame->CommandID != COMMAND_ID_SEND_DATAGRAM)
  2566. {
  2567. ASSERT((pSubFrame->CommandID == COMMAND_ID_SEND_RELIABLE) || (pSubFrame->CommandID == COMMAND_ID_COPIED_RETRY));
  2568. pNewSubFrame = CopyFMD(pSubFrame, pEPD);
  2569. if(pNewSubFrame == NULL)
  2570. {
  2571. DPFX(DPFPREP,0, "Failed to copy new subframe FMD");
  2572. // Free all the subframes we've successfully copied so far.
  2573. while (! pNewFMD->blCoalesceLinkage.IsEmpty())
  2574. {
  2575. pNewSubFrame = CONTAINING_OBJECT(pNewFMD->blCoalesceLinkage.GetNext(), FMD, blCoalesceLinkage);
  2576. ASSERT_FMD(pNewSubFrame);
  2577. pNewSubFrame->blCoalesceLinkage.RemoveFromList();
  2578. RELEASE_FMD(pNewSubFrame, "Final subframe release on mem fail");
  2579. }
  2580. // Free the copied coalescence header.
  2581. RELEASE_FMD(pNewFMD, "Final release on mem fail");
  2582. return NULL;
  2583. }
  2584. // Change the immediate data buffer desc to point to a zero padding buffer in case this
  2585. // packet needs to be DWORD aligned.
  2586. ASSERT(pNewSubFrame->lpImmediatePointer == pNewSubFrame->ImmediateData);
  2587. DBG_CASSERT(sizeof(COALESCEHEADER) <= 4);
  2588. pNewSubFrame->lpImmediatePointer = pNewSubFrame->ImmediateData + 4;
  2589. *((DWORD*) pNewSubFrame->lpImmediatePointer) = 0;
  2590. ASSERT(pNewSubFrame->SendDataBlock.pBuffers == (PBUFFERDESC) &pNewSubFrame->uiImmediateLength);
  2591. if (pSubFrame->SendDataBlock.pBuffers != (PBUFFERDESC) &pSubFrame->uiImmediateLength)
  2592. {
  2593. ASSERT(pSubFrame->SendDataBlock.pBuffers == pSubFrame->rgBufferList);
  2594. pNewSubFrame->SendDataBlock.pBuffers = pNewSubFrame->rgBufferList;
  2595. }
  2596. else
  2597. {
  2598. ASSERT(pNewSubFrame->SendDataBlock.dwBufferCount > 1);
  2599. }
  2600. // Copied coalesced retries don't maintain a reference on their containing header.
  2601. pNewSubFrame->pCSD = NULL;
  2602. pNewSubFrame->blCoalesceLinkage.InsertBefore(&pNewFMD->blCoalesceLinkage);
  2603. }
  2604. else
  2605. {
  2606. // Datagrams should get pulled out of the list as soon as they complete so we normally we
  2607. // wouldn't see them at retry time. But we're making a copy because the original frame
  2608. // is still in the SP, so there could be uncompleted datagrams still here.
  2609. DPFX(DPFPREP, 1, "(0x%p) Not including datagram frame 0x%p that's still in the SP", pEPD, pSubFrame);
  2610. }
  2611. pLink = pLink->GetNext();
  2612. }
  2613. }
  2614. else
  2615. {
  2616. ASSERT((pFMD->CommandID == COMMAND_ID_SEND_RELIABLE) || (pFMD->CommandID == COMMAND_ID_COPIED_RETRY));
  2617. pNewFMD->CommandID = COMMAND_ID_COPIED_RETRY;
  2618. }
  2619. pNewFMD->lRefCnt = 1;
  2620. pNewFMD->ulFFlags = 0;
  2621. pNewFMD->bSubmitted = FALSE;
  2622. pNewFMD->lpImmediatePointer = (LPVOID) pNewFMD->ImmediateData;
  2623. pNewFMD->SendDataBlock.pBuffers = (PBUFFERDESC) &pNewFMD->uiImmediateLength;
  2624. pNewFMD->SendDataBlock.pvContext = pNewFMD;
  2625. pNewFMD->SendDataBlock.hCommand = 0;
  2626. ASSERT( pNewFMD->pEPD == pEPD);
  2627. DPFX(DPFPREP,7, "COPYFMD -- replacing FMD %p with copy %p", pFMD, pNewFMD);
  2628. return pNewFMD;
  2629. }
  2630. /*
  2631. ** Send Command Frame
  2632. **
  2633. ** Build a CFrame addressed to the specified EndPoint, and Queue it on the SPD
  2634. ** to be sent.
  2635. **
  2636. ** ** THIS FUNCTION CALLED WITH EPD->EPLOCK HELD. IF bSendDirect IS FALSE IT RETURNS **
  2637. ** ** WITH THE LOCK STILL HELD. IF bSendDirect IS TRUE IT RETURNS WITH THE EPD LOCK RELEASED **
  2638. */
  2639. #undef DPF_MODNAME
  2640. #define DPF_MODNAME "SendCommandFrame"
  2641. HRESULT SendCommandFrame(PEPD pEPD, BYTE ExtOpcode, BYTE RspID, ULONG ulFFlags, BOOL bSendDirect)
  2642. {
  2643. PSPD pSPD = pEPD->pSPD;
  2644. PFMD pFMD;
  2645. PCFRAME pCFrame;
  2646. PCHKPT pChkPt;
  2647. DWORD tNow = GETTIMESTAMP();
  2648. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2649. // Frame already initialized to 1 buffer
  2650. if((pFMD = (PFMD)POOLALLOC(MEMID_SENDCMD_FMD, &FMDPool)) == NULL)
  2651. {
  2652. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD", pEPD);
  2653. if (bSendDirect)
  2654. {
  2655. Unlock(&pEPD->EPLock);
  2656. }
  2657. return DPNERR_OUTOFMEMORY;
  2658. }
  2659. pCFrame = (PCFRAME)pFMD->ImmediateData;
  2660. pCFrame->bCommand = 0;
  2661. // If this frame requires a response (or if we are specifically asked to) we will build
  2662. // a Checkpoint structure which will be stored to correlate the eventual response with
  2663. // the original frame.
  2664. if( (pEPD->ulEPFlags & EPFLAGS_CHECKPOINT_INIT)||
  2665. (ExtOpcode == FRAME_EXOPCODE_CONNECT))
  2666. {
  2667. if((pChkPt = (PCHKPT)POOLALLOC(MEMID_CHKPT, &ChkPtPool)) != NULL)
  2668. {
  2669. pChkPt->bMsgID = pEPD->bNextMsgID; // Note next ID in CP structure
  2670. pCFrame->bCommand |= PACKET_COMMAND_POLL; // make this frame a CP
  2671. pEPD->ulEPFlags &= ~EPFLAGS_CHECKPOINT_INIT;
  2672. pChkPt->tTimestamp = tNow;
  2673. pChkPt->blLinkage.Initialize();
  2674. pChkPt->blLinkage.InsertBefore(&pEPD->blChkPtQueue);
  2675. }
  2676. else
  2677. {
  2678. // If we need a checkpoint and don't get one, then the operation can't succeed
  2679. // because the response won't be able to be correllated.
  2680. DPFX(DPFPREP,0, "(%p) Failed to allocate new CHKPT", pEPD);
  2681. RELEASE_FMD(pFMD, "Final Release on Mem Fail");
  2682. if (bSendDirect)
  2683. {
  2684. Unlock(&pEPD->EPLock);
  2685. }
  2686. return DPNERR_OUTOFMEMORY;
  2687. }
  2688. }
  2689. pFMD->pEPD = pEPD; // Track EPD for RefCnt
  2690. LOCK_EPD(pEPD, "LOCK (Prep Cmd Frame)"); // Bump RefCnt on EPD until send is completed
  2691. pFMD->CommandID = COMMAND_ID_CFRAME;
  2692. pFMD->pMSD = NULL; // this will indicate a NON-Data frame
  2693. pFMD->uiImmediateLength = sizeof(CFRAME); // standard size for C Frames
  2694. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt; // Place address in frame
  2695. pFMD->ulFFlags=ulFFlags; //whatever flags for frame caller has specified
  2696. pCFrame->bCommand |= PACKET_COMMAND_CFRAME;
  2697. pCFrame->bExtOpcode = ExtOpcode;
  2698. pCFrame->dwVersion = DNET_VERSION_NUMBER;
  2699. pCFrame->bRspID = RspID;
  2700. pCFrame->dwSessID = pEPD->dwSessID;
  2701. pCFrame->tTimestamp = tNow;
  2702. pCFrame->bMsgID = pEPD->bNextMsgID++; // include MsgID in frame
  2703. //if we're sending a hard disconnect and the link is signed then we also need to sign the hard disconnect frame
  2704. if ((ExtOpcode==FRAME_EXOPCODE_HARD_DISCONNECT) && (pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK))
  2705. {
  2706. UNALIGNED ULONGLONG * pullSig=(UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength);
  2707. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  2708. //fast signing is trivial, simply store the local secret as the sig in the outgoing frame
  2709. if (pEPD->ulEPFlags2 & EPFLAGS2_FAST_SIGNED_LINK)
  2710. {
  2711. *pullSig=pEPD->ullCurrentLocalSecret;
  2712. }
  2713. //otherwise if we're full signing it we need to hash the frame to generate the sig
  2714. else
  2715. {
  2716. DNASSERT(pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK);
  2717. //we stuff the next data frame sequence num in each hard disconnects response id
  2718. //this allows the receiver to work out what secret it should be using to check the signature
  2719. pCFrame->bRspID = pEPD->bNextSend;
  2720. //zero the space where this sig goes so we have a known packet state to hash over
  2721. *pullSig=0;
  2722. *pullSig=GenerateOutgoingFrameSig(pFMD, pEPD->ullCurrentLocalSecret);
  2723. }
  2724. }
  2725. pFMD->uiFrameLength = pFMD->uiImmediateLength ;
  2726. //take SP lock and queue frame up for sending
  2727. Lock(&pSPD->SPLock);
  2728. ASSERT(pFMD->blQLinkage.IsEmpty());
  2729. pFMD->blQLinkage.InsertBefore( &pSPD->blSendQueue);
  2730. //if we want to commit the send immediately then do so, otherwise schedule worker thread
  2731. //to do the send if necessary
  2732. if (bSendDirect)
  2733. {
  2734. Unlock(&pEPD->EPLock);
  2735. //call with SP lock held and EPD lock released
  2736. ServiceCmdTraffic(pSPD);
  2737. //returns with SP lock still held
  2738. }
  2739. else
  2740. {
  2741. if((pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)==0)
  2742. {
  2743. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  2744. pSPD->ulSPFlags |= SPFLAGS_SEND_THREAD_SCHEDULED;
  2745. ScheduleProtocolWork(pSPD, RunSendThread, pSPD);
  2746. }
  2747. }
  2748. Unlock(&pSPD->SPLock);
  2749. return DPN_OK;
  2750. }
  2751. /*
  2752. ** SendConnectedSignedFrame
  2753. **
  2754. ** Sends a connected signed cframe in response to receiving one
  2755. ** This is called when this side is connecting (as opposed to listening) and we've just
  2756. ** receiveived a CONNECTEDSIGNED frame from the listener.
  2757. **
  2758. ** Called with EP lock held and returns with it held
  2759. */
  2760. #undef DPF_MODNAME
  2761. #define DPF_MODNAME "SendConnectedSignedFrame"
  2762. HRESULT SendConnectedSignedFrame(PEPD pEPD, CFRAME_CONNECTEDSIGNED * pCFrameRecv, DWORD tNow)
  2763. {
  2764. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2765. PSPD pSPD = pEPD->pSPD;
  2766. //get a frame to send
  2767. PFMD pFMD=(PFMD) POOLALLOC(MEMID_SENDCMD_FMD, &FMDPool);
  2768. if (pFMD== NULL)
  2769. {
  2770. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD", pEPD);
  2771. return DPNERR_OUTOFMEMORY;
  2772. }
  2773. pFMD->pEPD = pEPD; // Track EPD for RefCnt
  2774. LOCK_EPD(pEPD, "LOCK (Prep Cmd Frame)"); // Bump RefCnt on EPD until send is completed
  2775. pFMD->CommandID = COMMAND_ID_CFRAME;
  2776. pFMD->pMSD = NULL; // this will indicate a NON-Data frame
  2777. pFMD->uiImmediateLength = sizeof(CFRAME_CONNECTEDSIGNED);
  2778. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt; // Place address in frame
  2779. pFMD->uiFrameLength = sizeof(CFRAME_CONNECTEDSIGNED); // Never have user data in Cframe
  2780. pFMD->ulFFlags=0;
  2781. //fill out fields common to all CFRAMES
  2782. CFRAME_CONNECTEDSIGNED * pCFrameSend = (CFRAME_CONNECTEDSIGNED *) pFMD->ImmediateData;
  2783. pCFrameSend->bCommand = PACKET_COMMAND_CFRAME;
  2784. pCFrameSend->bExtOpcode = FRAME_EXOPCODE_CONNECTED_SIGNED;
  2785. pCFrameSend->dwVersion = DNET_VERSION_NUMBER;
  2786. pCFrameSend->bRspID = 0;
  2787. pCFrameSend->dwSessID = pCFrameRecv->dwSessID;
  2788. pCFrameSend->tTimestamp = tNow;
  2789. pCFrameSend->bMsgID = pEPD->bNextMsgID++;
  2790. //and fill out fields specific to CONNECTEDSIGNED frames
  2791. pCFrameSend->ullConnectSig=pCFrameRecv->ullConnectSig;
  2792. pCFrameSend->ullSenderSecret=pEPD->ullCurrentLocalSecret;
  2793. pCFrameSend->ullReceiverSecret=pEPD->ullCurrentRemoteSecret;
  2794. pCFrameSend->dwSigningOpts=pCFrameRecv->dwSigningOpts;
  2795. pCFrameSend->dwEchoTimestamp=pCFrameRecv->tTimestamp;
  2796. //take SP lock and queue frame up for sending
  2797. Lock(&pSPD->SPLock);
  2798. ASSERT(pFMD->blQLinkage.IsEmpty());
  2799. pFMD->blQLinkage.InsertBefore( &pSPD->blSendQueue);
  2800. if((pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)==0)
  2801. {
  2802. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  2803. pSPD->ulSPFlags |= SPFLAGS_SEND_THREAD_SCHEDULED;
  2804. ScheduleProtocolWork(pSPD, RunSendThread, pSPD);
  2805. }
  2806. Unlock(&pSPD->SPLock);
  2807. return DPN_OK;
  2808. }
  2809. /*
  2810. ** Send Ack Frame
  2811. **
  2812. ** This routine is called to immediately transmit our current receive
  2813. ** state to the indicated EndPoint. This is equivalent to acknowledging
  2814. ** all received frames. We may want to change this routine so that it
  2815. ** will attempt to piggyback the ack if there is data waiting to be sent.
  2816. **
  2817. ** THIS ROUTINE IS CALLED WITH EDP->EPLOCK HELD, BUT RELEASES IT IF DirectFlag IS SET
  2818. */
  2819. #undef DPF_MODNAME
  2820. #define DPF_MODNAME "SendAckFrame"
  2821. VOID SendAckFrame(PEPD pEPD, BOOL DirectFlag, BOOL fFinalAck/* = FALSE*/)
  2822. {
  2823. PSPD pSPD = pEPD->pSPD;
  2824. PFMD pFMD;
  2825. UINT index = 0;
  2826. PSACKFRAME8 pSackFrame;
  2827. ASSERT_SPD(pSPD);
  2828. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2829. // Frame already initialized to 1 buffer
  2830. if((pFMD = (PFMD)POOLALLOC(MEMID_ACK_FMD, &FMDPool)) == NULL)
  2831. {
  2832. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD", pEPD);
  2833. if(DirectFlag)
  2834. {
  2835. Unlock(&pEPD->EPLock);
  2836. }
  2837. return;
  2838. }
  2839. // We can stop all delayed Ack timers since we are sending full status here.
  2840. if(pEPD->DelayedAckTimer != 0)
  2841. {
  2842. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  2843. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique) == DPN_OK)
  2844. {
  2845. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedAck timer)");
  2846. }
  2847. else
  2848. {
  2849. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  2850. }
  2851. pEPD->DelayedAckTimer = 0;
  2852. }
  2853. if(pEPD->DelayedMaskTimer != 0)
  2854. {
  2855. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  2856. if(CancelProtocolTimer(pSPD, pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  2857. {
  2858. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMask timer)");
  2859. }
  2860. else
  2861. {
  2862. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  2863. }
  2864. pEPD->DelayedMaskTimer = 0;
  2865. }
  2866. if (fFinalAck)
  2867. {
  2868. pFMD->ulFFlags |= FFLAGS_FINAL_ACK;
  2869. }
  2870. pFMD->pEPD = pEPD; // Track EPD for RefCnt
  2871. LOCK_EPD(pEPD, "LOCK (SendAckFrame)"); // Bump RefCnt on EPD until send is completed
  2872. pFMD->CommandID = COMMAND_ID_CFRAME;
  2873. pFMD->pMSD = NULL; // this will indicate a NON-Data frame
  2874. pFMD->SendDataBlock.hEndpoint = pEPD->hEndPt;
  2875. // Now that DG and S have been merged, there are no longer 3 flavors of ACK frame. We are back to only
  2876. // one flavor that may or may not have detailed response info on one frame. Actually, I think we can
  2877. // always include response info on the last ack'd frame.
  2878. pSackFrame = (PSACKFRAME8) pFMD->ImmediateData;
  2879. pSackFrame->bCommand = PACKET_COMMAND_CFRAME;
  2880. pSackFrame->bExtOpcode = FRAME_EXOPCODE_SACK;
  2881. pSackFrame->bNSeq = pEPD->bNextSend;
  2882. pSackFrame->bNRcv = pEPD->bNextReceive;
  2883. pSackFrame->bFlags = 0;
  2884. pSackFrame->bReserved1 = 0;
  2885. pSackFrame->bReserved2 = 0;
  2886. pSackFrame->tTimestamp = pEPD->tLastDataFrame;
  2887. ULONG * rgMask=(ULONG * ) (pSackFrame+1);
  2888. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_NACK)
  2889. {
  2890. DPFX(DPFPREP,7, "(%p) SENDING SACK WITH *NACK* N(R)=%x Low=%x High=%x", pEPD, pEPD->bNextReceive, pEPD->ulReceiveMask, pEPD->ulReceiveMask2);
  2891. if(pEPD->ulReceiveMask)
  2892. {
  2893. rgMask[index++] = pEPD->ulReceiveMask;
  2894. pSackFrame->bFlags |= SACK_FLAGS_SACK_MASK1;
  2895. }
  2896. if(pEPD->ulReceiveMask2)
  2897. {
  2898. rgMask[index++] = pEPD->ulReceiveMask2;
  2899. pSackFrame->bFlags |= SACK_FLAGS_SACK_MASK2;
  2900. }
  2901. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  2902. }
  2903. if(pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)
  2904. {
  2905. DPFX(DPFPREP,7, "(%p) SENDING SACK WITH SEND MASK N(S)=%x Low=%x High=%x", pEPD, pEPD->bNextSend, pEPD->ulSendMask, pEPD->ulSendMask2);
  2906. if(pEPD->ulSendMask)
  2907. {
  2908. rgMask[index++] = pEPD->ulSendMask;
  2909. pSackFrame->bFlags |= SACK_FLAGS_SEND_MASK1;
  2910. pEPD->ulSendMask = 0;
  2911. }
  2912. if(pEPD->ulSendMask2)
  2913. {
  2914. rgMask[index++] = pEPD->ulSendMask2;
  2915. pSackFrame->bFlags |= SACK_FLAGS_SEND_MASK2;
  2916. pEPD->ulSendMask2 = 0;
  2917. }
  2918. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_SENDMASK);
  2919. }
  2920. pSackFrame->bFlags |= SACK_FLAGS_RESPONSE; // time fields are always valid now
  2921. #ifdef DBG
  2922. ASSERT(pEPD->bLastDataSeq == (BYTE) (pEPD->bNextReceive - 1));
  2923. #endif // DBG
  2924. pSackFrame->bRetry = pEPD->bLastDataRetry;
  2925. pEPD->ulEPFlags &= ~(EPFLAGS_DELAY_ACKNOWLEDGE);
  2926. pFMD->uiImmediateLength = sizeof(SACKFRAME8) + (index * sizeof(ULONG));
  2927. //if we've got a signed link we'd better sign this frame. Signature goes at the end after the various masks
  2928. if (pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK)
  2929. {
  2930. UNALIGNED ULONGLONG * pullSig=(UNALIGNED ULONGLONG * ) (pFMD->ImmediateData+ pFMD->uiImmediateLength);
  2931. pFMD->uiImmediateLength+=sizeof(ULONGLONG);
  2932. //fast signed link is trivial simply insert the local secret as the sig
  2933. if (pEPD->ulEPFlags2 & EPFLAGS2_FAST_SIGNED_LINK)
  2934. {
  2935. *pullSig=pEPD->ullCurrentLocalSecret;
  2936. }
  2937. else
  2938. {
  2939. //otherwise if we're full signing it we need to hash the frame to generate the sig
  2940. DNASSERT(pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK);
  2941. *pullSig=0;
  2942. *pullSig=GenerateOutgoingFrameSig(pFMD, pEPD->ullCurrentLocalSecret);
  2943. }
  2944. }
  2945. pFMD->uiFrameLength = pFMD->uiImmediateLength;
  2946. 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);
  2947. // We can either schedule a worker thread to do the send or else we can do the work ourselves.
  2948. // The DirectFlag tells us whether we are in a time-crit section, like processing
  2949. // receive data, or whether we are free to call the SP ourselves.
  2950. Lock(&pSPD->SPLock); // Place SACK frame on send queue
  2951. ASSERT(pFMD->blQLinkage.IsEmpty());
  2952. pFMD->blQLinkage.InsertBefore( &pSPD->blSendQueue);
  2953. if(DirectFlag)
  2954. {
  2955. // ServiceCmdTraffic will call into the SP so we must not hold the EPD lock
  2956. Unlock(&pEPD->EPLock);
  2957. ServiceCmdTraffic(pSPD); // Called with SPLock held
  2958. }
  2959. else
  2960. {
  2961. if((pSPD->ulSPFlags & SPFLAGS_SEND_THREAD_SCHEDULED)==0)
  2962. {
  2963. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  2964. pSPD->ulSPFlags |= SPFLAGS_SEND_THREAD_SCHEDULED;
  2965. ScheduleProtocolWork(pSPD, RunSendThread, pSPD);
  2966. }
  2967. }
  2968. Unlock(&pSPD->SPLock);
  2969. }
  2970. /*
  2971. ** Delayed Ack Timeout
  2972. **
  2973. ** We are waiting for a chance to piggyback a reliable frame acknowledgement,
  2974. ** but the sands have run out. Its time to send a dedicated Ack now.
  2975. */
  2976. #undef DPF_MODNAME
  2977. #define DPF_MODNAME "DelayedAckTimeout"
  2978. VOID CALLBACK DelayedAckTimeout(void * const pvUser, void * const uID, const UINT uMsg)
  2979. {
  2980. PEPD pEPD = (PEPD) pvUser;
  2981. ASSERT_EPD(pEPD);
  2982. Lock(&pEPD->EPLock);
  2983. DPFX(DPFPREP,7, "(%p) Delayed Ack Timer fires", pEPD);
  2984. if((pEPD->DelayedAckTimer == uID)&&(pEPD->DelayedAckTimerUnique == uMsg))
  2985. {
  2986. pEPD->DelayedAckTimer = 0;
  2987. }
  2988. else if((pEPD->DelayedMaskTimer == uID)&&(pEPD->DelayedMaskTimerUnique == uMsg))
  2989. {
  2990. pEPD->DelayedMaskTimer = 0;
  2991. }
  2992. else
  2993. {
  2994. // Stale timer, ignore
  2995. DPFX(DPFPREP,7, "(%p) Stale Delayed Ack Timer, ignoring", pEPD);
  2996. RELEASE_EPD(pEPD, "UNLOCK (DelayedAck complete)"); // release reference for timer, releases EPLock
  2997. return;
  2998. }
  2999. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  3000. if (pEPD->ulEPFlags & EPFLAGS_NO_DELAYED_ACKS)
  3001. {
  3002. DPFX(DPFPREP,7, "(%p) DEBUG: Skipping delayed ACK due to test request", pEPD);
  3003. }
  3004. else
  3005. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  3006. {
  3007. if( (pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) && (pEPD->ulEPFlags & (EPFLAGS_DELAY_ACKNOWLEDGE | EPFLAGS_DELAYED_NACK | EPFLAGS_DELAYED_SENDMASK)))
  3008. {
  3009. DPFX(DPFPREP,7, "(%p) Sending ACK frame", pEPD);
  3010. SendAckFrame(pEPD, 0);
  3011. }
  3012. else
  3013. {
  3014. DPFX(DPFPREP,7, "(%p) Nothing to do, ACK already occurred or no longer connected", pEPD);
  3015. }
  3016. }
  3017. RELEASE_EPD(pEPD, "UNLOCK (DelayedAck complete)"); // release reference for timer, releases EPLock
  3018. }
  3019. /*
  3020. ** Send Keep Alive
  3021. **
  3022. ** When we have not received anything from an endpoint in a long time (default 60 sec)
  3023. ** will will initiate a checkpoint to make sure that the partner is still connected. We do
  3024. ** this by inserting a zero-data frame into the reliable pipeline. Thereby, the standard
  3025. ** timeout & retry mechanisms will either confirm or drop the link as appropriate. Logic above
  3026. ** this routine will have already verified that we are not already sending reliable traffic, which
  3027. ** would eliminate the need for a keep alive frame.
  3028. **
  3029. ** *** EPD->EPLock is held on Entry and return
  3030. */
  3031. #undef DPF_MODNAME
  3032. #define DPF_MODNAME "SendKeepAlive"
  3033. VOID
  3034. SendKeepAlive(PEPD pEPD)
  3035. {
  3036. PFMD pFMD;
  3037. PMSD pMSD;
  3038. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  3039. if(pEPD->ulEPFlags & EPFLAGS_KEEPALIVE_RUNNING)
  3040. {
  3041. DPFX(DPFPREP,7, "Ignoring duplicate KeepAlive");
  3042. return;
  3043. }
  3044. pEPD->ulEPFlags |= EPFLAGS_KEEPALIVE_RUNNING;
  3045. if( (pMSD = (PMSD)POOLALLOC(MEMID_KEEPALIVE_MSD, &MSDPool)) == NULL)
  3046. {
  3047. DPFX(DPFPREP,0, "(%p) Failed to allocate new MSD");
  3048. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  3049. return;
  3050. }
  3051. if((pFMD = (PFMD)POOLALLOC(MEMID_KEEPALIVE_FMD, &FMDPool)) == NULL)
  3052. {
  3053. DPFX(DPFPREP,0, "(%p) Failed to allocate new FMD");
  3054. Lock(&pMSD->CommandLock); // An MSD must be locked to be released
  3055. RELEASE_MSD(pMSD, "Release On FMD Get Failed");
  3056. pEPD->ulEPFlags &= ~(EPFLAGS_KEEPALIVE_RUNNING);
  3057. return;
  3058. }
  3059. // Initialize the frame count AFTER we are sure we have a frame or MSD_Release will assert
  3060. pMSD->uiFrameCount = 1;
  3061. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Initialize Frame count, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  3062. pMSD->ulMsgFlags2 |= MFLAGS_TWO_KEEPALIVE;
  3063. pMSD->pEPD = pEPD;
  3064. pMSD->pSPD = pEPD->pSPD;
  3065. LOCK_EPD(pEPD, "LOCK (SendKeepAlive)"); // Add a reference for this checkpoint
  3066. pFMD->ulFFlags |= FFLAGS_CHECKPOINT | FFLAGS_END_OF_MESSAGE | FFLAGS_DONT_COALESCE;
  3067. pFMD->bPacketFlags = PACKET_COMMAND_DATA | PACKET_COMMAND_RELIABLE | PACKET_COMMAND_SEQUENTIAL | PACKET_COMMAND_END_MSG;
  3068. pFMD->uiFrameLength = 0; // No user data in this frame
  3069. pFMD->blMSDLinkage.InsertAfter( &pMSD->blFrameList); // Attach frame to MSD
  3070. pFMD->pMSD = pMSD; // Link frame back to message
  3071. pFMD->pEPD = pEPD;
  3072. pFMD->CommandID = COMMAND_ID_SEND_RELIABLE;
  3073. pMSD->CommandID = COMMAND_ID_KEEPALIVE; // Mark MSD for completion handling
  3074. //N.B. We set the priority has high to handle a problem with the signed connect sequence
  3075. //Basically if we drop one of the CONNECTEDSIGNED packets then the initial keep alive packet
  3076. //acts to re-trigger the connect sequence at this listener. The only penalty to doing this is
  3077. //if we suddently get a flood of medium/high priority data immediately we've queued a keep alive
  3078. //we'll send the keep alive first. This is a pretty unlikely event, and hence not a big problem
  3079. pMSD->ulSendFlags = DN_SENDFLAGS_RELIABLE | DN_SENDFLAGS_HIGH_PRIORITY;
  3080. DPFX(DPFPREP,7,"(%p) Sending KEEPALIVE", pEPD);
  3081. EnqueueMessage(pMSD, pEPD); // Insert this message into the stream
  3082. }
  3083. /*
  3084. ** Endpoint Background Process
  3085. **
  3086. ** This routine is run for each active endpoint every minute or so. This will initiate
  3087. ** a KeepAlive exchange if the link has been idle since the last run of the procedure. We
  3088. ** will also look for expired timeouts and perhaps this will be an epoch delimiter for links
  3089. ** in a STABLE state of being.
  3090. **
  3091. */
  3092. #undef DPF_MODNAME
  3093. #define DPF_MODNAME "EndPointBackgroundProcess"
  3094. VOID CALLBACK
  3095. EndPointBackgroundProcess(void * const pvUser, void * const pvTimerData, const UINT uiTimerUnique)
  3096. {
  3097. PEPD pEPD = (PEPD) pvUser;
  3098. PSPD pSPD = pEPD->pSPD;
  3099. DWORD tNow = GETTIMESTAMP();
  3100. DWORD dwIdleInterval;
  3101. DPFX(DPFPREP,7, "(%p) BACKGROUND PROCESS for EPD; RefCnt=%d; WindowF=%d; WindowB=%d",
  3102. pEPD, pEPD->lRefCnt, pEPD->uiWindowF, pEPD->uiWindowBIndex);
  3103. Lock(&pEPD->EPLock);
  3104. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  3105. {
  3106. DPFX(DPFPREP,7, "Killing Background Process, endpoint is not connected. Flags = 0x%x", pEPD->ulEPFlags);
  3107. pEPD->BGTimer = 0;
  3108. RELEASE_EPD(pEPD, "UNLOCK (release BG timer)"); // release reference for this timer, releases EPLock
  3109. return;
  3110. }
  3111. dwIdleInterval = pEPD->pSPD->pPData->tIdleThreshhold;
  3112. // Do we need to start a KeepAlive cycle?
  3113. if( ((pEPD->ulEPFlags & (EPFLAGS_SDATA_READY | EPFLAGS_KEEPALIVE_RUNNING))==0) &&
  3114. ((tNow - pEPD->tLastPacket) > dwIdleInterval))
  3115. {
  3116. // We are not sending data and we havent heard from our partner in a long time.
  3117. // We will send a keep alive packet which he must respond to. We will insert a
  3118. // NULL data packet into the reliable stream so ack/retry mechanisms will either
  3119. // clear the keep-alive or else timeout the link.
  3120. //
  3121. // There's also the special case where we've started a graceful disconnect and
  3122. // our request has been acknowledged, but somehow our partner's got lost.
  3123. // There currently is no timer set for that, so if we detect the link in that
  3124. // condition, our keepalive will almost certainly fail; the other side knows
  3125. // we're shutting down, so has probably already dropped the link and wouldn't
  3126. // respond. So to prevent the person from having to wait for the entire idle
  3127. // timeout _plus_ reliable message timeout, just drop the link now.
  3128. if (pEPD->ulEPFlags & EPFLAGS_DISCONNECT_ACKED)
  3129. {
  3130. // If all three parts happened, why is the link still up!?
  3131. ASSERT(! (pEPD->ulEPFlags & EPFLAGS_ACKED_DISCONNECT));
  3132. DPFX(DPFPREP,1, "(%p) EPD has been waiting for partner disconnect for %u ms (idle threshold = %u ms), dropping link.",
  3133. pEPD, (tNow - pEPD->tLastPacket), dwIdleInterval);
  3134. // We don't need to reschedule a timer, so clear it. This also prevents
  3135. // drop link from trying to cancel the one we're in now. That error is
  3136. // ignored, but no point in doing it.
  3137. pEPD->BGTimer = 0;
  3138. DECREMENT_EPD(pEPD, "UNLOCK (release BGTimer)");
  3139. // Since we're just hanging out waiting for partner to send his disconnect,
  3140. // he's probably gone now. Drop the link.
  3141. DropLink(pEPD); // releases EPLock
  3142. return;
  3143. }
  3144. //else if we haven't sent a disconnect, and no hard disconnect sequence is in progress then send a keep alive
  3145. else if ((pEPD->ulEPFlags &
  3146. (EPFLAGS_SENT_DISCONNECT | EPFLAGS_HARD_DISCONNECT_SOURCE |EPFLAGS_HARD_DISCONNECT_TARGET))==0)
  3147. {
  3148. DPFX(DPFPREP,5, "(%p) Sending KEEPALIVE...", pEPD);
  3149. SendKeepAlive(pEPD);
  3150. }
  3151. else
  3152. {
  3153. // The EndOfStream message will either get ACK'd or timeout, we allow no further sends, even KeepAlives
  3154. DPFX(DPFPREP,5, "(%p) KeepAlive timeout fired, but we're in a disconnect sequence, ignoring", pEPD);
  3155. }
  3156. }
  3157. // Reschedule next interval
  3158. // Cap the background process interval at this value.
  3159. if (dwIdleInterval > ENDPOINT_BACKGROUND_INTERVAL)
  3160. {
  3161. dwIdleInterval = ENDPOINT_BACKGROUND_INTERVAL;
  3162. }
  3163. DPFX(DPFPREP,7, "(%p) Setting Endpoint Background Timer for %u ms", pEPD, dwIdleInterval);
  3164. RescheduleProtocolTimer(pSPD, pEPD->BGTimer, dwIdleInterval, 1000, EndPointBackgroundProcess, (PVOID) pEPD, &pEPD->BGTimerUnique);
  3165. Unlock(&pEPD->EPLock);
  3166. }
  3167. /*
  3168. ** Hard Disconnect Resend
  3169. **
  3170. ** This routine is run when an endpoint is hard disconnecting. It is used to send a single hard disconnect frame
  3171. ** at a period of rtt/2.
  3172. **
  3173. */
  3174. #undef DPF_MODNAME
  3175. #define DPF_MODNAME "HardDisconnectResendTimeout"
  3176. VOID CALLBACK
  3177. HardDisconnectResendTimeout(void * const pvUser, void * const pvTimerData, const UINT uiTimerUnique)
  3178. {
  3179. PEPD pEPD=(PEPD) pvUser;
  3180. PProtocolData pPData=pEPD->pSPD->pPData;
  3181. DPFX(DPFPREP,7, "(%p) Entry. pvTimerData[%p] uiTimerUnique[%u] EPD::RefCnt[%d], EPD::uiNumRetriesRemaining[%u]",
  3182. pEPD, pvTimerData, uiTimerUnique, pEPD->lRefCnt, pEPD->uiNumRetriesRemaining);
  3183. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, FALSE);
  3184. Lock(&pEPD->EPLock);
  3185. DNASSERT(pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_SOURCE);
  3186. DNASSERT((pEPD->ulEPFlags & EPFLAGS_SENT_DISCONNECT)==0);
  3187. //if this is a stale timer then we've nothing more to do
  3188. if (pEPD->LinkTimerUnique!=uiTimerUnique || pEPD->LinkTimer!=pvTimerData)
  3189. {
  3190. DPFX(DPFPREP,7, "Timer is Stale. EPD::LinkTimer[%p], EPD::LinkTimerUnique[%u]", pEPD->LinkTimer, pEPD->LinkTimerUnique);
  3191. RELEASE_EPD(pEPD, "UNLOCK (Hard Disconnect Resend Timer)");
  3192. // above call releases reference for this timer and releases EPLock
  3193. return;
  3194. }
  3195. //whatever happens now, we've processed this timer
  3196. pEPD->LinkTimerUnique=0;
  3197. pEPD->LinkTimer=NULL;
  3198. //if endpoint is being terminated then we shouldn't attempt to touch it
  3199. if (pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING)
  3200. {
  3201. DPFX(DPFPREP,7, "Endpoint is terminating. Flags = 0x%x", pEPD->ulEPFlags);
  3202. RELEASE_EPD(pEPD, "UNLOCK (Hard Disconnect Resend Timer)");
  3203. // above call releases reference for this timer and releases EPLock
  3204. return;
  3205. }
  3206. //looks like we've got a valid timer on a valid endpoint, update the number of retries we have left to send
  3207. pEPD->uiNumRetriesRemaining--;
  3208. DNASSERT(pEPD->uiNumRetriesRemaining<0x80000000); //ensure we haven't gone negative on retries remaining
  3209. ULONG ulFFlags;
  3210. //if we hit zero retries remaining then we'll make this the last hard disconnect frame we send out
  3211. if (pEPD->uiNumRetriesRemaining==0)
  3212. {
  3213. ulFFlags=FFLAGS_FINAL_HARD_DISCONNECT;
  3214. DPFX(DPFPREP,7, "(%p) Sending final hard disconnect", pEPD);
  3215. }
  3216. //otherwise we'll need to reschedule the timer to send the next retry
  3217. else
  3218. {
  3219. ulFFlags=0;
  3220. DWORD dwRetryPeriod=pEPD->uiRTT/2;
  3221. if (dwRetryPeriod>pPData->dwMaxHardDisconnectPeriod)
  3222. dwRetryPeriod=pPData->dwMaxHardDisconnectPeriod;
  3223. else if (dwRetryPeriod<MIN_HARD_DISCONNECT_PERIOD)
  3224. dwRetryPeriod=MIN_HARD_DISCONNECT_PERIOD;
  3225. pEPD->LinkTimer=pvTimerData;
  3226. RescheduleProtocolTimer(pEPD->pSPD, pvTimerData, dwRetryPeriod, 10, HardDisconnectResendTimeout,
  3227. pEPD, &pEPD->LinkTimerUnique);
  3228. DPFX(DPFPREP,7, "(%p) Rescheduled timer for next hard disconnect send", pEPD);
  3229. }
  3230. HRESULT hr=SendCommandFrame(pEPD, FRAME_EXOPCODE_HARD_DISCONNECT, 0, ulFFlags, TRUE);
  3231. //since we selected send direct EP lock will have been released by above call
  3232. //if that was the last disconnect frame we won't have rescheduled the timer, and should therefore
  3233. //drop the ep reference that the timer holds
  3234. if (ulFFlags==FFLAGS_FINAL_HARD_DISCONNECT)
  3235. {
  3236. Lock(&pEPD->EPLock);
  3237. //if the send failed on the last hard disconnect frame we'll have to drop the link now
  3238. //as we won't be getting a completition back from the sp for it
  3239. if (FAILED(hr))
  3240. {
  3241. CompleteHardDisconnect(pEPD);
  3242. //above call will have release EP lock
  3243. Lock(&pEPD->EPLock);
  3244. DPFX(DPFPREP,0, "Failed to send final hard disconnect frame. Dropping link. hr[%x]", hr);
  3245. }
  3246. RELEASE_EPD(pEPD, "UNLOCK (Hard Disconnect Resend Timer)");
  3247. }
  3248. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  3249. }