/****************************************************************************/ // xtapi.cpp // // XT layer - portable API // // Copyright (C) 1997-1999 Microsoft Corporation /****************************************************************************/ #include extern "C" { #define TRC_FILE "xtapi" #define TRC_GROUP TRC_GROUP_NETWORK #include } #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=" + 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 */