#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 inline BOOL BadReadPtr(T* p, DWORD dwSize = 1) { return IsBadReadPtr(p, dwSize * sizeof(T)); } template 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 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 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 (StringA), const_cast (StringB), CaseInSensitive); } static __inline INT RtlCompareStringConst ( IN const STRING * StringA, IN const STRING * StringB, IN BOOLEAN CaseInSensitive) { return RtlCompareString ( const_cast (StringA), const_cast (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