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.

489 lines
21 KiB

  1. /****************************************************************************/
  2. // aupint.cpp
  3. //
  4. // RDP Update Packager internal functions.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #define TRC_FILE "aupint"
  11. #include <as_conf.hpp>
  12. #include <nprcount.h>
  13. /****************************************************************************/
  14. // UPSendOrders
  15. //
  16. // Packages orders to send to the client. Returns TRUE if all orders for
  17. // this call (all available orders for non-shadow, one buffer for shadow)
  18. // were sent.
  19. //
  20. // Packing algorithm details:
  21. //
  22. // Each network buffer (allocated in SC) is size sc8KOutBufUsableSpace
  23. // (8K minus some header space). Within that space we try to pack to
  24. // multiples of the 1460-byte TCP payload. For slow link connections we aim
  25. // for 1460 * 1 (SMALL_SLOWLINK_PAYLOAD_SIZE) as the final size to send,
  26. // for LAN, 1460 * 3 (LARGE_SLOWLINK_PAYLOAD_SIZE).
  27. //
  28. // Order packing takes into account the current MPPC compression estimate
  29. // for slow links. We divide the target size by the compression ratio to get
  30. // the predicted size of data that, when compressed, will fit into the
  31. // target size. This size is throttled by the sc8KOutBufUsableSpace
  32. // size so we don't overrun the network buffer.
  33. /****************************************************************************/
  34. NTSTATUS RDPCALL SHCLASS UPSendOrders(PPDU_PACKAGE_INFO pPkgInfo)
  35. {
  36. BYTE *pOrderBuffer;
  37. unsigned NumOrders;
  38. unsigned cbOrderBytes;
  39. unsigned cbOrderBytesRemaining;
  40. unsigned cbPacketSize;
  41. int RealSpaceAvail, ScaledSpaceAvail;
  42. unsigned SmallPackingSize = m_pShm->sch.SmallPackingSize;
  43. unsigned LargePackingSize = m_pShm->sch.LargePackingSize;
  44. unsigned MPPCCompEst = m_pShm->sch.MPPCCompressionEst;
  45. unsigned ScaledSmallPackingSize;
  46. unsigned ScaledLargePackingSize;
  47. unsigned CurrentScaledLargePackingSize;
  48. unsigned BufLen;
  49. BOOL bSmallPackingSizeTarget;
  50. #ifdef DC_HICOLOR
  51. BOOL bTriedVeryLargeBuffer = FALSE;
  52. #endif
  53. NTSTATUS status = STATUS_SUCCESS;
  54. DC_BEGIN_FN("UPSendOrders");
  55. // Find out how many bytes of orders there are in the Order List.
  56. cbOrderBytesRemaining = OA_GetTotalOrderListBytes();
  57. // Process any orders on the list.
  58. if (cbOrderBytesRemaining > 0) {
  59. TRC_DBG((TB, "%u order bytes to fetch", cbOrderBytesRemaining));
  60. BufLen = pPkgInfo->cbLen;
  61. // Handling for the first buffer is different from any later ones.
  62. // We want at least a few bytes beyond the update-orders PDU
  63. // header for some orders. If we are at the end of a packing buffer
  64. // for the first packing size, use the second packing size. If
  65. // we are at the end of the second packing size, we need to flush.
  66. if (pPkgInfo->cbInUse < SmallPackingSize) {
  67. // Check that we actually have a buffer allocated.
  68. if (BufLen) {
  69. RealSpaceAvail = SmallPackingSize - pPkgInfo->cbInUse;
  70. if (RealSpaceAvail >=
  71. (int)(upUpdateHdrSize + SCH_MIN_ORDER_BUFFER_SPACE)) {
  72. bSmallPackingSizeTarget = TRUE;
  73. }
  74. else {
  75. bSmallPackingSizeTarget = FALSE;
  76. RealSpaceAvail = LargePackingSize - pPkgInfo->cbInUse;
  77. }
  78. pOrderBuffer = (BYTE *)pPkgInfo->pBuffer +
  79. pPkgInfo->cbInUse + upUpdateHdrSize;
  80. }
  81. else {
  82. goto ForceFlush;
  83. }
  84. }
  85. else {
  86. // Note RealSpaceAvail is an int to easily handle where cbInUse >
  87. // LargePackingSize.
  88. RealSpaceAvail = (int)LargePackingSize - (int)pPkgInfo->cbInUse;
  89. if (RealSpaceAvail >=
  90. (int)(upUpdateHdrSize + SCH_MIN_ORDER_BUFFER_SPACE)) {
  91. bSmallPackingSizeTarget = FALSE;
  92. pOrderBuffer = (BYTE *)pPkgInfo->pBuffer +
  93. pPkgInfo->cbInUse + upUpdateHdrSize;
  94. }
  95. else {
  96. ForceFlush:
  97. status = SC_FlushAndAllocPackage(pPkgInfo);
  98. if ( STATUS_SUCCESS == status ) {
  99. // If we are not shadowing (or are shadowing but had
  100. // a null buffer in the package), then we can continue.
  101. // Otherwise, we've sent our one buffer allowed this
  102. // round.
  103. if (m_pTSWd->shadowState == SHADOW_NONE || BufLen == 0) {
  104. TRC_ASSERT((pPkgInfo->cbLen >= LargePackingSize),
  105. (TB,"Assumed default package alloc size too "
  106. "small"));
  107. RealSpaceAvail = (int)SmallPackingSize;
  108. bSmallPackingSizeTarget = TRUE;
  109. pOrderBuffer = (BYTE *)pPkgInfo->pBuffer +
  110. upUpdateHdrSize;
  111. }
  112. else {
  113. DC_QUIT;
  114. }
  115. }
  116. else {
  117. // Failed to allocate a packet. We skip out immediately
  118. // and try again later.
  119. TRC_NRM((TB, "Failed to alloc order packet"));
  120. INC_INCOUNTER(IN_SND_NO_BUFFER);
  121. DC_QUIT;
  122. }
  123. }
  124. }
  125. // Calculate the scaled packing sizes, which are the sizes of buffer
  126. // available after the update order PDU header.
  127. if (m_pTSWd->bCompress) {
  128. // Whatever size we're packing for, we need to divide by the MPPC
  129. // compression estimate to get the size we really want to pack
  130. // so that, after compression, we achieve the size we would like
  131. // to get. Note we add in a 7/8 fudge factor to increase the
  132. // chance we will pack within the target buffer and closer to
  133. // a full packet size. Also tried 3/4, 4/5, and 15/16 as factors
  134. // but they yielded more frames. The scaled size is throttled at
  135. // the full size of the buffer.
  136. ScaledSpaceAvail = (int)(((unsigned)RealSpaceAvail -
  137. upUpdateHdrSize) * SCH_UNCOMP_BYTES / MPPCCompEst *
  138. 7 / 8);
  139. ScaledSpaceAvail = min(ScaledSpaceAvail, (int)(pPkgInfo->cbLen -
  140. pPkgInfo->cbInUse - upUpdateHdrSize));
  141. // Calculate the large packing size target for the first buffer,
  142. // based on the space currently available. This value will be
  143. // used below for if we need to retry the order copy after
  144. // failure to transfer any orders to a small buffer size.
  145. // It is throttled at the buffer maximum size.
  146. TRC_ASSERT(((int)pPkgInfo->cbInUse < LargePackingSize),
  147. (TB,"At least LargePackingSize in use and we've not "
  148. "flushed - cbInUse=%u, LargePackingSize=%u",
  149. pPkgInfo->cbInUse, LargePackingSize));
  150. TRC_ASSERT((MPPCCompEst <= SCH_UNCOMP_BYTES),
  151. (TB,"MPPC compression ratio > 1.0!"));
  152. CurrentScaledLargePackingSize = (LargePackingSize -
  153. pPkgInfo->cbInUse - upUpdateHdrSize) * SCH_UNCOMP_BYTES /
  154. MPPCCompEst * 7 / 8;
  155. CurrentScaledLargePackingSize = min(CurrentScaledLargePackingSize,
  156. (pPkgInfo->cbLen - pPkgInfo->cbInUse - upUpdateHdrSize));
  157. // Precalculate the large and small sizes for the second and later
  158. // buffers (where pPkgInfo->cbInUse is reset to 0).
  159. // Throttle the small size to reduce slow-link burstiness.
  160. ScaledSmallPackingSize = (SmallPackingSize - upUpdateHdrSize) *
  161. SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8;
  162. ScaledSmallPackingSize = min(ScaledSmallPackingSize,
  163. (sc8KOutBufUsableSpace - upUpdateHdrSize));
  164. ScaledSmallPackingSize = (unsigned int)min(ScaledSmallPackingSize,
  165. (2 * SMALL_SLOWLINK_PAYLOAD_SIZE));
  166. ScaledLargePackingSize = (LargePackingSize - upUpdateHdrSize) *
  167. SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8;
  168. ScaledLargePackingSize = min(ScaledLargePackingSize,
  169. (sc8KOutBufUsableSpace - upUpdateHdrSize));
  170. }
  171. else {
  172. ScaledSpaceAvail = RealSpaceAvail - upUpdateHdrSize;
  173. // Calculate initial large packing size for the first buffer.
  174. CurrentScaledLargePackingSize = LargePackingSize -
  175. pPkgInfo->cbInUse - upUpdateHdrSize;
  176. // For uncompressed, packing sizes need no scaling.
  177. ScaledSmallPackingSize = SmallPackingSize - upUpdateHdrSize;
  178. ScaledLargePackingSize = LargePackingSize - upUpdateHdrSize;
  179. }
  180. // Keep sending packets while there are some orders to do.
  181. while (cbOrderBytesRemaining > 0) {
  182. // Loop in case we need to use multiple packing sizes.
  183. for (;;) {
  184. // The encoded orders must not exceed the packing buffer
  185. // bounds.
  186. TRC_ASSERT(((pPkgInfo->cbInUse + (unsigned)ScaledSpaceAvail +
  187. upUpdateHdrSize) <= pPkgInfo->cbLen),
  188. (TB,"Target ScaledSpaceAvail %d exceeds the "
  189. "encoding buffer - cbInUse=%u, cbLen=%u, "
  190. "upHdrSize=%u",
  191. ScaledSpaceAvail, pPkgInfo->cbInUse,
  192. pPkgInfo->cbLen, upUpdateHdrSize));
  193. // Transfer as many orders into the packet as will fit.
  194. cbOrderBytes = (unsigned)ScaledSpaceAvail;
  195. cbOrderBytesRemaining = UPFetchOrdersIntoBuffer(
  196. pOrderBuffer, &NumOrders, &cbOrderBytes);
  197. TRC_DBG((TB, "%u bytes fetched into %d byte payload. %u "
  198. "remain", cbOrderBytes, ScaledSpaceAvail -
  199. upUpdateHdrSize, cbOrderBytesRemaining));
  200. if (cbOrderBytes > 0) {
  201. // If we had any orders transferred, fill out the header
  202. // and record the added bytes in the package.
  203. if (scUseFastPathOutput) {
  204. *(pOrderBuffer - upUpdateHdrSize) =
  205. TS_UPDATETYPE_ORDERS |
  206. scCompressionUsedValue;
  207. *((PUINT16_UA)(pOrderBuffer - 2)) =
  208. (UINT16)NumOrders;
  209. }
  210. else {
  211. TS_UPDATE_ORDERS_PDU UNALIGNED *pUpdateOrdersPDU;
  212. pUpdateOrdersPDU = (TS_UPDATE_ORDERS_PDU UNALIGNED *)
  213. (pOrderBuffer - upUpdateHdrSize);
  214. pUpdateOrdersPDU->shareDataHeader.pduType2 =
  215. TS_PDUTYPE2_UPDATE;
  216. pUpdateOrdersPDU->data.updateType =
  217. TS_UPDATETYPE_ORDERS;
  218. pUpdateOrdersPDU->data.numberOrders =
  219. (UINT16)NumOrders;
  220. }
  221. // Add the data we have and allow MPPC compression to
  222. // take place.
  223. TRC_DBG((TB, "Send orders pkt. size(%d)", cbOrderBytes));
  224. SC_AddToPackage(pPkgInfo, (cbOrderBytes + upUpdateHdrSize),
  225. TRUE);
  226. #ifdef DC_HICOLOR
  227. // Having sent some data, we can again resort to the
  228. // Very Large Buffer later if we need to
  229. bTriedVeryLargeBuffer = FALSE;
  230. #endif
  231. // No need to try a larger size.
  232. break;
  233. }
  234. else if (bSmallPackingSizeTarget) {
  235. // Not having any orders transferred is not an error
  236. // condition if we are working with a buffer target
  237. // smaller than LargePackingSize -- there may
  238. // have been a large order (most likely a cache-bitmap
  239. // secondary order) that would not fit in the space we
  240. // had in the buffer. Try again with a larger size.
  241. ScaledSpaceAvail = CurrentScaledLargePackingSize;
  242. bSmallPackingSizeTarget = FALSE;
  243. continue;
  244. }
  245. else if (pPkgInfo->cbInUse) {
  246. // This was the first packet and we may not have had
  247. // enough space for a really large order. Need to force
  248. // the packet to flush. Jump out of the loop.
  249. break;
  250. }
  251. #ifdef DC_HICOLOR
  252. else if (!bTriedVeryLargeBuffer) {
  253. // Last ditch - try the very biggest package we're
  254. // allowed to send.
  255. TRC_NRM((TB, "Failed to send order in 8k - try 16k (%d)",
  256. sc16KOutBufUsableSpace));
  257. if (SC_GetSpaceInPackage(pPkgInfo,
  258. sc16KOutBufUsableSpace)) {
  259. pOrderBuffer = (BYTE *)pPkgInfo->pBuffer +
  260. upUpdateHdrSize;
  261. ScaledSpaceAvail = sc16KOutBufUsableSpace -
  262. upUpdateHdrSize;
  263. bTriedVeryLargeBuffer = TRUE;
  264. }
  265. else {
  266. // Failed to allocate a packet. Skip out immediately
  267. // and try again later.
  268. TRC_NRM((TB, "Failed to alloc order packet"));
  269. INC_INCOUNTER(IN_SND_NO_BUFFER);
  270. status = STATUS_NO_MEMORY;
  271. DC_QUIT;
  272. }
  273. }
  274. #endif
  275. else {
  276. // We're totally out of luck here. See comments immediately
  277. // above. Return FALSE to simulate a failed allocation.
  278. TRC_ASSERT((!bSmallPackingSizeTarget &&
  279. pPkgInfo->cbInUse > 0),
  280. (TB,"We failed to add an order even with largest "
  281. "buffer size"));
  282. status = STATUS_UNSUCCESSFUL; // what's the right error code here
  283. DC_QUIT;
  284. }
  285. }
  286. // Force flush only if we have more orders to encode. Otherwise,
  287. // we might be able to fit in more info into the package.
  288. if (cbOrderBytesRemaining > 0) {
  289. // Flush the packet.
  290. status = SC_FlushAndAllocPackage(pPkgInfo);
  291. if ( STATUS_SUCCESS == status ) {
  292. // If we were unable to transfer during the last order
  293. // flush, use the large size in this new package.
  294. if (cbOrderBytes) {
  295. bSmallPackingSizeTarget = TRUE;
  296. ScaledSpaceAvail = ScaledSmallPackingSize;
  297. }
  298. else {
  299. bSmallPackingSizeTarget = FALSE;
  300. ScaledSpaceAvail = ScaledLargePackingSize;
  301. }
  302. // No longer the first packet, we can push out to the full
  303. // large packing size for packet retries.
  304. CurrentScaledLargePackingSize = ScaledLargePackingSize;
  305. pOrderBuffer = (BYTE *)pPkgInfo->pBuffer +
  306. upUpdateHdrSize;
  307. }
  308. else {
  309. // Failed to allocate a packet. We skip out immediately
  310. // and try again later.
  311. TRC_NRM((TB, "Failed to alloc order packet"));
  312. INC_INCOUNTER(IN_SND_NO_BUFFER);
  313. DC_QUIT;
  314. }
  315. }
  316. // If we are not shadowing, then send as many buffers as necessary
  317. if (m_pTSWd->shadowState == SHADOW_NONE)
  318. continue;
  319. // Else return back to the DD if we are in a shadow to force sending
  320. // one buffer at a time.
  321. else if (cbOrderBytesRemaining != 0) {
  322. break;
  323. }
  324. }
  325. }
  326. TRC_DBG((TB, "%d bytes of orders left", cbOrderBytesRemaining));
  327. if (cbOrderBytesRemaining == 0) {
  328. TRC_DBG((TB, "No orders left, reset the start of the heap"));
  329. OA_ResetOrderList();
  330. }
  331. else if (m_pTSWd->shadowState == SHADOW_NONE) {
  332. TRC_ALT((TB, "Shouldn't get here: heap should be empty!"));
  333. // shouldn't we assert here?
  334. status = STATUS_UNSUCCESSFUL;
  335. }
  336. DC_EXIT_POINT:
  337. DC_END_FN();
  338. return status;
  339. }
  340. /****************************************************************************/
  341. // UPFetchOrdersIntoBuffer
  342. //
  343. // Copies as many orders as will fit from the order heap into the given packet
  344. // space, freeing the order heap space for each order copied. Returns the
  345. // number of orders copied and the number of bytes of order heap data
  346. // remaining.
  347. /****************************************************************************/
  348. unsigned RDPCALL SHCLASS UPFetchOrdersIntoBuffer(
  349. PBYTE pBuffer,
  350. unsigned *pcOrders,
  351. PUINT pcbBufferSize)
  352. {
  353. PINT_ORDER pOrder;
  354. unsigned FreeBytesInBuffer;
  355. unsigned OrdersCopied;
  356. DC_BEGIN_FN("UPFetchOrdersIntoBuffer");
  357. // Initialize the buffer pointer and size.
  358. FreeBytesInBuffer = *pcbBufferSize;
  359. // Keep a count of the number of orders we copy.
  360. OrdersCopied = 0;
  361. // Return as many orders as possible.
  362. pOrder = OA_GetFirstListOrder();
  363. TRC_DBG((TB, "First order: %p", pOrder));
  364. while (pOrder != NULL) {
  365. #if DC_DEBUG
  366. unsigned sum = 0;
  367. unsigned i;
  368. // Check the order checksum integrity
  369. for (i = 0; i < pOrder->OrderLength; i++) {
  370. sum += pOrder->OrderData[i];
  371. }
  372. if (pOrder->CheckSum != sum) {
  373. TRC_ASSERT((FALSE), (TB, "order heap corruption: %p\n", pOrder));
  374. }
  375. #endif
  376. // All orders are placed in the heap pre-encoded for the wire.
  377. // We need simply copy the resulting orders into the target buffer.
  378. if (pOrder->OrderLength <= FreeBytesInBuffer) {
  379. TRC_DBG((TB,"Copying heap order at hdr addr %p, len %u",
  380. pOrder, pOrder->OrderLength));
  381. memcpy(pBuffer, pOrder->OrderData, pOrder->OrderLength);
  382. // Update the buffer pointer past the encoded order and get the
  383. // next order.
  384. pBuffer += pOrder->OrderLength;
  385. FreeBytesInBuffer -= pOrder->OrderLength;
  386. OrdersCopied++;
  387. pOrder = OA_RemoveListOrder(pOrder);
  388. }
  389. else {
  390. // The order was too big to fit in this buffer.
  391. // Exit the loop - this order will go in the next packet.
  392. break;
  393. }
  394. }
  395. // Fill in the packet header.
  396. *pcOrders = OrdersCopied;
  397. // Update the buffer size to indicate how much data we have written.
  398. *pcbBufferSize -= FreeBytesInBuffer;
  399. TRC_DBG((TB, "Returned %d orders in %d bytes", OrdersCopied,
  400. *pcbBufferSize));
  401. DC_END_FN();
  402. return OA_GetTotalOrderListBytes();
  403. }
  404. /****************************************************************************/
  405. /* Name: UPEnumSoundCaps */
  406. /* */
  407. /* Purpose: Enumeration function for sound capabilities */
  408. /* */
  409. /* Params: locPersonID - persion ID of supplied caps */
  410. /* pCapabilities - caps */
  411. /****************************************************************************/
  412. void CALLBACK SHCLASS UPEnumSoundCaps(
  413. LOCALPERSONID locPersonID,
  414. UINT_PTR UserData,
  415. PTS_CAPABILITYHEADER pCapabilities)
  416. {
  417. PTS_SOUND_CAPABILITYSET pSoundCaps =
  418. (PTS_SOUND_CAPABILITYSET)pCapabilities;
  419. DC_BEGIN_FN("UPEnumSoundCaps");
  420. DC_IGNORE_PARAMETER(UserData);
  421. TRC_ASSERT((pSoundCaps->capabilitySetType == TS_CAPSETTYPE_SOUND),
  422. (TB,"Caps type not sound"));
  423. // We don't want to take our own sound caps into account - we are the
  424. // server so we don't advertise support for sound PDUs.
  425. if (SC_LOCAL_PERSON_ID != locPersonID) {
  426. // If there are no caps or the beep flag isn't set, disable beeps.
  427. if (pSoundCaps->lengthCapability == 0 ||
  428. !(pSoundCaps->soundFlags & TS_SOUND_FLAG_BEEPS))
  429. upCanSendBeep = FALSE;
  430. }
  431. DC_END_FN();
  432. } /* UPEnumSoundCaps */