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.
 
 
 
 
 
 

1911 lines
76 KiB

/****************************************************************************/
// aco.cpp
//
// Core class.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <adcg.h>
#define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "aco"
#define TSC_HR_FILEID TSC_HR_ACO_CPP
#include <atrcapi.h>
#include "aco.h"
// Order important
#include "wui.h"
#include "cd.h"
#include "cc.h"
#include "snd.h"
#include "ih.h"
#include "uh.h"
#include "sl.h"
#include "op.h"
#include "rcv.h"
#include "cm.h"
#include "sp.h"
#include "or.h"
#include "autil.h"
#ifdef OS_WINCE
#include <ceconfig.h>
#endif
extern "C"
VOID WINAPI CO_StaticInit(HINSTANCE hInstance)
{
CIH::IH_StaticInit(hInstance);
}
extern "C"
VOID WINAPI CO_StaticTerm()
{
CIH::IH_StaticTerm();
}
CCO::CCO(CObjs* objs)
{
_pClientObjects = objs;
_fCOInitComplete = FALSE;
}
CCO::~CCO()
{
}
//
// API functions
//
/****************************************************************************/
/* Name: CO_Init */
/* */
/* Purpose: Core Initialization */
/* */
/* Params: IN hInstance - the instance handle */
/* IN hwndMain - the handle of the main window */
/* IN hwndContainer - the handle of the container window */
/****************************************************************************/
void DCAPI CCO::CO_Init(HINSTANCE hInstance, HWND hwndMain, HWND hwndContainer)
{
DC_BEGIN_FN("CO_Init");
TRC_ASSERT(_pClientObjects, (TB,_T("_pClientObjects is NULL")));
_pClientObjects->AddObjReference(CO_OBJECT_FLAG);
//Setup local object pointers
_pUt = _pClientObjects->_pUtObject;
_pUi = _pClientObjects->_pUiObject;
_pSl = _pClientObjects->_pSlObject;
_pUh = _pClientObjects->_pUHObject;
_pRcv = _pClientObjects->_pRcvObject;
_pCd = _pClientObjects->_pCdObject;
_pSnd = _pClientObjects->_pSndObject;
_pCc = _pClientObjects->_pCcObject;
_pIh = _pClientObjects->_pIhObject;
_pOr = _pClientObjects->_pOrObject;
_pSp = _pClientObjects->_pSPObject;
_pOp = _pClientObjects->_pOPObject;
_pCm = _pClientObjects->_pCMObject;
_pClx = _pClientObjects->_pCLXObject;
DC_MEMSET(&_CO, 0, sizeof(_CO));
memset(m_disconnectHRs, 0, sizeof(m_disconnectHRs));
m_disconnectHRIndex = 0;
/************************************************************************/
/* Set UT instance handle */
/************************************************************************/
TRC_NRM((TB, _T("CO setting Instance handle in UT to %p"), hInstance));
_pUi->UI_SetInstanceHandle(hInstance);
_pUt->UT_SetInstanceHandle(hInstance);
/************************************************************************/
/* Set UT Main Window handle. */
/************************************************************************/
TRC_NRM((TB, _T("CO setting Main Window handle in UT to %p"), hwndMain));
_pUi->UI_SetUIMainWindow(hwndMain);
/************************************************************************/
/* Set UT Container Window handle. */
/************************************************************************/
TRC_NRM((TB, _T("CO setting Container Window handle in UT to %p"),
hwndContainer));
_pUi->UI_SetUIContainerWindow(hwndContainer);
//
// Initialize the component decoupler and register the UI (as we are
// running on the UI thread here). CD_Init must be called after
// setting UT.hInstance.
//
_pCd->CD_Init();
_pCd->CD_RegisterComponent(CD_UI_COMPONENT);
COSubclassUIWindows();
// Start the sender thread
_pUt->UT_StartThread(CSND::SND_StaticMain, &_CO.sendThreadID, _pSnd);
_fCOInitComplete = TRUE;
DC_END_FN();
} /* CO_Init */
/****************************************************************************/
/* Name: CO_Term */
/* */
/* Purpose: Core Termination */
/****************************************************************************/
void DCAPI CCO::CO_Term()
{
DC_BEGIN_FN("CO_Term");
if(_fCOInitComplete)
{
// Deregister from the component decoupler
_pCd->CD_UnregisterComponent(CD_UI_COMPONENT);
#ifdef OS_WIN32
// We're on Win32 so terminate the Sender Thread.
// We're called on the UI thread so PUMP messages while
// waiting for the thread to get destroyed
//
//
// Pump messages while waiting since this is the UI thread
//
_pUt->UT_DestroyThread(_CO.sendThreadID, TRUE);
#else
// We're on Win16 so just call SND_Term directly.
SND_Term();
#endif
_pCd->CD_Term();
_pClientObjects->ReleaseObjReference(CO_OBJECT_FLAG);
}
else
{
TRC_DBG((TB,_T("Skipping CO_Term because _fCOInitComplete is false")));
}
DC_END_FN();
} /* CO_Term */
/****************************************************************************/
/* Name: CO_Connect */
/* */
/* Purpose: Connect to an RNS */
/* */
/* Params: IN pConnectStruct - connection information */
/****************************************************************************/
void DCAPI CCO::CO_Connect(PCONNECTSTRUCT pConnectStruct)
{
DC_BEGIN_FN("CO_Connect");
/************************************************************************/
/* Check that the core is initialized. */
/************************************************************************/
TRC_ASSERT((_pUi->UI_IsCoreInitialized()), (TB, _T("Core not initialized")));
/************************************************************************/
/* Call CC with a Connect event */
/************************************************************************/
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Connect),
pConnectStruct,
sizeof(CONNECTSTRUCT));
DC_END_FN();
} /* CO_Connect */
/****************************************************************************/
/* Name: CO_Disconnect */
/* */
/* Purpose: Disconnect */
/* */
/* Operation: call the Call Controller FSM */
/****************************************************************************/
void DCAPI CCO::CO_Disconnect(void)
{
DC_BEGIN_FN("CO_Disconnect");
// Check that the core is initialized.
TRC_ASSERT((_pUi->UI_IsCoreInitialized()), (TB, _T("Core not initialized")));
// Call CC with a Disconnect event.
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, _pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR) CC_EVT_API_DISCONNECT);
DC_END_FN();
} /* CO_Disconnect */
/****************************************************************************/
/* Name: CO_Shutdown */
/* */
/* Purpose: Shutdown the client */
/* */
/* Params: IN shutdownCode - what kind of shutdown is required. */
/* */
/* Operation: call the Call Controller FSM */
/****************************************************************************/
void DCAPI CCO::CO_Shutdown(unsigned shutdownCode)
{
DC_BEGIN_FN("CO_Shutdown");
//Prevent race by ensuring CO init is complete
if(_fCOInitComplete)
{
// Check that the core is initialized.
if (!_pUi->UI_IsCoreInitialized())
{
//
// Trace and then fake-up a call to UI_OnShutdown to pretend to the
// UI that the shutdown completed successfully.
//
TRC_NRM((TB,_T("Core NOT initialized")));
_pUi->UI_OnShutDown(UI_SHUTDOWN_SUCCESS);
DC_QUIT;
}
switch (shutdownCode)
{
case CO_DISCONNECT_AND_EXIT:
{
TRC_DBG((TB, _T("Shutdown type: disconnect and exit")));
// Call CC with a Shutdown event
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR) CC_EVT_API_DISCONNECTANDEXIT);
}
break;
case CO_SHUTDOWN:
{
TRC_DBG((TB, _T("Shutdown type: shutdown")));
// Call CC with a Shutdown event
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR) CC_EVT_API_SHUTDOWN);
}
break;
default:
{
TRC_ABORT((TB, _T("Illegal shutdown code")));
}
break;
}
}
DC_EXIT_POINT:
DC_END_FN();
} /* CO_Shutdown */
/****************************************************************************/
/* Name: CO_OnSaveSessionInfoPDU */
/* */
/* Purpose: Process Save Session PDU */
/* */
/* Params: pInfoPDU - Ptr to PTS_SAVE_SESSION_INFO_PDU */
/****************************************************************************/
// SECURITY - the size of the packet has been checked only to be sure there is
// enough data to read the PTS_SAVE_SESSION_INFO_PDU_DATA.InfoType field
HRESULT DCAPI CCO::CO_OnSaveSessionInfoPDU(
PTS_SAVE_SESSION_INFO_PDU_DATA pInfoPDU,
DCUINT dataLength)
{
HRESULT hr = S_OK;
UINT32 sessionId;
TSUINT8 UserNameGot[TS_MAX_USERNAME_LENGTH];
TSUINT8 DomainNameGot[TS_MAX_DOMAIN_LENGTH];
TSUINT32 DomainLength, UserNameLength;
TSUINT16 VersionGot;
DCUINT packetSize;
DC_BEGIN_FN("CO_OnSaveSessionInfoPDU");
switch (pInfoPDU->InfoType) {
case TS_INFOTYPE_LOGON:
{
TRC_NRM((TB, _T("Logon PDU")));
packetSize = FIELDOFFSET(TS_SAVE_SESSION_INFO_PDU_DATA, Info) +
sizeof(TS_LOGON_INFO);
if (packetSize >= dataLength)
sessionId = pInfoPDU->Info.LogonInfo.SessionId;
else if (packetSize - FIELDSIZE(TS_LOGON_INFO, SessionId) >=
dataLength) {
// NT4 servers did not send the session ID so default to zero
// if there is no data.
sessionId = 0;
}
else {
TRC_ABORT((TB,_T("bad TS_SAVE_SESSION_INFO_PDU_DATA; size %u"),
dataLength ));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
TRC_ALT((TB, _T("Session ID is: %ld"), sessionId));
if (pInfoPDU->Info.LogonInfo.cbDomain > TS_MAX_DOMAIN_LENGTH_OLD ||
pInfoPDU->Info.LogonInfo.cbUserName > TS_MAX_USERNAME_LENGTH ) {
TRC_ABORT(( TB, _T("Invalid TS_INFOTYPE_LOGON; cbDomain %u ")
_T("cbUserName %u"),
pInfoPDU->Info.LogonInfo.cbDomain,
pInfoPDU->Info.LogonInfo.cbUserName));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
_pUi->UI_UpdateSessionInfo((PDCWCHAR)(pInfoPDU->Info.LogonInfo.Domain),
(DCUINT) (pInfoPDU->Info.LogonInfo.cbDomain),
(PDCWCHAR)(pInfoPDU->Info.LogonInfo.UserName),
(DCUINT) (pInfoPDU->Info.LogonInfo.cbUserName),
sessionId);
}
break;
case TS_INFOTYPE_LOGON_LONG:
{
TRC_NRM((TB, _T("Logon PDU")));
VersionGot = pInfoPDU->Info.LogonInfoVersionTwo.Version ;
DomainLength = pInfoPDU->Info.LogonInfoVersionTwo.cbDomain ;
UserNameLength = pInfoPDU->Info.LogonInfoVersionTwo.cbUserName ;
if ((FIELDOFFSET( TS_SAVE_SESSION_INFO_PDU_DATA, Info) +
sizeof(TS_LOGON_INFO_VERSION_2) + DomainLength + UserNameLength
> dataLength) ||
(DomainLength > TS_MAX_DOMAIN_LENGTH) ||
(UserNameLength > TS_MAX_USERNAME_LENGTH))
{
TRC_ABORT(( TB, _T("Invalid TS_INFOTYPE_LOGON_LONG; cbDomain ")
_T("%u cbUserName %u"), DomainLength, UserNameLength));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
// Get the sessionId
sessionId = pInfoPDU->Info.LogonInfoVersionTwo.SessionId;
TRC_ALT((TB, _T("Session ID is: %ld"), sessionId));
// Parse out the Domain and UserName from the pInfoPDU
memset( DomainNameGot, 0, TS_MAX_DOMAIN_LENGTH);
memset( UserNameGot, 0, TS_MAX_USERNAME_LENGTH);
memcpy( DomainNameGot,
(PBYTE)(pInfoPDU + 1),
DomainLength) ;
memcpy(UserNameGot,
(PBYTE)(pInfoPDU + 1) + DomainLength,
UserNameLength) ;
_pUi->UI_UpdateSessionInfo((PDCWCHAR)(DomainNameGot),
(DCUINT) (DomainLength),
(PDCWCHAR)(UserNameGot),
(DCUINT) (UserNameLength),
sessionId);
}
break;
case TS_INFOTYPE_LOGON_PLAINNOTIFY:
{
//Notify of login event
_pUi->UI_OnLoginComplete();
}
break;
case TS_INFOTYPE_LOGON_EXTENDED_INFO:
{
TRC_NRM((TB,_T("Received TS_INFOTYPE_LOGON_EXTENDED_INFO")));
TS_LOGON_INFO_EXTENDED UNALIGNED* pLogonInfoExPkt =
(TS_LOGON_INFO_EXTENDED UNALIGNED*)&pInfoPDU->Info.LogonInfoEx;
if (FIELDOFFSET(TS_SAVE_SESSION_INFO_PDU_DATA, Info) +
pLogonInfoExPkt->Length > dataLength) {
TRC_ABORT(( TB, _T("Invalid TS_INFOTYPE_LOGON_EXTENDED_INFO")
_T("[expected %u got %u]"),
sizeof(TS_SAVE_SESSION_INFO_PDU_DATA) -
FIELDSIZE(TS_SAVE_SESSION_INFO_PDU_DATA, Info) +
pLogonInfoExPkt->Length, dataLength));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
PBYTE pBuf = (PBYTE)(pLogonInfoExPkt + 1);
if (pLogonInfoExPkt &&
pLogonInfoExPkt->Flags & LOGON_EX_AUTORECONNECTCOOKIE)
{
//
// Autoreconnect cookie is present
//
ULONG cbAutoReconnectSize = *((ULONG UNALIGNED *)(pBuf));
PBYTE pAutoReconnectCookie = (PBYTE)(pBuf) + sizeof(ULONG);
pBuf += cbAutoReconnectSize + sizeof(ULONG);
if (cbAutoReconnectSize > TS_MAX_AUTORECONNECT_LEN) {
TRC_ABORT(( TB, _T("TS_INFOTYPE_LOGON_EXTENDED_INFO")
_T("autoreconnect wrong size; [got %u]"),
cbAutoReconnectSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
CHECK_READ_N_BYTES( pAutoReconnectCookie, (PBYTE)pInfoPDU + dataLength,
cbAutoReconnectSize, hr,
(TB,_T("TS_INFOTYPE_LOGON_EXTENDED_INFO")
_T("autoreconnect wrong size; [got %u]"),
cbAutoReconnectSize));
TRC_ALT((TB,_T("Received autoreconnect cookie - size: %d"),
cbAutoReconnectSize));
//
// Store the autoreconnect cookie. It will be used
// if we get disconnected unexpectedly to allow a
// fast reconnect to the server.
//
_pUi->UI_SetAutoReconnectCookie(pAutoReconnectCookie,
cbAutoReconnectSize);
}
}
break;
default:
{
TRC_ERR((TB, _T("Unexpected Save Session Info PDU type: %u"),
(DCUINT)pInfoPDU->InfoType));
}
break;
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
} /* CO_OnSaveSessionInfoPDU */
/****************************************************************************/
/* Name: CO_OnSetKeyboardIndicatorsPDU */
/* */
/* Purpose: Process the TS_SET_KEYBOARD_INDICATORS_PDU */
/* */
/* Params: pKeyPDU - Ptr to TS_SET_KEYBOARD_INDICATORS_PDU */
/****************************************************************************/
HRESULT DCAPI CCO::CO_OnSetKeyboardIndicatorsPDU(
PTS_SET_KEYBOARD_INDICATORS_PDU pKeyPDU, DCUINT dataLen)
{
DC_BEGIN_FN("CO_OnSetKeyboardIndicatorsPDU");
DC_IGNORE_PARAMETER(dataLen);
_pIh->IH_UpdateKeyboardIndicators(pKeyPDU->UnitId, pKeyPDU->LedFlags);
DC_END_FN();
return S_OK;
} /* CO_OnSetKeyboardIndicatorsPDU */
/****************************************************************************/
/* Name: CO_SetConfigurationValue */
/* */
/* Purpose: Sets a given configuration setting to a given value */
/* */
/* Params: configItem - the configuration item to change */
/* configValue - the new value of the configuration item */
/* (see acoapi.h for valid values) */
/****************************************************************************/
void DCAPI CCO::CO_SetConfigurationValue(
unsigned configItem,
unsigned configValue)
{
DC_BEGIN_FN("CO_SetConfigurationValue");
TRC_ASSERT((_pUi->UI_IsCoreInitialized()), (TB, _T("Core not initialized")));
switch (configItem) {
case CO_CFG_ACCELERATOR_PASSTHROUGH:
{
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_SetAcceleratorPassthrough),
(ULONG_PTR) configValue);
}
break;
case CO_CFG_ENCRYPTION:
{
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pSl,
CD_NOTIFICATION_FUNC(CSL,SL_EnableEncryption),
(ULONG_PTR) configValue);
}
break;
#ifdef DC_DEBUG
case CO_CFG_DEBUG_SETTINGS:
{
_pCd->CD_DecoupleSimpleNotification(CD_RCV_COMPONENT,
_pUh,
CD_NOTIFICATION_FUNC(CUH,UH_ChangeDebugSettings),
(ULONG_PTR) configValue);
}
break;
#endif /* DC_DEBUG */
default:
{
TRC_ABORT((TB, _T("Invalid configItem: %u"), configItem));
}
break;
}
DC_END_FN();
} /* CO_SetConfigurationValue */
/****************************************************************************/
/* Name: CO_SetHotkey */
/* */
/* Purpose: call the function with the given data */
/****************************************************************************/
void DCAPI CCO::CO_SetHotkey(PDCHOTKEY pHotkey)
{
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_SetHotkey),
&pHotkey,
sizeof(PDCHOTKEY));
}
#ifdef DC_DEBUG
/****************************************************************************/
/* Name: CO_GetRandomFailureItem */
/* */
/* Purpose: Simple wrapper to _pUt->UT_GetRandomFailureItem */
/* */
/* Returns: % times item currently fails */
/* */
/* Params: ItemID - IN - requested item */
/****************************************************************************/
int DCAPI CCO::CO_GetRandomFailureItem(unsigned itemID)
{
DC_BEGIN_FN("CO_GetRandomFailureItem");
DC_END_FN();
return _pUt->UT_GetRandomFailureItem(itemID);
} /* CO_GetRandomFailureItem */
/****************************************************************************/
/* Name: CO_SetRandomFailureItem */
/* */
/* Purpose: Simple wrapper for _pUi->UI_SetRandomFailureItem */
/* */
/* Params: See _pUi->UI_SetRandomFailureItem */
/****************************************************************************/
void DCAPI CCO::CO_SetRandomFailureItem(unsigned itemID, int percent)
{
DC_BEGIN_FN("CO_SetRandomFailureItem");
_pUt->UT_SetRandomFailureItem(itemID, percent);
DC_END_FN();
} /* CO_SetRandomFailureItem */
#endif /* DC_DEBUG */
/****************************************************************************/
/* Name: COContainerWindowSubclassProc */
/* */
/* Purpose: Subclass procedure for the UI Container Window */
/****************************************************************************/
LRESULT CALLBACK CCO::COContainerWindowSubclassProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
LRESULT rc = 0;
POINT newPos;
DC_BEGIN_FN("COContainerWindowSubclassProc");
switch (message)
{
case WM_SETFOCUS:
{
//
// Note, the code here used to use CallWindowProc.
// this has been changed to use a direct call.
// If there is ever a need for Unicode/ANSI conversions
// then change the direct calls to the window proc
// to use CallWindowProc
//
rc =_pUi->UIContainerWndProc( hwnd, message, wParam, lParam);
if (rc) {
SetFocus(_pIh->IH_GetInputHandlerWindow());
}
}
break;
case WM_MOVE:
{
/****************************************************************/
/* Tell IH about the new window position. */
/* Take care with sign extension here. */
/****************************************************************/
newPos.x = (DCINT)((DCINT16)LOWORD(lParam));
newPos.y = (DCINT)((DCINT16)HIWORD(lParam));
TRC_DBG((TB, _T("Move to %d,%d"), newPos.x, newPos.y));
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_SetVisiblePos),
&newPos,
sizeof(newPos));
rc = _pUi->UIContainerWndProc( hwnd, message, wParam, lParam);
}
break;
default:
{
rc =_pUi->UIContainerWndProc( hwnd, message, wParam, lParam);
}
break;
}
DC_END_FN();
return rc;
} /* COContainerWindowSubclassProc */
/****************************************************************************/
/* Name: COMainFrameWindowSubclassProc */
/* */
/* Purpose: Subclass procedure for the UI Main Frame Window */
/****************************************************************************/
LRESULT CALLBACK CCO::COMainWindowSubclassProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
LRESULT rc = 0;
DCSIZE newSize;
DC_BEGIN_FN("COMainWindowSubclassProc");
switch (message) {
case WM_SIZE:
{
/****************************************************************/
/* Tell IH about the new window size. */
/* Take care with sign extension here. */
/****************************************************************/
newSize.width = (DCINT)((DCINT16)LOWORD(lParam));
newSize.height = (DCINT)((DCINT16)HIWORD(lParam));
TRC_DBG((TB, _T("Size now %d,%d"), newSize.width, newSize.height));
switch (wParam)
{
case SIZE_MINIMIZED:
case SIZE_MAXIMIZED:
case SIZE_RESTORED:
{
WPARAM newWindowState = wParam;
//
// This is slightly hack-erific.
// because we're now an ActiveX nested child window
// we don't get a WM_MINIMIZED. But on minimize
// the size becomes 0,0 so fake it.
//
if(!newSize.width && !newSize.height)
{
newWindowState = SIZE_MINIMIZED;
}
/********************************************************/
/* OR interested in these to maybe send */
/* SuppressOutputPDU */
/********************************************************/
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pOr,
CD_NOTIFICATION_FUNC(COR,OR_SetSuppressOutput),
(UINT) newWindowState);
}
break;
default:
{
/********************************************************/
/* OR not interested in these - do nothing */
/********************************************************/
}
break;
}
rc =_pUi->UIMainWndProc( hwnd, message, wParam, lParam);
}
break;
case WM_PALETTECHANGED:
{
TRC_NRM((TB, _T("WM_PALETTECHANGED")));
/****************************************************************/
/* Note that we are calling this function (which should */
/* logically be called on the receive thread) on the UI thread. */
/* See comment in function description. */
/****************************************************************/
_pOp->OP_PaletteChanged(hwnd, (HWND)wParam);
}
break;
case WM_QUERYNEWPALETTE:
{
TRC_NRM((TB, _T("WM_QUERYNEWPALETTE")));
/****************************************************************/
/* Note that we are calling this function (which should */
/* logically be called on the receive thread) on the UI thread. */
/* See comment in function description. */
/****************************************************************/
rc = _pOp->OP_QueryNewPalette(hwnd);
}
break;
#ifdef OS_WINNT
case WM_ENTERSIZEMOVE:
{
/****************************************************************/
/* Tell IH we're entering Size/Move mode */
/****************************************************************/
TRC_NRM((TB, _T("Enter Size/Move")));
_CO.inSizeMove = TRUE;
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_InputEvent),
WM_ENTERSIZEMOVE);
}
break;
case WM_CAPTURECHANGED:
{
if (_CO.inSizeMove)
{
/************************************************************/
/* Tell IH we're leaving size/move mode (Windows doesn't */
/* always send WM_EXITSIZEMOVE, but it does seem to always */
/* send WM_CAPTURECHANGED). */
/************************************************************/
TRC_NRM((TB, _T("Capture Changed when in Size/Move")));
_CO.inSizeMove = FALSE;
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_InputEvent),
WM_EXITSIZEMOVE);
}
}
break;
case WM_EXITSIZEMOVE:
{
// Tell IH we're leaving size/move mode.
TRC_NRM((TB, _T("Exit Size/Move")));
_CO.inSizeMove = FALSE;
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_InputEvent),
WM_EXITSIZEMOVE);
}
break;
case WM_EXITMENULOOP:
{
// Tell IH we're exiting the system menu handler.
TRC_NRM((TB, _T("Exit menu loop")));
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT,
_pIh,
CD_NOTIFICATION_FUNC(CIH,IH_InputEvent),
WM_EXITMENULOOP);
}
break;
#endif
#ifdef OS_WINCE
// HPC devices do not get WM_SIZE (SIZE_RESTORED) on a maximize,
// but we do get the WM_ACTIVATE message.
case WM_ACTIVATE:
{
if (g_CEConfig != CE_CONFIG_WBT &&
LOWORD(wParam) != WA_INACTIVE)
{
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pOr,
CD_NOTIFICATION_FUNC(COR,OR_SetSuppressOutput),
SIZE_RESTORED);
}
}
// FALL-THRU
#endif // OS_WINCE
default:
{
rc =_pUi->UIMainWndProc( hwnd, message, wParam, lParam);
}
break;
}
DC_END_FN();
return rc;
} /* COContainerWindowSubclassProc */
LRESULT CALLBACK CCO::COStaticContainerWindowSubclassProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
// delegate to appropriate instance
CCO* pCO = (CCO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
return pCO->COContainerWindowSubclassProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK CCO::COStaticMainWindowSubclassProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
// delegate to appropriate instance
CCO* pCO = (CCO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
return pCO->COMainWindowSubclassProc(hwnd, message, wParam, lParam);
}
/****************************************************************************/
/* Name: COSubclassUIWindows */
/* */
/* Purpose: Subclasses the UI's Main Frame and Container Windows */
/****************************************************************************/
void DCINTERNAL CCO::COSubclassUIWindows()
{
DC_BEGIN_FN("COSubclassUIWindows");
// Replace the instance pointer with that for the CO object
// when subclassing. Have to do this because CO is not derived from UI
SetWindowLongPtr( _pUi->UI_GetUIMainWindow(), GWLP_USERDATA, (LONG_PTR)this);
SetWindowLongPtr( _pUi->UI_GetUIContainerWindow(), GWLP_USERDATA, (LONG_PTR)this);
_CO.pUIMainWndProc = SubclassWindow( _pUi->UI_GetUIMainWindow(),
COStaticMainWindowSubclassProc );
_CO.pUIContainerWndProc = SubclassWindow( _pUi->UI_GetUIContainerWindow(),
COStaticContainerWindowSubclassProc );
DC_END_FN();
} /* COSubclassUIWindows */
/****************************************************************************/
/* Name: CO_OnInitialized */
/* */
/* Purpose: Handle Initialized notification from SL */
/* */
/* Operation: Initialize the Receiver Thread */
/****************************************************************************/
void DCCALLBACK CCO::CO_OnInitialized()
{
DC_BEGIN_FN("CO_OnInitialized");
// Call RCV_Init to initialize the Core.
_pRcv->RCV_Init();
DC_END_FN();
} /* CO_OnInitialized */
/****************************************************************************/
/* Name: CO_OnTerminating */
/* */
/* Purpose: Handle Terminating notification from SL */
/****************************************************************************/
void DCCALLBACK CCO::CO_OnTerminating()
{
DC_BEGIN_FN("CO_OnTerminating");
// Terminate Core components.
_pRcv->RCV_Term();
DC_END_FN();
} /* CO_OnTerminating */
/****************************************************************************/
/* Name: CO_OnConnected */
/* */
/* Purpose: Handle Connected notification from SL */
/* */
/* Params: IN channelID */
/* IN pUserData */
/* IN userDataLength */
/****************************************************************************/
void DCCALLBACK CCO::CO_OnConnected(
unsigned channelID,
PVOID pUserData,
unsigned userDataLength,
UINT32 serverVersion)
{
DC_BEGIN_FN("CO_OnConnected");
TRC_DBG((TB, _T("Channel %d"), channelID));
DC_IGNORE_PARAMETER(serverVersion);
// Currently there is no Core userdata sent from the Server.
DC_IGNORE_PARAMETER(pUserData);
DC_IGNORE_PARAMETER(userDataLength);
DC_IGNORE_PARAMETER(channelID);
// Pass to CC.
TRC_NRM((TB, _T("Connect OK")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR) CC_EVT_API_ONCONNECTOK);
DC_END_FN();
} /* CO_OnConnected */
/****************************************************************************/
/* Name: CO_OnDisconnected */
/* */
/* Purpose: Handle Disconnected notification from SL */
/* */
/* Params: IN result - disconnection reason code */
/****************************************************************************/
void DCCALLBACK CCO::CO_OnDisconnected(unsigned result)
{
DC_BEGIN_FN("CO_OnDisconnected");
DC_IGNORE_PARAMETER(result);
// Pass to CC.
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_OnDisconnected),
(ULONG_PTR) result);
DC_END_FN();
} /* CO_OnDisconnected */
#define CO_CHECKPACKETCAST( type, size, hr ) \
if ( (size) < sizeof(type)) { \
TRC_ABORT((TB, _T("Bad ") _T( #type ) _T(" len [expected %u got %u]"), \
sizeof(type), (size) )); \
hr = E_TSC_CORE_LENGTH; \
DC_QUIT; \
}
#define CO_CHECKPACKETCAST_SPECIFC( type, size, expected, hr ) \
if ( (size) < (expected)) { \
TRC_ABORT((TB, _T("Bad ") _T( #type ) _T(" len [expected %u got %u]"), \
(expected), (size) )); \
hr = E_TSC_CORE_LENGTH; \
DC_QUIT; \
}
// This macro is used to see that when a pointer to a TS_SHAREDATAHEADER
// is passed on to a handler, the TS_SHAREDATAHEADER is an uncompressed packet
// If the packet was compressed, then the data after the TS_SHAREDATAHEADER is
// still compressed, and the method we pass this header onto will puke on the
// data, assuming it does not uncompress the data, which no layers above this
// do
#define COPR_MUSTBEUNCOMP( type, pDataHdr, hr ) \
if (pDataHdr->generalCompressedType & PACKET_COMPRESSED) { \
TRC_ABORT((TB, _T( #type ) \
_T(" was unexpectedly compressed"))); \
hr = E_TSC_CORE_UNEXPECTEDCOMP; \
DC_QUIT; \
}
/****************************************************************************/
/* Name: CO_OnPacketReceived */
/* */
/* Purpose: Handle PacketReceived notification from SL */
/* */
/* Params: IN pData - packet received */
/* IN dataLen - length of packet */
/* IN flags - RNS_SEC_ flags */
/* IN channelID - MCS channel on which packet was sent */
/* IN priority - priority of packet */
/****************************************************************************/
HRESULT DCCALLBACK CCO::CO_OnPacketReceived(
PBYTE pData,
unsigned dataLen,
unsigned flags,
unsigned channelID,
unsigned priority)
{
HRESULT hr = S_OK;
PTS_SHARECONTROLHEADER pCtrlHdr;
PTS_SHAREDATAHEADER pDataHdr;
PTS_FLOW_PDU pFlowPDU;
PDCUINT8 pCurrentPDU;
DCUINT currentDataLen;
DCUINT dataBufLen;
#ifdef DC_DEBUG
DCUINT countPDU = 0;
#endif
DCUINT dataRemaining = dataLen;
DC_BEGIN_FN("CO_OnPacketReceived");
DC_IGNORE_PARAMETER(flags);
DC_IGNORE_PARAMETER(priority);
DC_IGNORE_PARAMETER(channelID);
TRC_ASSERT((pData != NULL), (TB, _T("NULL packet")));
TRC_NRM((TB, _T("channelID %#x"), channelID));
TRC_NRM((TB, _T("(fixed) Buffer: %p len %d"), pData, dataLen));
TRC_DATA_DBG("Contents", pData, dataLen);
// Find the first PDU in the packet.
pCurrentPDU = pData;
// And while there are more PDUs in the packet, route each PDU.
while (pCurrentPDU != NULL) {
// Intermediate variable to save in casts!
pCtrlHdr = (PTS_SHARECONTROLHEADER)pCurrentPDU;
// SECURITY: NOTE - it is not safe to read the pduSource
// field of the TS_SHARECONTROLHEADER since we are not
// requiring this data to be there. This is to support
// the TS_PDUTYPE_DEACTIVATEALLPDU which appears smaller
// on win2k
// Be sure there is enough data to read the totalLength
if (dataRemaining < FIELDOFFSET(TS_SHARECONTROLHEADER, pduSource)) {
TRC_ABORT(( TB, _T("dataRemaining %u partial sizeof(TS_")
_T("SHARECONTROLHEADER) %u "), dataRemaining,
FIELDOFFSET(TS_SHARECONTROLHEADER, pduSource)));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
// All PDUs start with the length and PDU type, except FlowPDUs.
if (pCtrlHdr->totalLength != TS_FLOW_MARKER) {
currentDataLen = pCtrlHdr->totalLength;
// Be sure there is enough data for the entire packet
if (dataRemaining < currentDataLen) {
TRC_ABORT(( TB, _T("dataRemaining %u currentDataLen %u"),
dataRemaining, currentDataLen));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (sizeof(PTS_SHAREDATAHEADER) <= dataRemaining) {
TRC_NRM((TB, _T("current PDU x%p type %u, type2 %u, data len %u"),
pCurrentPDU,
(pCtrlHdr->pduType) & TS_MASK_PDUTYPE,
((PTS_SHAREDATAHEADER)pCurrentPDU)->pduType2,
currentDataLen));
}
switch ((pCtrlHdr->pduType) & TS_MASK_PDUTYPE) {
case TS_PDUTYPE_DATAPDU:
{
PDCUINT8 pDataBuf;
TRC_DBG((TB, _T("A Data PDU")));
CO_CHECKPACKETCAST(TS_SHAREDATAHEADER, currentDataLen, hr);
pDataHdr = (PTS_SHAREDATAHEADER)pCurrentPDU;
pDataBuf = pCurrentPDU + sizeof(TS_SHAREDATAHEADER);
dataBufLen = currentDataLen - sizeof(TS_SHAREDATAHEADER);
if (pDataHdr->generalCompressedType & PACKET_COMPRESSED) {
UCHAR *buf;
int bufSize;
if (pDataHdr->generalCompressedType & PACKET_FLUSHED)
initrecvcontext (&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
PACKET_COMPR_TYPE_64K);
if (decompress(pDataBuf,
pCtrlHdr->totalLength - sizeof(TS_SHAREDATAHEADER),
(pDataHdr->generalCompressedType & PACKET_AT_FRONT),
&buf,
&bufSize,
&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
(pDataHdr->generalCompressedType &
PACKET_COMPR_TYPE_MASK))) {
pDataBuf = buf;
dataBufLen = bufSize;
}
else {
TRC_ABORT((TB, _T("Decompression FAILURE!!!")));
hr = E_TSC_UI_DECOMPRESSION;
DC_QUIT;
}
}
switch (pDataHdr->pduType2) {
case TS_PDUTYPE2_UPDATE:
CO_CHECKPACKETCAST(TS_UPDATE_HDR_DATA,
dataBufLen, hr);
TRC_DBG((TB, _T("Update PDU")));
hr = _pUh->UH_OnUpdatePDU(
(TS_UPDATE_HDR_DATA UNALIGNED FAR *)
pDataBuf, dataBufLen);
DC_QUIT_ON_FAIL(hr);
break;
case TS_PDUTYPE2_POINTER:
// SECURITY: Only the TS_POINTER_PDU_DATA.messageType needs to be
// read. NT4 servers may not send a TS_POINTER_PDU_DATA.pointerData
CO_CHECKPACKETCAST_SPECIFC(TS_POINTER_PDU_DATA,
dataBufLen, sizeof(TSUINT16), hr);
TRC_DBG((TB, _T("Mouse Pointer PDU")));
hr = _pCm->CM_SlowPathPDU(
(TS_POINTER_PDU_DATA UNALIGNED FAR *)
pDataBuf, dataBufLen);
DC_QUIT_ON_FAIL(hr);
break;
case TS_PDUTYPE2_FONTMAP:
case TS_PDUTYPE2_INPUT:
case TS_PDUTYPE2_UPDATECAPABILITY:
case TS_PDUTYPE2_DESKTOP_SCROLL:
case TS_PDUTYPE2_APPLICATION:
case TS_PDUTYPE2_CONTROL:
case TS_PDUTYPE2_MEDIATEDCONTROL:
case TS_PDUTYPE2_REMOTESHARE:
case TS_PDUTYPE2_SYNCHRONIZE:
case TS_PDUTYPE2_WINDOWLISTUPDATE:
case TS_PDUTYPE2_WINDOWACTIVATION:
TRC_DBG((TB, _T("Ignore pdutype2 %#x"),
pDataHdr->pduType2));
break;
case TS_PDUTYPE2_SHUTDOWN_DENIED:
TRC_DBG((TB, _T("ShutdownDeniedPDU")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR)CC_EVT_API_ONSHUTDOWNDENIED);
break;
case TS_PDUTYPE2_PLAY_SOUND:
CO_CHECKPACKETCAST(TS_PLAY_SOUND_PDU_DATA,
dataBufLen, hr);
TRC_DBG((TB, _T("PlaySoundPDU")));
hr = _pSp->SP_OnPlaySoundPDU((PTS_PLAY_SOUND_PDU_DATA)
pDataBuf, dataBufLen);
DC_QUIT_ON_FAIL(hr);
break;
case TS_PDUTYPE2_SAVE_SESSION_INFO:
//CO_CHECKPACKETCAST(TS_SAVE_SESSION_INFO_PDU_DATA, dataBufLen, hr);
// SECURITY: TS_SAVE_SESSION_INFO_PDU_DATA may be sent from NT4 with
// only a TS_SAVE_SESSION_INFO_PDU_DATA.InfoType
CO_CHECKPACKETCAST_SPECIFC(TS_SAVE_SESSION_INFO_PDU_DATA,
dataBufLen, sizeof(TSUINT32), hr);
TRC_DBG((TB, _T("Save Session Info PDU")));
hr = CO_OnSaveSessionInfoPDU(
(PTS_SAVE_SESSION_INFO_PDU_DATA)pDataBuf,
dataBufLen);
DC_QUIT_ON_FAIL(hr);
break;
case TS_PDUTYPE2_SET_KEYBOARD_INDICATORS:
CO_CHECKPACKETCAST(TS_SET_KEYBOARD_INDICATORS_PDU,
currentDataLen, hr);
COPR_MUSTBEUNCOMP(TS_SET_KEYBOARD_INDICATORS_PDU,
pDataHdr, hr);
TRC_DBG((TB, _T("TS_PDUTYPE2_SET_KEYBOARD_INDICATORS PDU")));
hr = CO_OnSetKeyboardIndicatorsPDU
((PTS_SET_KEYBOARD_INDICATORS_PDU)pCurrentPDU,
currentDataLen);
DC_QUIT_ON_FAIL(hr);
break;
case TS_PDUTYPE2_SET_KEYBOARD_IME_STATUS:
{
PTS_SET_KEYBOARD_IME_STATUS_PDU pImePDU;
CO_CHECKPACKETCAST(TS_SET_KEYBOARD_IME_STATUS_PDU,
currentDataLen, hr);
COPR_MUSTBEUNCOMP(TS_SET_KEYBOARD_IME_STATUS_PDU,
pDataHdr, hr);
TRC_DBG((TB, _T("TS_PDUTYPE2_SET_KEYBOARD_IME_STATUS PDU")));
pImePDU = (PTS_SET_KEYBOARD_IME_STATUS_PDU)pCurrentPDU;
_pIh->IH_SetKeyboardImeStatus(pImePDU->ImeOpen,
pImePDU->ImeConvMode);
break;
}
case TS_PDUTYPE2_SET_ERROR_INFO_PDU:
{
PTS_SET_ERROR_INFO_PDU pErrInfoPDU;
CO_CHECKPACKETCAST(TS_SET_ERROR_INFO_PDU,
currentDataLen, hr);
COPR_MUSTBEUNCOMP(TS_SET_ERROR_INFO_PDU,
pDataHdr, hr);
TRC_DBG((TB, _T("TS_SET_ERROR_INFO_PDU PDU")));
pErrInfoPDU = (PTS_SET_ERROR_INFO_PDU)pCurrentPDU;
_pUi->UI_SetServerErrorInfo(pErrInfoPDU->errorInfo);
break;
}
case TS_PDUTYPE2_ARC_STATUS_PDU:
{
PTS_AUTORECONNECT_STATUS_PDU pArcStatusPDU;
CO_CHECKPACKETCAST(TS_AUTORECONNECT_STATUS_PDU,
currentDataLen, hr);
COPR_MUSTBEUNCOMP(TS_AUTORECONNECT_STATUS_PDU,
pDataHdr, hr);
TRC_DBG((TB, _T("TS_PDUTYPE2_ARC_STATUS_PDU")));
pArcStatusPDU = (PTS_AUTORECONNECT_STATUS_PDU)pCurrentPDU;
_pUi->UI_OnReceivedArcStatus(pArcStatusPDU->arcStatus);
break;
}
default:
TRC_ABORT((TB, _T("Invalid pduType2 %#x"),
pDataHdr->pduType2));
break;
}
}
break;
case TS_PDUTYPE_DEMANDACTIVEPDU:
TRC_DBG((TB, _T("DemandActivePDU")));
CO_CHECKPACKETCAST(TS_DEMAND_ACTIVE_PDU, currentDataLen, hr);
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
_pCc,
CD_NOTIFICATION_FUNC(CCC,CC_OnDemandActivePDU),
pCurrentPDU,
currentDataLen);
break;
case TS_PDUTYPE_DEACTIVATEALLPDU:
TRC_DBG((TB, _T("DeactivateAllPDU")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, _pCc,
CD_NOTIFICATION_FUNC(CCC,CC_Event),
(ULONG_PTR)CC_EVT_API_ONDEACTIVATEALL);
break;
case TS_PDUTYPE_DEACTIVATESELFPDU:
case TS_PDUTYPE_DEACTIVATEOTHERPDU:
case TS_PDUTYPE_CONFIRMACTIVEPDU:
case TS_PDUTYPE_REQUESTACTIVEPDU:
TRC_ERR((TB, _T("PDU type %x unexpected!"), pCtrlHdr->pduType));
break;
default:
TRC_ABORT((TB, _T("Unrecognized PDU type: %#x"),
pCtrlHdr->pduType));
break;
}
}
else {
TRC_NRM((TB, _T("FlowPDU")));
pFlowPDU = (PTS_FLOW_PDU)pData;
switch (pFlowPDU->pduType) {
case TS_PDUTYPE_FLOWTESTPDU:
TRC_NRM((TB, _T("FlowTestPDU ignored")));
break;
case TS_PDUTYPE_FLOWRESPONSEPDU:
TRC_NRM((TB, _T("FlowResponsePDU ignored")));
break;
default:
TRC_ABORT((TB, _T("Unknown FlowPDU %#x"), pFlowPDU->pduType));
break;
}
DC_QUIT;
}
// Now look for the next PDU in the packet.
pCurrentPDU += pCtrlHdr->totalLength;
dataRemaining -= pCtrlHdr->totalLength;
if ((DCUINT)(pCurrentPDU - pData) >= dataLen) {
TRC_NRM((TB, _T("Last PDU in packet")));
pCurrentPDU = NULL;
}
#ifdef DC_DEBUG
countPDU++;
#endif
}
#ifdef DC_DEBUG
if (countPDU > 1)
{
TRC_NRM((TB, _T("*** PDU count %u"), countPDU));
}
#endif
DC_EXIT_POINT:
if (FAILED(hr) && IMMEDIATE_DISSCONNECT_ON_HR(hr)) {
TRC_ABORT((TB, _T("Disconnect for security")));
CO_DropLinkImmediate(SL_ERR_INVALIDPACKETFORMAT, hr);
}
DC_END_FN();
return hr;
} /* CO_OnPacketReceived */
/****************************************************************************/
// CO_OnFastPathOutputReceived
//
// Handles fast-path output from the server by dispatching subpackets
// to the right handler component.
/****************************************************************************/
#define DC_QUIT_ON_FAIL_TRC(hr, trc) if (FAILED(hr)) {TRC_ABORT( trc );DC_QUIT;}
HRESULT DCAPI CCO::CO_OnFastPathOutputReceived(BYTE FAR *pData,
unsigned DataLen)
{
HRESULT hr = S_OK;
unsigned RawPDUSize;
unsigned HdrSize;
unsigned PDUSize;
BYTE FAR *pPDU;
DC_BEGIN_FN("CO_OnFastPathOutputReceived");
// Fast-path output is a series of PDUs packed on byte boundaries.
while (DataLen) {
// First byte is header containing the update type and compression-
// used flag. If compression-used is true the following byte is the
// compression flags, otherwise it's not present. Final part of
// header is 2-byte little-endian size field.
if (*pData & TS_OUTPUT_FASTPATH_COMPRESSION_USED) {
HdrSize = 4;
if (HdrSize > DataLen) {
TRC_ABORT((TB, _T("Bad comp fast path PDU")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
RawPDUSize = *((UINT16 UNALIGNED FAR *)(pData + 2));
// Be sure there is enough size for the header
if (HdrSize + RawPDUSize > DataLen) {
TRC_ABORT((TB, _T("Bad comp fast path PDU; [need %u have %u]"),
HdrSize + RawPDUSize, DataLen));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (pData[1] & PACKET_COMPRESSED) {
if (pData[1] & PACKET_FLUSHED)
initrecvcontext (&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
PACKET_COMPR_TYPE_64K);
if (!decompress(pData + 4, RawPDUSize,
pData[1] & PACKET_AT_FRONT, &pPDU, (PDCINT) &PDUSize,
&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
pData[1] & PACKET_COMPR_TYPE_MASK)) {
TRC_ABORT((TB, _T("Decompression FAILURE!!!")));
hr = E_TSC_UI_DECOMPRESSION;
DC_QUIT;
}
}
else {
pPDU = pData + 4;
PDUSize = RawPDUSize;
}
}
else {
// Compression flags not present.
HdrSize = 3;
if (HdrSize > DataLen) {
TRC_ABORT((TB, _T("Bad uncomp fast path PDU; [need %u have %u]"),
HdrSize, DataLen));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
PDUSize = RawPDUSize = *((UINT16 UNALIGNED FAR *)(pData + 1));
pPDU = pData + 3;
// Be sure there is enough size for the header
if (HdrSize + RawPDUSize > DataLen) {
TRC_ABORT((TB, _T("Bad uncomp fast path PDU; [need %u have %u]"),
HdrSize + RawPDUSize, DataLen));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
}
switch (*pData & TS_OUTPUT_FASTPATH_UPDATETYPE_MASK) {
case TS_UPDATETYPE_ORDERS:
// Number of orders is in little-endian format in
// the first two bytes of the PDU area.
TRC_NRM((TB, _T("Fast-path Order PDU")));
hr = _pUh->UH_ProcessOrders(*((UINT16 UNALIGNED FAR *)pPDU),
pPDU + 2, PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("UH_ProcessOrders")));
break;
case TS_UPDATETYPE_BITMAP:
// BitmapPDU format unchanged from normal path.
CO_CHECKPACKETCAST(TS_UPDATE_BITMAP_PDU_DATA, PDUSize, hr);
TRC_NRM((TB, _T("Bitmap PDU")));
hr = _pUh->UH_ProcessBitmapPDU(
(TS_UPDATE_BITMAP_PDU_DATA UNALIGNED FAR *)pPDU,
PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("UH_ProcessBitmapPDU")));
break;
case TS_UPDATETYPE_PALETTE:
CO_CHECKPACKETCAST(TS_UPDATE_PALETTE_PDU_DATA, PDUSize, hr);
// PalettePDU format unchanged from normal path.
TRC_NRM((TB, _T("Palette PDU")));
hr = _pUh->UH_ProcessPalettePDU(
(TS_UPDATE_PALETTE_PDU_DATA UNALIGNED FAR *)pPDU,
PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("UH_ProcessPalettePDU")));
break;
case TS_UPDATETYPE_SYNCHRONIZE:
TRC_NRM((TB, _T("Sync PDU")));
break;
case TS_UPDATETYPE_MOUSEPTR_SYSTEM_NULL:
TRC_NRM((TB,_T("Mouse null system pointer PDU")));
_pCm->CM_NullSystemPointerPDU();
break;
case TS_UPDATETYPE_MOUSEPTR_SYSTEM_DEFAULT:
TRC_NRM((TB,_T("Mouse default system pointer PDU")));
_pCm->CM_DefaultSystemPointerPDU();
break;
case TS_UPDATETYPE_MOUSEPTR_MONO:
CO_CHECKPACKETCAST(TS_MONOPOINTERATTRIBUTE, PDUSize, hr);
TRC_NRM((TB,_T("Mouse mono pointer PDU")));
hr = _pCm->CM_MonoPointerPDU(
(TS_MONOPOINTERATTRIBUTE UNALIGNED FAR *)pPDU,PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("CM_MonoPointerPDU")));
break;
case TS_UPDATETYPE_MOUSEPTR_POSITION:
CO_CHECKPACKETCAST(TS_POINT16, PDUSize, hr);
TRC_NRM((TB,_T("Mouse position PDU")));
_pCm->CM_PositionPDU((TS_POINT16 UNALIGNED FAR *)pPDU);
break;
case TS_UPDATETYPE_MOUSEPTR_COLOR:
CO_CHECKPACKETCAST(TS_COLORPOINTERATTRIBUTE, PDUSize, hr);
TRC_NRM((TB,_T("Mouse color pointer PDU")));
hr = _pCm->CM_ColorPointerPDU(
(TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *)pPDU,
PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("CM_ColorPointerPDU")));
break;
case TS_UPDATETYPE_MOUSEPTR_CACHED:
CO_CHECKPACKETCAST(TSUINT16, PDUSize, hr);
TRC_NRM((TB,_T("Mouse cached pointer PDU")));
_pCm->CM_CachedPointerPDU(*((TSUINT16 UNALIGNED FAR *)pPDU));
break;
case TS_UPDATETYPE_MOUSEPTR_POINTER:
CO_CHECKPACKETCAST(TS_POINTERATTRIBUTE, PDUSize, hr);
TRC_NRM((TB,_T("Mouse pointer PDU")));
hr = _pCm->CM_PointerPDU(
(TS_POINTERATTRIBUTE UNALIGNED FAR *)pPDU, PDUSize);
DC_QUIT_ON_FAIL_TRC( hr, (TB,_T("CM_PointerPDU")));
break;
default:
TRC_ERR((TB, _T("Unexpected Update PDU type: %u"),
*pData & TS_OUTPUT_FASTPATH_UPDATETYPE_MASK));
break;
}
pData += HdrSize + RawPDUSize;
DataLen -= HdrSize + RawPDUSize;
}
/************************************************************************/
/* If there are a large number of PDUs arriving, messages flood the */
/* Receive Thread's message queue and it is possible for WM_PAINT */
/* messages to not get processed within a reasonable amount of time */
/* (as they have the lowest priority). We therefore ensure that */
/* any outstanding WM_PAINTs are flushed if they have not been */
/* processed within UH_WORST_CASE_WM_PAINT_PERIOD. */
/* */
/* Note that the normal processing of updates does not involve */
/* WM_PAINT messages - we draw directly to the Output Window. */
/* WM_PAINTs are only generated by resizing or obscuring/revealing */
/* an area of the client window. */
/************************************************************************/
_pOp->OP_MaybeForcePaint();
DC_EXIT_POINT:
if (FAILED(hr) && IMMEDIATE_DISSCONNECT_ON_HR(hr)) {
TRC_ABORT((TB, _T("Disconnect for security")));
CO_DropLinkImmediate(SL_ERR_INVALIDPACKETFORMAT, hr);
}
DC_END_FN();
return hr;
}
#define CHECK_ULONGLEN_STRING(p, pEnd, str, ulSize, descr) \
{\
CHECK_READ_N_BYTES(p, pEnd, sizeof(ULONG), hr, (TB,_T("can not read ") _T( #descr ) _T("size"))) \
(ulSize) = *((ULONG UNALIGNED *)(p)); \
(str) = (PBYTE)(p) + sizeof(ULONG); \
CHECK_READ_N_BYTES(str , pEnd, ulSize, hr, (TB,_T("can not read ") _T( #descr ))) \
(p) += (ulSize) + sizeof(ULONG); \
}
/****************************************************************************/
// CO_OnServerRedirectionPacket
//
// Called from SL on receipt of a server redir packet for load balancing.
/****************************************************************************/
HRESULT DCAPI CCO::CO_OnServerRedirectionPacket(
RDP_SERVER_REDIRECTION_PACKET UNALIGNED *pPkt,
DCUINT dataLen)
{
HRESULT hr = S_OK;
WCHAR AlignedAddress[TS_MAX_SERVERADDRESS_LENGTH];
unsigned length;
PBYTE pEnd = ((BYTE *)pPkt) + pPkt->Length;
BOOL fNeedRedirect = TRUE;
DC_BEGIN_FN("CO_OnServerRedirectionPacket");
TRC_DBG((TB, _T("RDP_SERVER_REDIRECTION_PACKET")));
//
// Notify the CLX test harness of the redirection packet
//
_pClx->CLX_RedirectNotify(pPkt, dataLen);
if (dataLen < pPkt->Length) {
TRC_ABORT(( TB, _T("packet length incorrect")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (pPkt->Flags & RDP_SEC_REDIRECTION_PKT) {
// Copy the address to an aligned buffer.
length = min(pPkt->Length + sizeof(WCHAR) - sizeof(RDP_SERVER_REDIRECTION_PACKET),
sizeof(AlignedAddress));
if (length > 0 && length <= sizeof(AlignedAddress)) {
memcpy(AlignedAddress, pPkt->ServerAddress, length);
// Set the redir info in UI and disconnect.
_pUi->UI_SetServerRedirectionInfo(pPkt->SessionID, AlignedAddress,
NULL, 0, fNeedRedirect);
}
}
else if (pPkt->Flags & RDP_SEC_REDIRECTION_PKT2) {
RDP_SERVER_REDIRECTION_PACKET_V2 UNALIGNED *pPkt2 =
(RDP_SERVER_REDIRECTION_PACKET_V2 UNALIGNED*)pPkt;
PBYTE LBInfo = NULL;
PBYTE ServerName = NULL;
PBYTE pBuf = NULL;
unsigned LBInfoSize = 0;
unsigned ServerNameSize = 0;
pBuf = (PBYTE)(pPkt2 + 1);
if (pPkt2->RedirFlags & TARGET_NET_ADDRESS) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, ServerName,
ServerNameSize, TARGET_NET_ADDRESS);
}
if (pPkt2->RedirFlags & LOAD_BALANCE_INFO) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, LBInfo,
LBInfoSize, LOAD_BALANCE_INFO);
}
if (ServerNameSize > 0 && ServerNameSize <= sizeof(AlignedAddress)) {
memcpy(AlignedAddress, ServerName, ServerNameSize);
// Set the redir info in UI and disconnect.
_pUi->UI_SetServerRedirectionInfo(pPkt2->SessionID, AlignedAddress,
NULL, 0, fNeedRedirect);
}
else {
// Set the redir info in UI and disconnect. That LBInfo is going to
// be there indicates to XT_SendCR that we are in the middle of
// a redirect and should use the redirect info instead of scripting
// or hash-mode cookie.
_pUi->UI_SetServerRedirectionInfo(pPkt2->SessionID,
_pUi->_UI.strAddress, LBInfo, LBInfoSize, fNeedRedirect);
}
}
else if (pPkt->Flags & RDP_SEC_REDIRECTION_PKT3) {
RDP_SERVER_REDIRECTION_PACKET_V3 UNALIGNED *pPkt3 =
(RDP_SERVER_REDIRECTION_PACKET_V3 UNALIGNED*)pPkt;
PBYTE LBInfo = NULL;
PBYTE ServerName = NULL;
PBYTE pBuf = NULL;
PBYTE pUserName = NULL;
PBYTE pDomain = NULL;
PBYTE pClearPassword = NULL;
unsigned LBInfoSize = 0;
unsigned ServerNameSize = 0;
unsigned UserNameSize = 0;
unsigned DomainSize = 0;
unsigned PasswordSize = 0;
pBuf = (PBYTE)(pPkt3 + 1);
if (pPkt3->RedirFlags & TARGET_NET_ADDRESS) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, ServerName,
ServerNameSize, TARGET_NET_ADDRESS);
}
if (pPkt3->RedirFlags & LOAD_BALANCE_INFO) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, LBInfo,
LBInfoSize, LOAD_BALANCE_INFO);
}
if (pPkt3->RedirFlags & LB_USERNAME) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, pUserName,
UserNameSize, LB_USERNAME);
}
if (pPkt3->RedirFlags & LB_DOMAIN) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, pDomain,
DomainSize, LB_DOMAIN);
}
if (pPkt3->RedirFlags & LB_PASSWORD) {
CHECK_ULONGLEN_STRING(pBuf, pEnd, pClearPassword,
PasswordSize, LB_PASSWORD);
}
if (pPkt3->RedirFlags & LB_SMARTCARD_LOGON) {
_pUi->UI_SetUseSmartcardLogon(TRUE);
}
if ((pPkt3->RedirFlags & LB_NOREDIRECT) != 0) {
fNeedRedirect = FALSE;
}
if (UserNameSize > 0) {
PBYTE pAlignedUserName = (PBYTE)LocalAlloc(LPTR,
UserNameSize+sizeof(TCHAR));
if (pAlignedUserName) {
memset(pAlignedUserName, 0, UserNameSize+sizeof(TCHAR));
memcpy(pAlignedUserName, pUserName, UserNameSize);
if (pPkt3->RedirFlags & LB_DONTSTOREUSERNAME) {
_pUi->UI_SetRedirectionUserName((LPTSTR)pAlignedUserName);
} else {
_pUi->UI_SetUserName((LPTSTR)pAlignedUserName);
}
LocalFree(pAlignedUserName);
}
}
if (DomainSize > 0) {
PBYTE pAlignedDomain = (PBYTE)LocalAlloc(LPTR,
DomainSize+sizeof(TCHAR));
if (pAlignedDomain) {
memset(pAlignedDomain, 0, DomainSize+sizeof(TCHAR));
memcpy(pAlignedDomain, pDomain, DomainSize);
_pUi->UI_SetDomain((LPTSTR)pAlignedDomain);
LocalFree(pAlignedDomain);
}
}
if ((PasswordSize > 0) &&
((PasswordSize + sizeof(TCHAR)) <= UI_MAX_PASSWORD_LENGTH)) {
PBYTE pAlignedClearPass = (PBYTE)LocalAlloc(LPTR,
UI_MAX_PASSWORD_LENGTH);
if (pAlignedClearPass) {
SecureZeroMemory(pAlignedClearPass, UI_MAX_PASSWORD_LENGTH);
memcpy(pAlignedClearPass, pClearPassword, PasswordSize);
BYTE Salt[UT_SALT_LENGTH];
//
// The password has to be stored in our internal 'obfuscated'
// format.
//
if(TSRNG_GenerateRandomBits(Salt, sizeof(Salt))) {
//Encrypt the password
if(EncryptDecryptLocalData50(pAlignedClearPass,
PasswordSize,
Salt, sizeof(Salt))) {
_pUi->UI_SetPassword( pAlignedClearPass );
_pUi->UI_SetSalt( Salt);
}
else {
TRC_ERR((TB,_T("Error encrytping password")));
}
}
else {
TRC_ERR((TB,_T("Error generating salt")));
}
//
// For security reasons clear the password field
//
SecureZeroMemory(pAlignedClearPass, PasswordSize+sizeof(TCHAR));
SecureZeroMemory(pClearPassword, PasswordSize);
LocalFree(pAlignedClearPass);
//
// Set the autologon flag
//
if (UserNameSize)
{
_pUi->_UI.fAutoLogon = TRUE;
}
}
}
if (ServerNameSize > 0 && ServerNameSize <= sizeof(AlignedAddress)) {
memcpy(AlignedAddress, ServerName, ServerNameSize);
// Set the redir info in UI and disconnect.
_pUi->UI_SetServerRedirectionInfo(pPkt3->SessionID, AlignedAddress,
NULL, 0, fNeedRedirect);
}
else {
// Set the redir info in UI and disconnect. That LBInfo is going to
// be there indicates to XT_SendCR that we are in the middle of
// a redirect and should use the redirect info instead of scripting
// or hash-mode cookie.
_pUi->UI_SetServerRedirectionInfo(pPkt3->SessionID,
_pUi->_UI.strAddress, LBInfo, LBInfoSize, fNeedRedirect);
}
}
else {
TRC_ERR((TB,_T("Unexpected redirection packet")));
}
if (fNeedRedirect) {
CO_Disconnect();
}
DC_EXIT_POINT:
if (FAILED(hr) && IMMEDIATE_DISSCONNECT_ON_HR(hr)) {
TRC_ABORT((TB, _T("Disconnect for security")));
CO_DropLinkImmediate(SL_ERR_INVALIDPACKETFORMAT, hr);
}
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Name: CO_OnBufferAvailable */
/* */
/* Purpose: Handle BufferAvailable notification from SL. */
/****************************************************************************/
void DCCALLBACK CCO::CO_OnBufferAvailable()
{
DC_BEGIN_FN("CO_OnBufferAvailable");
// Tell the Sender Thread.
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
_pSnd,
CD_NOTIFICATION_FUNC(CSND,SND_BufferAvailable),
(ULONG_PTR) 0);
DC_END_FN();
} /* CO_OnBufferAvailable */
//
// CO_DropLinkImmediate
//
// Purpose: Immediately drops the link without doing a gracefull connection
// shutdown (i.e. no DPUm is sent and we don't transition to the SND
// thread at any point before dropping the link). Higher level components
// will still get all the usual disconnect notifications so they can
// be properly torn down.
//
// This call was added to trigger an immediate disconnect in cases
// where we detect invalid data that could be due to an attack, it
// ensures we won't receive any more data after the call returns
//
// Params: reason - SL disconnect reason code
// hrDisconnect - hresult as to why the TSC_CORE wanted to disconnect
//
// Returns: HRESULT
//
// Thread context: Call on RCV thread
//
HRESULT DCINTERNAL CCO::CO_DropLinkImmediate(UINT reason, HRESULT hrDisconnect )
{
DC_BEGIN_FN("CO_DropLinkImmediate");
HRESULT hr = E_FAIL;
TRC_ASSERT((NULL != _pSl),
(TB, _T("SL not connected can not drop immediate")));
if (_pSl) {
hr = _pSl->SL_DropLinkImmediate(reason);
}
COSetDisconnectHR(hrDisconnect);
DC_END_FN();
return hr;
}