355 lines
10 KiB
C++
355 lines
10 KiB
C++
|
#include "precomp.h"
|
||
|
DEBUG_FILEZONE(ZONE_T120_GCCNC);
|
||
|
/*
|
||
|
* ogcccode.cpp
|
||
|
*
|
||
|
* Copyright (c) 1994 by DataBeam Corporation, Lexington, KY
|
||
|
*
|
||
|
* Abstract:
|
||
|
* This is the implementation file for the CGCCCoder class. This class
|
||
|
* is responsible for encoding and decoding GCC (T.124) PDU's using ASN.1
|
||
|
* encoding rules via the ASN.1 toolkit. This class is also capable
|
||
|
* of determining the size of both the encoded and decoded PDU's.
|
||
|
*
|
||
|
* Static Variables:
|
||
|
*
|
||
|
* Caveats:
|
||
|
* Only one instance of this class should be in existance at any one time
|
||
|
* due to the static variable.
|
||
|
*
|
||
|
* Author:
|
||
|
* John B. O'Nan
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* External Interfaces
|
||
|
*/
|
||
|
#include <string.h>
|
||
|
#include "ogcccode.h"
|
||
|
|
||
|
/*
|
||
|
* This is a global variable that has a pointer to the one GCC coder that
|
||
|
* is instantiated by the GCC 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.
|
||
|
*/
|
||
|
CGCCCoder *g_GCCCoder;
|
||
|
|
||
|
/*
|
||
|
* CGCCCoder ()
|
||
|
*
|
||
|
* Public
|
||
|
*
|
||
|
* Functional Description:
|
||
|
* This is the constructor for the CGCCCoder class. It initializes
|
||
|
* the ASN.1 encoder/decoder and sets the encoding rules to the
|
||
|
* Packed-Aligned variant.
|
||
|
*/
|
||
|
CGCCCoder::CGCCCoder ()
|
||
|
:m_pEncInfo(NULL),
|
||
|
m_pDecInfo(NULL)
|
||
|
{
|
||
|
// lonchanc: We should move Init out of constructor. However,
|
||
|
// to minimize the changes in the GCC/MCS code, we put it here for now.
|
||
|
// Otherwise, we need to change MCS and Packet interfaces.
|
||
|
// We will move it out and call Init() separately.
|
||
|
Init();
|
||
|
}
|
||
|
|
||
|
BOOL CGCCCoder::Init ( void )
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
GCCPDU_Module_Startup();
|
||
|
if (GCCPDU_Module != NULL)
|
||
|
{
|
||
|
if (ASN1_CreateEncoder(
|
||
|
GCCPDU_Module, // ptr to mdule
|
||
|
&m_pEncInfo, // ptr to encoder info
|
||
|
NULL, // buffer ptr
|
||
|
0, // buffer size
|
||
|
NULL) // parent ptr
|
||
|
== ASN1_SUCCESS)
|
||
|
{
|
||
|
ASSERT(m_pEncInfo != NULL);
|
||
|
fRet = (ASN1_CreateDecoder(
|
||
|
GCCPDU_Module, // ptr to mdule
|
||
|
&m_pDecInfo, // ptr to decoder info
|
||
|
NULL, // buffer ptr
|
||
|
0, // buffer size
|
||
|
NULL) // parent ptr
|
||
|
== ASN1_SUCCESS);
|
||
|
ASSERT(fRet && m_pDecInfo != NULL);
|
||
|
}
|
||
|
}
|
||
|
ASSERT(fRet);
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ~CGCCCoder ()
|
||
|
*
|
||
|
* Public Functional Description:
|
||
|
* This is a virtual destructor. It is used to clean up after ASN.1.
|
||
|
*/
|
||
|
CGCCCoder::~CGCCCoder ()
|
||
|
{
|
||
|
if (GCCPDU_Module != NULL)
|
||
|
{
|
||
|
ASN1_CloseEncoder(m_pEncInfo);
|
||
|
ASN1_CloseDecoder(m_pDecInfo);
|
||
|
GCCPDU_Module_Cleanup();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Encode ()
|
||
|
*
|
||
|
* Public Functional Description:
|
||
|
* This function encodes GCC Protocol Data Units (PDU's) into ASN.1
|
||
|
* compliant byte streams using the ASN.1 toolkit.
|
||
|
* The coder allocates the buffer space for the encoded data.
|
||
|
*/
|
||
|
BOOL CGCCCoder::Encode(LPVOID pdu_structure,
|
||
|
int pdu_type,
|
||
|
UINT nEncodingRule_not_used,
|
||
|
LPBYTE *encoding_buffer,
|
||
|
UINT *encoding_buffer_length)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
int return_value;
|
||
|
ConnectData connect_data_structure;
|
||
|
|
||
|
// clean up local buffer pointer
|
||
|
connect_data_structure.connect_pdu.value = NULL;
|
||
|
|
||
|
/*
|
||
|
* If the PDU to be encoded is a "ConnectGCC" PDU we must first encode the
|
||
|
* "ConnectGCC" PDU. A "ConnectData" PDU structure is then built which
|
||
|
* contains the encoded "ConnectGCC" PDU along with object identifier key.
|
||
|
* The "ConnectData" PDU is then encoded into the provided buffer.
|
||
|
*/
|
||
|
if (pdu_type == CONNECT_GCC_PDU)
|
||
|
{
|
||
|
return_value = ASN1_Encode(m_pEncInfo, // ptr to encoder info
|
||
|
pdu_structure, // pdu data structure
|
||
|
pdu_type, // pdu id
|
||
|
ASN1ENCODE_ALLOCATEBUFFER, // flags
|
||
|
NULL, // do not provide buffer
|
||
|
0); // buffer size if provided
|
||
|
if (ASN1_FAILED(return_value))
|
||
|
{
|
||
|
ERROR_OUT(("CGCCCoder::Encode: ASN1_Encode failed, err=%d in CONNECT_GCC_PDU.",
|
||
|
return_value));
|
||
|
ASSERT(FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
ASSERT(return_value == ASN1_SUCCESS);
|
||
|
/*
|
||
|
* Fill in the "ConnectData" PDU structure and encode it.
|
||
|
*/
|
||
|
connect_data_structure.t124_identifier = t124identifier;
|
||
|
|
||
|
connect_data_structure.connect_pdu.length = m_pEncInfo->len; // len of encoded data in buffer
|
||
|
connect_data_structure.connect_pdu.value = m_pEncInfo->buf; // buffer to encode into
|
||
|
|
||
|
// Prepare for the encode call
|
||
|
pdu_structure = (LPVOID) &connect_data_structure;
|
||
|
pdu_type = CONNECT_DATA_PDU;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Encode the Non-Connect PDU into the buffer provided.
|
||
|
*/
|
||
|
return_value = ASN1_Encode(m_pEncInfo, // ptr to encoder info
|
||
|
pdu_structure, // pdu data structure
|
||
|
pdu_type, // pdu id
|
||
|
ASN1ENCODE_ALLOCATEBUFFER, // flags
|
||
|
NULL, // do not provide buffer
|
||
|
0); // buffer size if provided
|
||
|
if (ASN1_FAILED(return_value))
|
||
|
{
|
||
|
ERROR_OUT(("CGCCCoder::Encode: ASN1_Encode failed, err=%d", return_value));
|
||
|
ASSERT(FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
ASSERT(return_value == ASN1_SUCCESS);
|
||
|
*encoding_buffer_length = m_pEncInfo->len; // len of encoded data in buffer
|
||
|
*encoding_buffer = m_pEncInfo->buf; // buffer to encode into
|
||
|
fRet = TRUE;
|
||
|
|
||
|
MyExit:
|
||
|
|
||
|
/*
|
||
|
* If this was a CONNECT_DATA_PDU we need to free the buffer that
|
||
|
* was allocated by ASN.1.
|
||
|
*/
|
||
|
if (CONNECT_DATA_PDU == pdu_type && connect_data_structure.connect_pdu.value != NULL)
|
||
|
{
|
||
|
ASN1_FreeEncoded(m_pEncInfo, connect_data_structure.connect_pdu.value);
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Decode ()
|
||
|
*
|
||
|
* Public Functional Description:
|
||
|
* This function decodes ASN.1 compliant byte streams into the
|
||
|
* appropriate GCC PDU structures using the ASN.1 toolkit.
|
||
|
*/
|
||
|
BOOL CGCCCoder::Decode(LPBYTE encoded_buffer,
|
||
|
UINT encoded_buffer_length,
|
||
|
int pdu_type,
|
||
|
UINT nEncodingRule_not_used,
|
||
|
LPVOID *pdecoding_buffer,
|
||
|
UINT *pdecoding_buffer_length)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
int return_value;
|
||
|
LPVOID connect_data_decoding_buffer = NULL;
|
||
|
ASN1optionparam_s OptParam;
|
||
|
|
||
|
/*
|
||
|
* If the PDU is a "ConnectGCC" PDU then after it is decoded we must decode
|
||
|
* the "ConnectGCC" PDU which is actually contained within a "ConnectData"
|
||
|
* PDU.
|
||
|
*/
|
||
|
if (pdu_type == CONNECT_GCC_PDU)
|
||
|
{
|
||
|
return_value = ASN1_Decode(m_pDecInfo, // ptr to decoder info
|
||
|
&connect_data_decoding_buffer, // destination buffer
|
||
|
CONNECT_DATA_PDU, // pdu type
|
||
|
ASN1DECODE_SETBUFFER, // flags
|
||
|
encoded_buffer, // source buffer
|
||
|
encoded_buffer_length); // source buffer size
|
||
|
if (ASN1_FAILED(return_value))
|
||
|
{
|
||
|
ERROR_OUT(("CGCCCoder::Decode: ASN1_Decode failed, err=%d", return_value));
|
||
|
ASSERT(FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
ASSERT(return_value == ASN1_SUCCESS);
|
||
|
|
||
|
/*
|
||
|
* If the decoded PDU is a "ConnectData" PDU, then we first must check
|
||
|
* to make sure this PDU originated from a T.124-compliant source.
|
||
|
* If so we then decode the "ConnectGCC" PDU which is held in the
|
||
|
* "connect_pdu" field. If the PDU is not T.124-compliant, we will
|
||
|
* report an error which will cause the PDU to be rejected.
|
||
|
*/
|
||
|
if (IsObjectIDCompliant(&(((PConnectData) connect_data_decoding_buffer)->t124_identifier))
|
||
|
== FALSE)
|
||
|
{
|
||
|
ERROR_OUT(("CGCCCoder::Decode: Non-T.124 objectID"));
|
||
|
ASSERT (FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
ASSERT(connect_data_decoding_buffer != NULL);
|
||
|
encoded_buffer = (PUChar)((PConnectData) connect_data_decoding_buffer)->
|
||
|
connect_pdu.value;
|
||
|
encoded_buffer_length = (UINT)((PConnectData) connect_data_decoding_buffer)->
|
||
|
connect_pdu.length;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Decode the Non-Connect PDU into the buffer provided.
|
||
|
*/
|
||
|
return_value = ASN1_Decode(m_pDecInfo, // ptr to decoder info
|
||
|
pdecoding_buffer, // destination buffer
|
||
|
pdu_type, // pdu type
|
||
|
ASN1DECODE_SETBUFFER, // flags
|
||
|
encoded_buffer, // source buffer
|
||
|
encoded_buffer_length); // source buffer size
|
||
|
if (ASN1_FAILED(return_value))
|
||
|
{
|
||
|
ERROR_OUT(("CCCCoder::Decode: ASN1_Decode failed, err=%d", return_value));
|
||
|
ASSERT(FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
ASSERT(return_value == ASN1_SUCCESS);
|
||
|
|
||
|
OptParam.eOption = ASN1OPT_GET_DECODED_BUFFER_SIZE;
|
||
|
return_value = ASN1_GetDecoderOption(m_pDecInfo, &OptParam);
|
||
|
if (ASN1_FAILED(return_value))
|
||
|
{
|
||
|
ERROR_OUT(("CGCCCoder::Decode: ASN1_GetDecoderOption failed, err=%d", return_value));
|
||
|
ASSERT(FALSE);
|
||
|
goto MyExit;
|
||
|
}
|
||
|
*pdecoding_buffer_length = OptParam.cbRequiredDecodedBufSize;
|
||
|
|
||
|
ASSERT(return_value == ASN1_SUCCESS);
|
||
|
ASSERT(*pdecoding_buffer_length > 0);
|
||
|
|
||
|
fRet = TRUE;
|
||
|
|
||
|
MyExit:
|
||
|
|
||
|
/*
|
||
|
* Free the PDU structure allocated by decoder for the Connect-Data PDU.
|
||
|
*/
|
||
|
if (connect_data_decoding_buffer != NULL)
|
||
|
{
|
||
|
ASSERT (pdu_type == CONNECT_GCC_PDU);
|
||
|
ASN1_FreeDecoded(m_pDecInfo, connect_data_decoding_buffer, CONNECT_DATA_PDU);
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* IsObjectIDCompliant ()
|
||
|
*
|
||
|
* Private Functional Description:
|
||
|
* This function is used to verify that the object identifier contained
|
||
|
* in a "Connect" PDU is compliant with this version of GCC.
|
||
|
*/
|
||
|
BOOL CGCCCoder::IsObjectIDCompliant (PKey t124_identifier)
|
||
|
{
|
||
|
BOOL return_value = TRUE;
|
||
|
PSetOfObjectID test_object_id_set;
|
||
|
PSetOfObjectID valid_object_id_set;
|
||
|
|
||
|
/*
|
||
|
* First check to make sure that the identifier is a standard Object
|
||
|
* Identifier type.
|
||
|
*/
|
||
|
if (t124_identifier->choice == OBJECT_CHOSEN)
|
||
|
{
|
||
|
/*
|
||
|
* Retrieve the object identifier to test and the valid T.124
|
||
|
* identifier ("t124identifier) to use as a comparison.
|
||
|
*/
|
||
|
test_object_id_set = t124_identifier->u.object;
|
||
|
valid_object_id_set = t124identifier.u.object;
|
||
|
|
||
|
while ((valid_object_id_set != NULL) && (test_object_id_set != NULL))
|
||
|
{
|
||
|
if (test_object_id_set->value != valid_object_id_set->value)
|
||
|
{
|
||
|
return_value = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
test_object_id_set = test_object_id_set->next;
|
||
|
valid_object_id_set = valid_object_id_set->next;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return_value = FALSE;
|
||
|
|
||
|
return (return_value);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CGCCCoder::FreeEncoded (PUChar encoded_buffer)
|
||
|
{
|
||
|
ASN1_FreeEncoded(m_pEncInfo, encoded_buffer);
|
||
|
}
|
||
|
|
||
|
void CGCCCoder::FreeDecoded (int pdu_type, LPVOID decoded_buffer)
|
||
|
{
|
||
|
ASN1_FreeDecoded(m_pDecInfo, decoded_buffer, pdu_type);
|
||
|
}
|