Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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