|
|
/****************************************************************************/ // aupint.cpp
//
// RDP Update Packager internal functions.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "aupint"
#include <as_conf.hpp>
#include <nprcount.h>
/****************************************************************************/ // UPSendOrders
//
// Packages orders to send to the client. Returns TRUE if all orders for
// this call (all available orders for non-shadow, one buffer for shadow)
// were sent.
//
// Packing algorithm details:
//
// Each network buffer (allocated in SC) is size sc8KOutBufUsableSpace
// (8K minus some header space). Within that space we try to pack to
// multiples of the 1460-byte TCP payload. For slow link connections we aim
// for 1460 * 1 (SMALL_SLOWLINK_PAYLOAD_SIZE) as the final size to send,
// for LAN, 1460 * 3 (LARGE_SLOWLINK_PAYLOAD_SIZE).
//
// Order packing takes into account the current MPPC compression estimate
// for slow links. We divide the target size by the compression ratio to get
// the predicted size of data that, when compressed, will fit into the
// target size. This size is throttled by the sc8KOutBufUsableSpace
// size so we don't overrun the network buffer.
/****************************************************************************/ NTSTATUS RDPCALL SHCLASS UPSendOrders(PPDU_PACKAGE_INFO pPkgInfo) { BYTE *pOrderBuffer; unsigned NumOrders; unsigned cbOrderBytes; unsigned cbOrderBytesRemaining; unsigned cbPacketSize; int RealSpaceAvail, ScaledSpaceAvail; unsigned SmallPackingSize = m_pShm->sch.SmallPackingSize; unsigned LargePackingSize = m_pShm->sch.LargePackingSize; unsigned MPPCCompEst = m_pShm->sch.MPPCCompressionEst; unsigned ScaledSmallPackingSize; unsigned ScaledLargePackingSize; unsigned CurrentScaledLargePackingSize; unsigned BufLen; BOOL bSmallPackingSizeTarget; #ifdef DC_HICOLOR
BOOL bTriedVeryLargeBuffer = FALSE; #endif
NTSTATUS status = STATUS_SUCCESS;
DC_BEGIN_FN("UPSendOrders");
// Find out how many bytes of orders there are in the Order List.
cbOrderBytesRemaining = OA_GetTotalOrderListBytes();
// Process any orders on the list.
if (cbOrderBytesRemaining > 0) { TRC_DBG((TB, "%u order bytes to fetch", cbOrderBytesRemaining));
BufLen = pPkgInfo->cbLen;
// Handling for the first buffer is different from any later ones.
// We want at least a few bytes beyond the update-orders PDU
// header for some orders. If we are at the end of a packing buffer
// for the first packing size, use the second packing size. If
// we are at the end of the second packing size, we need to flush.
if (pPkgInfo->cbInUse < SmallPackingSize) { // Check that we actually have a buffer allocated.
if (BufLen) { RealSpaceAvail = SmallPackingSize - pPkgInfo->cbInUse; if (RealSpaceAvail >= (int)(upUpdateHdrSize + SCH_MIN_ORDER_BUFFER_SPACE)) { bSmallPackingSizeTarget = TRUE; } else { bSmallPackingSizeTarget = FALSE; RealSpaceAvail = LargePackingSize - pPkgInfo->cbInUse; } pOrderBuffer = (BYTE *)pPkgInfo->pBuffer + pPkgInfo->cbInUse + upUpdateHdrSize; } else { goto ForceFlush; } } else { // Note RealSpaceAvail is an int to easily handle where cbInUse >
// LargePackingSize.
RealSpaceAvail = (int)LargePackingSize - (int)pPkgInfo->cbInUse; if (RealSpaceAvail >= (int)(upUpdateHdrSize + SCH_MIN_ORDER_BUFFER_SPACE)) { bSmallPackingSizeTarget = FALSE; pOrderBuffer = (BYTE *)pPkgInfo->pBuffer + pPkgInfo->cbInUse + upUpdateHdrSize; } else { ForceFlush: status = SC_FlushAndAllocPackage(pPkgInfo);
if ( STATUS_SUCCESS == status ) { // If we are not shadowing (or are shadowing but had
// a null buffer in the package), then we can continue.
// Otherwise, we've sent our one buffer allowed this
// round.
if (m_pTSWd->shadowState == SHADOW_NONE || BufLen == 0) { TRC_ASSERT((pPkgInfo->cbLen >= LargePackingSize), (TB,"Assumed default package alloc size too " "small")); RealSpaceAvail = (int)SmallPackingSize; bSmallPackingSizeTarget = TRUE; pOrderBuffer = (BYTE *)pPkgInfo->pBuffer + upUpdateHdrSize; } else { DC_QUIT; } } else { // Failed to allocate a packet. We skip out immediately
// and try again later.
TRC_NRM((TB, "Failed to alloc order packet")); INC_INCOUNTER(IN_SND_NO_BUFFER); DC_QUIT; } } }
// Calculate the scaled packing sizes, which are the sizes of buffer
// available after the update order PDU header.
if (m_pTSWd->bCompress) { // Whatever size we're packing for, we need to divide by the MPPC
// compression estimate to get the size we really want to pack
// so that, after compression, we achieve the size we would like
// to get. Note we add in a 7/8 fudge factor to increase the
// chance we will pack within the target buffer and closer to
// a full packet size. Also tried 3/4, 4/5, and 15/16 as factors
// but they yielded more frames. The scaled size is throttled at
// the full size of the buffer.
ScaledSpaceAvail = (int)(((unsigned)RealSpaceAvail - upUpdateHdrSize) * SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8); ScaledSpaceAvail = min(ScaledSpaceAvail, (int)(pPkgInfo->cbLen - pPkgInfo->cbInUse - upUpdateHdrSize));
// Calculate the large packing size target for the first buffer,
// based on the space currently available. This value will be
// used below for if we need to retry the order copy after
// failure to transfer any orders to a small buffer size.
// It is throttled at the buffer maximum size.
TRC_ASSERT(((int)pPkgInfo->cbInUse < LargePackingSize), (TB,"At least LargePackingSize in use and we've not " "flushed - cbInUse=%u, LargePackingSize=%u", pPkgInfo->cbInUse, LargePackingSize)); TRC_ASSERT((MPPCCompEst <= SCH_UNCOMP_BYTES), (TB,"MPPC compression ratio > 1.0!")); CurrentScaledLargePackingSize = (LargePackingSize - pPkgInfo->cbInUse - upUpdateHdrSize) * SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8; CurrentScaledLargePackingSize = min(CurrentScaledLargePackingSize, (pPkgInfo->cbLen - pPkgInfo->cbInUse - upUpdateHdrSize));
// Precalculate the large and small sizes for the second and later
// buffers (where pPkgInfo->cbInUse is reset to 0).
// Throttle the small size to reduce slow-link burstiness.
ScaledSmallPackingSize = (SmallPackingSize - upUpdateHdrSize) * SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8; ScaledSmallPackingSize = min(ScaledSmallPackingSize, (sc8KOutBufUsableSpace - upUpdateHdrSize)); ScaledSmallPackingSize = (unsigned int)min(ScaledSmallPackingSize, (2 * SMALL_SLOWLINK_PAYLOAD_SIZE)); ScaledLargePackingSize = (LargePackingSize - upUpdateHdrSize) * SCH_UNCOMP_BYTES / MPPCCompEst * 7 / 8; ScaledLargePackingSize = min(ScaledLargePackingSize, (sc8KOutBufUsableSpace - upUpdateHdrSize)); } else { ScaledSpaceAvail = RealSpaceAvail - upUpdateHdrSize;
// Calculate initial large packing size for the first buffer.
CurrentScaledLargePackingSize = LargePackingSize - pPkgInfo->cbInUse - upUpdateHdrSize;
// For uncompressed, packing sizes need no scaling.
ScaledSmallPackingSize = SmallPackingSize - upUpdateHdrSize; ScaledLargePackingSize = LargePackingSize - upUpdateHdrSize; }
// Keep sending packets while there are some orders to do.
while (cbOrderBytesRemaining > 0) { // Loop in case we need to use multiple packing sizes.
for (;;) { // The encoded orders must not exceed the packing buffer
// bounds.
TRC_ASSERT(((pPkgInfo->cbInUse + (unsigned)ScaledSpaceAvail + upUpdateHdrSize) <= pPkgInfo->cbLen), (TB,"Target ScaledSpaceAvail %d exceeds the " "encoding buffer - cbInUse=%u, cbLen=%u, " "upHdrSize=%u", ScaledSpaceAvail, pPkgInfo->cbInUse, pPkgInfo->cbLen, upUpdateHdrSize));
// Transfer as many orders into the packet as will fit.
cbOrderBytes = (unsigned)ScaledSpaceAvail; cbOrderBytesRemaining = UPFetchOrdersIntoBuffer( pOrderBuffer, &NumOrders, &cbOrderBytes);
TRC_DBG((TB, "%u bytes fetched into %d byte payload. %u " "remain", cbOrderBytes, ScaledSpaceAvail - upUpdateHdrSize, cbOrderBytesRemaining));
if (cbOrderBytes > 0) { // If we had any orders transferred, fill out the header
// and record the added bytes in the package.
if (scUseFastPathOutput) { *(pOrderBuffer - upUpdateHdrSize) = TS_UPDATETYPE_ORDERS | scCompressionUsedValue; *((PUINT16_UA)(pOrderBuffer - 2)) = (UINT16)NumOrders; } else { TS_UPDATE_ORDERS_PDU UNALIGNED *pUpdateOrdersPDU;
pUpdateOrdersPDU = (TS_UPDATE_ORDERS_PDU UNALIGNED *) (pOrderBuffer - upUpdateHdrSize); pUpdateOrdersPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_UPDATE; pUpdateOrdersPDU->data.updateType = TS_UPDATETYPE_ORDERS; pUpdateOrdersPDU->data.numberOrders = (UINT16)NumOrders; }
// Add the data we have and allow MPPC compression to
// take place.
TRC_DBG((TB, "Send orders pkt. size(%d)", cbOrderBytes)); SC_AddToPackage(pPkgInfo, (cbOrderBytes + upUpdateHdrSize), TRUE);
#ifdef DC_HICOLOR
// Having sent some data, we can again resort to the
// Very Large Buffer later if we need to
bTriedVeryLargeBuffer = FALSE; #endif
// No need to try a larger size.
break; } else if (bSmallPackingSizeTarget) { // Not having any orders transferred is not an error
// condition if we are working with a buffer target
// smaller than LargePackingSize -- there may
// have been a large order (most likely a cache-bitmap
// secondary order) that would not fit in the space we
// had in the buffer. Try again with a larger size.
ScaledSpaceAvail = CurrentScaledLargePackingSize; bSmallPackingSizeTarget = FALSE; continue; } else if (pPkgInfo->cbInUse) { // This was the first packet and we may not have had
// enough space for a really large order. Need to force
// the packet to flush. Jump out of the loop.
break; } #ifdef DC_HICOLOR
else if (!bTriedVeryLargeBuffer) { // Last ditch - try the very biggest package we're
// allowed to send.
TRC_NRM((TB, "Failed to send order in 8k - try 16k (%d)", sc16KOutBufUsableSpace));
if (SC_GetSpaceInPackage(pPkgInfo, sc16KOutBufUsableSpace)) { pOrderBuffer = (BYTE *)pPkgInfo->pBuffer + upUpdateHdrSize; ScaledSpaceAvail = sc16KOutBufUsableSpace - upUpdateHdrSize; bTriedVeryLargeBuffer = TRUE; } else { // Failed to allocate a packet. Skip out immediately
// and try again later.
TRC_NRM((TB, "Failed to alloc order packet")); INC_INCOUNTER(IN_SND_NO_BUFFER); status = STATUS_NO_MEMORY; DC_QUIT; } } #endif
else { // We're totally out of luck here. See comments immediately
// above. Return FALSE to simulate a failed allocation.
TRC_ASSERT((!bSmallPackingSizeTarget && pPkgInfo->cbInUse > 0), (TB,"We failed to add an order even with largest " "buffer size")); status = STATUS_UNSUCCESSFUL; // what's the right error code here
DC_QUIT; } }
// Force flush only if we have more orders to encode. Otherwise,
// we might be able to fit in more info into the package.
if (cbOrderBytesRemaining > 0) { // Flush the packet.
status = SC_FlushAndAllocPackage(pPkgInfo); if ( STATUS_SUCCESS == status ) { // If we were unable to transfer during the last order
// flush, use the large size in this new package.
if (cbOrderBytes) { bSmallPackingSizeTarget = TRUE; ScaledSpaceAvail = ScaledSmallPackingSize; } else { bSmallPackingSizeTarget = FALSE; ScaledSpaceAvail = ScaledLargePackingSize; }
// No longer the first packet, we can push out to the full
// large packing size for packet retries.
CurrentScaledLargePackingSize = ScaledLargePackingSize;
pOrderBuffer = (BYTE *)pPkgInfo->pBuffer + upUpdateHdrSize; } else { // Failed to allocate a packet. We skip out immediately
// and try again later.
TRC_NRM((TB, "Failed to alloc order packet")); INC_INCOUNTER(IN_SND_NO_BUFFER); DC_QUIT; } }
// If we are not shadowing, then send as many buffers as necessary
if (m_pTSWd->shadowState == SHADOW_NONE) continue;
// Else return back to the DD if we are in a shadow to force sending
// one buffer at a time.
else if (cbOrderBytesRemaining != 0) { break; } } }
TRC_DBG((TB, "%d bytes of orders left", cbOrderBytesRemaining)); if (cbOrderBytesRemaining == 0) { TRC_DBG((TB, "No orders left, reset the start of the heap")); OA_ResetOrderList(); } else if (m_pTSWd->shadowState == SHADOW_NONE) { TRC_ALT((TB, "Shouldn't get here: heap should be empty!"));
// shouldn't we assert here?
status = STATUS_UNSUCCESSFUL; }
DC_EXIT_POINT: DC_END_FN(); return status; }
/****************************************************************************/ // UPFetchOrdersIntoBuffer
//
// Copies as many orders as will fit from the order heap into the given packet
// space, freeing the order heap space for each order copied. Returns the
// number of orders copied and the number of bytes of order heap data
// remaining.
/****************************************************************************/ unsigned RDPCALL SHCLASS UPFetchOrdersIntoBuffer( PBYTE pBuffer, unsigned *pcOrders, PUINT pcbBufferSize) { PINT_ORDER pOrder; unsigned FreeBytesInBuffer; unsigned OrdersCopied;
DC_BEGIN_FN("UPFetchOrdersIntoBuffer");
// Initialize the buffer pointer and size.
FreeBytesInBuffer = *pcbBufferSize;
// Keep a count of the number of orders we copy.
OrdersCopied = 0;
// Return as many orders as possible.
pOrder = OA_GetFirstListOrder(); TRC_DBG((TB, "First order: %p", pOrder));
while (pOrder != NULL) {
#if DC_DEBUG
unsigned sum = 0; unsigned i;
// Check the order checksum integrity
for (i = 0; i < pOrder->OrderLength; i++) { sum += pOrder->OrderData[i]; } if (pOrder->CheckSum != sum) { TRC_ASSERT((FALSE), (TB, "order heap corruption: %p\n", pOrder)); } #endif
// All orders are placed in the heap pre-encoded for the wire.
// We need simply copy the resulting orders into the target buffer.
if (pOrder->OrderLength <= FreeBytesInBuffer) { TRC_DBG((TB,"Copying heap order at hdr addr %p, len %u", pOrder, pOrder->OrderLength));
memcpy(pBuffer, pOrder->OrderData, pOrder->OrderLength);
// Update the buffer pointer past the encoded order and get the
// next order.
pBuffer += pOrder->OrderLength; FreeBytesInBuffer -= pOrder->OrderLength; OrdersCopied++; pOrder = OA_RemoveListOrder(pOrder); } else { // The order was too big to fit in this buffer.
// Exit the loop - this order will go in the next packet.
break; } }
// Fill in the packet header.
*pcOrders = OrdersCopied;
// Update the buffer size to indicate how much data we have written.
*pcbBufferSize -= FreeBytesInBuffer;
TRC_DBG((TB, "Returned %d orders in %d bytes", OrdersCopied, *pcbBufferSize));
DC_END_FN(); return OA_GetTotalOrderListBytes(); }
/****************************************************************************/ /* Name: UPEnumSoundCaps */ /* */ /* Purpose: Enumeration function for sound capabilities */ /* */ /* Params: locPersonID - persion ID of supplied caps */ /* pCapabilities - caps */ /****************************************************************************/ void CALLBACK SHCLASS UPEnumSoundCaps( LOCALPERSONID locPersonID, UINT_PTR UserData, PTS_CAPABILITYHEADER pCapabilities) { PTS_SOUND_CAPABILITYSET pSoundCaps = (PTS_SOUND_CAPABILITYSET)pCapabilities;
DC_BEGIN_FN("UPEnumSoundCaps");
DC_IGNORE_PARAMETER(UserData);
TRC_ASSERT((pSoundCaps->capabilitySetType == TS_CAPSETTYPE_SOUND), (TB,"Caps type not sound"));
// We don't want to take our own sound caps into account - we are the
// server so we don't advertise support for sound PDUs.
if (SC_LOCAL_PERSON_ID != locPersonID) { // If there are no caps or the beep flag isn't set, disable beeps.
if (pSoundCaps->lengthCapability == 0 || !(pSoundCaps->soundFlags & TS_SOUND_FLAG_BEEPS)) upCanSendBeep = FALSE; }
DC_END_FN(); } /* UPEnumSoundCaps */
|