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.

1316 lines
45 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Command.cpp
  6. * Content: This file contains code which implements assorted APIs for the
  7. * DirectPlay protocol.
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 11/06/98 ejs Created
  13. * 07/01/2000 masonb Assumed Ownership
  14. *
  15. ****************************************************************************/
  16. #include "dnproti.h"
  17. /*
  18. ** Update
  19. **
  20. ** Update an SP about host migration
  21. */
  22. #undef DPF_MODNAME
  23. #define DPF_MODNAME "DNPUpdate"
  24. HRESULT
  25. DNPUpdateListen(HANDLE hProtocolData,HANDLE hEndPt,DWORD dwFlags)
  26. {
  27. ProtocolData *pPData;
  28. MSD *pMSD;
  29. HRESULT hr=DPNERR_INVALIDFLAGS;
  30. SPUPDATEDATA UpdateData;
  31. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hEndPt[%p], dwFlags[%p]",hProtocolData,hEndPt,dwFlags);
  32. DNASSERT(hProtocolData != NULL);
  33. DNASSERT(hEndPt != NULL);
  34. DNASSERT( ! ((dwFlags & DN_UPDATELISTEN_ALLOWENUMS) && (dwFlags & DN_UPDATELISTEN_DISALLOWENUMS)) );
  35. pPData = (ProtocolData*) hProtocolData;
  36. pMSD = (MSD*) hEndPt;
  37. ASSERT_MSD( pMSD );
  38. DNASSERT( pMSD->pSPD );
  39. UpdateData.hEndpoint = pMSD->hListenEndpoint;
  40. if (dwFlags & DN_UPDATELISTEN_HOSTMIGRATE)
  41. {
  42. UpdateData.UpdateType = SP_UPDATE_HOST_MIGRATE;
  43. hr = IDP8ServiceProvider_Update(pMSD->pSPD->IISPIntf,&UpdateData);
  44. }
  45. if (dwFlags & DN_UPDATELISTEN_ALLOWENUMS)
  46. {
  47. UpdateData.UpdateType = SP_UPDATE_ALLOW_ENUMS;
  48. hr = IDP8ServiceProvider_Update(pMSD->pSPD->IISPIntf,&UpdateData);
  49. }
  50. if (dwFlags & DN_UPDATELISTEN_DISALLOWENUMS)
  51. {
  52. UpdateData.UpdateType = SP_UPDATE_DISALLOW_ENUMS;
  53. hr = IDP8ServiceProvider_Update(pMSD->pSPD->IISPIntf,&UpdateData);
  54. }
  55. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x]",hr);
  56. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  57. return( hr );
  58. }
  59. /*
  60. ** Cancel Command
  61. **
  62. ** This procedure is passed a HANDLE returned from a previous asynchronous
  63. ** DPLAY command. At the moment, the handle is a pointer to an internal data
  64. ** structure. Problem with this is that due to FPM's (fixed pool manager) design
  65. ** they will get recycled very quickly and frequently. We might want to map them
  66. ** into an external handle table which will force them to recycle much more slowly.
  67. ** Perhaps, I will let the upper DN layer do this mapping...
  68. **
  69. ** Anyway, the only check I can do right now is that the HANDLE is currently
  70. ** allocated to something.
  71. **
  72. ** We do not expect cancels to happen very often. Therefore, I do not feel
  73. ** bad about walking the global command list to find the Handle. Of course, if
  74. ** we do go to a handle mapped system then we should not need to do this walk.
  75. **
  76. ** I THINK - That any cancellable command will be on either MessageList or TimeoutList!
  77. **
  78. ** Things we can cancel and their possible states:
  79. **
  80. ** SEND Datagram
  81. ** On SPD Send Queue
  82. ** On EPD Send Queue
  83. ** In SP call
  84. **
  85. ** SEND Reliable
  86. ** We can only cancel if it has not started transmitting. Once its started, the
  87. ** user program must Abort the link to cancel the send.
  88. **
  89. ** CONNECT
  90. ** In SP call
  91. ** On PD list
  92. **
  93. ** LISTEN
  94. ** In SP call
  95. ** On PD list
  96. **
  97. ** Remember, if we cancel a command in SP then the CommandComplete is supposed to
  98. ** occur. This means that we should not have to explicitly free the MSD, etc in these
  99. ** cases.
  100. */
  101. #undef DPF_MODNAME
  102. #define DPF_MODNAME "DNPCancelCommand"
  103. HRESULT
  104. DNPCancelCommand(HANDLE hProtocolData, HANDLE hCommand)
  105. {
  106. ProtocolData* pPData;
  107. PMSD pMSD;
  108. HRESULT hr;
  109. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hCommand[%p]", hProtocolData, hCommand);
  110. pPData = (ProtocolData*)hProtocolData;
  111. ASSERT_PPD(pPData);
  112. pMSD = (PMSD) hCommand;
  113. ASSERT_MSD(pMSD);
  114. Lock(&pMSD->CommandLock); // Take this early to freeze state of command
  115. // validate instance of MSD
  116. ASSERT(pMSD->lRefCnt != -1);
  117. hr = DoCancel(pMSD, DPNERR_USERCANCEL); // Releases CommandLock
  118. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x], pMSD[%p]", hr, pMSD);
  119. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  120. return hr;
  121. }
  122. /*
  123. ** Do Cancel
  124. **
  125. ** This function implements the meat of the cancel asynch operation. It gets called from
  126. ** two places. Either from the User cancel API right above, or from the global timeout handler.
  127. **
  128. ** ***This code requires the MSD->CommandLock to be help upon entry, unlocks upon return
  129. */
  130. #undef DPF_MODNAME
  131. #define DPF_MODNAME "DoCancel"
  132. HRESULT
  133. DoCancel(PMSD pMSD, HRESULT CompletionCode)
  134. {
  135. PEPD pEPD;
  136. HRESULT hr = DPN_OK;
  137. DPFX(DPFPREP,7, "Cancelling pMSD=%p", pMSD);
  138. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  139. // The MSD better not be back in the pool or our ref counts are wrong
  140. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_USE);
  141. if(pMSD->ulMsgFlags1 & (MFLAGS_ONE_CANCELLED | MFLAGS_ONE_COMPLETE))
  142. {
  143. DPFX(DPFPREP,7, "(%p) MSD is Cancelled or Complete, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pMSD->pEPD, pMSD);
  144. Unlock(&pMSD->CommandLock);
  145. return DPNERR_CANNOTCANCEL;
  146. }
  147. pMSD->ulMsgFlags1 |= MFLAGS_ONE_CANCELLED;
  148. switch(pMSD->CommandID)
  149. {
  150. case COMMAND_ID_SEND_DATAGRAM:
  151. case COMMAND_ID_SEND_RELIABLE:
  152. pEPD = pMSD->pEPD;
  153. ASSERT_EPD(pEPD);
  154. Lock(&pEPD->EPLock);
  155. if(pMSD->ulMsgFlags2 & (MFLAGS_TWO_ABORT | MFLAGS_TWO_TRANSMITTING | MFLAGS_TWO_SEND_COMPLETE))
  156. {
  157. DPFX(DPFPREP,7, "(%p) MSD is Aborted, Transmitting, or Complete, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pEPD, pMSD);
  158. Unlock(&pEPD->EPLock); // Link is dropping or DNET is terminating
  159. hr = DPNERR_CANNOTCANCEL; // To cancel an xmitting reliable send you
  160. break; // must Abort the connection.
  161. }
  162. pMSD->blQLinkage.RemoveFromList(); // Remove cmd from queue
  163. ASSERT(pEPD->uiQueuedMessageCount > 0);
  164. --pEPD->uiQueuedMessageCount; // keep count of MSDs on all send queues
  165. // Clear data-ready flag if everything is sent
  166. if((pEPD->uiQueuedMessageCount == 0) && (pEPD->pCurrentSend == NULL))
  167. {
  168. pEPD->ulEPFlags &= ~(EPFLAGS_SDATA_READY);
  169. }
  170. #ifdef DBG
  171. ASSERT(pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED);
  172. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  173. #endif // DBG
  174. ASSERT(pEPD->pCurrentSend != pMSD);
  175. pMSD->uiFrameCount = 0;
  176. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Send cancelled before sending, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  177. Unlock(&pEPD->EPLock);
  178. if (pMSD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  179. {
  180. DPFX(DPFPREP,7, "(%p) Completing(cancel) Nonreliable send, pMSD[%p]", pEPD, pMSD);
  181. CompleteDatagramSend(pMSD->pSPD, pMSD, CompletionCode); // Releases CommandLock
  182. }
  183. else
  184. {
  185. ASSERT(pMSD->CommandID == COMMAND_ID_SEND_RELIABLE);
  186. DPFX(DPFPREP,7, "(%p) Completing(cancel) Reliable Send, pMSD[%p]", pEPD, pMSD);
  187. CompleteReliableSend(pMSD->pSPD, pMSD, CompletionCode); // Releases CommandLock
  188. }
  189. return hr;
  190. case COMMAND_ID_CONNECT:
  191. #ifndef DPNBUILD_NOMULTICAST
  192. case COMMAND_ID_CONNECT_MULTICAST_SEND:
  193. case COMMAND_ID_CONNECT_MULTICAST_RECEIVE:
  194. #endif // ! DPNBUILD_NOMULTICAST
  195. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER)
  196. {
  197. // SP owns the command - issue a cancel and let CompletionEvent clean up command
  198. Unlock(&pMSD->CommandLock); // We could deadlock if we cancel with lock held
  199. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  200. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Connect, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  201. (void) IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  202. // If the SP Cancel fails it should not matter. It would usually mean we are
  203. // in a race with the command completing, in which case the cancel flag will
  204. // nip it in the bud.
  205. return DPN_OK;
  206. }
  207. // We will only get here once because the entry to this function checks CANCEL and COMPLETE and sets
  208. // CANCEL. CompleteConnect will set COMPLETE as well.
  209. pEPD = pMSD->pEPD;
  210. ASSERT_EPD(pEPD);
  211. Lock(&pEPD->EPLock);
  212. // Unlink the MSD from the EPD
  213. ASSERT(pEPD->pCommand == pMSD);
  214. pEPD->pCommand = NULL;
  215. DECREMENT_MSD(pMSD, "EPD Ref");
  216. Unlock(&pMSD->CommandLock); // DropLink may call into the SP.
  217. DropLink(pEPD); // This unlocks the EPLock
  218. Lock(&pMSD->CommandLock);
  219. DPFX(DPFPREP,5, "(%p) Connect cancelled, completing Connect, pMSD[%p]", pEPD, pMSD);
  220. CompleteConnect(pMSD, pMSD->pSPD, NULL, DPNERR_USERCANCEL); // releases command lock
  221. return DPN_OK;
  222. case COMMAND_ID_LISTEN:
  223. #ifndef DPNBUILD_NOMULTICAST
  224. case COMMAND_ID_LISTEN_MULTICAST:
  225. #endif // !DPNBUILD_NOMULTICAST
  226. /*
  227. ** Cancel Listen
  228. **
  229. ** SP will own parts of the MSD until the SPCommandComplete function is called. We will
  230. ** defer much of our cancel processing to this handler.
  231. */
  232. // Stop listening in SP -- This will prevent new connections from popping up while we are
  233. // closing down any left in progress. Only problem is we need to release command lock to
  234. // do it.
  235. Unlock(&pMSD->CommandLock); // We can deadlock if we hold across this call
  236. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  237. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Listen, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  238. (void) IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  239. Lock(&pMSD->CommandLock); // Lock this down again.
  240. // Are there any connections in progress?
  241. // For a Listen command, connecting endpoints are held on the blFrameList
  242. while(!pMSD->blFrameList.IsEmpty())
  243. {
  244. pEPD = CONTAINING_OBJECT(pMSD->blFrameList.GetNext(), EPD, blSPLinkage);
  245. ASSERT_EPD(pEPD);
  246. DPFX(DPFPREP,1, "FOUND CONNECT IN PROGRESS ON CANCELLED LISTEN, EPD=%p", pEPD);
  247. Lock(&pEPD->EPLock);
  248. // Ensure we don't stay in this loop forever
  249. pEPD->ulEPFlags &= ~(EPFLAGS_LINKED_TO_LISTEN);
  250. pEPD->blSPLinkage.RemoveFromList(); // Unlink EPD from Listen Queue
  251. // It is possible that RejectInvalidPacket is happening at the same time as this, so guard against us
  252. // both doing the same clean up and removing the same reference from the MSD.
  253. if (!(pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING))
  254. {
  255. // We know this only happens once because anyone who does it either transitions us to the
  256. // CONNECTED or TERMINATING state, and also removes us from the Listen list above.
  257. // Unlink MSD from EPD
  258. ASSERT(pEPD->pCommand == pMSD); // This should be pointing back to this listen
  259. pEPD->pCommand = NULL;
  260. DECREMENT_MSD(pMSD, "EPD Ref"); // Unlink from EPD and release associated reference
  261. Unlock(&pMSD->CommandLock); // DropLink may call into the SP.
  262. DropLink(pEPD); // releases EPLock
  263. Lock(&pMSD->CommandLock); // Lock this down again.
  264. }
  265. else
  266. {
  267. Unlock(&pEPD->EPLock);
  268. }
  269. } // for each connection in progress
  270. RELEASE_MSD(pMSD, "(Base Ref) Release On Cancel"); // release base reference
  271. return DPN_OK;
  272. case COMMAND_ID_ENUM:
  273. {
  274. Unlock(&pMSD->CommandLock);
  275. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  276. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Enum, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  277. return IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  278. // We will pass HRESULT from SP directly to user
  279. }
  280. case COMMAND_ID_ENUMRESP:
  281. {
  282. Unlock(&pMSD->CommandLock);
  283. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  284. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on EnumResp, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  285. return IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  286. // We will pass HRESULT from SP directly to user
  287. }
  288. case COMMAND_ID_DISCONNECT: // Core guarantees not to cancel a disconnect
  289. case COMMAND_ID_COPIED_RETRY: // This should be on FMD's only
  290. case COMMAND_ID_COPIED_RETRY_COALESCE: // This should be on FMD's only
  291. case COMMAND_ID_CFRAME: // This should be on FMD's only
  292. case COMMAND_ID_DISC_RESPONSE: // These are never placed on the global list and aren't cancellable
  293. case COMMAND_ID_KEEPALIVE: // These are never placed on the global list and aren't cancellable
  294. default:
  295. ASSERT(0); // Should never get here
  296. hr = DPNERR_CANNOTCANCEL;
  297. break;
  298. }
  299. Unlock(&pMSD->CommandLock);
  300. return hr;
  301. }
  302. /*
  303. ** Get Listen Info
  304. **
  305. ** Return a buffer full of interesting and provocative tidbits about a particular Listen command.
  306. */
  307. #undef DPF_MODNAME
  308. #define DPF_MODNAME "DNPGetListenAddressInfo"
  309. HRESULT
  310. DNPGetListenAddressInfo(HANDLE hProtocolData, HANDLE hListen, PSPGETADDRESSINFODATA pSPData)
  311. {
  312. ProtocolData* pPData;
  313. PMSD pMSD;
  314. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hListen[%p], pSPData[%p]", hProtocolData, hListen, pSPData);
  315. pPData = (ProtocolData*)hProtocolData;
  316. ASSERT_PPD(pPData);
  317. pMSD = (PMSD)hListen;
  318. ASSERT_MSD(pMSD);
  319. #ifndef DPNBUILD_NOMULTICAST
  320. ASSERT(((pMSD->CommandID == COMMAND_ID_LISTEN) || (pMSD->CommandID == COMMAND_ID_LISTEN_MULTICAST)) && (pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER));
  321. #else // DPNBUILD_NOMULTICAST
  322. ASSERT(((pMSD->CommandID == COMMAND_ID_LISTEN)) && (pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER));
  323. #endif // ! DPNBUILD_NOMULTICAST
  324. pSPData->hEndpoint = pMSD->hListenEndpoint;
  325. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  326. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->GetAddressInfo, pMSD[%p], hEndpoint[%x], pSPD[%p]", pMSD, pMSD->hListenEndpoint, pMSD->pSPD);
  327. return IDP8ServiceProvider_GetAddressInfo(pMSD->pSPD->IISPIntf, pSPData);
  328. }
  329. /*
  330. ** Disconnect End Point
  331. **
  332. ** This function is called when the client no longer wishes
  333. ** to communicate with the specified end point. We will initiate
  334. ** the disconnect protocol with the endpoint, and when it is
  335. ** acknowleged, we will disconnect the SP and release the handle.
  336. **
  337. ** Disconnect is defined in Direct Net to allow all previously
  338. ** submitted sends to complete, but no additional sends to be submitted.
  339. ** Also, any sends the partner has in progress will be delivered, but
  340. ** no additional sends will be accepted following the indication that
  341. ** a disconnect is in progress on the remote end.
  342. **
  343. ** This implies that two indications will be generated on the remote
  344. ** machine, Disconnect Initiated and Disconnect Complete. Only the
  345. ** Complete will be indicated on the issueing side.
  346. */
  347. #undef DPF_MODNAME
  348. #define DPF_MODNAME "DNPDisconnectEndPoint"
  349. HRESULT
  350. DNPDisconnectEndPoint(HANDLE hProtocolData, HANDLE hEndPoint, VOID* pvContext, HANDLE* phDisconnect, const DWORD dwFlags)
  351. {
  352. ProtocolData* pPData;
  353. PEPD pEPD;
  354. PMSD pMSD;
  355. HRESULT hr;
  356. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hEndPoint[%x], pvContext[%p], phDisconnect[%p] dwFlags[%u]",
  357. hProtocolData, hEndPoint, pvContext, phDisconnect, dwFlags);
  358. hr = DPNERR_PENDING;
  359. pPData = (ProtocolData*)hProtocolData;
  360. ASSERT_PPD(pPData);
  361. pEPD = (PEPD) hEndPoint;
  362. ASSERT_EPD(pEPD);
  363. LOCK_EPD(pEPD, "LOCK (DISCONNECT)");
  364. Lock(&pEPD->EPLock);
  365. // If we aren't connected, or we have already initiated a disconnect, don't allow a new disconnect
  366. if( (pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) ==0 ||
  367. (pEPD->ulEPFlags & (EPFLAGS_SENT_DISCONNECT | EPFLAGS_RECEIVED_DISCONNECT
  368. | EPFLAGS_HARD_DISCONNECT_SOURCE | EPFLAGS_HARD_DISCONNECT_TARGET)))
  369. {
  370. RELEASE_EPD(pEPD, "UNLOCK (Validate EP)"); // Releases EPLock
  371. DPFX(DPFPREP,1, "Attempt to disconnect already disconnecting endpoint");
  372. hr = DPNERR_ALREADYDISCONNECTING;
  373. goto Exit;
  374. }
  375. //if the disconnect should be a hard one, then we want to effectively put the endpoint into
  376. //stasis. We'll free and sends and recvs, cancel all its timers and just sit around long
  377. //enough to fire off the disconnect frame 3 times
  378. if (dwFlags & DN_DISCONNECTFLAGS_IMMEDIATE)
  379. {
  380. //setting this flag ensures that any incoming frames for the endpoint (other than hard disconnects)
  381. //are instantly discarded from this point on
  382. pEPD->ulEPFlags |= EPFLAGS_HARD_DISCONNECT_SOURCE;
  383. DNASSERT((pEPD->ulEPFlags2 & EPFLAGS2_HARD_DISCONNECT_COMPLETE)==0);
  384. //core will never cancel a disconnect so store a NULL command handle
  385. //if they do try and cancel this we will assert
  386. *phDisconnect=NULL;
  387. //store the context we need to complete the disconnect with
  388. pEPD->pvHardDisconnectContext=pvContext;
  389. //all following calls are performed with EPD lock held
  390. CancelEpdTimers(pEPD);
  391. AbortRecvsOnConnection(pEPD);
  392. AbortSendsOnConnection(pEPD);
  393. //above call will have released EPD lock, so retake it
  394. Lock(&pEPD->EPLock);
  395. //setup state to send a sequence of hard disconnect frames
  396. pEPD->uiNumRetriesRemaining=pPData->dwNumHardDisconnectSends-1;
  397. DNASSERT(pEPD->uiNumRetriesRemaining>0);
  398. DWORD dwRetryPeriod = pEPD->uiRTT/2;
  399. if (dwRetryPeriod>pPData->dwMaxHardDisconnectPeriod)
  400. dwRetryPeriod=pPData->dwMaxHardDisconnectPeriod;
  401. else if (dwRetryPeriod<MIN_HARD_DISCONNECT_PERIOD)
  402. dwRetryPeriod=MIN_HARD_DISCONNECT_PERIOD;
  403. hr=ScheduleProtocolTimer(pEPD->pSPD, dwRetryPeriod, 10, HardDisconnectResendTimeout, pEPD,
  404. &pEPD->LinkTimer, &pEPD->LinkTimerUnique);
  405. //if we fail to schedule a timer we've only got one chance to send a hard disconnect frame, so make it the last
  406. ULONG ulFFlags;
  407. if (FAILED(hr))
  408. {
  409. ulFFlags=FFLAGS_FINAL_HARD_DISCONNECT;
  410. }
  411. //if we did schedule a timer we need to take a reference on the endpoint, which is kept until the timer
  412. //completes or is cancelled
  413. else
  414. {
  415. ulFFlags=0;
  416. LOCK_EPD(pEPD, "LOCK (Hard Disconnect Resend Timer)");
  417. }
  418. hr=SendCommandFrame(pEPD, FRAME_EXOPCODE_HARD_DISCONNECT, 0, ulFFlags, TRUE);
  419. //above call will have released EPD lock
  420. //if we failed to set a timer, then at a minimum we need to drop a reference to the ep
  421. if (ulFFlags==FFLAGS_FINAL_HARD_DISCONNECT)
  422. {
  423. Lock(&pEPD->EPLock);
  424. //if we also failed to send the hard disconnect frame then we have to complete the
  425. //disconnect here, since we're not going to get another chance
  426. if (FAILED(hr))
  427. {
  428. CompleteHardDisconnect(pEPD);
  429. //above call will have release EP lock
  430. DPFX(DPFPREP,0, "Failed to set timer to schedule hard disconnect sends. hr[%x]", hr);
  431. hr = DPNERR_OUTOFMEMORY;
  432. }
  433. else
  434. {
  435. DPFX(DPFPREP,0, "Failed to set timer to schedule hard disconnect sends but sent final hard disconnect frame. hr[%x]", hr);
  436. hr = DPNERR_PENDING;
  437. }
  438. }
  439. else
  440. {
  441. if (FAILED(hr))
  442. {
  443. DPFX(DPFPREP,0, "Failed to send hard disconnect frame but scheduled timer for future sends. hr[%x]", hr);
  444. }
  445. else
  446. {
  447. DPFX(DPFPREP,7, "Sent first hard disconnect frame and scheduled timer for future sends. dwRetryPeriod[%u]", dwRetryPeriod);
  448. }
  449. hr = DPNERR_PENDING;
  450. }
  451. goto Exit;
  452. }
  453. //Its a normal disconnect, rather than a hard disconnect
  454. //Accept no more sends, but don't scrap link yet
  455. pEPD->ulEPFlags |= EPFLAGS_SENT_DISCONNECT;
  456. #ifndef DPNBUILD_NOMULTICAST
  457. if (pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE))
  458. {
  459. pEPD->ulEPFlags |= EPFLAGS_STATE_TERMINATING;
  460. //
  461. // Create an MSD for the disconnect
  462. //
  463. if((pMSD = (PMSD)POOLALLOC(MEMID_MCAST_DISCONNECT_MSD, &MSDPool)) == NULL)
  464. {
  465. RELEASE_EPD(pEPD, "UNLOCK (Allocation failed)"); // Releases EPLock
  466. DPFX(DPFPREP,0, "Returning DPNERR_OUTOFMEMORY - failed to create new MSD");
  467. hr = DPNERR_OUTOFMEMORY;
  468. goto Exit;
  469. }
  470. pMSD->pSPD = pEPD->pSPD;
  471. pMSD->pEPD = pEPD;
  472. }
  473. else
  474. #endif // DPNBUILD_NOMULTICAST
  475. {
  476. if((pMSD = BuildDisconnectFrame(pEPD)) == NULL)
  477. {
  478. DropLink(pEPD); // releases EPLock
  479. Lock(&pEPD->EPLock);
  480. RELEASE_EPD(pEPD, "UNLOCK (Validate EP)"); // releases EPLock
  481. DPFX(DPFPREP,0, "Failed to build disconnect frame");
  482. hr = DPNERR_OUTOFMEMORY;
  483. goto Exit;
  484. }
  485. }
  486. pMSD->CommandID = COMMAND_ID_DISCONNECT;
  487. pMSD->Context = pvContext; // retain user's context value
  488. *phDisconnect = pMSD; // pass back command handle
  489. // We borrow the reference placed above by ValidateEP for this. It will be released
  490. // on completion of the Disconnect.
  491. ASSERT(pEPD->pCommand == NULL);
  492. pEPD->pCommand = pMSD; // Store the disconnect command on the endpoint until it is complete
  493. #ifdef DBG
  494. Lock(&pMSD->pSPD->SPLock);
  495. pMSD->blSPLinkage.InsertBefore( &pMSD->pSPD->blMessageList);
  496. pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST;
  497. Unlock(&pMSD->pSPD->SPLock);
  498. #endif // DBG
  499. #ifndef DPNBUILD_NOMULTICAST
  500. if (pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE))
  501. {
  502. DECREMENT_EPD(pEPD,"Cleanup Multicast");
  503. RELEASE_EPD(pEPD, "UNLOCK (Validate EP)"); // Releases EPLock
  504. }
  505. else
  506. #endif // DPNBUILD_NOMULTICAST
  507. {
  508. DPFX(DPFPREP,5, "(%p) Queueing DISCONNECT message", pEPD);
  509. EnqueueMessage(pMSD, pEPD); // Enqueue Disc frame on SendQ
  510. Unlock(&pEPD->EPLock);
  511. }
  512. Exit:
  513. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x]", hr);
  514. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  515. return hr;
  516. }
  517. /*
  518. ** Get/Set Protocol Caps
  519. **
  520. ** Return or Set information about the entire protocol.
  521. **
  522. */
  523. #undef DPF_MODNAME
  524. #define DPF_MODNAME "DNPGetProtocolCaps"
  525. HRESULT
  526. DNPGetProtocolCaps(HANDLE hProtocolData, DPN_CAPS* pCaps)
  527. {
  528. ProtocolData* pPData;
  529. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], pCaps[%p]", hProtocolData, pCaps);
  530. pPData = (ProtocolData*)hProtocolData;
  531. ASSERT_PPD(pPData);
  532. ASSERT(pCaps->dwSize == sizeof(DPN_CAPS) || pCaps->dwSize == sizeof(DPN_CAPS_EX));
  533. ASSERT(pCaps->dwFlags == 0);
  534. pCaps->dwConnectTimeout = pPData->dwConnectTimeout;
  535. pCaps->dwConnectRetries = pPData->dwConnectRetries;
  536. pCaps->dwTimeoutUntilKeepAlive = pPData->tIdleThreshhold;
  537. if (pCaps->dwSize==sizeof(DPN_CAPS_EX))
  538. {
  539. DPN_CAPS_EX * pCapsEx=(DPN_CAPS_EX * ) pCaps;
  540. pCapsEx->dwMaxRecvMsgSize=pPData->dwMaxRecvMsgSize;
  541. pCapsEx->dwNumSendRetries=pPData->dwSendRetriesToDropLink;
  542. pCapsEx->dwMaxSendRetryInterval=pPData->dwSendRetryIntervalLimit;
  543. pCapsEx->dwDropThresholdRate = pPData->dwDropThresholdRate;
  544. pCapsEx->dwThrottleRate = pPData->dwThrottleRate;
  545. pCapsEx->dwNumHardDisconnectSends = pPData->dwNumHardDisconnectSends;
  546. pCapsEx->dwMaxHardDisconnectPeriod=pPData->dwMaxHardDisconnectPeriod;
  547. }
  548. return DPN_OK;
  549. }
  550. #undef DPF_MODNAME
  551. #define DPF_MODNAME "DNPSetProtocolCaps"
  552. HRESULT
  553. DNPSetProtocolCaps(HANDLE hProtocolData, DPN_CAPS* pCaps)
  554. {
  555. ProtocolData* pPData;
  556. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], pCaps[%p]", hProtocolData, pCaps);
  557. pPData = (ProtocolData*)hProtocolData;
  558. ASSERT_PPD(pPData);
  559. ASSERT(pCaps->dwSize == sizeof(DPN_CAPS) || pCaps->dwSize == sizeof(DPN_CAPS_EX));
  560. ASSERT(pCaps->dwFlags == 0);
  561. pPData->dwConnectTimeout = pCaps->dwConnectTimeout;
  562. pPData->dwConnectRetries = pCaps->dwConnectRetries;
  563. pPData->tIdleThreshhold = pCaps->dwTimeoutUntilKeepAlive;
  564. if (pCaps->dwSize==sizeof(DPN_CAPS_EX))
  565. {
  566. DPN_CAPS_EX * pCapsEx=(DPN_CAPS_EX * ) pCaps;
  567. pPData->dwMaxRecvMsgSize=pCapsEx->dwMaxRecvMsgSize;
  568. pPData->dwSendRetriesToDropLink=pCapsEx->dwNumSendRetries;
  569. if (pPData->dwSendRetriesToDropLink>MAX_SEND_RETRIES_TO_DROP_LINK)
  570. {
  571. pPData->dwSendRetriesToDropLink=MAX_SEND_RETRIES_TO_DROP_LINK;
  572. }
  573. pPData->dwSendRetryIntervalLimit=pCapsEx->dwMaxSendRetryInterval;
  574. if (pPData->dwSendRetryIntervalLimit>MAX_SEND_RETRY_INTERVAL_LIMIT)
  575. {
  576. pPData->dwSendRetryIntervalLimit=MAX_SEND_RETRY_INTERVAL_LIMIT;
  577. }
  578. else if (pPData->dwSendRetryIntervalLimit<MIN_SEND_RETRY_INTERVAL_LIMIT)
  579. {
  580. pPData->dwSendRetryIntervalLimit=MIN_SEND_RETRY_INTERVAL_LIMIT;
  581. }
  582. pPData->dwDropThresholdRate = pCapsEx->dwDropThresholdRate;
  583. if (pPData->dwDropThresholdRate > 100)
  584. {
  585. pPData->dwDropThresholdRate = 100;
  586. }
  587. pPData->dwDropThreshold = (32 * pPData->dwDropThresholdRate) / 100;
  588. pPData->dwThrottleRate = pCapsEx->dwThrottleRate;
  589. if (pPData->dwThrottleRate > 100)
  590. {
  591. pPData->dwThrottleRate = 100;
  592. }
  593. pPData->fThrottleRate = ((FLOAT)100.0 - (FLOAT)(pPData->dwThrottleRate)) / (FLOAT)100.0;
  594. pPData->dwNumHardDisconnectSends=pCapsEx->dwNumHardDisconnectSends;
  595. if (pPData->dwNumHardDisconnectSends>MAX_HARD_DISCONNECT_SENDS)
  596. {
  597. pPData->dwNumHardDisconnectSends=MAX_HARD_DISCONNECT_SENDS;
  598. }
  599. else if (pPData->dwNumHardDisconnectSends<MIN_HARD_DISCONNECT_SENDS)
  600. {
  601. pPData->dwNumHardDisconnectSends=MIN_HARD_DISCONNECT_SENDS;
  602. }
  603. pPData->dwMaxHardDisconnectPeriod=pCapsEx->dwMaxHardDisconnectPeriod;
  604. if (pPData->dwMaxHardDisconnectPeriod>MAX_HARD_DISCONNECT_PERIOD)
  605. {
  606. pPData->dwMaxHardDisconnectPeriod=MAX_HARD_DISCONNECT_PERIOD;
  607. }
  608. else if (pPData->dwMaxHardDisconnectPeriod<MIN_HARD_DISCONNECT_PERIOD)
  609. {
  610. pPData->dwMaxHardDisconnectPeriod=MIN_HARD_DISCONNECT_PERIOD;
  611. }
  612. }
  613. return DPN_OK;
  614. }
  615. /*
  616. ** Get Endpoint Caps
  617. **
  618. ** Return information and statistics about a particular endpoint.
  619. **
  620. */
  621. #undef DPF_MODNAME
  622. #define DPF_MODNAME "DNPGetEPCaps"
  623. HRESULT
  624. DNPGetEPCaps(HANDLE hProtocolData, HANDLE hEndpoint, DPN_CONNECTION_INFO* pBuffer)
  625. {
  626. ProtocolData* pPData;
  627. PEPD pEPD;
  628. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hEndpoint[%p], pBuffer[%p]", hProtocolData, hEndpoint, pBuffer);
  629. pPData = (ProtocolData*)hProtocolData;
  630. ASSERT_PPD(pPData);
  631. pEPD = (PEPD)hEndpoint;
  632. ASSERT_EPD(pEPD);
  633. // This occurs when DropLink has been called, but the Core has not yet been given
  634. // an IndicateConnectionTerminated.
  635. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  636. {
  637. DPFX(DPFPREP,0, "Returning DPNERR_INVALIDENDPOINT - Enpoint is not connected");
  638. return DPNERR_INVALIDENDPOINT;
  639. }
  640. ASSERT(pBuffer != NULL);
  641. ASSERT(pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO) ||
  642. pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO_INTERNAL) ||
  643. pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO_INTERNAL2));
  644. pBuffer->dwRoundTripLatencyMS = pEPD->uiRTT;
  645. pBuffer->dwThroughputBPS = pEPD->uiPeriodRateB * 4; // Convert to apx of bytes/second (really bytes/1024 ms)
  646. pBuffer->dwPeakThroughputBPS = pEPD->uiPeakRateB * 4;
  647. pBuffer->dwBytesSentGuaranteed = pEPD->uiGuaranteedBytesSent;
  648. pBuffer->dwPacketsSentGuaranteed = pEPD->uiGuaranteedFramesSent;
  649. pBuffer->dwBytesSentNonGuaranteed = pEPD->uiDatagramBytesSent;
  650. pBuffer->dwPacketsSentNonGuaranteed = pEPD->uiDatagramFramesSent;
  651. pBuffer->dwBytesRetried = pEPD->uiGuaranteedBytesDropped;
  652. pBuffer->dwPacketsRetried = pEPD->uiGuaranteedFramesDropped;
  653. pBuffer->dwBytesDropped = pEPD->uiDatagramBytesDropped;
  654. pBuffer->dwPacketsDropped = pEPD->uiDatagramFramesDropped;
  655. pBuffer->dwMessagesTransmittedHighPriority = pEPD->uiMsgSentHigh;
  656. pBuffer->dwMessagesTimedOutHighPriority = pEPD->uiMsgTOHigh;
  657. pBuffer->dwMessagesTransmittedNormalPriority = pEPD->uiMsgSentNorm;
  658. pBuffer->dwMessagesTimedOutNormalPriority = pEPD->uiMsgTONorm;
  659. pBuffer->dwMessagesTransmittedLowPriority = pEPD->uiMsgSentLow;
  660. pBuffer->dwMessagesTimedOutLowPriority = pEPD->uiMsgTOLow;
  661. pBuffer->dwBytesReceivedGuaranteed = pEPD->uiGuaranteedBytesReceived;
  662. pBuffer->dwPacketsReceivedGuaranteed = pEPD->uiGuaranteedFramesReceived;
  663. pBuffer->dwBytesReceivedNonGuaranteed = pEPD->uiDatagramBytesReceived;
  664. pBuffer->dwPacketsReceivedNonGuaranteed = pEPD->uiDatagramFramesReceived;
  665. pBuffer->dwMessagesReceived = pEPD->uiMessagesReceived;
  666. if (pBuffer->dwSize >= sizeof(DPN_CONNECTION_INFO_INTERNAL))
  667. {
  668. DPFX(DPFPREP,DPF_CALLIN_LVL, "(%p) Test App requesting extended internal parameters", pEPD);
  669. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiDropCount = pEPD->uiDropCount;
  670. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiThrottleEvents = pEPD->uiThrottleEvents;
  671. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiAdaptAlgCount = pEPD->uiAdaptAlgCount;
  672. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowFilled = pEPD->uiWindowFilled;
  673. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiPeriodAcksBytes = pEPD->uiPeriodAcksBytes;
  674. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiPeriodXmitTime = pEPD->uiPeriodXmitTime;
  675. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->dwLastThroughputBPS = pEPD->uiLastRateB * 4;
  676. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiLastBytesAcked = pEPD->uiLastBytesAcked;
  677. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiQueuedMessageCount = pEPD->uiQueuedMessageCount;
  678. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowF = pEPD->uiWindowF;
  679. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowB = pEPD->uiWindowB;
  680. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiUnackedFrames = pEPD->uiUnackedFrames;
  681. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiUnackedBytes = pEPD->uiUnackedBytes;
  682. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiBurstGap = pEPD->uiBurstGap;
  683. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->iBurstCredit = pEPD->iBurstCredit;
  684. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodWindowF = pEPD->uiGoodWindowF;
  685. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodWindowB = pEPD->uiGoodWindowBI * pEPD->pSPD->uiFrameLength;
  686. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodBurstGap = pEPD->uiGoodBurstGap;
  687. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodRTT = pEPD->uiGoodRTT;
  688. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreWindowF = pEPD->uiRestoreWindowF;
  689. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreWindowB = pEPD->uiRestoreWindowBI * pEPD->pSPD->uiFrameLength;
  690. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreBurstGap = pEPD->uiRestoreBurstGap;
  691. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->bNextSend = pEPD->bNextSend;
  692. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->bNextReceive = pEPD->bNextReceive;
  693. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulReceiveMask = pEPD->ulReceiveMask;
  694. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulReceiveMask2 = pEPD->ulReceiveMask2;
  695. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulSendMask = pEPD->ulSendMask;
  696. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulSendMask2 = pEPD->ulSendMask2;
  697. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiCompleteMsgCount = pEPD->uiCompleteMsgCount;
  698. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRetryTimeout = pEPD->uiRetryTimeout;
  699. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulEPFlags = pEPD->ulEPFlags;
  700. }
  701. if (pBuffer->dwSize >= sizeof(DPN_CONNECTION_INFO_INTERNAL2))
  702. {
  703. DPFX(DPFPREP,DPF_CALLIN_LVL, "(%p) Test App requesting extended internal parameters 2", pEPD);
  704. ((PDPN_CONNECTION_INFO_INTERNAL2)pBuffer)->dwDropBitMask = pEPD->dwDropBitMask;
  705. #ifdef DBG
  706. ((PDPN_CONNECTION_INFO_INTERNAL2)pBuffer)->uiTotalThrottleEvents = pEPD->uiTotalThrottleEvents;
  707. #else
  708. ((PDPN_CONNECTION_INFO_INTERNAL2)pBuffer)->uiTotalThrottleEvents = (DWORD ) -1;
  709. #endif // DBG
  710. }
  711. return DPN_OK;
  712. }
  713. /*
  714. ** Build Disconnect Frame
  715. **
  716. ** Build a DISC frame, a Message actually, because we return an MSD which can be inserted into
  717. ** our reliable stream and will trigger one-side of the disconnect protocol when it is received
  718. ** by a partner.
  719. */
  720. #undef DPF_MODNAME
  721. #define DPF_MODNAME "BuildDisconnectFrame"
  722. PMSD
  723. BuildDisconnectFrame(PEPD pEPD)
  724. {
  725. PFMD pFMD;
  726. PMSD pMSD;
  727. // Allocate and fill out a Message Descriptor for this operation
  728. if((pMSD = (PMSD)POOLALLOC(MEMID_DISCONNECT_MSD, &MSDPool)) == NULL)
  729. {
  730. DPFX(DPFPREP,0, "Failed to allocate MSD");
  731. return NULL;
  732. }
  733. if((pFMD = (PFMD)POOLALLOC(MEMID_DISCONNECT_FMD, &FMDPool)) == NULL)
  734. {
  735. DPFX(DPFPREP,0, "Failed to allocate FMD");
  736. Lock(&pMSD->CommandLock);
  737. RELEASE_MSD(pMSD, "Release On FMD Get Failed");
  738. return NULL;
  739. }
  740. // NOTE: Set this to 1 after FMD allocation succeeds
  741. pMSD->uiFrameCount = 1;
  742. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Initialize Frame count, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  743. pMSD->ulMsgFlags2 |= MFLAGS_TWO_END_OF_STREAM;
  744. pMSD->ulSendFlags = DN_SENDFLAGS_RELIABLE | DN_SENDFLAGS_LOW_PRIORITY; // Priority is LOW so all previously submitted traffic will be sent
  745. pMSD->pSPD = pEPD->pSPD;
  746. pMSD->pEPD = pEPD;
  747. pFMD->CommandID = COMMAND_ID_SEND_RELIABLE;
  748. pFMD->ulFFlags |= FFLAGS_END_OF_MESSAGE | FFLAGS_END_OF_STREAM | FFLAGS_DONT_COALESCE; // Mark this frame as Disconnect
  749. pFMD->bPacketFlags = PACKET_COMMAND_DATA | PACKET_COMMAND_RELIABLE | PACKET_COMMAND_SEQUENTIAL | PACKET_COMMAND_END_MSG;
  750. pFMD->uiFrameLength = 0; // No user data in this frame
  751. pFMD->blMSDLinkage.InsertAfter( &pMSD->blFrameList); // Attach frame to MSD
  752. pFMD->pMSD = pMSD; // Link frame back to message
  753. pFMD->pEPD = pEPD;
  754. return pMSD;
  755. }
  756. /*
  757. ** Abort Sends on Connection
  758. **
  759. ** Walk the EPD's send queues and cancel all sends awaiting service. We might add
  760. ** code to issue Cancel commands to the SP for frames still owned by SP. On one hand,
  761. ** we are not expecting a big backlog to develop in SP, but on the other hand it still
  762. ** might happen. Esp, if we dont fix behavior I have observed with SP being really pokey
  763. ** about completing transmitted sends.
  764. **
  765. ** ** CALLED WITH EPD->EPLock HELD; RETURNS WITH LOCK RELEASED **
  766. */
  767. #undef DPF_MODNAME
  768. #define DPF_MODNAME "AbortSendsOnConnection"
  769. VOID
  770. AbortSendsOnConnection(PEPD pEPD)
  771. {
  772. PSPD pSPD = pEPD->pSPD;
  773. PFMD pFMD;
  774. PMSD pMSD;
  775. CBilink *pLink;
  776. CBilink TempList;
  777. PFMD pRealFMD;
  778. ASSERT_SPD(pSPD);
  779. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  780. TempList.Initialize(); // We will empty all send queues onto this temporary list
  781. do
  782. {
  783. if( (pLink = pEPD->blHighPriSendQ.GetNext()) == &pEPD->blHighPriSendQ)
  784. {
  785. if( (pLink = pEPD->blNormPriSendQ.GetNext()) == &pEPD->blNormPriSendQ)
  786. {
  787. if( (pLink = pEPD->blLowPriSendQ.GetNext()) == &pEPD->blLowPriSendQ)
  788. {
  789. if( (pLink = pEPD->blCompleteSendList.GetNext()) == &pEPD->blCompleteSendList)
  790. {
  791. break; // ALL DONE - No more sends
  792. }
  793. }
  794. }
  795. }
  796. // We have found another send on one of our send queues.
  797. pLink->RemoveFromList(); // Remove it from the queue
  798. pMSD = CONTAINING_OBJECT(pLink, MSD, blQLinkage);
  799. ASSERT_MSD(pMSD);
  800. pMSD->ulMsgFlags2 |= (MFLAGS_TWO_ABORT | MFLAGS_TWO_ABORT_WILL_COMPLETE); // Do no further processing
  801. #ifdef DBG
  802. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  803. #endif // DBG
  804. // If this MSD is a Disconnect, it will be caught by the code below that checks
  805. // pEPD->pCommand. We don't want to end up putting it on the TempList twice.
  806. if (pMSD->CommandID != COMMAND_ID_DISCONNECT && pMSD->CommandID != COMMAND_ID_DISC_RESPONSE)
  807. {
  808. DPFX(DPFPREP,5, "(%p) ABORT SENDS. Found (%p)", pEPD, pMSD);
  809. LOCK_MSD(pMSD, "AbortSends Temp Ref");
  810. pMSD->blQLinkage.InsertBefore( &TempList); // Place on the temporary list
  811. }
  812. }
  813. while (1);
  814. pEPD->uiQueuedMessageCount = 0; // keep count of MSDs on all send queues
  815. if((pMSD = pEPD->pCommand) != NULL)
  816. {
  817. // There may be a DISCONNECT command waiting on this special pointer for the final DISC frame
  818. // from partner to arrive.
  819. pMSD->ulMsgFlags2 |= (MFLAGS_TWO_ABORT | MFLAGS_TWO_ABORT_WILL_COMPLETE); // Do no further processing
  820. if(pMSD->CommandID == COMMAND_ID_DISCONNECT || pMSD->CommandID == COMMAND_ID_DISC_RESPONSE)
  821. {
  822. pEPD->pCommand = NULL;
  823. LOCK_MSD(pMSD, "AbortSends Temp Ref");
  824. pMSD->blQLinkage.InsertBefore( &TempList);
  825. // We will be indicating below, so make sure no one else does once we
  826. // leave the EPLock.
  827. ASSERT(!(pEPD->ulEPFlags & EPFLAGS_INDICATED_DISCONNECT));
  828. pEPD->ulEPFlags |= EPFLAGS_INDICATED_DISCONNECT;
  829. }
  830. else
  831. {
  832. DPFX(DPFPREP,0,"(%p) Any Connect or Listen on pCommand should have already been cleaned up", pEPD);
  833. ASSERT(!"Any Connect or Listen on pCommand should have already been cleaned up");
  834. }
  835. }
  836. // If we clear out our SendWindow before we cancel the sends, then we dont need to differentiate
  837. // between sends that have or have not been transmitted.
  838. while(!pEPD->blSendWindow.IsEmpty())
  839. {
  840. pFMD = CONTAINING_OBJECT(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  841. ASSERT_FMD(pFMD);
  842. pFMD->ulFFlags &= ~(FFLAGS_IN_SEND_WINDOW);
  843. pFMD->blWindowLinkage.RemoveFromList(); // Eliminate each frame from the Send Window
  844. RELEASE_FMD(pFMD, "Send Window");
  845. DPFX(DPFPREP,5, "(%p) ABORT CONN: Release frame from Window: pFMD=0x%p", pEPD, pFMD);
  846. }
  847. pEPD->pCurrentSend = NULL;
  848. pEPD->pCurrentFrame = NULL;
  849. while(!pEPD->blRetryQueue.IsEmpty())
  850. {
  851. pFMD = CONTAINING_OBJECT(pEPD->blRetryQueue.GetNext(), FMD, blQLinkage);
  852. ASSERT_FMD(pFMD);
  853. pFMD->blQLinkage.RemoveFromList();
  854. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  855. if ((pFMD->CommandID == COMMAND_ID_SEND_COALESCE) ||
  856. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  857. {
  858. pLink = pFMD->blCoalesceLinkage.GetNext();
  859. while (pLink != &pFMD->blCoalesceLinkage)
  860. {
  861. pRealFMD = CONTAINING_OBJECT(pLink, FMD, blCoalesceLinkage);
  862. ASSERT_FMD(pRealFMD);
  863. ASSERT_MSD(pRealFMD->pMSD);
  864. pRealFMD->pMSD->uiFrameCount--; // Protected by EPLock, retries count against outstanding frame count
  865. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Coalesced retry frame reference decremented on abort, pMSD[%p], framecount[%u], ID %u", pRealFMD->pMSD, pRealFMD->pMSD->uiFrameCount, pRealFMD->CommandID);
  866. pLink = pLink->GetNext();
  867. // If this was a copied retry subframe, remove it from the coalesced list since it will never
  868. // get a true completion like the originals do (the originals were also in one of the priority
  869. // send queues). The release below should be the final reference.
  870. if (pRealFMD->CommandID == COMMAND_ID_COPIED_RETRY)
  871. {
  872. ASSERT(pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE);
  873. DPFX(DPFPREP, 7, "Removing copied retry frame 0x%p from coalesced list (header = 0x%p)", pRealFMD, pFMD);
  874. // Copied retries don't maintain a reference on their containing header.
  875. ASSERT(pRealFMD->pCSD == NULL);
  876. pRealFMD->blCoalesceLinkage.RemoveFromList();
  877. DECREMENT_EPD(pEPD, "UNLOCK (Copy Complete coalesce)"); // SPLock not already held
  878. }
  879. else
  880. {
  881. ASSERT(pFMD->CommandID == COMMAND_ID_SEND_COALESCE);
  882. }
  883. RELEASE_FMD(pRealFMD, "SP Submit (coalesce)");
  884. }
  885. }
  886. else
  887. {
  888. ASSERT_MSD(pFMD->pMSD);
  889. pFMD->pMSD->uiFrameCount--; // Protected by EPLock, retries count against outstanding frame count
  890. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Retry frame reference decremented on abort, pMSD[%p], framecount[%u]", pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  891. }
  892. DECREMENT_EPD(pEPD, "UNLOCK (Releasing Retry Frame)"); // SPLock not already held
  893. if ((pFMD->CommandID == COMMAND_ID_COPIED_RETRY) ||
  894. (pFMD->CommandID == COMMAND_ID_COPIED_RETRY_COALESCE))
  895. {
  896. DECREMENT_EPD(pEPD, "UNLOCK (Copy Complete)"); // SPLock not already held
  897. }
  898. RELEASE_FMD(pFMD, "SP Submit");
  899. }
  900. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  901. // Now that we have emptied the EPD's queues we will release the EPLock so we can lock each
  902. // MSD before we complete it.
  903. Unlock(&pEPD->EPLock);
  904. while(!TempList.IsEmpty())
  905. {
  906. pMSD = CONTAINING_OBJECT(TempList.GetNext(), MSD, blQLinkage);
  907. ASSERT_MSD(pMSD);
  908. pMSD->blQLinkage.RemoveFromList(); // remove this send from temporary queue
  909. Lock(&pMSD->CommandLock); // Complete call will Unlock MSD
  910. Lock(&pEPD->EPLock);
  911. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_USE);
  912. ASSERT(pMSD->CommandID == COMMAND_ID_DISCONNECT ||
  913. pMSD->CommandID == COMMAND_ID_DISC_RESPONSE ||
  914. pMSD->CommandID == COMMAND_ID_SEND_RELIABLE ||
  915. pMSD->CommandID == COMMAND_ID_KEEPALIVE ||
  916. pMSD->CommandID == COMMAND_ID_SEND_DATAGRAM);
  917. pLink = pMSD->blFrameList.GetNext();
  918. while (pLink != &pMSD->blFrameList)
  919. {
  920. pFMD = CONTAINING_OBJECT(pLink, FMD, blMSDLinkage);
  921. ASSERT_FMD(pFMD);
  922. // We don't allow a send to complete to the Core until uiFrameCount goes to zero indicating that all frames
  923. // of the message are out of the SP. We need to remove references from uiFrameCount for any frames that
  924. // never were transmitted. Frames and retries that were transmitted will have their references removed in
  925. // DNSP_CommandComplete when the SP completes them.
  926. if (!(pFMD->ulFFlags & FFLAGS_TRANSMITTED))
  927. {
  928. pMSD->uiFrameCount--; // Protected by EPLock
  929. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count decremented on abort for non-transmitted frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  930. }
  931. pLink = pLink->GetNext();
  932. }
  933. if (pMSD->uiFrameCount == 0) // Protected by EPLock
  934. {
  935. if (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT_WILL_COMPLETE)
  936. {
  937. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  938. DECREMENT_MSD(pMSD, "AbortSends Temp Ref");
  939. // Decide which completion function to call based on the MSD type
  940. if (pMSD->CommandID == COMMAND_ID_DISCONNECT || pMSD->CommandID == COMMAND_ID_DISC_RESPONSE)
  941. {
  942. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing disconnect or disconnect response, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  943. Unlock(&pEPD->EPLock);
  944. CompleteDisconnect(pMSD, pSPD, pEPD); // Releases CommandLock
  945. }
  946. else if (pMSD->CommandID == COMMAND_ID_SEND_DATAGRAM)
  947. {
  948. Unlock(&pEPD->EPLock);
  949. CompleteDatagramSend(pMSD->pSPD, pMSD, DPNERR_CONNECTIONLOST); // Releases CommandLock
  950. }
  951. else
  952. {
  953. ASSERT(pMSD->CommandID == COMMAND_ID_SEND_RELIABLE || pMSD->CommandID == COMMAND_ID_KEEPALIVE);
  954. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing Reliable frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  955. // See what error code we need to return
  956. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_SEND_COMPLETE)
  957. {
  958. Unlock(&pEPD->EPLock);
  959. CompleteReliableSend(pSPD, pMSD, DPN_OK); // This releases the CommandLock
  960. }
  961. else
  962. {
  963. Unlock(&pEPD->EPLock);
  964. CompleteReliableSend(pSPD, pMSD, DPNERR_CONNECTIONLOST); // This releases the CommandLock
  965. }
  966. }
  967. }
  968. else
  969. {
  970. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "SP Completion has already completed MSD to the Core, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  971. Unlock(&pEPD->EPLock);
  972. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  973. }
  974. }
  975. else
  976. {
  977. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frames still out, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  978. Unlock(&pEPD->EPLock);
  979. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  980. }
  981. }
  982. }
  983. /*
  984. ** Protocol Test Functions
  985. **
  986. ** The following functions are used to test the protocol by various test apps.
  987. **
  988. */
  989. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  990. #undef DPF_MODNAME
  991. #define DPF_MODNAME "SetLinkParms"
  992. VOID SetLinkParms(PEPD pEPD, PINT Data)
  993. {
  994. if(Data[0])
  995. {
  996. pEPD->uiGoodWindowF = pEPD->uiWindowF = Data[0];
  997. pEPD->uiGoodWindowBI = pEPD->uiWindowBIndex = Data[0];
  998. pEPD->uiWindowB = pEPD->uiWindowBIndex * pEPD->pSPD->uiFrameLength;
  999. DPFX(DPFPREP,7, "** ADJUSTING WINDOW TO %d FRAMES", Data[0]);
  1000. }
  1001. if(Data[1])
  1002. {
  1003. }
  1004. if(Data[2])
  1005. {
  1006. pEPD->uiGoodBurstGap = pEPD->uiBurstGap = Data[2];
  1007. DPFX(DPFPREP,7, "** ADJUSTING GAP TO %d ms", Data[2]);
  1008. }
  1009. pEPD->uiPeriodAcksBytes = 0;
  1010. pEPD->uiPeriodXmitTime = 0;
  1011. }
  1012. #undef DPF_MODNAME
  1013. #define DPF_MODNAME "DNPDebug"
  1014. HRESULT
  1015. DNPDebug(HANDLE hProtocolData, UINT uiOpCode, HANDLE hEndpoint, VOID* pvData)
  1016. {
  1017. ProtocolData* pPData;
  1018. PEPD pEPD;
  1019. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], uiOpCode[%d], hEndpoint[%p], pvData[%p]", hProtocolData, uiOpCode, hEndpoint, pvData);
  1020. pPData = (ProtocolData*)hProtocolData;
  1021. ASSERT_PPD(pPData);
  1022. pEPD = (PEPD)hEndpoint;
  1023. if (pEPD != NULL)
  1024. {
  1025. ASSERT_EPD(pEPD);
  1026. }
  1027. switch(uiOpCode)
  1028. {
  1029. case PROTDEBUG_FREEZELINK:
  1030. /* Toggle link frozen state */
  1031. pEPD->ulEPFlags ^= EPFLAGS_LINK_FROZEN;
  1032. break;
  1033. case PROTDEBUG_TOGGLE_KEEPALIVE:
  1034. /* Toggle whether KeepAlives are on or off */
  1035. pEPD->ulEPFlags ^= EPFLAGS_KEEPALIVE_RUNNING;
  1036. break;
  1037. case PROTDEBUG_TOGGLE_ACKS:
  1038. /* Toggle whether delayed acks (via DelayedAckTimeout) are on or off */
  1039. pEPD->ulEPFlags ^= EPFLAGS_NO_DELAYED_ACKS;
  1040. break;
  1041. case PROTDEBUG_SET_ASSERTFUNC:
  1042. /* Set a function to be called when an assert occurs */
  1043. g_pfnAssertFunc = (PFNASSERTFUNC)pvData;
  1044. break;
  1045. case PROTDEBUG_SET_LINK_PARMS:
  1046. /* Manually set link parameters */
  1047. SetLinkParms(pEPD, (int*)pvData);
  1048. break;
  1049. case PROTDEBUG_TOGGLE_LINKSTATE:
  1050. /* Toggle Dynamic/Static Link control */
  1051. pEPD->ulEPFlags ^= EPFLAGS_LINK_STABLE;
  1052. break;
  1053. case PROTDEBUG_TOGGLE_NO_RETRIES:
  1054. /* Toggle whether we send retries or not */
  1055. pEPD->ulEPFlags2 ^= EPFLAGS2_DEBUG_NO_RETRIES;
  1056. break;
  1057. case PROTDEBUG_SET_MEMALLOCFUNC:
  1058. /* Set a function to be called when a memory allocation occurs */
  1059. g_pfnMemAllocFunc = (PFNMEMALLOCFUNC)pvData;
  1060. break;
  1061. case PROTDEBUG_TOGGLE_TIMER_FAILURE:
  1062. /* Toggle whether Scheduling a timer should succeed or fail */
  1063. pPData->ulProtocolFlags^=PFLAGS_FAIL_SCHEDULE_TIMER;
  1064. default:
  1065. return DPNERR_GENERIC;
  1066. }
  1067. return DPN_OK;
  1068. }
  1069. #endif // !DPNBUILD_NOPROTOCOLTESTITF