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.
 
 
 
 
 
 

2894 lines
117 KiB

/**MOD+**********************************************************************/
/* Module: cchannel.c */
/* */
/* Purpose: Virtual Channel Client functions */
/* */
/* Copyright(C) Microsoft Corporation 1997 */
/* */
/****************************************************************************/
/* Changes: */
/* $Log$ */
/* */
/**MOD-**********************************************************************/
/****************************************************************************/
/****************************************************************************/
/* HEADERS */
/****************************************************************************/
/****************************************************************************/
#include <adcg.h>
extern "C" {
#define TRC_GROUP TRC_GROUP_NETWORK
#define TRC_FILE "cchannel"
#include <atrcapi.h>
}
#include "autil.h"
#include "wui.h"
#include "sl.h"
#include "nc.h"
#include "cd.h"
#include "cchan.h"
CChan* CChan::pStaticClientInstance = NULL;
/****************************************************************************/
/****************************************************************************/
/* Constants */
/****************************************************************************/
/****************************************************************************/
#define CHANNEL_MSG_SEND 1
#define CHANNEL_MSG_SUSPEND 2
#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(P) (P)
#endif
#define WEBCTRL_DLL_NAME TEXT("mstscax.dll")
#ifdef DEBUG_CCHAN_COMPRESSION
_inline ULONG DbgUserPrint(TCHAR* Format, ...)
{
va_list arglist;
TCHAR Buffer[512];
ULONG retval;
//
// Format the output into a buffer and then print it.
//
va_start(arglist, Format);
retval = _vsntprintf(Buffer, sizeof(Buffer), Format, arglist);
if (retval != -1) {
OutputDebugString(Buffer);
}
return retval;
}
#endif
CChan::CChan(CObjs* objs)
{
DC_BEGIN_FN("CChan");
_pClientObjs = objs;
_pInitHandle = NULL;
_pFirstWrite = NULL;
_pLastWrite = NULL;
_connected = CONNECTION_NONE;
_inChannelEntry = FALSE;
_ChannelInitCalled = FALSE;
_channelCount = 0;
_fCapsVCCompressionSupported = FALSE;
_fCompressChannels = FALSE;
if(!CChan::pStaticClientInstance)
{
//
// Legacy addins can only talk to the initial instance of the client
//
CChan::pStaticClientInstance = this;
}
_pMPPCContext = NULL;
_CompressFlushes = 0;
_fCompressionFlushed = 0;
_pUserOutBuf = NULL;
_fNeedToResetContext = TRUE;
_fLockInitalized = FALSE;
#ifdef DEBUG_CCHAN_COMPRESSION
_pDbgRcvDecompr8K = NULL;
_fDbgVCTriedAllocRecvContext = FALSE;
_fDbgAllocFailedForVCRecvContext = TRUE;
#endif
_iDbgCompressFailedCount = 0;
_iChanSuspendCount = 0;
_iChanResumeCount = 0;
_iChanCapsRecvdCount = 0;
DC_END_FN();
}
CChan::~CChan()
{
if(_fLockInitalized)
{
DeleteCriticalSection(&_VirtualChannelInitLock);
}
if(this == CChan::pStaticClientInstance)
{
CChan::pStaticClientInstance = NULL;
}
}
VOID CChan::SetCapabilities(LONG caps)
{
DC_BEGIN_FN("SetCapabilities");
//
// Determine if we can send compressed VC data to the server
// NOTE: for a few whistler builds the server supported 64K
// compressed channels from the client, but this capability
// has been removed to enhance server scalability.
//
// The capability in the other direction, e.g can the server send
// us compressed data is something the client exposes to the server
//
_iChanCapsRecvdCount++;
_fCapsVCCompressionSupported = (caps & TS_VCCAPS_COMPRESSION_8K) ?
TRUE : FALSE;
TRC_NRM((TB,_T("VC Caps, compression supported: %d"),
_fCapsVCCompressionSupported));
_fCompressChannels = (_fCapsVCCompressionSupported & _pUi->UI_GetCompress());
TRC_NRM((TB,_T("Compress virtual channels: %d"),
_fCompressChannels));
DC_END_FN();
}
void CChan::OnDeviceChange(ULONG_PTR params)
{
PDEVICE_PARAMS deviceParams = (PDEVICE_PARAMS)params;
if (deviceParams->deviceObj != NULL) {
deviceParams->deviceObj->OnDeviceChange(deviceParams->wParam, deviceParams->lParam);
}
}
/****************************************************************************/
/****************************************************************************/
/* API Functions */
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/* VirtualChannelInit - see cchannel.h */
/****OC-*********************************************************************/
UINT VCAPITYPE DCEXPORT VirtualChannelInitEx(
PVOID lpUserParam,
PVOID pInitHandle,
PCHANNEL_DEF pChannel,
INT channelCount,
DWORD versionRequested,
PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
{
DC_BEGIN_FN("VirtualChannelInitEx");
UINT rc = CHANNEL_RC_OK;
/************************************************************************/
/* Check parameters */
/************************************************************************/
if (NULL == pInitHandle)
{
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
rc = ((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst->IntVirtualChannelInit(
lpUserParam,
NULL, pChannel,
channelCount,
versionRequested,
NULL,
pChannelInitEventProcEx);
DC_EXIT_POINT:
return (rc);
DC_END_FN();
}
UINT VCAPITYPE DCEXPORT VirtualChannelInit(
PVOID * ppInitHandle,
PCHANNEL_DEF pChannel,
INT channelCount,
DWORD versionRequested,
PCHANNEL_INIT_EVENT_FN pChannelInitEventProc)
{
DC_BEGIN_FN("VirtualChannelInit");
UINT rc = CHANNEL_RC_OK;
/************************************************************************/
/* Check parameters */
/************************************************************************/
TRC_ASSERT( CChan::pStaticClientInstance,
(TB, _T("CChan::pStaticClientInstance is NULL in VirtualChannelInit\n")));
if (NULL == CChan::pStaticClientInstance)
{
rc = CHANNEL_RC_INVALID_INSTANCE;
DC_QUIT;
}
rc = (CChan::pStaticClientInstance)->IntVirtualChannelInit(
NULL,
ppInitHandle, pChannel,
channelCount,
versionRequested,
pChannelInitEventProc,
NULL);
DC_EXIT_POINT:
return (rc);
DC_END_FN();
}
UINT VCAPITYPE DCEXPORT CChan::IntVirtualChannelInit(
PVOID pParam,
PVOID * ppInitHandle,
PCHANNEL_DEF pChannel,
INT channelCount,
DWORD versionRequested,
PCHANNEL_INIT_EVENT_FN pChannelInitEventProc,
PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
{
UINT rc = CHANNEL_RC_OK;
INT i, j, k;
PCHANNEL_INIT_HANDLE pRealInitHandle;
DC_BEGIN_FN("IntVirtualChannelInit");
UNREFERENCED_PARAMETER( versionRequested );
EnterCriticalSection(&_VirtualChannelInitLock);
/************************************************************************/
/* Check parameters */
/************************************************************************/
if( versionRequested > VIRTUAL_CHANNEL_VERSION_WIN2000)
{
rc = CHANNEL_RC_UNSUPPORTED_VERSION;
DC_QUIT;
}
//
// ppInitHandle is not used by the EX version of the API
//
if (pChannelInitEventProc && ppInitHandle == NULL)
{
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if(pChannelInitEventProc && IsBadWritePtr(ppInitHandle, sizeof(PVOID)))
{
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (pChannel == NULL)
{
rc = CHANNEL_RC_BAD_CHANNEL;
DC_QUIT;
}
if(channelCount <= 0)
{
rc = CHANNEL_RC_BAD_CHANNEL;
DC_QUIT;
}
if ((IsBadReadPtr(pChannel, channelCount * sizeof(CHANNEL_DEF))) ||
(IsBadWritePtr(pChannel, channelCount * sizeof(CHANNEL_DEF))))
{
rc = CHANNEL_RC_BAD_CHANNEL;
DC_QUIT;
}
if ((_channelCount + channelCount) > CHANNEL_MAX_COUNT)
{
rc = CHANNEL_RC_TOO_MANY_CHANNELS;
DC_QUIT;
}
for (i = 0; i < channelCount; i++)
{
for (j = 0; j <= CHANNEL_NAME_LEN; j++)
{
if (pChannel[i].name[j] == '\0')
{
break;
}
}
if (!j || j > CHANNEL_NAME_LEN)
{
/****************************************************************/
/* There was no terminating null in this channel name string */
/* or the channel name was zero length */
/****************************************************************/
rc = CHANNEL_RC_BAD_CHANNEL;
DC_QUIT;
}
}
if (pChannelInitEventProc == NULL && pChannelInitEventProcEx == NULL)
{
rc = CHANNEL_RC_BAD_PROC;
DC_QUIT;
}
/************************************************************************/
/* Check state */
/************************************************************************/
if (_connected != CONNECTION_NONE)
{
rc = CHANNEL_RC_ALREADY_CONNECTED;
DC_QUIT;
}
if (!_inChannelEntry)
{
TRC_ERR((TB,_T("VirtualChannelInit called outside VirtualChannelEntry")));
rc = CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
DC_QUIT;
}
/************************************************************************/
/* Save the fact that VirtualChannelInit has been called, so that */
/* IntChannelLoad knows it's done. */
/************************************************************************/
_ChannelInitCalled = TRUE;
/************************************************************************/
/* Initialize a handle (allocated by VirtualChannelEntry) */
/************************************************************************/
pRealInitHandle = _newInitHandle;
pRealInitHandle->pInitEventFn = pChannelInitEventProc;
pRealInitHandle->pInitEventExFn = pChannelInitEventProcEx;
pRealInitHandle->channelCount = channelCount;
pRealInitHandle->dwFlags = 0;
if(pChannelInitEventProcEx)
{
pRealInitHandle->lpParam = pParam;
pRealInitHandle->fUsingExApi = TRUE;
}
else
{
pRealInitHandle->fUsingExApi = FALSE;
}
/************************************************************************/
/* Process all Channel data */
/************************************************************************/
for (i = 0, j = _channelCount; i < channelCount; i++)
{
/********************************************************************/
/* Assume it's going to be OK */
/********************************************************************/
pChannel[i].options |= CHANNEL_OPTION_INITIALIZED;
/********************************************************************/
/* Check for duplicate names */
/********************************************************************/
for (k = 0; k < j; k++)
{
#ifdef UNICODE
TRC_DBG((TB, _T("Test %S (#%d) for (case insensitive) dup with %S ((#%d)"),
pChannel[i].name, i, _channel[k].name, k));
#else
TRC_DBG((TB, _T("Test %s (#%d) for (case insensitive) dup with %s ((#%d)"),
pChannel[i].name, i, _channel[k].name, k));
#endif
if (0 == DC_ASTRNICMP(pChannel[i].name, _channel[k].name,
CHANNEL_NAME_LEN))
{
/************************************************************/
/* Tell the caller this channel is not initialized */
/************************************************************/
#ifdef UNICODE
TRC_ERR((TB, _T("Dup channel name %S (#%d/#%d)"),
pChannel[i].name, i, k));
#else
TRC_ERR((TB, _T("Dup channel name %s (#%d/#%d)"),
pChannel[i].name, i, k));
#endif
pChannel[i].options &= (~(CHANNEL_OPTION_INITIALIZED));
pRealInitHandle->channelCount--;
break;
}
}
if (pChannel[i].options & CHANNEL_OPTION_INITIALIZED)
{
/****************************************************************/
/* Channel is OK - save its data */
/****************************************************************/
DC_MEMCPY(_channel[j].name, pChannel[i].name, CHANNEL_NAME_LEN);
//name length is CHANNEL_NAME_LEN+1, ensure null termination
_channel[j].name[CHANNEL_NAME_LEN] = 0;
/****************************************************************/
/* Channels are lower case */
/****************************************************************/
DC_ACSLWR(_channel[j].name);
_channel[j].options = pChannel[i].options;
#ifdef UNICODE
TRC_NRM((TB, _T("Channel #%d, %S"), i, _channel[j].name));
#else
TRC_NRM((TB, _T("Channel #%d, %s"), i, _channel[j].name));
#endif
_channelData[j].pOpenEventFn = NULL;
_channelData[j].pOpenEventExFn = NULL;
_channelData[j].MCSChannelID = 0;
_channelData[j].pInitHandle = pRealInitHandle;
_channelData[j].status = CHANNEL_STATUS_CLOSED;
_channelData[j].priority =
(_channel[j].options & CHANNEL_OPTION_PRI_HIGH) ? TS_HIGHPRIORITY:
(_channel[j].options & CHANNEL_OPTION_PRI_MED) ? TS_MEDPRIORITY:
TS_LOWPRIORITY;
TRC_NRM((TB, _T(" Priority %d"), _channelData[j].priority));
//Ignore all flags, channels always encrypt
_channelData[j].SLFlags = RNS_SEC_ENCRYPT;
_channelData[j].VCFlags =
(_channel[j].options & CHANNEL_OPTION_SHOW_PROTOCOL) ?
CHANNEL_FLAG_SHOW_PROTOCOL : 0;
#ifdef UNICODE
TRC_NRM((TB, _T("Channel %S has %s shadow persistent option"), _channel[j].name,
(_channel[j].options & CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT)? _T(""): _T("NO")));
#else
TRC_NRM((TB, _T("Channel %S has %s shadow persistent option"), _channel[j].name,
(_channel[j].options & CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT) ? _T(""): _T("NO")));
#endif
if (_channel[j].options & CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT) {
_channelData[j].VCFlags |= CHANNEL_FLAG_SHADOW_PERSISTENT;
// if one channel is shadow persistent then the whole plugin is too.
pRealInitHandle->dwFlags |= CHANNEL_FLAG_SHADOW_PERSISTENT;
}
TRC_NRM((TB, _T("VC Flags: %#x"), _channelData[j].VCFlags));
j++;
}
}
_channelCount += pRealInitHandle->channelCount;
/************************************************************************/
/* Set return code */
/************************************************************************/
if(!pRealInitHandle->fUsingExApi)
{
*ppInitHandle = pRealInitHandle;
TRC_NRM((TB, _T("Return handle %p"), *ppInitHandle));
}
rc = CHANNEL_RC_OK;
DC_EXIT_POINT:
LeaveCriticalSection(&_VirtualChannelInitLock);
DC_END_FN();
return(rc);
} /* VirtualChannelInit */
/****************************************************************************/
/* VirtualChannelOpen - see cchannel.h */
/****************************************************************************/
UINT VCAPITYPE DCEXPORT VirtualChannelOpen(
PVOID pInitHandle,
PDWORD pOpenHandle,
PCHAR pChannelName,
PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc)
{
DC_BEGIN_FN("VirtualChannelOpen");
UINT rc = CHANNEL_RC_OK;
if (pInitHandle == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
rc = ((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst->IntVirtualChannelOpen(pInitHandle,
pOpenHandle,
pChannelName,
pChannelOpenEventProc,
NULL);
DC_EXIT_POINT:
return (rc);
DC_END_FN();
}
UINT VCAPITYPE DCEXPORT VirtualChannelOpenEx(
PVOID pInitHandle,
PDWORD pOpenHandle,
PCHAR pChannelName,
PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx)
{
DC_BEGIN_FN("VirtualChannelOpenEx");
UINT rc = CHANNEL_RC_OK;
if (pInitHandle == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
rc = ((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst->IntVirtualChannelOpen(pInitHandle,
pOpenHandle,
pChannelName,
NULL,
pChannelOpenEventProcEx);
DC_EXIT_POINT:
return (rc);
DC_END_FN();
}
UINT VCAPITYPE CChan::IntVirtualChannelOpen(
PVOID pInitHandle,
PDWORD pOpenHandle,
PCHAR pChannelName,
PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc,
PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx)
{
PCHANNEL_INIT_HANDLE pRealInitHandle;
UINT channelID;
UINT rc = CHANNEL_RC_OK;
DC_BEGIN_FN("IntVirtualChannelOpen");
pRealInitHandle = (PCHANNEL_INIT_HANDLE)pInitHandle;
/************************************************************************/
/* Check parameters */
/************************************************************************/
if (pInitHandle == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (pRealInitHandle->signature != CHANNEL_INIT_SIGNATURE)
{
TRC_ERR((TB, _T("Invalid init handle signature %#lx"),
pRealInitHandle->signature));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
if (pOpenHandle == NULL)
{
TRC_ERR((TB, _T("NULL Open Handle")));
rc = CHANNEL_RC_BAD_CHANNEL_HANDLE;
DC_QUIT;
}
if(pRealInitHandle->fUsingExApi)
{
if (pChannelOpenEventProcEx == NULL)
{
rc = CHANNEL_RC_BAD_PROC;
DC_QUIT;
}
}
else
{
if (pChannelOpenEventProc == NULL)
{
rc = CHANNEL_RC_BAD_PROC;
DC_QUIT;
}
}
/************************************************************************/
/* Check connection state */
/************************************************************************/
if ((_connected != CONNECTION_VC) &&
(_connected != CONNECTION_SUSPENDED))
{
TRC_ERR((TB, _T("Not yet connected")));
rc = CHANNEL_RC_NOT_CONNECTED;
DC_QUIT;
}
/************************************************************************/
/* Find the requested channel */
/* channel names are lowercase but do a case insensitve cmp */
/* Just incase an older plugin passed in an upper case name (doc was */
/* not clear channel names had to be lower case */
/************************************************************************/
for (channelID = 0; channelID < _channelCount; channelID++)
{
if (0 == DC_ASTRNICMP(pChannelName, _channel[channelID].name,
CHANNEL_NAME_LEN))
{
break;
}
}
if (channelID == _channelCount)
{
#ifdef UNICODE
TRC_ERR((TB, _T("Unregistered channel %S"), pChannelName));
#else
TRC_ERR((TB, _T("Unregistered channel %s"), pChannelName));
#endif
rc = CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
DC_QUIT;
}
/************************************************************************/
/* Check this channel is registered by this user */
/************************************************************************/
if (_channelData[channelID].pInitHandle != pInitHandle)
{
#ifdef UNICODE
TRC_ERR((TB, _T("Channel %S not registered to this user"), pChannelName));
#else
TRC_ERR((TB, _T("Channel %s not registered to this user"), pChannelName));
#endif
rc = CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
DC_QUIT;
}
/************************************************************************/
/* Check that this channel is not already open */
/************************************************************************/
if (_channelData[channelID].status == CHANNEL_STATUS_OPEN)
{
#ifdef UNICODE
TRC_ERR((TB, _T("Channel %S already open"), pChannelName));
#else
TRC_ERR((TB, _T("Channel %s already open"), pChannelName));
#endif
rc = CHANNEL_RC_ALREADY_OPEN;
DC_QUIT;
}
/************************************************************************/
/* Well, everything seems to be in order. Mark the channel as open and */
/* return its index as the handle. */
/************************************************************************/
_channelData[channelID].status = CHANNEL_STATUS_OPEN;
_channelData[channelID].pOpenEventFn = pChannelOpenEventProc;
_channelData[channelID].pOpenEventExFn = pChannelOpenEventProcEx;
*pOpenHandle = channelID;
rc = CHANNEL_RC_OK;
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* VirtualChannelOpen */
/****************************************************************************/
/* VirtualChannelClose - see cchannel.h */
/****************************************************************************/
UINT VCAPITYPE DCEXPORT VirtualChannelClose(DWORD openHandle)
{
UINT rc = CHANNEL_RC_OK;
DC_BEGIN_FN("VirtualChannelClose");
TRC_ASSERT( CChan::pStaticClientInstance,
(TB, _T("CChan::pStaticClientInstance is NULL in VirtualChannelInit\n")));
if (NULL == CChan::pStaticClientInstance)
{
rc = CHANNEL_RC_INVALID_INSTANCE;
DC_QUIT;
}
else
{
rc = (CChan::pStaticClientInstance)->IntVirtualChannelClose(openHandle);
}
DC_END_FN();
DC_EXIT_POINT:
return rc;
}
UINT VCAPITYPE DCEXPORT VirtualChannelCloseEx(LPVOID pInitHandle,
DWORD openHandle)
{
DC_BEGIN_FN("VirtualChannelCloseEx");
UINT rc = CHANNEL_RC_OK;
/************************************************************************/
/* Check parameters */
/************************************************************************/
if (NULL == pInitHandle)
{
return CHANNEL_RC_NULL_DATA;
DC_QUIT;
}
if (((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
return CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
rc = ((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst->IntVirtualChannelClose(
openHandle);
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
UINT VCAPITYPE DCEXPORT CChan::IntVirtualChannelClose(DWORD openHandle)
{
UINT rc = CHANNEL_RC_OK;
DWORD chanIndex;
DC_BEGIN_FN("VirtualChannelClose");
chanIndex = openHandle;
/************************************************************************/
/* Check parameters */
/************************************************************************/
if (chanIndex >= _channelCount)
{
TRC_ERR((TB, _T("Invalid handle %ul ...(channel index portion '%ul' invalid)"),
openHandle, chanIndex));
rc = CHANNEL_RC_BAD_CHANNEL_HANDLE;
DC_QUIT;
}
/************************************************************************/
/* Check we're connected */
/************************************************************************/
if ((_connected != CONNECTION_VC) &&
(_connected != CONNECTION_SUSPENDED))
{
TRC_ALT((TB, _T("Not connected")));
rc = CHANNEL_RC_NOT_CONNECTED;
DC_QUIT;
}
/************************************************************************/
/* Check channel status */
/************************************************************************/
if (_channelData[chanIndex].status != CHANNEL_STATUS_OPEN)
{
TRC_ERR((TB, _T("Channel %ul not open"), chanIndex));
rc = CHANNEL_RC_NOT_OPEN;
DC_QUIT;
}
/************************************************************************/
/* Close the channel */
/************************************************************************/
TRC_NRM((TB, _T("Close channel %ul"), chanIndex));
_channelData[chanIndex].status = CHANNEL_STATUS_CLOSED;
_channelData[chanIndex].pOpenEventFn = NULL;
_channelData[chanIndex].pOpenEventExFn = NULL;
/************************************************************************/
/* Er, that's it */
/************************************************************************/
rc = CHANNEL_RC_OK;
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* VirtualChannelClose */
/****************************************************************************/
/* VirtualChannelWrite - see cchannel.h */
/****************************************************************************/
UINT VCAPITYPE DCEXPORT VirtualChannelWrite(DWORD openHandle,
LPVOID pData,
ULONG dataLength,
LPVOID pUserData)
{
DC_BEGIN_FN("VirtualChannelWrite");
UINT rc = CHANNEL_RC_OK;
TRC_ASSERT( CChan::pStaticClientInstance,
(TB, _T("CChan::pStaticClientInstance is NULL in VirtualChannelInit\n")));
if (NULL == CChan::pStaticClientInstance)
{
rc = CHANNEL_RC_INVALID_INSTANCE;
DC_QUIT;
}
else
{
rc = (CChan::pStaticClientInstance)->IntVirtualChannelWrite(openHandle,
pData,
dataLength,
pUserData);
}
DC_END_FN();
DC_EXIT_POINT:
return rc;
}
UINT VCAPITYPE DCEXPORT VirtualChannelWriteEx(LPVOID pInitHandle,
DWORD openHandle,
LPVOID pData,
ULONG dataLength,
LPVOID pUserData)
{
DC_BEGIN_FN("VirtualChannelWriteEx");
/************************************************************************/
/* Check parameters */
/************************************************************************/
UINT rc = CHANNEL_RC_OK;
if (NULL == pInitHandle)
{
rc = CHANNEL_RC_NULL_DATA;
DC_QUIT;
}
if (((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst == NULL)
{
TRC_ERR((TB, _T("Null Init Handle")));
rc = CHANNEL_RC_BAD_INIT_HANDLE;
DC_QUIT;
}
rc = ((PCHANNEL_INIT_HANDLE)pInitHandle)->pInst->IntVirtualChannelWrite(
openHandle,
pData,
dataLength,
pUserData);
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
UINT VCAPITYPE DCEXPORT CChan::IntVirtualChannelWrite(DWORD openHandle,
LPVOID pData,
ULONG dataLength,
LPVOID pUserData)
{
UINT rc = CHANNEL_RC_OK;
PCHANNEL_WRITE_DECOUPLE pDecouple;
UINT chanIndex;
DC_BEGIN_FN("VirtualChannelWrite");
chanIndex = openHandle;
TRC_DBG((TB, _T("Got channel index: %ul from handle: %d"), chanIndex, openHandle));
/************************************************************************/
/* Check that we're connected */
/************************************************************************/
if ((_connected != CONNECTION_VC) &&
(_connected != CONNECTION_SUSPENDED))
{
TRC_ERR((TB, _T("Not connected")));
rc = CHANNEL_RC_NOT_CONNECTED;
DC_QUIT;
}
/************************************************************************/
/* Check that this channel is open */
/************************************************************************/
if(chanIndex > _channelCount)
{
TRC_ERR((TB, _T("Invalid channel index %ul from handle %ul"), chanIndex,
openHandle));
rc = CHANNEL_RC_BAD_CHANNEL_HANDLE;
DC_QUIT;
}
/************************************************************************/
/* Check that this channel is open */
/************************************************************************/
if (_channelData[chanIndex].status != CHANNEL_STATUS_OPEN)
{
TRC_ERR((TB, _T("Channel %ul not open"), chanIndex));
rc = CHANNEL_RC_BAD_CHANNEL_HANDLE;
DC_QUIT;
}
/************************************************************************/
/* Check parameters */
/************************************************************************/
if (!pData)
{
TRC_ERR((TB, _T("No data passed")));
rc = CHANNEL_RC_NULL_DATA;
DC_QUIT;
}
if (dataLength == 0)
{
TRC_ERR((TB, _T("Zero data length")));
rc = CHANNEL_RC_ZERO_LENGTH;
DC_QUIT;
}
/************************************************************************/
/* Queue the write operation */
/************************************************************************/
pDecouple = (PCHANNEL_WRITE_DECOUPLE) UT_Malloc(_pUt, sizeof(CHANNEL_WRITE_DECOUPLE));
if (pDecouple == NULL)
{
TRC_ERR((TB, _T("Failed to allocate decouple structure")));
rc = CHANNEL_RC_NO_MEMORY;
DC_QUIT;
}
TRC_NRM((TB, _T("Decouple structure allocated at %p"), pDecouple));
pDecouple->signature = CHANNEL_DECOUPLE_SIGNATURE;
pDecouple->pData = pData;
pDecouple->pNextData = pData;
pDecouple->dataLength = dataLength;
pDecouple->dataLeft = dataLength;
pDecouple->dataSent = 0;
pDecouple->openHandle = openHandle;
pDecouple->pUserData = pUserData;
pDecouple->pNext = NULL;
pDecouple->pPrev = NULL;
pDecouple->chanOptions = _channel[chanIndex].options;
pDecouple->flags = _channelData[chanIndex].VCFlags | CHANNEL_FLAG_FIRST;
/************************************************************************/
/* Pass the request to the SND thread */
/************************************************************************/
TRC_NRM((TB, _T("Decouple, pass %p -> %p"), &pDecouple, pDecouple));
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CChan,IntChannelWrite),
&pDecouple,
sizeof(pDecouple));
/************************************************************************/
/* All done! */
/************************************************************************/
rc = CHANNEL_RC_OK;
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* VirtualChannelWrite */
/****************************************************************************/
/****************************************************************************/
/* Callback Functions */
/****************************************************************************/
/****************************************************************************/
/**PROC+*********************************************************************/
/* Name: ChannelOnInitialized */
/* */
/* Purpose: Called when MSTSC completes initialization */
/* */
/* Returns: none */
/* */
/* Params: none */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnInitialized(DCVOID)
{
DC_BEGIN_FN("ChannelOnInitialized");
/************************************************************************/
/* Call Initialized callbacks */
/************************************************************************/
TRC_NRM((TB, _T("Call callbacks ...")));
IntChannelCallCallbacks(CHANNEL_EVENT_INITIALIZED, NULL, 0);
DC_END_FN();
return;
} /* ChannelOnInitialized */
/**PROC+*********************************************************************/
/* Name: ChannelOnTerminating */
/* */
/* Purpose: Call when MSTSC is terminating */
/* */
/* Returns: none */
/* */
/* Params: none */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnTerminating(DCVOID)
{
PCHANNEL_INIT_HANDLE pInitHandle;
PCHANNEL_INIT_HANDLE pFreeHandle;
DC_BEGIN_FN("ChannelOnTerminating");
/************************************************************************/
/* Loop through all handles */
/************************************************************************/
pInitHandle = _pInitHandle;
while (pInitHandle != NULL)
{
TRC_NRM((TB, _T("Terminate handle %p"), pInitHandle));
/********************************************************************/
/* Call the terminated callback */
/********************************************************************/
if(pInitHandle->fUsingExApi)
{
pInitHandle->pInitEventExFn(
pInitHandle->lpParam,
pInitHandle,
CHANNEL_EVENT_TERMINATED,
NULL, 0);
}
else
{
pInitHandle->pInitEventFn(pInitHandle,
CHANNEL_EVENT_TERMINATED,
NULL, 0);
}
/********************************************************************/
/* Free the library */
/********************************************************************/
FreeLibrary(pInitHandle->hMod);
/********************************************************************/
/* Free the handle */
/********************************************************************/
pFreeHandle = pInitHandle;
pInitHandle = pInitHandle->pNext;
pFreeHandle->signature = 0;
UT_Free(_pUt, pFreeHandle);
}
if(_pMPPCContext)
{
UT_Free(_pUt, _pMPPCContext);
_pMPPCContext = NULL;
}
if(_pUserOutBuf)
{
UT_Free(_pUt, _pUserOutBuf);
_pUserOutBuf = NULL;
}
/************************************************************************/
/* Clear key data */
/************************************************************************/
_pInitHandle = NULL;
_channelCount = 0;
_connected = CONNECTION_NONE;
DC_END_FN();
DC_EXIT_POINT:
return;
} /* ChannelOnTerminating */
/**PROC+*********************************************************************/
/* Name: ChannelOnConnected */
/* */
/* Purpose: Called when a connection is established */
/* */
/* Returns: None */
/* */
/* Params: channelID - T128 MCS channel ID */
/* serverVersion - software version of Server */
/* pUserData - Server-Client Net user data */
/* userDataLength - length of user data */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnConnected(DCUINT channelID,
DCUINT32 serverVersion,
PDCVOID pUserData,
DCUINT userDataLength)
{
PRNS_UD_SC_NET pNetUserData;
PDCUINT16 pMCSChannel;
UINT i;
UINT expectedLength;
UINT event;
DCTCHAR serverName[UT_MAX_ADDRESS_LENGTH];
DC_BEGIN_FN("ChannelOnConnected");
UNREFERENCED_PARAMETER( channelID );
#ifndef DC_DEBUG
UNREFERENCED_PARAMETER( userDataLength );
#endif
/************************************************************************/
/* Check Server software version */
/************************************************************************/
if (_RNS_MINOR_VERSION(serverVersion) < 2)
{
TRC_ALT((TB, _T("Old Server - no channel support")));
event = CHANNEL_EVENT_V1_CONNECTED;
_connected = CONNECTION_V1;
}
else
{
TRC_NRM((TB, _T("New Server version - channels supported")));
/********************************************************************/
/* Set up local pointers */
/********************************************************************/
pNetUserData = (PRNS_UD_SC_NET)pUserData;
pMCSChannel = (PDCUINT16)(pNetUserData + 1);
/********************************************************************/
/* Check parameters */
/********************************************************************/
TRC_ASSERT((pNetUserData->channelCount == _channelCount),
(TB, _T("Channel count changed by Server: was %hd, is %d"),
_channelCount, pNetUserData->channelCount));
expectedLength = sizeof(RNS_UD_SC_NET) +
(pNetUserData->channelCount * sizeof(DCUINT16));
if (userDataLength < expectedLength) {
TRC_ABORT((TB,_T("SC NET user data too short - is %d, expect %d"),
userDataLength, expectedLength));
_pSl->SL_DropLinkImmediate(SL_ERR_INVALIDPACKETFORMAT);
DC_QUIT;
}
/********************************************************************/
/* Save channel data */
/********************************************************************/
for (i = 0; i < _channelCount; i++)
{
_channelData[i].MCSChannelID = pMCSChannel[i];
}
/********************************************************************/
/* Update our state */
/********************************************************************/
_connected = CONNECTION_VC;
event = CHANNEL_EVENT_CONNECTED;
}
/************************************************************************/
/* Call Connected callbacks */
/************************************************************************/
_pUi->UI_GetServerName(serverName, SIZE_TCHARS(serverName));
IntChannelCallCallbacks(event, serverName, UT_MAX_ADDRESS_LENGTH);
DC_EXIT_POINT:
DC_END_FN();
return;
} /* ChannelOnConnected */
/**PROC+*********************************************************************/
/* Name: ChannelOnDisconnected */
/* */
/* Purpose: Called when a session is disconnected */
/* */
/* Returns: none */
/* */
/* Params: reason - disconnect reason code */
/* */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnDisconnected(DCUINT reason)
{
UINT i;
DC_BEGIN_FN("ChannelOnDisconnected");
UNREFERENCED_PARAMETER( reason );
/************************************************************************/
/* Don't do anything if we haven't told the callbacks we're connected. */
/************************************************************************/
if (_connected == CONNECTION_NONE)
{
TRC_ALT((TB, _T("Disconnected callback when not connected")));
DC_QUIT;
}
/************************************************************************/
/* Change state */
/************************************************************************/
_connected = CONNECTION_NONE;
/************************************************************************/
/* Call Disconnected callbacks */
/************************************************************************/
TRC_NRM((TB, _T("Call disconnected callbacks")));
IntChannelCallCallbacks(CHANNEL_EVENT_DISCONNECTED, NULL, 0);
/************************************************************************/
/* Disconnection implies that all channels are closed */
/************************************************************************/
for (i = 0; i < _channelCount; i++)
{
TRC_NRM((TB, _T("'Close' channel %d"), i));
_channelData[i].status = CHANNEL_STATUS_CLOSED;
}
/************************************************************************/
/* Switch to SND thread to cancel all outstanding sends */
/************************************************************************/
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CChan,IntChannelCancelSend),
CHANNEL_MSG_SEND);
DC_EXIT_POINT:
DC_END_FN();
return;
} /* ChannelOnDisconnected */
/**PROC+*********************************************************************/
/* Name: ChannelOnSuspended */
/* */
/* Purpose: Called when a session is suspended (shadow client) */
/* */
/* Returns: none */
/* */
/* Params: reason - disconnect reason code */
/* */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnSuspended(DCUINT reason)
{
UINT i;
DC_BEGIN_FN("ChannelOnDisconnected");
UNREFERENCED_PARAMETER( reason );
/************************************************************************/
/* Don't do anything if we haven't told the callbacks we're connected. */
/************************************************************************/
if (_connected == CONNECTION_NONE)
{
TRC_ALT((TB, _T("Disconnected callback when not connected")));
DC_QUIT;
}
_iChanSuspendCount++;
/************************************************************************/
/* Change state */
/************************************************************************/
_connected = CONNECTION_SUSPENDED;
/************************************************************************/
/* Call Disconnected callbacks */
/************************************************************************/
TRC_NRM((TB, _T("Call disconnected callbacks")));
IntChannelCallCallbacks(CHANNEL_EVENT_REMOTE_CONTROL_START, NULL, 0);
/************************************************************************/
/* Disconnection implies that all channels are closed */
/************************************************************************/
for (i = 0; i < _channelCount; i++)
{
TRC_NRM((TB, _T("'Close' channel %d"), i));
// If a plug-in specified at least one of its channels shadow persistent,
// then it will be notified with the shadow start event instead of the
// disconnected event. In this case the plug-in is supposed to shutdown
// only its non-shadow-persistent channels. So close only channels that
// are not shadow persistent.
if (!(_channelData[i].VCFlags & CHANNEL_FLAG_SHADOW_PERSISTENT))
_channelData[i].status = CHANNEL_STATUS_CLOSED;
}
/************************************************************************/
/* Switch to SND thread to cancel all outstanding sends */
/************************************************************************/
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CChan,IntChannelCancelSend),
CHANNEL_MSG_SUSPEND);
DC_EXIT_POINT:
DC_END_FN();
return;
} /* ChannelOnSuspended */
/**PROC+*********************************************************************/
/* Name: ChannelOnPacketReceived */
/* */
/* Purpose: Called when data is received from the Server */
/* */
/* Returns: none */
/* */
/* Params: pData - data received */
/* dataLen - length of data received */
/* flags - security flags (meaningless to this function) */
/* channelID - ID of channel on which data received */
/* priority - priority on which data was sent */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnPacketReceived(PDCUINT8 pData,
DCUINT dataLen,
DCUINT flags,
DCUINT channelID,
DCUINT priority)
{
UINT i;
PCHANNEL_PDU_HEADER pHdr;
UINT32 len;
DCTCHAR serverName[UT_MAX_ADDRESS_LENGTH];
UINT32 Hdrflags;
UINT32 Hdrlength;
DC_BEGIN_FN("ChannelOnPacketReceived");
UNREFERENCED_PARAMETER( priority );
UNREFERENCED_PARAMETER( flags );
/************************************************************************/
/* First of all, handle suspend/resume messages */
/************************************************************************/
if (dataLen < sizeof(CHANNEL_PDU_HEADER)) {
TRC_ERR((TB,_T("Not enough data: 0x%x need at least: 0x%x"),
dataLen, sizeof(CHANNEL_PDU_HEADER)));
DC_QUIT;
}
pHdr = (PCHANNEL_PDU_HEADER)pData;
memcpy(&Hdrflags,(UNALIGNED UINT32 *)&(pHdr->flags),sizeof(Hdrflags));
memcpy(&Hdrlength,(UNALIGNED UINT32 *)&(pHdr->length),sizeof(Hdrlength));
if (Hdrflags & CHANNEL_FLAG_SUSPEND)
{
TRC_ALT((TB, _T("VC suspended")));
/********************************************************************/
/* Treat as a disconnection */
/********************************************************************/
ChannelOnSuspended(0);
DC_QUIT;
}
if (Hdrflags & CHANNEL_FLAG_RESUME)
{
TRC_ALT((TB, _T("VC resumed")));
/********************************************************************/
/* Update our state */
/********************************************************************/
_connected = CONNECTION_VC;
_iChanResumeCount++;
/********************************************************************/
/* Call Connected callbacks */
/********************************************************************/
_pUi->UI_GetServerName(serverName, SIZE_TCHARS(serverName));
IntChannelCallCallbacks(CHANNEL_EVENT_REMOTE_CONTROL_STOP,
serverName,
UT_MAX_ADDRESS_LENGTH);
DC_QUIT;
}
/************************************************************************/
/* Check we're still connected */
/************************************************************************/
if ((_connected != CONNECTION_VC) &&
(_connected != CONNECTION_SUSPENDED))
{
TRC_ASSERT((_connected != CONNECTION_V1),
(TB,_T("Channel data received from V1 Server!")));
TRC_NRM((TB, _T("Discard packet received when we're not connected")));
DC_QUIT;
}
/************************************************************************/
/* Find the channel data for this channel */
/************************************************************************/
for (i = 0; i < _channelCount; i++)
{
if (_channelData[i].MCSChannelID == channelID)
{
//
// Note it's important to do the decompression even if the channel
// is closed otherwise the context could get out of sync
//
/****************************************************************/
/* call the callback */
/****************************************************************/
TRC_NRM((TB, _T("MCS channel %x = channel %d"), channelID, i));
pData = (PDCUINT8)(pHdr + 1);
len = dataLen - sizeof(CHANNEL_PDU_HEADER);
UCHAR vcCompressFlags = (Hdrflags >> VC_FLAG_COMPRESS_SHIFT) &
VC_FLAG_COMPRESS_MASK;
//Data that is returned to user
PDCUINT8 pVCUserData = pData;
UINT32 cbVCUserDataLen = len;
if(vcCompressFlags & PACKET_COMPRESSED)
{
UCHAR *buf;
int bufSize;
//Decompress channel data
if(vcCompressFlags & PACKET_FLUSHED)
{
initrecvcontext (&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
PACKET_COMPR_TYPE_64K);
}
#ifdef DC_DEBUG
//Update compression stats (debug only)
_cbCompressedBytesRecvd += len;
#endif
if (decompress(pData,
len,
(vcCompressFlags & PACKET_AT_FRONT),
&buf,
&bufSize,
&_pUi->_UI.Context1,
(RecvContext2_Generic*)_pUi->_UI.pRecvContext2,
vcCompressFlags & PACKET_COMPR_TYPE_MASK))
{
if(!_pUserOutBuf)
{
_pUserOutBuf = (PUCHAR)UT_Malloc(_pUt, VC_USER_OUTBUF);
}
TRC_ASSERT(_pUserOutBuf, (TB,_T("_pUserOutBuf is NULL")));
TRC_ASSERT((bufSize < VC_USER_OUTBUF),
(TB,_T("Decompressed buffer to big!!!")));
if(_pUserOutBuf && (bufSize < VC_USER_OUTBUF))
{
//
// Make a copy of the buffer as we can't hand off
// a pointer to the decompression context to the
// user because a badly behaved plugin can corrupt
// the decompression context causing all sorts of
// horrible and hard to debug problems.
//
memcpy(_pUserOutBuf, buf, bufSize);
pVCUserData = _pUserOutBuf;
cbVCUserDataLen = bufSize;
}
else
{
DC_QUIT;
}
}
else {
TRC_ABORT((TB, _T("Decompression FAILURE!!!")));
_pSl->SL_DropLinkImmediate(SL_ERR_INVALIDPACKETFORMAT);
DC_QUIT;
}
}
#ifdef DC_DEBUG
//Update compression stats (debug only)
_cbBytesRecvd += len;
_cbDecompressedBytesRecvd += cbVCUserDataLen;
#endif
//
// Turn off header flags to hide internal
// protocol info from user
//
Hdrflags &= ~VC_FLAG_PRIVATE_PROTOCOL_MASK;
//
// Drop the packet at the last moment if the channel is closed
//
if (_channelData[i].status != CHANNEL_STATUS_OPEN)
{
TRC_ALT((TB, _T("Data received on un-opened channel %x"),
channelID));
DC_QUIT;
}
if(_channelData[i].pInitHandle->fUsingExApi)
{
_channelData[i].pOpenEventExFn(
_channelData[i].pInitHandle->lpParam,
i,
CHANNEL_EVENT_DATA_RECEIVED,
pVCUserData,
cbVCUserDataLen,
Hdrlength,
Hdrflags);
}
else
{
_channelData[i].pOpenEventFn(i,
CHANNEL_EVENT_DATA_RECEIVED,
pVCUserData,
cbVCUserDataLen,
Hdrlength,
Hdrflags);
}
DC_QUIT;
}
}
/************************************************************************/
/* If we get here, we didn't find this channel */
/************************************************************************/
TRC_ALT((TB, _T("Data received on unknown channel %x"), channelID));
DC_EXIT_POINT:
DC_END_FN();
return;
} /* ChannelOnPacketReceived */
/**PROC+*********************************************************************/
/* Name: ChannelOnBufferAvailable */
/* */
/* Purpose: Called when a buffer is available, after a write has failed */
/* because no buffer was available */
/* */
/* Returns: none */
/* */
/* Params: none */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnBufferAvailable(DCVOID)
{
DC_BEGIN_FN("ChannelOnBufferAvailable");
/************************************************************************/
/* Kick the send process into restarting */
/************************************************************************/
TRC_NRM((TB, _T("Write pending %p"), _pFirstWrite));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CChan,IntChannelSend),
CHANNEL_MSG_SEND);
DC_END_FN();
return;
} /* ChannelOnBufferAvailable */
/**PROC+*********************************************************************/
/* Name: ChannelOnConnecting */
/* */
/* Purpose: Called when a connection is being established - returns */
/* virtual channel user data to be sent to the Server */
/* */
/* Returns: None */
/* */
/* Params: ppChannel (returned) - virtual channel user data */
/* pChannelCount (returned) - number of channels returned */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnConnecting(PPCHANNEL_DEF ppChannel,
PDCUINT32 pChannelCount)
{
DC_BEGIN_FN("ChannelOnConnecting");
//Reset the context on each new connection
_fNeedToResetContext = TRUE;
*ppChannel = _channel;
*pChannelCount = _channelCount;
DC_END_FN();
return;
} /* ChannelOnConnecting */
/**PROC+*********************************************************************/
/* Name: ChannelOnInitializing */
/* */
/* Purpose: Called when MSTSC Network Layer is initializing - loads all */
/* configured application DLLs */
/* */
/* Returns: none */
/* */
/* Params: none */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CChan::ChannelOnInitializing(DCVOID)
{
HINSTANCE hInst;
PDCTCHAR szAddinDllList = NULL;
DWORD status = ERROR_SUCCESS;
PRDPDR_DATA pdrInitData = NULL;
DC_BEGIN_FN("ChannelOnInitializing");
//
// Initialize private member pointers
//
_pCd = _pClientObjs->_pCdObject;
_pSl = _pClientObjs->_pSlObject;
_pUt = _pClientObjs->_pUtObject;
_pUi = _pClientObjs->_pUiObject;
/************************************************************************/
/* Create the exported function table */
/************************************************************************/
_channelEntryPoints.cbSize = sizeof(CHANNEL_ENTRY_POINTS);
_channelEntryPoints.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000;
hInst = _pUi->UI_GetInstanceHandle();
_channelEntryPoints.pVirtualChannelInit =
(PVIRTUALCHANNELINIT)(MakeProcInstance
((FARPROC)VirtualChannelInit, hInst));
_channelEntryPoints.pVirtualChannelOpen =
(PVIRTUALCHANNELOPEN)(MakeProcInstance
((FARPROC)VirtualChannelOpen, hInst));
_channelEntryPoints.pVirtualChannelClose =
(PVIRTUALCHANNELCLOSE)(MakeProcInstance
((FARPROC)VirtualChannelClose, hInst));
_channelEntryPoints.pVirtualChannelWrite =
(PVIRTUALCHANNELWRITE)(MakeProcInstance
((FARPROC)VirtualChannelWrite, hInst));
_channelEntryPointsEx.cbSize = sizeof(CHANNEL_ENTRY_POINTS);
_channelEntryPointsEx.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000;
_channelEntryPointsEx.pVirtualChannelInitEx =
(PVIRTUALCHANNELINITEX)(MakeProcInstance
((FARPROC)VirtualChannelInitEx, hInst));
_channelEntryPointsEx.pVirtualChannelOpenEx =
(PVIRTUALCHANNELOPENEX)(MakeProcInstance
((FARPROC)VirtualChannelOpenEx, hInst));
_channelEntryPointsEx.pVirtualChannelCloseEx =
(PVIRTUALCHANNELCLOSEEX)(MakeProcInstance
((FARPROC)VirtualChannelCloseEx, hInst));
_channelEntryPointsEx.pVirtualChannelWriteEx =
(PVIRTUALCHANNELWRITEEX)(MakeProcInstance
((FARPROC)VirtualChannelWriteEx, hInst));
//
// Initialize the single instance VC critical
// section lock. This is used to ensure only one
// VC plugin at a time can be in the Initialize fn.
//
//
__try
{
InitializeCriticalSection(&_VirtualChannelInitLock);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
}
if(ERROR_SUCCESS == status)
{
_fLockInitalized = TRUE;
}
else
{
//
// Without the lock we can't ensure we won't get re-entered
// because the API's did not make it clear that we did
// not support re-entrancy in the VirtualChannelInit fn
// so this is fatal just bail out and don't load plugins.
//
_fLockInitalized = FALSE;
TRC_ERR((TB,_T("InitializeCriticalSection failed 0x%x.")
_T("NOT LOADING PLUGINS"),status));
DC_QUIT;
}
//
// RDPDR is statically linked in
//
// Initialize and pass in initialization info to rdpdr
// rdpdr keeps a pointer to this struct accross connections
// (because there is no clean way to pass it back in again)
// On each connection, the core reinitalizes the struct settings.
_pUi->UI_InitRdpDrSettings();
pdrInitData = _pUi->UI_GetRdpDrInitData();
if(!_pUi->_UI.fDisableInternalRdpDr)
{
if(!IntChannelInitAddin( NULL, RDPDR_VirtualChannelEntryEx, NULL,WEBCTRL_DLL_NAME,
pdrInitData))
{
TRC_ERR((TB, _T("Failed to load internal addin 'RDPDR'")));
}
}
else
{
TRC_NRM((TB, _T("NOT LOADING Internal RDPDR, fDisableInternalRdpDr is set")));
}
//
// Ts ActiveX control's exposed interfaces to the virtual channel API
// are also statically linked in
//
if(!IntChannelInitAddin( NULL, MSTSCAX_VirtualChannelEntryEx, NULL, WEBCTRL_DLL_NAME,
(PVOID)_pUi->_UI.pUnkAxControlInstance))
{
TRC_NRM((TB, _T("Internal addin (scriptable vchans) did not load: possibly none requested")));
}
//Get a comma separated list of dll's to load (passed down from control)
szAddinDllList = _pUi->UI_GetVChanAddinList();
if(!szAddinDllList)
{
TRC_DBG((TB, _T("Not loading any external plugins")));
DC_QUIT;
}
else
{
PDCTCHAR szTok = NULL;
DCUINT len = DC_TSTRLEN(szAddinDllList);
PDCTCHAR szCopyAddinList = (PDCTCHAR) UT_Malloc( _pUt,sizeof(DCTCHAR) *
(len+1));
TRC_ASSERT(szCopyAddinList, (TB, _T("Could not allocate mem for addin list")));
if(!szCopyAddinList)
{
DC_QUIT;
}
StringCchCopy(szCopyAddinList, len+1, szAddinDllList);
szTok = DC_TSTRTOK( szCopyAddinList, _T(","));
while(szTok)
{
//
// Load the DLL
//
if (_tcsicmp(szTok, _T("rdpdr.dll")))
{
IntChannelLoad( szTok);
}
else
{
//
// Don't load the crusty rdpdr.dll since
// we have a newer better one built-in
//
TRC_ERR((TB,_T("Skiping load of rdpdr.dll")));
}
szTok = DC_TSTRTOK( NULL, _T(","));
}
UT_Free( _pUt, szCopyAddinList);
}
#ifdef DC_DEBUG
//Debug compression counters
_cbBytesRecvd = 0;
_cbCompressedBytesRecvd = 0;
_cbDecompressedBytesRecvd = 0;
_cbTotalBytesUserAskSend = 0;
_cbTotalBytesSent = 0;
_cbComprInput = 0;
_cbComprOutput = 0;
#endif
DC_EXIT_POINT:
DC_END_FN();
return;
} /* ChannelOnInitializing */
/****************************************************************************/
/****************************************************************************/
/* Internal Functions */
/****************************************************************************/
/****************************************************************************/
/**PROC+*********************************************************************/
/* Name: IntChannelCallCallbacks */
/* */
/* Purpose: Call all ChannelInitEvent callbacks with a specified event */
/* */
/* Returns: none */
/* */
/* Params: event - event to pass to callbacks */
/* pData - additional data */
/* dataLength - length of additional data */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelCallCallbacks(DCUINT event,
PDCVOID pData,
DCUINT dataLength)
{
PCHANNEL_INIT_HANDLE pInitHandle;
DCUINT altEvent, sentEvent;
if (event == CHANNEL_EVENT_REMOTE_CONTROL_START) {
altEvent = CHANNEL_EVENT_DISCONNECTED;
} else if (event == CHANNEL_EVENT_REMOTE_CONTROL_STOP) {
altEvent = CHANNEL_EVENT_CONNECTED;
} else {
altEvent = event;
}
DC_BEGIN_FN("IntChannelCallCallbacks");
pInitHandle = _pInitHandle;
while (pInitHandle != NULL)
{
if (pInitHandle->dwFlags & CHANNEL_FLAG_SHADOW_PERSISTENT) {
// The plug-in supports the new events, don't change it.
sentEvent = event;
} else {
// No support or the new event is not wanted.
sentEvent = altEvent;
}
if(pInitHandle->fUsingExApi)
{
TRC_NRM((TB, _T("Call callback (Ex) at %p, handle %p, event %d"),
pInitHandle->pInitEventExFn, pInitHandle, sentEvent));
pInitHandle->pInitEventExFn(pInitHandle->lpParam,
pInitHandle, sentEvent, pData, dataLength);
}
else
{
TRC_NRM((TB, _T("Call callback at %p, handle %p, event %d"),
pInitHandle->pInitEventFn, pInitHandle, sentEvent));
pInitHandle->pInitEventFn(pInitHandle, sentEvent, pData, dataLength);
}
pInitHandle = pInitHandle->pNext;
}
DC_END_FN();
return;
} /* IntChannelCallCallbacks */
/**PROC+*********************************************************************/
/* Name: IntChannelFreeLibrary */
/* */
/* Purpose: Decoupled function to unload a DLL */
/* */
/* Returns: none */
/* */
/* Params: value - hMod of DLL to free */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelFreeLibrary(DCUINT value)
{
BOOL bRc;
DC_BEGIN_FN("IntChannelFreeLibrary");
if(value)
{
//
// Statically linked extenstions (e.g RDPDR) have a null hModule
//
#ifdef OS_WIN32
bRc = FreeLibrary(
#ifndef OS_WINCE
(HMODULE)ULongToPtr(value)
#else
(HMODULE)value
#endif
);
if (bRc)
{
TRC_NRM((TB, _T("Free library %#x OK"), value));
}
else
{
TRC_ERR((TB, _T("Failed to free library %#x"), value));
}
#else //OS_WIN32
FreeLibrary((HMODULE)value);
#endif // OS_WIN32
}
DC_END_FN();
return;
} /* IntChannelFreeLibrary */
//
// IntChannelCompressData
// Compressed the buffer directly into the outbuf.
// Caller MUST decide if input buf is in size range for compression
// and should handle copying over the buffer directly in that case.
//
// Params:
// pSrcData - input buffer
// cbSrcLen - length of input buffer
// pOutBuf - output buffer
// pcbOutLen- compressed output size
// Returns:
// Compression result (see compress() fn)
//
UCHAR CChan::IntChannelCompressData(UCHAR* pSrcData, ULONG cbSrcLen,
UCHAR* pOutBuf, ULONG* pcbOutLen)
{
UCHAR compressResult = 0;
ULONG CompressedSize = cbSrcLen;
DC_BEGIN_FN("IntChannelCompressData");
TRC_ASSERT(((cbSrcLen > VC_MIN_COMPRESS_INPUT_BUF) &&
(cbSrcLen < VC_MAX_COMPRESSED_BUFFER)),
(TB,_T("Compression src len out of range: %d"),
cbSrcLen));
TRC_ASSERT(_pMPPCContext,(TB,_T("_pMPPCContext is null")));
//Attempt to compress directly into the outbuf
compressResult = compress(pSrcData,
pOutBuf,
&CompressedSize,
_pMPPCContext);
if(compressResult & PACKET_COMPRESSED)
{
//Successful compression.
TRC_ASSERT((CompressedSize >= CompressedSize),
(TB,_T("Compression created larger size than uncompr")));
compressResult |= _fCompressionFlushed;
_fCompressionFlushed = 0;
#ifdef DC_DEBUG
//Compr counters
_cbComprInput += cbSrcLen;
_cbComprOutput += CompressedSize;
#endif
}
else if(compressResult & PACKET_FLUSHED)
{
//Overran compression history, copy over the
//uncompressed buffer.
_fCompressionFlushed = PACKET_FLUSHED;
memcpy(pOutBuf, pSrcData, cbSrcLen);
_CompressFlushes++;
}
else
{
TRC_ALT((TB, _T("Compression FAILURE")));
}
DC_END_FN();
*pcbOutLen = CompressedSize;
return compressResult;
}
/**PROC+*********************************************************************/
/* Name: IntChannelSend */
/* */
/* Purpose: Internal function to send data to the Server */
/* */
/* Returns: None */
/* */
/* Params: value - message passed from caller */
/* */
/* Operation: Called on SND thread */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelSend(ULONG_PTR value)
{
PCHANNEL_WRITE_DECOUPLE pDecouple;
DCBOOL bRc;
PDCUINT8 pBuffer;
SL_BUFHND bufHnd;
PCHANNEL_PDU_HEADER pHdr;
ULONG thisLength;
DWORD chanIndex = 0xFDFDFDFD;
ULONG cbOutLen = 0;
UCHAR compressResult = 0;
BOOL fNeedToDirectCopy = TRUE;
DC_BEGIN_FN("IntChannelSend");
//
// CD passes param as PVOID
//
#ifndef DC_DEBUG
UNREFERENCED_PARAMETER(value);
#endif
/************************************************************************/
/* Assert parameters */
/************************************************************************/
TRC_ASSERT((value == CHANNEL_MSG_SEND),
(TB, _T("Unexpected value %d"), value));
/************************************************************************/
/* Exit immediately if there's nothing to do. */
/************************************************************************/
if (_pFirstWrite == NULL)
{
TRC_NRM((TB, _T("Nothing to do")));
DC_QUIT;
}
TRC_ASSERT((_pFirstWrite->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid first signature %#lx"), _pFirstWrite->signature));
TRC_ASSERT((_pLastWrite->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid last signature %#lx"), _pLastWrite->signature));
/************************************************************************/
/* Get the next queued request */
/************************************************************************/
pDecouple = _pFirstWrite;
/************************************************************************/
/* Calculate the length to send */
/************************************************************************/
thisLength = CHANNEL_CHUNK_LENGTH;
/************************************************************************/
/* Truncate the data sent if we're about to send more than is left */
/************************************************************************/
if (thisLength >= pDecouple->dataLeft)
{
thisLength = pDecouple->dataLeft;
pDecouple->flags |= CHANNEL_FLAG_LAST;
}
TRC_NRM((TB,
_T("pDecouple %p, src %p, this %lu, left %lu, flags %#lx"),
pDecouple, pDecouple->pNextData, thisLength,
pDecouple->dataLeft, pDecouple->flags));
/************************************************************************/
/* Get a buffer */
/************************************************************************/
bRc = _pSl->SL_GetBuffer(thisLength + sizeof(CHANNEL_PDU_HEADER),
&pBuffer, &bufHnd);
if (!bRc)
{
/********************************************************************/
/* Failed to get a buffer. This is not entirely unexpected and is */
/* most likely simply due to back-pressure. The write will be */
/* retried when a buffer becomes available (signalled by a call to */
/* ChannelOnBufferAvailable). */
/********************************************************************/
TRC_NRM((TB, _T("Failed to get %d-byte buffer"), thisLength +
sizeof(CHANNEL_PDU_HEADER)));
DC_QUIT;
}
/************************************************************************/
/* Fill in the Channel PDU */
/************************************************************************/
pHdr = (PCHANNEL_PDU_HEADER)pBuffer;
memcpy((UNALIGNED UINT32 *)&(pHdr->length),
&(pDecouple->dataLength),sizeof(pDecouple->dataLength));
memcpy((UNALIGNED UINT32 *)&(pHdr->flags),
&(pDecouple->flags),sizeof(pDecouple->flags));
cbOutLen = thisLength;
compressResult = 0;
fNeedToDirectCopy = TRUE;
if(_fCompressChannels &&
(pDecouple->chanOptions & CHANNEL_OPTION_COMPRESS_RDP))
{
if((thisLength > VC_MIN_COMPRESS_INPUT_BUF) &&
(thisLength < VC_MAX_COMPRESSED_BUFFER))
{
//Compress the packet
if(!_pMPPCContext)
{
//Deferred init of the send context
_pMPPCContext = (SendContext*) UT_Malloc(_pUt,
VC_MAX_COMPRESSED_BUFFER+
sizeof(SendContext));
if(!_pMPPCContext)
{
#ifdef OS_WINCE //Applies to OS_WINNT too
_pSl->SL_FreeBuffer(bufHnd);
#endif
TRC_ERR((TB,_T("Failed to alloc MPPC send context")));
DC_QUIT;
}
_fNeedToResetContext = TRUE;
}
#ifdef DEBUG_CCHAN_COMPRESSION
if (!_pDbgRcvDecompr8K)
{
_fDbgVCTriedAllocRecvContext = TRUE;
_pDbgRcvDecompr8K = (RecvContext2_8K*)
LocalAlloc(LPTR, sizeof(RecvContext2_8K));
if (_pDbgRcvDecompr8K)
{
_pDbgRcvDecompr8K->cbSize = sizeof(RecvContext2_8K);
initrecvcontext(&_DbgRcvContext1,
(RecvContext2_Generic*)_pDbgRcvDecompr8K,
PACKET_COMPR_TYPE_8K);
}
else
{
_fDbgAllocFailedForVCRecvContext = TRUE;
TRC_ERR((TB,_T("Fail to alloc debug decompression context")));
DC_QUIT;
}
}
#endif
if(_fNeedToResetContext)
{
//
//Reset the context at the start of every connection.
//
// Server only supports 8K compression from client
// i.e. it will only decompress with 8K of history
//
initsendcontext(_pMPPCContext, PACKET_COMPR_TYPE_8K);
_fNeedToResetContext = FALSE;
}
TRC_ASSERT((_pMPPCContext),
(TB,_T("_pMPPCContext is null")));
compressResult = IntChannelCompressData( (UCHAR*)pDecouple->pNextData,
thisLength,
(UCHAR*)(pHdr+1),
&cbOutLen );
if(0 != compressResult)
{
#ifdef DEBUG_CCHAN_COMPRESSION
//
// debug: decompresss the packet
//
PUCHAR pDecompOutBuf = NULL;
INT cbDecompLen;
if (compressResult & PACKET_COMPRESSED)
{
if (compressResult & PACKET_FLUSHED)
{
initrecvcontext(&_DbgRcvContext1,
(RecvContext2_Generic*)_pDbgRcvDecompr8K,
PACKET_COMPR_TYPE_8K);
}
if (decompress((PUCHAR)(pHdr+1),
cbOutLen,
(compressResult & PACKET_AT_FRONT), //0 start
&pDecompOutBuf,
&cbDecompLen,
&_DbgRcvContext1,
(RecvContext2_Generic*)_pDbgRcvDecompr8K,
PACKET_COMPR_TYPE_8K))
{
if (cbDecompLen != thisLength)
{
DbgUserPrint(_T("Decompress check failed. Inlen!=outlen\n"));
DbgUserPrint(_T("Mail tsstress - orig len %d, decompressed len %d\n"),
thisLength,cbDecompLen);
DbgUserPrint(_T("pHdr 0x%x, inlen %d\n"),
pHdr, thisLength);
DbgUserPrint(_T("compression result %d\n"),compressResult);
DbgUserPrint(_T("pDecompOutBuf 0x%x, cbDecompLen %d\n"),
pDecompOutBuf, cbDecompLen);
DebugBreak();
}
if (memcmp(pDecompOutBuf, (PUCHAR)(pDecouple->pNextData), cbDecompLen))
{
DbgUserPrint(_T("Decompressed buffer does not match original!"));
DbgUserPrint(_T("Mail tsstress!"));
DbgUserPrint(_T("pHdr 0x%x, inlen %d\n"),
pHdr, thisLength);
DbgUserPrint(_T("compression result %d\n"),compressResult);
DbgUserPrint(_T("pDecompOutBuf 0x%x, cbDecompLen %d\n"),
pDecompOutBuf, cbDecompLen);
DebugBreak();
}
}
else
{
DbgUserPrint(_T("Decompression check failed!"));
DbgUserPrint(_T("Mail tsstress!"));
DbgUserPrint(_T("pHdr 0x%x, inlen %d\n"),pHdr, thisLength);
DbgUserPrint(_T("compression result %d\n"),compressResult);
DbgUserPrint(_T("pDecompOutBuf 0x%x, cbDecompLen %d\n"),
pDecompOutBuf, cbDecompLen);
DebugBreak();
}
}
#endif
//Update the VC packet header flags with the compression info
UINT32 newFlags = (pDecouple->flags |
((compressResult & VC_FLAG_COMPRESS_MASK) <<
VC_FLAG_COMPRESS_SHIFT));
memcpy((UNALIGNED UINT32 *)&(pHdr->flags),
&newFlags,sizeof(newFlags));
//Succesfully compressed no need to direct copy
fNeedToDirectCopy = FALSE;
cbOutLen += sizeof(CHANNEL_PDU_HEADER);
}
else
{
_iDbgCompressFailedCount++;
#ifdef DEBUG_CCHAN_COMPRESSION
DebugBreak();
#endif
TRC_ERR((TB, _T("IntChannelCompressData failed")));
_pSl->SL_FreeBuffer(bufHnd);
DC_QUIT;
}
}
}
//Copy buffer directly if compression not enabled
//or the buffer does not fit size range for compression
if(fNeedToDirectCopy)
{
DC_MEMCPY(pHdr+1, pDecouple->pNextData, thisLength);
cbOutLen = thisLength + sizeof(CHANNEL_PDU_HEADER);
}
#ifdef DC_DEBUG
//Compr counters
_cbTotalBytesUserAskSend += thisLength;
_cbTotalBytesSent += cbOutLen;
#endif
TRC_DATA_DBG("Send channel data", pBuffer, cbOutLen);
/************************************************************************/
/* Get the channel index */
/************************************************************************/
chanIndex = pDecouple->openHandle;
/************************************************************************/
/* Send the Channel PDU */
/************************************************************************/
_pSl->SL_SendPacket(pBuffer,
cbOutLen,
_channelData[chanIndex].SLFlags,
bufHnd,
_pUi->UI_GetClientMCSID(),
_channelData[chanIndex].MCSChannelID,
_channelData[chanIndex].priority);
/************************************************************************/
/* Set up for next iteration */
/************************************************************************/
pDecouple->pNextData = ((HPDCUINT8)(pDecouple->pNextData)) + thisLength;
pDecouple->dataLeft -= thisLength;
pDecouple->dataSent += thisLength;
pDecouple->flags = _channelData[chanIndex].VCFlags;
TRC_NRM((TB, _T("Done write %p, src %p, sent %lu, left %lu, flags %#lx"),
pDecouple, pDecouple->pNextData, pDecouple->dataSent,
pDecouple->dataLeft, pDecouple->flags));
/************************************************************************/
/* See if we've finished this operation */
/************************************************************************/
if (pDecouple->dataLeft <= 0)
{
/********************************************************************/
/* Remove the operation from the queue */
/********************************************************************/
_pFirstWrite = pDecouple->pNext;
if (_pFirstWrite == NULL)
{
TRC_NRM((TB, _T("Finished last write")));
_pLastWrite = NULL;
}
else
{
TRC_NRM((TB, _T("New first in queue: %p"), _pFirstWrite));
_pFirstWrite->pPrev = NULL;
}
/********************************************************************/
/* Operation complete - call the callback */
/********************************************************************/
TRC_NRM((TB, _T("Write %p complete"), pDecouple));
if(_channelData[chanIndex].pInitHandle->fUsingExApi)
{
TRC_ASSERT((NULL != _channelData[chanIndex].pOpenEventExFn),
(TB, _T("Callback %p, handle %ld"),
_channelData[chanIndex].pOpenEventExFn,
pDecouple->openHandle));
/************************************************************************/
/* Is the channel still open? This was checked in */
/* IntVirtualChannelWrite, but that was before the post to this thread. */
/* If the VC was closed, it's possible we no longer have callback */
/* pointers. */
/************************************************************************/
if (NULL != _channelData[chanIndex].pOpenEventExFn)
{
_channelData[chanIndex].pOpenEventExFn(
_channelData[chanIndex].pInitHandle->lpParam,
pDecouple->openHandle,
CHANNEL_EVENT_WRITE_COMPLETE,
pDecouple->pUserData,
0, 0, 0);
}
}
else
{
TRC_ASSERT((NULL != _channelData[chanIndex].pOpenEventFn),
(TB, _T("Callback %p, handle %ld"),
_channelData[chanIndex].pOpenEventFn,
pDecouple->openHandle));
if (NULL != _channelData[chanIndex].pOpenEventFn)
{
_channelData[chanIndex].pOpenEventFn( pDecouple->openHandle,
CHANNEL_EVENT_WRITE_COMPLETE,
pDecouple->pUserData,
0, 0, 0);
}
}
/********************************************************************/
/* Free the request */
/********************************************************************/
UT_Free( _pUt,pDecouple);
}
/************************************************************************/
/* Kick the process again if there's anything left to do */
/************************************************************************/
if (_pFirstWrite != NULL)
{
TRC_NRM((TB, _T("More work to do %p"), _pFirstWrite));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CChan,IntChannelSend),
CHANNEL_MSG_SEND);
}
/************************************************************************/
/* Note that if we failed to get a buffer above, we won't kick the */
/* process into continuing. This is done later, on receipt of an */
/* OnBufferAvailable callback from SL. */
/************************************************************************/
DC_EXIT_POINT:
DC_END_FN();
return;
} /* IntChannelSend */
/**PROC+*********************************************************************/
/* Name: IntChannelWrite */
/* */
/* Purpose: Start writing data to the Server */
/* */
/* Returns: none */
/* */
/* Params: pData - CHANNEL_WRITE_DECOUPLE structure */
/* dataLength - length of pData */
/* */
/* Operation: Called on SND thread */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelWrite(PDCVOID pData, DCUINT dataLength)
{
PCHANNEL_WRITE_DECOUPLE pDecouple;
DC_BEGIN_FN("IntChannelWrite");
#ifndef DC_DEBUG
UNREFERENCED_PARAMETER(dataLength);
#endif
/************************************************************************/
/* Check parameters */
/************************************************************************/
TRC_ASSERT((dataLength == sizeof(PCHANNEL_WRITE_DECOUPLE)),
(TB, _T("Wrong size data: is/expect %d/%d"),
dataLength, sizeof(PCHANNEL_WRITE_DECOUPLE)));
TRC_ASSERT((((_pFirstWrite == NULL) && (_pLastWrite == NULL)) ||
((_pFirstWrite != NULL) && (_pLastWrite != NULL))),
(TB,_T("Invalid queue, pFirst %p, pLast %p"),
_pFirstWrite, _pLastWrite));
pDecouple = *((PPCHANNEL_WRITE_DECOUPLE)pData);
TRC_NRM((TB, _T("Receive %p -> %p"), pData, pDecouple));
TRC_ASSERT((pDecouple->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid decouple signature %#lx"), pDecouple->signature));
/************************************************************************/
/* Add this request to the queue */
/************************************************************************/
if (_pFirstWrite == NULL)
{
/********************************************************************/
/* Empty queue */
/********************************************************************/
TRC_NRM((TB, _T("Empty queue")));
_pFirstWrite = pDecouple;
_pLastWrite = pDecouple;
}
else
{
/********************************************************************/
/* Non-empty queue */
/********************************************************************/
TRC_NRM((TB, _T("Non-empty queue: first %p, last %p"),
_pFirstWrite, _pLastWrite));
pDecouple->pPrev = _pLastWrite;
_pLastWrite->pNext = pDecouple;
_pLastWrite = pDecouple;
}
TRC_ASSERT((_pFirstWrite->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid first signature %#lx"), _pFirstWrite->signature));
TRC_ASSERT((_pLastWrite->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid last signature %#lx"), _pLastWrite->signature));
/************************************************************************/
/* Try to send the data */
/************************************************************************/
IntChannelSend(CHANNEL_MSG_SEND);
DC_END_FN();
return;
} /* IntChannelWrite */
/**PROC+*********************************************************************/
/* Name: IntChannelLoad */
/* */
/* Purpose: Load an Addin */
/* */
/* Returns: none */
/* */
/* Params: DLLName - name of Addin DLL to load */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelLoad(PDCTCHAR DLLName)
{
DCBOOL rc = FALSE;
PVIRTUALCHANNELENTRY pChannelEntry;
PVIRTUALCHANNELENTRYEX pChannelEntryEx;
HMODULE hMod;
PCHANNEL_INIT_HANDLE pAddin;
DC_BEGIN_FN("IntChannelLoad");
/************************************************************************/
/* Load the DLL */
/************************************************************************/
hMod = LoadLibrary(DLLName);
if (!hMod)
{
TRC_ERR((TB, _T("Failed to load %s"), DLLName));
DC_QUIT;
}
TRC_NRM((TB, _T("Loaded %s (%p)"), DLLName, hMod));
/************************************************************************/
/* Search the already-loaded Addins in case this is a duplicate */
/************************************************************************/
for (pAddin = _pInitHandle; pAddin != NULL; pAddin = pAddin->pNext)
{
TRC_DBG((TB, _T("Compare %s, %p, %p"), DLLName, pAddin->hMod, hMod));
if (pAddin->hMod == hMod)
{
TRC_ERR((TB, _T("Reloading %s (%p)"), DLLName, hMod));
DC_QUIT;
}
}
/************************************************************************/
/* DLL loaded OK - find its VirtualChannelEntry function */
/************************************************************************/
//
// First try to find the Ex entry point
//
pChannelEntryEx = (PVIRTUALCHANNELENTRYEX)GetProcAddress(hMod,
CE_WIDETEXT("VirtualChannelEntryEx"));
if(pChannelEntryEx)
{
TRC_NRM((TB,_T("Found EX entry point, Init using ex api: %s"), DLLName));
IntChannelInitAddin( NULL, pChannelEntryEx, hMod, DLLName, NULL);
}
else
{
//
// Only try to load legacy DLL's from the first instance
//
if( CChan::pStaticClientInstance == this)
{
TRC_NRM((TB,_T("Did not find EX entry point, looking for old api: %s"), DLLName));
pChannelEntry = (PVIRTUALCHANNELENTRY)GetProcAddress(hMod,
CE_WIDETEXT("VirtualChannelEntry"));
if (pChannelEntry == NULL)
{
TRC_ERR((TB, _T("Failed to find VirtualChannelEntry in %s"),
DLLName));
DC_QUIT;
}
IntChannelInitAddin( pChannelEntry, NULL, hMod, DLLName, NULL);
}
}
DC_EXIT_POINT:
DC_END_FN();
return;
} /* IntChannelLoad */
/**PROC+*********************************************************************/
/* Name: IntChannelInitAddin */
/* */
/* Purpose: Initialize addin given it's entry point */
/* */
/* Returns: Success flag */
/* */
/* Params: pChannelEntry - Addin entry point */
/* */
/**PROC-*********************************************************************/
DCBOOL DCINTERNAL CChan::IntChannelInitAddin(PVIRTUALCHANNELENTRY pChannelEntry,
PVIRTUALCHANNELENTRYEX pChannelEntryEx,
HMODULE hMod,
PDCTCHAR DLLName,
PVOID pPassParamToEx)
{
DCBOOL rc = FALSE;
PCHANNEL_ENTRY_POINTS pTempEntryPoints = NULL;
PCHANNEL_ENTRY_POINTS_EX pTempEntryPointsEx = NULL;
UINT i=0;
DC_BEGIN_FN("IntChannelInitAddin");
_newInitHandle = NULL;
if (pChannelEntry == NULL && pChannelEntryEx == NULL)
{
TRC_ERR((TB, _T("Invalid VirtualChannelEntry")));
DC_QUIT;
}
if (DLLName == NULL)
{
TRC_ERR((TB, _T("Invalid DLLName")));
DC_QUIT;
}
TRC_NRM((TB, _T("VirtualChannelEntry at %p"), pChannelEntry));
TRC_NRM((TB, _T("VirtualChannelEntryEx at %p"), pChannelEntryEx));
/************************************************************************/
/* Allocate and initialize a handle */
/************************************************************************/
_newInitHandle = (PCHANNEL_INIT_HANDLE)UT_Malloc( _pUt,sizeof(CHANNEL_INIT_HANDLE));
if (_newInitHandle == NULL)
{
TRC_ERR((TB, _T("Failed to allocate handle")));
DC_QUIT;
}
_newInitHandle->signature = CHANNEL_INIT_SIGNATURE;
_newInitHandle->hMod = hMod;
_newInitHandle->pInst = this;
//
//ChannelCount for this addin is marked as 0 now
//it will be updated by the plugin's calls to VirtualChannelInit
//if VirtualChannelEntry returns false, this count will be used
//to rollback any created channels.
//
_newInitHandle->channelCount = 0;
//
// Internal addin's can get params passed back down
// today this is used so the control can pass it's internal
// an interface pointer to the virtual channel scripting addin
//
_newInitHandle->lpInternalAddinParam = pPassParamToEx;
/************************************************************************/
/* Allocate and fill a temporary structure in which to pass the entry */
/* points. This keeps our global entry points structure safe from */
/* badly-behaved addins that could overwrite it and stop other addins */
/* from working correctly. Note that addins must copy this structure */
/* -- it is only valid during this call to VirtualChannelEntry. */
/************************************************************************/
if(pChannelEntryEx)
{
pTempEntryPointsEx = (PCHANNEL_ENTRY_POINTS_EX)UT_Malloc(
_pUt,sizeof(CHANNEL_ENTRY_POINTS_EX));
if (pTempEntryPointsEx == NULL)
{
TRC_ERR((TB, _T("Failed to allocate temporary entry points (Ex) structure")));
DC_QUIT;
}
DC_MEMCPY(pTempEntryPointsEx,
&_channelEntryPointsEx,
sizeof(CHANNEL_ENTRY_POINTS_EX));
}
else
{
pTempEntryPoints = (PCHANNEL_ENTRY_POINTS)UT_Malloc( _pUt,sizeof(CHANNEL_ENTRY_POINTS));
if (pTempEntryPoints == NULL)
{
TRC_ERR((TB, _T("Failed to allocate temporary entry points structure")));
DC_QUIT;
}
DC_MEMCPY(pTempEntryPoints,
&_channelEntryPoints,
sizeof(CHANNEL_ENTRY_POINTS));
}
/************************************************************************/
/* Call VirtualChannelEntry */
/************************************************************************/
_ChannelInitCalled = FALSE;
_inChannelEntry = TRUE;
if(pChannelEntryEx)
{
//
// Pass the adddin a pointer to the new init handle
//
rc = pChannelEntryEx(pTempEntryPointsEx, _newInitHandle);
}
else
{
rc = pChannelEntry(pTempEntryPoints);
}
_inChannelEntry = FALSE;
if (!rc)
{
TRC_NRM((TB, _T("ChannelEntry aborted")));
DC_QUIT;
}
/************************************************************************/
/* Make sure that the Addin called VirtualChannelInit from */
/* VirtualChannelEntry */
/************************************************************************/
if (!_ChannelInitCalled)
{
TRC_ERR((TB, _T("Addin %s didn't call VirtualChannelInit"), DLLName));
rc = FALSE;
DC_QUIT;
}
/************************************************************************/
/* Everything OK - insert this handle into chain of Init Handles */
/************************************************************************/
_newInitHandle->pPrev = NULL;
_newInitHandle->pNext = _pInitHandle;
if (_pInitHandle != NULL)
{
_pInitHandle->pPrev = _newInitHandle;
}
_pInitHandle = _newInitHandle;
rc = TRUE;
DC_EXIT_POINT:
if (!rc)
{
TRC_NRM((TB, _T("Something failed - tidy up")));
if (hMod)
{
TRC_NRM((TB, _T("Free the library")));
FreeLibrary(hMod);
}
if (_newInitHandle)
{
//
// Remove any channel entries that were created
// for this plugin. These should be consecutive channels at the tail
// of the channels array.
//
if(_newInitHandle->channelCount)
{
UINT startRemoveIdx = _channelCount - _newInitHandle->channelCount;
TRC_ASSERT((startRemoveIdx < _channelCount),
(TB,_T("startRemoveIdx for channel cleanup is invalid")));
if(startRemoveIdx < _channelCount)
{
//
// Rollback creation of virtual channels
//
for( i=startRemoveIdx; i<_channelCount; i++)
{
TRC_ASSERT((_channelData[i].pInitHandle == _newInitHandle),
(TB,_T("_channelData[i].pInitHandle != _newInitHandle on rollback")));
if(_channelData[i].pInitHandle == _newInitHandle)
{
_channel[i].options = ~CHANNEL_OPTION_INITIALIZED;
DC_MEMSET(_channel[i].name, 0, CHANNEL_NAME_LEN+1);
_channelData[i].pOpenEventExFn = NULL;
_channelData[i].pOpenEventFn = NULL;
_channelData[i].status = CHANNEL_STATUS_CLOSED;
}
else
{
break;
}
}
_channelCount -= _newInitHandle->channelCount;
}
}
TRC_NRM((TB, _T("Free unused handle")));
UT_Free( _pUt,_newInitHandle);
}
}
if (pTempEntryPoints)
{
UT_Free( _pUt,pTempEntryPoints);
}
if (pTempEntryPointsEx)
{
UT_Free( _pUt, pTempEntryPointsEx);
}
DC_END_FN();
return rc;
} /* IntChannelInitAddin */
/**PROC+*********************************************************************/
/* Name: IntChannelCancelSend */
/* */
/* Purpose: Cancel outstanding send requests */
/* */
/* Returns: none */
/* */
/* Params: value - message passed from caller */
/* */
/* Operation: Called on SND thread */
/* */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CChan::IntChannelCancelSend(ULONG_PTR value)
{
PCHANNEL_WRITE_DECOUPLE pDecouple;
PCHANNEL_WRITE_DECOUPLE pFree;
DWORD chanIndex = 0xFDFDFDFD;
DC_BEGIN_FN("IntChannelCancelSend");
//UNREFERENCED_PARAMETER( value );
pDecouple = _pFirstWrite;
while (pDecouple != NULL)
{
TRC_ASSERT((pDecouple->signature == CHANNEL_DECOUPLE_SIGNATURE),
(TB,_T("Invalid decouple signature %#lx"), pDecouple->signature));
chanIndex = pDecouple->openHandle;
if ((value == CHANNEL_MSG_SUSPEND) &&
(_channelData[chanIndex].VCFlags & CHANNEL_FLAG_SHADOW_PERSISTENT)) {
// skip this one as it should not be closed
pDecouple = pDecouple->pNext;
continue;
}
/********************************************************************/
/* Call the callback */
/********************************************************************/
TRC_NRM((TB, _T("Write %p cancelled"), pDecouple));
if(_channelData[chanIndex].pInitHandle->fUsingExApi)
{
_channelData[chanIndex].pOpenEventExFn(
_channelData[chanIndex].pInitHandle->lpParam,
pDecouple->openHandle,
CHANNEL_EVENT_WRITE_CANCELLED,
pDecouple->pUserData,
0, 0, 0);
}
else
{
_channelData[chanIndex].pOpenEventFn( pDecouple->openHandle,
CHANNEL_EVENT_WRITE_CANCELLED,
pDecouple->pUserData,
0, 0, 0);
}
/********************************************************************/
/* Free the decouple structure */
/********************************************************************/
pFree = pDecouple;
pDecouple = pDecouple->pNext;
if (pDecouple) {
pDecouple->pPrev = pFree->pPrev;
} else {
_pLastWrite = pFree->pPrev;
}
if (pFree->pPrev) {
pFree->pPrev->pNext = pDecouple;
} else {
_pFirstWrite = pDecouple;
}
pFree->signature = 0;
UT_Free( _pUt,pFree);
}
if (value != CHANNEL_MSG_SUSPEND) {
_pFirstWrite = NULL;
_pLastWrite = NULL;
}
DC_END_FN();
return;
} /* IntChannelCancelSend */