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.
 
 
 
 
 
 

2996 lines
134 KiB

/****************************************************************************/
// ascapi.c
//
// Share Controller API Functions.
//
// Copyright (C) Microsoft Corp., PictureTel 1992-1997
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "ascapi"
#include <as_conf.hpp>
extern "C"
{
#include <acomapi.h>
#include <asmapi.h>
#include <asmint.h>
}
#include <string.h>
/****************************************************************************/
// SC_Init
// Initializes the Share Controller.
//
// PARAMETERS:
// pSMHandle - Handle to pass to SM calls
//
// RETURNS: FALSE on failure.
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_Init(PVOID pSMHandle)
{
BOOL rc;
unsigned MaxPDUSize;
DC_BEGIN_FN("SC_Init");
// Don't check the state - there's no static data init in the C++ App
// Serving build so this will see complete garbage in scState and fail.
#define DC_INIT_DATA
#include <ascdata.c>
#undef DC_INIT_DATA
// Register with SM.
rc = SM_Register(pSMHandle, &MaxPDUSize, &scUserID);
if (rc) {
// Save the User ID.
scPartyArray[0].netPersonID = scUserID;
scPSMHandle = pSMHandle;
TRC_NRM((TB, "Local user id [%d]", scUserID));
// Set the user name.
strcpy(scPartyArray[0].name, "RDP");
// Get the usable space (and hence the allocation request size) for
// our 8K and 16K OutBufs.
sc8KOutBufUsableSpace = IcaBufferGetUsableSpace(OUTBUF_8K_ALLOC_SIZE)
- OUTBUF_HEADER_OVERHEAD;
sc16KOutBufUsableSpace = IcaBufferGetUsableSpace(
OUTBUF_16K_ALLOC_SIZE) - OUTBUF_HEADER_OVERHEAD;
// Move onto the next state.
SC_SET_STATE(SCS_INITED)
}
else {
TRC_ERR((TB, "Failed to register with SM"));
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// SC_Update
// Update the Share Controller after shadow.
//
/****************************************************************************/
void RDPCALL SHCLASS SC_Update()
{
DC_BEGIN_FN("SC_Update");
scNoBitmapCompressionHdr = TS_EXTRA_NO_BITMAP_COMPRESSION_HDR;
DC_END_FN();
}
/****************************************************************************/
/* SC_Term() */
/* */
/* Terminates the Share Controller. */
/****************************************************************************/
void RDPCALL SHCLASS SC_Term(void)
{
DC_BEGIN_FN("SC_Term");
SC_CHECK_STATE(SCE_TERM);
// Reset state.
SC_SET_STATE(SCS_STARTED);
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* SC_CreateShare() */
/* */
/* Creates a share for the current session. */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_CreateShare(void)
{
BOOL rc = FALSE;
unsigned pktLen;
unsigned nameLen;
unsigned capsSize;
UINT32 sessionId;
PTS_COMBINED_CAPABILITIES caps;
PTS_DEMAND_ACTIVE_PDU pPkt = NULL;
PTS_BITMAP_CAPABILITYSET pBitmapCaps;
NTSTATUS status;
DC_BEGIN_FN("SC_CreateShare");
SC_CHECK_STATE(SCE_CREATE_SHARE);
/************************************************************************/
/* For console sessions, there's no client, so not much point in */
/* sending a demand active PDU. We also have to set up caps ourselves. */
/************************************************************************/
if (m_pTSWd->StackClass == Stack_Console)
{
LOCALPERSONID localPersonID = 0;
unsigned localCapsSize;
PTS_COMBINED_CAPABILITIES pLocalCaps;
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
BOOL callingPJS = FALSE;
TRC_NRM((TB, "SC_CreateShare called for console stack"));
/********************************************************************/
/* Move onto the next state. */
/********************************************************************/
SC_SET_STATE(SCS_IN_SHARE);
/********************************************************************/
/* carry on as if a confirm active has been received */
/********************************************************************/
callingPJS = TRUE;
if (scNumberInShare == 0)
{
CPC_GetCombinedCapabilities(SC_LOCAL_PERSON_ID,
&localCapsSize,
&pLocalCaps);
if (!SCCallPartyJoiningShare(SC_LOCAL_PERSON_ID,
localCapsSize,
pLocalCaps,
acceptedArray,
0))
{
/************************************************************/
/* Some component rejected the local party */
/************************************************************/
TRC_ERR((TB, "The local party should never be rejected"));
DC_QUIT;
}
/****************************************************************/
/* There is now one party in the share (the local one). */
/****************************************************************/
scNumberInShare = 1;
TRC_NRM((TB, "Added local person"));
}
/********************************************************************/
/* Calculate a localPersonID for the remote party and store their */
/* details in the party array. */
/********************************************************************/
for ( localPersonID = 1;
localPersonID < SC_DEF_MAX_PARTIES;
localPersonID++ )
{
if (scPartyArray[localPersonID].netPersonID == 0)
{
/************************************************************/
/* Found an empty slot. */
/************************************************************/
TRC_NRM((TB, "Allocated local person ID %d", localPersonID));
break;
}
}
/********************************************************************/
/* If we don't find an empty slot, we can't keep running because */
/* we write past the end of the scPartyArray below. */
/********************************************************************/
if (SC_DEF_MAX_PARTIES <= localPersonID)
{
TRC_ABORT((TB, "Couldn't find room to store local person"));
DC_QUIT;
}
/********************************************************************/
/* Store the new person's details */
/********************************************************************/
scPartyArray[localPersonID].netPersonID = 42;
strncpy(scPartyArray[localPersonID].name,
"Console",
sizeof(scPartyArray[0].name) );
memset(scPartyArray[localPersonID].sync,
0,
sizeof(scPartyArray[localPersonID].sync));
TRC_NRM((TB, "{%d} person name %s",
(unsigned)localPersonID, scPartyArray[localPersonID].name));
/********************************************************************/
/* We need to set up client caps ourselves, since there's no actual */
/* client to do it. We set up a maximal set that will get */
/* negotiated down when someone shadows us. */
/********************************************************************/
typedef struct tagCC_COMBINED_CAPABILITIES
{
UINT16 numberCapabilities;
#ifdef DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
#define CC_COMBINED_CAPS_NUMBER_CAPABILITIES 18
#else
#define CC_COMBINED_CAPS_NUMBER_CAPABILITIES 17
#endif
#else // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
#define CC_COMBINED_CAPS_NUMBER_CAPABILITIES 17
#else
#define CC_COMBINED_CAPS_NUMBER_CAPABILITIES 16
#endif
#endif // DRAW_GDIPLUS
UINT16 pad2octets;
TS_GENERAL_CAPABILITYSET generalCapabilitySet;
TS_BITMAP_CAPABILITYSET bitmapCapabilitySet;
TS_ORDER_CAPABILITYSET orderCapabilitySet;
TS_BITMAPCACHE_CAPABILITYSET bitmapCacheCaps;
TS_COLORTABLECACHE_CAPABILITYSET colorTableCacheCapabilitySet;
TS_WINDOWACTIVATION_CAPABILITYSET windowActivationCapabilitySet;
TS_CONTROL_CAPABILITYSET controlCapabilitySet;
TS_POINTER_CAPABILITYSET pointerCapabilitySet;
TS_SHARE_CAPABILITYSET shareCapabilitySet;
TS_INPUT_CAPABILITYSET inputCapabilitySet;
TS_SOUND_CAPABILITYSET soundCapabilitySet;
TS_FONT_CAPABILITYSET fontCapabilitySet;
TS_GLYPHCACHE_CAPABILITYSET glyphCacheCapabilitySet;
TS_BRUSH_CAPABILITYSET brushCapabilitySet;
TS_OFFSCREEN_CAPABILITYSET offscreenCapabilitySet;
TS_VIRTUALCHANNEL_CAPABILITYSET virtualchannelCapabilitySet;
#ifdef DRAW_NINEGRID
TS_DRAW_NINEGRID_CAPABILITYSET drawNineGridCapabilitySet;
#endif
#ifdef DRAW_GDIPLUS
TS_DRAW_GDIPLUS_CAPABILITYSET drawGdiplusCapabilitySet;
#endif
} CC_COMBINED_CAPABILITIES;
// ARG! Why isn't this const!!!
CC_COMBINED_CAPABILITIES caps =
{
CC_COMBINED_CAPS_NUMBER_CAPABILITIES, /* Number of capabilities */
0, /* padding */
/****************************************************************/
/* General caps */
/****************************************************************/
{
TS_CAPSETTYPE_GENERAL, /* capabilitySetType */
sizeof(TS_GENERAL_CAPABILITYSET), /* lengthCapability */
TS_OSMAJORTYPE_WINDOWS, /* OSMajorType */
TS_OSMINORTYPE_WINDOWS_NT, /* OSMinorType */
TS_CAPS_PROTOCOLVERSION, /* protocolVersion */
0, /* pad1 */
0, /* generalCompressionTypes */
TS_EXTRA_NO_BITMAP_COMPRESSION_HDR |
TS_FASTPATH_OUTPUT_SUPPORTED |
TS_LONG_CREDENTIALS_SUPPORTED |
TS_AUTORECONNECT_COOKIE_SUPPORTED |
TS_ENC_SECURE_CHECKSUM,/*recv safer checksums */
FALSE, /* updateCapabilityFlag */
FALSE, /* remoteUnshareFlag */
0, /* generalCompressionLevel */
0, /* refreshRectSupport */
0 /* suppressOutputSupport */
},
/****************************************************************/
/* Bitmap caps */
/****************************************************************/
{
TS_CAPSETTYPE_BITMAP, /* capabilitySetType */
sizeof(TS_BITMAP_CAPABILITYSET), /* lengthCapability */
8, /* Set in CC */ /* preferredBitsPerPixel */
TRUE, /* receive1BitPerPixel */
TRUE, /* receive4BitsPerPixel */
TRUE, /* receive8BitsPerPixel */
1024, /* Set in CC */ /* desktopWidth */
768, /* Set in CC */ /* desktopHeight */
0, /* pad2 */
FALSE, /* desktopResizeFlag */
1, /* bitmapCompressionFlag */
0, /* highColorFlags */
0, /* pad1 */
TRUE, /* multipleRectangleSupport*/
0 /* pad2 */
},
/****************************************************************/
/* Order Caps */
/****************************************************************/
{
TS_CAPSETTYPE_ORDER, /* capabilitySetType */
sizeof(TS_ORDER_CAPABILITYSET), /* lengthCapability */
{'\0','\0','\0','\0','\0','\0','\0','\0',
'\0','\0','\0','\0','\0','\0','\0','\0'}, /* terminalDescriptor */
0, /* pad1 */
1, /* desktopSaveXGranularity */
20, /* desktopSaveYGranularity */
0, /* pad2 */
1, /* maximumOrderLevel */
0, /* numberFonts */
TS_ORDERFLAGS_ZEROBOUNDSDELTASSUPPORT | /* orderFlags */
TS_ORDERFLAGS_NEGOTIATEORDERSUPPORT |
TS_ORDERFLAGS_COLORINDEXSUPPORT,
{
/********************************************************/
/* Order Support flags. */
/* */
/* The array index corresponds to the TS_NEG_xxx_INDEX */
/* value indicated (from at128.h) The values marked */
/* with an x in the first column are overwritten at run */
/* time by UH before CC sends the combined */
/* capabilities. */
/********************************************************/
1, /* 0 TS_NEG_DSTBLT_INDEX destinationBltSupport */
1, /* 1 TS_NEG_PATBLT_INDEX patternBltSupport */
1, /* x 2 TS_NEG_SCRBLT_INDEX screenBltSupport */
1, /* 3 TS_NEG_MEMBLT_INDEX memoryBltSupport */
1, /* 4 TS_NEG_MEM3BLT_INDEX memoryThreeWayBltSupport */
0, /* x 5 TS_NEG_ATEXTOUT_INDEX textASupport */
0, /* x 6 TS_NEG_AEXTTEXTOUT_INDEX extendedTextASupport */
#ifdef DRAW_NINEGRID
1, /* 7 TS_NEG_RECTANGLE_INDEX rectangleSupport */
#else
0,
#endif
1, /* 8 TS_NEG_LINETO_INDEX lineSupport */
#ifdef DRAW_NINEGRID
1, /* 9 TS_NEG_FASTFRAME_INDEX frameSupport */
#else
0,
#endif
0, /* 10 TS_NEG_OPAQUERECT_INDEX opaqueRectangleSupport */
1, /* x11 TS_NEG_SAVEBITMAP_INDEX desktopSaveSupport */
0, /* x12 TS_NEG_WTEXTOUT_INDEX textWSupport */
1, /* 13 TS_NEG_MEMBLT_R2_INDEX Reserved entry */
1, /* 14 TS_NEG_MEM3BLT_R2_INDEX Reserved entry */
1, /* 15 TS_NEG_MULTIDSTBLT_INDEX multi DstBlt support */
1, /* 16 TS_NEG_MULTIPATBLT_INDEX multi PatBlt support */
1, /* 17 TS_NEG_MULTISCRBLT_INDEX multi ScrBlt support */
1, /* 18 TS_NEG_MULTIOPAQUERECT_INDEX multi OpaqueRect support */
1, /* 19 TS_NEG_FAST_INDEX */
1, /* 20 TS_NEG_POLYGON_SC_INDEX */
1, /* 21 TS_NEG_POLYGON_CB_INDEX */
1, /* 22 TS_NEG_POLYLINE_INDEX polyLineSupport */
0, /* 23 MS reserved entry 2 */
1, /* 24 TS_NEG_FAST_GLYPH_INDEX */
1, /* 25 TS_NEG_ELLIPSE_SC_INDEX */
1, /* 26 TS_NEG_ELLIPSE_CB_INDEX */
0, /* 27 MS reserved entry 6 */
0, /* x28 TS_NEG_WEXTTEXTOUT_INDEX extendedTextWSupport */
0, /* x29 TS_NEG_WLONGTEXTOUT_INDEX longTextWSupport */
0, /* x30 TS_NEG_WLONGEXTTEXTOUT_INDEX longExtendedTextWSupport */
0, /* 31 DCL reserved entry 3 */
},
(TS_TEXT_AND_MASK)|(TS_TEXT_OR_MASK), /* textFlags */
0, /* pad2 */
0, /* pad4 */
480 * 480, /* desktopSaveSize */
0, /* pad2 */
0, /* pad2 */
0, /* textANSICodePage */
0 /* pad2 */
},
/****************************************************************/
/* BitmapCache Caps Note that this same space is used for rev1 */
/* and rev2, we declare as rev1 because it is the larger of the */
/* two. We will cast to rev2 if we get a server advertisement */
/* that it supports rev2 (via */
/* TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT). */
/****************************************************************/
{
TS_CAPSETTYPE_BITMAPCACHE_REV2, /* capabilitySetType */
sizeof(TS_BITMAPCACHE_CAPABILITYSET), /* lengthCapability */
0, /* pad DWORDs 1 */
0, /* pad DWORDs 2 */
0, /* pad DWORDs 3 */
0, /* pad DWORDs 4 */
0, /* pad DWORDs 5 */
0, /* pad DWORDs 6 */
0, 0, /* Cache1 */
0, 0, /* Cache2 */
0, 0, /* Cache3 */
},
/****************************************************************/
/* ColorTableCache Caps */
/****************************************************************/
{
TS_CAPSETTYPE_COLORCACHE, /* capabilitySetType */
sizeof(TS_COLORTABLECACHE_CAPABILITYSET), /* lengthCapability */
6, /* colortableCacheSize */
0 /* notpartOfTSharePad */
},
/****************************************************************/
/* WindowActivation Caps */
/****************************************************************/
{
TS_CAPSETTYPE_ACTIVATION, /* capabilitySetType */
sizeof(TS_WINDOWACTIVATION_CAPABILITYSET), /* lengthCapability */
FALSE, /* helpKeyFlag */
FALSE, /* helpKeyIndexFlag */
FALSE, /* helpExtendedKeyFlag */
FALSE /* windowManagerKeyFlag */
},
/****************************************************************/
/* Control Caps */
/****************************************************************/
{
TS_CAPSETTYPE_CONTROL, /* capabilitySetType */
sizeof(TS_CONTROL_CAPABILITYSET), /* lengthCapability */
0, /* controlFlags */
FALSE, /* remoteDetachFlag */
TS_CONTROLPRIORITY_NEVER, /* controlInterest */
TS_CONTROLPRIORITY_NEVER /* detachInterest */
},
/****************************************************************/
/* Pointer Caps */
/****************************************************************/
{
TS_CAPSETTYPE_POINTER, /* capabilitySetType */
sizeof(TS_POINTER_CAPABILITYSET), /* lengthCapability */
TRUE, /* colorPointerFlag */
20, /* colorPointerCacheSize */
21 /* pointerCacheSize */
},
/****************************************************************/
/* Share Caps */
/****************************************************************/
{
TS_CAPSETTYPE_SHARE, /* capabilitySetType */
sizeof(TS_SHARE_CAPABILITYSET), /* lengthCapability */
0, /* nodeId */
0 /* padding */
},
/****************************************************************/
/* Input Caps */
/****************************************************************/
{
TS_CAPSETTYPE_INPUT,
sizeof(TS_INPUT_CAPABILITYSET), /* lengthCapability */
TS_INPUT_FLAG_SCANCODES
| TS_INPUT_FLAG_MOUSEX, /* inputFlags */
TS_INPUT_FLAG_FASTPATH_INPUT2, /* padding */
0 /* keyboard layout */
},
/****************************************************************/
/* Sound */
/****************************************************************/
{
TS_CAPSETTYPE_SOUND,
sizeof(TS_SOUND_CAPABILITYSET), /* lengthCapability */
TS_SOUND_FLAG_BEEPS, /* soundFlags */
0, /* padding */
},
/****************************************************************/
/* Font */
/****************************************************************/
{
TS_CAPSETTYPE_FONT,
sizeof(TS_FONT_CAPABILITYSET), /* lengthCapability */
TS_FONTSUPPORT_FONTLIST, /* fontSupportFlags */
0, /* padding */
},
/****************************************************************/
/* GlyphCache Caps */
/****************************************************************/
{
TS_CAPSETTYPE_GLYPHCACHE, /* capabilitySetType */
sizeof(TS_GLYPHCACHE_CAPABILITYSET), /* lengthCapability */
{ /* GlyphCache */
{ 254, 4 },
{ 254, 4 },
{ 254, 8 },
{ 254, 8 },
{ 254, 16 },
{ 254, 32 },
{ 254, 64 },
{ 254, 128 },
{ 254, 256 },
{ 254, 2048 }
},
{ 256, 256 }, /* FragCache */
2, /* GlyphSupportLevel */
},
/****************************************************************/
/* Brush Caps */
/****************************************************************/
{
TS_CAPSETTYPE_BRUSH, /* capabilitySetType */
sizeof(TS_BRUSH_CAPABILITYSET), /* lengthCapability */
1, /* TS_BRUSH_COLOR8x8 */ /* brushSupportLevel */
},
// Enable this capability when GDI supports Device Bitmaps in mirroring
// display drivers.
/************************************************************************/
/* Offscreen Caps */
/************************************************************************/
{
TS_CAPSETTYPE_OFFSCREENCACHE, /* capabilitySetType */
sizeof(TS_OFFSCREEN_CAPABILITYSET), /* lengthCapability */
TS_OFFSCREEN_SUPPORTED, /* offscreenSupportLevel */
TS_OFFSCREEN_CACHE_SIZE_SERVER_DEFAULT, /* offscreenCacheSize */
TS_OFFSCREEN_CACHE_ENTRIES_DEFAULT, /* offscreenCacheEntries */
},
/************************************************************************/
/* Virtual Channel Caps */
/************************************************************************/
{
TS_CAPSETTYPE_VIRTUALCHANNEL, /* capabilitySetType */
sizeof(TS_VIRTUALCHANNEL_CAPABILITYSET), /* lengthCapability */
//
// What this particular cap means is that the client understands
// virtual channels compressed from the server at 64K.
//
// The client recevies what compression cap the server supports
// from the client and compresses appropriately
//
TS_VCCAPS_COMPRESSION_64K,//TS_VCCAPS_DEFAULT?/* vc support flags */
#ifdef DRAW_NINEGRID
},
{
TS_CAPSETTYPE_DRAWNINEGRIDCACHE, // capabilitySetType
sizeof(TS_DRAW_NINEGRID_CAPABILITYSET), // lengthCapability
TS_DRAW_NINEGRID_SUPPORTED_REV2, // drawNineGridSupportLevel
TS_DRAW_NINEGRID_CACHE_SIZE_DEFAULT, // drawNineGridCacheSize
TS_DRAW_NINEGRID_CACHE_ENTRIES_DEFAULT, // drawNineGridCacheEntries
#endif
#ifdef DRAW_GDIPLUS
},
{
TS_CAPSETTYPE_DRAWGDIPLUS, // capabilitySetType
sizeof(TS_DRAW_GDIPLUS_CAPABILITYSET), // lengthCapability
TS_DRAW_GDIPLUS_SUPPORTED, // drawEscapeSupportLevel
0xFFFFFFFF, // TSGdiplusVersion
TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE, // drawGdiplusCacheLevel
TS_GDIP_GRAPHICS_CACHE_ENTRIES_DEFAULT,
TS_GDIP_BRUSH_CACHE_ENTRIES_DEFAULT,
TS_GDIP_PEN_CACHE_ENTRIES_DEFAULT,
TS_GDIP_IMAGE_CACHE_ENTRIES_DEFAULT,
TS_GDIP_IMAGEATTRIBUTES_CACHE_ENTRIES_DEFAULT,
TS_GDIP_GRAPHICS_CACHE_CHUNK_SIZE_DEFAULT,
TS_GDIP_BRUSH_CACHE_CHUNK_SIZE_DEFAULT,
TS_GDIP_PEN_CACHE_CHUNK_SIZE_DEFAULT,
TS_GDIP_IMAGEATTRIBUTES_CACHE_CHUNK_SIZE_DEFAULT,
TS_GDIP_IMAGE_CACHE_CHUNK_SIZE_DEFAULT, // Chunk size to store image cache
TS_GDIP_IMAGE_CACHE_TOTAL_SIZE_DEFAULT, // Total size of image cache in number of chunks
TS_GDIP_IMAGE_CACHE_MAX_SIZE_DEFAULT, // Maximun size of image to cache, in number of chunks
#endif
}
};
/********************************************************************/
/* set up bitmap cache caps */
/********************************************************************/
{
TS_BITMAPCACHE_CAPABILITYSET_REV2 *pRev2Caps;
// Rev2 caps.
pRev2Caps = (TS_BITMAPCACHE_CAPABILITYSET_REV2 *)&caps.bitmapCacheCaps;
TRC_ALT((TB,"Preparing REV2 caps for server\n"));
pRev2Caps->capabilitySetType = TS_CAPSETTYPE_BITMAPCACHE_REV2;
pRev2Caps->NumCellCaches = 3;
pRev2Caps->bPersistentKeysExpected = FALSE;
pRev2Caps->bAllowCacheWaitingList = FALSE;
pRev2Caps->CellCacheInfo[0].bSendBitmapKeys = FALSE;
pRev2Caps->CellCacheInfo[0].NumEntries = 600;
pRev2Caps->CellCacheInfo[1].bSendBitmapKeys = FALSE;
pRev2Caps->CellCacheInfo[1].NumEntries = 300;
pRev2Caps->CellCacheInfo[2].bSendBitmapKeys = FALSE;
pRev2Caps->CellCacheInfo[2].NumEntries = 300;
pRev2Caps->CellCacheInfo[3].bSendBitmapKeys = 0;
pRev2Caps->CellCacheInfo[3].NumEntries = 0;
pRev2Caps->CellCacheInfo[4].bSendBitmapKeys = 0;
pRev2Caps->CellCacheInfo[4].NumEntries = 0;
}
/********************************************************************/
/* and screen size */
/********************************************************************/
{
PTS_BITMAP_CAPABILITYSET pBmpCaps;
pBmpCaps = (TS_BITMAP_CAPABILITYSET *)&caps.bitmapCapabilitySet;
pBmpCaps->desktopWidth = (TSUINT16)(m_pTSWd->desktopWidth);
pBmpCaps->desktopHeight = (TSUINT16)(m_pTSWd->desktopHeight);
#ifdef DC_HICOLOR
pBmpCaps->preferredBitsPerPixel = (TSUINT16)(m_pTSWd->desktopBpp);
#endif
}
if (!SCCallPartyJoiningShare(localPersonID,
sizeof(caps),
&caps,
acceptedArray,
scNumberInShare))
{
/****************************************************************/
/* Some component rejected the remote party */
/****************************************************************/
TRC_ERR((TB, "Remote party rejected"));
DC_QUIT;
}
/********************************************************************/
/* The remote party is now in the share. */
/********************************************************************/
callingPJS = FALSE;
rc = TRUE;
scNumberInShare++;
TRC_NRM((TB, "Number in share %d", (unsigned)scNumberInShare));
/********************************************************************/
/* Synchronise only for primary stacks. Shadow stacks will be */
/* sync'd by the DD right before output starts. */
/********************************************************************/
SCInitiateSync(m_pTSWd->StackClass == Stack_Shadow);
/********************************************************************/
/* don't wait for a response - there isn't a client out there. */
/* Just wake up the WD now */
/********************************************************************/
TRC_NRM((TB, "Wake up WDW"));
WDW_ShareCreated(m_pTSWd, TRUE);
DC_QUIT;
}
/************************************************************************/
/* Get the combined capabilities */
/************************************************************************/
CPC_GetCombinedCapabilities(SC_LOCAL_PERSON_ID, &capsSize, &caps);
/************************************************************************/
/* If we support dynamic client resizing, then we need to update the */
/* desktop width and height in the caps passed out on the demand active */
/* PDU to notify the client of the change */
/************************************************************************/
pBitmapCaps = (PTS_BITMAP_CAPABILITYSET) WDW_GetCapSet(
m_pTSWd, TS_CAPSETTYPE_BITMAP, caps, capsSize);
if (pBitmapCaps)
{
if (pBitmapCaps->desktopResizeFlag == TS_CAPSFLAG_SUPPORTED)
{
TRC_ALT((TB, "Update client desktop size"));
pBitmapCaps->desktopHeight = (TSUINT16)(m_pTSWd->desktopHeight);
pBitmapCaps->desktopWidth = (TSUINT16)(m_pTSWd->desktopWidth);
}
#ifdef DC_HICOLOR
/********************************************************************/
/* For high color, update the color depth too */
/********************************************************************/
pBitmapCaps->preferredBitsPerPixel = (TSUINT16)(m_pTSWd->desktopBpp);
#endif
}
/************************************************************************/
/* Get the sessionId from the WD structure */
/************************************************************************/
sessionId = m_pTSWd->sessionId;
/************************************************************************/
/* Calculate the size of the various bits of the TS_DEMAND_ACTIVE_PDU */
/************************************************************************/
pktLen = sizeof(TS_DEMAND_ACTIVE_PDU) - 1 + sizeof(UINT32);
nameLen = strlen(scPartyArray[0].name);
nameLen = (unsigned)DC_ROUND_UP_4(nameLen);
pktLen += nameLen;
pktLen += capsSize;
/************************************************************************/
// Get a buffer - this should not fail, so abort if it does
// fWait is TRUE means that we will always wait for a buffer to be avail
/************************************************************************/
status = SM_AllocBuffer(scPSMHandle, (PPVOID)(&pPkt), pktLen, TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
// Calculate a new shareID.
scGeneration++;
scShareID = scUserID | (((UINT32)(scGeneration & 0xFFFF)) << 16);
// Fill in the packet fields.
pPkt->shareControlHeader.totalLength = (UINT16)pktLen;
pPkt->shareControlHeader.pduType = TS_PDUTYPE_DEMANDACTIVEPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16)scUserID;
pPkt->shareID = scShareID;
pPkt->lengthSourceDescriptor = (UINT16)nameLen;
pPkt->lengthCombinedCapabilities = (UINT16)capsSize;
memcpy(&(pPkt->data[0]), scPartyArray[0].name, nameLen);
memcpy(&(pPkt->data[nameLen]), caps, capsSize);
memcpy(&(pPkt->data[nameLen+capsSize]),
&sessionId,
sizeof(sessionId));
// Send it.
rc = SM_SendData(scPSMHandle, pPkt, pktLen, TS_HIGHPRIORITY, 0,
FALSE, RNS_SEC_ENCRYPT, FALSE);
if (rc) {
TRC_ALT((TB, "%s Stack sent TS_DEMAND_ACTIVE_PDU",
m_pTSWd->StackClass == Stack_Primary ? "Primary" :
(m_pTSWd->StackClass == Stack_Shadow ? "Shadow" :
"PassThru")));
}
else {
TRC_ERR((TB, "Failed to send TS_DEMAND_ACTIVE_PDU"));
}
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for TS_DEMAND_ACTIVE_PDU",
pktLen));
rc = FALSE;
DC_QUIT;
}
/************************************************************************/
/* Change SC state. */
/************************************************************************/
SC_SET_STATE(SCS_SHARE_STARTING)
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
/* SC_SendServerCert */
/* */
/* Sends the target server's random + certificate to a client server for */
/* use in shadowing. */
/****************************************************************************/
NTSTATUS RDPCALL SHCLASS SC_SendServerCert(PSHADOWCERT pCert, ULONG ulLength)
{
PTS_SERVER_CERTIFICATE_PDU pPkt;
ULONG ulPktSize;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SC_SendServerCert");
ulPktSize = sizeof(TS_SERVER_CERTIFICATE_PDU) - 1 +
pCert->shadowRandomLen + pCert->shadowCertLen;
TRC_ERR((TB, "handle: %p, &pPkt: %p, size: %ld",
m_pTSWd->pSmInfo, &pPkt, ulPktSize));
status = SM_AllocBuffer(m_pTSWd->pSmInfo, (PPVOID) &pPkt, ulPktSize, TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
// Fill in the packet fields.
pPkt->shareControlHeader.totalLength = (UINT16) ulPktSize;
pPkt->shareControlHeader.pduType = TS_PDUTYPE_SERVERCERTIFICATEPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16) scUserID;
pPkt->encryptionMethod = pCert->encryptionMethod;
pPkt->encryptionLevel = pCert->encryptionLevel;
pPkt->shadowRandomLen = pCert->shadowRandomLen;
pPkt->shadowCertLen = pCert->shadowCertLen;
// Copy over the random + cert
if (pPkt->encryptionLevel != 0) {
memcpy(pPkt->data, pCert->data,
pCert->shadowRandomLen + pCert->shadowCertLen);
}
// Send ServerCertificatePDU
rc = SM_SendData(m_pTSWd->pSmInfo, pPkt, ulPktSize, TS_HIGHPRIORITY,
0, FALSE, RNS_SEC_ENCRYPT, FALSE);
if (rc) {
status = STATUS_SUCCESS;
TRC_ALT((TB, "Sent TS_SERVER_CERTIFICATE_PDU: %ld", ulPktSize));
}
else {
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ERR((TB, "Failed to send TS_SERVER_CERTIFICATE_PDU"));
}
}
else {
status = STATUS_NO_MEMORY;
TRC_ERR((TB, "Failed to alloc %d bytes for TS_SERVER_CERTIFICATE_PDU",
ulPktSize));
}
DC_END_FN();
return status;
}
/****************************************************************************/
/* SC_SaveServerCert */
/* */
/* Save the server certificate + random for subsequent validation by rdpwsx.*/
/* A NULL pPkt indicates we should save an empty certificate. */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_SaveServerCert(PTS_SERVER_CERTIFICATE_PDU pPkt,
ULONG ulLength)
{
PSHADOWCERT pCert;
ULONG ulCertLen;
DC_BEGIN_FN("SC_SaveServerCert");
// Save off the data and signal rdpwsx that we got it. We will actually
// perform the validation in user mode.
if (pPkt != NULL) {
ulCertLen = pPkt->shadowRandomLen + pPkt->shadowCertLen;
pCert = (PSHADOWCERT) COM_Malloc(sizeof(SHADOWCERT) + ulCertLen - 1);
if (pCert != NULL) {
pCert->encryptionMethod = pPkt->encryptionMethod;
pCert->encryptionLevel = pPkt->encryptionLevel;
pCert->shadowRandomLen = pPkt->shadowRandomLen;
pCert->shadowCertLen = pPkt->shadowCertLen;
// If the encryption level is non-zero, then we should have a server random
// and certificate following the initial header
if (pCert->encryptionLevel != 0) {
memcpy(pCert->data, pPkt->data, ulCertLen);
}
TRC_ALT((TB, "Received certificate[%ld], level=%ld, method=%lx, random[%ld]",
pCert->shadowCertLen,
pCert->encryptionLevel,
pCert->encryptionMethod,
pCert->shadowRandomLen));
// Update SM parameters with negotiated values
SM_SetEncryptionParams(m_pTSWd->pSmInfo, pCert->encryptionLevel,
pCert->encryptionMethod);
}
else {
TRC_ERR((TB, "Could not allocate space for server cert: %ld!",
ulCertLen));
}
}
// Else, the target server did not send back a certificate (B3)
else {
pCert = (PSHADOWCERT) COM_Malloc(sizeof(SHADOWCERT));
if (pCert != NULL) {
memset(pCert, 0, sizeof(SHADOWCERT));
}
else {
TRC_ERR((TB, "Could not allocate space for server cert: %ld!",
sizeof(SHADOWCERT)));
}
}
// wake up the rdpwsx thread which is waiting on this information
m_pTSWd->pShadowCert = pCert;
KeSetEvent(m_pTSWd->pSecEvent, 0, FALSE);
DC_END_FN();
return TRUE;
} /* SC_SaveServerCert */
/****************************************************************************/
/* SC_SendClientRandom */
/* */
/* Send the encrypted client random to the shadow target server. */
/****************************************************************************/
NTSTATUS RDPCALL SHCLASS SC_SendClientRandom(PBYTE pClientRandom,
ULONG ulLength)
{
PTS_CLIENT_RANDOM_PDU pPkt;
ULONG ulPktSize;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SC_SendClientRandom");
ulPktSize = sizeof(TS_CLIENT_RANDOM_PDU) - 1 + ulLength;
status = NM_AllocBuffer(m_pTSWd->pNMInfo,
(PPVOID) &pPkt, ulPktSize, TRUE);
if (STATUS_SUCCESS == status) {
// Fill in the packet fields.
pPkt->shareControlHeader.totalLength = (UINT16) ulPktSize;
pPkt->shareControlHeader.pduType = TS_PDUTYPE_CLIENTRANDOMPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16)scUserID;
pPkt->clientRandomLen = ulLength;
// Copy over the random
TRC_ALT((TB, "PDUType: %lx, random length: %ld, pktSize: %ld",
pPkt->shareControlHeader.pduType, ulLength, ulPktSize));
memcpy(pPkt->data, pClientRandom, ulLength);
TRC_DATA_DBG("snd random: ", pClientRandom, ulLength);
rc = NM_SendData(m_pTSWd->pNMInfo,
(PBYTE) pPkt, ulPktSize, TS_HIGHPRIORITY, 0, FALSE);
if (rc) {
status = STATUS_SUCCESS;
TRC_ALT((TB, "Sent TS_CLIENT_RANDOM_PDU: %ld", ulPktSize));
}
else {
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ERR((TB, "Failed to send TS_CLIENT_RANDOM_PDU"));
}
}
else {
status = STATUS_NO_MEMORY;
TRC_ERR((TB, "Failed to alloc %d bytes for TS_CLIENT_RANDOM_PDU",
ulPktSize));
}
DC_END_FN();
return status;
}
/****************************************************************************/
/* SC_SaveClientRandom */
/* */
/* Save the encrypted client random for subsequent use by rdpwsx. */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_SaveClientRandom(PTS_CLIENT_RANDOM_PDU pPkt,
ULONG ulLength)
{
PCLIENTRANDOM pClientRandom;
BOOL rc = FALSE;
DC_BEGIN_FN("SC_SaveClientRandom");
//Validate data length
if ((ulLength < sizeof(TS_CLIENT_RANDOM_PDU)) ||
(ulLength + sizeof(TSUINT8) - sizeof(TS_CLIENT_RANDOM_PDU)) < pPkt->clientRandomLen) {
TRC_ERR((TB, "Bad client random length: %ld", pPkt->clientRandomLen));
return FALSE;
}
// The largest possible client random size is 512,
// defined in SendClientRandom() in tsrvsec.c
if (pPkt->clientRandomLen > CLIENT_RANDOM_MAX_SIZE) {
TRC_ERR((TB, "Client random length is too large: %ld", pPkt->clientRandomLen));
return FALSE;
}
// Save off the data and signal rdpwsx that we got it. We will actually
// perform the decryption in user mode.
pClientRandom = (PCLIENTRANDOM) COM_Malloc(sizeof(CLIENTRANDOM) - 1 +
pPkt->clientRandomLen);
if (pClientRandom != NULL) {
pClientRandom->clientRandomLen = pPkt->clientRandomLen;
memcpy(pClientRandom->data, pPkt->data, pPkt->clientRandomLen);
TRC_ALT((TB, "Received encrypted client random: @%p, len=%ld",
pClientRandom, pPkt->clientRandomLen));
TRC_DATA_DBG("sav random: ", pClientRandom->data,
pClientRandom->clientRandomLen);
}
else {
TRC_ERR((TB, "Could not allocate space for client random: %ld!",
pPkt->clientRandomLen));
}
// Free pShadowRandom in case it was allocated before
if (NULL != m_pTSWd->pShadowRandom) {
COM_Free(m_pTSWd->pShadowRandom);
m_pTSWd->pShadowRandom = NULL;
}
// wake up the termsrv thread which is waiting on this information
m_pTSWd->pShadowRandom = pClientRandom;
KeSetEvent (m_pTSWd->pSecEvent, 0, FALSE);
DC_END_FN();
return TRUE;
}
/****************************************************************************/
/* SC_GetSecurityData */
/* */
/* Wait for either a server certificate or a client random and return the */
/* data to rdpwsx. */
/****************************************************************************/
NTSTATUS RDPCALL SHCLASS SC_GetSecurityData(PSD_IOCTL pSdIoctl)
{
PSECURITYTIMEOUT pSecurityTimeout = (PSECURITYTIMEOUT) pSdIoctl->InputBuffer;
ULONG ulBytesNeeded = 0;
NTSTATUS status;
DC_BEGIN_FN("SC_GetSecurityData");
// Wait for the connected indication from SC (if necessary)
if (((pSdIoctl->IoControlCode == IOCTL_TSHARE_GET_CERT_DATA) &&
(pSdIoctl->OutputBufferLength == 0)) ||
(pSdIoctl->IoControlCode == IOCTL_TSHARE_GET_CLIENT_RANDOM)) {
TRC_ALT((TB, "About to wait for %s data",
pSdIoctl->IoControlCode == IOCTL_TSHARE_GET_CERT_DATA ?
"Server Certificate" : "Client Random"));
if (pSdIoctl->InputBufferLength == sizeof(SECURITYTIMEOUT)) {
status = WDW_WaitForConnectionEvent(m_pTSWd, m_pTSWd->pSecEvent,
pSecurityTimeout->ulTimeout);
}
else {
status = STATUS_INVALID_PARAMETER;
TRC_ERR((TB, "Bogus timeout value structure: Length [%ld] != Expected [%ld]",
pSdIoctl->InputBufferLength, sizeof(SECURITYTIMEOUT)));
DC_QUIT;
}
TRC_ALT((TB, "Back from wait for security data"));
if (status != STATUS_SUCCESS) {
TRC_ERR((TB, "Error waiting for security data: %lx, msec=%ld",
status, pSecurityTimeout->ulTimeout));
if (!NT_ERROR(status)) {
status = STATUS_IO_TIMEOUT;
}
DC_QUIT;
}
}
// Server certificate + random
if (pSdIoctl->IoControlCode == IOCTL_TSHARE_GET_CERT_DATA) {
if (m_pTSWd->pShadowCert != NULL) {
ULONG ulCertLength = m_pTSWd->pShadowCert->shadowCertLen +
m_pTSWd->pShadowCert->shadowRandomLen;
ulBytesNeeded = sizeof(SHADOWCERT) - 1 + ulCertLength;
// Return the length so rdpwsx can alloc the right amount of memory.
if ((pSdIoctl->OutputBuffer == NULL) ||
(pSdIoctl->OutputBufferLength < ulBytesNeeded)) {
TRC_ALT((TB, "Cert[%ld] + Rand[%ld] buffer too small: %ld < %ld",
m_pTSWd->pShadowCert->shadowCertLen,
m_pTSWd->pShadowCert->shadowRandomLen,
pSdIoctl->OutputBufferLength, ulBytesNeeded));
status = STATUS_BUFFER_TOO_SMALL;
}
// else, return the data to rdpwsx
else {
PSHADOWCERT pShadowCertOut = (PSHADOWCERT) pSdIoctl->OutputBuffer;
PSHADOWCERT pShadowCertIn = m_pTSWd->pShadowCert;
pShadowCertOut->encryptionMethod = pShadowCertIn->encryptionMethod;
pShadowCertOut->encryptionLevel = pShadowCertIn->encryptionLevel;
pShadowCertOut->shadowRandomLen = pShadowCertIn->shadowRandomLen;
pShadowCertOut->shadowCertLen = pShadowCertIn->shadowCertLen;
memcpy(pShadowCertOut->data, pShadowCertIn->data, ulCertLength);
// Free up the temporary buffer
COM_Free(m_pTSWd->pShadowCert);
m_pTSWd->pShadowCert = NULL;
status = STATUS_SUCCESS;
}
}
// We were unable to save the certificate!
else {
TRC_ERR((TB, "Saved certificate not found!"));
status = STATUS_NO_MEMORY;
}
}
// Encrypted client random
else if (pSdIoctl->IoControlCode == IOCTL_TSHARE_GET_CLIENT_RANDOM) {
if (m_pTSWd->pShadowRandom != NULL) {
ulBytesNeeded = m_pTSWd->pShadowRandom->clientRandomLen;
// Return the length so rdpwsx can alloc the right amount of memory.
if ((pSdIoctl->OutputBuffer == NULL) ||
(pSdIoctl->OutputBufferLength < ulBytesNeeded)) {
status = STATUS_BUFFER_TOO_SMALL;
TRC_ALT((TB, "Client random buffer too small: %ld < %ld",
pSdIoctl->OutputBufferLength, ulBytesNeeded));
}
// else, return the data to rdpwsx
else {
PCLIENTRANDOM pRandomIn = m_pTSWd->pShadowRandom;
PBYTE pRandomOut = (PBYTE) pSdIoctl->OutputBuffer;
TRC_ALT((TB, "Received client random: @%p, len=%ld",
pRandomIn, ulBytesNeeded));
memcpy(pRandomOut, pRandomIn->data, ulBytesNeeded);
TRC_DATA_DBG("rcv random: ", pRandomOut, ulBytesNeeded);
// Free up the temporary buffer
COM_Free(m_pTSWd->pShadowRandom);
m_pTSWd->pShadowRandom = NULL;
status = STATUS_SUCCESS;
}
}
// We were unable to save the encrypted random!
else {
TRC_ERR((TB, "Saved encrypted random not found!"));
status = STATUS_NO_MEMORY;
}
}
else {
TRC_ERR((TB, "Unrecognized ioctl: %lx", pSdIoctl->IoControlCode));
status = STATUS_INVALID_PARAMETER;
}
DC_EXIT_POINT:
pSdIoctl->BytesReturned = ulBytesNeeded;
DC_END_FN();
return status;
}
/****************************************************************************/
/* Name: SC_ShadowSyncShares */
/* */
/* See ascapi.h */
/****************************************************************************/
#ifdef DC_HICOLOR
BOOL RDPCALL SHCLASS SC_ShadowSyncShares(PTS_COMBINED_CAPABILITIES pCaps,
ULONG capsLen)
#else
BOOL RDPCALL SHCLASS SC_ShadowSyncShares(void)
#endif
{
BOOL rc = TRUE;
ShareClass *dcShare = (ShareClass *)m_pTSWd->dcShare;
DC_BEGIN_FN("SC_SyncShare");
TRC_ASSERT((dcShare != NULL), (TB, "NULL Share Class"));
#ifdef DC_HICOLOR
/************************************************************************/
/* if we're the primary or console, update the caps with those supplied */
/* for the shadower. It can only "lower" the capabilities, so there's */
/* no problem with setting up caps the target can't cope with */
/************************************************************************/
if ((m_pTSWd->StackClass == Stack_Primary) ||
(m_pTSWd->StackClass == Stack_Console))
{
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
TRC_ALT((TB, "Update caps for shadower"));
// Free the memory
if (cpcRemoteCombinedCaps[SC_SHADOW_PERSON_ID - 1] != NULL) {
COM_Free((PVOID)cpcRemoteCombinedCaps[SC_SHADOW_PERSON_ID - 1]);
cpcRemoteCombinedCaps[SC_SHADOW_PERSON_ID - 1] = NULL;
}
SCCallPartyJoiningShare(SC_SHADOW_PERSON_ID,
capsLen,
pCaps,
acceptedArray,
scNumberInShare);
/********************************************************************/
/* Now update the DD caps via the shared mem */
/********************************************************************/
DCS_TriggerUpdateShmCallback();
}
#endif
SCInitiateSync(TRUE);
TRC_ALT((TB, "Synchronized Shares"));
DC_END_FN();
return(rc);
} /* SC_ShadowSyncShares */
/****************************************************************************/
/* Name: SC_EndShare */
/* */
/* Ends a share */
/****************************************************************************/
void RDPCALL SHCLASS SC_EndShare(BOOLEAN bForce)
{
PTS_DEACTIVATE_ALL_PDU pPkt;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SC_EndShare");
// Due to the way a shadow hotkey terminates a session, we sometimes need
// to force sending of a deactivate all PDU. This is done explicitly
// instead of changing the state table so we don't effect normal connect
// processing.
if (!bForce) {
SC_CHECK_STATE(SCE_END_SHARE);
}
else {
TRC_ALT((TB, "Forcing deactivate all PDU"));
}
/************************************************************************/
// Get a buffer - this should not fail, so abort if it does
// fWait is TRUE means that we will always wait for a buffer to be avail
/************************************************************************/
status = SM_AllocBuffer(scPSMHandle, (PPVOID)(&pPkt),
sizeof(TS_DEACTIVATE_ALL_PDU), TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
// Fill in the packet fields.
pPkt->shareControlHeader.totalLength = sizeof(TS_DEACTIVATE_ALL_PDU);
pPkt->shareControlHeader.pduType = TS_PDUTYPE_DEACTIVATEALLPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16)scUserID;
pPkt->shareID = scShareID;
pPkt->lengthSourceDescriptor = 1;
pPkt->sourceDescriptor[0] = 0;
// Send DeactivateAllPDU.
rc = SM_SendData(scPSMHandle, pPkt, sizeof(TS_DEACTIVATE_ALL_PDU),
TS_HIGHPRIORITY, 0, FALSE, RNS_SEC_ENCRYPT, FALSE);
if (rc) {
TRC_ALT((TB, "Sent DeactivateAllPDU"));
SCEndShare();
}
else {
TRC_ERR((TB, "Failed to send TS_DEACTIVATE_ALL_PDU"));
}
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for TS_DEACTIVATE_ALL_PDU",
sizeof(PTS_DEACTIVATE_ALL_PDU)));
}
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
// SC_OnDisconnected
//
// Handles disconnection notification.
/****************************************************************************/
void RDPCALL SHCLASS SC_OnDisconnected(UINT32 userID)
{
DC_BEGIN_FN("SC_OnDisconnected");
if (scNumberInShare != 0) {
SC_CHECK_STATE(SCE_DETACH_USER);
TRC_NRM((TB, "User %u detached", userID));
// Do the real work...
SCEndShare();
}
else {
TRC_NRM((TB, "Share already ended: nothing more to do"));
}
DC_EXIT_POINT:
DC_END_FN();
} /* SC_OnDisconnected */
/****************************************************************************/
/* Name: SC_OnDataReceived */
/* */
/* Purpose: Callback from SM for data receive path. */
/* */
/* Params: netPersonID - MCS UserID of the data sender */
/* priority - MCS data priority the data was sent on */
/* pPkt - pointer to start of packet */
/****************************************************************************/
void RDPCALL ShareClass::SC_OnDataReceived(
PBYTE pPkt,
NETPERSONID netPersonID,
unsigned DataLength,
UINT32 priority)
{
UINT16 pduType, pduType2;
LOCALPERSONID localID;
BOOL pduOK = FALSE;
DC_BEGIN_FN("SC_OnDataReceived");
TRC_NRM((TB, "Data Received"));
if (DataLength >= sizeof(TS_SHARECONTROLHEADER)) {
pduType = (((PTS_SHARECONTROLHEADER)pPkt)->pduType) & TS_MASK_PDUTYPE;
TRC_NRM((TB, "[%u]SC packet type %u", netPersonID, pduType));
}
else {
TRC_ERR((TB,"Data len %u too small for share ctrl header",
DataLength));
goto ShortPDU;
}
if (pduType == TS_PDUTYPE_DATAPDU)
{
/********************************************************************/
/* Data PDU. This is critical path so decode inline. */
/********************************************************************/
if (DataLength >= sizeof(TS_SHAREDATAHEADER)) {
pduType2 = ((PTS_SHAREDATAHEADER)pPkt)->pduType2;
SC_CHECK_STATE(SCE_DATAPACKET);
pduOK = TRUE;
}
else {
TRC_ERR((TB,"Data len %u too small for share data header",
DataLength));
goto ShortPDU;
}
#ifdef DC_DEBUG
{
/****************************************************************/
/* Ok, this is ugly. I'm trying to trace the PDU name without */
/* - searching a table */
/* - implementing a sparse table */
/* - a huge if ... else if switch. */
/* If you don't like it or don't understand it, ask MF. Before */
/* you get too het up, bear in mind the #ifdef DC_DEBUG above. */
/****************************************************************/
unsigned pduIndex =
(pduType2 == TS_PDUTYPE2_UPDATE) ? 1 :
(pduType2 == TS_PDUTYPE2_FONT) ? 2 :
(pduType2 == TS_PDUTYPE2_CONTROL) ? 3 :
((pduType2 >= TS_PDUTYPE2_WINDOWACTIVATION) &&
(pduType2 <= TS_PDUTYPE2_BITMAPCACHE_ERROR_PDU)) ?
pduType2 - 19 : 0;
TRC_NRM((TB, "DataPDU type %s (%u)", scPktName[pduIndex],
pduType2));
}
#endif
/********************************************************************/
/* First check for synchronize packets */
/********************************************************************/
if (pduType2 != TS_PDUTYPE2_SYNCHRONIZE) {
/****************************************************************/
/* Now check that this priority has been synchronized */
/****************************************************************/
localID = SC_NetworkIDToLocalID(netPersonID);
if (!scPartyArray[localID].sync[priority])
{
TRC_ALT((TB,
"[%d] {%d} Discarding packet on unsynched priority %d",
netPersonID, localID, priority));
DC_QUIT;
}
/****************************************************************/
/* All is well - pass the packet to its destination */
/****************************************************************/
switch (pduType2) {
case TS_PDUTYPE2_INPUT:
// Note that changes to this path should be examined
// in light of fast-path input (IM_DecodeFastPathInput).
IM_PlaybackEvents((PTS_INPUT_PDU)pPkt, DataLength);
break;
case TS_PDUTYPE2_CONTROL:
CA_ReceivedPacket((PTS_CONTROL_PDU)pPkt, DataLength,
localID);
break;
case TS_PDUTYPE2_FONTLIST:
USR_ProcessRemoteFonts((PTS_FONT_LIST_PDU)pPkt,
DataLength, localID);
break;
case TS_PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST:
// Persistent bitmap cache key list PDU.
SBC_HandlePersistentCacheList(
(TS_BITMAPCACHE_PERSISTENT_LIST *)pPkt, DataLength,
localID);
break;
case TS_PDUTYPE2_BITMAPCACHE_ERROR_PDU:
// For future support of bitmap error PDU
SBC_HandleBitmapCacheErrorPDU(
(TS_BITMAPCACHE_ERROR_PDU *)pPkt, DataLength,
localID);
break;
case TS_PDUTYPE2_OFFSCRCACHE_ERROR_PDU:
// offscreen cache error PDU
SBC_HandleOffscrCacheErrorPDU(
(TS_OFFSCRCACHE_ERROR_PDU *)pPkt, DataLength,
localID);
break;
#ifdef DRAW_NINEGRID
case TS_PDUTYPE2_DRAWNINEGRID_ERROR_PDU:
// drawninegrid error PDU
SBC_HandleDrawNineGridErrorPDU(
(TS_DRAWNINEGRID_ERROR_PDU *)pPkt, DataLength,
localID);
break;
#endif
#ifdef DRAW_GDIPLUS
case TS_PDUTYPE2_DRAWGDIPLUS_ERROR_PDU:
SBC_HandleDrawGdiplusErrorPDU(
(TS_DRAWGDIPLUS_ERROR_PDU *)pPkt, DataLength,
localID);
break;
#endif
case TS_PDUTYPE2_REFRESH_RECT:
WDW_InvalidateRect(m_pTSWd, (PTS_REFRESH_RECT_PDU)pPkt,
DataLength);
break;
case TS_PDUTYPE2_SUPPRESS_OUTPUT:
UP_ReceivedPacket((PTS_SUPPRESS_OUTPUT_PDU)pPkt,
DataLength, localID);
break;
case TS_PDUTYPE2_SHUTDOWN_REQUEST:
DCS_ReceivedShutdownRequestPDU((PTS_SHAREDATAHEADER)pPkt,
DataLength, localID);
break;
default:
/********************************************************/
/* Unknown pduType2 */
/********************************************************/
TRC_ERR((TB, "Unknown data packet %d", pduType2));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_UnknownPDUType2,
(BYTE *)&pduType2,
sizeof(pduType2));
break;
}
}
else
{
TRC_NRM((TB, "Synchronize PDU"));
SCSynchronizePDU(netPersonID, priority,(PTS_SYNCHRONIZE_PDU)pPkt);
}
}
else
{
/********************************************************************/
/* Control PDU. Not critical so throw to handler. */
/********************************************************************/
TRC_DBG((TB, "Control PDU"));
SCReceivedControlPacket(netPersonID, priority, (PVOID)pPkt,
DataLength);
pduOK = TRUE;
}
DC_EXIT_POINT:
if (!pduOK)
{
/********************************************************************/
/* An out-of-sequence packet has been received. It's possible we */
/* might receive an input PDU just after we brought the share down, */
/* so don't kick off the client for that. */
/********************************************************************/
TRC_ERR((TB, "Out-of-sequence packet %hx/%hd received in state %d",
pduType, pduType2, scState));
if ((pduType == TS_PDUTYPE_DATAPDU) &&
(pduType2 == TS_PDUTYPE2_INPUT))
{
TRC_ERR((TB, "Not kicking client off: it was only an input PDU"));
}
else
{
/****************************************************************/
/* Disconnect the client. */
/****************************************************************/
wchar_t detailData[(sizeof(pduType) * 2) +
(sizeof(pduType2) * 2) +
(sizeof(scState) * 2) + 3];
TRC_ERR((TB, "Kicking client off"));
swprintf(detailData,
L"%hx %hx %x",
pduType,
pduType2,
scState);
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_DataPDUSequence,
(BYTE *)&detailData,
sizeof(detailData));
}
}
DC_END_FN();
return;
// Error handling.
ShortPDU:
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShareDataTooShort, pPkt, DataLength);
DC_END_FN();
} /* SC_OnDataReceived */
/****************************************************************************/
/* Name: SC_OnShadowDataReceived */
/* */
/* Purpose: Callback from SM for shadow data receive path. Main purpose */
/* is to scan for the shadow hotkey being pressed. */
/* */
/* Params: netPersonID - MCS UserID of the data sender */
/* priority - MCS data priority the data was sent on */
/* pPkt - pointer to start of packet */
/****************************************************************************/
void RDPCALL ShareClass::SC_OnShadowDataReceived(
PBYTE pPkt,
NETPERSONID netPersonID,
unsigned DataLength,
UINT32 priority)
{
UINT16 pduType, pduType2;
LOCALPERSONID localID;
BOOLEAN bShadowData = TRUE;
NTSTATUS status;
DC_BEGIN_FN("SC_OnShadowDataReceived");
TRC_NRM((TB, "Shadow data Received"));
// If this is the primary client stack, then process the data and figure out
// whether or not the PDU should be passed on to the target. Else this is
// a passthru stack and we should forward PDUs regardless.
// Note IM_DecodeFastPathInput() performs this logic for fast-path input.
if (m_pTSWd->StackClass == Stack_Primary) {
// check that we have enough data before we deref the pduType.
if (sizeof(TS_SHARECONTROLHEADER) > DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_SHARECONTROLHEADER %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
pduType = (((PTS_SHARECONTROLHEADER)pPkt)->pduType) & TS_MASK_PDUTYPE;
TRC_NRM((TB, "[%u]SC packet type %u", netPersonID, pduType));
if (pduType == TS_PDUTYPE_DATAPDU)
{
/********************************************************************/
/* Data PDU. This is critical path so decode inline. */
/********************************************************************/
if (sizeof(TS_SHAREDATAHEADER) > DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_SHAREDATAHEADER %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
pduType2 = ((PTS_SHAREDATAHEADER)pPkt)->pduType2;
#ifdef DC_DEBUG
{
/****************************************************************/
/* Ok, this is ugly. I'm trying to trace the PDU name without */
/* - searching a table */
/* - implementing a sparse table */
/* - a huge if ... else if switch. */
/* If you don't like it or don't understand it, ask MF. Before */
/* you get too het up, bear in mind the #ifdef DC_DEBUG above. */
/****************************************************************/
unsigned pduIndex =
(pduType2 == TS_PDUTYPE2_UPDATE) ? 1 :
(pduType2 == TS_PDUTYPE2_FONT) ? 2 :
(pduType2 == TS_PDUTYPE2_CONTROL) ? 3 :
((pduType2 >= TS_PDUTYPE2_WINDOWACTIVATION) &&
(pduType2 <= TS_PDUTYPE2_BITMAPCACHE_ERROR_PDU)) ?
pduType2 - 19 : 0;
if (pduIndex != (TS_PDUTYPE2_INPUT - 19)) {
TRC_NRM((TB, "Shadow DataPDU type %s (%d)",
scPktName[pduIndex], pduType2));
}
}
#endif
/********************************************************************/
/* First check for synchronize packets */
/********************************************************************/
if (pduType2 != TS_PDUTYPE2_SYNCHRONIZE)
{
/****************************************************************/
/* Now check that this priority has been synchronized */
/****************************************************************/
localID = SC_NetworkIDToLocalID(netPersonID);
if (!scPartyArray[localID].sync[priority])
{
TRC_ALT((TB,
"[%d] {%d} Discarding packet on unsynched priority %d",
netPersonID, localID, priority));
DC_QUIT;
}
/****************************************************************/
/* All is well - pass the packet to its destination */
/****************************************************************/
switch (pduType2)
{
case TS_PDUTYPE2_INPUT:
{
// Note that changes to this path should be examined
// in light of fast-path input (IM_DecodeFastPathInput).
IM_PlaybackEvents((PTS_INPUT_PDU)pPkt, DataLength);
}
break;
case TS_PDUTYPE2_SUPPRESS_OUTPUT:
{
/********************************************************/
/* A SuppressOutputPDU. Don't process it as it would */
/* disable output for the shadow target as well! */
/********************************************************/
TRC_ALT((TB, "Not forwarding TS_PDUTYPE2_SUPPRESS_OUTPUT"));
bShadowData = FALSE;
}
break;
case TS_PDUTYPE2_SHUTDOWN_REQUEST:
{
/********************************************************/
/* A ShutdownRequestPDU. Process locally only. It */
/* should apply to the shadow client and not the target.*/
/********************************************************/
// this does not actually use the pPkt member and we
// have at lest TS_SHAREDATAHEADER left
DCS_ReceivedShutdownRequestPDU((PTS_SHAREDATAHEADER)pPkt,
DataLength, localID);
TRC_ALT((TB, "Not forwarding TS_PDUTYPE2_SHUTDOWN_REQUEST"));
bShadowData = FALSE;
}
break;
case TS_PDUTYPE2_FONTLIST:
{
if (sizeof(TS_FONT_LIST_PDU) - sizeof(TS_FONT_ATTRIBUTE)
> DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_FONT_LIST_PDU %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
PTS_FONT_LIST_PDU pFontListPDU = (PTS_FONT_LIST_PDU) pPkt;
/********************************************************/
/* NT5 server doesn't do anything with a font packet so */
/* send the smallest possible packet accross the pipe. */
/********************************************************/
DataLength = sizeof(TS_FONT_LIST_PDU) -
sizeof(TS_FONT_ATTRIBUTE);
pFontListPDU->shareDataHeader.shareControlHeader.totalLength =
(UINT16)DataLength;
pFontListPDU->shareDataHeader.generalCompressedType = 0;
pFontListPDU->shareDataHeader.generalCompressedLength = 0;
pFontListPDU->numberFonts = 0;
pFontListPDU->totalNumFonts = 0;
pFontListPDU->entrySize = sizeof(TS_FONT_ATTRIBUTE);
}
break;
// Forward all other PDUs until we learn otherwise!
default:
break;
}
}
else
{
// TODO: Why are we processing this?
TRC_ALT((TB, "Shadow Synchronize PDU"));
SCSynchronizePDU(netPersonID, priority,(PTS_SYNCHRONIZE_PDU)pPkt);
}
}
else {
/********************************************************************/
/* Need to watch for confirm actives so we can determine how to */
/* terminate the shadow session. */
/********************************************************************/
if (sizeof(TS_FLOW_PDU) > DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_SHAREDATAHEADER %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
if (((PTS_FLOW_PDU)pPkt)->flowMarker != TS_FLOW_MARKER)
{
// here we already checked that we have enough buffer
// for a TS_SHARECONTROLHEADER
pduType = ((PTS_SHARECONTROLHEADER)pPkt)->pduType & TS_MASK_PDUTYPE;
switch (pduType)
{
case TS_PDUTYPE_CONFIRMACTIVEPDU:
TRC_ALT((TB, "Shadow Client ConfirmActivePDU - shadow active!"));
m_pTSWd->bInShadowShare = TRUE;
break;
default:
break;
}
}
}
}
else if (m_pTSWd->StackClass == Stack_Passthru) {
// If we see a demand active and no server certificate has been received
// then wake up rdpwsx.
// check that we have enough data before we deref the flow marker
if (sizeof(TS_FLOW_PDU) > DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_FLOW_PDU %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
if (((PTS_FLOW_PDU)pPkt)->flowMarker != TS_FLOW_MARKER) {
// Check that we have enough data before we deref the
// TS_SHARECONTROLHEADER marker.
// As of today we know exaclty that we have enough buffer
// size sizeof(TS_FLOW_PDU) is grater then sizeof TS_SHARECONTROLHEADER.
if (sizeof(TS_SHARECONTROLHEADER) > DataLength) {
TRC_ERR((TB,"The PDU is not long enough to contain the TS_SHARECONTROLHEADER %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShadowDataTooShort,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
pduType = ((PTS_SHARECONTROLHEADER)pPkt)->pduType & TS_MASK_PDUTYPE;
switch (pduType)
{
case TS_PDUTYPE_DEMANDACTIVEPDU:
TRC_ALT((TB, "Passthru stack - demand active!"));
SC_SaveServerCert(NULL, 0);
m_pTSWd->bInShadowShare = TRUE;
break;
case TS_PDUTYPE_SERVERCERTIFICATEPDU:
// check that we have enough data before we pass the
// TS_SERVER_CERTIFICATE_PDU marker.
if (sizeof(TS_SERVER_CERTIFICATE_PDU) > DataLength) {
TRC_ERR((TB,
"The PDU is not long enough to contain the TS_SERVER_CERTIFICATE_PDU %d",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_BadServerCertificateData,
(PBYTE)pPkt, DataLength);
DC_QUIT;
}
TRC_ALT((TB, "ServerCertificatePDU"));
SC_SaveServerCert((PTS_SERVER_CERTIFICATE_PDU) pPkt, DataLength);
bShadowData = FALSE;
break;
default:
break;
}
}
}
// Forward PDU to shadow if it's OK.
// Note IM_DecodeFastPathInput() performs this logic for fast-path input.
if (bShadowData) {
TRC_NRM((TB, "Forwarding shadow data: %ld", DataLength));
status = IcaRawInput(m_pTSWd->pContext,
NULL,
pPkt,
DataLength);
if (!NT_SUCCESS(status)) {
TRC_ERR((TB, "Failed shadow input data [%ld]: %x",
DataLength, status));
}
}
DC_EXIT_POINT:
DC_END_FN();
} /* SC_OnShadowDataReceived */
/****************************************************************************/
/* Name: SC_AllocBuffer */
/* */
/* Purpose: Allocate a send buffer */
/* */
/* Returns: TRUE - buffer allocated OK */
/* FALSE - failed to allocate buffer */
/* */
/* Params: ppPkt - (returned) pointer to allocated packet */
/* pktLen - length of packet required */
/* priority - priority on which buffer will be used */
/****************************************************************************/
NTSTATUS __fastcall SHCLASS SC_AllocBuffer(PPVOID ppPkt, UINT32 pktLen)
{
NTSTATUS status;
DC_BEGIN_FN("SC_AllocBuffer");
// fWait is TRUE means that we will always wait for a buffer to be avail
status = SM_AllocBuffer(scPSMHandle, ppPkt, pktLen, TRUE, FALSE);
DC_END_FN();
return(status);
} /* SC_AllocBuffer */
/****************************************************************************/
/* Name: SC_FreeBuffer */
/* */
/* Purpose: Free an unused send buffer */
/* */
/* Params: pPkt - pointer to buffer to free */
/* pktLen - size of the packet */
/* priority - priority buffer was allocated on */
/****************************************************************************/
void __fastcall SHCLASS SC_FreeBuffer(PVOID pPkt)
{
SM_FreeBuffer(scPSMHandle, pPkt, FALSE);
} /* SC_FreeBuffer */
/****************************************************************************/
/* Name: SC_SendData */
/* */
/* Purpose: Send a packet */
/* */
/* Returns: TRUE - packet sent OK */
/* FALSE - failed to send packet */
/* */
/* Params: pPkt - packet to send */
/* dataLen - length of packet */
/* pduLen - length of PDU : this will be used as the length */
/* of the packet if it is non-zero */
/* priority - priority (0 = all priorities) */
/* personID - person to send packet to (0 = all persons) */
/****************************************************************************/
BOOL RDPCALL ShareClass::SC_SendData(
PTS_SHAREDATAHEADER pPkt,
UINT32 dataLen,
UINT32 pduLen,
UINT32 priority,
NETPERSONID personID)
{
BOOL rc;
DC_BEGIN_FN("SC_SendData");
/************************************************************************/
/* Fill in the Share control and data header(s) if this is a single PDU */
/* */
/* Since we can send multiple PDUs per packet, the total length of data */
/* to send and the PDU length are not always the same. Where they are */
/* not, each PDU will have had its length (and compression) set up as */
/* it was assembled and we should not interfere here! */
/************************************************************************/
pPkt->shareControlHeader.pduType = TS_PDUTYPE_DATAPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16)scUserID;
if (pduLen != 0)
{
pPkt->shareControlHeader.totalLength = (UINT16)pduLen;
// Fill in the Share data header.
pPkt->shareID = scShareID;
pPkt->streamID = (BYTE)priority;
pPkt->uncompressedLength = (UINT16)pduLen;
pPkt->generalCompressedType = 0;
pPkt->generalCompressedLength = 0;
m_pTSWd->pProtocolStatus->Output.CompressedBytes += pduLen;
}
// Send with false for fast-path flag.
rc = SM_SendData(scPSMHandle, (PVOID)pPkt, dataLen, TS_HIGHPRIORITY, 0,
FALSE, RNS_SEC_ENCRYPT, FALSE);
if (!rc)
{
TRC_ERR((TB, "Failed to send %d bytes", dataLen));
}
DC_END_FN();
return(rc);
} /* SC_SendData */
/****************************************************************************/
/* SC_GetMyNetworkPersonID */
/* */
/* Returns the network person ID for this machine. */
/****************************************************************************/
NETPERSONID RDPCALL SHCLASS SC_GetMyNetworkPersonID(void)
{
NETPERSONID rc = 0;
DC_BEGIN_FN("SC_GetMyNetworkPersonID");
SC_CHECK_STATE(SCE_GETMYNETWORKPERSONID);
rc = scPartyArray[0].netPersonID;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: SC_KeepAlive */
/* */
/* Purpose: KeepAlive packet send processing */
/* */
/* Returns: TRUE/FALSE */
/* */
/* Operation: Send a KeepAlive PDU if required */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_KeepAlive(void)
{
BOOL rc = FALSE;
PTS_FLOW_PDU pFlowTestPDU;
DC_BEGIN_FN("SC_KeepAlive");
TRC_NRM((TB, "Time for a KeepAlive PDU"));
if (scState == SCS_IN_SHARE) {
// only send the FlowTestPDU if we are in the share
// fWait is FALSE means that we will not wait for a buffer to be available
// If the buffer is full, that means there are packets waiting to be send out,
// so there is no need to send out keep alive packet anyway.
if ( STATUS_SUCCESS == SM_AllocBuffer(scPSMHandle, (PPVOID) (&pFlowTestPDU), sizeof(*pFlowTestPDU), FALSE, FALSE) ) {
pFlowTestPDU->flowMarker = TS_FLOW_MARKER;
pFlowTestPDU->pduType = TS_PDUTYPE_FLOWTESTPDU;
pFlowTestPDU->flowIdentifier = 0;
pFlowTestPDU->flowNumber = 0;
pFlowTestPDU->pduSource = (TSUINT16) scUserID;
if (SM_SendData(scPSMHandle, pFlowTestPDU, sizeof(*pFlowTestPDU),
0, 0, FALSE, RNS_SEC_ENCRYPT, FALSE)) {
TRC_NRM((TB, "Sent a KeepAlive PDU to the client"));
rc = TRUE;
}
else {
TRC_ERR((TB, "Failed to send KeepAlive PDU"));
}
}
else {
TRC_ERR((TB, "Failed to alloc buffer for KeepAlive PDU"));
}
}
else {
TRC_ERR((TB, "In the wrong state: scState=%d, no KeepAlive PDU sent", scState));
}
DC_END_FN();
return rc;
} /* SC_KeepAlive */
/****************************************************************************/
/* Name: SC_RedrawScreen */
/* */
/* Purpose: Redraw the desktop upon request */
/****************************************************************************/
void RDPCALL SHCLASS SC_RedrawScreen(void)
{
NTSTATUS Status;
ICA_CHANNEL_COMMAND Cmd;
DC_BEGIN_FN("SC_RedrawScreen");
TRC_NRM((TB, "Call IcaChannelInput for screen redraw"));
// redraw the whole desktop
Cmd.Header.Command = ICA_COMMAND_REDRAW_RECTANGLE;
Cmd.RedrawRectangle.Rect.Left = 0;
Cmd.RedrawRectangle.Rect.Top = 0;
Cmd.RedrawRectangle.Rect.Right = (short) m_desktopWidth;
Cmd.RedrawRectangle.Rect.Bottom = (short) m_desktopHeight;
/************************************************************/
// Pass the filled in structure to ICADD.
/************************************************************/
Status = IcaChannelInput(m_pTSWd->pContext, Channel_Command, 0, NULL,
(unsigned char *) &Cmd, sizeof(ICA_CHANNEL_COMMAND));
if (Status == STATUS_SUCCESS) {
TRC_NRM((TB, "Issued IcaChannelInput for Screen Redraw"));
}
else {
TRC_ERR((TB, "Error issuing an IcaChannelInput, status=%lu", Status));
}
DC_END_FN();
}
/****************************************************************************/
/* SC_LocalIDToNetworkID() */
/* */
/* Converts a local person ID to the corresponding network person ID. */
/* */
/* PARAMETERS: */
/* */
/* localPersonID - a local person ID. This must be a valid local person */
/* ID. */
/* */
/* RETURNS: a network person ID. */
/****************************************************************************/
NETPERSONID RDPCALL SHCLASS SC_LocalIDToNetworkID(
LOCALPERSONID localPersonID)
{
DC_BEGIN_FN("SC_LocalIDToNetworkID");
SC_CHECK_STATE(SCE_LOCALIDTONETWORKID);
/************************************************************************/
/* Validate the localPersonID. */
/************************************************************************/
TRC_ASSERT( (SC_IsLocalPersonID(localPersonID)),
(TB,"Invalid {%d}", localPersonID) );
/************************************************************************/
/* Return this party's personID. */
/************************************************************************/
TRC_DBG((TB, "localID %u is network %hu", (unsigned)localPersonID,
scPartyArray[localPersonID].netPersonID));
DC_EXIT_POINT:
DC_END_FN();
return(scPartyArray[localPersonID].netPersonID);
}
/****************************************************************************/
/* SC_IsLocalPersonID() */
/* */
/* Validates a local person ID */
/* */
/* PARAMETERS */
/* */
/* localPersonID - the local person ID to validate */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_IsLocalPersonID(LOCALPERSONID localPersonID)
{
BOOL rc = FALSE;
DC_BEGIN_FN("SC_IsLocalPersonID");
SC_CHECK_STATE(SCE_ISLOCALPERSONID);
/************************************************************************/
/* Return TRUE if the localPersonID is valid, FALSE otherwise. */
/************************************************************************/
rc = ((localPersonID < SC_DEF_MAX_PARTIES) &&
(scPartyArray[localPersonID].netPersonID)) ? TRUE : FALSE;
DC_EXIT_POINT:
DC_END_FN();
return(rc);
}
/****************************************************************************/
/* SC_IsNetworkPersonID() */
/* */
/* Validates a network person ID */
/* */
/* PARAMETERS */
/* */
/* personID - the network person ID to validate */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_IsNetworkPersonID(NETPERSONID netPersonID)
{
LOCALPERSONID localPersonID;
BOOL rc = FALSE;
DC_BEGIN_FN("SC_IsNetworkPersonID");
SC_CHECK_STATE(SCE_ISNETWORKPERSONID);
/************************************************************************/
/* Check for a zero personID. */
/************************************************************************/
if (netPersonID == 0)
{
DC_QUIT;
}
/************************************************************************/
/* Search for the personID. */
/************************************************************************/
for ( localPersonID = 0;
localPersonID < SC_DEF_MAX_PARTIES;
localPersonID++ )
{
if (netPersonID == scPartyArray[localPersonID].netPersonID)
{
rc = TRUE;
DC_QUIT;
}
}
DC_EXIT_POINT:
DC_END_FN();
return(rc);
}
/****************************************************************************/
/* SC_SetCapabilities() */
/* */
/* Sets the SC's capabilities at start of day. */
/* This function is required because the SC is initialized before the CPC, */
/* so cannot register its capabilities in SC_Init(). */
/****************************************************************************/
void RDPCALL SHCLASS SC_SetCapabilities(void)
{
TS_SHARE_CAPABILITYSET caps;
DC_BEGIN_FN("SC_SetCapabilities");
/************************************************************************/
/* Register capabilities. */
/************************************************************************/
caps.capabilitySetType = TS_CAPSETTYPE_SHARE;
caps.nodeID = (TSUINT16)scUserID;
CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&caps,
sizeof(TS_SHARE_CAPABILITYSET));
DC_END_FN();
}
/****************************************************************************/
/* SC_SetCombinedCapabilities() */
/* */
/* Sets the share's combined capabilities to a predetermined set of values. */
/* This is used by shadow stacks so that the host's capabilities start with */
/* the value of the previous stack. */
/****************************************************************************/
void RDPCALL SHCLASS SC_SetCombinedCapabilities(UINT cbCapsSize,
PTS_COMBINED_CAPABILITIES pCaps)
{
DC_BEGIN_FN("SC_SetCombinedCapabilities");
/************************************************************************/
/* Initialize capabilities. */
/************************************************************************/
CPC_SetCombinedCapabilities(cbCapsSize, pCaps);
DC_END_FN();
}
/****************************************************************************/
/* SC_GetCombinedCapabilities() */
/* */
/* Used during initiation of a shadow to gather the currently active set of */
/* combined capabilities for the shadow client. These will be passed to */
/* the shadow target for negotiation. */
/****************************************************************************/
void RDPCALL SHCLASS SC_GetCombinedCapabilities(LOCALPERSONID localID,
PUINT pcbCapsSize,
PTS_COMBINED_CAPABILITIES *ppCaps)
{
DC_BEGIN_FN("SC_GetCombinedCapabilities");
/************************************************************************/
/* Initialize capabilities. */
/************************************************************************/
CPC_GetCombinedCapabilities(localID, pcbCapsSize, ppCaps);
DC_END_FN();
}
/****************************************************************************/
/* Name: SC_AddPartyToShare */
/* */
/* Purpose: Add another party to the share such that we get a new set of */
/* negotiated capabilities. This function is used when a new */
/* shadow connects. */
/* */
/* Returns: none */
/* */
/* Params: netPersonID - ID of sender of capabilities */
/* pCaps - new capabilities for person */
/* capsLength - length of capability sets */
/* */
/* Operation: see purpose */
/****************************************************************************/
NTSTATUS RDPCALL SHCLASS SC_AddPartyToShare(
NETPERSONID netPersonID,
PTS_COMBINED_CAPABILITIES pCaps,
unsigned capsLength)
{
LOCALPERSONID localPersonID;
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
NTSTATUS status = STATUS_SUCCESS;
PTS_GENERAL_CAPABILITYSET pGenCapSet;
unsigned MPPCCompressionLevel;
DC_BEGIN_FN("SC_AddPartyToShare");
/************************************************************************/
/* Reject this party if it will exceed the maximum number of parties */
/* allowed in a share. (Not required for RNS V1.0, but left in as it */
/* doesn't do any harm). */
/************************************************************************/
if (scNumberInShare == SC_DEF_MAX_PARTIES)
{
TRC_ERR((TB, "Reached max parties in share %d",
SC_DEF_MAX_PARTIES));
status = STATUS_DEVICE_BUSY;
DC_QUIT;
}
/************************************************************************/
/* Calculate a localPersonID for the remote party and store their */
/* details in the party array. */
/************************************************************************/
for ( localPersonID = 1;
localPersonID < SC_DEF_MAX_PARTIES;
localPersonID++ )
{
if (scPartyArray[localPersonID].netPersonID == 0)
{
/****************************************************************/
/* Found an empty slot. */
/****************************************************************/
TRC_NRM((TB, "Allocated local person ID %d", localPersonID));
break;
}
}
/************************************************************************/
/* Even though scNumberInShare is checked against SC_DEF_MAX_PARTIES */
/* above, the loop above might still not find an empty slot. */
/************************************************************************/
if (SC_DEF_MAX_PARTIES <= localPersonID)
{
TRC_ABORT((TB, "Couldn't find room to store local person"));
DC_QUIT;
}
/************************************************************************/
/* Store the new person's details */
/************************************************************************/
scPartyArray[localPersonID].netPersonID = netPersonID;
memcpy(scPartyArray[localPersonID].name, L"Shadow", sizeof(L"Shadow"));
memset(scPartyArray[localPersonID].sync,
0,
sizeof(scPartyArray[localPersonID].sync));
TRC_NRM((TB, "{%d} person name %s",
(unsigned)localPersonID, scPartyArray[localPersonID].name));
/************************************************************************/
/* Call the XX_PartyJoiningShare() functions for the remote party. */
/************************************************************************/
if (!SCCallPartyJoiningShare(localPersonID,
capsLength,
(PVOID) pCaps,
acceptedArray,
scNumberInShare))
{
/********************************************************************/
/* Some component rejected the remote party. */
/********************************************************************/
TRC_ERR((TB, "Remote party rejected"));
SCCallPartyLeftShare(localPersonID,
acceptedArray,
scNumberInShare );
scPartyArray[localPersonID].netPersonID = 0;
status = STATUS_REVISION_MISMATCH;
DC_QUIT;
}
// For shadow connections, we must force fast-path output off to prevent
// any fast-path encoding from going across the cross-server pipe.
// This is to maintain backward compatibility with TS5 beta 3.
// Checking for m_pTSWd->shadowState in SCPartyJoiningShare() is not
// sufficient since SHADOW_TARGET is likely not to have been set yet.
// Note we have to update *all* precalculated header sizes, in SC and
// UP.
TRC_ALT((TB,"Forcing fast-path output off in shadow"));
scUseFastPathOutput = FALSE;
scUpdatePDUHeaderSpace = sizeof(TS_SHAREDATAHEADER);
UP_UpdateHeaderSize();
// Update the compression level.
// assume no compression
scUseShadowCompression = FALSE;
if (pCaps != NULL) {
pGenCapSet = (PTS_GENERAL_CAPABILITYSET) WDW_GetCapSet(
m_pTSWd, TS_CAPSETTYPE_GENERAL, pCaps, capsLength);
if (pGenCapSet != NULL) {
// update the compression capability
if (m_pTSWd->bCompress &&
(pGenCapSet->extraFlags & TS_SHADOW_COMPRESSION_LEVEL) &&
(m_pTSWd->pMPPCContext->ClientComprType == pGenCapSet->generalCompressionLevel)) {
MPPCCompressionLevel = m_pTSWd->pMPPCContext->ClientComprType;
scUseShadowCompression = TRUE;
}
}
}
if (scUseShadowCompression) {
// the compression history will be flushed
m_pTSWd->bFlushed = PACKET_FLUSHED;
// the compression will restart over
initsendcontext(m_pTSWd->pMPPCContext, MPPCCompressionLevel);
}
/************************************************************************/
/* The remote party is now in the share. */
/************************************************************************/
scNumberInShare++;
TRC_ALT((TB, "Number in share %d", (unsigned)scNumberInShare));
DC_EXIT_POINT:
DC_END_FN();
return status;
} /* SC_AddPartyToShare */
/****************************************************************************/
/* Name: SC_RemovePartyFromShare */
/* */
/* Purpose: Remove a party from the share such that we get a new set of */
/* negotiated capabilities. This function is used when a shadow */
/* disconnects from the share. */
/* */
/* Params: localID - ID of person to remove. */
/****************************************************************************/
NTSTATUS RDPCALL SHCLASS SC_RemovePartyFromShare(NETPERSONID netPersonID)
{
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
NTSTATUS status = STATUS_SUCCESS;
UINT i;
DC_BEGIN_FN("SC_RemovePartyFromShare");
// Map network ID to the corresponding local ID
for (i = SC_DEF_MAX_PARTIES - 1; i > 0; i--)
{
if (scPartyArray[i].netPersonID != netPersonID)
continue;
else
break;
}
// Call PLS for remote person
if (scPartyArray[i].netPersonID == netPersonID) {
memset(acceptedArray, TRUE, sizeof(acceptedArray));
TRC_ALT((TB, "Party %d left Share", i));
scNumberInShare--;
SCCallPartyLeftShare(i, acceptedArray, scNumberInShare);
scPartyArray[i].netPersonID = 0;
memset(&(scPartyArray[i]), 0, sizeof(*scPartyArray));
}
else {
status = STATUS_INVALID_PARAMETER;
TRC_ERR((TB, "Unable to find netID: %ld. Party not removed!",
netPersonID));
}
scUseShadowCompression = FALSE;
DC_END_FN();
return status;
}
/****************************************************************************/
/* SC_NetworkIDToLocalID() */
/* */
/* Converts a network person ID to the corresponding local person ID. */
/* */
/* PARAMETERS: */
/* personID - a network person ID. This must be a valid network person ID. */
/* */
/* RETURNS: a local person ID. */
/****************************************************************************/
LOCALPERSONID __fastcall SHCLASS SC_NetworkIDToLocalID(
NETPERSONID netPersonID)
{
LOCALPERSONID localID;
LOCALPERSONID rc = 0;
DC_BEGIN_FN("SC_NetworkIDToLocalID");
/************************************************************************/
/* Fastpath if same ID passed in as last time. */
/************************************************************************/
if (netPersonID == scLastNetID)
{
TRC_DBG((TB, "Same Network ID - return same local ID"));
DC_END_FN();
return(scLastLocID);
}
SC_CHECK_STATE(SCE_NETWORKIDTOLOCALID);
TRC_ASSERT((netPersonID), (TB, "Zero personID"));
/************************************************************************/
/* Search for the personID. */
/************************************************************************/
if (SC_ValidateNetworkID(netPersonID, &localID))
{
rc = localID;
DC_QUIT;
}
TRC_ABORT((TB, "Invalid [%u]", (unsigned)netPersonID));
DC_EXIT_POINT:
scLastNetID = netPersonID;
scLastLocID = rc;
DC_END_FN();
return(rc);
}
/****************************************************************************/
/* SC_ValidateNetworkID() */
/* */
/* Checks that a network ID is valid and returns the local ID corresponding */
/* to it if it is. */
/* */
/* PARAMETERS: */
/* netPersonID - a network person ID. */
/* pLocalPersonID - (returned) corresponding local ID if network ID valid */
/* (can pass NULL if you do not want local ID) */
/* */
/* RETURNS: */
/* TRUE - Network ID is valid FALSE - Network ID is not valid */
/****************************************************************************/
BOOL RDPCALL SHCLASS SC_ValidateNetworkID(NETPERSONID netPersonID,
LOCALPERSONID * pLocalID)
{
BOOL rc = FALSE;
LOCALPERSONID localID;
DC_BEGIN_FN("SC_ValidateNetworkID");
/************************************************************************/
/* Search for the personID. */
/************************************************************************/
for (localID = 0; localID < SC_DEF_MAX_PARTIES; localID++)
{
if (netPersonID == scPartyArray[localID].netPersonID)
{
/****************************************************************/
/* Found required person, set return values and quit */
/****************************************************************/
rc = TRUE;
if (pLocalID)
{
*pLocalID = localID;
}
break;
}
}
TRC_DBG((TB, "Network ID 0x%04u rc = 0x%04x (localID=%u)",
netPersonID,
rc,
localID));
DC_END_FN();
return(rc);
}
/****************************************************************************/
// SC_FlushAndAllocPackage
//
// Combines a forced network flush of the current package contents with
// an allocation of the standard package buffer size.
// Returns FALSE on allocation failure.
/****************************************************************************/
NTSTATUS __fastcall ShareClass::SC_FlushAndAllocPackage(PPDU_PACKAGE_INFO pPkgInfo)
{
NTSTATUS status = STATUS_SUCCESS;
DC_BEGIN_FN("SC_FlushAndAllocPackage");
if (pPkgInfo->cbLen) {
if (pPkgInfo->cbInUse) {
// Send the package contents.
if (scUseFastPathOutput)
// Send with fast-path flag.
SM_SendData(scPSMHandle, (PVOID)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, TS_HIGHPRIORITY, 0, TRUE, RNS_SEC_ENCRYPT, FALSE);
else
SC_SendData((PTS_SHAREDATAHEADER)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, 0, PROT_PRIO_MISC, 0);
}
else {
// or free the buffer if it's been allocated but not used.
TRC_NRM((TB, "Freeing unused package"));
SC_FreeBuffer(pPkgInfo->pOutBuf);
}
}
// We always allocate 8K (unless the bytes needed are greater) to reduce
// the number of buffers we allocate in the OutBuf pool. It is up to
// the package users to pack to wire packet sizes within this
// block.
status = SC_AllocBuffer(&(pPkgInfo->pOutBuf), sc8KOutBufUsableSpace);
if ( STATUS_SUCCESS == status ) {
// If compression is not enabled, then output directly into the
// OutBuf, else output into a temporary buffer.
if (!m_pTSWd->bCompress)
pPkgInfo->pBuffer = (BYTE *)pPkgInfo->pOutBuf;
else
pPkgInfo->pBuffer = m_pTSWd->pCompressBuffer;
pPkgInfo->cbLen = sc8KOutBufUsableSpace;
pPkgInfo->cbInUse = 0;
}
else {
pPkgInfo->cbLen = 0;
pPkgInfo->cbInUse = 0;
pPkgInfo->pBuffer = NULL;
TRC_NRM((TB, "could not allocate package buffer"));
}
DC_END_FN();
return status;
}
/****************************************************************************/
/* SC_GetSpaceInPackage */
/* */
/* Purpose: Ensure there's enough space in a PDU package for the data */
/* sending the existing package if necessary */
/* */
/* Returns: pointer to the space, or NULL if none available */
/* FALSE - no space available (alloc failed) */
/* */
/* Params: pPkgInfo - pointer to package info */
/* cbNeeded - space needed in package */
/****************************************************************************/
PBYTE __fastcall SHCLASS SC_GetSpaceInPackage(
PPDU_PACKAGE_INFO pPkgInfo,
unsigned cbNeeded)
{
PBYTE pSpace;
unsigned cbPackageSize;
NTSTATUS status = STATUS_SUCCESS;
unsigned RealAllocSize;
DC_BEGIN_FN("SC_GetSpaceInPackage");
// Handle the most common case where we have an allocated buffer and
// enough space.
if (pPkgInfo->cbLen) {
if (cbNeeded <= (pPkgInfo->cbLen - pPkgInfo->cbInUse))
goto EnoughSpace;
// We have a buffer allocated, but from the fast-path check above
// we know we don't have enough space. Send what we have.
if (pPkgInfo->cbInUse != 0) {
TRC_NRM((TB, "Not enough space - sending current package "
"of %u bytes", pPkgInfo->cbInUse));
if (scUseFastPathOutput)
// Send with fast-path flag.
SM_SendData(scPSMHandle, (PVOID)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, TS_HIGHPRIORITY, 0, TRUE, RNS_SEC_ENCRYPT, FALSE);
else
SC_SendData((PTS_SHAREDATAHEADER)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, 0, PROT_PRIO_MISC, 0);
}
else {
// or free the buffer if it's been allocated but not used.
TRC_NRM((TB, "Freeing unused package"));
SC_FreeBuffer(pPkgInfo->pOutBuf);
}
}
// We always allocate 8K (unless the bytes needed are greater) to reduce
// the number of buffers we allocate in the OutBuf pool. It is up to
// the package users to pack to wire packet sizes within this
// block.
cbPackageSize = max(cbNeeded, sc8KOutBufUsableSpace);
status = SC_AllocBuffer(&(pPkgInfo->pOutBuf), cbPackageSize);
if ( STATUS_SUCCESS == status ) {
// If compression is not enabled, then output directly into the
// OutBuf, else output into a temporary buffer.
if (!m_pTSWd->bCompress)
pPkgInfo->pBuffer = (BYTE *)pPkgInfo->pOutBuf;
else
pPkgInfo->pBuffer = m_pTSWd->pCompressBuffer;
pPkgInfo->cbLen = cbPackageSize;
pPkgInfo->cbInUse = 0;
}
else {
pPkgInfo->cbLen = 0;
pPkgInfo->cbInUse = 0;
pPkgInfo->pBuffer = NULL;
TRC_NRM((TB, "could not allocate package buffer"));
pSpace = NULL;
DC_QUIT;
}
EnoughSpace:
pSpace = pPkgInfo->pBuffer + pPkgInfo->cbInUse;
DC_EXIT_POINT:
DC_END_FN();
return pSpace;
} /* SC_GetSpaceInPackage */
/****************************************************************************/
/* SC_AddToPackage */
/* */
/* Purpose: Add the bytes to the PDU package - fills in the per-pdu info */
/* */
/* Params: pPkgInfo - pointer to package info */
/* cbLen - Length of data to add */
/* bShadow - whether or not the data should be shadowed */
/****************************************************************************/
void RDPCALL SHCLASS SC_AddToPackage(
PPDU_PACKAGE_INFO pPkgInfo,
unsigned cbLen,
BOOL bShadow)
{
BYTE *pPktHdr;
UCHAR compressResult;
ULONG CompressedSize;
DC_BEGIN_FN("SC_AddToPackage");
pPktHdr = pPkgInfo->pBuffer + pPkgInfo->cbInUse;
// CompressedSize is the size of the data minus headers.
CompressedSize = cbLen - scUpdatePDUHeaderSpace;
compressResult = 0;
if (m_pTSWd->bCompress) {
UCHAR *pSrcBuf = pPktHdr + scUpdatePDUHeaderSpace;
// Compress or copy the data into the OutBuf.
if ((cbLen > WD_MIN_COMPRESS_INPUT_BUF) &&
(cbLen < MAX_COMPRESS_INPUT_BUF) &&
((m_pTSWd->shadowState == SHADOW_NONE) || scUseShadowCompression)) {
// Copy the header over to the OutBuf
memcpy((BYTE *)pPkgInfo->pOutBuf + pPkgInfo->cbInUse, pPktHdr,
scUpdatePDUHeaderSpace);
pPktHdr = (BYTE *)pPkgInfo->pOutBuf + pPkgInfo->cbInUse;
// Attempt to compress the PDU body directly into the OutBuf
compressResult = compress(pSrcBuf,
pPktHdr + scUpdatePDUHeaderSpace,
&CompressedSize, m_pTSWd->pMPPCContext);
if (compressResult & PACKET_COMPRESSED) {
unsigned CompEst;
// Successful compression - update the compression ratio.
TRC_ASSERT(((cbLen - scUpdatePDUHeaderSpace) >=
CompressedSize),
(TB,"Compression created larger size than uncompr"));
scMPPCUncompTotal += cbLen - scUpdatePDUHeaderSpace;
scMPPCCompTotal += CompressedSize;
if (scMPPCUncompTotal >= SC_SAMPLE_SIZE) {
// Compression estimate is average # of bytes that
// SCH_UNCOMP_BYTES bytes of uncomp data compress to.
CompEst = SCH_UNCOMP_BYTES * scMPPCCompTotal /
scMPPCUncompTotal;
TRC_ASSERT((CompEst <= SCH_UNCOMP_BYTES),
(TB,"MPPC compression estimate above 1.0 (%u)",
CompEst));
scMPPCCompTotal = 0;
scMPPCUncompTotal = 0;
if (CompEst < SCH_COMP_LIMIT)
CompEst = SCH_COMP_LIMIT;
m_pShm->sch.MPPCCompressionEst = CompEst;
TRC_NRM((TB, "New MPPC compr estimate %u", CompEst));
}
compressResult |= m_pTSWd->bFlushed;
m_pTSWd->bFlushed = 0;
}
else if (compressResult & PACKET_FLUSHED) {
// Overran compression history, copy over the original
// uncompressed buffer.
m_pTSWd->bFlushed = PACKET_FLUSHED;
memcpy(pPktHdr + scUpdatePDUHeaderSpace, pSrcBuf,
cbLen - scUpdatePDUHeaderSpace);
m_pTSWd->pProtocolStatus->Output.CompressFlushes++;
}
else {
TRC_ALT((TB, "Compression FAILURE"));
}
}
else {
// This packet is too small or too big, copy over the header and
// uncompressed data.
memcpy((UCHAR *)pPkgInfo->pOutBuf + pPkgInfo->cbInUse,
pPktHdr, cbLen);
pPktHdr = (UCHAR *)pPkgInfo->pOutBuf + pPkgInfo->cbInUse;
}
}
// Fill in the header based on whether we're using fast-path.
if (scUseFastPathOutput) {
if (m_pTSWd->bCompress) {
// Set up compression flags if we're compressing, whether
// or not the compression succeeded above.
pPktHdr[1] = compressResult;
// Size is the size of the payload after this header.
*((PUINT16_UA)(pPktHdr + 2)) = (UINT16)CompressedSize;
}
else {
// Size is the size of the payload after this header.
*((PUINT16_UA)(pPktHdr + 1)) = (UINT16)CompressedSize;
}
}
else {
TS_SHAREDATAHEADER UNALIGNED *pHdr;
pHdr = (TS_SHAREDATAHEADER UNALIGNED *)pPktHdr;
// Fill in the Share control header.
pHdr->shareControlHeader.totalLength = (TSUINT16)
(CompressedSize + scUpdatePDUHeaderSpace);
pHdr->shareControlHeader.pduType = TS_PDUTYPE_DATAPDU |
TS_PROTOCOL_VERSION;
pHdr->shareControlHeader.pduSource = (TSUINT16)scUserID;
// Fill in the Share data header.
pHdr->shareID = scShareID;
pHdr->streamID = PROT_PRIO_MISC;
pHdr->uncompressedLength = (UINT16)cbLen;
pHdr->generalCompressedType = (compressResult | m_pTSWd->bFlushed);
pHdr->generalCompressedLength = (TSUINT16)(m_pTSWd->bCompress ?
CompressedSize + scUpdatePDUHeaderSpace : 0);
}
// Advance the usage size past the header and compressed or
// uncompressed data.
pPkgInfo->cbInUse += CompressedSize + scUpdatePDUHeaderSpace;
TRC_ASSERT((pPkgInfo->cbInUse <= pPkgInfo->cbLen),
(TB,"Overflowed package!"));
m_pTSWd->pProtocolStatus->Output.CompressedBytes += CompressedSize +
scUpdatePDUHeaderSpace;
#ifdef DC_HICOLOR
// If shadowing, we need to save this data so that the shadow stack can
// duplicate it.
if ((m_pTSWd->shadowState == SHADOW_TARGET) && bShadow)
{
if (m_pTSWd->pShadowInfo)
{
ULONG dataSize = CompressedSize +
scUpdatePDUHeaderSpace + sizeof(SHADOW_INFO) - 1;
// If we've not started on the extra space, see if this will fit
// in the main space
if ((m_pTSWd->pShadowInfo->messageSizeEx == 0) &&
(m_pTSWd->pShadowInfo->messageSize + dataSize)
<= WD_MAX_SHADOW_BUFFER)
{
memcpy(&m_pTSWd->pShadowInfo->data[m_pTSWd->pShadowInfo->messageSize],
pPktHdr,
CompressedSize + scUpdatePDUHeaderSpace);
TRC_NRM((TB, "Saving shadow data buffer[%ld] += %ld",
m_pTSWd->pShadowInfo->messageSize,
CompressedSize + scUpdatePDUHeaderSpace));
m_pTSWd->pShadowInfo->messageSize += CompressedSize +
scUpdatePDUHeaderSpace;
}
// Nope - will it fit in the extra buffer?
else if ((m_pTSWd->pShadowInfo->messageSizeEx + dataSize)
<= WD_MAX_SHADOW_BUFFER)
{
TRC_ALT((TB, "Using extra shadow space..."));
memcpy(&m_pTSWd->pShadowInfo->data[WD_MAX_SHADOW_BUFFER
+ m_pTSWd->pShadowInfo->messageSizeEx],
pPktHdr,
CompressedSize + scUpdatePDUHeaderSpace);
TRC_NRM((TB, "Saving shadow data bufferEx[%ld] += %ld",
m_pTSWd->pShadowInfo->messageSizeEx,
CompressedSize + scUpdatePDUHeaderSpace));
m_pTSWd->pShadowInfo->messageSizeEx += CompressedSize +
scUpdatePDUHeaderSpace;
}
else
{
TRC_ERR((TB, "Shadow buffer too small: %p[%ld/%ld] + %ld = %ld/%ld",
m_pTSWd->pShadowInfo->data,
m_pTSWd->pShadowInfo->messageSizeEx,
m_pTSWd->pShadowInfo->messageSize,
CompressedSize + scUpdatePDUHeaderSpace,
m_pTSWd->pShadowInfo->messageSize + cbLen,
m_pTSWd->pShadowInfo->messageSizeEx + cbLen));
}
}
}
#else
// If shadowing, we need to save this data so that the shadow stack can
// duplicate it.
if ((m_pTSWd->shadowState == SHADOW_TARGET) && bShadow) {
if (m_pTSWd->pShadowInfo &&
((m_pTSWd->pShadowInfo->messageSize + cbLen +
sizeof(SHADOW_INFO) - 1) <= WD_MAX_SHADOW_BUFFER)) {
memcpy(&m_pTSWd->pShadowInfo->data[m_pTSWd->pShadowInfo->messageSize],
pPktHdr, CompressedSize + scUpdatePDUHeaderSpace);
m_pTSWd->pShadowInfo->messageSize += CompressedSize +
scUpdatePDUHeaderSpace;
TRC_NRM((TB, "Saving shadow data buffer[%ld] += %ld",
m_pTSWd->pShadowInfo->messageSize - CompressedSize -
scUpdatePDUHeaderSpace,
CompressedSize + scUpdatePDUHeaderSpace));
}
else {
TRC_ERR((TB, "Shadow buffer too small: %p[%ld] + %ld = %ld",
m_pTSWd->pShadowInfo->data,
m_pTSWd->pShadowInfo->messageSize,
CompressedSize + scUpdatePDUHeaderSpace,
m_pTSWd->pShadowInfo->messageSize + cbLen));
}
}
#endif
DC_END_FN();
} /* SC_AddToPackage */
/****************************************************************************/
/* SC_FlushPackage */
/* */
/* Purpose: Send any remaining data, or free the buffer if allocated */
/* */
/* Params: pPkgInfo - pointer to package info */
/****************************************************************************/
void RDPCALL SHCLASS SC_FlushPackage(PPDU_PACKAGE_INFO pPkgInfo)
{
DC_BEGIN_FN("SC_FlushPackage");
/************************************************************************/
/* If there's anything there, send it */
/************************************************************************/
if (pPkgInfo->cbInUse > 0) {
// Send the package contents.
if (scUseFastPathOutput)
// Send directly to SM with fast-path flag.
SM_SendData(scPSMHandle, (PVOID)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, TS_HIGHPRIORITY, 0, TRUE, RNS_SEC_ENCRYPT, FALSE);
else
SC_SendData((PTS_SHAREDATAHEADER)pPkgInfo->pOutBuf,
pPkgInfo->cbInUse, 0, PROT_PRIO_MISC, 0);
}
/************************************************************************/
/* If there's nothing in use but a buffer has been allocated, then free */
/* it */
/************************************************************************/
else if ((pPkgInfo->cbLen != 0) && (pPkgInfo->pBuffer != NULL))
SC_FreeBuffer(pPkgInfo->pOutBuf);
// Reset the package info.
pPkgInfo->cbLen = 0;
pPkgInfo->cbInUse = 0;
pPkgInfo->pBuffer = NULL;
pPkgInfo->pOutBuf = NULL;
DC_END_FN();
}
/****************************************************************************/
/* Name: SC_UpdateShm */
/* */
/* Purpose: Update the Shm data with sc data */
/****************************************************************************/
void RDPCALL SHCLASS SC_UpdateShm(void)
{
DC_BEGIN_FN("SC_UpdateShm");
m_pShm->bc.noBitmapCompressionHdr = scNoBitmapCompressionHdr;
DC_END_FN();
}
//
// Accessor for scUseAutoReconnect
// returns TRUE if we can autoreconnect
//
BOOL RDPCALL SHCLASS SC_IsAutoReconnectEnabled()
{
DC_BEGIN_FN("SC_IsAutoReconnectEnabled");
DC_END_FN();
return scUseAutoReconnect;
}