958 lines
25 KiB
C++
958 lines
25 KiB
C++
#ifndef __h323ics_util_h
|
|
#define __h323ics_util_h
|
|
|
|
extern "C" DWORD DebugLevel;
|
|
|
|
EXTERN_C BOOL IsInList (LIST_ENTRY * ListHead, LIST_ENTRY * ListEntry);
|
|
EXTERN_C void ExtractList (LIST_ENTRY * DestinationListHead, LIST_ENTRY * SourceListHead);
|
|
EXTERN_C DWORD CountListLength (LIST_ENTRY * ListHead);
|
|
EXTERN_C void MergeLists (PLIST_ENTRY Result, PLIST_ENTRY Source);
|
|
EXTERN_C void AssertListIntegrity (LIST_ENTRY * ListHead);
|
|
|
|
#define INET_NTOA(a) inet_ntoa(*(struct in_addr*)&(a))
|
|
|
|
typedef HANDLE TIMER_HANDLE;
|
|
|
|
__inline
|
|
LPWSTR AnsiToUnicode (LPCSTR string, LPWSTR buffer, DWORD buffer_len)
|
|
{
|
|
int x;
|
|
|
|
x = MultiByteToWideChar (CP_ACP, 0, string, -1, buffer, buffer_len);
|
|
buffer [x] = 0;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
__inline
|
|
LPSTR UnicodeToAnsi (LPCWSTR string, LPSTR buffer, DWORD buffer_len)
|
|
{
|
|
int x;
|
|
|
|
x = WideCharToMultiByte (CP_ACP, 0, string, -1, buffer, buffer_len,
|
|
NULL, FALSE);
|
|
buffer [x] = 0;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
class TIMER_PROCESSOR;
|
|
class OVERLAPPED_PROCESSOR;
|
|
|
|
class Q931_INFO;
|
|
class SOURCE_Q931_INFO;
|
|
class DEST_Q931_INFO;
|
|
|
|
class LOGICAL_CHANNEL;
|
|
class H245_INFO;
|
|
class SOURCE_H245_INFO;
|
|
class DEST_H245_INFO;
|
|
|
|
class H323_STATE;
|
|
class SOURCE_H323_STATE;
|
|
class DEST_H323_STATE;
|
|
|
|
class CALL_BRIDGE;
|
|
|
|
#ifdef __cplusplus
|
|
template <class T>
|
|
inline BOOL BadReadPtr(T* p, DWORD dwSize = 1)
|
|
{
|
|
return IsBadReadPtr(p, dwSize * sizeof(T));
|
|
}
|
|
|
|
template <class T>
|
|
inline BOOL BadWritePtr(T* p, DWORD dwSize = 1)
|
|
{
|
|
return IsBadWritePtr(p, dwSize * sizeof(T));
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(DBG)
|
|
|
|
void Debug (LPCTSTR);
|
|
void DebugF (LPCTSTR, ...);
|
|
void DebugError (DWORD, LPCTSTR);
|
|
void DebugErrorF (DWORD, LPCTSTR, ...);
|
|
void DebugLastError (LPCTSTR);
|
|
void DebugLastErrorF (LPCTSTR, ...);
|
|
|
|
void DumpMemory (const UCHAR * Data, ULONG Length);
|
|
void DumpError (DWORD);
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif // __cplusplus
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif // __cplusplus
|
|
|
|
#else // !defined(DBG)
|
|
|
|
static __inline void Debug (LPCTSTR) {}
|
|
static __inline void DebugF (LPCTSTR, ...) {}
|
|
static __inline void DebugError (DWORD, LPCTSTR) {}
|
|
static __inline void DebugErrorF (DWORD, LPCTSTR, ...) {}
|
|
static __inline void DebugLastError (LPCTSTR) {}
|
|
static __inline void DebugLastErrorF (LPCTSTR, ...) {}
|
|
|
|
static __inline void DumpMemory (const UCHAR * Data, ULONG Length) {}
|
|
static __inline void DumpError (DWORD) {}
|
|
|
|
#endif // defined(DBG)
|
|
|
|
|
|
#ifdef _ASSERTE
|
|
#undef _ASSERTE
|
|
#endif // _ASSERTE
|
|
|
|
#ifdef assert
|
|
#undef assert
|
|
#endif
|
|
|
|
#if DBG
|
|
|
|
// The latest and greatest Proxy assert
|
|
__inline void PxAssert(LPCTSTR file, DWORD line, LPCTSTR condition)
|
|
{
|
|
DebugF (_T("%s(%d) : Assertion failed, condition: %s\n"),
|
|
file, line, condition);
|
|
DebugBreak();
|
|
}
|
|
|
|
#define _ASSERTE(condition) if(condition);else\
|
|
{ PxAssert(_T(__FILE__), __LINE__, _T(#condition)); }
|
|
|
|
#define assert _ASSERTE
|
|
|
|
__inline void PxAssertNeverReached (LPCTSTR File, DWORD Line)
|
|
{
|
|
DebugF (_T("%s(%d) : Assertion failure, code path should never be executed\n"),
|
|
File, Line);
|
|
DebugBreak();
|
|
}
|
|
|
|
#define AssertNeverReached() PxAssertNeverReached (_T(__FILE__), __LINE__);
|
|
|
|
#else // !DBG
|
|
|
|
#define _ASSERTE(condition) NOP_FUNCTION
|
|
#define assert NOP_FUNCTION
|
|
#define AssertNeverReached() NOP_FUNCTION
|
|
|
|
#endif // DBG
|
|
|
|
|
|
|
|
|
|
// 0,1,2,3 : count of bytes from MSB to LSB in host order
|
|
#define BYTE0(l) ((BYTE)((DWORD)(l) >> 24))
|
|
#define BYTE1(l) ((BYTE)((DWORD)(l) >> 16))
|
|
#define BYTE2(l) ((BYTE)((DWORD)(l) >> 8))
|
|
#define BYTE3(l) ((BYTE)((DWORD)(l)))
|
|
|
|
// Handy macro to use in printf statements
|
|
#define BYTES0123(l) BYTE0(l), BYTE1(l), BYTE2(l), BYTE3(l)
|
|
|
|
// 0,1,2,3 : count of bytes from MSB to LSB in network order
|
|
#define NETORDER_BYTE0(l) ((BYTE)((BYTE *) &l)[0])
|
|
#define NETORDER_BYTE1(l) ((BYTE)((BYTE *) &l)[1])
|
|
#define NETORDER_BYTE2(l) ((BYTE)((BYTE *) &l)[2])
|
|
#define NETORDER_BYTE3(l) ((BYTE)((BYTE *) &l)[3])
|
|
|
|
#define SOCKADDR_IN_PRINTF(SocketAddress) \
|
|
ntohl ((SocketAddress) -> sin_addr.s_addr), \
|
|
ntohs ((SocketAddress) -> sin_port)
|
|
|
|
// Handy macro to use in printf statements
|
|
#define NETORDER_BYTES0123(l) NETORDER_BYTE0(l), NETORDER_BYTE1(l), \
|
|
NETORDER_BYTE2(l), NETORDER_BYTE3(l)
|
|
|
|
static __inline LONG RegQueryValueString (
|
|
IN HKEY Key,
|
|
IN LPCTSTR ValueName,
|
|
OUT LPTSTR ReturnString,
|
|
IN DWORD StringMax)
|
|
{
|
|
DWORD ValueLength;
|
|
DWORD Type;
|
|
LONG Status;
|
|
|
|
ValueLength = sizeof (TCHAR) * StringMax;
|
|
Status = RegQueryValueEx (Key, ValueName, NULL, &Type, (LPBYTE) ReturnString, &ValueLength);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
return Status;
|
|
|
|
if (Type != REG_SZ)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static __inline LONG RegQueryValueDWORD (
|
|
IN HKEY Key,
|
|
IN LPCTSTR ValueName,
|
|
OUT DWORD * ReturnValue)
|
|
{
|
|
DWORD ValueLength;
|
|
DWORD Type;
|
|
LONG Status;
|
|
|
|
ValueLength = sizeof (DWORD);
|
|
Status = RegQueryValueEx (Key, ValueName, NULL, &Type, (LPBYTE) ReturnValue, &ValueLength);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
return Status;
|
|
|
|
if (Type != REG_DWORD)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
class SIMPLE_CRITICAL_SECTION_BASE
|
|
{
|
|
protected:
|
|
|
|
CRITICAL_SECTION CriticalSection;
|
|
|
|
protected:
|
|
|
|
void Lock (void) { EnterCriticalSection (&CriticalSection); }
|
|
void Unlock (void) { LeaveCriticalSection (&CriticalSection); }
|
|
void AssertLocked (void) { assert (PtrToUlong(CriticalSection.OwningThread) == GetCurrentThreadId()); }
|
|
void AssertNotLocked (void) { assert (!CriticalSection.OwningThread); }
|
|
void AssertThreadNotLocked (void) { assert (PtrToUlong(CriticalSection.OwningThread) != GetCurrentThreadId()); }
|
|
|
|
protected:
|
|
|
|
SIMPLE_CRITICAL_SECTION_BASE (void) {
|
|
InitializeCriticalSection (&CriticalSection);
|
|
}
|
|
|
|
~SIMPLE_CRITICAL_SECTION_BASE (void) {
|
|
if (CriticalSection.OwningThread) {
|
|
DebugF (_T("SIMPLE_CRITICAL_SECTION_BASE::~SIMPLE_CRITICAL_SECTION_BASE: thread %08XH stills holds this critical section (this %p)\n"),
|
|
PtrToUlong(CriticalSection.OwningThread), this);
|
|
}
|
|
|
|
AssertNotLocked();
|
|
DeleteCriticalSection (&CriticalSection);
|
|
}
|
|
};
|
|
|
|
#if ENABLE_REFERENCE_HISTORY
|
|
#include "dynarray.h"
|
|
#endif // ENABLE_REFERENCE_HISTORY
|
|
|
|
class SYNC_COUNTER;
|
|
|
|
class LIFETIME_CONTROLLER
|
|
{
|
|
#if ENABLE_REFERENCE_HISTORY
|
|
public:
|
|
LIST_ENTRY ListEntry;
|
|
|
|
struct REFERENCE_HISTORY {
|
|
LONG CurrentReferenceCount;
|
|
PVOID CallersAddress;
|
|
};
|
|
|
|
DYNAMIC_ARRAY <REFERENCE_HISTORY> ReferenceHistory;
|
|
CRITICAL_SECTION ReferenceHistoryLock;
|
|
|
|
#define MAKE_REFERENCE_HISTORY_ENTRY() { \
|
|
PVOID CallersAddress, CallersCallersAddress; \
|
|
RtlGetCallersAddress (&CallersAddress, &CallersCallersAddress); \
|
|
EnterCriticalSection (&ReferenceHistoryLock); \
|
|
REFERENCE_HISTORY * ReferenceHistoryNode = ReferenceHistory.AllocAtEnd (); \
|
|
ReferenceHistoryNode -> CallersAddress = CallersAddress; \
|
|
ReferenceHistoryNode -> CurrentReferenceCount = Count; \
|
|
LeaveCriticalSection (&ReferenceHistoryLock); \
|
|
}
|
|
|
|
#endif //ENABLE_REFERENCE_HISTORY
|
|
|
|
private:
|
|
|
|
LONG ReferenceCount;
|
|
SYNC_COUNTER * AssociatedSyncCounter;
|
|
|
|
protected:
|
|
|
|
LIFETIME_CONTROLLER (SYNC_COUNTER * AssocSyncCounter = NULL);
|
|
virtual ~LIFETIME_CONTROLLER ();
|
|
|
|
public:
|
|
|
|
void AddRef (void);
|
|
|
|
void Release (void);
|
|
};
|
|
|
|
|
|
template <DWORD SampleHistorySize>
|
|
class SAMPLE_PREDICTOR {
|
|
public:
|
|
|
|
SAMPLE_PREDICTOR (void) {
|
|
|
|
ZeroMemory ((PVOID) &Samples[0], sizeof (Samples));
|
|
|
|
FirstSampleIndex = 0;
|
|
SamplesArraySize = 0;
|
|
}
|
|
|
|
HRESULT AddSample (LONG Sample) {
|
|
|
|
DWORD ThisSampleIndex;
|
|
|
|
if (0UL == SampleHistorySize)
|
|
return E_ABORT;
|
|
|
|
if (SamplesArraySize < SampleHistorySize) {
|
|
|
|
ThisSampleIndex = SamplesArraySize;
|
|
|
|
SamplesArraySize++;
|
|
|
|
} else {
|
|
|
|
ThisSampleIndex = FirstSampleIndex; // Overwrite the least recent sample
|
|
|
|
FirstSampleIndex++;
|
|
|
|
FirstSampleIndex %= SampleHistorySize;
|
|
}
|
|
|
|
Samples [ThisSampleIndex] = Sample;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LONG PredictNextSample (void) {
|
|
|
|
DWORD Index;
|
|
DWORD CurrentSampleIndex;
|
|
|
|
LONG Coefficient = 0;
|
|
LONG Prediction = 0;
|
|
|
|
if (0 == SampleHistorySize)
|
|
return 0;
|
|
|
|
for (Index = 0; Index < SamplesArraySize; Index++) {
|
|
|
|
if (0 == Index) {
|
|
|
|
Coefficient = (LONG)((SamplesArraySize & 1) << 1) - 1; // 1 or -1
|
|
|
|
} else {
|
|
|
|
Coefficient *= (LONG) Index - (LONG) SamplesArraySize - 1;
|
|
Coefficient /= (LONG) Index;
|
|
}
|
|
|
|
CurrentSampleIndex = (FirstSampleIndex + Index) % SamplesArraySize;
|
|
|
|
Prediction += Coefficient * Samples [CurrentSampleIndex];
|
|
|
|
}
|
|
|
|
return Prediction;
|
|
}
|
|
|
|
#if DBG
|
|
void PrintSamples (void) {
|
|
DWORD Index;
|
|
|
|
if (SamplesArraySize) {
|
|
DebugF (_T("Samples in predictor %p are: \n"), this);
|
|
|
|
for (Index = 0; Index < SamplesArraySize; Index++)
|
|
DebugF (_T("\t@%d(%d)-- %d\n"), Index, Index < FirstSampleIndex ? SamplesArraySize - (FirstSampleIndex - Index) : Index - FirstSampleIndex, Samples[Index]);
|
|
} else {
|
|
DebugF (_T("There are no samples in predictor %p.\n"), this);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HRESULT RetrieveOldSample (
|
|
IN DWORD StepsInThePast, // 0 -- most recent sample
|
|
OUT LONG * OldSample) {
|
|
|
|
DWORD SampleIndex;
|
|
|
|
if (0 == SampleHistorySize)
|
|
return E_ABORT;
|
|
|
|
if (StepsInThePast < SamplesArraySize) {
|
|
// Valid request
|
|
|
|
_ASSERTE (SamplesArraySize);
|
|
|
|
SampleIndex = (SamplesArraySize + FirstSampleIndex - StepsInThePast - 1) % SamplesArraySize;
|
|
|
|
*OldSample = Samples [SampleIndex];
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
private:
|
|
|
|
LONG Samples [SampleHistorySize]; // This is where samples are kept
|
|
LONG PositiveTerms [SampleHistorySize];
|
|
LONG NegativeTerms [SampleHistorySize];
|
|
DWORD SamplesArraySize;
|
|
DWORD FirstSampleIndex; // Index of the least recent sample
|
|
};
|
|
|
|
static __inline HRESULT GetLastErrorAsResult (void) {
|
|
return GetLastError() == ERROR_SUCCESS ? S_OK : HRESULT_FROM_WIN32 (GetLastError());
|
|
}
|
|
|
|
static __inline HRESULT GetLastResult (void) {
|
|
return GetLastError() == ERROR_SUCCESS ? S_OK : HRESULT_FROM_WIN32 (GetLastError());
|
|
}
|
|
|
|
// A sync counter is an integer counter.
|
|
// It is kind of the opposite of a semaphore.
|
|
// When the counter is zero, the sync counter is signaled.
|
|
// When the counter is nonzero, the sync counter is not signaled.
|
|
|
|
class SYNC_COUNTER :
|
|
public SIMPLE_CRITICAL_SECTION_BASE
|
|
{
|
|
friend class LIFETIME_CONTROLLER;
|
|
|
|
private:
|
|
|
|
LONG CounterValue; // the current value of the counter
|
|
HANDLE ZeroEvent; // signaled when CounterValue = 0
|
|
|
|
public:
|
|
#if ENABLE_REFERENCE_HISTORY
|
|
LIST_ENTRY ActiveLifetimeControllers;
|
|
#endif // ENABLE_REFERENCE_HISTORY
|
|
|
|
|
|
SYNC_COUNTER ();
|
|
~SYNC_COUNTER ();
|
|
|
|
HRESULT Start (void);
|
|
void Stop (void);
|
|
|
|
void Increment (void);
|
|
void Decrement (void);
|
|
|
|
DWORD Wait (DWORD Timeout);
|
|
};
|
|
|
|
|
|
|
|
#define HRESULT_FROM_WIN32_ERROR_CODE HRESULT_FROM_WIN32
|
|
#define HRESULT_FROM_WINSOCK_ERROR_CODE HRESULT_FROM_WINSOCK_ERROR_CODE
|
|
|
|
// ASN.1 utility functions
|
|
|
|
// Setup_UUIE&
|
|
// SetupMember(
|
|
// IN H323_UserInformation *pH323UserInfo
|
|
// );
|
|
#define SetupMember(pH323UserInfo) \
|
|
(pH323UserInfo)->h323_uu_pdu.h323_message_body.u.setup
|
|
|
|
// Returns a non-zero value only. So don't try comparing it with TRUE/FALSE
|
|
// BOOL
|
|
// IsDestCallSignalAddressPresent(
|
|
// IN H323_UserInformation *pH323UserInfo
|
|
// );
|
|
#define IsDestCallSignalAddressPresent(pH323UserInfo) \
|
|
(SetupMember(pH323UserInfo).bit_mask & Setup_UUIE_destCallSignalAddress_present)
|
|
|
|
// Get the destCallSignalAddress member
|
|
// TransportAddress&
|
|
// DCSAddrMember(
|
|
// IN H323_UserInformation *pH323UserInfo
|
|
// );
|
|
#define DCSAddrMember(pH323UserInfo) \
|
|
SetupMember(pH323UserInfo).destCallSignalAddress
|
|
|
|
// Get the destCallSignalAddress member
|
|
// DESTINATION_ADDRESS *&
|
|
// DestAddrMember(
|
|
// IN H323_UserInformation *pH323UserInfo
|
|
// );
|
|
#define DestAddrMember(pH323UserInfo) \
|
|
SetupMember(pH323UserInfo).destinationAddress
|
|
|
|
// BOOL
|
|
// IsTransportAddressTypeIP(
|
|
// IN TransportAddress Addr
|
|
// );
|
|
#define IsTransportAddressTypeIP(Addr) \
|
|
(Addr.choice == ipAddress_chosen)
|
|
|
|
// BOOL
|
|
// IPAddrMember(
|
|
// IN TransportAddress Addr
|
|
// );
|
|
#define IPAddrMember(Addr) \
|
|
Addr.u.ipAddress
|
|
|
|
typedef struct Setup_UUIE_destinationAddress DESTINATION_ADDRESS;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines for filling and extracting from structures used to //
|
|
// store Transport addresses in Q.931 and H.245 ASN //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// fills the TransportAddress port and address bytes with
|
|
// those specified. assumes that the passed in values are
|
|
// in host order
|
|
__inline void
|
|
FillTransportAddress(
|
|
IN DWORD IPv4Address, // host order
|
|
IN WORD Port, // host order
|
|
OUT TransportAddress &TransportAddress
|
|
)
|
|
{
|
|
// we are filling in an IP address
|
|
TransportAddress.choice = ipAddress_chosen;
|
|
|
|
// fill in the port
|
|
TransportAddress.u.ipAddress.port = Port;
|
|
|
|
// value is a ptr to a struct, so it can't be null
|
|
_ASSERTE(NULL != TransportAddress.u.ipAddress.ip.value);
|
|
|
|
// 4 bytes in the IP address
|
|
// copy the bytes into the transport address array
|
|
TransportAddress.u.ipAddress.ip.length = 4;
|
|
*((DWORD *)TransportAddress.u.ipAddress.ip.value) =
|
|
htonl(IPv4Address);
|
|
}
|
|
|
|
static __inline void FillTransportAddress (
|
|
IN const SOCKADDR_IN & SocketAddress,
|
|
OUT TransportAddress & ReturnTransportAddress)
|
|
{
|
|
FillTransportAddress (
|
|
ntohl (SocketAddress.sin_addr.s_addr),
|
|
ntohs (SocketAddress.sin_port),
|
|
ReturnTransportAddress);
|
|
}
|
|
|
|
// returns E_INVALIDARG for PDUs which can not be handled.
|
|
__inline HRESULT
|
|
GetTransportInfo(
|
|
IN const TransportAddress &TransportAddress,
|
|
OUT DWORD &IPv4Address, // host order
|
|
OUT WORD &Port // host order
|
|
)
|
|
{
|
|
// we proceed only if the transport address has the
|
|
// IP address (v4) field filled
|
|
if (!(ipAddress_chosen & TransportAddress.choice))
|
|
{
|
|
DebugF( _T("GetTransportInfo(&H245Address, &0x%x, &%u), ")
|
|
_T("non unicast address type = %d, returning E_INVALIDARG\n"),
|
|
IPv4Address, Port, TransportAddress.choice);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// fill in the port
|
|
Port = TransportAddress.u.ipAddress.port;
|
|
|
|
// 4 bytes in the IP address
|
|
// copy the bytes into the transport address array
|
|
if (4 != TransportAddress.u.ipAddress.ip.length)
|
|
{
|
|
DebugF( _T("GetTransportInfo: bogus address length (%d) in TransportAddress\n"),
|
|
TransportAddress.u.ipAddress.ip.length);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
IPv4Address = ntohl(*((DWORD *)TransportAddress.u.ipAddress.ip.value));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static __inline HRESULT GetTransportInfo (
|
|
IN const TransportAddress & TransportAddress,
|
|
OUT SOCKADDR_IN & ReturnSocketAddress)
|
|
{
|
|
HRESULT Result;
|
|
|
|
ReturnSocketAddress.sin_family = AF_INET;
|
|
|
|
Result = GetTransportInfo (TransportAddress,
|
|
ReturnSocketAddress.sin_addr.s_addr,
|
|
ReturnSocketAddress.sin_port);
|
|
|
|
ReturnSocketAddress.sin_addr.s_addr = htonl (ReturnSocketAddress.sin_addr.s_addr);
|
|
ReturnSocketAddress.sin_port = htons (ReturnSocketAddress.sin_port);
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
// fills the H245TransportAddress port and address bytes with
|
|
// those specified. assumes that the passed in values are
|
|
// in host order
|
|
inline void
|
|
FillH245TransportAddress(
|
|
IN DWORD IPv4Address,
|
|
IN WORD Port,
|
|
OUT H245TransportAddress &H245Address
|
|
)
|
|
{
|
|
// we are filling in an unicast IP address
|
|
H245Address.choice = unicastAddress_chosen;
|
|
|
|
// alias for the unicast address
|
|
UnicastAddress &UnicastIPAddress = H245Address.u.unicastAddress;
|
|
|
|
// its an IP address
|
|
UnicastIPAddress.choice = UnicastAddress_iPAddress_chosen;
|
|
|
|
// fill in the port
|
|
UnicastIPAddress.u.iPAddress.tsapIdentifier = Port;
|
|
|
|
// value is a ptr to a struct, so it can't be null
|
|
_ASSERTE(NULL != UnicastIPAddress.u.iPAddress.network.value);
|
|
|
|
// 4 bytes in the IP address
|
|
// copy the bytes into the transport address array
|
|
UnicastIPAddress.u.iPAddress.network.length = 4;
|
|
*((DWORD *)UnicastIPAddress.u.iPAddress.network.value) =
|
|
htonl(IPv4Address);
|
|
}
|
|
|
|
// Returned IPaddress and port are in host order
|
|
inline HRESULT
|
|
GetH245TransportInfo(
|
|
IN const H245TransportAddress &H245Address,
|
|
OUT DWORD &IPv4Address,
|
|
OUT WORD &Port
|
|
)
|
|
{
|
|
// we proceed only if the transport address has a unicast address
|
|
if (!(unicastAddress_chosen & H245Address.choice))
|
|
{
|
|
DebugF( _T("GetH245TransportInfo(&H245Address, &0x%x, &%u), ")
|
|
_T("non unicast address type = %d, returning E_INVALIDARG\n"),
|
|
IPv4Address, Port, H245Address.choice);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// we proceed only if the transport address has the
|
|
// IP address (v4) field filled
|
|
if (!(UnicastAddress_iPAddress_chosen &
|
|
H245Address.u.unicastAddress.choice))
|
|
{
|
|
DebugF( _T("GetH245TransportInfo(&TransportAddress, &0x%x, &%u), ")
|
|
_T("non ip address type = %d, returning E_INVALIDARG\n"),
|
|
IPv4Address, Port, H245Address.u.unicastAddress.choice);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
const UnicastAddress & UnicastIPAddress = H245Address.u.unicastAddress;
|
|
|
|
// fill in the port
|
|
Port = UnicastIPAddress.u.iPAddress.tsapIdentifier;
|
|
|
|
// 4 bytes in the IP address
|
|
// copy the bytes into the transport address array
|
|
if (4 != UnicastIPAddress.u.iPAddress.network.length)
|
|
{
|
|
DebugF( _T("GetH245TransportInfo: bogus ip address length (%d), failing\n"),
|
|
UnicastIPAddress.u.iPAddress.network.length);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// value is a ptr to a struct, so it can't be null
|
|
_ASSERTE(NULL != UnicastIPAddress.u.iPAddress.network.value);
|
|
IPv4Address = ntohl(*((DWORD *)UnicastIPAddress.u.iPAddress.network.value));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static __inline HRESULT GetH245TransportInfo (
|
|
IN const H245TransportAddress & H245Address,
|
|
OUT SOCKADDR_IN * ReturnSocketAddress)
|
|
{
|
|
DWORD IPAddress;
|
|
WORD Port;
|
|
HRESULT Result;
|
|
|
|
Result = GetH245TransportInfo (H245Address, IPAddress, Port);
|
|
if (Result == S_OK) {
|
|
ReturnSocketAddress -> sin_family = AF_INET;
|
|
ReturnSocketAddress -> sin_addr.s_addr = htonl (IPAddress);
|
|
ReturnSocketAddress -> sin_port = htons (Port);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines dealing with the T.120 Parameters in H.245 PDUs //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// In case of failure the routine returns
|
|
// INADDR_NONE for the T120ConnectToIPAddr
|
|
inline HRESULT
|
|
GetT120ConnectToAddress(
|
|
IN NetworkAccessParameters separateStack,
|
|
OUT DWORD &T120ConnectToIPAddr,
|
|
OUT WORD &T120ConnectToPort
|
|
)
|
|
{
|
|
// These are the return values in case of a failure.
|
|
T120ConnectToIPAddr = INADDR_NONE;
|
|
T120ConnectToPort = 0;
|
|
|
|
// CODEWORK: should we require the distribution member
|
|
// to be present always ?
|
|
|
|
if ((separateStack.bit_mask & distribution_present) &&
|
|
(separateStack.distribution.choice != unicast_chosen))
|
|
{
|
|
// We support Unicast only
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Deal with t120SetupProcedure
|
|
|
|
if (separateStack.networkAddress.choice != localAreaAddress_chosen)
|
|
{
|
|
// Support only local area addresses
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
GetH245TransportInfo(
|
|
separateStack.networkAddress.u.localAreaAddress,
|
|
T120ConnectToIPAddr,
|
|
T120ConnectToPort
|
|
);
|
|
|
|
DebugF (_T ("T120: Endpoint is listening on: %08X:%04X.\n"),
|
|
T120ConnectToIPAddr,
|
|
T120ConnectToPort
|
|
);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
#define TPKT_HEADER_SIZE 4
|
|
#define TPKT_VERSION 3
|
|
|
|
|
|
inline DWORD GetPktLenFromTPKTHdr(BYTE *pbTpktHdr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute the length of the packet from the TPKT header.
|
|
The TPKT header is four bytes long. Byte 0 gives
|
|
the TPKT version (defined by TPKT_VERSION). Byte 1
|
|
is reserved and should not be interpreted. Bytes 2 and 3
|
|
together give the size of the packet (Byte 2 is the MSB and
|
|
Byte 3 is the LSB i.e. in network byte order). (This assumes
|
|
that the size of the packet will always fit in 2 bytes).
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Values:
|
|
|
|
Returns the length of the PDU which follows the TPKT header.
|
|
|
|
--*/
|
|
{
|
|
_ASSERTE(pbTpktHdr[0] == TPKT_VERSION);
|
|
return ((pbTpktHdr[2] << 8) + pbTpktHdr[3] - TPKT_HEADER_SIZE);
|
|
}
|
|
|
|
inline void SetupTPKTHeader(
|
|
OUT BYTE * pbTpktHdr,
|
|
IN DWORD dwLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Setup the TPKT header based on the length.
|
|
|
|
The TPKT header is four bytes long. Byte 0 gives
|
|
the TPKT version (defined by TPKT_VERSION). Byte 1
|
|
is reserved and should not be interpreted. Bytes 2 and 3
|
|
together give the size of the packet (Byte 2 is the MSB and
|
|
Byte 3 is the LSB i.e. in network byte order). (This assumes
|
|
that the size of the packet will always fit in 2 bytes).
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Values:
|
|
|
|
Returns S_OK if the version is right and E_FAIL otherwise.
|
|
|
|
--*/
|
|
{
|
|
_ASSERTE(pbTpktHdr);
|
|
|
|
dwLength += TPKT_HEADER_SIZE;
|
|
|
|
// TPKT requires that the packet size fit in two bytes.
|
|
_ASSERTE(dwLength < (1L << 16));
|
|
|
|
pbTpktHdr[0] = TPKT_VERSION;
|
|
pbTpktHdr[1] = 0;
|
|
pbTpktHdr[2] = HIBYTE(dwLength); //(BYTE)(dwLength >> 8);
|
|
pbTpktHdr[3] = LOBYTE(dwLength); //(BYTE)dwLength;
|
|
}
|
|
|
|
static __inline BOOLEAN RtlEqualStringConst (
|
|
IN const STRING * StringA,
|
|
IN const STRING * StringB,
|
|
IN BOOLEAN CaseInSensitive)
|
|
{
|
|
return RtlEqualString (
|
|
const_cast<STRING *> (StringA),
|
|
const_cast<STRING *> (StringB),
|
|
CaseInSensitive);
|
|
}
|
|
|
|
static __inline INT RtlCompareStringConst (
|
|
IN const STRING * StringA,
|
|
IN const STRING * StringB,
|
|
IN BOOLEAN CaseInSensitive)
|
|
{
|
|
return RtlCompareString (
|
|
const_cast<STRING *> (StringA),
|
|
const_cast<STRING *> (StringB),
|
|
CaseInSensitive);
|
|
}
|
|
|
|
static __inline void InitializeAnsiString (
|
|
OUT ANSI_STRING * AnsiString,
|
|
IN ASN1octetstring_t * AsnString)
|
|
{
|
|
assert (AnsiString);
|
|
assert (AsnString);
|
|
|
|
AnsiString -> Buffer = (PSTR) AsnString -> value;
|
|
AnsiString -> Length = (USHORT) AsnString -> length / sizeof (CHAR);
|
|
}
|
|
|
|
static __inline void InitializeUnicodeString (
|
|
OUT UNICODE_STRING * UnicodeString,
|
|
IN ASN1char16string_t * AsnString)
|
|
{
|
|
assert (UnicodeString);
|
|
assert (AsnString);
|
|
|
|
UnicodeString -> Buffer = (PWSTR)AsnString -> value;
|
|
UnicodeString -> Length = (USHORT) AsnString -> length / sizeof (WCHAR);
|
|
}
|
|
|
|
// use with "%.*s" or "%.*S"
|
|
#define ANSI_STRING_PRINTF(AnsiString) (AnsiString) -> Length, (AnsiString) -> Buffer
|
|
|
|
|
|
// { Length, MaximumLength, Buffer }
|
|
#define ANSI_STRING_INIT(Text) { sizeof (Text) - sizeof (CHAR), 0, (Text) } // account for NUL
|
|
|
|
void FreeAnsiString (
|
|
IN ANSI_STRING * String);
|
|
|
|
NTSTATUS CopyAnsiString (
|
|
IN ANSI_STRING * SourceString,
|
|
OUT ANSI_STRING * DestString);
|
|
|
|
static __inline ULONG ByteSwap (
|
|
IN ULONG Value)
|
|
{
|
|
union ULONG_SWAP {
|
|
BYTE Bytes [sizeof (ULONG)];
|
|
ULONG Integer;
|
|
};
|
|
|
|
ULONG_SWAP * SwapValue;
|
|
ULONG_SWAP SwapResult;
|
|
|
|
SwapValue = (ULONG_SWAP *) &Value;
|
|
SwapResult.Bytes [0] = SwapValue -> Bytes [3];
|
|
SwapResult.Bytes [1] = SwapValue -> Bytes [2];
|
|
SwapResult.Bytes [2] = SwapValue -> Bytes [1];
|
|
SwapResult.Bytes [3] = SwapValue -> Bytes [0];
|
|
|
|
return SwapResult.Integer;
|
|
}
|
|
|
|
// does NOT convert to host order first
|
|
static __inline INT Compare_SOCKADDR_IN (
|
|
IN const SOCKADDR_IN * AddressA,
|
|
IN const SOCKADDR_IN * AddressB)
|
|
{
|
|
assert (AddressA);
|
|
assert (AddressB);
|
|
|
|
if (AddressA -> sin_addr.s_addr < AddressB -> sin_addr.s_addr) return -1;
|
|
if (AddressA -> sin_addr.s_addr > AddressB -> sin_addr.s_addr) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static __inline BOOL IsEqualSocketAddress (
|
|
IN const SOCKADDR_IN * AddressA,
|
|
IN const SOCKADDR_IN * AddressB)
|
|
{
|
|
assert (AddressA);
|
|
assert (AddressB);
|
|
assert (AddressA -> sin_family == AF_INET);
|
|
assert (AddressB -> sin_family == AF_INET);
|
|
|
|
return AddressA -> sin_addr.s_addr == AddressB -> sin_addr.s_addr
|
|
&& AddressA -> sin_port == AddressB -> sin_port;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
void ExposeTimingWindow (void);
|
|
|
|
#endif
|
|
|
|
// Get the address of the best interface that will
|
|
// be used to connect to the DestinationAddress
|
|
ULONG GetBestInterfaceAddress (
|
|
IN DWORD DestinationAddress, // host order
|
|
OUT DWORD * InterfaceAddress); // host order
|
|
|
|
DWORD
|
|
H323MapAdapterToAddress (
|
|
IN DWORD AdapterIndex
|
|
);
|
|
#endif // __h323ics_util_h
|