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.
998 lines
46 KiB
998 lines
46 KiB
/****************************************************************************/
|
|
// xtapi.cpp
|
|
//
|
|
// XT layer - portable API
|
|
//
|
|
// Copyright (C) 1997-1999 Microsoft Corporation
|
|
/****************************************************************************/
|
|
|
|
#include <adcg.h>
|
|
extern "C" {
|
|
#define TRC_FILE "xtapi"
|
|
#define TRC_GROUP TRC_GROUP_NETWORK
|
|
#include <atrcapi.h>
|
|
}
|
|
|
|
#include "autil.h"
|
|
#include "xt.h"
|
|
#include "cd.h"
|
|
#include "nl.h"
|
|
#include "sl.h"
|
|
#include "mcs.h"
|
|
|
|
|
|
|
|
|
|
CXT::CXT(CObjs* objs)
|
|
{
|
|
_pClientObjects = objs;
|
|
}
|
|
|
|
CXT::~CXT()
|
|
{
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_Init */
|
|
/* */
|
|
/* Purpose: Initializes _XT. Since XT is stateless, this just involves */
|
|
/* initializing TD. */
|
|
/****************************************************************************/
|
|
DCVOID DCAPI CXT::XT_Init(DCVOID)
|
|
{
|
|
DC_BEGIN_FN("XT_Init");
|
|
|
|
/************************************************************************/
|
|
/* Initialize our global data. */
|
|
/************************************************************************/
|
|
DC_MEMSET(&_XT, 0, sizeof(_XT));
|
|
|
|
_pCd = _pClientObjects->_pCdObject;
|
|
_pSl = _pClientObjects->_pSlObject;
|
|
_pTd = _pClientObjects->_pTDObject;
|
|
_pMcs = _pClientObjects->_pMCSObject;
|
|
_pUt = _pClientObjects->_pUtObject;
|
|
_pUi = _pClientObjects->_pUiObject;
|
|
_pClx = _pClientObjects->_pCLXObject;
|
|
|
|
TRC_NRM((TB, _T("XT pkt max-size:%u min-size:%u"),
|
|
XT_MAX_HEADER_SIZE,
|
|
XT_MIN_HEADER_SIZE));
|
|
|
|
_pTd->TD_Init();
|
|
|
|
TRC_NRM((TB, _T("XT successfully initialized")));
|
|
|
|
DC_END_FN();
|
|
} /* XT_Init */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_SendBuffer */
|
|
/* */
|
|
/* Purpose: Adds the XT data packet header and then sends the packet. */
|
|
/* */
|
|
/* Params: IN pData - pointer to the start of the data. */
|
|
/* IN dataLength - amount of the buffer used. */
|
|
/* IN bufHandle - handle to a buffer. */
|
|
/****************************************************************************/
|
|
DCVOID DCAPI CXT::XT_SendBuffer(PDCUINT8 pData,
|
|
DCUINT dataLength,
|
|
XT_BUFHND bufHandle)
|
|
{
|
|
DCUINT packetLength;
|
|
XT_DT xtDT = XT_DT_DATA;
|
|
|
|
DC_BEGIN_FN("XT_SendBuffer");
|
|
|
|
/************************************************************************/
|
|
/* Check that we're not being asked to send more data than we can. */
|
|
/************************************************************************/
|
|
TRC_ASSERT((dataLength <= XT_MAX_DATA_SIZE),
|
|
(TB, _T("Data exceeds XT TSDU length of %u"), XT_MAX_DATA_SIZE));
|
|
|
|
/************************************************************************/
|
|
/* Add our XT data header. All the invariant fields are already */
|
|
/* initialized, so all that remains to be filled in is the packet */
|
|
/* length. */
|
|
/************************************************************************/
|
|
packetLength = dataLength + sizeof(XT_DT);
|
|
xtDT.hdr.lengthHighPart = ((DCUINT16)packetLength) >> 8;
|
|
xtDT.hdr.lengthLowPart = ((DCUINT16)packetLength) & 0xFF;
|
|
|
|
TRC_DBG((TB, _T("XT pkt length:%u"), packetLength));
|
|
|
|
/************************************************************************/
|
|
/* Now update the data pointer to point to the include the XT data */
|
|
/* header. */
|
|
/************************************************************************/
|
|
TRC_DBG((TB, _T("Move pData back from %p to %p"),
|
|
pData,
|
|
pData - sizeof(XT_DT)));
|
|
pData -= sizeof(XT_DT);
|
|
|
|
/************************************************************************/
|
|
/* Copy in the header. */
|
|
/************************************************************************/
|
|
memcpy(pData, &xtDT, sizeof(XT_DT));
|
|
|
|
/************************************************************************/
|
|
/* Trace out the packet. */
|
|
/************************************************************************/
|
|
TRC_DATA_DBG("XT packet:", pData, packetLength);
|
|
|
|
/************************************************************************/
|
|
/* Now send the buffer. */
|
|
/************************************************************************/
|
|
_pTd->TD_SendBuffer(pData, packetLength, (TD_BUFHND)bufHandle);
|
|
|
|
DC_END_FN();
|
|
} /* XT_SendBuffer */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_Recv */
|
|
/* */
|
|
/* Purpose: Attempts to retrieve the requested number of bytes into the */
|
|
/* buffer pointed to by pBuffer. This function should only */
|
|
/* be called in response to an MCS_OnXTDataAvailable callback. */
|
|
/* */
|
|
/* Returns: The number of bytes received. */
|
|
/* */
|
|
/* Params: IN pData - pointer to buffer to receive the data. */
|
|
/* IN length - number of bytes to receive. */
|
|
/****************************************************************************/
|
|
DCUINT DCAPI CXT::XT_Recv(PDCUINT8 pData, DCUINT length)
|
|
{
|
|
DCUINT bytesRead;
|
|
DCUINT numBytes;
|
|
|
|
DC_BEGIN_FN("XT_Recv");
|
|
|
|
TRC_ASSERT((length != 0), (TB, _T("Data length to receive is 0")));
|
|
TRC_ASSERT((length < 65535),(TB,_T("Data length %u too large"), length));
|
|
TRC_ASSERT((pData != 0), (TB, _T("Data pointer is NULL")));
|
|
|
|
// We can only receive the minimum of the number of bytes in XT and
|
|
// the requested length.
|
|
numBytes = DC_MIN(length, _XT.dataBytesLeft);
|
|
TRC_DBG((TB, _T("Receive %u bytes (length:%u dataBytesLeft:%u)"),
|
|
numBytes, length, _XT.dataBytesLeft));
|
|
|
|
// Try to read the bytes from TD.
|
|
bytesRead = _pTd->TD_Recv(pData, numBytes);
|
|
|
|
// Decrement the count of data bytes left in _XT.
|
|
_XT.dataBytesLeft -= bytesRead;
|
|
TRC_DBG((TB, _T("%u data bytes left in XT frame"), _XT.dataBytesLeft));
|
|
|
|
if (!_pTd->TD_QueryDataAvailable() || (0 == _XT.dataBytesLeft)) {
|
|
// TD has no more data or this XT frame is finished - so there is
|
|
// no longer any data left in _XT.
|
|
TRC_DBG((TB, _T("No data left in XT")));
|
|
_XT.dataInXT = FALSE;
|
|
}
|
|
|
|
TRC_DATA_DBG("Data received:", pData, bytesRead);
|
|
|
|
DC_END_FN();
|
|
return bytesRead;
|
|
} /* XT_Recv */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_OnTDConnected */
|
|
/* */
|
|
/* Purpose: This is called by TD when it has successfully connected. */
|
|
/****************************************************************************/
|
|
DCVOID DCCALLBACK CXT::XT_OnTDConnected(DCVOID)
|
|
{
|
|
DC_BEGIN_FN("XT_OnTDConnected");
|
|
|
|
TRC_NRM((TB, _T("TD connected: init states and decouple CR send")));
|
|
|
|
// Initialize our state and count of bytes that we're waiting for.
|
|
// Fast-path server output can send as small as 2 bytes for a header,
|
|
// so we init the header receive size to get 2 bytes, which we'll expand
|
|
// to X.224 or fast-path remainder as needed when receiving.
|
|
//
|
|
// Also reset the count of data bytes left and flag that there is
|
|
// currently no data in _XT.
|
|
XT_ResetDataState();
|
|
|
|
// Decouple to the sender thread and send a XT CR.
|
|
|
|
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
|
|
CD_NOTIFICATION_FUNC(CXT,XTSendCR),
|
|
0);
|
|
|
|
DC_END_FN();
|
|
} /* XT_OnTDConnected */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_OnTDDisconnected */
|
|
/* */
|
|
/* Purpose: This callback function is called by TD when it has */
|
|
/* disconnected. */
|
|
/* */
|
|
/* Params: IN reason - reason for the disconnection. */
|
|
/****************************************************************************/
|
|
DCVOID DCCALLBACK CXT::XT_OnTDDisconnected(DCUINT reason)
|
|
{
|
|
DC_BEGIN_FN("XT_OnTDDisconnected");
|
|
|
|
TRC_ASSERT((reason != 0), (TB, _T("Disconnect reason from TD is 0")));
|
|
|
|
/************************************************************************/
|
|
/* Decide if we want to over-ride the disconnect reason code. */
|
|
/************************************************************************/
|
|
if (_XT.disconnectErrorCode != 0)
|
|
{
|
|
TRC_ALT((TB, _T("Over-riding disconnection error code (%u->%u)"),
|
|
reason,
|
|
_XT.disconnectErrorCode));
|
|
|
|
/********************************************************************/
|
|
/* Over-ride the error code and set the global variable to 0. */
|
|
/********************************************************************/
|
|
reason = _XT.disconnectErrorCode;
|
|
_XT.disconnectErrorCode = 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Just pass this up to MCS. */
|
|
/************************************************************************/
|
|
TRC_NRM((TB, _T("Disconnect reason:%u"), reason));
|
|
_pMcs->MCS_OnXTDisconnected(reason);
|
|
|
|
DC_END_FN();
|
|
} /* XT_OnTDDisconnected */
|
|
|
|
|
|
/****************************************************************************/
|
|
// XTRecvToHdrBuf
|
|
//
|
|
// Receives data into the header buffer.
|
|
// We use a macro to force cutting the function call overhead. Data-receive
|
|
// must be as fast as possible, at the expense of a bit of code size.
|
|
// Returns TRUE in bytesNeededZero if the receive bytes needed count is zero.
|
|
// Returns FALSE in status if an invalid number of bytes is being read
|
|
//
|
|
/****************************************************************************/
|
|
#define XTRecvToHdrBuf(bytesNeededZero,status) { \
|
|
unsigned bytesRecv; \
|
|
\
|
|
/* Check that we're being asked to receive some data and that the */ \
|
|
/* header buffer has space for it. */ \
|
|
/* We also chech the unsigned overflow here. If we add to a trusted */ \
|
|
/* size (_XT.hdrBytesRead) anything the result should not be smaller */ \
|
|
/* then the trusted size. */ \
|
|
TRC_ASSERT((0 != _XT.hdrBytesNeeded), (TB, _T("No data to receive"))); \
|
|
TRC_ASSERT((_XT.hdrBytesRead + _XT.hdrBytesNeeded <= sizeof(_XT.pHdrBuf)), \
|
|
(TB, _T("Header buffer size %u too small for %u read + %u needed"), \
|
|
sizeof(_XT.pHdrBuf), \
|
|
_XT.hdrBytesRead, \
|
|
_XT.hdrBytesNeeded)); \
|
|
TRC_ASSERT((_XT.hdrBytesRead + _XT.hdrBytesNeeded >= _XT.hdrBytesRead), \
|
|
(TB, _T("Header size overflow caused by %u read + %u needed"), \
|
|
sizeof(_XT.pHdrBuf), \
|
|
_XT.hdrBytesRead, \
|
|
_XT.hdrBytesNeeded)); \
|
|
if ((_XT.hdrBytesRead + _XT.hdrBytesNeeded <= sizeof(_XT.pHdrBuf))) \
|
|
{ \
|
|
bytesRecv = _pTd->TD_Recv(_XT.pHdrBuf + _XT.hdrBytesRead, _XT.hdrBytesNeeded); \
|
|
_XT.hdrBytesNeeded -= bytesRecv; \
|
|
_XT.hdrBytesRead += bytesRecv; \
|
|
bytesNeededZero = (0 == _XT.hdrBytesNeeded); \
|
|
status = TRUE; \
|
|
} \
|
|
else \
|
|
{ \
|
|
status = FALSE; \
|
|
} \
|
|
\
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XT_OnTDDataAvailable */
|
|
/* */
|
|
/* Purpose: This callback function is called by TD when it has received */
|
|
/* data from the server. */
|
|
/****************************************************************************/
|
|
DCVOID DCCALLBACK CXT::XT_OnTDDataAvailable(DCVOID)
|
|
{
|
|
PXT_CMNHDR pCmnHdr = (PXT_CMNHDR)_XT.pHdrBuf;
|
|
unsigned pktType;
|
|
unsigned unreadPktBytes;
|
|
DCBOOL fAllBytesRecvd = FALSE;
|
|
DCBOOL rcvOk = TRUE;
|
|
|
|
DC_BEGIN_FN("XT_OnTDDataAvailable");
|
|
|
|
// Check for recursion.
|
|
if (!_XT.inXTOnTDDataAvail) {
|
|
_XT.inXTOnTDDataAvail = TRUE;
|
|
|
|
// Loop round while there is data available in TD.
|
|
while (_pTd->TD_QueryDataAvailable()) {
|
|
TRC_DBG((TB, _T("Data available from TD, state:%u"), _XT.rcvState));
|
|
|
|
switch (_XT.rcvState) {
|
|
case XT_RCVST_HEADER:
|
|
XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
|
|
if (fAllBytesRecvd && rcvOk) {
|
|
// We've read the first two bytes, and can now decide
|
|
// what type of packet this is.
|
|
if ((_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ACTION_MASK) ==
|
|
TS_OUTPUT_FASTPATH_ACTION_FASTPATH) {
|
|
// This is a fast-path output header. The length
|
|
// is in the second and, maybe, third byte.
|
|
if (!(_XT.pHdrBuf[1] & 0x80)) {
|
|
// Length was in first byte only. Proceed to
|
|
// the data state.
|
|
_XT.hdrBytesNeeded =
|
|
XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
|
|
_XT.hdrBytesRead = 0;
|
|
_XT.rcvState =
|
|
XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA;
|
|
|
|
// Before updating the count of data bytes
|
|
// left, assert that it is currently zero.
|
|
TRC_ASSERT((0 == _XT.dataBytesLeft),
|
|
(TB, _T("Data bytes left non-zero:%u"),
|
|
_XT.dataBytesLeft));
|
|
_XT.dataBytesLeft = _XT.pHdrBuf[1] - 2;
|
|
|
|
if (_XT.dataBytesLeft >= 2) {
|
|
TRC_DBG((TB,_T("Fast-path output pkt, ")
|
|
_T("size=%u"), _XT.dataBytesLeft));
|
|
|
|
MCS_SetDataLengthToReceive(_pMcs,
|
|
_XT.dataBytesLeft);
|
|
|
|
/************************************************************/
|
|
/* There is a retail check for size in MCS_RecvToDataBuf, */
|
|
/* but this helps us debug it before that point. */
|
|
/************************************************************/
|
|
TRC_ASSERT((_pMcs->_MCS.dataBytesNeeded < 65535),
|
|
(TB,_T("Data recv size %u too large"), _pMcs->_MCS.dataBytesNeeded));
|
|
}
|
|
else {
|
|
TRC_ABORT((TB, _T("Fast-path size byte %02X")
|
|
_T("contains len < 2"),
|
|
_XT.pHdrBuf[1]));
|
|
|
|
TRC_ASSERT((0 == _XT.disconnectErrorCode),
|
|
(TB, _T("Disconnect error code ")
|
|
_T("already set!")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
else {
|
|
_XT.hdrBytesNeeded = 1;
|
|
_XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_HEADER;
|
|
}
|
|
}
|
|
else {
|
|
// The first byte is standard X.224. Reset the
|
|
// state to read a full X.224 header.
|
|
_XT.hdrBytesNeeded = sizeof(XT_DT) -
|
|
XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
|
|
_XT.rcvState = XT_RCVST_X224_HEADER;
|
|
}
|
|
}
|
|
else if (!rcvOk)
|
|
{
|
|
TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
break;
|
|
|
|
|
|
case XT_RCVST_FASTPATH_OUTPUT_HEADER:
|
|
XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
|
|
if (fAllBytesRecvd && rcvOk) {
|
|
// This is a long fast-path output header (3 bytes).
|
|
// Get the size from the second and third bytes and
|
|
// change to data state.
|
|
_XT.hdrBytesNeeded =
|
|
XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
|
|
_XT.hdrBytesRead = 0;
|
|
_XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA;
|
|
|
|
// Before updating the count of data bytes left,
|
|
// assert that it is currently zero.
|
|
TRC_ASSERT((0 == _XT.dataBytesLeft),
|
|
(TB, _T("Data bytes left non-zero:%u"),
|
|
_XT.dataBytesLeft));
|
|
_XT.dataBytesLeft = (((_XT.pHdrBuf[1] & 0x7F) << 8) |
|
|
_XT.pHdrBuf[2]) - 3;
|
|
|
|
if (_XT.dataBytesLeft >= 3) {
|
|
TRC_DBG((TB,_T("Fast-path output pkt, size=%u"),
|
|
_XT.dataBytesLeft));
|
|
|
|
MCS_SetDataLengthToReceive(_pMcs, _XT.dataBytesLeft);
|
|
|
|
/************************************************************/
|
|
/* There is a retail check for size in MCS_RecvToDataBuf, */
|
|
/* but this helps us debug it before that point. */
|
|
/************************************************************/
|
|
TRC_ASSERT((_pMcs->_MCS.dataBytesNeeded < 65535),
|
|
(TB,_T("Data recv size %u too large"), _pMcs->_MCS.dataBytesNeeded));
|
|
}
|
|
else {
|
|
TRC_ABORT((TB, _T("Fast-path size bytes %02X %02X")
|
|
_T("contain len < 3"),
|
|
_XT.pHdrBuf[1], _XT.pHdrBuf[2]));
|
|
|
|
TRC_ASSERT((0 == _XT.disconnectErrorCode),
|
|
(TB, _T("Disconnect error code ")
|
|
_T("already set!")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
else if (!rcvOk)
|
|
{
|
|
TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA: {
|
|
BYTE FAR *_pTdData;
|
|
|
|
// If we can, use the fully-recv()'d data straight from
|
|
// the TD buffer, since fast-path does not need to
|
|
// copy to an aligned buffer. Since we're at state
|
|
// BEGIN_DATA we know we've not yet read any post-header
|
|
// output data. The most common implementation of recv()
|
|
// copies into the target buffer the entire data for one
|
|
// TCP sequence (i.e. one server OUTBUF) if the target
|
|
// buffer is large enough. Which means that most often
|
|
// we'll be able to use the data directly, since the TD
|
|
// receive buffer size is tuned to accept an entire large
|
|
// (~8K) server OUTBUF. If we can't get the full data,
|
|
// copy into the MCS buffer and move to CONTINUE_DATA.
|
|
TD_GetDataForLength(_pMcs->_MCS.dataBytesNeeded, &_pTdData, _pTd);
|
|
if (_pTdData != NULL) {
|
|
HRESULT hrTemp;
|
|
// We've gotten all the data. Now we can fast-path
|
|
// call past all the layering to SL for decryption.
|
|
hrTemp = _pSl->SL_OnFastPathOutputReceived(_pTdData,
|
|
_pMcs->_MCS.dataBytesNeeded,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
|
|
|
|
// Reset for the next header.
|
|
_pMcs->_MCS.dataBytesRead = 0;
|
|
_XT.dataBytesLeft = 0;
|
|
_XT.rcvState = XT_RCVST_HEADER;
|
|
|
|
if (!SUCCEEDED(hrTemp))
|
|
{
|
|
XT_IgnoreRestofPacket();
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
else {
|
|
HRESULT hrTemp;
|
|
|
|
// Copy for reassembly directly into the MCS data buffer.
|
|
MCS_RecvToDataBuf(hrTemp, this, _pMcs);
|
|
if (!SUCCEEDED(hrTemp))
|
|
{
|
|
TRC_ABORT((TB,_T("Recv to databuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
fAllBytesRecvd = (S_OK == hrTemp);
|
|
if (fAllBytesRecvd) {
|
|
// We've gotten all the data. Now we can fast-path
|
|
// call past all the layering to SL for decryption.
|
|
hrTemp = _pSl->SL_OnFastPathOutputReceived(_pMcs->_MCS.pReceivedPacket,
|
|
_pMcs->_MCS.dataBytesRead,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
|
|
|
|
// Reset for the next header.
|
|
_pMcs->_MCS.dataBytesRead = 0;
|
|
_XT.dataBytesLeft = 0;
|
|
_XT.rcvState = XT_RCVST_HEADER;
|
|
|
|
if (!SUCCEEDED(hrTemp))
|
|
{
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
else {
|
|
_XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA:
|
|
{
|
|
HRESULT hrTemp;
|
|
|
|
// Copy for reassembly directly into the MCS data buffer.
|
|
MCS_RecvToDataBuf(hrTemp, this, _pMcs);
|
|
if (!SUCCEEDED(hrTemp))
|
|
{
|
|
TRC_ABORT((TB,_T("Recv to databuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
fAllBytesRecvd = (S_OK == hrTemp);
|
|
if (fAllBytesRecvd) {
|
|
// We've gotten all the data. Now we can fast-path
|
|
// call past all the layering to SL for decryption.
|
|
hrTemp = _pSl->SL_OnFastPathOutputReceived(_pMcs->_MCS.pReceivedPacket,
|
|
_pMcs->_MCS.dataBytesRead,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
|
|
_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
|
|
|
|
// Reset for the next header.
|
|
_pMcs->_MCS.dataBytesRead = 0;
|
|
_XT.dataBytesLeft = 0;
|
|
_XT.rcvState = XT_RCVST_HEADER;
|
|
|
|
if (!SUCCEEDED(hrTemp))
|
|
{
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
else {
|
|
_XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XT_RCVST_X224_HEADER:
|
|
XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
|
|
if (fAllBytesRecvd && rcvOk) {
|
|
// We've read a complete X.224 common header, so we
|
|
// can now attempt to interpret it. First of all check
|
|
// that the TPKT version is correct.
|
|
if (pCmnHdr->vrsn != XT_TPKT_VERSION)
|
|
{
|
|
TRC_ABORT((TB, _T("Unknown TPKT version:%u"),
|
|
(DCUINT)pCmnHdr->vrsn));
|
|
|
|
TRC_ASSERT((0 == _XT.disconnectErrorCode),
|
|
(TB, _T("Disconnect error code already set!")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADTPKTVERSION);
|
|
|
|
// Something very bad has happened so just
|
|
// disconnect.
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
// Get the packet type - this is given by the top four
|
|
// bits of the crcDt field.
|
|
pktType = pCmnHdr->typeCredit >> 4;
|
|
|
|
// Calculate the number of unread bytes in the packet.
|
|
unreadPktBytes = ((pCmnHdr->lengthHighPart << 8) | pCmnHdr->lengthLowPart) -
|
|
_XT.hdrBytesRead;
|
|
|
|
TRC_DBG((TB, _T("Pkt type:%u read:%u unread:%u"),
|
|
pktType,
|
|
_XT.hdrBytesRead,
|
|
unreadPktBytes));
|
|
|
|
if (XT_PKT_DT == pktType) {
|
|
// This is a data packet - we don't need to
|
|
// receive any more header bytes. Update our
|
|
// state variables.
|
|
_XT.hdrBytesNeeded =
|
|
XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
|
|
_XT.hdrBytesRead = 0;
|
|
_XT.rcvState = XT_RCVST_X224_DATA;
|
|
|
|
// Before updating the count of data bytes left,
|
|
// assert that it is currently zero.
|
|
TRC_ASSERT((0 == _XT.dataBytesLeft),
|
|
(TB, _T("Data bytes left non-zero:%u"),
|
|
_XT.dataBytesLeft));
|
|
|
|
_XT.dataBytesLeft = unreadPktBytes;
|
|
//
|
|
// Here we don't have to check the unreadPktBytes
|
|
// because this can't cause an overflow. The size
|
|
// of the data in an XT packet can be as much as
|
|
// XT_MAX_DATA_SIZE and it should be checked by
|
|
// the protocols above.
|
|
//
|
|
TRC_ASSERT((XT_MAX_DATA_SIZE >= _XT.dataBytesLeft),
|
|
(TB, _T("Data bytes left too big:%u"),
|
|
_XT.dataBytesLeft));
|
|
|
|
TRC_DBG((TB, _T("Data pkt(size:%u) state HDR->DATA"),
|
|
_XT.dataBytesLeft));
|
|
}
|
|
else {
|
|
// This is a control packet - we need to receive
|
|
// some more bytes.
|
|
|
|
// Here we have a real issue if we have an overflow.
|
|
// We have to check that what we still have to read
|
|
// is not going to overflow the buffer. We check
|
|
// the overflow against the hdrBytesRead because
|
|
// this is a trusted value.
|
|
if ((_XT.hdrBytesRead + unreadPktBytes >
|
|
sizeof(_XT.pHdrBuf)) ||
|
|
(_XT.hdrBytesRead + unreadPktBytes <
|
|
_XT.hdrBytesRead)) {
|
|
TRC_ERR((TB,_T("The header length is too big.")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
// TD_Disconnect doesn't have anything to
|
|
// do with the XT state so we have to reset
|
|
// the XT state in order to have a successful
|
|
// disconnect
|
|
_pTd->TD_Disconnect();
|
|
XT_IgnoreRestofPacket();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
_XT.hdrBytesNeeded = unreadPktBytes;
|
|
_XT.rcvState = XT_RCVST_X224_CONTROL;
|
|
|
|
TRC_NRM((TB, _T("Ctrl pkt state HEADER->CONTROL")));
|
|
}
|
|
}
|
|
else if (!rcvOk)
|
|
{
|
|
TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
break;
|
|
|
|
|
|
case XT_RCVST_X224_CONTROL:
|
|
XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
|
|
if (fAllBytesRecvd && rcvOk) {
|
|
// We've now managed to get a whole packet, so try to
|
|
// interpret it.
|
|
XTHandleControlPkt();
|
|
|
|
// Update our states.
|
|
_XT.rcvState = XT_RCVST_HEADER;
|
|
_XT.hdrBytesNeeded =
|
|
XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
|
|
_XT.hdrBytesRead = 0;
|
|
|
|
TRC_NRM((TB, _T("Processed ctrl pkt state CONTROL->HEADER")));
|
|
}
|
|
else if (!rcvOk)
|
|
{
|
|
TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTBADHEADER);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
break;
|
|
|
|
|
|
case XT_RCVST_X224_DATA:
|
|
// We now have some data available, so set our flag and
|
|
// callback to MCS.
|
|
_XT.dataInXT = TRUE;
|
|
if (_pMcs->MCS_OnXTDataAvailable()) {
|
|
// MCS has finished with this frame. This frame
|
|
// should not have any remaining data in it!
|
|
TRC_ASSERT((_XT.dataBytesLeft == 0),
|
|
(TB, _T("Unexpected extra %u bytes in the frame"),
|
|
_XT.dataBytesLeft));
|
|
if (_XT.dataBytesLeft != 0)
|
|
{
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(
|
|
NL_ERR_XTUNEXPECTEDDATA);
|
|
_pTd->TD_Disconnect();
|
|
goto PostDataRead;
|
|
}
|
|
|
|
// No data remaining so zip back to the expecting
|
|
// header state.
|
|
_XT.rcvState = XT_RCVST_HEADER;
|
|
TRC_DBG((TB, _T("Munched data pkt state DATA->HEADER")));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TRC_ABORT((TB, _T("Unrecognized XT recv state:%u"),
|
|
_XT.rcvState));
|
|
goto PostDataRead;
|
|
}
|
|
}
|
|
|
|
PostDataRead:
|
|
_XT.inXTOnTDDataAvail = FALSE;
|
|
if ( _XT.disconnectErrorCode == 0 ) {
|
|
_pClx->CLX_ClxPktDrawn();
|
|
}
|
|
}
|
|
else {
|
|
TRC_ALT((TB, _T("Recursion!")));
|
|
// Note we need to make sure not to reset _XT.inXTOnTDDataAvail.
|
|
}
|
|
|
|
DC_END_FN();
|
|
} /* XT_OnTDDataAvailable */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XTSendCR */
|
|
/* */
|
|
/* Purpose: Sends an X224 CR TPDU on the sender thread. */
|
|
/* */
|
|
/* Operation: This function gets a private buffer from TD, fills it with */
|
|
/* an X224 CR and then sends it. */
|
|
/****************************************************************************/
|
|
DCVOID DCINTERNAL CXT::XTSendCR(ULONG_PTR unused)
|
|
{
|
|
PDCUINT8 pBuffer;
|
|
TD_BUFHND bufHandle;
|
|
DCBOOL intRC;
|
|
XT_CR xtCR = XT_CR_DATA;
|
|
PBYTE pLBInfo;
|
|
BYTE HashModeCookie[HASHMODE_COOKIE_LENGTH];
|
|
BYTE TruncatedUserName[USERNAME_TRUNCATED_LENGTH + 1];
|
|
BOOL HashMode = FALSE;
|
|
DCUINT8 LBInfoLen;
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("XTSendCR");
|
|
|
|
DC_IGNORE_PARAMETER(unused);
|
|
|
|
|
|
// First set up the load balance information. The algorithm is as follows:
|
|
// 1. If in the middle of a redirection and there is a redirection cookie,
|
|
// use the redirection cookie.
|
|
// 2. If in the middle of a redirection and there is no redirection cookie,
|
|
// use no cookie at all.
|
|
// Otherwise, non-redirection rules apply:
|
|
// 3. If no scripted cookie is available, use the default built-in hash mode
|
|
// cookie. ("Cookie: mstshash=<truncated username>" + CR + LF)
|
|
// Only do this if there is something in the username field.
|
|
// 4. If a scripted cookie is available, use it.
|
|
|
|
if (_pUi->UI_IsClientRedirected()) {
|
|
// Handles cases 1 and 2, above.
|
|
pLBInfo = (PBYTE)_pUi->UI_GetRedirectedLBInfo();
|
|
}
|
|
else {
|
|
pLBInfo = (PBYTE)_pUi->UI_GetLBInfo();
|
|
// If pLBInfo is NULL then case 3. Otherwise, fall through--it's
|
|
// case 4.
|
|
if (pLBInfo == NULL && _pUi->_UI.UserName[0] != NULL) {
|
|
// Take the 1st 10 ASCII bytes of the username.
|
|
// NOT an error for this to fail as we intentionally truncate
|
|
hr = StringCchPrintfA(
|
|
(char *) TruncatedUserName,
|
|
USERNAME_TRUNCATED_LENGTH,
|
|
"%S", _pUi->_UI.UserName);
|
|
|
|
|
|
TruncatedUserName[USERNAME_TRUNCATED_LENGTH] = '\0';
|
|
|
|
// Create the cookie
|
|
hr = StringCchPrintfA(
|
|
(char *) HashModeCookie,
|
|
HASHMODE_COOKIE_LENGTH - 1,
|
|
"Cookie: mstshash=%s\r\n",
|
|
TruncatedUserName);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Printf hasmodecookie failed: 0x%x"),hr));
|
|
}
|
|
|
|
HashModeCookie[HASHMODE_COOKIE_LENGTH - 1] = NULL;
|
|
|
|
pLBInfo = HashModeCookie;
|
|
|
|
// Set hash mode to true to indicate pLBInfo is not a BSTR.
|
|
HashMode = TRUE;
|
|
}
|
|
}
|
|
|
|
if (pLBInfo) {
|
|
DCUINT16 xtLen;
|
|
|
|
// If HashMode is FALSE then pLBInfo is a BSTR. Otherwise it points to
|
|
// bytes.
|
|
if (HashMode == FALSE)
|
|
LBInfoLen = (DCUINT8) SysStringByteLen((BSTR)pLBInfo);
|
|
else
|
|
LBInfoLen = strlen((char *) pLBInfo);
|
|
|
|
xtLen = (xtCR.hdr.lengthHighPart << 8) + xtCR.hdr.lengthLowPart;
|
|
xtLen += LBInfoLen;
|
|
xtCR.hdr.lengthHighPart = xtLen >> 8;
|
|
xtCR.hdr.lengthLowPart = xtLen & 0xFF;
|
|
}
|
|
else {
|
|
LBInfoLen = 0;
|
|
}
|
|
xtCR.hdr.li += (DCUINT8)LBInfoLen;
|
|
|
|
/************************************************************************/
|
|
/* TD is now connected. */
|
|
/************************************************************************/
|
|
TRC_NRM((TB, _T("Send XT CR...")));
|
|
|
|
/************************************************************************/
|
|
/* Get a private buffer in which to send the TD connection request. */
|
|
/************************************************************************/
|
|
intRC = _pTd->TD_GetPrivateBuffer(sizeof(xtCR) + LBInfoLen,
|
|
&pBuffer, &bufHandle);
|
|
if (intRC) {
|
|
// Fill in the buffer with the CR.
|
|
DC_MEMCPY(pBuffer, &xtCR, sizeof(xtCR));
|
|
if (pLBInfo) {
|
|
DC_MEMCPY(pBuffer + sizeof(xtCR), pLBInfo, LBInfoLen);
|
|
}
|
|
TRC_DATA_NRM("CR data:", &xtCR, sizeof(xtCR));
|
|
|
|
// Send the XT CR.
|
|
_pTd->TD_SendBuffer(pBuffer, sizeof(xtCR) + LBInfoLen, bufHandle);
|
|
TRC_NRM((TB, _T("Sent XT CR")));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Failed to get a private buffer - just quit")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
} /* XTSendCR */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: XTHandleControlPkt */
|
|
/* */
|
|
/* Purpose: This function is called after XT has received a control */
|
|
/* packet. It is responsible for interpreting the control */
|
|
/* packet and calling the appropriate functions. */
|
|
/****************************************************************************/
|
|
DCVOID DCINTERNAL CXT::XTHandleControlPkt(DCVOID)
|
|
{
|
|
PXT_CMNHDR pCmnHdr = (PXT_CMNHDR) _XT.pHdrBuf;
|
|
DCUINT pktType;
|
|
|
|
DC_BEGIN_FN("XTHandleControlPkt");
|
|
|
|
/************************************************************************/
|
|
/* Get the packet type - this is given by the top four bits of the */
|
|
/* crcDt field. */
|
|
/************************************************************************/
|
|
pktType = pCmnHdr->typeCredit >> 4;
|
|
|
|
TRC_NRM((TB, _T("Pkt type:%u"), pktType));
|
|
|
|
/************************************************************************/
|
|
/* Now check for the packet type. */
|
|
/************************************************************************/
|
|
switch (pktType)
|
|
{
|
|
case XT_PKT_CR:
|
|
{
|
|
/****************************************************************/
|
|
/* We don't expect to receive one of these, so trace an alert. */
|
|
/****************************************************************/
|
|
TRC_ERR((TB, _T("Received unexpected XT CR pkt")));
|
|
|
|
/****************************************************************/
|
|
/* We could handle this case by sending a X224 ER or DR packet, */
|
|
/* but instead we'll do the absolute minimum and just ignore */
|
|
/* this packet (the other side should time-out its connection */
|
|
/* request). */
|
|
/****************************************************************/
|
|
}
|
|
break;
|
|
|
|
case XT_PKT_CC:
|
|
{
|
|
TRC_NRM((TB, _T("XT CC received")));
|
|
|
|
/****************************************************************/
|
|
/* This is a connection confirm. We're not interested in the */
|
|
/* contents of this packet - all we need to do is to tell MCS */
|
|
/* that we're now connected. */
|
|
/****************************************************************/
|
|
_pMcs->MCS_OnXTConnected();
|
|
}
|
|
break;
|
|
|
|
case XT_PKT_DR:
|
|
case XT_PKT_ER:
|
|
{
|
|
TRC_NRM((TB, _T("XT DR/ER received")));
|
|
|
|
/****************************************************************/
|
|
/* This is a disconnect request or an error - we've either */
|
|
/* failed to establish the connection or the other party is */
|
|
/* wanting to disconnect from the existing connection. Note */
|
|
/* that we don't need to respond to the DR TPDU (Class 0 X224 */
|
|
/* doesn't provide any way to do so). Call _pTd->TD_Disconnect to */
|
|
/* disconnect the layer below us. TD will call us (XT) back */
|
|
/* when it has disconnected - at that point we'll tell the */
|
|
/* layers above that we've disconnected. */
|
|
/****************************************************************/
|
|
_pTd->TD_Disconnect();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
/****************************************************************/
|
|
/* Something very bad has happened so we'd better try to */
|
|
/* disconnect. */
|
|
/****************************************************************/
|
|
TRC_ABORT((TB, _T("Unrecognized XT header - %u"), pktType));
|
|
|
|
/****************************************************************/
|
|
/* Set the disconnect error code. This will be used to */
|
|
/* over-ride/ the reason code in the OnDisconnected callback. */
|
|
/****************************************************************/
|
|
TRC_ASSERT((0 == _XT.disconnectErrorCode),
|
|
(TB, _T("Disconnect error code has already been set!")));
|
|
_XT.disconnectErrorCode =
|
|
NL_MAKE_DISCONNECT_ERR(NL_ERR_XTBADHEADER);
|
|
|
|
/****************************************************************/
|
|
/* Begin the disconnection. */
|
|
/****************************************************************/
|
|
_pTd->TD_Disconnect();
|
|
}
|
|
break;
|
|
}
|
|
|
|
DC_END_FN();
|
|
} /* XTHandleControlPkt */
|
|
|
|
|
|
|