windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/t120/mst120/datapkt.cpp

434 lines
12 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_MCSNC);
/*
* datapkt.cpp
*
* Copyright (c) 1997 by Microsoft Corporation, Redmond, WA
*
* Abstract:
* This is the implementation file for the MCS data packet class. The data packet
* class is responsible for encoding and decoding the PDUs, as well as
* maintaining the necessary pointers to the encoded and decoded data.
* However, they differ from normal packets, in that there is only one copy of the
* user data in the encoded and decoded buffers. Only the encoded buffer has the user data,
* while the decoded one maintains a pointer to the data.
* Instances of this class will be created both by User and Connection
* objects as PDUs flow through MCS.
*
* Private Instance Variables:
* ulDataOffset
* Maintains the offset of the starting byte of the user data
* from the start of the encoded buffer.
*
* Caveats:
* None.
*
* Author:
* Christos Tsollis
*/
#include "omcscode.h"
/*
* This is a global variable that has a pointer to the one MCS coder that
* is instantiated by the MCS Controller. Most objects know in advance
* whether they need to use the MCS or the GCC coder, so, they do not need
* this pointer in their constructors.
*/
extern CMCSCoder *g_MCSCoder;
/*
* The following array contains a template for the X.224 data header.
* The 5 of the 7 bytes that it initializes are actually sent to the
* wire. Bytes 3 and 4 will be set to contain the size of the PDU.
* The array is only used when we encode a data PDU.
*/
extern UChar g_X224Header[];
/*
* These are globals that correspond to the static variables declared as part
* of this class.
*/
PVoid * DataPacket::Object_Array;
long DataPacket::Object_Count;
/*
* operator new
*
* Public
*
* Functional Description:
* This is the "new" operator for the DataPacket class.
*
*/
PVoid DataPacket::operator new (size_t)
{
PVoid pNewObject;
TRACE_OUT(("DataPacket::DataPacket: %d pre-allocated data packet objects are left.",
Object_Count));
if (Object_Count > 0) {
pNewObject = Object_Array[--Object_Count];
}
else {
// Allocate an object from the heap
DBG_SAVE_FILE_LINE
pNewObject = (PVoid) new BYTE[sizeof(DataPacket)];
if (pNewObject != NULL)
((PDataPacket) pNewObject)->fPreAlloc = FALSE;
}
return (pNewObject);
}
/*
* operator delete
*
* Public
*
* Functional Description:
* This is the "delete" operator for the Packet class.
*
*/
Void DataPacket::operator delete (PVoid object)
{
if (((PDataPacket) object)->fPreAlloc) {
Object_Array[Object_Count++] = object;
}
else
delete [] ((BYTE *) object);
}
/*
* The AllocateMemoryPool static function pre-allocates DataPacket
* objects for use by MCS.
*/
Void DataPacket::AllocateMemoryPool (long maximum_objects)
{
ULong memory_size;
PUChar object_ptr;
long object_count;
PVoid *pStack;
/*
* Calculate the amount of memory needed to hold the specified number of
* entries. This memory block will contains two different types of
* information:
*
* 1. A stack of available objects (each entry is a PVoid). The "new"
* operator pops the top entry off the stack. The "delete" operator
* pushes one back on.
* 2. The objects themselves, sequentially in memory.
*
* That is why this calculation adds the size of a PVoid to the size of
* an instance of the class, and multiplies by the specified number. This
* allows enough room for both sections.
*/
memory_size = ((sizeof (PVoid) + sizeof (DataPacket)) * maximum_objects);
/*
* Allocate the memory required.
*/
DBG_SAVE_FILE_LINE
Object_Array = (PVoid *) new BYTE[memory_size];
if (Object_Array != NULL)
{
Object_Count = maximum_objects;
/*
* Set a pointer to the first object, which immediately follows the
* stack of available objects.
*/
object_ptr = (PUChar) Object_Array + (sizeof (PVoid) * maximum_objects);
/*
* This loop initializes the stack of available objects to contain all
* objects, in sequential order.
*/
for (pStack = Object_Array, object_count = 0; object_count < maximum_objects;
object_count++)
{
*pStack++ = (PVoid) object_ptr;
((PDataPacket) object_ptr)->fPreAlloc = TRUE; // this object is pre-allocated
object_ptr += sizeof (DataPacket);
}
}
else
{
/*
* The memory allocation failed. Set the static variable indicating
* that there are no objects left. This way, ALL attempted allocations
* will fail.
*/
Object_Count = 0;
}
}
/*
* The FreeMemoryPool static function frees the pre-allocates DataPacket
* objects. It also deletes the critical section
* that controls access to these objects and the memory-tracking
* mechanisms in T.120
*/
Void DataPacket::FreeMemoryPool ()
{
if (Object_Array != NULL)
delete [] ((BYTE *) Object_Array);
};
/*
* DataPacket ()
*
* Public
*
* Functional Description:
* This constructor is used to create an outgoing data packet.
* The packet is created by the user object, when the request
* for a send data or uniform send data comes through the user
* portal.
*/
//outgoing data packets.
DataPacket::DataPacket (ASN1choice_t choice,
PUChar data_ptr,
ULong data_length,
UINT channel_id,
Priority priority,
Segmentation segmentation,
UINT initiator_id,
SendDataFlags flags,
PMemory memory,
PPacketError packet_error)
:
SimplePacket(TRUE),
m_fIncoming (FALSE),
m_Memory (memory),
m_EncodedDataBroken (FALSE),
m_nMessageType(0)
{
*packet_error = PACKET_NO_ERROR;
// Fill in the decoded domain PDU fields.
m_DecodedPDU.choice = choice;
m_DecodedPDU.u.send_data_request.initiator = (UserID) initiator_id;
m_DecodedPDU.u.send_data_request.channel_id = (ChannelID) channel_id;
m_DecodedPDU.u.send_data_request.data_priority = (PDUPriority) priority;
m_DecodedPDU.u.send_data_request.segmentation = (PDUSegmentation) segmentation;
m_DecodedPDU.u.send_data_request.user_data.length = data_length;
m_DecodedPDU.u.send_data_request.user_data.value = (ASN1octet_t *) data_ptr;
/*
* Now, encode the data PDU. Note that no error/allocation should
* occur during the Encode operation.
*/
if (flags == APP_ALLOCATION) {
ASSERT (m_Memory == NULL);
// We will need to memcpy the data
m_EncodedPDU = NULL;
}
else {
// No need for data memcpy!
ASSERT (m_Memory != NULL);
/*
* We need to set the m_EncodedPDU ptr. If this is the 1st packet
* of the data request, the space is already allocated. Otherwise,
* we need to allocate it.
*/
if (segmentation & SEGMENTATION_BEGIN) {
m_EncodedPDU = data_ptr - MAXIMUM_PROTOCOL_OVERHEAD;
}
else {
DBG_SAVE_FILE_LINE
m_EncodedPDU = Allocate (MAXIMUM_PROTOCOL_OVERHEAD);
if (NULL != m_EncodedPDU) {
m_EncodedDataBroken = TRUE;
}
else {
WARNING_OUT (("DataPacket::DataPacket: Failed to allocate MCS encoded headers."));
*packet_error = PACKET_MALLOC_FAILURE;
}
}
/*
* We lock the big buffer that contains the data included in this packet.
*/
LockMemory (m_Memory);
}
if (*packet_error == PACKET_NO_ERROR) {
if (g_MCSCoder->Encode ((LPVOID) &m_DecodedPDU, DOMAIN_MCS_PDU,
PACKED_ENCODING_RULES, &m_EncodedPDU,
&Encoded_Data_Length)) {
if (m_Memory == NULL) {
m_Memory = GetMemoryObjectFromEncData(m_EncodedPDU);
}
}
else {
WARNING_OUT (("DataPacket::DataPacket: Encode failed. Possibly, allocation error."));
*packet_error = PACKET_MALLOC_FAILURE;
}
}
}
/*
* Packet ()
*
* Public
*
* Functional Description:
* This version of the constructor is used to create a DataPacket object
* for incomming PDUs when the packet is to be created from an encoded
* data stream containing the PDU data to be decoded.
*
* Input parameters:
* pTransportData: This structure contains the following fields:
* user_data: Pointer to space containing the real user data + 7 initial
* bytes for X.224 headers.
* user_data_length: Length of the user data including the 7-byte X.224
* header.
* buffer: The beginning of the buffer containing the user_data ptr. These
* 2 ptrs can be different because of security. This is the buffer
* to be freed after we no longer need the data.
* buffer_length: size of "buffer" space. It's only used for accounting
* purposes. RECV_PRIORITY space is limited.
* fPacketDirectionUp: Direction of the data pkt in MCS domain.
*/
// incoming packets
DataPacket::DataPacket(PTransportData pTransportData,
BOOL fPacketDirectionUp)
:
SimplePacket(fPacketDirectionUp),
m_fIncoming (TRUE),
m_Memory (pTransportData->memory),
m_EncodedDataBroken (FALSE),
m_nMessageType(0)
{
m_EncodedPDU = (LPBYTE) pTransportData->user_data;
Encoded_Data_Length = (UINT) pTransportData->user_data_length;
// take care of the X.224 header
memcpy (m_EncodedPDU, g_X224Header, PROTOCOL_OVERHEAD_X224);
AddRFCSize (m_EncodedPDU, Encoded_Data_Length);
// Now, we can decode the PDU
g_MCSCoder->Decode (m_EncodedPDU + PROTOCOL_OVERHEAD_X224,
Encoded_Data_Length - PROTOCOL_OVERHEAD_X224,
DOMAIN_MCS_PDU, PACKED_ENCODING_RULES,
(LPVOID *) &m_DecodedPDU, NULL);
TRACE_OUT (("DataPacket::DataPacket: incoming data PDU packet was created successfully. Encoded size: %d",
Encoded_Data_Length - PROTOCOL_OVERHEAD_X224));
}
/*
* ~DataPacket ()
*
* Public
*
* Functional Description:
* Destructor for the DataPacket class. The destructor ensures that all
* resources that have been allocated are freed.
*/
DataPacket::~DataPacket(void)
{
if (m_EncodedPDU != NULL) {
UnlockMemory (m_Memory);
if (m_EncodedDataBroken) {
// Free the MCS and X.224 header buffer.
Free (m_EncodedPDU);
}
}
}
/*
* Equivalent ()
*
* Public
*
* Functional Description:
* This function returns TRUE if the 2 packets belong to the same
* original SendData request (normal or uniform), and FALSE, otherwise.
*/
BOOL DataPacket::Equivalent (PDataPacket packet)
{
ASSERT (m_DecodedPDU.u.send_data_request.segmentation == SEGMENTATION_END);
ASSERT ((packet->m_DecodedPDU.u.send_data_request.segmentation & SEGMENTATION_END) == 0);
return ((m_DecodedPDU.u.send_data_request.initiator == packet->m_DecodedPDU.u.send_data_request.initiator) &&
(m_DecodedPDU.u.send_data_request.channel_id == packet->m_DecodedPDU.u.send_data_request.channel_id) &&
(m_DecodedPDU.u.send_data_request.data_priority == packet->m_DecodedPDU.u.send_data_request.data_priority) &&
(m_DecodedPDU.choice == packet->m_DecodedPDU.choice));
}
/*
* IsDataPacket ()
*
* Public
*
* Functional Description:
* This function returns whether this is a data packet (it is).
*/
BOOL DataPacket::IsDataPacket(void)
{
return (TRUE);
}
/*
* SetDirection ()
*
* Public
*
* Functional Description:
* If the DataPacket object is oriented differently than desired
* by the caller of this method, then the packet coder is called to
* reverse the direction of the PDU.
*/
Void DataPacket::SetDirection (DBBoolean packet_direction_up)
{
/*
* If the packet's encoded data is oriented differently from the desired
* direction, call the packet coder's ReverseDirection method and
* reverse the packet's direction indicator.
*/
if (packet_direction_up != Packet_Direction_Up)
{
/*
* Reverse the direction of the PDU.
*/
g_MCSCoder->ReverseDirection (m_EncodedPDU);
/*
* The packet coder has reversed the direction of the PDU. Set
* the Packet_Direction_Up flag to indicate the new state.
*/
Packet_Direction_Up = packet_direction_up;
}
}
/*
* GetDecodedData ()
*
* Public
*
* Functional Description:
* The GetDecodedData method returns a pointer to the decoded data
* buffer. If the packet does not have decoded data the Decode method is
* called.
*/
PVoid DataPacket::GetDecodedData ()
{
return ((PVoid) &m_DecodedPDU);
}
/*
* GetPDUType ()
*
* Public
*
* Functional Description:
* The GetPDUType method returns the PDU type for the data packet.
* For such a packet, the value is always
*/
int DataPacket::GetPDUType ()
{
return (DOMAIN_MCS_PDU);
}