Windows2003-3790/termsrv/newclient/core/mcsapi.cpp
2020-09-30 16:53:55 +02:00

1044 lines
54 KiB
C++

/**MOD+**********************************************************************/
/* Module: mcsapi.cpp */
/* */
/* Purpose: MCS API code */
/* */
/* Copyright(C) Microsoft Corporation 1997-1999 */
/* */
/****************************************************************************/
#include <adcg.h>
/****************************************************************************/
/* */
/* INCLUDES */
/* */
/****************************************************************************/
extern "C" {
/****************************************************************************/
/* Tracing defines and include. */
/****************************************************************************/
#define TRC_FILE "mcsapi"
#define TRC_GROUP TRC_GROUP_NETWORK
#include <atrcapi.h>
}
#include "autil.h"
#include "mcs.h"
#include "cd.h"
#include "xt.h"
#include "nc.h"
#include "nl.h"
CMCS::CMCS(CObjs* objs)
{
_pClientObjects = objs;
}
CMCS::~CMCS()
{
}
/****************************************************************************/
/* */
/* FUNCTIONS */
/* */
/****************************************************************************/
/**PROC+*********************************************************************/
/* Name: MCS_Init */
/* */
/* Purpose: Initializes _MCS. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_Init(DCVOID)
{
DC_BEGIN_FN("MCS_Init");
/************************************************************************/
/* Initialize global data. */
/************************************************************************/
DC_MEMSET(&_MCS, 0, sizeof(_MCS));
_pCd = _pClientObjects->_pCdObject;
_pNc = _pClientObjects->_pNcObject;
_pUt = _pClientObjects->_pUtObject;
_pXt = _pClientObjects->_pXTObject;
_pNl = _pClientObjects->_pNlObject;
_pSl = _pClientObjects->_pSlObject;
/************************************************************************/
/* Pre-allocate memory for the header buffer. */
/************************************************************************/
_MCS.pHdrBuf = (PDCUINT8)UT_Malloc( _pUt, MCS_DEFAULT_HEADER_LENGTH );
if( _MCS.pHdrBuf )
{
_MCS.hdrBufLen = MCS_DEFAULT_HEADER_LENGTH;
}
else
{
TRC_ASSERT(((ULONG_PTR)_MCS.pHdrBuf),
(TB, _T("Cannot allocate memory for MCS header")));
}
/************************************************************************/
/* Set the received packet buffer pointer - this must be aligned to */
/* 4-byte boundary + 2, in order that 32-bit fields within a T.128 */
/* packet are correctly aligned. */
/************************************************************************/
_MCS.pReceivedPacket = &(_MCS.dataBuf[2]);
TRC_ASSERT(((ULONG_PTR)_MCS.pReceivedPacket % 4 == 2),
(TB, _T("Data buffer %p not 2-byte aligned"), _MCS.pReceivedPacket));
/************************************************************************/
/* Call the XT initialization function. */
/************************************************************************/
_pXt->XT_Init();
TRC_NRM((TB, _T("MCS successfully initialized")));
DC_END_FN();
return;
} /* MCS_Init */
/**PROC+*********************************************************************/
/* Name: MCS_Term */
/* */
/* Purpose: Terminates _MCS. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_Term(DCVOID)
{
DC_BEGIN_FN("MCS_Term");
if( _MCS.pHdrBuf )
{
UT_Free( _pUt, _MCS.pHdrBuf );
_MCS.pHdrBuf = NULL;
_MCS.hdrBufLen = 0;
}
/************************************************************************/
/* Call the XT termination function. */
/************************************************************************/
_pXt->XT_Term();
TRC_NRM((TB, _T("MCS successfully terminated")));
DC_END_FN();
return;
} /* MCS_Term */
/**PROC+*********************************************************************/
/* Name: MCS_Connect */
/* */
/* Purpose: This function calls XT_Connect to begin the connection */
/* process. This will hopefully result in a MCS_OnXTConnected */
/* callback from XT. At that point we can send the MCS */
/* Connect-Initial PDU. */
/* */
/* Returns: Nothing. */
/* */
/* Params: IN bInitateConnect - TRUE to Initate connection */
/* IN pServerAddress - the address of the server to call. */
/* IN pUserData - a pointer to some user data. */
/* IN userDataLength - the length of the user data. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_Connect(BOOL bInitateConnect,
PDCTCHAR pServerAddress,
PDCUINT8 pUserData,
DCUINT userDataLength)
{
DC_BEGIN_FN("MCS_Connect");
/************************************************************************/
/* Use the receiver buffer to temporarily store the user data. We'll */
/* need to add it to the Connect-Initial PDU when we assemble it after */
/* receiving the MCS_OnXTConnected callback. */
/************************************************************************/
_MCS.userDataLength = userDataLength;
TRC_ASSERT((_MCS.pReceivedPacket != NULL), (TB, _T("Null rcv packet buffer")));
DC_MEMCPY(_MCS.pReceivedPacket, pUserData, _MCS.userDataLength);
TRC_NRM((TB, _T("Copied userdata, now calling XT_Connect (address:%s)..."),
pServerAddress));
/************************************************************************/
/* Now start the connection process. */
/************************************************************************/
_pXt->XT_Connect(bInitateConnect, pServerAddress);
DC_END_FN();
return;
} /* MCS_Connect */
/**PROC+*********************************************************************/
/* Name: MCS_Disconnect */
/* */
/* Purpose: This function sends a Disconnect-Provider ultimatum PDU to */
/* the server. After that has happened MCSContinueDisconnect */
/* will call XT_Disconnect to disconnect the lower layers. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_Disconnect(DCVOID)
{
DC_BEGIN_FN("MCS_Disconnect");
/************************************************************************/
/* Call MCS to send a disconnect provider ultimatum. */
/************************************************************************/
TRC_NRM((TB, _T("Decouple to snd thrd and send MCS DPum PDU")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CMCS, MCSSendDisconnectProviderUltimatum),
(ULONG_PTR) 0);
DC_END_FN();
return;
} /* MCS_Disconnect */
/**PROC+*********************************************************************/
/* Name: MCS_AttachUser */
/* */
/* Purpose: Generates and sends a MCS Attach-User-Request PDU. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/* Operation: This function will result in a NC_OnMCSAttachUserConfirm */
/* callback. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_AttachUser(DCVOID)
{
DC_BEGIN_FN("MCS_AttachUser");
/************************************************************************/
/* Decouple to the send thread and send an MCS Attach-User-Request PDU. */
/************************************************************************/
TRC_NRM((TB, _T("Decouple to snd thrd and send MCS AUR PDU")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CMCS, MCSSendAttachUserRequest),
(ULONG_PTR) 0);
DC_END_FN();
return;
} /* MCS_AttachUser */
/**PROC+*********************************************************************/
/* Name: MCS_JoinChannel */
/* */
/* Purpose: Joins the specified MCS channel. */
/* */
/* Returns: Nothing. */
/* */
/* Params: IN channel - the channel ID to join. */
/* IN userID - the MCS user ID. */
/* */
/* Operation: This function will result in a NC_OnMCSChannelJoinConfirm */
/* callback. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_JoinChannel(DCUINT channel, DCUINT userID)
{
MCS_DECOUPLEINFO decoupleInfo;
DC_BEGIN_FN("MCS_JoinChannel");
//
// Flag which channel we are currently joining so we
// can validate channel confirm PDU's.
//
MCS_SetPendingChannelJoin((DCUINT16)channel);
/************************************************************************/
/* Fill in the decoupling information structure. */
/************************************************************************/
decoupleInfo.channel = channel;
decoupleInfo.userID = userID;
/************************************************************************/
/* Decouple to the send thread and send an MCS Channel-Join-Request */
/* PDU. */
/************************************************************************/
TRC_NRM((TB, _T("Decouple to snd thrd and send MCS CJR PDU")));
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CMCS, MCSSendChannelJoinRequest),
&decoupleInfo,
sizeof(decoupleInfo));
DC_END_FN();
return;
} /* MCS_JoinChannel */
/**PROC+*********************************************************************/
/* Name: MCS_GetBuffer */
/* */
/* Purpose: Attempts to get a buffer from XT. This function gets a */
/* buffer which is big enough to include the MCS header and then */
/* updates the buffer pointer obtained from XT past the space */
/* reserved for the MCS header. */
/* */
/* Returns: TRUE if a buffer is successfully obtained and FALSE */
/* otherwise. */
/* */
/* Params: IN dataLength - length of the buffer requested. */
/* OUT ppBuffer - a pointer to a pointer to the buffer. */
/* OUT pBufHandle - a pointer to a buffer handle. */
/* */
/**PROC-*********************************************************************/
DCBOOL DCAPI CMCS::MCS_GetBuffer(DCUINT dataLength,
PPDCUINT8 ppBuffer,
PMCS_BUFHND pBufHandle)
{
DCBOOL rc;
DCUINT headerLength;
PDCUINT8 pBuf = NULL;
DCUINT alignment;
DCUINT alignPad = 0;
DC_BEGIN_FN("MCS_GetBuffer");
/************************************************************************/
/* Calculate the required header length. */
/************************************************************************/
headerLength = MCSGetSDRHeaderLength(dataLength);
TRC_DBG((TB, _T("dataLength:%u headerLength:%u"), dataLength, headerLength));
/************************************************************************/
/* Now add this length to the total amount of data needed from XT. */
/************************************************************************/
dataLength += headerLength;
/************************************************************************/
/* Adjust the length to take account of the 4n+2 alignment below. */
/************************************************************************/
alignment = (_pXt->XT_GetBufferHeaderLen() + headerLength) % 4;
TRC_DBG((TB, _T("alignment:%u"), alignment));
if (alignment != 2)
{
alignPad = (6 - alignment) % 4;
dataLength += alignPad;
TRC_DBG((TB, _T("datalength now:%u"), dataLength));
}
/************************************************************************/
/* Now get a buffer from XT. */
/************************************************************************/
rc = _pXt->XT_GetPublicBuffer(dataLength, &pBuf, (PXT_BUFHND) pBufHandle);
if (!rc)
{
/********************************************************************/
/* We failed to get a buffer so just quit. */
/********************************************************************/
TRC_DBG((TB, _T("Failed to get a buffer from XT")));
DC_QUIT;
}
/************************************************************************/
/* Now move the buffer pointer along to make space for our header. */
/************************************************************************/
TRC_DBG((TB, _T("Moving header ptr from %p to %p"),
pBuf,
pBuf + headerLength));
*ppBuffer = pBuf + headerLength;
/************************************************************************/
/* Force alignment to be 4n+2 - so that T.128 PDUs are naturally */
/* aligned. */
/************************************************************************/
if (alignment != 2)
{
*ppBuffer += alignPad;
TRC_DBG((TB, _T("Realigned buffer pointer to %p"), *ppBuffer));
}
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* MCS_GetBuffer */
/**PROC+*********************************************************************/
/* Name: MCS_SendPacket */
/* */
/* Purpose: Generates and adds an MCS header to the packet before */
/* passing it to XT to send. */
/* */
/* Returns: Nothing. */
/* */
/* Params: IN pData - pointer to the start of the data. */
/* IN dataLength - length of the data. */
/* IN bufHandle - MCS buffer handle. */
/* IN channel - channel to send the data on. */
/* IN priority - priority to send the data at. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_SendPacket(PDCUINT8 pData,
DCUINT dataLength,
DCUINT flags,
MCS_BUFHND bufHandle,
DCUINT userID,
DCUINT channel,
DCUINT priority)
{
PDCUINT8 pHeader;
DCUINT headerLength;
DC_BEGIN_FN("MCS_SendPacket");
/************************************************************************/
/* Ignore the priority parameter as we implement a single priority. */
/* Also ignore the flags parameter as we don't support any flags at */
/* present. */
/************************************************************************/
DC_IGNORE_PARAMETER(priority);
DC_IGNORE_PARAMETER(flags);
/************************************************************************/
/* Assert that the hiword of the channel is 0. */
/************************************************************************/
TRC_ASSERT((0 == HIWORD((DCUINT32)channel)),
(TB, _T("Hi-word of channel is non-zero")));
/************************************************************************/
/* Assert that the hiword of the user-id is 0. */
/************************************************************************/
TRC_ASSERT((0 == HIWORD((DCUINT32)userID)),
(TB, _T("Hi-word of userID is non-zero")));
/************************************************************************/
/* Check that the packet length is within the allowable range. */
/************************************************************************/
TRC_ASSERT((dataLength < MCS_MAX_SNDPKT_LENGTH),
(TB, _T("Bad packet length :%u"), dataLength));
/************************************************************************/
/* Update the performance counter. */
/************************************************************************/
PRF_INC_COUNTER(PERF_PKTS_SENT);
/************************************************************************/
/* The size of the MCS header is variable and depends on the length */
/* of the data in the PDU. Calculate the length now. */
/************************************************************************/
headerLength = MCSGetSDRHeaderLength(dataLength);
/************************************************************************/
/* Wind back the data buffer pointer by the size of the MCS header. */
/************************************************************************/
pData -= headerLength;
pHeader = pData;
/************************************************************************/
/* Generate the header - there is so little commonality between SDrq */
/* PDUs that we just fill all the fields in directly - instead of */
/* memcpying a common structure and filling in the case-specific gaps. */
/* */
/* Fill in the first byte. The upper six bits of this byte contain the */
/* PDU type followed by two bits of padding. */
/************************************************************************/
*pHeader = 0x64;
pHeader++;
/************************************************************************/
/* Fill in the user-id. Convert it from our local byte order to the */
/* wire byte order. */
/* Avoid non-aligned access. */
/************************************************************************/
*pHeader++ = (DCUINT8)(MCSLocalUserIDToWireUserID((DCUINT16)userID));
*pHeader++ = (DCUINT8)(MCSLocalUserIDToWireUserID((DCUINT16)userID) >> 8);
/************************************************************************/
/* Fill in the channel-id. Convert it from our local byte order to the */
/* wire byte order. */
/************************************************************************/
*pHeader++ = (DCUINT8)(MCSLocalToWire16((DCUINT16)channel));
*pHeader++ = (DCUINT8)(MCSLocalToWire16((DCUINT16)channel) >> 8);
/************************************************************************/
/* Fill in the data priority and segmentation. The next byte is used */
/* in the following way (with our settings in square brackets on the */
/* far right): */
/* */
/* b7 (MSB) : priority [0] */
/* b6 : priority [1] */
/* b5 : begin segmentation flag [1] */
/* b4 : end segmentation flag [1] */
/* b3 : padding [0] */
/* b2 : padding [0] */
/* b1 : padding [0] */
/* b0 (LSB) : padding [0] */
/* */
/* Our settings can be hard-coded as we only have one priority and */
/* never segment data. */
/************************************************************************/
*pHeader = 0x70;
pHeader++;
/************************************************************************/
/* Now fill in the length of the user-data using packed encoded rules. */
/* These are as follows: */
/* */
/* - if the length is less than 128 bytes then it is encoded using a */
/* single byte. */
/* - if the length is more than 128 bytes but less than 16K then it */
/* encoded using two bytes with the MSB of the first byte set to 1. */
/* */
/* Note that if the length is 16K or more then more complex encoding */
/* rules apply but we do not generate any packets greater than 16K in */
/* length currently. */
/************************************************************************/
if (dataLength < 128)
{
/********************************************************************/
/* The length is less than 128 bytes so just fill in the value */
/* directly. */
/********************************************************************/
*pHeader = (DCUINT8) dataLength;
}
else
{
/********************************************************************/
/* The length is greater than 128 bytes (and less than 16K) so fill */
/* in the length. */
/********************************************************************/
*pHeader = (DCUINT8)(MCSLocalToWire16((DCUINT16)dataLength));
*(pHeader+1) = (DCUINT8)(MCSLocalToWire16((DCUINT16)dataLength) >> 8);
/********************************************************************/
/* We now to set the MSB of the first byte to 1. */
/********************************************************************/
*pHeader |= 0x80;
}
/************************************************************************/
/* Trace out the MCS header. */
/************************************************************************/
TRC_DATA_DBG("MCS SDrq header", pData, headerLength);
/************************************************************************/
/* Now get XT to send the packet for us. */
/************************************************************************/
dataLength += headerLength;
_pXt->XT_SendBuffer(pData, dataLength, (XT_BUFHND) bufHandle);
TRC_DBG((TB, _T("Sent %u bytes of data on channel %#x"),
dataLength,
channel));
DC_END_FN();
return;
} /* MCS_SendPacket */
/**PROC+*********************************************************************/
/* Name: MCS_FreeBuffer */
/* */
/* Purpose: Frees a buffer. */
/* */
/* Returns: Nothing. */
/* */
/* Params: IN bufHandle - MCS buffer handle. */
/* */
/**PROC-*********************************************************************/
DCVOID DCAPI CMCS::MCS_FreeBuffer(MCS_BUFHND bufHandle)
{
DC_BEGIN_FN("MCS_FreeBuffer");
/************************************************************************/
/* Pass this call through to XT to free the buffer. */
/************************************************************************/
_pXt->XT_FreeBuffer((XT_BUFHND) bufHandle);
DC_END_FN();
return;
} /* MCS_FreeBuffer */
/****************************************************************************/
/* */
/* CALLBACKS */
/* */
/****************************************************************************/
/**PROC+*********************************************************************/
/* Name: MCS_OnXTConnected */
/* */
/* Purpose: This function is called by XT when it has successfully */
/* connected. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CMCS::MCS_OnXTConnected(DCVOID)
{
DC_BEGIN_FN("MCS_OnXTConnected");
/************************************************************************/
/* Set up our receive control variable. The initial state is */
/* MCS_RCVST_PDUENCODING so that we can work out what PDU encoding has */
/* been used for the PDU. Also set the number of bytes needed and */
/* reset the count of header bytes read so far. */
/************************************************************************/
_MCS.rcvState = MCS_RCVST_PDUENCODING;
_MCS.hdrBytesNeeded = MCS_NUM_PDUENCODING_BYTES;
_MCS.hdrBytesRead = 0;
/************************************************************************/
/* Set up the data receive control variables. The initial state is */
/* MCS_DATAST_SIZE1 which is used to determine the size of the PDU from */
/* the previously read header information. Also set the number of */
/* bytes needed to zero (the number of bytes needed will be calculated */
/* once the size of the data in the PDU has been determined). Finally */
/* the number of bytes read must be zero. */
/************************************************************************/
_MCS.dataState = MCS_DATAST_SIZE1;
_MCS.dataBytesNeeded = 0;
_MCS.dataBytesRead = 0;
/************************************************************************/
/* Finally decouple to the sender thread and get it to send the MCS */
/* Connect-Initial PDU. */
/************************************************************************/
TRC_NRM((TB, _T("Decouple to snd thrd and send MCS CI PDU")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
this,
CD_NOTIFICATION_FUNC(CMCS, MCSSendConnectInitial),
(ULONG_PTR) 0);
DC_END_FN();
return;
} /* MCS_OnXTConnected */
/**PROC+*********************************************************************/
/* Name: MCS_OnXTDisconnected */
/* */
/* Purpose: This callback function is called by XT when it has */
/* disconnected. */
/* */
/* Returns: Nothing. */
/* */
/* Params: IN reason - reason for the disconnection. */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CMCS::MCS_OnXTDisconnected(DCUINT reason)
{
DC_BEGIN_FN("MCS_OnXTDisconnected");
TRC_ASSERT((reason != 0), (TB, _T("Disconnect reason from XT is 0")));
/************************************************************************/
/* Decide if we want to over-ride the disconnect reason code. */
/************************************************************************/
if (_MCS.disconnectReason != 0)
{
TRC_ALT((TB, _T("Over-riding disconnection reason (%#x->%#x)"),
reason,
_MCS.disconnectReason));
/********************************************************************/
/* Over-ride the error code and set the global variable to 0. */
/********************************************************************/
reason = _MCS.disconnectReason;
_MCS.disconnectReason = 0;
}
/************************************************************************/
/* Call NC to let him know that we've disconnected. */
/************************************************************************/
TRC_NRM((TB, _T("Disconnect reason:%#x"), reason));
_pNc->NC_OnMCSDisconnected(reason);
DC_END_FN();
return;
} /* MCS_OnXTDisconnected */
/**PROC+*********************************************************************/
/* Name: MCS_OnXTDataAvailable */
/* */
/* Purpose: This callback function is called by XT when it has data */
/* available for MCS to process. It returns either when MCS */
/* has finished processing a MCS PDU completely or when XT */
/* runs out of data. */
/* */
/* Returns: TRUE if a MCS frame was processed completely and FALSE if */
/* a MCS frame is still being processed. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCBOOL DCCALLBACK CMCS::MCS_OnXTDataAvailable(DCVOID)
{
DCUINT pduType;
DCUINT lengthBytes;
DCBOOL rc = FALSE;
DC_BEGIN_FN("MCS_OnXTDataAvailable");
/************************************************************************/
/* Loop while there is data available in XT and we have not completed */
/* the processing of one MCS frame. */
/************************************************************************/
while (_pXt->XT_QueryDataAvailable())
{
TRC_DBG((TB, _T("Data available in XT, state:%u"), _MCS.rcvState));
/********************************************************************/
/* Now switch on the receive state. */
/********************************************************************/
switch (_MCS.rcvState)
{
case MCS_RCVST_PDUENCODING:
{
/************************************************************/
/* We're expecting to receive some bytes of PDU encoding. */
/* Try to receive some more data into the header buffer. */
/************************************************************/
if (MCSRecvToHdrBuf())
{
/********************************************************/
/* Successfully received all the encoding bytes that */
/* were required. Now determine if this a BER or PER */
/* encoded PDU. This is done by looking at the first */
/* byte to see if it is equal to the MCS BER connect */
/* PDU prefix. */
/********************************************************/
if (MCS_BER_CONNECT_PREFIX == _MCS.pHdrBuf[0])
{
/****************************************************/
/* This is a BER encoded PDU. Get the next two */
/* bytes. The first of these contains the PDU */
/* type while the second is the first length field. */
/* The length field is a variable length field so */
/* we need to get the first byte to determine the */
/* actual length. */
/****************************************************/
_MCS.rcvState = MCS_RCVST_BERHEADER;
_MCS.hdrBytesNeeded = 2;
TRC_NRM((TB, _T("State PDUENCODING->BERHEADER")));
}
else
{
/****************************************************/
/* This is a PER encoded PDU. Determine the pdu */
/* type and the number of remaining bytes to */
/* receive. */
/****************************************************/
MCSGetPERInfo(&pduType, &_MCS.hdrBytesNeeded);
if (MCS_TYPE_SENDDATAINDICATION == pduType)
{
/************************************************/
/* It's a data PDU so change to the data state. */
/************************************************/
_MCS.rcvState = MCS_RCVST_DATA;
TRC_DBG((TB, _T("State PDUENCODING->DATA")));
}
else
{
/************************************************/
/* It's a control PDU so change to the control */
/* state. */
/************************************************/
_MCS.rcvState = MCS_RCVST_CONTROL;
TRC_NRM((TB, _T("State PDUENCODING->CONTROL")));
}
}
}
}
break;
case MCS_RCVST_BERHEADER:
{
if (MCSRecvToHdrBuf())
{
/********************************************************/
/* We now have a complete BER header so split out the */
/* type. We are expecting this to be a */
/* Connect-Response PDU, so check for this now. */
/********************************************************/
TRC_DATA_NRM("Header buffer contents:",
_MCS.pHdrBuf,
_MCS.hdrBytesRead);
pduType = _MCS.pHdrBuf[1];
if (MCS_TYPE_CONNECTRESPONSE != pduType)
{
/****************************************************/
/* This is not a Connect-Response PDU. Something */
/* bad has happened to cause the other party to */
/* send us this so get out now by disconnecting. */
/****************************************************/
TRC_DATA_ERR("Header buffer contents:",
_MCS.pHdrBuf,
_MCS.hdrBytesRead);
TRC_ABORT((TB, _T("Not a MCS Connect-Response PDU")));
MCSSetReasonAndDisconnect(NL_ERR_MCSNOTCRPDU);
DC_QUIT;
}
/********************************************************/
/* The second byte tells us the length of the length */
/* field itself. For PDUs less than 127 bytes the */
/* length is encoded directly in this field - for */
/* lengths greater than 127 bytes this field has the */
/* high bit set and the other bits contain a count of */
/* the number of remaining bytes in the length field. */
/********************************************************/
lengthBytes = MCSGetBERLengthSize(_MCS.pHdrBuf[2]) - 1;
if (0 == lengthBytes)
{
/****************************************************/
/* The length is less than or equal to 127 bytes so */
/* we don't need to get any additional length */
/* bytes. This means we can switch directly to the */
/* reading data state. */
/****************************************************/
_MCS.rcvState = MCS_RCVST_CONTROL;
_MCS.hdrBytesNeeded = _MCS.pHdrBuf[2];
TRC_NRM((TB, _T("%u bytes needed"), _MCS.hdrBytesNeeded));
TRC_NRM((TB, _T("State BERHEADER->CONTROL")));
}
else
{
TRC_NRM((TB, _T("Length > 127 (%u length bytes remain)"),
lengthBytes));
/****************************************************/
/* We don't expect to get a PDU more than 64Kb in */
/* length - if we do then just disconnect as */
/* something has obviously gone wrong. */
/* */
/* SECURITY: The length coming from within the */
/* packet is bad, but it is capped to 64k. Thus, */
/* this code-path won't ask the client to allocate */
/* an infinite amount of memory. */
/****************************************************/
if (lengthBytes > 2)
{
TRC_ABORT((TB,
_T("Bad MCS Connect-Response length (%u)"),
lengthBytes));
MCSSetReasonAndDisconnect(NL_ERR_MCSBADCRLENGTH);
DC_QUIT;
}
/****************************************************/
/* We now need to read the remaining bytes in this */
/* PDU so set up the new state variables and bytes */
/* required. */
/****************************************************/
_MCS.rcvState = MCS_RCVST_BERLENGTH;
_MCS.hdrBytesNeeded = lengthBytes;
TRC_NRM((TB, _T("State BERHEADER->BERLENGTH")));
}
}
}
break;
case MCS_RCVST_BERLENGTH:
{
if (MCSRecvToHdrBuf())
{
/********************************************************/
/* We now have a complete length field. */
/********************************************************/
TRC_DATA_NRM("Header buffer contents:",
_MCS.pHdrBuf,
_MCS.hdrBytesRead);
/********************************************************/
/* Work out how many length bytes are in this PDU. */
/* */
/* SECURITY: The length coming from within the */
/* packet is bad, but it is capped to 64k. Thus, */
/* this code-path won't ask the client to allocate */
/* an infinite amount of memory. */
/********************************************************/
_MCS.hdrBytesNeeded = MCSGetBERLength(&_MCS.pHdrBuf[2]);
TRC_NRM((TB, _T("%u bytes needed"), _MCS.hdrBytesNeeded));
/********************************************************/
/* Finally set the next state. */
/********************************************************/
_MCS.rcvState = MCS_RCVST_CONTROL;
TRC_NRM((TB, _T("State BERLENGTH->CONTROL")));
}
}
break;
case MCS_RCVST_CONTROL:
{
if (MCSRecvToHdrBuf())
{
/********************************************************/
/* We've now got a complete MCS control packet, so */
/* hand it over to the interpretation function. */
/********************************************************/
MCSHandleControlPkt();
/********************************************************/
/* Reset the state variables, ready for the next */
/* packet. */
/********************************************************/
_MCS.rcvState = MCS_RCVST_PDUENCODING;
_MCS.hdrBytesRead = 0;
_MCS.hdrBytesNeeded = 1;
/********************************************************/
/* Set the return code. MCS will use this to throw */
/* away any additional bytes that might exist in the */
/* XT frame. */
/********************************************************/
rc = TRUE;
TRC_NRM((TB, _T("State CONTROL->PDUENCODING")));
DC_QUIT;
}
}
break;
case MCS_RCVST_DATA:
{
HRESULT hrTemp;
BOOL fFinishedData;
/************************************************************/
/* Call the receive data function. */
/************************************************************/
hrTemp = MCSRecvData(&fFinishedData);
if (fFinishedData || !SUCCEEDED(hrTemp))
{
/********************************************************/
/* We've processed another complete packet for the */
/* layer above, so reset our state variables. */
/********************************************************/
_MCS.rcvState = MCS_RCVST_PDUENCODING;
_MCS.hdrBytesRead = 0;
_MCS.hdrBytesNeeded = MCS_NUM_PDUENCODING_BYTES;
/********************************************************/
/* In a failure case (MCSRecvData failed), we enter */
/* this branch and clean up the MCS state (above). */
/* However, there is still state in XT and TD that */
/* is waiting to be processed for this packet, and */
/* bailing out here and disconnecting WON'T CLEAN THAT */
/* up. That is why we call XT_IgnoreRestofPacket(). */
/*
/* In other cases of disconnecting, such a function */
/* didn't have to be called, but that's because the */
/* disconnect happened after processing the entire */
/* packet; Here, were in the MIDDLE of reading in date */
/* from XT/TD. Without flushing data in XT/TD, the */
/* next connection in this instance of the client would */
/* try to read the rest of this data, which is bogus. */
/********************************************************/
if (!SUCCEEDED(hrTemp))
{
_pXt->XT_IgnoreRestofPacket();
}
/********************************************************/
/* Set the return code. MCS will use this to throw */
/* away any additional bytes that might exist in the */
/* XT frame. Even if we failed above, we still want */
/* to throw away bytes in the XT frame. */
/********************************************************/
rc = TRUE;
TRC_DBG((TB, _T("State DATA->PDUENCODING")));
DC_QUIT;
}
}
break;
default:
{
TRC_ABORT((TB, _T("Unrecognized MCS receive state:%u"),
_MCS.rcvState));
}
break;
}
}
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* MCS_OnXTDataAvailable */
/**PROC+*********************************************************************/
/* Name: MCS_OnXTBufferAvailable */
/* */
/* Purpose: Callback from XT indicating that a back-pressure situation */
/* which caused an earlier XT_GetBuffer call to fail has now */
/* been relieved. Called on the Receiver thread. */
/* */
/* Returns: Nothing. */
/* */
/* Params: None. */
/* */
/**PROC-*********************************************************************/
DCVOID DCCALLBACK CMCS::MCS_OnXTBufferAvailable(DCVOID)
{
DC_BEGIN_FN("MCS_OnXTBufferAvailable");
/************************************************************************/
/* Call the NL callback. */
/************************************************************************/
TRC_NRM((TB, _T("Buffer available")));
_pNc->NC_OnMCSBufferAvailable();
DC_END_FN();
return;
} /* MCS_OnXTBufferAvailable */