|
|
/*++
Copyright (c) 1998-2000 Microsoft Corporation
Module Name:
vcint.cpp
Abstract:
This module contains virtual channel interface routines.
Author:
madan appiah (madana) 16-Sep-1998
Revision History:
--*/
#include "precom.h"
#define TRC_FILE "vcint"
#include "cclip.h"
#include "vcint.h"
#include "rdpdrcom.h"
#include "drdbg.h"
#include "rdpsndc.h"
VOID VCAPITYPE RDPDR_InitEventFnEx( IN PVOID lpUserParam, IN PVOID pInitHandle, IN UINT event, IN PVOID pData, IN UINT dataLength ) /*++
Routine Description:
Handles InitEvent callbacks by delegating to the connection manager.
Arguments:
- pInitHandle - a handle uniquely identifying this connection - event - the event that has occurred - see CHANNEL_EVENT_XXX defines - pData - data associated with the event - see CHANNEL_EVENT_XXX defines - dataLength - length of the data.
Return Value:
None
--*/ { CRDPSound *pSound = NULL;
DC_BEGIN_FN("InitEventFn");
ASSERT(lpUserParam != NULL); if(!lpUserParam) { return; }
VCManager* pVCMgr = (VCManager*)lpUserParam; ASSERT(pVCMgr != NULL); if(!pVCMgr) { return; }
CClip* pClip = pVCMgr->GetClip();
ASSERT(pClip != NULL); if(!pClip) { return; }
pVCMgr->ChannelInitEvent(pInitHandle, event, pData, dataLength);
pClip->ClipInitEventFn(pInitHandle, event, pData, dataLength);
if ( pVCMgr->GetInitData()->fEnableRedirectedAudio ) { pSound = pVCMgr->GetSound(); if ( NULL != pSound ) { pSound->InitEventFn( pInitHandle, event, pData, dataLength ); } }
if(CHANNEL_EVENT_TERMINATED == event) { //CLEANUP
pSound = pVCMgr->GetSound(); if ( NULL != pSound ) delete pSound;
delete pVCMgr; delete pClip; }
DC_END_FN(); return; }
VOID VCAPITYPE RDPDR_OpenEventFn( IN LPVOID lpUserParam, IN ULONG openHandle, IN UINT event, IN PVOID pData, IN UINT32 dataLength, IN UINT32 totalLength, IN UINT32 dataFlags ) /*++
Routine Description:
Handles OpenEvent callbacks by delegating to the connection manager.
Arguments:
openHandle - a handle uniquely identifying this channel event - event that has occurred - see CHANNEL_EVENT_XXX below pData - data received dataLength - length of the data totalLength - total length of data written by the Server dataFlags - flags, zero, one or more of: - 0x01 - beginning of data from a single write operation at the Server - 0x02 - end of data from a single write operation at the Server.
Return Value:
None
--*/
{ DC_BEGIN_FN("OpenEventFn");
TRC_NRM((TB, _T("Event %x, handle %lx, datalength %ld, dataFlags %lx"), event, openHandle, dataLength, dataFlags));
ASSERT(lpUserParam != NULL); if(!lpUserParam) { return; } ((VCManager*)lpUserParam)->ChannelOpenEvent(openHandle, event, pData, dataLength, totalLength, dataFlags);
DC_END_FN(); return; }
#ifdef OS_WIN32
BOOL DCAPI #else //OS_WIN32
BOOL __loadds DCAPI #endif //OS_WIN32
RDPDR_VirtualChannelEntryEx( IN PCHANNEL_ENTRY_POINTS_EX pEntryPoints, IN PVOID pInitHandle ) /*++
Routine Description:
Exported API called by the Virtual Channels
Arguments:
pEntryPoints - Entry point structure containing all callback methods.
Return Value:
None.
--*/
{ BOOL rv = FALSE; VCManager* pcmMgr = NULL; CClip* pClip = NULL; CRDPSound *pSound = NULL; CHANNEL_DEF aChannel[3]; UINT uiRet; PCHANNEL_INIT_HANDLE pChanInitHandle; PRDPDR_DATA pRdpDrInitSettings;
DC_BEGIN_FN("VirtualChannelEntry");
if( pEntryPoints->cbSize < sizeof(CHANNEL_ENTRY_POINTS_EX) ) {
//
// we don't have all entry points we need.
//
goto exitpt; }
pChanInitHandle = (PCHANNEL_INIT_HANDLE)pInitHandle; pRdpDrInitSettings = (PRDPDR_DATA)pChanInitHandle->lpInternalAddinParam; ASSERT(pRdpDrInitSettings);
if(!pRdpDrInitSettings) { goto exitpt; }
pcmMgr = new VCManager(pEntryPoints); pRdpDrInitSettings->pUpdateDeviceObj = pcmMgr;
if( pcmMgr == NULL ) { goto exitpt; }
pcmMgr->SetInitData( pRdpDrInitSettings); pClip = new CClip(pcmMgr);
if( pClip == NULL ) { goto exitpt; }
pcmMgr->SetClip( pClip); pClip->SetVCInitHandle( pInitHandle);
pSound = new CRDPSound( pEntryPoints, pInitHandle ); if ( NULL == pSound ) { goto exitpt; } pcmMgr->SetSound( pSound );
if (!pClip->ClipChannelEntry(pEntryPoints)) { TRC_ALT((TB, _T("Clip rejected VirtualChannelEntry"))); goto exitpt; }
memset(aChannel[0].name, 0, CHANNEL_NAME_LEN); memcpy(aChannel[0].name, PRDR_VC_CHANNEL_NAME, strlen(PRDR_VC_CHANNEL_NAME));
aChannel[0].options = CHANNEL_OPTION_COMPRESS_RDP;
memset(aChannel[1].name, 0, CHANNEL_NAME_LEN); memcpy(aChannel[1].name, CLIP_CHANNEL, sizeof(CLIP_CHANNEL)); aChannel[1].options = CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
memset( aChannel[2].name, 0, CHANNEL_NAME_LEN ); memcpy( aChannel[2].name, _SNDVC_NAME, sizeof( _SNDVC_NAME )); aChannel[2].options = CHANNEL_OPTION_ENCRYPT_RDP;
uiRet = (pEntryPoints->pVirtualChannelInitEx)(pcmMgr, pInitHandle, aChannel, 3, VIRTUAL_CHANNEL_VERSION_WIN2000, RDPDR_InitEventFnEx);
TRC_NRM((TB, _T("VirtualChannelInit rc[%d]"), uiRet));
if( uiRet != CHANNEL_RC_OK ) { goto exitpt; }
rv = TRUE;
exitpt: if ( !rv ) { if ( NULL != pClip ) delete pClip;
if ( NULL != pSound ) delete pSound;
if ( NULL != pcmMgr ) delete pcmMgr; }
DC_END_FN();
return(rv); }
/* ----------------------------------------------------------------*/
VCManager::VCManager( IN PCHANNEL_ENTRY_POINTS_EX pEntries ) /*++
Routine Description:
Initilizes the system, and determines which processor to load for the given operating system.
Arguments:
Id - Connection Id
Return Value:
None
--*/
{ DC_BEGIN_FN("VCManager::VCManager");
_bState = STATE_UNKNOWN; _ChannelEntries = *pEntries;
_pProcObj = NULL; _hVCHandle = NULL; _Buffer.uiLength = _Buffer.uiAvailLen = 0; _Buffer.pbData = NULL; _hVCOpenHandle = 0; //_pRdpDrInitSettings receives settings from the core
_pRdpDrInitSettings = NULL;
DC_END_FN(); }
VOID VCManager::ChannelWrite( IN LPVOID pData, IN UINT uiLength ) /*++
Routine Description:
Abstracts writing data to the channel for the processing components
If the write should fail, this function releases the outgoing buffer.
Arguments:
pData - Data to be written uiLength - Length of data to write
Return Value:
None
--*/ { DC_BEGIN_FN("VCManager::ChannelWrite"); TRC_NRM((TB, _T("Data[%p] Length[%d]"), pData, uiLength));
#if DBG
if( !IsValidHeader(pData) ) { TRC_ERR((TB, _T("Sending an invalid dr header"))); } #endif // DBG
UINT uiRet;
uiRet = (_ChannelEntries.pVirtualChannelWriteEx)( _hVCHandle, _hVCOpenHandle, pData, uiLength, (PVOID)pData);
TRC_NRM((TB, _T("VirtualChannelWrite Ret [%d]"), uiRet));
switch (uiRet) { case CHANNEL_RC_OK: break;
case CHANNEL_RC_NOT_INITIALIZED: ASSERT(FALSE); break;
case CHANNEL_RC_NOT_CONNECTED: { //Valid to receive this because we can be getting
//disconnected on another thread
TRC_ALT((TB,_T("Write failed with CHANNEL_RC_NOT_CONNECTED"))); } break;
case CHANNEL_RC_BAD_CHANNEL_HANDLE: ASSERT(FALSE); break;
case CHANNEL_RC_NULL_DATA: ASSERT(FALSE); break;
case CHANNEL_RC_ZERO_LENGTH: ASSERT(FALSE); break;
default: TRC_ALT((TB, _T("Unknown return value for VirtualChannelWrite[%d]\n"), uiRet)); break; }
//
// Release the buffer on failure.
//
if (uiRet != CHANNEL_RC_OK) { delete []((BYTE *)pData); }
DC_END_FN(); return; }
UINT VCManager::ChannelWriteEx( IN LPVOID pData, IN UINT uiLength ) /*++
Routine Description:
Abstracts writing data to the channel for the processing components. This version returns the return value back
If this function fails the buffer is released.
Arguments:
pData - Data to be written uiLength - Length of data to write
Return Value:
CHANNEL_RC_OK CHANNEL_RC_NOT_INITIALIZED CHANNEL_RC_NOT_CONNECTED CHANNEL_RC_BAD_CHANNEL_HANDLE CHANNEL_RC_NULL_DATA CHANNEL_RC_ZERO_LENGTH
--*/ { DC_BEGIN_FN("VCManager::ChannelWriteEx"); TRC_NRM((TB, _T("Data[%p] Length[%d]"), pData, uiLength));
#if DBG
if( !IsValidHeader(pData) ) { TRC_ERR((TB, _T("Sending an invalid dr header"))); } #endif // DBG
UINT uiRet;
uiRet = (_ChannelEntries.pVirtualChannelWriteEx)( _hVCHandle, _hVCOpenHandle, pData, uiLength, (PVOID)pData);
if (uiRet != CHANNEL_RC_OK) { TRC_NRM((TB, _T("VirtualChannelWrite Ret [%d]"), uiRet)); delete []((BYTE *)pData); }
return uiRet; }
/*++
Routine Description:
Closes the virtual channel
Arguments:
None
Return Value:
CHANNEL_RC_OK on Success - see VirtualChannelClose docs in MSDN
--*/ UINT VCManager::ChannelClose() { UINT uiRet;
DC_BEGIN_FN("ChannelClose");
uiRet = (_ChannelEntries.pVirtualChannelCloseEx)( _hVCHandle, _hVCOpenHandle);
if (uiRet != CHANNEL_RC_OK) { TRC_ERR((TB, _T("VirtualChannelClose Ret [%d]"), uiRet)); }
DC_END_FN(); return uiRet; }
VOID VCManager::ChannelInitEvent( IN PVOID pInitHandle, IN UINT uiEvent, IN PVOID pData, IN UINT uiDataLength ) /*++
Routine Description:
Handles InitEvent callbacks
Arguments:
pInitHandle - a handle uniquely identifying this connection
uiEvent - the event that has occurred - see CHANNEL_EVENT_XXX defines
pData - data associated with the event - see CHANNEL_EVENT_XXX defines
uiDataLength - length of the data.
Return Value:
None
--*/
{ DC_BEGIN_FN("VCManager::ChannelInitEvent"); UNREFERENCED_PARAMETER( pData ); UNREFERENCED_PARAMETER( uiDataLength );
UINT uiRetVal;
TRC_NRM((TB, _T("Event %d, handle %p"), uiEvent, pInitHandle));
if (_hVCHandle == NULL) _hVCHandle = pInitHandle;
switch (uiEvent) { case CHANNEL_EVENT_INITIALIZED :
ASSERT(_bState == STATE_UNKNOWN);
_bState = CHANNEL_EVENT_INITIALIZED; break;
case CHANNEL_EVENT_CONNECTED :
ASSERT((_bState == CHANNEL_EVENT_INITIALIZED) || (_bState == CHANNEL_EVENT_DISCONNECTED));
//
// Create the platform-specific Processing instance
//
TRC_NRM((TB, _T("VCManager::ChannelnitEvent: Creating processor."))); _pProcObj = ProcObj::Instantiate(this);
if( _pProcObj == NULL ) { TRC_NRM((TB, _T("Error creating processor."))); return; }
//
// Initialize the proc obj instance
//
uiRetVal = (UINT) _pProcObj->Initialize();
if( uiRetVal != ERROR_SUCCESS ) { delete _pProcObj; _pProcObj = NULL; return; }
//
// Open the virtual channel interface.
//
uiRetVal = (_ChannelEntries.pVirtualChannelOpenEx)( _hVCHandle, &_hVCOpenHandle, PRDR_VC_CHANNEL_NAME, &RDPDR_OpenEventFn);
TRC_NRM((TB, _T("VirtualChannelOpen Ret[%d]"), uiRetVal));
_bState = CHANNEL_EVENT_CONNECTED;
break;
case CHANNEL_EVENT_V1_CONNECTED : ASSERT((_bState == CHANNEL_EVENT_INITIALIZED) || (_bState == CHANNEL_EVENT_DISCONNECTED));
_bState = CHANNEL_EVENT_V1_CONNECTED; break;
case CHANNEL_EVENT_DISCONNECTED : //ASSERT((_bState == CHANNEL_EVENT_CONNECTED) ||
// (_bState == CHANNEL_EVENT_V1_CONNECTED));
if (_pProcObj) { delete _pProcObj; _pProcObj = NULL; }
_bState = CHANNEL_EVENT_DISCONNECTED; break;
case CHANNEL_EVENT_TERMINATED : /*
DbgAssert((_bState == CHANNEL_EVENT_DISCONNECTED) || (_bState == CHANNEL_EVENT_V1_CONNECTED) || (_bState == CHANNEL_EVENT_INITIALIZED), ("_bState[%d] is in inproper position to be TERMINATED", _bState)); */
if (_pProcObj) { delete _pProcObj; _pProcObj = NULL; }
_bState = CHANNEL_EVENT_TERMINATED;
break;
default:
TRC_ALT((TB, _T("Unknown Event in ChannelInitEvent recieved[%d]\n"), uiEvent));
break; }
DC_END_FN(); return; }
VOID VCManager::ChannelOpenEvent( IN ULONG ulOpenHandle, IN UINT uiEvent, IN PVOID pData, IN UINT32 uiDataLength, IN UINT32 uiTotalLength, IN UINT32 uiDataFlags ) /*++
Routine Description:
Handles OpenEvent callbacks
Arguments:
ulOpenHandle - a handle uniquely identifying this channel uiEvent - event that has occurred - see CHANNEL_EVENT_XXX below pData - data received uiDataLength - length of the data uiTotalLength - total length of data written by the Server uiDataFlags - flags, zero, one or more of: - 0x01 - beginning of data from a single write operation at the Server - 0x02 - end of data from a single write operation at the Server.
Return Value:
None
--*/ { DC_BEGIN_FN("VCManager::ChannelOpenEvent");
TRC_NRM((TB, _T("Event[0x%x], uiDataLength[%ld], uiDataFlags[0x%lx]"), uiEvent, uiDataLength, uiDataFlags));
ASSERT(ulOpenHandle == _hVCOpenHandle);
//
// not for us, simply return.
//
if( ulOpenHandle != _hVCOpenHandle ) { return; }
ASSERT(uiDataLength <= uiTotalLength);
//
// total length much less, give up.
//
if( uiDataLength > uiTotalLength ) { return; }
//
// free data buffer on write complete.
//
if ((uiEvent == CHANNEL_EVENT_WRITE_COMPLETE) || (uiEvent == CHANNEL_EVENT_WRITE_CANCELLED)) {
delete []((BYTE *)pData); TRC_NRM((TB, _T("VCManager::ChannelOpenEvent:S:WriteComplete"))); return; }
ASSERT(uiEvent == CHANNEL_EVENT_DATA_RECEIVED);
//
// alocated new buffer for incoming data.
//
if( (uiDataFlags == CHANNEL_FLAG_FIRST) || (uiDataFlags == CHANNEL_FLAG_ONLY) ) {
TRC_NRM((TB, _T("Allocating %ld bytes"), uiTotalLength));
_Buffer.pbData = new BYTE[uiTotalLength];
if( _Buffer.pbData == NULL ) { TRC_ERR((TB,_T("_Buffer.pbData is NULL"))); return; }
_Buffer.uiLength = 0; _Buffer.uiAvailLen = uiTotalLength; }
if( _Buffer.pbData == NULL ) { TRC_ERR((TB,_T("_Buffer.pbData is NULL"))); return; }
//
// copy first part of the data in the buffer.
//
if (uiDataFlags == CHANNEL_FLAG_FIRST) {
TRC_NRM((TB, _T("CHANNEL_FLAG_FIRST Creating:[%ld]"), uiTotalLength));
memcpy(_Buffer.pbData, pData, uiDataLength); _Buffer.uiLength = uiDataLength;
TRC_NRM((TB, _T("VCManager::ChannelOpenEvent[1]"))); return; }
//
// add data to the buffer.
//
UINT32 uiLen; uiLen = _Buffer.uiLength + uiDataLength; ASSERT(_Buffer.uiAvailLen >= uiLen);
//
// too much data arrived.
//
if( _Buffer.uiAvailLen < uiLen ) { TRC_ERR((TB,_T("Too much data arrived: avail:0x%x arrived:0x%x"), _Buffer.uiAvailLen, uiLen));
//
// Disconnect the channel
//
ChannelClose(); return; }
memcpy( _Buffer.pbData + _Buffer.uiLength, pData, uiDataLength ); _Buffer.uiLength = uiLen;
if (uiDataFlags == CHANNEL_FLAG_MIDDLE) { TRC_NRM((TB, _T("VCManager::ChannelOpenEvent[2]"))); return; }
//
// complete data buffer available, process it.
//
_pProcObj->ProcessServerPacket(&_Buffer);
DC_END_FN(); return; }
void VCManager::OnDeviceChange(WPARAM wParam, LPARAM lParam) /*++
Routine Description:
Receive a device change notification from the control. Pass it to the proc obj to handle.
Arguments:
Return Value:
None.
--*/
{ if (_pProcObj != NULL) { _pProcObj->OnDeviceChange(wParam, lParam); } }
|