641 lines
13 KiB
C++
641 lines
13 KiB
C++
#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
|