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
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 */
|
|
|