Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1131 lines
36 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. VOID AbortDatagramSend(PMSD, HRESULT);
  18. /*
  19. ** Cancel Command
  20. **
  21. ** This procedure is passed a HANDLE returned from a previous asynchronous
  22. ** DPLAY command. At the moment, the handle is a pointer to an internal data
  23. ** structure. Problem with this is that due to FPM's (fixed pool manager) design
  24. ** they will get recycled very quickly and frequently. We might want to map them
  25. ** into an external handle table which will force them to recycle much more slowly.
  26. ** Perhaps, I will let the upper DN layer do this mapping...
  27. **
  28. ** Anyway, the only check I can do right now is that the HANDLE is currently
  29. ** allocated to something.
  30. **
  31. ** We do not expect cancels to happen very often. Therefore, I do not feel
  32. ** bad about walking the global command list to find the Handle. Of course, if
  33. ** we do go to a handle mapped system then we should not need to do this walk.
  34. **
  35. ** I THINK - That any cancellable command will be on either MessageList or TimeoutList!
  36. **
  37. ** Things we can cancel and their possible states:
  38. **
  39. ** SEND Datagram
  40. ** On SPD Send Queue
  41. ** On EPD Send Queue
  42. ** In SP call
  43. **
  44. ** SEND Reliable
  45. ** We can only cancel if it has not started transmitting. Once its started, the
  46. ** user program must Abort the link to cancel the send.
  47. **
  48. ** CONNECT
  49. ** In SP call
  50. ** On PD list
  51. **
  52. ** LISTEN
  53. ** In SP call
  54. ** On PD list
  55. **
  56. ** Remember, if we cancel a command in SP then the CommandComplete is supposed to
  57. ** occur. This means that we should not have to explicitly free the MSD, etc in these
  58. ** cases.
  59. */
  60. #undef DPF_MODNAME
  61. #define DPF_MODNAME "DNPCancelCommand"
  62. HRESULT
  63. DNPCancelCommand(PProtocolData pPData, HANDLE hCommand)
  64. {
  65. PMSD pMSD = (PMSD) hCommand;
  66. HRESULT hr;
  67. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], hCommand[%x]", pPData, hCommand);
  68. if(pMSD->Sign != MSD_SIGN)
  69. {
  70. DPFX(DPFPREP,0, "Cancel called with invalid handle");
  71. return DPNERR_INVALIDHANDLE;
  72. }
  73. Lock(&pMSD->CommandLock); // Take this early to freeze state of command
  74. // validate instance of MSD
  75. if(pMSD->lRefCnt == -1)
  76. {
  77. DPFX(DPFPREP,0, "Cancel called with invalid handle");
  78. Unlock(&pMSD->CommandLock);
  79. return DPNERR_INVALIDHANDLE;
  80. }
  81. hr = DoCancel(pMSD, DPNERR_USERCANCEL); // Releases CommandLock
  82. return hr;
  83. }
  84. /*
  85. ** Do Cancel
  86. **
  87. ** This function implements the meat of the cancel asynch operation. It gets called from
  88. ** two places. Either from the User cancel API right above, or from the global timeout handler.
  89. **
  90. ** ***This code requires the MSD->CommandLock to be help upon entry, unlocks upon return
  91. */
  92. #undef DPF_MODNAME
  93. #define DPF_MODNAME "DoCancel"
  94. HRESULT
  95. DoCancel(PMSD pMSD, HRESULT CompletionCode)
  96. {
  97. PEPD pEPD;
  98. HRESULT hr = DPN_OK;
  99. DPFX(DPFPREP,7, "Cancelling pMSD=%p", pMSD);
  100. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  101. if (!(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_USE))
  102. {
  103. DPFX(DPFPREP,0, "(%p) MSD is in Pool, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pMSD->pEPD, pMSD);
  104. ASSERT(0);
  105. Unlock(&pMSD->CommandLock);
  106. return DPNERR_CANNOTCANCEL;
  107. }
  108. if(pMSD->ulMsgFlags1 & (MFLAGS_ONE_CANCELLED | MFLAGS_ONE_COMPLETE))
  109. {
  110. DPFX(DPFPREP,7, "(%p) MSD is Cancelled or Complete, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pMSD->pEPD, pMSD);
  111. Unlock(&pMSD->CommandLock);
  112. return DPNERR_CANNOTCANCEL;
  113. }
  114. pMSD->ulMsgFlags1 |= MFLAGS_ONE_CANCELLED;
  115. switch(pMSD->CommandID)
  116. {
  117. case COMMAND_ID_SEND_DATAGRAM:
  118. pEPD = pMSD->pEPD;
  119. ASSERT_EPD(pEPD);
  120. Lock(&pEPD->EPLock);
  121. if(pMSD->ulMsgFlags2 & (MFLAGS_TWO_ABORT | MFLAGS_TWO_TRANSMITTING | MFLAGS_TWO_SEND_COMPLETE))
  122. {
  123. DPFX(DPFPREP,7, "(%p) MSD is Aborted, Transmitting, or Complete, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pEPD, pMSD);
  124. Unlock(&pEPD->EPLock); // Link is dropping or DNET is terminating
  125. hr = DPNERR_CANNOTCANCEL; // To cancel an xmitting reliable send you
  126. break; // must Abort the connection.
  127. }
  128. pMSD->blQLinkage.RemoveFromList(); // Remove from SendQueue (whichever one)
  129. ASSERT(pEPD->uiQueuedMessageCount > 0);
  130. --pEPD->uiQueuedMessageCount; // keep count of MSDs on all send queues
  131. // Clear data-ready flag if everything is sent
  132. if((pEPD->uiQueuedMessageCount == 0) && (pEPD->pCurrentSend == NULL))
  133. {
  134. pEPD->ulEPFlags &= ~(EPFLAGS_SDATA_READY);
  135. }
  136. #ifdef DEBUG
  137. ASSERT(pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED);
  138. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  139. #endif
  140. Unlock(&pEPD->EPLock); // release lock on queue
  141. DPFX(DPFPREP,7, "(%p) Aborting Datagram send, pMSD[%p]", pEPD, pMSD);
  142. AbortDatagramSend(pMSD, CompletionCode); // Releases CommandLock
  143. return hr;
  144. case COMMAND_ID_SEND_RELIABLE:
  145. pEPD = pMSD->pEPD;
  146. ASSERT_EPD(pEPD);
  147. Lock(&pEPD->EPLock);
  148. if(pMSD->ulMsgFlags2 & (MFLAGS_TWO_ABORT | MFLAGS_TWO_TRANSMITTING | MFLAGS_TWO_SEND_COMPLETE))
  149. {
  150. DPFX(DPFPREP,7, "(%p) MSD is Aborted, Transmitting, or Complete, returning DPNERR_CANNOTCANCEL, pMSD[%p]", pEPD, pMSD);
  151. Unlock(&pEPD->EPLock); // Link is dropping or DNET is terminating
  152. hr = DPNERR_CANNOTCANCEL; // To cancel an xmitting reliable send you
  153. break; // must Abort the connection.
  154. }
  155. if(pMSD->TimeoutTimer != NULL)
  156. {
  157. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer", pEPD);
  158. if(CancelMyTimer(pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  159. {
  160. DECREMENT_MSD(pMSD, "Send Timeout Timer");
  161. }
  162. else
  163. {
  164. DPFX(DPFPREP,7, "(%p) Cancelling Timeout Timer Failed", pEPD);
  165. }
  166. pMSD->TimeoutTimer = NULL;
  167. }
  168. pMSD->blQLinkage.RemoveFromList(); // Remove cmd from queue
  169. ASSERT(pEPD->uiQueuedMessageCount > 0);
  170. --pEPD->uiQueuedMessageCount; // keep count of MSDs on all send queues
  171. // Clear data-ready flag if everything is sent
  172. if((pEPD->uiQueuedMessageCount == 0) && (pEPD->pCurrentSend == NULL))
  173. {
  174. pEPD->ulEPFlags &= ~(EPFLAGS_SDATA_READY);
  175. }
  176. #ifdef DEBUG
  177. ASSERT(pMSD->ulMsgFlags2 & MFLAGS_TWO_ENQUEUED);
  178. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  179. #endif
  180. // This only gets complex if the cancelled send was the "on deck" send for the endpoint.
  181. //
  182. // New Logic! With advent of priority sending, we can no longer prepare the On Deck send before we are
  183. // ready to transmit since the arrival of a higher priority send should be checked for before starting to
  184. // send a new message. This means that pCurrentSend != pMSD unless the MFLAGS_TRANSMITTING flag has also
  185. // been set, rendering the message impossible to cancel.
  186. ASSERT(pEPD->pCurrentSend != pMSD);
  187. pMSD->uiFrameCount = 0;
  188. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Send cancelled before sending, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  189. Unlock(&pEPD->EPLock);
  190. DPFX(DPFPREP,7, "(%p) Completing Reliable Send", pEPD);
  191. CompleteReliableSend(pMSD->pSPD, pMSD, CompletionCode);
  192. return hr;
  193. case COMMAND_ID_CONNECT:
  194. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER)
  195. {
  196. // SP owns the command - issue a cancel and let CompletionEvent clean up command
  197. Unlock(&pMSD->CommandLock); // We could deadlock if we cancel with lock held
  198. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Connect, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  199. (void) IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  200. // If the SP Cancel fails it should not matter. It would usually mean we are
  201. // in a race with the command completing, in which case the cancel flag will
  202. // nip it in the bud.
  203. return DPN_OK;
  204. }
  205. // We will only get here once because the entry to this function checks CANCEL and COMPLETE and sets
  206. // CANCEL. CompleteConnect will set COMPLETE as well.
  207. pEPD = pMSD->pEPD;
  208. ASSERT_EPD(pEPD);
  209. Lock(&pEPD->EPLock);
  210. // Unlink the MSD from the EPD
  211. ASSERT(pEPD->pCommand == pMSD);
  212. pEPD->pCommand = NULL;
  213. DECREMENT_MSD(pMSD, "EPD Ref");
  214. DropLink(pEPD); // This unlocks the EPLock
  215. // MSD lock still held
  216. DPFX(DPFPREP,5, "(%p) Connect cancelled, completing Connect, pMSD[%p]", pEPD, pMSD);
  217. CompleteConnect(pMSD, pMSD->pSPD, NULL, DPNERR_USERCANCEL); // releases command lock
  218. return DPN_OK;
  219. case COMMAND_ID_LISTEN:
  220. /*
  221. ** Cancel Listen
  222. **
  223. ** SP will own parts of the MSD until the SPCommandComplete function is called. We will
  224. ** defer much of our cancel processing to this handler.
  225. */
  226. // Stop listening in SP -- This will prevent new connections from popping up while we are
  227. // closing down any left in progress. Only problem is we need to release command lock to
  228. // do it.
  229. Unlock(&pMSD->CommandLock); // We can deadlock if we hold across this call
  230. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Listen, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  231. (void) IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  232. Lock(&pMSD->CommandLock); // Lock this down again.
  233. // Are there any connections in progress?
  234. // For a Listen command, connecting endpoints are held on the blFrameList
  235. while(!pMSD->blFrameList.IsEmpty())
  236. {
  237. pEPD = CONTAINING_RECORD(pMSD->blFrameList.GetNext(), EPD, blSPLinkage);
  238. ASSERT_EPD(pEPD);
  239. DPFX(DPFPREP,1, "FOUND CONNECT IN PROGRESS ON CANCELLED LISTEN, EPD=%p", pEPD);
  240. Lock(&pEPD->EPLock);
  241. // Ensure we don't stay in this loop forever
  242. pEPD->ulEPFlags &= ~(EPFLAGS_LINKED_TO_LISTEN);
  243. pEPD->blSPLinkage.RemoveFromList(); // Unlink EPD from Listen Queue
  244. // It is possible that RejectInvalidPacket is happening at the same time as this, so guard against us
  245. // both doing the same clean up and removing the same reference from the MSD.
  246. if (!(pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING))
  247. {
  248. // We know this only happens once because anyone who does it either transitions us to the
  249. // CONNECTED or TERMINATING state, and also removes us from the Listen list above.
  250. // Unlink MSD from EPD
  251. ASSERT(pEPD->pCommand == pMSD); // This should be pointing back to this listen
  252. pEPD->pCommand = NULL;
  253. DECREMENT_MSD(pMSD, "EPD Ref"); // Unlink from EPD and release associated reference
  254. DropLink(pEPD); // releases EPLock
  255. }
  256. else
  257. {
  258. Unlock(&pEPD->EPLock);
  259. }
  260. } // for each connection in progress
  261. RELEASE_MSD(pMSD, "(Base Ref) Release On Cancel"); // release base reference
  262. return DPN_OK;
  263. case COMMAND_ID_ENUM:
  264. {
  265. Unlock(&pMSD->CommandLock);
  266. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on Enum, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  267. return IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  268. // We will pass HRESULT from SP directly to user
  269. }
  270. case COMMAND_ID_ENUMRESP:
  271. {
  272. Unlock(&pMSD->CommandLock);
  273. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->CancelCommand on EnumResp, pMSD[%p], hCommand[%x], pSPD[%p]", pMSD, pMSD->hCommand, pMSD->pSPD);
  274. return IDP8ServiceProvider_CancelCommand(pMSD->pSPD->IISPIntf, pMSD->hCommand, pMSD->dwCommandDesc);
  275. // We will pass HRESULT from SP directly to user
  276. }
  277. case COMMAND_ID_DISCONNECT:
  278. case COMMAND_ID_COPIED_RETRY: // This should be on FMD's only
  279. case COMMAND_ID_CFRAME: // This should be on FMD's only
  280. case COMMAND_ID_DISC_RESPONSE: // These are never placed on the global list and aren't cancellable
  281. case COMMAND_ID_KEEPALIVE: // These are never placed on the global list and aren't cancellable
  282. default:
  283. ASSERT(0); // Should never get here
  284. hr = DPNERR_CANNOTCANCEL;
  285. break;
  286. }
  287. Unlock(&pMSD->CommandLock);
  288. return hr;
  289. }
  290. /*
  291. ** Get Listen Info
  292. **
  293. ** Return a buffer full of interesting and provokative tidbits about a particular Listen command.
  294. */
  295. #undef DPF_MODNAME
  296. #define DPF_MODNAME "DNPGetListenAddressInfo"
  297. HRESULT
  298. DNPGetListenAddressInfo(HANDLE hCommand, PSPGETADDRESSINFODATA pSPData)
  299. {
  300. PMSD pMSD = (PMSD) hCommand;
  301. HRESULT hr = DPNERR_INVALIDHANDLE;
  302. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hCommand[%x], pSPData[%p]", hCommand, pSPData);
  303. ASSERT(pMSD != NULL);
  304. ASSERT_MSD(pMSD);
  305. if((pMSD->CommandID == COMMAND_ID_LISTEN) && (pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_SERVICE_PROVIDER))
  306. {
  307. pSPData->hEndpoint = pMSD->hListenEndpoint;
  308. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->GetAddressInfo, pMSD[%p], hEndpoint[%x], pSPD[%p]", pMSD, pMSD->hListenEndpoint, pMSD->pSPD);
  309. hr = IDP8ServiceProvider_GetAddressInfo(pMSD->pSPD->IISPIntf, pSPData);
  310. }
  311. return hr;
  312. }
  313. /*
  314. ** Validate End Point
  315. **
  316. ** This routine checks standard flags, validates the Service
  317. ** Provider, and bumps the reference count on an end point descriptor
  318. ** which is passed in.
  319. */
  320. #undef DPF_MODNAME
  321. #define DPF_MODNAME "ValidateEndPoint"
  322. HRESULT
  323. ValidateEndPoint(PEPD pEPD)
  324. {
  325. if(pEPD == NULL)
  326. {
  327. DPFX(DPFPREP,1, "Validate EndPoint Fails on NULL EPD", pEPD);
  328. return DPNERR_INVALIDENDPOINT;
  329. }
  330. if (pEPD->Sign != EPD_SIGN)
  331. {
  332. DPFX(DPFPREP,1, "Validate EndPoint Fails on EPD with bad sign (%p)", pEPD);
  333. return DPNERR_INVALIDENDPOINT;
  334. }
  335. // Bump reference count on this baby
  336. if(!LOCK_EPD(pEPD, "LOCK (ValidateEndPoint - DISC)"))
  337. {
  338. // When LOCK_EPD returns FALSE, there is no ref placed on the endpoint, so we don't need to release
  339. DPFX(DPFPREP,1, "Validate EndPoint Fails on unreferenced EPD (%p)", pEPD);
  340. return DPNERR_INVALIDENDPOINT;
  341. }
  342. return DPN_OK;
  343. }
  344. /*
  345. ** Disconnect End Point
  346. **
  347. ** This function is called when the client no longer wishes
  348. ** to communicate with the specified end point. We will initiate
  349. ** the disconnect protocol with the endpoint, and when it is
  350. ** acknowleged, we will disconnect the SP and release the handle.
  351. **
  352. ** Disconnect is defined in Direct Net to allow all previously
  353. ** submitted sends to complete, but no additional sends to be submitted.
  354. ** Also, any sends the partner has in progress will be delivered, but
  355. ** no additional sends will be accepted following the indication that
  356. ** a disconnect is in progress on the remote end.
  357. **
  358. ** This implies that two indications will be generated on the remote
  359. ** machine, Disconnect Initiated and Disconnect Complete. Only the
  360. ** Complete will be indicated on the issueing side.
  361. */
  362. #undef DPF_MODNAME
  363. #define DPF_MODNAME "DNPDisconnectEndPoint"
  364. HRESULT
  365. DNPDisconnectEndPoint(PProtocolData pPData, HANDLE hEndPoint, PVOID pvContext, PHANDLE phCommand)
  366. {
  367. PEPD pEPD;
  368. PMSD pMSD;
  369. HRESULT hr;
  370. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], hEndPoint[%x], pvContext[%p], phCommand[%p]", pPData, hEndPoint, pvContext, phCommand);
  371. pEPD = (PEPD) hEndPoint;
  372. // This bumps REFCNT if it returns DPN_OK
  373. if((hr = ValidateEndPoint(pEPD)) != DPN_OK)
  374. {
  375. DPFX(DPFPREP,0, "Attempt to disconnect invalid endpoint");
  376. return hr;
  377. }
  378. Lock(&pEPD->EPLock);
  379. // If we aren't connected, or we have already initiated a disconnect, don't allow a new disconnect
  380. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED) || (pEPD->ulEPFlags & (EPFLAGS_SENT_DISCONNECT | EPFLAGS_RECEIVED_DISCONNECT)))
  381. {
  382. RELEASE_EPD(pEPD, "UNLOCK (Validate EP)"); // Releases EPLock
  383. DPFX(DPFPREP,1, "Attempt to disconnect already disconnecting endpoint");
  384. return DPNERR_ALREADYDISCONNECTING;
  385. }
  386. pEPD->ulEPFlags |= EPFLAGS_SENT_DISCONNECT; // Accept no more sends, but don't scrap link yet
  387. if((pMSD = BuildDisconnectFrame(pEPD)) == NULL)
  388. {
  389. RELEASE_EPD(pEPD, "UNLOCK (Validate EP)"); // Releases EPLock
  390. DPFX(DPFPREP,0, "Failed to build disconnect frame");
  391. return DPNERR_OUTOFMEMORY; // The educated user will next try an Abort command
  392. }
  393. pMSD->CommandID = COMMAND_ID_DISCONNECT;
  394. pMSD->Context = pvContext; // retain user's context value
  395. *phCommand = pMSD; // pass back command handle
  396. // We borrow the reference placed above by ValidateEP for this. It will be released
  397. // on completion of the Disconnect.
  398. ASSERT(pEPD->pCommand == NULL);
  399. pEPD->pCommand = pMSD; // Store the disconnect command on the endpoint until it is complete
  400. #ifdef DEBUG
  401. Lock(&pMSD->pSPD->SPLock);
  402. pMSD->blSPLinkage.InsertBefore( &pMSD->pSPD->blMessageList);
  403. pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST;
  404. Unlock(&pMSD->pSPD->SPLock);
  405. #endif
  406. DPFX(DPFPREP,5, "(%p) Queueing DISCONNECT message", pEPD);
  407. EnqueueMessage(pMSD, pEPD); // Enqueue Disc frame on SendQ
  408. Unlock(&pEPD->EPLock);
  409. return DPNERR_PENDING;
  410. }
  411. /*
  412. ** Get/Set Protocol Caps
  413. **
  414. ** Return or Set information about the entire protocol.
  415. **
  416. */
  417. #undef DPF_MODNAME
  418. #define DPF_MODNAME "DNPGetProtocolCaps"
  419. HRESULT
  420. DNPGetProtocolCaps(PProtocolData pPData, PDPN_CAPS pData)
  421. {
  422. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], pData[%p]", pPData, pData);
  423. ASSERT(pData->dwSize == sizeof(DPN_CAPS));
  424. ASSERT(pData->dwFlags == 0);
  425. pData->dwConnectTimeout = pPData->dwConnectTimeout;
  426. pData->dwConnectRetries = pPData->dwConnectRetries;
  427. pData->dwTimeoutUntilKeepAlive = pPData->tIdleThreshhold;
  428. return DPN_OK;
  429. }
  430. #undef DPF_MODNAME
  431. #define DPF_MODNAME "DNPSetProtocolCaps"
  432. HRESULT
  433. DNPSetProtocolCaps(PProtocolData pPData, const DPN_CAPS * const pData)
  434. {
  435. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], pData[%p]", pPData, pData);
  436. ASSERT(pData->dwSize == sizeof(DPN_CAPS));
  437. ASSERT(pData->dwFlags == 0);
  438. pPData->dwConnectTimeout = pData->dwConnectTimeout;
  439. pPData->dwConnectRetries = pData->dwConnectRetries;
  440. pPData->tIdleThreshhold = pData->dwTimeoutUntilKeepAlive;
  441. return DPN_OK;
  442. }
  443. /*
  444. ** Get Endpoint Caps
  445. **
  446. ** Return information and statistics about a particular endpoint.
  447. **
  448. */
  449. #undef DPF_MODNAME
  450. #define DPF_MODNAME "DNPGetEPCaps"
  451. HRESULT
  452. DNPGetEPCaps(HANDLE hEndpoint, PDPN_CONNECTION_INFO pBuffer)
  453. {
  454. PEPD pEPD;
  455. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hEndpoint[%x], pBuffer[%p]", hEndpoint, pBuffer);
  456. pEPD = (PEPD) hEndpoint;
  457. if(pEPD == NULL || !(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  458. {
  459. DPFX(DPFPREP,0, "Returning DPNERR_INVALIDENDPOINT - hEndpoint is NULL or Enpoint is not connected");
  460. return DPNERR_INVALIDENDPOINT;
  461. }
  462. if(pBuffer == NULL)
  463. {
  464. DPFX(DPFPREP,0, "Returning DPNERR_INVALIDPARAM - pBuffer is NULL");
  465. return DPNERR_INVALIDPARAM;
  466. }
  467. ASSERT_EPD(pEPD);
  468. ASSERT(pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO) ||
  469. pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO_INTERNAL));
  470. pBuffer->dwRoundTripLatencyMS = pEPD->uiRTT;
  471. pBuffer->dwThroughputBPS = pEPD->uiPeriodRateB * 4; // Convert to apx of bytes/second (really bytes/1024 ms)
  472. pBuffer->dwPeakThroughputBPS = pEPD->uiPeakRateB * 4;
  473. pBuffer->dwBytesSentGuaranteed = pEPD->uiGuaranteedBytesSent;
  474. pBuffer->dwPacketsSentGuaranteed = pEPD->uiGuaranteedFramesSent;
  475. pBuffer->dwBytesSentNonGuaranteed = pEPD->uiDatagramBytesSent;
  476. pBuffer->dwPacketsSentNonGuaranteed = pEPD->uiDatagramFramesSent;
  477. pBuffer->dwBytesRetried = pEPD->uiGuaranteedBytesDropped;
  478. pBuffer->dwPacketsRetried = pEPD->uiGuaranteedFramesDropped;
  479. pBuffer->dwBytesDropped = pEPD->uiDatagramBytesDropped;
  480. pBuffer->dwPacketsDropped = pEPD->uiDatagramFramesDropped;
  481. pBuffer->dwMessagesTransmittedHighPriority = pEPD->uiMsgSentHigh;
  482. pBuffer->dwMessagesTimedOutHighPriority = pEPD->uiMsgTOHigh;
  483. pBuffer->dwMessagesTransmittedNormalPriority = pEPD->uiMsgSentNorm;
  484. pBuffer->dwMessagesTimedOutNormalPriority = pEPD->uiMsgTONorm;
  485. pBuffer->dwMessagesTransmittedLowPriority = pEPD->uiMsgSentLow;
  486. pBuffer->dwMessagesTimedOutLowPriority = pEPD->uiMsgTOLow;
  487. pBuffer->dwBytesReceivedGuaranteed = pEPD->uiGuaranteedBytesReceived;
  488. pBuffer->dwPacketsReceivedGuaranteed = pEPD->uiGuaranteedFramesReceived;
  489. pBuffer->dwBytesReceivedNonGuaranteed = pEPD->uiDatagramBytesReceived;
  490. pBuffer->dwPacketsReceivedNonGuaranteed = pEPD->uiDatagramFramesReceived;
  491. pBuffer->dwMessagesReceived = pEPD->uiMessagesReceived;
  492. if (pBuffer->dwSize == sizeof(DPN_CONNECTION_INFO_INTERNAL))
  493. {
  494. DPFX(DPFPREP,DPF_CALLIN_LVL, "(%p) Test App requesting extended internal parameters", pEPD);
  495. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiDropCount = pEPD->uiDropCount;
  496. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiThrottleEvents = pEPD->uiThrottleEvents;
  497. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiAdaptAlgCount = pEPD->uiAdaptAlgCount;
  498. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowFilled = pEPD->uiWindowFilled;
  499. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiPeriodAcksBytes = pEPD->uiPeriodAcksBytes;
  500. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiPeriodXmitTime = pEPD->uiPeriodXmitTime;
  501. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->dwLastThroughputBPS = pEPD->uiLastRateB * 4;
  502. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiLastBytesAcked = pEPD->uiLastBytesAcked;
  503. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiQueuedMessageCount = pEPD->uiQueuedMessageCount;
  504. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowF = pEPD->uiWindowF;
  505. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiWindowB = pEPD->uiWindowB;
  506. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiUnackedFrames = pEPD->uiUnackedFrames;
  507. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiUnackedBytes = pEPD->uiUnackedBytes;
  508. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiBurstGap = pEPD->uiBurstGap;
  509. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->iBurstCredit = pEPD->iBurstCredit;
  510. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodWindowF = pEPD->uiGoodWindowF;
  511. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodWindowB = pEPD->uiGoodWindowBI * pEPD->pSPD->uiFrameLength;
  512. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodBurstGap = pEPD->uiGoodBurstGap;
  513. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiGoodRTT = pEPD->uiGoodRTT;
  514. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreWindowF = pEPD->uiRestoreWindowF;
  515. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreWindowB = pEPD->uiRestoreWindowBI * pEPD->pSPD->uiFrameLength;
  516. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRestoreBurstGap = pEPD->uiRestoreBurstGap;
  517. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->bNextSend = pEPD->bNextSend;
  518. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->bNextReceive = pEPD->bNextReceive;
  519. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulReceiveMask = pEPD->ulReceiveMask;
  520. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulReceiveMask2 = pEPD->ulReceiveMask2;
  521. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulSendMask = pEPD->ulSendMask;
  522. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulSendMask2 = pEPD->ulSendMask2;
  523. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiCompleteMsgCount = pEPD->uiCompleteMsgCount;
  524. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->uiRetryTimeout = pEPD->uiRetryTimeout;
  525. ((PDPN_CONNECTION_INFO_INTERNAL)pBuffer)->ulEPFlags = pEPD->ulEPFlags;
  526. }
  527. return DPN_OK;
  528. }
  529. /*
  530. ** Build Disconnect Frame
  531. **
  532. ** Build a DISC frame, a Message actually, because we return an MSD which can be inserted into
  533. ** our reliable stream and will trigger one-side of the disconnect protocol when it is received
  534. ** by a partner.
  535. */
  536. #undef DPF_MODNAME
  537. #define DPF_MODNAME "BuildDisconnectFrame"
  538. PMSD
  539. BuildDisconnectFrame(PEPD pEPD)
  540. {
  541. PFMD pFMD;
  542. PMSD pMSD;
  543. // Allocate and fill out a Message Descriptor for this operation
  544. if( (pMSD = static_cast<PMSD>( MSDPool->Get(MSDPool) )) == NULL)
  545. {
  546. DPFX(DPFPREP,0, "Failed to allocate MSD");
  547. return NULL;
  548. }
  549. pMSD->uiFrameCount = 1;
  550. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Initialize Frame count, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  551. pMSD->ulMsgFlags2 |= MFLAGS_TWO_END_OF_STREAM;
  552. pMSD->ulSendFlags = DN_SENDFLAGS_RELIABLE | DN_SENDFLAGS_LOW_PRIORITY; // Priority is LOW so all previously submitted traffic will be sent
  553. pMSD->pSPD = pEPD->pSPD;
  554. if((pFMD = static_cast<PFMD>( FMDPool->Get(FMDPool) )) == NULL)
  555. {
  556. DPFX(DPFPREP,0, "Failed to allocate FMD");
  557. Lock(&pMSD->CommandLock);
  558. RELEASE_MSD(pMSD, "Release On FMD Get Failed");
  559. return NULL;
  560. }
  561. pMSD->pEPD = pEPD;
  562. pFMD->CommandID = COMMAND_ID_SEND_RELIABLE;
  563. pFMD->ulFFlags |= FFLAGS_END_OF_STREAM; // Mark this frame as Disconnect
  564. pFMD->bPacketFlags = PACKET_COMMAND_DATA | PACKET_COMMAND_RELIABLE | PACKET_COMMAND_SEQUENTIAL | PACKET_COMMAND_END_MSG;
  565. pFMD->uiFrameLength = 0; // No user data in this frame
  566. pFMD->blMSDLinkage.InsertAfter( &pMSD->blFrameList); // Attach frame to MSD
  567. pFMD->pMSD = pMSD; // Link frame back to message
  568. pFMD->pEPD = pEPD;
  569. return pMSD;
  570. }
  571. /*
  572. ** Abort Sends on Connection
  573. **
  574. ** Walk the EPD's send queues and cancel all sends awaiting service. We might add
  575. ** code to issue Cancel commands to the SP for frames still owned by SP. On one hand,
  576. ** we are not expecting a big backlog to develop in SP, but on the other hand it still
  577. ** might happen. Esp, if we dont fix behavior I have observed with SP being really pokey
  578. ** about completing transmitted sends.
  579. **
  580. ** ** CALLED WITH EPD->EPLock HELD; RETURNS WITH LOCK RELEASED **
  581. */
  582. #undef DPF_MODNAME
  583. #define DPF_MODNAME "AbortSendsOnConnection"
  584. VOID
  585. AbortSendsOnConnection(PEPD pEPD)
  586. {
  587. PSPD pSPD = pEPD->pSPD;
  588. PFMD pFMD;
  589. PMSD pMSD;
  590. CBilink *pLink;
  591. CBilink TempList;
  592. ASSERT_SPD(pSPD);
  593. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  594. TempList.Initialize(); // We will empty all send queues onto this temporary list
  595. do
  596. {
  597. if( (pLink = pEPD->blHighPriSendQ.GetNext()) == &pEPD->blHighPriSendQ)
  598. {
  599. if( (pLink = pEPD->blNormPriSendQ.GetNext()) == &pEPD->blNormPriSendQ)
  600. {
  601. if( (pLink = pEPD->blLowPriSendQ.GetNext()) == &pEPD->blLowPriSendQ)
  602. {
  603. if( (pLink = pEPD->blCompleteSendList.GetNext()) == &pEPD->blCompleteSendList)
  604. {
  605. break; // ALL DONE - No more sends
  606. }
  607. }
  608. }
  609. }
  610. // We have found another send on one of our send queues.
  611. pLink->RemoveFromList(); // Remove it from the queue
  612. pMSD = CONTAINING_RECORD(pLink, MSD, blQLinkage);
  613. ASSERT_MSD(pMSD);
  614. pMSD->ulMsgFlags2 |= (MFLAGS_TWO_ABORT | MFLAGS_TWO_ABORT_WILL_COMPLETE); // Do no further processing
  615. #ifdef DEBUG
  616. pMSD->ulMsgFlags2 &= ~(MFLAGS_TWO_ENQUEUED);
  617. #endif
  618. // If this MSD is a Disconnect, it will be caught by the code below that checks
  619. // pEPD->pCommand. We don't want to end up putting it on the TempList twice.
  620. if (pMSD->CommandID != COMMAND_ID_DISCONNECT && pMSD->CommandID != COMMAND_ID_DISC_RESPONSE)
  621. {
  622. DPFX(DPFPREP,5, "(%p) ABORT SENDS. Found (%p)", pEPD, pMSD);
  623. LOCK_MSD(pMSD, "AbortSends Temp Ref");
  624. pMSD->blQLinkage.InsertBefore( &TempList); // Place on the temporary list
  625. }
  626. }
  627. while (1);
  628. pEPD->uiQueuedMessageCount = 0; // keep count of MSDs on all send queues
  629. if((pMSD = pEPD->pCommand) != NULL)
  630. {
  631. // There may be a DISCONNECT command waiting on this special pointer for the final DISC frame
  632. // from partner to arrive.
  633. pMSD->ulMsgFlags2 |= (MFLAGS_TWO_ABORT | MFLAGS_TWO_ABORT_WILL_COMPLETE); // Do no further processing
  634. if(pMSD->CommandID == COMMAND_ID_DISCONNECT || pMSD->CommandID == COMMAND_ID_DISC_RESPONSE)
  635. {
  636. pEPD->pCommand = NULL;
  637. LOCK_MSD(pMSD, "AbortSends Temp Ref");
  638. pMSD->blQLinkage.InsertBefore( &TempList);
  639. // We will be indicating below, so make sure no one else does once we
  640. // leave the EPLock.
  641. ASSERT(!(pEPD->ulEPFlags & EPFLAGS_INDICATED_DISCONNECT));
  642. pEPD->ulEPFlags |= EPFLAGS_INDICATED_DISCONNECT;
  643. }
  644. else
  645. {
  646. DPFX(DPFPREP,0,"(%p) Any Connect or Listen on pCommand should have already been cleaned up", pEPD);
  647. ASSERT(!"Any Connect or Listen on pCommand should have already been cleaned up");
  648. }
  649. }
  650. // If we clear out our SendWindow before we cancel the sends, then we dont need to differentiate
  651. // between sends that have or have not been transmitted.
  652. while(!pEPD->blSendWindow.IsEmpty())
  653. {
  654. pFMD = CONTAINING_RECORD(pEPD->blSendWindow.GetNext(), FMD, blWindowLinkage);
  655. ASSERT_FMD(pFMD);
  656. pFMD->ulFFlags &= ~(FFLAGS_IN_SEND_WINDOW);
  657. pFMD->blWindowLinkage.RemoveFromList(); // Eliminate each frame from the Send Window
  658. RELEASE_FMD(pFMD, "Send Window");
  659. DPFX(DPFPREP,5, "(%p) ABORT CONN: Release frame from Window: pFMD=0x%p", pEPD, pFMD);
  660. }
  661. pEPD->pCurrentSend = NULL;
  662. pEPD->pCurrentFrame = NULL;
  663. while(!pEPD->blRetryQueue.IsEmpty())
  664. {
  665. pFMD = CONTAINING_RECORD(pEPD->blRetryQueue.GetNext(), FMD, blQLinkage);
  666. ASSERT_FMD(pFMD);
  667. pFMD->blQLinkage.RemoveFromList();
  668. pFMD->ulFFlags &= ~(FFLAGS_RETRY_QUEUED); // No longer on the retry queue
  669. ASSERT_MSD(pFMD->pMSD);
  670. pFMD->pMSD->uiFrameCount--; // Protected by EPLock, retries count against outstanding frame count
  671. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Retry frame reference decremented on abort, pMSD[%p], framecount[%u]", pFMD->pMSD, pFMD->pMSD->uiFrameCount);
  672. DECREMENT_EPD(pEPD, "UNLOCK (Releasing Retry Frame)"); // SPLock not already held
  673. if (pFMD->CommandID == COMMAND_ID_COPIED_RETRY)
  674. {
  675. DECREMENT_EPD(pEPD, "UNLOCK (Copy Complete)"); // SPLock not already held
  676. }
  677. RELEASE_FMD(pFMD, "SP Submit");
  678. }
  679. pEPD->ulEPFlags &= ~(EPFLAGS_RETRIES_QUEUED);
  680. // Now that we have emptied the EPD's queues we will release the EPLock so we can lock each
  681. // MSD before we complete it.
  682. Unlock(&pEPD->EPLock);
  683. while(!TempList.IsEmpty())
  684. {
  685. pMSD = CONTAINING_RECORD(TempList.GetNext(), MSD, blQLinkage);
  686. ASSERT_MSD(pMSD);
  687. pMSD->blQLinkage.RemoveFromList(); // remove this send from temporary queue
  688. Lock(&pMSD->CommandLock); // Complete call will Unlock MSD
  689. ASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_IN_USE);
  690. switch(pMSD->CommandID)
  691. {
  692. case COMMAND_ID_SEND_RELIABLE:
  693. case COMMAND_ID_KEEPALIVE:
  694. {
  695. Lock(&pEPD->EPLock);
  696. pLink = pMSD->blFrameList.GetNext();
  697. while (pLink != &pMSD->blFrameList)
  698. {
  699. pFMD = CONTAINING_RECORD(pLink, FMD, blMSDLinkage);
  700. ASSERT_FMD(pFMD);
  701. // We don't allow a send to complete to the Core until uiFrameCount goes to zero indicating that all frames
  702. // of the message are out of the SP. We need to remove references from uiFrameCount for any frames that
  703. // never were transmitted. Frames and retries that were transmitted will have their references removed in
  704. // DNSP_CommandComplete when the SP completes them.
  705. if (!(pFMD->ulFFlags & FFLAGS_TRANSMITTED))
  706. {
  707. pMSD->uiFrameCount--; // Protected by EPLock
  708. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count decremented on abort for non-transmitted frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  709. }
  710. pLink = pLink->GetNext();
  711. }
  712. if (pMSD->uiFrameCount == 0) // Protected by EPLock
  713. {
  714. if (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT_WILL_COMPLETE)
  715. {
  716. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  717. DECREMENT_MSD(pMSD, "AbortSends Temp Ref");
  718. // See what error code we need to return
  719. if(pMSD->ulMsgFlags2 & MFLAGS_TWO_SEND_COMPLETE)
  720. {
  721. Unlock(&pEPD->EPLock);
  722. CompleteReliableSend(pSPD, pMSD, DPN_OK); // This releases the CommandLock
  723. }
  724. else
  725. {
  726. Unlock(&pEPD->EPLock);
  727. CompleteReliableSend(pSPD, pMSD, DPNERR_CONNECTIONLOST); // This releases the CommandLock
  728. }
  729. }
  730. else
  731. {
  732. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "SP Completion has already completed MSD to the Core, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  733. Unlock(&pEPD->EPLock);
  734. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  735. }
  736. }
  737. else
  738. {
  739. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frames still out, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  740. Unlock(&pEPD->EPLock);
  741. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  742. }
  743. }
  744. break;
  745. case COMMAND_ID_SEND_DATAGRAM:
  746. {
  747. Lock(&pEPD->EPLock);
  748. if (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT_WILL_COMPLETE)
  749. {
  750. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing NG, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  751. DECREMENT_MSD(pMSD, "AbortSends Temp Ref");
  752. Unlock(&pEPD->EPLock);
  753. AbortDatagramSend(pMSD, DPNERR_CONNECTIONLOST); // Releases CommandLock
  754. }
  755. else
  756. {
  757. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "SP Completion has already completed NG MSD to the Core, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  758. Unlock(&pEPD->EPLock);
  759. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  760. }
  761. }
  762. break;
  763. case COMMAND_ID_DISCONNECT:
  764. case COMMAND_ID_DISC_RESPONSE:
  765. {
  766. Lock(&pEPD->EPLock);
  767. pLink = pMSD->blFrameList.GetNext();
  768. while (pLink != &pMSD->blFrameList)
  769. {
  770. pFMD = CONTAINING_RECORD(pLink, FMD, blMSDLinkage);
  771. ASSERT_FMD(pFMD);
  772. // We don't allow a send to complete to the Core until uiFrameCount goes to zero indicating that all frames
  773. // of the message are out of the SP. We need to remove references from uiFrameCount for any frames that
  774. // never were transmitted. Frames and retries that were transmitted will have their references removed in
  775. // DNSP_CommandComplete when the SP completes them.
  776. if (!(pFMD->ulFFlags & FFLAGS_TRANSMITTED))
  777. {
  778. pMSD->uiFrameCount--; // Protected by EPLock
  779. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frame count decremented on abort for non-transmitted frame, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  780. }
  781. pLink = pLink->GetNext();
  782. }
  783. if (pMSD->uiFrameCount == 0)
  784. {
  785. if (pMSD->ulMsgFlags2 & MFLAGS_TWO_ABORT_WILL_COMPLETE)
  786. {
  787. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing disconnect, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  788. Unlock(&pEPD->EPLock);
  789. DECREMENT_MSD(pMSD, "AbortSends Temp Ref");
  790. CompleteDisconnect(pMSD, pSPD, pEPD); // Releases CommandLock
  791. }
  792. else
  793. {
  794. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "SP Completion has already completed MSD to the Core, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  795. Unlock(&pEPD->EPLock);
  796. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  797. }
  798. }
  799. else
  800. {
  801. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frames still out, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  802. Unlock(&pEPD->EPLock);
  803. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  804. }
  805. }
  806. break;
  807. default:
  808. {
  809. DPFX(DPFPREP,0, "UNKNOWN COMMAND FOUND ON SEND Q");
  810. ASSERT(0);
  811. RELEASE_MSD(pMSD, "AbortSends Temp Ref"); // Releases CommandLock
  812. }
  813. break;
  814. }
  815. }
  816. }
  817. /*
  818. ** Abort Datagram Send
  819. **
  820. **
  821. ** THIS IS ENTERED WITH MSD->COMMANDLOCK HELD, EXITS WITH IT RELEASED
  822. */
  823. #undef DPF_MODNAME
  824. #define DPF_MODNAME "AbortDatagramSend"
  825. VOID
  826. AbortDatagramSend(PMSD pMSD, HRESULT CompletionCode)
  827. {
  828. PFMD pFMD;
  829. CBilink *pLink;
  830. AssertCriticalSectionIsTakenByThisThread(&pMSD->CommandLock, TRUE);
  831. if(pMSD->TimeoutTimer != NULL)
  832. {
  833. DPFX(DPFPREP,7, "Cancelling Timeout Timer");
  834. if(CancelMyTimer(pMSD->TimeoutTimer, pMSD->TimeoutTimerUnique) == DPN_OK)
  835. {
  836. DECREMENT_MSD(pMSD, "Timeout Timer");
  837. }
  838. else
  839. {
  840. DPFX(DPFPREP,7, "Cancelling Timeout Timer Failed");
  841. }
  842. pMSD->TimeoutTimer = NULL;
  843. }
  844. pLink = pMSD->blFrameList.GetNext();
  845. while(pLink != &pMSD->blFrameList)
  846. {
  847. pFMD = CONTAINING_RECORD(pLink, FMD, blMSDLinkage);
  848. ASSERT_FMD(pFMD);
  849. pLink = pLink->GetNext();
  850. if((pFMD->ulFFlags & FFLAGS_TRANSMITTED)==0)
  851. {
  852. pFMD->blMSDLinkage.RemoveFromList();
  853. RELEASE_FMD(pFMD, "MSD Frame List");
  854. pMSD->uiFrameCount--;
  855. }
  856. }
  857. if(pMSD->blFrameList.IsEmpty())
  858. {
  859. CompleteDatagramSend(pMSD->pSPD, pMSD, CompletionCode);
  860. }
  861. else
  862. {
  863. Unlock(&pMSD->CommandLock);
  864. }
  865. }
  866. #undef DPF_MODNAME
  867. #define DPF_MODNAME "SetLinkParms"
  868. VOID SetLinkParms(PEPD pEPD, PINT Data)
  869. {
  870. if(Data[0])
  871. {
  872. pEPD->uiGoodWindowF = pEPD->uiWindowF = Data[0];
  873. pEPD->uiGoodWindowBI = pEPD->uiWindowBIndex = Data[0];
  874. pEPD->uiWindowB = pEPD->uiWindowBIndex * pEPD->pSPD->uiFrameLength;
  875. DPFX(DPFPREP,7, "** ADJUSTING WINDOW TO %d FRAMES", Data[0]);
  876. }
  877. if(Data[1])
  878. {
  879. }
  880. if(Data[2])
  881. {
  882. pEPD->uiGoodBurstGap = pEPD->uiBurstGap = Data[2];
  883. DPFX(DPFPREP,7, "** ADJUSTING GAP TO %d ms", Data[2]);
  884. }
  885. pEPD->uiPeriodAcksBytes = 0;
  886. pEPD->uiPeriodXmitTime = 0;
  887. }
  888. #undef DPF_MODNAME
  889. #define DPF_MODNAME "DNP_Debug"
  890. HRESULT WINAPI DNP_Debug(PProtocolData pPData, UINT OpCode, HANDLE EndPoint, PVOID Data)
  891. {
  892. PEPD pEPD = (PEPD) EndPoint;
  893. switch(OpCode)
  894. {
  895. case 1:
  896. /* Toggle link frozen state */
  897. pEPD->ulEPFlags ^= EPFLAGS_LINK_FROZEN;
  898. break;
  899. case 2:
  900. /* Toggle whether KeepAlives are on or off */
  901. pEPD->ulEPFlags ^= EPFLAGS_KEEPALIVE_RUNNING;
  902. break;
  903. case 5:
  904. /* Manually set link parameters */
  905. SetLinkParms(pEPD, (int *) Data);
  906. break;
  907. case 6:
  908. /* Toggle Dynamic/Static Link control */
  909. pEPD->ulEPFlags ^= EPFLAGS_LINK_STABLE;
  910. break;
  911. default:
  912. return DPNERR_GENERIC;
  913. }
  914. return DPN_OK;
  915. }