windows-nt/Source/XPSP1/NT/net/rras/ip/nath323/util.cpp
2020-09-26 16:20:57 +08:00

641 lines
13 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#if defined(DBG)
void Debug (LPCWSTR Text)
{
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
NTSTATUS Status;
assert (Text);
if (DebugLevel > 0) {
RtlInitUnicodeString (&UnicodeString, Text);
Status = RtlUnicodeStringToAnsiString (&AnsiString, &UnicodeString, TRUE);
if (NT_SUCCESS (Status)) {
OutputDebugStringA (AnsiString.Buffer);
RtlFreeAnsiString (&AnsiString);
}
}
}
void DebugVa (LPCTSTR Format, va_list VaList)
{
TCHAR Text [0x200];
_vsntprintf (Text, 0x200, Format, VaList);
Debug (Text);
}
void DebugF (LPCTSTR Format, ...)
{
va_list VaList;
va_start (VaList, Format);
DebugVa (Format, VaList);
va_end (VaList);
}
void DumpError (DWORD ErrorCode)
{
TCHAR Text [0x200];
DWORD TextLength;
DWORD MaxLength;
LPTSTR Pos;
_tcscpy (Text, _T("\tError: "));
Pos = Text + _tcslen (Text);
MaxLength = 0x200 - (DWORD)(Pos - Text);
TextLength = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode, LANG_NEUTRAL, Text, 0x200, NULL);
if (!TextLength)
_sntprintf (Pos, MaxLength, _T("Uknown error %08XH %u"), ErrorCode, ErrorCode);
_tcsncat (Text, _T("\n"), MaxLength);
Text [MaxLength - 1] = 0;
Debug (Text);
}
void DebugError (DWORD ErrorCode, LPCTSTR Text)
{
Debug (Text);
DumpError (ErrorCode);
}
void DebugErrorF (DWORD ErrorCode, LPCTSTR Format, ...)
{
va_list VaList;
va_start (VaList, Format);
DebugVa (Format, VaList);
va_end (VaList);
DumpError (ErrorCode);
}
void DebugLastError (LPCTSTR Text)
{
DebugError (GetLastError(), Text);
}
void DebugLastErrorF (LPCTSTR Format, ...)
{
va_list VaList;
DWORD ErrorCode;
ErrorCode = GetLastError();
va_start (VaList, Format);
DebugVa (Format, VaList);
va_end (VaList);
DumpError (ErrorCode);
}
static __inline CHAR ToHexA (UCHAR x)
{
x &= 0xF;
if (x < 10) return x + '0';
return (x - 10) + 'A';
}
void DumpMemory (const UCHAR * Data, ULONG Length)
{
const UCHAR * DataPos; // position within data
const UCHAR * DataEnd; // end of valid data
const UCHAR * RowPos; // position within a row
const UCHAR * RowEnd; // end of single row
CHAR Text [0x100];
LPSTR TextPos;
ULONG RowWidth;
assert (Data);
if (DebugLevel > 1) {
DataPos = Data;
DataEnd = Data + Length;
while (DataPos < DataEnd) {
RowWidth = (DWORD)(DataEnd - DataPos);
if (RowWidth > 16)
RowWidth = 16;
RowEnd = DataPos + RowWidth;
TextPos = Text;
*TextPos++ = '\t';
for (RowPos = DataPos; RowPos < RowEnd; RowPos++) {
*TextPos++ = ToHexA ((*RowPos >> 4) & 0xF);
*TextPos++ = ToHexA (*RowPos & 0xF);
*TextPos++ = ' ';
}
*TextPos++ = '\r';
*TextPos++ = '\n';
*TextPos = 0;
OutputDebugStringA (Text);
assert (RowEnd > DataPos); // make sure we are walking forward
DataPos = RowEnd;
}
}
}
#endif // defined(DBG)
// LIFETIME_CONTROLLER -------------------------------------------------------------------------
LIFETIME_CONTROLLER::LIFETIME_CONTROLLER (SYNC_COUNTER * AssocSyncCounter) {
ReferenceCount = 0L;
AssociatedSyncCounter = AssocSyncCounter;
if (AssociatedSyncCounter)
AssociatedSyncCounter -> Increment ();
#if ENABLE_REFERENCE_HISTORY
InitializeCriticalSection (&ReferenceHistoryLock);
if (AssociatedSyncCounter) {
AssociatedSyncCounter -> Lock ();
InsertTailList (&AssociatedSyncCounter -> ActiveLifetimeControllers, &ListEntry);
AssociatedSyncCounter -> Unlock ();
}
#endif // ENABLE_REFERENCE_HISTORY
}
LIFETIME_CONTROLLER::~LIFETIME_CONTROLLER () {
#if ENABLE_REFERENCE_HISTORY
if (AssociatedSyncCounter) {
AssociatedSyncCounter -> Lock ();
RemoveEntryList(&ListEntry);
AssociatedSyncCounter -> Unlock ();
}
DeleteCriticalSection(&ReferenceHistoryLock);
#endif // ENABLE_REFERENCE_HISTORY
_ASSERTE (ReferenceCount == 0L);
}
void LIFETIME_CONTROLLER::AddRef (void) {
LONG Count;
_ASSERTE (ReferenceCount >= 0L);
Count = InterlockedIncrement (&ReferenceCount);
#if ENABLE_REFERENCE_HISTORY
MAKE_REFERENCE_HISTORY_ENTRY ();
#endif //ENABLE_REFERENCE_HISTORY
}
void LIFETIME_CONTROLLER::Release (void) {
LONG Count;
Count = InterlockedDecrement (&ReferenceCount);
#if ENABLE_REFERENCE_HISTORY
MAKE_REFERENCE_HISTORY_ENTRY ();
#endif // ENABLE_REFERENCE_HISTORY
_ASSERTE (Count >= 0);
if (Count == 0) {
SYNC_COUNTER * LocalAssociatedSyncCounter;
LocalAssociatedSyncCounter = AssociatedSyncCounter;
delete this;
if (LocalAssociatedSyncCounter)
LocalAssociatedSyncCounter -> Decrement ();
}
}
// SYNC_COUNTER -------------------------------------------------------------------------
SYNC_COUNTER::SYNC_COUNTER () {
CounterValue = 0;
ZeroEvent = NULL;
}
SYNC_COUNTER::~SYNC_COUNTER () {
}
HRESULT SYNC_COUNTER::Start (void)
{
HRESULT Result = S_OK;
assert (ZeroEvent == NULL);
CounterValue = 1;
ZeroEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!ZeroEvent) {
Result = GetLastError ();
DebugLastError (_T("SYNC_COUNTER::SYNC_COUNTER: failed to create zero event\n"));
}
#if ENABLE_REFERENCE_HISTORY
Lock ();
InitializeListHead (&ActiveLifetimeControllers);
Unlock ();
#endif // ENABLE_REFERENCE_HISTORY
return Result;
}
void SYNC_COUNTER::Stop () {
if (ZeroEvent) {
CloseHandle (ZeroEvent);
ZeroEvent = NULL;
}
}
DWORD SYNC_COUNTER::Wait (DWORD Timeout)
{
if (!ZeroEvent) {
Debug (_T("SYNC_COUNTER::Wait: cannot wait because zero event could not be created\n"));
return ERROR_GEN_FAILURE;
}
Lock();
assert (CounterValue > 0);
if (--CounterValue == 0) {
if (ZeroEvent)
SetEvent (ZeroEvent);
}
Unlock ();
#if DBG
if (Timeout == INFINITE) {
DWORD Status;
for (;;) {
Status = WaitForSingleObject (ZeroEvent, 5000);
if (Status == WAIT_OBJECT_0)
return ERROR_SUCCESS;
assert (Status == WAIT_TIMEOUT);
DebugF (_T("SYNC_COUNTER::Wait: thread %08XH is taking a long time to wait for sync counter, counter value (%d)\n"),
GetCurrentThreadId(), CounterValue);
}
}
else
return WaitForSingleObject (ZeroEvent, Timeout);
#else
return WaitForSingleObject (ZeroEvent, Timeout);
#endif
}
void SYNC_COUNTER::Increment (void)
{
Lock();
CounterValue++;
Unlock();
}
void SYNC_COUNTER::Decrement (void)
{
Lock();
assert (CounterValue > 0);
if (--CounterValue == 0) {
if (ZeroEvent)
SetEvent (ZeroEvent);
}
Unlock();
}
EXTERN_C void MergeLists (PLIST_ENTRY Result, PLIST_ENTRY Source)
{
PLIST_ENTRY Entry;
// for now, we do a poor algorithm -- remove and insert every single object
AssertListIntegrity (Source);
AssertListIntegrity (Result);
while (!IsListEmpty (Source)) {
Entry = RemoveHeadList (Source);
assert (!IsInList (Result, Entry));
InsertTailList (Result, Entry);
}
}
// check to see if entry is in list
EXTERN_C BOOL IsInList (LIST_ENTRY * List, LIST_ENTRY * Entry)
{
LIST_ENTRY * Pos;
AssertListIntegrity (List);
for (Pos = List -> Flink; Pos != List; Pos = Pos -> Flink)
if (Pos == Entry)
return TRUE;
return FALSE;
}
EXTERN_C void ExtractList (LIST_ENTRY * Destination, LIST_ENTRY * Source)
{
AssertListIntegrity (Source);
InsertTailList (Source, Destination);
RemoveEntryList (Source);
InitializeListHead (Source);
}
EXTERN_C DWORD CountListLength (LIST_ENTRY * ListHead)
{
LIST_ENTRY * ListEntry;
DWORD Count;
assert (ListHead);
AssertListIntegrity (ListHead);
Count = 0;
for (ListEntry = ListHead -> Flink; ListEntry != ListHead; ListEntry++)
Count++;
return Count;
}
void AssertListIntegrity (LIST_ENTRY * list)
{
LIST_ENTRY * entry;
assert (list);
assert (list -> Flink -> Blink == list);
assert (list -> Blink -> Flink == list);
for (entry = list -> Flink; entry != list; entry = entry -> Flink) {
assert (entry);
assert (entry -> Flink -> Blink == entry);
assert (entry -> Blink -> Flink == entry);
}
}
NTSTATUS CopyAnsiString (
IN ANSI_STRING * SourceString,
OUT ANSI_STRING * DestString)
{
// assert (SourceString);
// assert (SourceString -> Buffer);
assert (DestString);
if (SourceString) {
// it's really SourceString -> Length, not * sizeof (CHAR), so don't change it
DestString -> Buffer = (LPSTR) HeapAlloc (GetProcessHeap(), 0, SourceString -> Length);
if (DestString -> Buffer) {
memcpy (DestString -> Buffer, SourceString -> Buffer, SourceString -> Length);
// yes, maxlen = len, not maxlen = maxlen
DestString -> MaximumLength = SourceString -> Length;
DestString -> Length = SourceString -> Length;
return STATUS_SUCCESS;
}
else {
ZeroMemory (DestString, sizeof (ANSI_STRING));
return STATUS_NO_MEMORY;
}
}
else {
DestString -> Buffer = NULL;
DestString -> MaximumLength = 0;
DestString -> Length = 0;
return STATUS_SUCCESS;
}
}
void FreeAnsiString (
IN ANSI_STRING * String)
{
assert (String);
if (String -> Buffer) {
HeapFree (GetProcessHeap(), 0, String -> Buffer);
String -> Buffer = NULL;
}
}
#if DBG
void ExposeTimingWindow (void)
{
#if 0
// this is here mostly to catch bug #393393, a/v on shutdown (race condition) -- arlied
Debug (_T("H323: waiting for 10s to expose race condition... (expect assertion failure on NatHandle)\n"));
DWORD Count;
for (Count = 0; Count < 10; Count++) {
assert (NatHandle);
Sleep (1000);
}
Debug (_T("H323: finished waiting for race condition, looks normal...\n"));
#endif
}
#endif
/*++
Routine Description:
Get the address of the best interface that
will be used to connect to the address specified.
Arguments:
DestinationAddress (IN) - address to be connected to, host order
InterfaceAddress (OUT) - address of the interface that
will be used for connection, host order
Return Values:
Win32 error specifying the outcome of the request
Notes:
Tries to use UDP-connect procedure to find the address of the interface
If the procedure fails, then tries an alternative way of consulting
the routing table, with GetBestInterface.
--*/
ULONG GetBestInterfaceAddress (
IN DWORD DestinationAddress, // host order
OUT DWORD * InterfaceAddress) // host order
{
SOCKET UDP_Socket;
ULONG Error;
SOCKADDR_IN ClientAddress;
SOCKADDR_IN LocalToClientAddress;
INT LocalToClientAddrSize = sizeof (SOCKADDR_IN);
Error = S_OK;
ClientAddress.sin_addr.s_addr = htonl (DestinationAddress);
ClientAddress.sin_port = htons (0);
ClientAddress.sin_family = AF_INET;
UDP_Socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (UDP_Socket == INVALID_SOCKET){
Error = WSAGetLastError ();
DebugLastError (_T("GetBestInterfaceAddress: failed to create UDP socket.\n"));
} else {
if (SOCKET_ERROR != connect (UDP_Socket, (PSOCKADDR)&ClientAddress, sizeof (SOCKADDR_IN))) {
LocalToClientAddrSize = sizeof (SOCKADDR_IN);
if (!getsockname (UDP_Socket, (struct sockaddr *)&LocalToClientAddress, &LocalToClientAddrSize)) {
*InterfaceAddress = ntohl (LocalToClientAddress.sin_addr.s_addr);
Error = ERROR_SUCCESS;
} else {
Error = WSAGetLastError ();
DebugLastError (_T("GetBestInterfaceAddress: failed to get name of UDP socket.\n"));
}
} else {
Error = WSAGetLastError ();
DebugLastError (_T("GetBestInterfaceAddress: failed to connect UDP socket."));
}
closesocket (UDP_Socket);
UDP_Socket = INVALID_SOCKET;
}
return Error;
}
DWORD
H323MapAdapterToAddress (
IN DWORD AdapterIndex
)
/*++
Routine Description:
This routine is invoked to map an adapter index to an IP address.
It does so by obtaining the stack's address table, and then linearly
searching through it trying to find an entry with matching adapter
index. If found, the entry is then used to obtain the IP address
corresponding to the adapter index.
Arguments:
AdapterIndex - Index of a local adapter for which an IP address is requested
Return Value:
DWORD - IP address (in host order)
If the routine succeeds, the return value will be a valid IP address
If the routine fails, the return value will be INADDR_NONE
--*/
{
DWORD Address = htonl (INADDR_NONE);
ULONG Index;
PMIB_IPADDRTABLE Table;
if (AllocateAndGetIpAddrTableFromStack (
&Table, FALSE, GetProcessHeap (), 0
) == NO_ERROR) {
for (Index = 0; Index < Table -> dwNumEntries; Index++) {
if (Table -> table[Index].dwIndex != AdapterIndex) {
continue;
}
Address = Table -> table [Index].dwAddr;
break;
}
HeapFree (GetProcessHeap (), 0, Table);
}
return ntohl (Address);
} // H323MapAddressToAdapter