mirror of https://github.com/tongzx/nt5src
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.
847 lines
19 KiB
847 lines
19 KiB
#include "stdafx.h"
|
|
#include "dynarray.h"
|
|
#include "q931msg.h"
|
|
#include "h323asn1.h"
|
|
|
|
struct Q931_ENCODE_CONTEXT
|
|
{
|
|
LPBYTE Pos; // next storage position, MAY EXCEED End!
|
|
LPBYTE End; // end of storage buffer
|
|
|
|
// if returns FALSE, then buffer is in overflow condition
|
|
BOOL StoreData (
|
|
IN LPBYTE Data,
|
|
IN DWORD Length);
|
|
|
|
BOOL HasOverflowed (void) { return Pos > End; }
|
|
|
|
// if returns FALSE, then buffer is in overflow condition, or would be
|
|
BOOL AllocData (
|
|
IN DWORD Length,
|
|
OUT LPBYTE * ReturnData);
|
|
};
|
|
|
|
BOOL Q931_ENCODE_CONTEXT::StoreData (
|
|
IN LPBYTE Data,
|
|
IN DWORD Length)
|
|
{
|
|
if (Pos + Length > End) {
|
|
Pos += Length;
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy (Pos, Data, Length);
|
|
Pos += Length;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Q931_ENCODE_CONTEXT::AllocData (
|
|
IN DWORD Length,
|
|
OUT LPBYTE * ReturnData)
|
|
{
|
|
if (Pos + Length > End) {
|
|
Pos += Length;
|
|
*ReturnData = NULL;
|
|
return FALSE;
|
|
}
|
|
else {
|
|
*ReturnData = Pos;
|
|
Pos += Length;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
|
|
void Q931TestDecoder (
|
|
IN LPBYTE PduData,
|
|
IN DWORD PduLength)
|
|
{
|
|
Q931_MESSAGE Message;
|
|
HRESULT Result;
|
|
|
|
Q931_MESSAGE NewMessage;
|
|
BYTE NewData [0x400];
|
|
DWORD NewLength;
|
|
|
|
Debug (_T("Q931TestDecoder --------------------------------------------------------------------\n"));
|
|
DebugF (_T("- processing Q.931 PDU, length %d, contents:\n"), PduLength);
|
|
DumpMemory (PduData, PduLength);
|
|
|
|
|
|
Result = Message.AttachDecodePdu (PduData, PduLength, FALSE);
|
|
|
|
if (Result != S_OK) {
|
|
DebugError (Result, _T("- failed to decode Q.931 PDU\n"));
|
|
return;
|
|
}
|
|
|
|
Debug (_T("- successfully decoded Q.931 PDU\n"));
|
|
|
|
// now, try to re-encode the same PDU
|
|
|
|
if (Message.MessageType == Q931_MESSAGE_TYPE_SETUP) {
|
|
// there is an issue with decoding and re-encoding ASN.1 UUIE for Setup from TAPI
|
|
// long, boring story
|
|
|
|
Debug (_T("- it's a Setup PDU, will not attempt to re-encode (due to ASN.1 compatability issue)\n"));
|
|
}
|
|
else {
|
|
Debug (_T("- will now attempt to re-encode\n"));
|
|
|
|
NewLength = 0x400;
|
|
Result = Message.EncodePdu (NewData, &NewLength);
|
|
|
|
if (Result == S_OK) {
|
|
DebugF (_T("- successfully re-encoded copy of Q.931 PDU, length %d, contents:\n"), NewLength);
|
|
|
|
|
|
if (PduLength != NewLength) {
|
|
DebugF (_T("- *** warning: original pdu length (%d) is different from re-encoded pdu length (%d), re-encoded contents:\n"),
|
|
PduLength, NewLength);
|
|
DumpMemory (NewData, NewLength);
|
|
}
|
|
else {
|
|
if (memcmp (PduData, NewData, NewLength) != 0) {
|
|
DebugF (_T("- *** warning: original pdu contents differ from re-encoded pdu contents, which follow:\n"));
|
|
DumpMemory (NewData, NewLength);
|
|
}
|
|
else {
|
|
DebugF (_T("- re-encoded pdu is identical to original pdu -- success!\n"));
|
|
}
|
|
}
|
|
|
|
Debug (_T("- will now attempt to decode re-encoded PDU\n"));
|
|
|
|
Result = NewMessage.AttachDecodePdu (NewData, NewLength, FALSE);
|
|
|
|
if (Result == S_OK) {
|
|
Debug (_T("- successfully decoded copy of Q.931 PDU\n"));
|
|
}
|
|
else {
|
|
DebugError (Result, _T("- failed to decode copy of Q.931 PDU\n"));
|
|
}
|
|
}
|
|
else {
|
|
DebugError (Result, _T("- failed to re-encode Q.931 PDU\n"));
|
|
}
|
|
}
|
|
|
|
Message.Detach();
|
|
NewMessage.Detach();
|
|
|
|
Debug (_T("\n"));
|
|
}
|
|
|
|
#endif
|
|
|
|
// Q931_MESSAGE -----------------------------------------------------------------------------
|
|
|
|
Q931_MESSAGE::Q931_MESSAGE (void)
|
|
{
|
|
Buffer = NULL;
|
|
BufferLength = 0;
|
|
}
|
|
|
|
Q931_MESSAGE::~Q931_MESSAGE (void)
|
|
{
|
|
Detach();
|
|
|
|
assert (!InfoElementArray.m_Length);
|
|
assert (!Buffer);
|
|
}
|
|
|
|
void Q931_MESSAGE::Detach (void)
|
|
{
|
|
FreeInfoElementArray();
|
|
|
|
if (Buffer) {
|
|
if (BufferIsOwner) {
|
|
LocalFree (Buffer);
|
|
}
|
|
|
|
Buffer = NULL;
|
|
BufferLength = 0;
|
|
BufferIsOwner = FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::Detach (
|
|
OUT LPBYTE * ReturnBuffer,
|
|
OUT DWORD * ReturnBufferLength)
|
|
{
|
|
HRESULT Result;
|
|
|
|
assert (ReturnBuffer);
|
|
assert (ReturnBufferLength);
|
|
|
|
if (Buffer) {
|
|
*ReturnBuffer = Buffer;
|
|
*ReturnBufferLength = BufferLength;
|
|
|
|
Result = S_OK;
|
|
}
|
|
else {
|
|
Result = S_FALSE;
|
|
}
|
|
|
|
Detach();
|
|
|
|
return Result;
|
|
}
|
|
|
|
void Q931_MESSAGE::FreeInfoElementArray (void)
|
|
{
|
|
Q931_IE * Pos;
|
|
Q931_IE * End;
|
|
|
|
InfoElementArray.GetExtents (&Pos, &End);
|
|
|
|
for (; Pos < End; Pos++) {
|
|
FreeInfoElement (Pos);
|
|
}
|
|
|
|
InfoElementArray.Clear();
|
|
}
|
|
|
|
void Q931_MESSAGE::FreeInfoElement (Q931_IE * InfoElement)
|
|
{
|
|
assert (InfoElement);
|
|
|
|
switch (InfoElement -> Identifier) {
|
|
case Q931_IE_USER_TO_USER:
|
|
|
|
assert (InfoElement -> Data.UserToUser.PduStructure);
|
|
|
|
if (InfoElement -> Data.UserToUser.IsOwner) {
|
|
|
|
H225FreePdu_H323_UserInformation (
|
|
InfoElement -> Data.UserToUser.PduStructure);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::DecodeInfoElement (
|
|
IN OUT LPBYTE * ArgPos,
|
|
IN LPBYTE End,
|
|
OUT Q931_IE * ReturnInfoElement)
|
|
{
|
|
LPBYTE Pos;
|
|
BYTE Identifier;
|
|
DWORD LengthLength; // length of the IE length element, in bytes!
|
|
LPBYTE VariableData; // payload of variable-length data
|
|
DWORD VariableDataLength;
|
|
BYTE FixedData; // payload of fixed-length data
|
|
HRESULT Result;
|
|
|
|
|
|
assert (ArgPos);
|
|
assert (End);
|
|
|
|
Pos = *ArgPos;
|
|
|
|
if (Pos >= End) {
|
|
Debug (_T("Q931_MESSAGE::DecodeInfoElement: should never have been called\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Identifier = *Pos;
|
|
Pos++;
|
|
|
|
// is it a single-byte IE?
|
|
// if so, then bit 7 of the first byte = 1
|
|
|
|
if (Identifier & 0x80) {
|
|
|
|
// there are two types of single-byte IEs
|
|
// Type 1 has a four-bit identifier and a four-bit value
|
|
// Type 2 has only an identifier, and no value
|
|
|
|
switch (Identifier & 0xF0) {
|
|
case Q931_IE_MORE_DATA:
|
|
case Q931_IE_SENDING_COMPLETE:
|
|
// these IEs have an identifier, but no value
|
|
|
|
ReturnInfoElement -> Identifier = (Q931_IE_IDENTIFIER) Identifier;
|
|
|
|
DebugF (_T("Q931_MESSAGE::DecodeInfoElement: fixed-length IE, id %02XH, no value\n"),
|
|
Identifier);
|
|
|
|
break;
|
|
|
|
default:
|
|
// the other single-byte IEs have a value in the lower four bits
|
|
ReturnInfoElement -> Identifier = (Q931_IE_IDENTIFIER) (Identifier & 0xF0);
|
|
ReturnInfoElement -> Data.UnknownFixed.Value = Identifier & 0x0F;
|
|
|
|
DebugF (_T("Q931_MESSAGE::DecodeInfoElement: fixed-length IE, id %02XH value %01XH\n"),
|
|
ReturnInfoElement -> Identifier,
|
|
ReturnInfoElement -> Data.UnknownFixed.Value);
|
|
|
|
break;
|
|
}
|
|
|
|
// we don't currently parse any fixed-length IEs
|
|
|
|
Result = S_OK;
|
|
}
|
|
else {
|
|
// the next byte indicates the length of the info element
|
|
|
|
// unfortunately, the number of octets that make up the length
|
|
// depends on the identifier.
|
|
// -XXX- is this because I don't understand the octet extension mechanism?
|
|
|
|
ReturnInfoElement -> Identifier = (Q931_IE_IDENTIFIER) Identifier;
|
|
|
|
switch (Identifier) {
|
|
case Q931_IE_USER_TO_USER:
|
|
LengthLength = 2;
|
|
break;
|
|
|
|
default:
|
|
LengthLength = 1;
|
|
break;
|
|
}
|
|
|
|
if (Pos + LengthLength > End) {
|
|
Debug (_T("Q931_MESSAGE::DecodeInfoElement: insufficient data for header of variable-length IE\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (LengthLength == 1) {
|
|
VariableDataLength = *Pos;
|
|
}
|
|
else {
|
|
VariableDataLength = Pos [1] + (((WORD) Pos [0]) << 8);
|
|
}
|
|
Pos += LengthLength;
|
|
|
|
if (Pos + VariableDataLength > End) {
|
|
Debug (_T("Q931_MESSAGE::DecodeInfoElement: insufficient data for body of variable-length IE\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
VariableData = (LPBYTE) Pos;
|
|
Pos += VariableDataLength;
|
|
|
|
// DebugF (_T("Q931_MESSAGE::DecodeInfoElement: variable-length IE, id %02XH length %d\n"),
|
|
// Identifier, VariableDataLength);
|
|
|
|
ReturnInfoElement -> Data.UnknownVariable.Data = VariableData;
|
|
ReturnInfoElement -> Data.UnknownVariable.Length = VariableDataLength;
|
|
|
|
Result = ParseIE (ReturnInfoElement);
|
|
|
|
if (Result != S_OK) {
|
|
DebugError (Result, _T("Q931_MESSAGE::DecodeInfoElement: IE was located, but failed to parse\n"));
|
|
}
|
|
}
|
|
|
|
*ArgPos = Pos;
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::AppendInfoElement (
|
|
IN Q931_IE * InfoElement)
|
|
{
|
|
Q931_IE * ArrayEntry;
|
|
|
|
ArrayEntry = InfoElementArray.AllocAtEnd();
|
|
|
|
if (ArrayEntry) {
|
|
*ArrayEntry = *InfoElement;
|
|
|
|
return S_OK;
|
|
}
|
|
else {
|
|
Debug (_T("Q931_MESSAGE::AppendInfoElement: allocation failure\n"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::ParseIE_UUIE (
|
|
IN Q931_IE * InfoElement)
|
|
{
|
|
LPBYTE Data;
|
|
DWORD Length;
|
|
DWORD Status;
|
|
|
|
// be careful to copy out all parameters from one branch of the union
|
|
// before you start stomping on another branch
|
|
Data = InfoElement -> Data.UnknownVariable.Data;
|
|
Length = InfoElement -> Data.UnknownVariable.Length;
|
|
|
|
if (Length < 1) {
|
|
Debug (_T("Q931_MESSAGE::ParseIE_UUIE: IE payload is too short to contain UUIE\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
InfoElement -> Data.UserToUser.Type = (Q931_UUIE_TYPE) *Data++;
|
|
Length--;
|
|
|
|
InfoElement -> Data.UserToUser.PduStructure = NULL;
|
|
|
|
Status = H225DecodePdu_H323_UserInformation (Data, Length,
|
|
&InfoElement -> Data.UserToUser.PduStructure);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
if (InfoElement -> Data.UserToUser.PduStructure) {
|
|
// return value was a warning, not error
|
|
|
|
H225FreePdu_H323_UserInformation (InfoElement -> Data.UserToUser.PduStructure);
|
|
|
|
InfoElement -> Data.UserToUser.PduStructure = NULL;
|
|
}
|
|
|
|
|
|
InfoElement -> Data.UserToUser.PduStructure = NULL;
|
|
DebugError (Status, _T("Q931_MESSAGE::ParseIE_UUIE: failed to decode UUIE / ASN.1\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
InfoElement -> Data.UserToUser.IsOwner = TRUE;
|
|
|
|
// Debug (_T("Q931_MESSAGE::ParseIE_UUIE: successfully decoded UUIE\n"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::ParseIE (
|
|
IN Q931_IE * InfoElement)
|
|
{
|
|
assert (InfoElement);
|
|
|
|
switch (InfoElement -> Identifier) {
|
|
|
|
case Q931_IE_USER_TO_USER:
|
|
return ParseIE_UUIE (InfoElement);
|
|
break;
|
|
|
|
case Q931_IE_CAUSE:
|
|
// Debug (_T("Q931_MESSAGE::ParseInfoElement: Q931_IE_CAUSE\n"));
|
|
break;
|
|
|
|
case Q931_IE_DISPLAY:
|
|
// Debug (_T("Q931_MESSAGE::ParseInfoElement: Q931_IE_DISPAY\n"));
|
|
break;
|
|
|
|
case Q931_IE_BEARER_CAPABILITY:
|
|
// Debug (_T("Q931_MESSAGE::ParseInfoElement: Q931_IE_BEARER_CAPABILITY\n"));
|
|
break;
|
|
|
|
default:
|
|
DebugF (_T("Q931_MESSAGE::ParseInfoElement: unknown IE identifier (%02XH), no interpretation will be imposed\n"),
|
|
InfoElement -> Identifier);
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::AttachDecodePdu (
|
|
IN LPBYTE Data,
|
|
IN DWORD Length,
|
|
IN BOOL IsDataOwner)
|
|
{
|
|
LPBYTE Pos;
|
|
LPBYTE End;
|
|
HRESULT Result;
|
|
|
|
Q931_IE * ArrayEntry;
|
|
|
|
assert (Data);
|
|
|
|
Detach();
|
|
|
|
if (Length < 5) {
|
|
DebugF (_T("Q931_MESSAGE::Decode: header is too short (%d)\n"), Length);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// octet 0 is the Protocol Discriminator
|
|
|
|
if (Data [0] != Q931_PROTOCOL_DISCRIMINATOR) {
|
|
DebugF (_T("Q931_MESSAGE::Decode: the pdu is not a Q.931 pdu, protocol discriminator = %02XH\n"),
|
|
Data [0]);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// octet 1: bits 0-3 contain the length, in octets of the Call Reference Value
|
|
// octet 1: bits 4-7 should be zero
|
|
|
|
if (Data [1] & 0xF0) {
|
|
DebugF (_T("Q931_MESSAGE::Decode: the pdu has non-zero bits in octet 1: %02XH\n"),
|
|
Data [1]);
|
|
}
|
|
|
|
// according to H.225, the Call Reference Value must be two octets in length
|
|
|
|
if ((Data [1] & 0x0F) != 2) {
|
|
DebugF (_T("Q931_MESSAGE::Decode: the call reference value size is invalid (%d), should be 2\n"),
|
|
Data [1] & 0x0F);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// since the Call Reference Value size is 2 octets, octets 2 and 3 are the CRV
|
|
// octets are in network (big-endian) order.
|
|
|
|
CallReferenceValue = (((WORD) Data [2]) << 8) | Data [3];
|
|
|
|
// DebugF (_T("Q931_MESSAGE::Decode: crv %04XH\n"), CallReferenceValue);
|
|
|
|
// Message Type is at octet offset 4
|
|
|
|
if (Data [4] & 0x80) {
|
|
DebugF (_T("Q931_MESSAGE::Decode: message type is invalid (%02XH)\n"), Data [4]);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
MessageType = (Q931_MESSAGE_TYPE) Data [4];
|
|
|
|
// enumerate the Information Elements and extract the ones that we will use
|
|
|
|
Pos = Data + 5;
|
|
End = Data + Length;
|
|
|
|
Result = S_OK;
|
|
|
|
while (Pos < End) {
|
|
ArrayEntry = InfoElementArray.AllocAtEnd();
|
|
|
|
if (!ArrayEntry) {
|
|
Result = E_OUTOFMEMORY;
|
|
Debug (_T("Q931_MESSAGE::Decode: allocation failure\n"));
|
|
break;
|
|
}
|
|
|
|
Result = DecodeInfoElement (&Pos, End, ArrayEntry);
|
|
|
|
if (Result != S_OK) {
|
|
DebugError (Result, _T("Q931_MESSAGE::Decode: failed to decode IE, packet may be corrupt, terminating (but not failing) decode\n"));
|
|
Result = S_OK;
|
|
|
|
InfoElementArray.DeleteEntry (ArrayEntry);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Result == S_OK) {
|
|
assert (!Buffer);
|
|
|
|
Buffer = Data;
|
|
BufferLength = Length;
|
|
BufferIsOwner = IsDataOwner;
|
|
}
|
|
else {
|
|
Detach();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::EncodePdu (
|
|
IN OUT LPBYTE Data,
|
|
IN OUT LPDWORD Length)
|
|
{
|
|
Q931_ENCODE_CONTEXT Context;
|
|
Q931_IE * IePos;
|
|
Q931_IE * IeEnd;
|
|
HRESULT Result;
|
|
DWORD EncodeLength;
|
|
|
|
assert (Data);
|
|
assert (Length);
|
|
|
|
Context.Pos = Data;
|
|
Context.End = Data + *Length;
|
|
|
|
SortInfoElementArray();
|
|
|
|
Result = EncodeHeader (&Context);
|
|
if (Result != S_OK)
|
|
return Result;
|
|
|
|
// walk IE array
|
|
|
|
InfoElementArray.GetExtents (&IePos, &IeEnd);
|
|
for (; IePos < IeEnd; IePos++) {
|
|
Result = EncodeInfoElement (&Context, IePos);
|
|
if (Result != S_OK) {
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
EncodeLength = (DWORD)(Context.Pos - Data);
|
|
|
|
if (Context.HasOverflowed()) {
|
|
|
|
Result = HRESULT_FROM_WIN32 (ERROR_MORE_DATA);
|
|
}
|
|
else {
|
|
|
|
Result = S_OK;
|
|
|
|
}
|
|
|
|
*Length = EncodeLength;
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::EncodeHeader (
|
|
IN Q931_ENCODE_CONTEXT * Context)
|
|
{
|
|
BYTE Header [5];
|
|
|
|
Header [0] = Q931_PROTOCOL_DISCRIMINATOR;
|
|
Header [1] = 2;
|
|
Header [2] = (CallReferenceValue >> 8) & 0xFF;
|
|
Header [3] = CallReferenceValue & 0xFF;
|
|
Header [4] = MessageType;
|
|
|
|
Context -> StoreData (Header, 5);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::EncodeInfoElement (
|
|
IN Q931_ENCODE_CONTEXT * Context,
|
|
IN Q931_IE * InfoElement)
|
|
{
|
|
BYTE Header [0x10];
|
|
WORD Length;
|
|
DWORD LengthLength; // length of Length, in bytes
|
|
LPBYTE LengthInsertionPoint;
|
|
LPBYTE IeContents;
|
|
DWORD IeContentsLength;
|
|
DWORD ShiftCount;
|
|
HRESULT Result;
|
|
|
|
if (InfoElement -> Identifier & 0x80) {
|
|
// single-byte IE
|
|
|
|
switch (InfoElement -> Identifier & 0xF0) {
|
|
case Q931_IE_MORE_DATA:
|
|
case Q931_IE_SENDING_COMPLETE:
|
|
// these IEs have an identifier, but no value
|
|
|
|
Header [0] = (BYTE) InfoElement -> Identifier;
|
|
break;
|
|
|
|
default:
|
|
// these IEs have an identifier and a value, combined in a single byte
|
|
Header [0] = (((BYTE) InfoElement -> Identifier) & 0xF0)
|
|
| (InfoElement -> Data.UnknownFixed.Value & 0x0F);
|
|
break;
|
|
}
|
|
|
|
Context -> StoreData (Header, 1);
|
|
|
|
Result = S_OK;
|
|
}
|
|
else {
|
|
// variable-length IE
|
|
|
|
Header [0] = (BYTE) InfoElement -> Identifier;
|
|
Context -> StoreData (Header, 1);
|
|
|
|
// allocate data for the insertion point
|
|
Context -> AllocData (2, &LengthInsertionPoint);
|
|
|
|
// record the current buffer position, for use below in storing the content length
|
|
IeContents = Context -> Pos;
|
|
|
|
switch (InfoElement -> Identifier) {
|
|
case Q931_IE_USER_TO_USER:
|
|
Result = EncodeIE_UUIE (Context, InfoElement);
|
|
break;
|
|
|
|
default:
|
|
|
|
Context -> StoreData (
|
|
InfoElement -> Data.UnknownVariable.Data,
|
|
InfoElement -> Data.UnknownVariable.Length);
|
|
|
|
if (InfoElement -> Data.UnknownVariable.Length >= 0x10000) {
|
|
DebugF (_T("Q931_MESSAGE::EncodeInfoElement: payload is waaaaay too big (%d %08XH)\n"),
|
|
InfoElement -> Data.UnknownVariable.Length,
|
|
InfoElement -> Data.UnknownVariable.Length);
|
|
|
|
Result = E_INVALIDARG;
|
|
}
|
|
else {
|
|
Result = S_OK;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (Result == S_OK) {
|
|
|
|
IeContentsLength = (DWORD)(Context -> Pos - IeContents);
|
|
|
|
// this is such a hack
|
|
// with little or no justification for when LengthLength = 1 and when LengthLength = 2
|
|
// the octet group extension mechanism is poorly defined in Q.931
|
|
|
|
if (InfoElement -> Identifier == Q931_IE_USER_TO_USER)
|
|
LengthLength = 2;
|
|
else
|
|
LengthLength = 1;
|
|
|
|
// if the storage context has not overflowed,
|
|
// and if it is necessary to resize the Length parameter (we guessed pessimistically
|
|
// that it would be 2), then move the buffer down one byte
|
|
|
|
ShiftCount = 2 - LengthLength;
|
|
|
|
if (ShiftCount > 0) {
|
|
if (!Context -> HasOverflowed()) {
|
|
memmove (
|
|
LengthInsertionPoint + LengthLength, // destination, where IE contents should be
|
|
IeContents, // source, where IE contents were actually stored
|
|
IeContentsLength); // length of the contents
|
|
}
|
|
|
|
// pull back the storage context's position pointer
|
|
Context -> Pos -= ShiftCount;
|
|
}
|
|
|
|
// now store the actual count
|
|
|
|
switch (LengthLength) {
|
|
case 1:
|
|
assert (IeContentsLength < 0x100);
|
|
LengthInsertionPoint [0] = (BYTE) IeContentsLength;
|
|
break;
|
|
|
|
case 2:
|
|
assert (IeContentsLength < 0x10000);
|
|
LengthInsertionPoint [0] = (BYTE) (IeContentsLength >> 8);
|
|
LengthInsertionPoint [1] = (BYTE) (IeContentsLength & 0xFF);
|
|
break;
|
|
|
|
default:
|
|
assert (FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::EncodeIE_UUIE (
|
|
IN Q931_ENCODE_CONTEXT * Context,
|
|
IN Q931_IE * InfoElement)
|
|
{
|
|
DWORD Status;
|
|
LPBYTE Buffer;
|
|
DWORD Length;
|
|
BYTE ProtocolDiscriminator;
|
|
|
|
assert (Context);
|
|
assert (InfoElement);
|
|
assert (InfoElement -> Data.UserToUser.PduStructure);
|
|
|
|
|
|
// store the UUIE protocol discriminator
|
|
ProtocolDiscriminator = InfoElement -> Data.UserToUser.Type;
|
|
Context -> StoreData (&ProtocolDiscriminator, 1);
|
|
|
|
|
|
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
|
|
Status = H225EncodePdu_H323_UserInformation (
|
|
InfoElement -> Data.UserToUser.PduStructure,
|
|
&Buffer, &Length);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
Context -> StoreData (Buffer, Length);
|
|
H225FreeBuffer (Buffer);
|
|
|
|
return S_OK;
|
|
}
|
|
else {
|
|
// Status is not a real Win32 error code
|
|
// it is an ASN.1 enum (
|
|
#if DBG
|
|
// we pull this in so source debuggers can show actual symbolic enum name
|
|
tagASN1error_e AsnError = (tagASN1error_e) Status;
|
|
|
|
DebugF (_T("Q931_MESSAGE::EncodeIE_UUIE: failed to encode ASN.1 structure (%d)\n"),
|
|
AsnError);
|
|
|
|
#endif
|
|
|
|
// -XXX- one day, i'm going to convince Lon to use real Win32 error codes for ASN.1 return values
|
|
// -XXX- on that day, the return value should reflect the actual ASN.1 error code
|
|
|
|
return DIGSIG_E_ENCODE;
|
|
}
|
|
}
|
|
|
|
void Q931_MESSAGE::SortInfoElementArray (void)
|
|
{
|
|
InfoElementArray.QuickSort (CompareInfoElement);
|
|
}
|
|
|
|
// static
|
|
INT __cdecl Q931_MESSAGE::CompareInfoElement (
|
|
const Q931_IE * ComparandA,
|
|
const Q931_IE * ComparandB)
|
|
{
|
|
if (ComparandA -> Identifier < ComparandB -> Identifier) return -1;
|
|
if (ComparandA -> Identifier > ComparandB -> Identifier) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
HRESULT Q931_MESSAGE::FindInfoElement (
|
|
IN Q931_IE_IDENTIFIER Identifier,
|
|
OUT Q931_IE ** ReturnInfoElement)
|
|
{
|
|
DWORD Index;
|
|
|
|
assert (ReturnInfoElement);
|
|
|
|
if (InfoElementArray.BinarySearch ((SEARCH_FUNC_Q931_IE)InfoElementSearchFunc, &Identifier, &Index)) {
|
|
*ReturnInfoElement = InfoElementArray.m_Array + Index;
|
|
return S_OK;
|
|
}
|
|
else {
|
|
*ReturnInfoElement = NULL;
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
// static
|
|
INT Q931_MESSAGE::InfoElementSearchFunc (
|
|
IN const Q931_IE_IDENTIFIER * SearchKey,
|
|
IN const Q931_IE * Comparand)
|
|
{
|
|
Q931_IE_IDENTIFIER Identifier;
|
|
|
|
assert (SearchKey);
|
|
assert (Comparand);
|
|
|
|
Identifier = * (Q931_IE_IDENTIFIER *) SearchKey;
|
|
|
|
if (Identifier < Comparand -> Identifier) return -1;
|
|
if (Identifier > Comparand -> Identifier) return 1;
|
|
|
|
return 0;
|
|
}
|