609 lines
14 KiB
C++
609 lines
14 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
portmgmt.cpp
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Functions for allocating and freeing ports from the Port pool
|
|||
|
|
|||
|
PortPoolAllocRTPPort()
|
|||
|
PortPoolFreeRTPPort()
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Functions dealing with the TCP device to reserve/unreserve port ranges. //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Include files //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
|
|||
|
|
|||
|
#define NUM_DWORD_BITS (sizeof(DWORD)*8)
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Global Variables //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#define NUM_PORTS_PER_RANGE 100
|
|||
|
|
|||
|
struct PORT_RANGE
|
|||
|
{
|
|||
|
LIST_ENTRY ListEntry;
|
|||
|
|
|||
|
// This is the actual lower port. In case, the range allocated
|
|||
|
// by TCP starts with an odd port, we ignore the first port in
|
|||
|
// which case (low == AllocatedLow + 1). But when we free the
|
|||
|
// port range we should pass in AllocatedLow and not low.
|
|||
|
WORD AllocatedLow;
|
|||
|
WORD low;
|
|||
|
|
|||
|
// high is the last port we can use and not the allocated high.
|
|||
|
// In some cases high will be one less than the actual allocated high.
|
|||
|
WORD high;
|
|||
|
|
|||
|
//Each bit in this bitmap indicates the status of 2 consecutive ports
|
|||
|
|
|||
|
DWORD *AllocList;
|
|||
|
DWORD dwAllocListSize;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
class PORT_POOL :
|
|||
|
public SIMPLE_CRITICAL_SECTION_BASE
|
|||
|
{
|
|||
|
private:
|
|||
|
HANDLE TcpDevice;
|
|||
|
LIST_ENTRY PortRangeList; // contains PORT_RANGE.ListEntry
|
|||
|
|
|||
|
private:
|
|||
|
HRESULT OpenTcpDevice (void);
|
|||
|
HRESULT StartLocked (void);
|
|||
|
void FreeAll (void);
|
|||
|
|
|||
|
HRESULT CreatePortRange (
|
|||
|
OUT PORT_RANGE ** ReturnPortRange);
|
|||
|
|
|||
|
HRESULT ReservePortRange (
|
|||
|
IN ULONG RangeLength,
|
|||
|
OUT WORD * ReturnStartPort);
|
|||
|
|
|||
|
HRESULT UnReservePortRange (
|
|||
|
IN WORD StartPort);
|
|||
|
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
PORT_POOL (void);
|
|||
|
~PORT_POOL (void);
|
|||
|
|
|||
|
HRESULT Start (void);
|
|||
|
void Stop (void);
|
|||
|
|
|||
|
HRESULT AllocPort (
|
|||
|
OUT WORD * ReturnPort);
|
|||
|
|
|||
|
void FreePort (
|
|||
|
IN WORD Port);
|
|||
|
};
|
|||
|
|
|||
|
// global data -------------------------------------------------------------------------
|
|||
|
|
|||
|
static PORT_POOL PortPool;
|
|||
|
|
|||
|
// extern code -----------------------------------------------------------------------
|
|||
|
|
|||
|
HRESULT PortPoolStart (void)
|
|||
|
{
|
|||
|
return PortPool.Start();
|
|||
|
}
|
|||
|
|
|||
|
void PortPoolStop (void)
|
|||
|
{
|
|||
|
PortPool.Stop();
|
|||
|
}
|
|||
|
|
|||
|
HRESULT PortPoolAllocRTPPort (
|
|||
|
OUT WORD * ReturnPort)
|
|||
|
{
|
|||
|
return PortPool.AllocPort (ReturnPort);
|
|||
|
}
|
|||
|
|
|||
|
HRESULT PortPoolFreeRTPPort (
|
|||
|
IN WORD Port)
|
|||
|
{
|
|||
|
PortPool.FreePort (Port);
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
HRESULT PORT_POOL::ReservePortRange (
|
|||
|
IN ULONG RangeLength,
|
|||
|
OUT WORD * ReturnStartPort)
|
|||
|
{
|
|||
|
TCP_BLOCKPORTS_REQUEST PortRequest;
|
|||
|
DWORD BytesTransferred;
|
|||
|
ULONG StartPort;
|
|||
|
|
|||
|
AssertLocked();
|
|||
|
|
|||
|
*ReturnStartPort = 0;
|
|||
|
|
|||
|
if (!TcpDevice) {
|
|||
|
Debug (_T("H323: Cannot allocate port range, TCP device could not be opened.\n"));
|
|||
|
return E_UNEXPECTED;
|
|||
|
}
|
|||
|
|
|||
|
assert (TcpDevice != INVALID_HANDLE_VALUE);
|
|||
|
|
|||
|
PortRequest.ReservePorts = TRUE;
|
|||
|
PortRequest.NumberofPorts = RangeLength;
|
|||
|
|
|||
|
if (!DeviceIoControl (TcpDevice, IOCTL_TCP_BLOCK_PORTS,
|
|||
|
&PortRequest, sizeof PortRequest,
|
|||
|
&StartPort, sizeof StartPort,
|
|||
|
&BytesTransferred, NULL)) {
|
|||
|
|
|||
|
DebugLastError (_T("H323: Failed to allocate TCP port range.\n"));
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
DebugF (_T("H323: Reserved port range: [%04X - %04X)\n"),
|
|||
|
StartPort, StartPort + PortRequest.NumberofPorts);
|
|||
|
|
|||
|
*ReturnStartPort = (WORD) StartPort;
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
HRESULT PORT_POOL::UnReservePortRange (
|
|||
|
IN WORD StartPort)
|
|||
|
{
|
|||
|
TCP_BLOCKPORTS_REQUEST PortRequest;
|
|||
|
DWORD BytesTransferred;
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
AssertLocked();
|
|||
|
|
|||
|
if (!TcpDevice) {
|
|||
|
Debug (_T("H323: Cannot free TCP port range, TCP device is not open.\n"));
|
|||
|
return E_UNEXPECTED;
|
|||
|
}
|
|||
|
|
|||
|
assert (TcpDevice != INVALID_HANDLE_VALUE);
|
|||
|
|
|||
|
PortRequest.ReservePorts = FALSE;
|
|||
|
PortRequest.StartHandle = (ULONG) StartPort;
|
|||
|
|
|||
|
if (!DeviceIoControl(TcpDevice, IOCTL_TCP_BLOCK_PORTS,
|
|||
|
&PortRequest, sizeof PortRequest,
|
|||
|
&Status, sizeof Status,
|
|||
|
&BytesTransferred, NULL)) {
|
|||
|
|
|||
|
DebugLastError (_T("H323: Failed to free TCP port range.\n"));
|
|||
|
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Port Pool Functions. //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// PORT_POOL -----------------------------------------------------------------------
|
|||
|
|
|||
|
PORT_POOL::PORT_POOL (void)
|
|||
|
{
|
|||
|
TcpDevice = NULL;
|
|||
|
InitializeListHead (&PortRangeList);
|
|||
|
}
|
|||
|
|
|||
|
PORT_POOL::~PORT_POOL (void)
|
|||
|
{
|
|||
|
assert (!TcpDevice);
|
|||
|
assert (IsListEmpty (&PortRangeList));
|
|||
|
}
|
|||
|
|
|||
|
HRESULT PORT_POOL::Start (void)
|
|||
|
{
|
|||
|
HRESULT Result;
|
|||
|
|
|||
|
Lock();
|
|||
|
|
|||
|
Result = OpenTcpDevice();
|
|||
|
|
|||
|
Unlock();
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
HRESULT PORT_POOL::OpenTcpDevice (void)
|
|||
|
{
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
if (TcpDevice)
|
|||
|
return S_OK;
|
|||
|
|
|||
|
RtlInitUnicodeString (&DeviceName, (PCWSTR) DD_TCP_DEVICE_NAME);
|
|||
|
|
|||
|
InitializeObjectAttributes (&ObjectAttributes, &DeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|||
|
|
|||
|
Status = NtCreateFile (
|
|||
|
&TcpDevice,
|
|||
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA ,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
NULL,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|||
|
FILE_OPEN_IF, 0, NULL, 0);
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
TcpDevice = NULL;
|
|||
|
|
|||
|
DebugError (Status, _T("H323: Failed to open TCP device.\n"));
|
|||
|
|
|||
|
return (HRESULT) Status;
|
|||
|
}
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
void PORT_POOL::Stop (void)
|
|||
|
{
|
|||
|
Lock();
|
|||
|
|
|||
|
FreeAll();
|
|||
|
|
|||
|
if (TcpDevice) {
|
|||
|
assert (TcpDevice != INVALID_HANDLE_VALUE);
|
|||
|
|
|||
|
CloseHandle (TcpDevice);
|
|||
|
TcpDevice = NULL;
|
|||
|
}
|
|||
|
|
|||
|
Unlock();
|
|||
|
}
|
|||
|
|
|||
|
void PORT_POOL::FreeAll (void)
|
|||
|
{
|
|||
|
LIST_ENTRY * ListEntry;
|
|||
|
PORT_RANGE * PortRange;
|
|||
|
|
|||
|
while (!IsListEmpty (&PortRangeList)) {
|
|||
|
ListEntry = RemoveHeadList (&PortRangeList);
|
|||
|
PortRange = CONTAINING_RECORD (ListEntry, PORT_RANGE, ListEntry);
|
|||
|
|
|||
|
// Free the port range PortRange->AllocatedLow
|
|||
|
UnReservePortRange (PortRange -> AllocatedLow);
|
|||
|
EM_FREE (PortRange);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates a pair of RTP/RTCP ports from the
|
|||
|
port pool.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
rRTPport - This is an OUT parameter. If the function succeeds
|
|||
|
rRTPport will contain the RTP port (which is even).
|
|||
|
rRTPport+1 should be used as the RTCP port.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
This function returns S_OK on success and E_FAIL if it
|
|||
|
fails to allocate a port range.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
HRESULT PORT_POOL::AllocPort (
|
|||
|
OUT WORD * ReturnPort)
|
|||
|
{
|
|||
|
DWORD i, j;
|
|||
|
DWORD bitmap = 0x80000000;
|
|||
|
LIST_ENTRY * ListEntry;
|
|||
|
PORT_RANGE * PortRange;
|
|||
|
WORD Port;
|
|||
|
HRESULT Result;
|
|||
|
|
|||
|
Lock();
|
|||
|
|
|||
|
for (ListEntry = PortRangeList.Flink; ListEntry != &PortRangeList; ListEntry = ListEntry -> Flink) {
|
|||
|
PortRange = CONTAINING_RECORD (ListEntry, PORT_RANGE, ListEntry);
|
|||
|
|
|||
|
for (i = 0; i < PortRange->dwAllocListSize; i++) {
|
|||
|
|
|||
|
// traverse through AllocList of this portRange
|
|||
|
|
|||
|
if ((PortRange->AllocList[i] & 0xffffffff) != 0xffffffff) {
|
|||
|
// at least one entry is free
|
|||
|
bitmap = 0x80000000;
|
|||
|
|
|||
|
for (j = 0; j < NUM_DWORD_BITS; j++) {
|
|||
|
// traverse through each bit of the DWORD
|
|||
|
if ((PortRange->AllocList[i] & bitmap) == 0)
|
|||
|
{
|
|||
|
// found a free pair of ports
|
|||
|
Port = (WORD) (PortRange -> low + (i*NUM_DWORD_BITS*2) + (j*2));
|
|||
|
|
|||
|
if (Port > PortRange -> high) {
|
|||
|
// This check is needed because the last DWORD
|
|||
|
// in the AllocList may contain bits which are
|
|||
|
// actually not included in the AllocList.
|
|||
|
goto noports;
|
|||
|
}
|
|||
|
|
|||
|
// set the bit to show the pair of ports is allocated
|
|||
|
PortRange -> AllocList[i] |= bitmap;
|
|||
|
|
|||
|
// Leave the global critical section for the Port pool
|
|||
|
Unlock();
|
|||
|
|
|||
|
DebugF (_T("H323: Allocated port pair (%04X, %04X).\n"), Port, Port + 1);
|
|||
|
|
|||
|
*ReturnPort = Port;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
bitmap = bitmap >> 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
noports:
|
|||
|
// CODEWORK: Once we get the new ioctl() for dynamically reserving
|
|||
|
// port ranges, we need to allocate a new port range here. If the
|
|||
|
// ioctl() fails we need to return E_FAIL or another error which
|
|||
|
// says we have run out of ports.
|
|||
|
|
|||
|
// Allocate a new port range
|
|||
|
Result = CreatePortRange (&PortRange);
|
|||
|
|
|||
|
if (PortRange) {
|
|||
|
InsertHeadList (&PortRangeList, &PortRange -> ListEntry);
|
|||
|
|
|||
|
// allocate the first port in the range and
|
|||
|
Port = PortRange -> low;
|
|||
|
PortRange->AllocList[0] |= 0x80000000;
|
|||
|
|
|||
|
DebugF (_T("H323: Allocated port pair (%04X, %04X).\n"),
|
|||
|
Port, Port + 1);
|
|||
|
|
|||
|
*ReturnPort = Port;
|
|||
|
Result = S_OK;
|
|||
|
}
|
|||
|
else {
|
|||
|
Debug (_T("H323: Failed to allocate port range.\n"));
|
|||
|
|
|||
|
*ReturnPort = 0;
|
|||
|
Result = E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
Unlock();
|
|||
|
|
|||
|
return Result;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function frees a pair of RTP/RTCP ports.
|
|||
|
The data structure is changed to show that the pair of ports
|
|||
|
is now available.
|
|||
|
|
|||
|
CODEWORK: If an entire port range becomes free, do we release
|
|||
|
the port range to the operating system ? We probably need a
|
|||
|
heuristic to do this because allocating a port range again
|
|||
|
could be an expensive operation.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
wRTPport - This gives the RTP port to be freed.
|
|||
|
(RTCP port is RTPport+1 which is implicitly freed because
|
|||
|
we use one bit store the status of both these ports.)
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
Returns S_OK on success or E_FAIL if the port is not found in
|
|||
|
the port pool list.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
void PORT_POOL::FreePort (
|
|||
|
IN WORD Port)
|
|||
|
{
|
|||
|
HRESULT Result;
|
|||
|
|
|||
|
// assert RTP port is even
|
|||
|
_ASSERTE ((Port & 1) == 0);
|
|||
|
|
|||
|
DWORD Index = 0;
|
|||
|
DWORD Bitmap = 0x80000000;
|
|||
|
|
|||
|
LIST_ENTRY * ListEntry;
|
|||
|
PORT_RANGE * PortRange;
|
|||
|
|
|||
|
Lock();
|
|||
|
|
|||
|
// find the port range that this port belongs to
|
|||
|
// simple linear scan -- suboptimal
|
|||
|
|
|||
|
Result = E_FAIL;
|
|||
|
|
|||
|
for (ListEntry = PortRangeList.Flink; ListEntry != &PortRangeList; ListEntry = ListEntry -> Flink) {
|
|||
|
PortRange = CONTAINING_RECORD (ListEntry, PORT_RANGE, ListEntry);
|
|||
|
|
|||
|
if (PortRange -> low <= Port && PortRange -> high >= Port) {
|
|||
|
Result = S_OK;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Result == S_OK) {
|
|||
|
Index = (Port - PortRange -> low) / (NUM_DWORD_BITS * 2);
|
|||
|
|
|||
|
// assert index is less than the size of the array
|
|||
|
_ASSERTE (Index < PortRange -> dwAllocListSize);
|
|||
|
|
|||
|
// CODEWORK: make sure that the bit is set i.e. the port has
|
|||
|
// been previously allocated. Otherwise return an error and print
|
|||
|
// a warning.
|
|||
|
|
|||
|
// zero the bit to show the pair of ports is now free
|
|||
|
|
|||
|
PortRange -> AllocList [Index] &=
|
|||
|
~(Bitmap >> (((Port - PortRange -> low) / 2) % NUM_DWORD_BITS));
|
|||
|
|
|||
|
DebugF (_T("H323: Deallocated port pair (%04X, %04X).\n"), Port, Port + 1);
|
|||
|
}
|
|||
|
else {
|
|||
|
DebugF (_T("H323: warning, attempted to free port pair (%04X, %04X), but it did not belong to any port range.\n"),
|
|||
|
Port, Port + 1);
|
|||
|
}
|
|||
|
|
|||
|
Unlock();
|
|||
|
}
|
|||
|
|
|||
|
HRESULT PORT_POOL::CreatePortRange (
|
|||
|
OUT PORT_RANGE ** ReturnPortRange)
|
|||
|
{
|
|||
|
// CODEWORK: Once we get the new ioctl() for dynamically reserving
|
|||
|
// port ranges, we need to allocate a new port range here. If the
|
|||
|
// ioctl() fails we need to return E_FAIL or another error which
|
|||
|
// says we have run out of ports.
|
|||
|
|
|||
|
// assert low is even and high is odd
|
|||
|
// _ASSERTE((low % 2) == 0);
|
|||
|
// _ASSERTE((high % 2) == 1);
|
|||
|
|
|||
|
HRESULT Result;
|
|||
|
WORD AllocatedLowerPort;
|
|||
|
WORD LowerPort;
|
|||
|
DWORD NumPortsInRange;
|
|||
|
PORT_RANGE * PortRange;
|
|||
|
DWORD dwAllocListSize;
|
|||
|
|
|||
|
assert (ReturnPortRange);
|
|||
|
*ReturnPortRange = NULL;
|
|||
|
|
|||
|
Result = ReservePortRange (NUM_PORTS_PER_RANGE, &AllocatedLowerPort);
|
|||
|
if (FAILED (Result))
|
|||
|
return Result;
|
|||
|
|
|||
|
// If the allocated lower port is odd we do not use the lower port
|
|||
|
// and the range we use starts with the next higher port.
|
|||
|
if ((AllocatedLowerPort & 1) == 1) {
|
|||
|
// the allocated region is ODD
|
|||
|
// don't use the first entry
|
|||
|
|
|||
|
NumPortsInRange = NUM_PORTS_PER_RANGE - 1 - ((NUM_PORTS_PER_RANGE) & 1);
|
|||
|
LowerPort = AllocatedLowerPort + 1;
|
|||
|
}
|
|||
|
else {
|
|||
|
// the allocated region is EVEN
|
|||
|
// don't use the last entry
|
|||
|
|
|||
|
NumPortsInRange = NUM_PORTS_PER_RANGE;
|
|||
|
LowerPort = AllocatedLowerPort;
|
|||
|
}
|
|||
|
|
|||
|
// If NumPortsInRange is odd, we can not use the last port
|
|||
|
if ((NumPortsInRange & 1) == 1)
|
|||
|
{
|
|||
|
NumPortsInRange--;
|
|||
|
}
|
|||
|
|
|||
|
// Each bit gives the status (free/allocated) of two consecutive
|
|||
|
// ports. So, each DWORD can store the status of NUM_DWORD_BITS*2
|
|||
|
// ports. We add (NUM_DWORD_BITS*2 - 1) to round up the number of
|
|||
|
// DWORDS required.
|
|||
|
dwAllocListSize = (NumPortsInRange + NUM_DWORD_BITS*2 - 1)
|
|||
|
/ (NUM_DWORD_BITS * 2);
|
|||
|
|
|||
|
// allocate space for the AllocList also
|
|||
|
// Since we do not anticipate too many port ranges being allocated,
|
|||
|
// we do not require a separate heap for these structures.
|
|||
|
PortRange = (PORT_RANGE *) EM_MALLOC (
|
|||
|
sizeof (PORT_RANGE) + dwAllocListSize * sizeof (DWORD));
|
|||
|
|
|||
|
if (PortRange == NULL) {
|
|||
|
Debug (_T("H323: Allocation failure, cannot allocate PORT_RANGE and associated bit map\n"));
|
|||
|
|
|||
|
UnReservePortRange (AllocatedLowerPort);
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
_ASSERTE((LowerPort + NumPortsInRange - 1) <= 0xFFFF);
|
|||
|
|
|||
|
PortRange -> AllocatedLow = AllocatedLowerPort;
|
|||
|
PortRange -> low = LowerPort;
|
|||
|
PortRange -> high = (WORD) (LowerPort + NumPortsInRange - 1);
|
|||
|
PortRange -> dwAllocListSize = dwAllocListSize;
|
|||
|
PortRange -> AllocList = (DWORD *) (PortRange + 1);
|
|||
|
|
|||
|
DebugF (_T("H323: Allocated port block: [%04X - %04X].\n"),
|
|||
|
PortRange -> low,
|
|||
|
PortRange -> high,
|
|||
|
PortRange -> dwAllocListSize);
|
|||
|
|
|||
|
// Initialize the AllocList to show all the ports are free
|
|||
|
ZeroMemory (PortRange -> AllocList, (PortRange -> dwAllocListSize) * sizeof (DWORD));
|
|||
|
|
|||
|
*ReturnPortRange = PortRange;
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|