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.
 
 
 
 
 
 

958 lines
31 KiB

#include "precomp.h"
//
// UP.CPP
// Update Packager
//
// Copyright(c) Microsoft 1997-
//
#define MLZ_FILE_ZONE ZONE_NET
//
// UP_FlowControl()
// Checks if we've switched between slow and fast throughput
//
void ASHost::UP_FlowControl(UINT newBufferSize)
{
DebugEntry(ASHost::UP_FlowControl);
if (newBufferSize > (LARGE_ORDER_PACKET_SIZE / 2))
{
if (m_upfUseSmallPackets)
{
m_upfUseSmallPackets = FALSE;
TRACE_OUT(("UP_FlowControl: FAST; use large packets"));
}
}
else
{
if (!m_upfUseSmallPackets)
{
m_upfUseSmallPackets = TRUE;
TRACE_OUT(("UP_FlowControl: SLOW; use small packets"));
}
}
DebugExitVOID(ASHost::UP_FlowControl);
}
//
// UP_Periodic()
//
// Called periodically, to send graphical updates as orders and/or screen
// data.
//
void ASHost::UP_Periodic(UINT currentTime)
{
BOOL fSendSD = FALSE;
BOOL fSendOrders = FALSE;
UINT tmpTime;
UINT timeSinceOrders;
UINT timeSinceSD;
UINT timeSinceTrying;
DebugEntry(ASHost::UP_Periodic);
//
// This is a
// performance critical part of the scheduling so we apply some
// heuristics to try and keep the overheads down.
//
// 1.If there was no back pressure last time then we check the
// rate of accumulation of screendata over the last period.
// If it was high then we apply a time slice to the sending
// of screendata.
//
// 2.If the rate of order accumulation was also high then we
// apply a timeslice to the order accumulation as well, just
// to avoid too high a CPU overhead trying to send orders
// when we will eventually fail to keep up. We keep this
// time period low because the objective is simply to avoid
// sending hundreds of packets containing few orders each.
// (On the other hand, we want to send the single textout
// following a keystoke ASAP so we must not timeslice all the
// time.)
//
// 3.If neither orders nor screendata is piling up quickly then
// we do a full send immediately.
//
// 4.If there was back pressure on the last send then we still
// send orders, but always on the time slice, independent of
// the order accumulation rate.
//
// Note that we cannot sample the accumulation rates for every
// pass because the app doing the drawing may be interrupted by
// us for a few hundred milliseconds. Therefore we only sample
// the bounds every VOLUME_SAMPLE milliseconds.
//
//
timeSinceSD = currentTime - m_upLastSDTime;
timeSinceOrders = currentTime - m_upLastOrdersTime;
timeSinceTrying = currentTime - m_upLastTrialTime;
//
// Sample the accumulation rates.
//
m_upSDAccum += BA_QueryAccumulation();
m_upOrdersAccum += OA_QueryOrderAccum();
//
// Sample the throughput over the last period to see whether we
// can operate in rapid respose mode or whether we should
// timeslice.
//
if (timeSinceTrying > DCS_VOLUME_SAMPLE)
{
//
// Take the newly accumulated deltas.
//
m_upDeltaSD = m_upSDAccum;
m_upDeltaOrders = m_upOrdersAccum;
//
// Store time of last retrieval.
//
m_upLastTrialTime = currentTime;
//
// Reset the running totals.
//
m_upSDAccum = 0;
m_upOrdersAccum = 0;
}
//
// If we are way out of line then send updates. Not that this
// will reset the update timer independent of whether the send
// works or not, so that we don't enter this arm continually
// when we time out but are in a back pressure situation
//
// The long stop timer is there to catch apps that keep a
// continual flow of orders/SD at above the suppression rate.
// We want to tune our heuristics to avoid this, but if it
// happens than we must send the data eventually. The problem
// is that this objective clashes with the scenario of the user
// paging down twenty times, where our most efficient approach
// is to let him run and snapshot the SD at the end, rather
// than every PERIOD_LONG milliseconds. (A screen snapshot
// will stop the host for a second!).
//
if (timeSinceSD > DCS_SD_UPDATE_LONG_PERIOD)
{
fSendSD = TRUE;
}
else
{
//
// We only disregard our time slicing if the rate of orders
// and screendata is low enough to warrant it. If the rate
// is too high then hold off so that we can do some packet
// consolidation. If we had no back pressure last time or
// the screendata rate is now low enough then try sending
// SD as well as orders.
//
// The order threshold is measured in number of orders over
// the period. Screendata is measured in the total area
// accumulated (prior to any spoiling).
//
if (!m_upBackPressure)
{
if (m_upDeltaOrders < DCS_ORDERS_TURNOFF_FREQUENCY)
{
fSendOrders = TRUE;
if (m_upDeltaSD < DCS_BOUNDS_TURNOFF_RATE)
{
if ((timeSinceSD < DCS_SD_UPDATE_SHORT_PERIOD) &&
(m_upDeltaSD > DCS_BOUNDS_IMMEDIATE_RATE))
{
fSendSD = FALSE;
}
else
{
fSendSD = TRUE;
}
}
}
}
//
// Even in a back pressure situation we try and send orders
// periodically to keep current. If we overflow the order
// buffer then we will constrain the buffer size to prevent
// sending too many non-productive orders. (But we dont
// turn orders off because we still want the user to see
// things happening.) Generally we send orders immediately,
// provided the rate of accumulation is within the limits.
// This test is to time slice orders if they are being
// generated at a high rate. The constant must be
// reasonably small otherwise we force the order buffer to
// overflow and order processing will be turned off.
//
if (!fSendSD && !fSendOrders)
{
if (timeSinceOrders > DCS_ORDER_UPDATE_PERIOD)
{
fSendOrders = TRUE;
}
}
}
//
// Now we can go ahead and try sending! First look to see if
// we can do both screendata and orders
//
if (fSendSD)
{
//
// Indicate no back pressure (even if this send is
// triggered by a timout our initial assumption is no back
// pressure). Back pressure will be reinstated by
// SendUpdates if necessary.
//
m_upBackPressure = FALSE;
UPSendUpdates();
//
// Sending screendata can take a long time. It messes up
// our heuristics unless we adjust for it.
//
tmpTime = GetTickCount();
timeSinceTrying -= (tmpTime - currentTime);
m_pShare->m_dcsLastScheduleTime = tmpTime;
m_upLastSDTime = tmpTime;
m_upLastOrdersTime = tmpTime;
}
else
{
if (fSendOrders)
{
//
// Either the update rate is too high or we are
// experiencing back pressure so just send the orders
// and not the screendata. This is because we want to
// avoid entering screendata mode as a result of order
// back pressure for as long as we can. The screendata
// will come later, when things have settled down a bit
//
m_upLastOrdersTime = currentTime;
m_upBackPressure = TRUE;
if (!UPSendUpdates())
{
//
// This is the only real action so leave all the
// tracing separate for cleanliness. If there are
// orders in transit then everything is fine. If none
// are sent for a while then we want to break out of
// our SD back pressure wait. This is because we are
// only sampling the flow rates every DCS_VOLUME_SAMPLE msecs,
// but we dont want to have to wait that long to flush the SD.
// We cannot increase the flow sample rate because then
// it becomes too erratic because of system scheduling.
//
m_upBackPressure = FALSE;
UPSendUpdates();
m_upLastSDTime = currentTime;
}
}
}
DebugExitVOID(ASHost::UP_Periodic);
}
//
// UPSendUpdates()
// Actually tries to allocate and send orders + screen data. What it does
// depends on
// * Presence of back-pressure due to previous send failures
// * How much screen data & orders there are
// * Whether we're in serious spoiling mode and can't keep up
// * What packet size to send
//
// Returns:
// # of packets sent
//
UINT ASHost::UPSendUpdates(void)
{
BOOL synced;
BOOL ordersSent;
UINT numPackets = 0;
DebugEntry(ASHost::UPSendUpdates);
//
// If we actually have updates to send then try to send a sync token.
//
if ((OA_GetTotalOrderListBytes() > 0) ||
(m_sdgcLossy != 0) ||
(m_baNumRects > 0))
{
synced = UP_MaybeSendSyncToken();
//
// Only send updates if we have sent the sync token succesfully.
//
if (synced)
{
//
// There is no outstanding sync token waiting to be sent, so we
// can send the orders and screen data updates.
//
//
// Send accumulated orders. If this call fails (probably out
// of memory) then don't send any other updates - we'll try
// sending the whole lot later. The orders MUST be sent before
// the screen data.
//
if (PM_MaybeSendPalettePacket())
{
ordersSent = UPSendOrders(&numPackets);
if (!ordersSent)
{
m_upBackPressure = TRUE;
}
else
{
//
// Orders sent OK so go for the screendata, provided
// the caller wants us to.
//
if (!m_upBackPressure)
{
//
// We may now try and send screen data. However,
// we need to be careful not to do this too
// frequently, because DC-Share is now being
// scheduled to send as soon as network buffers
// become available. On the other hand, some
// apps respond to keystrokes with screendata so
// we cannot just slow it down!
//
// The approach is to have SendScreenDataArea
// return the amount of data sent, together with
// an indication as to whether we hit back pressure
//
// We return these to dcsapi which has control of
// when we are scheduled and passes the paramaters
// in again
//
//
TRACE_OUT(( "Sending SD"));
SDG_SendScreenDataArea(&m_upBackPressure, &numPackets);
}
else
{
//
// We sent the orders OK an so we must reset
// the back pressure indicator even though we
// were asked not to send screendata
//
TRACE_OUT(( "Orders sent and BP relieved"));
m_upBackPressure = FALSE;
}
}
}
}
}
else
{
m_upBackPressure = FALSE;
}
DebugExitDWORD(ASHost::UPSendUpdates, numPackets);
return(numPackets);
}
//
// UP_MaybeSendSyncToken()
//
BOOL ASHost::UP_MaybeSendSyncToken(void)
{
PUPSPACKET pUPSPacket;
#ifdef _DEBUG
UINT sentSize;
#endif // _DEBUG
DebugEntry(ASHost::UP_MaybeSendSyncToken);
//
// Check to see if we should send a sync token.
//
if (m_upfSyncTokenRequired)
{
//
// The sync packet consists of an updates packets as far as the end
// of the header.
//
pUPSPacket = (PUPSPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES,
g_s20BroadcastID, sizeof(UPSPACKET));
if (!pUPSPacket)
{
//
// We will try again later.
//
TRACE_OUT(("Failed to alloc UP sync packet"));
}
else
{
//
// Fill in the packet contents.
//
pUPSPacket->header.header.data.dataType = DT_UP;
pUPSPacket->header.updateType = UPD_SYNC;
//
// Now send the packet to the remote application.
//
if (m_pShare->m_scfViewSelf)
m_pShare->UP_ReceivedPacket(m_pShare->m_pasLocal,
&(pUPSPacket->header.header));
#ifdef _DEBUG
sentSize =
#endif // _DEBUG
m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES,
g_s20BroadcastID, &(pUPSPacket->header.header),
sizeof(*pUPSPacket));
TRACE_OUT(("UP SYNC packet size: %08d, sent %08d",
sizeof(*pUPSPacket), sentSize));
//
// The sync packet was successfully sent.
//
m_upfSyncTokenRequired = FALSE;
}
}
DebugExitBOOL(ASHost::UP_MaybeSendSyncToken, (!m_upfSyncTokenRequired));
return(!m_upfSyncTokenRequired);
}
//
// UPSendOrders(..)
//
// Sends all accumulated orders.
//
// Returns:
// TRUE if all orders successfully sent
// FALSE if send failed (e.g. if unable to allocate network packet)
//
//
BOOL ASHost::UPSendOrders(UINT * pcPackets)
{
PORDPACKET pPacket = NULL;
UINT cbOrderBytes;
UINT cbOrderBytesRemaining;
UINT cbPacketSize;
BOOL rc = TRUE;
#ifdef _DEBUG
UINT sentSize;
#endif // _DEBUG
DebugEntry(ASHost::UPSendOrders);
//
// Find out how many bytes of orders there are in the Order List.
//
cbOrderBytesRemaining = UPFetchOrdersIntoBuffer(NULL, NULL, NULL);
//
// Process any orders on the list.
//
if (cbOrderBytesRemaining > 0)
{
TRACE_OUT(( "%u order bytes to fetch", cbOrderBytesRemaining));
//
// Keep sending packets while there are some orders to do.
//
while (cbOrderBytesRemaining > 0)
{
UINT cbMax;
//
// Make sure the order size does not exceed the max packet
// size.
//
cbMax = (m_upfUseSmallPackets) ? SMALL_ORDER_PACKET_SIZE :
LARGE_ORDER_PACKET_SIZE;
cbPacketSize = min(cbOrderBytesRemaining,
(cbMax - sizeof(ORDPACKET) + 1));
//
// Allocate a packet to send the data in.
//
pPacket = (PORDPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES, g_s20BroadcastID,
sizeof(ORDPACKET) + cbPacketSize - 1);
if (!pPacket)
{
//
// Failed to allocate a packet. We skip out immediately -
// we'll try again later.
//
TRACE_OUT(("Failed to alloc UP order packet, size %u",
sizeof(ORDPACKET) + cbPacketSize - 1));
rc = FALSE;
DC_QUIT;
}
//
// Transfer as many orders into the packet as will fit.
//
cbOrderBytes = cbPacketSize;
cbOrderBytesRemaining = UPFetchOrdersIntoBuffer(
pPacket->data, &pPacket->cOrders, &cbOrderBytes);
TRACE_OUT(( "%u bytes fetched into %u byte pkt. %u remain.",
cbOrderBytes, cbPacketSize, cbOrderBytesRemaining));
//
// If no order bytes were transferred then try again with a
// Large Order Packet.
//
if (cbOrderBytes == 0)
{
//
// We need to use a larger packet to transfer the
// orders into. (The first order must be a very large
// order such as a large bitmap cache update).
//
S20_FreeDataPkt(&(pPacket->header.header));
//
// cbOrderBytesRemaining may not accurate if there are
// any MemBlt orders in the order heap. This is
// because we may have to insert a color table order
// and / or a bitmap bits order before the MemBlt.
//
// To avoid getting into an infinite loop if there is
// only a MemBlt remaining but we actually have to send
// a color table and / or a bitmap bits order
// (cbOrderBytesRemaining would never get set high
// enough to allow us to send the color table / bitmap
// bits order), make the buffer at least large enough
// to hold the largest amount of data required for all
// the parts of a MemBlt.
//
//
// The maximum number of bytes required to send a MemBlt order. This is
// The size of the largest possible color table order
// + the size of the largest possible bitmap bits order
// + the size of the largest MemBlt order.
//
cbPacketSize = sizeof(BMC_COLOR_TABLE_ORDER) +
(256 * sizeof(TSHR_RGBQUAD)) +
sizeof(BMC_BITMAP_BITS_ORDER_R2) +
sizeof(MEM3BLT_R2_ORDER) +
MP_CACHE_CELLSIZE(MP_LARGE_TILE_WIDTH, MP_LARGE_TILE_HEIGHT,
m_usrSendingBPP);
cbPacketSize = max(cbPacketSize, cbOrderBytesRemaining);
if (cbPacketSize > (UINT)(LARGE_ORDER_PACKET_SIZE -
sizeof(ORDPACKET) + 1))
{
TRACE_OUT(("Too many order bytes for large packet(%d)",
cbOrderBytesRemaining));
cbPacketSize = LARGE_ORDER_PACKET_SIZE -
sizeof(ORDPACKET) + 1;
}
pPacket = (PORDPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES,
g_s20BroadcastID, sizeof(ORDPACKET) + cbPacketSize - 1);
if (!pPacket)
{
TRACE_OUT(("Failed to alloc UP order packet, size %u",
sizeof(ORDPACKET) + cbPacketSize - 1));
rc = FALSE;
DC_QUIT;
}
//
// Transfer as many orders into the packet as will
// fit.
//
cbOrderBytes = cbPacketSize;
cbOrderBytesRemaining = UPFetchOrdersIntoBuffer(
pPacket->data, &pPacket->cOrders, &cbOrderBytes );
//
// If no orders were transferred then something has
// gone wrong. Probably flow control kicked in or
// a dekstop switch occurred.
// Return failure now!
// Hopefully things will sort themselves out later
// or we will resort to sending updates as screen
// data once the order accumulation heap becomes
// full.
//
if (cbOrderBytes == 0)
{
WARNING_OUT(("No orders fetched into %u byte packet, %u bytes left",
cbPacketSize, cbOrderBytesRemaining));
S20_FreeDataPkt(&(pPacket->header.header));
rc = FALSE;
DC_QUIT;
}
}
//
// Fill in the packet header.
//
pPacket->header.header.data.dataType = DT_UP;
pPacket->header.updateType = UPD_ORDERS;
pPacket->sendBPP = (TSHR_UINT16)m_usrSendingBPP;
//
// If encoding is switched on, update the data size to reflect
// it with encoded orders
//
if (m_pShare->m_oefOE2EncodingOn)
{
pPacket->header.header.dataLength = sizeof(ORDPACKET) + cbOrderBytes - 1
- sizeof(S20DATAPACKET) + sizeof(DATAPACKETHEADER);
}
//
// Now send it.
//
if (m_pShare->m_scfViewSelf)
m_pShare->UP_ReceivedPacket(m_pShare->m_pasLocal,
&(pPacket->header.header));
#ifdef _DEBUG
sentSize =
#endif // _DEBUG
m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES, g_s20BroadcastID,
&(pPacket->header.header), sizeof(ORDPACKET) + cbOrderBytes - 1);
TRACE_OUT(("UP ORDERS packet size: %08d, sent %08d",
sizeof(ORDPACKET) + cbOrderBytes - 1, sentSize));
++(*pcPackets);
}
}
DC_EXIT_POINT:
DebugExitBOOL(ASHost::UPSendOrders, rc);
return(rc);
}
//
//
// UPFetchOrdersIntoBuffer(..)
//
// Encodes orders from the Order List and copies them into the supplied
// buffer, then frees up the memory of each order copied.
//
// Orders are copied until the buffer is full or there are no more orders.
//
// Returns:
// The number of order bytes that were NOT returned.
// i.e. 0 if all orders were returned.
// A simple way to find out the total number of order bytes
// in the Order List is to call the function with a buffer length
// of zero.
//
// *pcbBufferSize is updated to contain the total number of bytes
// returned.
//
//
UINT ASHost::UPFetchOrdersIntoBuffer
(
LPBYTE pBuffer,
LPTSHR_UINT16 pcOrders,
LPUINT pcbBufferSize
)
{
LPINT_ORDER pListOrder;
LPINT_ORDER pCurrentOrder;
UINT cbFreeBytesInBuffer;
UINT cOrdersCopied;
LPBYTE pDst;
UINT cbOrderSize;
UINT ulRemainingOrderBytes;
BOOL processingMemBlt;
DebugEntry(ASHost::UPFetchOrdersIntoBuffer);
//
// Make a quick exit if the Order List length is being queried.
//
if ( (pcbBufferSize == NULL) ||
(*pcbBufferSize == 0) )
{
goto fetch_orders_exit;
}
//
// Initialize the buffer pointer and size.
//
pDst = pBuffer;
cbFreeBytesInBuffer = *pcbBufferSize;
//
// Keep a count of the number of orders we copy.
//
cOrdersCopied = 0;
//
// Return as many orders as possible.
//
pListOrder = OA_GetFirstListOrder();
TRACE_OUT(( "First order: 0x%08x", pListOrder));
while (pListOrder != NULL)
{
if (pListOrder->OrderHeader.Common.fOrderFlags & OF_INTERNAL)
{
//
// This is an internal order. Currently SBC is the only
// component to use internal orders, so get SBC to process it.
//
SBC_ProcessInternalOrder(pListOrder);
//
// Internal order must not get sent over the wire, so skip on
// to the next order
//
pListOrder = OA_RemoveListOrder(pListOrder);
continue;
}
if (ORDER_IS_MEMBLT(pListOrder) || ORDER_IS_MEM3BLT(pListOrder))
{
//
// This is a MEMBLT or a MEM3BLT so we have to do some extra
// processing... This function returns us a pointer to the
// next order which should be sent - this will often not be the
// MEMBLT, but a color table order or a bitmap bits order.
//
if (!SBC_ProcessMemBltOrder(pListOrder, &pCurrentOrder))
{
//
// This can fail if
// * we're low on memory
// * we changed from 8BPP to 24BPP sending, because
// somebody left the share, and we have queued up
// SBC orders that we can no longer process.
//
TRACE_OUT(("Failed to process SBC order, fall back to SDG"));
pListOrder = OA_RemoveListOrder(pListOrder);
continue;
}
processingMemBlt = TRUE;
}
else
{
//
// This isn't a MEMBLT or a MEM3BLT - just set pCurrentOrder to
// be pListOrder
//
pCurrentOrder = pListOrder;
processingMemBlt = FALSE;
}
if (m_pShare->m_oefOE2EncodingOn)
{
//
// Encoding is switched on.
// Encode the order into the next free space in the buffer
//
cbOrderSize = OE2_EncodeOrder( pCurrentOrder,
pDst,
(TSHR_UINT16)cbFreeBytesInBuffer );
TRACE_OUT(( "Encoded size, %u bytes", cbOrderSize));
}
else
{
//
// Copy the order into the buffer.
//
cbOrderSize = COM_ORDER_SIZE(
((LPCOM_ORDER)(&(pCurrentOrder->OrderHeader.Common))));
if (cbOrderSize <= cbFreeBytesInBuffer)
{
memcpy(pDst,
(LPCOM_ORDER)(&(pCurrentOrder->OrderHeader.Common)),
cbOrderSize);
}
else
{
//
// No room for this order in this packet.
//
cbOrderSize = 0;
}
}
//
// Check whether the order was copied into the buffer.
//
if (cbOrderSize == 0)
{
//
// The order was too big to fit in this buffer.
// Exit the loop - this order will go in the next packet.
//
break;
}
//
// Update the buffer pointer past the encoded order.
//
pDst += cbOrderSize;
cbFreeBytesInBuffer -= cbOrderSize;
cOrdersCopied++;
if (processingMemBlt)
{
//
// If we are processing a MEMBLT order, we have to notify SBC
// that we've dealt with it successfully so that it returns us
// a different order next time.
//
SBC_OrderSentNotification(pCurrentOrder);
}
if (pCurrentOrder == pListOrder)
{
//
// We successfully copied the order into the buffer - on to the
// next one UNLESS we haven't processed the last one we picked
// out of the order list i.e. pCurrentOrder is not the same as
// pListOrder. This will happen if we just processed a color
// table order or a bitmap bits order returned from
// SBC_ProcessMemBltOrder (if we processed the MEMBLT itself,
// we can safely move on to the next order).
//
pListOrder = OA_RemoveListOrder(pListOrder);
}
}
//
// Fill in the packet header.
//
if (pcOrders != NULL)
{
*pcOrders = (TSHR_UINT16)cOrdersCopied;
}
//
// Update the buffer size to indicate how much data we have
// written.
//
*pcbBufferSize -= cbFreeBytesInBuffer;
TRACE_OUT(( "Returned %d orders in %d bytes",
cOrdersCopied,
*pcbBufferSize));
fetch_orders_exit:
//
// Return the number of bytes still to be processed
//
ulRemainingOrderBytes = OA_GetTotalOrderListBytes();
DebugExitDWORD(ASHost::UPFetchOrdersIntoBuffer, ulRemainingOrderBytes);
return(ulRemainingOrderBytes);
}
//
// UP_ReceivePacket()
//
void ASShare::UP_ReceivedPacket
(
ASPerson * pasPerson,
PS20DATAPACKET pPacket
)
{
PUPPACKETHEADER pUPPacket;
DebugEntry(ASShare::UP_ReceivedPacket);
ValidatePerson(pasPerson);
if (!pasPerson->m_pView)
{
//
// Updates for parties which we don't recognise as hosts are just
// discarded.
//
// NOTE:
// 2.0 Win95 does not have HET, where we kick off sharing/unsharing.
// But it did have TT, and the packet type/messages were defined
// cleverly for HET so that 2.0 Win95 works the same. When they
// start to share, we get a PT_TT packet with a non-zero count.
// The difference really is that the number is apps for Win95 2.0
// and HWNDs for everybody else.
//
WARNING_OUT(("UP_ReceivedUpdates: Ignoring updates from person [%d] not hosting",
pasPerson->mcsID));
DC_QUIT;
}
pUPPacket = (PUPPACKETHEADER)pPacket;
switch (pUPPacket->updateType)
{
case UPD_SCREEN_DATA:
SDP_ReceivedPacket(pasPerson, pPacket);
break;
case UPD_ORDERS:
OD_ReceivedPacket(pasPerson, pPacket);
break;
case UPD_PALETTE:
PM_ReceivedPacket(pasPerson, pPacket);
break;
case UPD_SYNC:
//
// We need to reset our INCOMING decoding info since the sender
// resets his OUTGOING encoding info for a sync.
//
OD2_SyncIncoming(pasPerson);
//
// NOTE:
// We do not need to reset INCOMING data for
// PM -- the host won't send us old palette references
// RBC -- the host won't send us old bitmap references.
// Even though it would be nice to delete the existing
// bitmaps, recreating the cache is a hassle.
// CM -- the host won't send us old cursor references
// SSI -- the host won't send us old savebits references
//
break;
default:
ERROR_OUT(("Unknown UP packet type %u from [%d]",
pUPPacket->updateType,
pasPerson->mcsID));
break;
}
DC_EXIT_POINT:
DebugExitVOID(ASShare::UP_ReceivedPacket);
}