Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1699 lines
39 KiB

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corp., 1995 **/
/**********************************************************************/
/*
dhcpapi.cpp
DHCP Api function wrappers
FILE HISTORY:
*/
#include "stdafx.h"
#define DHCP_RPC_PREFERRED_SIZE ((DWORD) -1)
//
// User-friendly RPC memory release
//
void
CObjectPlus :: FreeRpcMemory (
void * pvRpcData
)
{
if ( pvRpcData )
{
::DhcpRpcFreeMemory( pvRpcData ) ;
}
}
CDhcpRpcDataWrapper :: ~ CDhcpRpcDataWrapper ()
{
}
//
// Constructor for free-standing structure, which may have been
// delivered by RPC or may be just an independent data structure.
//
CDhcpScopeInfo :: CDhcpScopeInfo (
const DHCP_SUBNET_INFO * pdhcSubnetInfo,
CDWRAP_Type wrapperType
)
: CDhcpRpcDataWrapper( wrapperType ),
m_p_subnet_info( (DHCP_SUBNET_INFO *) pdhcSubnetInfo )
{
}
//
// Constructor for generation of a structure for RPC purposes.
//
CDhcpScopeInfo :: CDhcpScopeInfo (
const CDhcpScope & cScope
)
: CDhcpRpcDataWrapper( CDWRAP_Internal ),
m_p_subnet_info( NULL )
{
LONG err = 0 ;
CATCH_MEM_EXCEPTION
{
do
{
m_p_subnet_info = new DHCP_SUBNET_INFO ;
if ( m_p_subnet_info == NULL )
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
CLEAR_TO_ZEROES( m_p_subnet_info ) ;
//
// Fill in scope-specific data
//
m_p_subnet_info->SubnetAddress = cScope.QueryId() ;
m_p_subnet_info->SubnetMask = cScope.QuerySubnetMask() ;
m_p_subnet_info->SubnetName = ::UtilWcstrDup( cScope.QueryName() ) ;
m_p_subnet_info->SubnetComment = ::UtilWcstrDup( cScope.QueryComment() ) ;
m_p_subnet_info->SubnetState = cScope.QueryEnabled()
? DhcpSubnetEnabled
: DhcpSubnetDisabled ;
//
// Fill in primary host info
// BUGBUG: what about NetBIOS and Host names?
//
m_p_subnet_info->PrimaryHost.IpAddress = cScope.QueryScopeId().QueryIpAddress() ;
m_p_subnet_info->PrimaryHost.NetBiosName = NULL ;
m_p_subnet_info->PrimaryHost.HostName = NULL ;
} while ( FALSE ) ;
}
END_MEM_EXCEPTION(err)
if ( err )
{
ReportError( err ) ;
}
}
CDhcpScopeInfo :: ~ CDhcpScopeInfo ()
{
FreeData() ;
}
LONG
CDhcpScopeInfo :: FreeData ()
{
switch ( m_type )
{
//
// This object is just a wrapper for a free-standing structure
//
case CDWRAP_Simple:
break ;
//
// This object is a wrapper for data returned by the DHCP API.
//
case CDWRAP_Rpc:
FreeRpcMemory( m_p_subnet_info ) ;
break ;
//
// This object is a wrapper for a structure built for use by the API.
// We must tear it down by hand.
//
case CDWRAP_Internal:
if ( m_p_subnet_info )
{
delete m_p_subnet_info->SubnetName ;
delete m_p_subnet_info->SubnetComment ;
delete m_p_subnet_info->PrimaryHost.NetBiosName ;
delete m_p_subnet_info->PrimaryHost.HostName ;
delete m_p_subnet_info ;
}
break ;
}
m_p_subnet_info = NULL ;
return 0 ;
}
DHCP_SUBNET_STATE CDhcpScopeInfo :: QueryState () const
{
return m_p_subnet_info
? m_p_subnet_info->SubnetState
: DhcpSubnetDisabled ;
}
DHCP_IP_ADDRESS CDhcpScopeInfo :: QuerySubnetAddress () const
{
return m_p_subnet_info
? m_p_subnet_info->SubnetAddress
: DHCP_IP_ADDRESS_INVALID ;
}
DHCP_IP_MASK CDhcpScopeInfo :: QuerySubnetMask () const
{
return m_p_subnet_info
? m_p_subnet_info->SubnetMask
: DHCP_IP_ADDRESS_INVALID ;
}
DHCP_IP_ADDRESS CDhcpScopeInfo :: QueryHostAddress () const
{
return m_p_subnet_info
? m_p_subnet_info->PrimaryHost.IpAddress
: DHCP_IP_ADDRESS_INVALID ;
}
const WCHAR *
CDhcpScopeInfo :: QueryNetbiosName () const
{
return m_p_subnet_info
? m_p_subnet_info->PrimaryHost.NetBiosName
: NULL ;
}
const WCHAR *
CDhcpScopeInfo :: QueryHostName () const
{
return m_p_subnet_info
? m_p_subnet_info->PrimaryHost.HostName
: NULL ;
}
const WCHAR *
CDhcpScopeInfo :: QuerySubnetName () const
{
return m_p_subnet_info
? m_p_subnet_info->SubnetName
: NULL ;
}
const WCHAR *
CDhcpScopeInfo :: QuerySubnetComment () const
{
return m_p_subnet_info
? m_p_subnet_info->SubnetComment
: NULL ;
}
//
// Update a type value from this scope
//
LONG
CDhcpScope :: QueryType (
CDhcpParamType * pdhcType,
BOOL bUpdateTypeInfo,
BOOL bUpdateValueInfo
) const
{
DHCP_OPTION * pdhpOption = NULL ;
LONG result = (LONG) ::DhcpGetOptionInfo( m_scope_id,
pdhcType->QueryId(),
& pdhpOption ) ;
if ( result == 0 )
{
CATCH_MEM_EXCEPTION
{
if ( bUpdateTypeInfo )
{
pdhcType->SetOptType( pdhpOption->OptionType ) ;
if ( (! pdhcType->SetName( pdhpOption->OptionName ))
|| (! pdhcType->SetComment( pdhpOption->OptionComment )) )
{
result = ERROR_NOT_ENOUGH_MEMORY ;
}
}
if ( result == 0 && bUpdateValueInfo )
{
CDhcpOptionValue dhcOptValue( & pdhpOption->DefaultValue, CDhcpRpcDataWrapper::CDWRAP_Rpc ) ;
result = pdhcType->Update( dhcOptValue ) ;
}
}
END_MEM_EXCEPTION(result)
}
FreeRpcMemory( pdhpOption ) ;
return result ;
}
//
// Create a new type to match the given information
//
LONG
CDhcpScope :: CreateType (
CDhcpParamType * pdhcType
)
{
DHCP_OPTION dhcOption ;
LONG err ;
CDhcpOptionValue * pcOptionValue = NULL ;
CLEAR_TO_ZEROES( & dhcOption ) ;
CATCH_MEM_EXCEPTION
{
//
// Create the structure required for RPC; force inclusion of
// at least one data element to define the data type.
//
pcOptionValue = new CDhcpOptionValue( & pdhcType->QueryValue(), TRUE ) ;
if ( (err = pcOptionValue->QueryError()) == 0 )
{
dhcOption.OptionID = pdhcType->QueryId() ;
dhcOption.OptionName = ::UtilWcstrDup( pdhcType->QueryName() );
dhcOption.OptionComment = ::UtilWcstrDup( pdhcType->QueryComment() ) ;
dhcOption.DefaultValue = pcOptionValue->QueryData() ;
dhcOption.OptionType = pdhcType->QueryOptType() ;
err = (LONG) ::DhcpCreateOption( m_scope_id.QueryWcName(),
pdhcType->QueryId(),
& dhcOption ) ;
delete dhcOption.OptionName ;
delete dhcOption.OptionComment ;
}
}
END_MEM_EXCEPTION(err)
TRACEEOLERR( err, "Create option type " << (int) dhcOption.OptionID
<< " in scope " << m_scope_id
<< " FAILED, error = " << err ) ;
delete pcOptionValue ;
return err ;
}
//
// Delete the type associated with this ID
//
LONG
CDhcpScope :: DeleteType (
DHCP_OPTION_ID dhcid
)
{
return (LONG) ::DhcpRemoveOption( m_scope_id, dhcid ) ;
}
LONG
CDhcpScope :: GetMibInfo (
LPDHCP_MIB_INFO * mibInfo
) const
{
return (LONG) :: DhcpGetMibInfo ( m_scope_id, mibInfo ) ;
}
//
// Scan/reconcile database
//
LONG
CDhcpScope :: ScanDatabase (
DWORD FixFlag,
LPDHCP_SCAN_LIST *ScanList
)
{
return (LONG) :: DhcpScanDatabase (
m_scope_id,
m_scope_id.QueryId(),
FixFlag,
ScanList
);
}
//
// Enumerate all options and their values
//
LONG
CDhcpScope :: EnumOptions (
LPDHCP_OPTION_ARRAY * pOptionsArray,
DWORD * pOptionsRead,
DWORD * pOptionsTotal
) const
{
DHCP_RESUME_HANDLE ResumeHandle = 0;
return (LONG) ::DhcpEnumOptions(
m_scope_id,
&ResumeHandle,
0xFFFFFFFF, // get all.
pOptionsArray,
pOptionsRead,
pOptionsTotal );
}
//
// Internal method to perform API
//
LONG
CDhcpScope :: SetValue (
CDhcpParamType * pdhcType,
DHCP_OPTION_SCOPE_TYPE dhcOptType,
DHCP_IP_ADDRESS dhipaReservation
)
{
LONG err = 0 ;
DHCP_OPTION_DATA dhcOptionData ;
DHCP_OPTION_SCOPE_INFO dhcScopeInfo ;
CDhcpOptionValue * pcOptionValue = NULL ;
CLEAR_TO_ZEROES( & dhcOptionData ) ;
CLEAR_TO_ZEROES( & dhcScopeInfo ) ;
CATCH_MEM_EXCEPTION
{
pcOptionValue = new CDhcpOptionValue( & pdhcType->QueryValue() ) ;
if ( (err = pcOptionValue->QueryError()) == 0 )
{
dhcScopeInfo.ScopeType = dhcOptType ;
//
// Provide the sub-net address if this is a scope-level operation
//
if ( dhcOptType == DhcpSubnetOptions )
{
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_scope_id.QueryId() ;
}
else if ( dhcOptType == DhcpReservedOptions )
{
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation ;
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_scope_id.QueryId() ;
}
dhcOptionData = pcOptionValue->QueryData() ;
err = (LONG) ::DhcpSetOptionValue( m_scope_id,
pdhcType->QueryId(),
& dhcScopeInfo,
& dhcOptionData ) ;
}
}
END_MEM_EXCEPTION(err) ;
delete pcOptionValue ;
return err ;
}
//
// Internal method to perform API
//
LONG
CDhcpScope :: GetValue (
DHCP_OPTION_ID OptionID,
DHCP_OPTION_SCOPE_TYPE dhcOptType,
DHCP_OPTION_VALUE ** ppdhcOptionValue,
DHCP_IP_ADDRESS dhipaReservation
)
{
LONG err = 0 ;
DHCP_OPTION_SCOPE_INFO dhcScopeInfo ;
CLEAR_TO_ZEROES( & dhcScopeInfo ) ;
CATCH_MEM_EXCEPTION
{
dhcScopeInfo.ScopeType = dhcOptType ;
//
// Provide the sub-net address if this is a scope-level operation
//
if ( dhcOptType == DhcpSubnetOptions )
{
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_scope_id.QueryId() ;
}
else if ( dhcOptType == DhcpReservedOptions )
{
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation ;
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_scope_id.QueryId() ;
}
err = (LONG) ::DhcpGetOptionValue( m_scope_id,
OptionID,
& dhcScopeInfo,
ppdhcOptionValue ) ;
}
END_MEM_EXCEPTION(err) ;
return err ;
}
LONG
CDhcpScope :: RemoveValue (
DHCP_OPTION_ID dhcOptId,
DHCP_OPTION_SCOPE_TYPE dhcOptType,
DHCP_IP_ADDRESS dhipaReservation
)
{
DHCP_OPTION_SCOPE_INFO dhcScopeInfo ;
CLEAR_TO_ZEROES( & dhcScopeInfo ) ;
dhcScopeInfo.ScopeType = dhcOptType ;
//
// Provide the sub-net address if this is a scope-level operation
//
if ( dhcOptType == DhcpSubnetOptions )
{
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_scope_id.QueryId() ;
}
else if ( dhcOptType == DhcpReservedOptions )
{
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation;
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_scope_id.QueryId();
}
return (LONG) ::DhcpRemoveOptionValue( m_scope_id,
dhcOptId,
& dhcScopeInfo ) ;
}
//
// Client database access routines
//
// CreateClient() creates a reservation for a client. The act
// of adding a new reserved IP address causes the DHCP server
// to create a new client record; we then set the client info
// for this newly created client.
//
// See DHCPLEAS.CPP for further explanation of the relationship
// between reservations and clients.
//
LONG
CDhcpScope :: CreateClient (
const CDhcpClient * pcClient
)
{
APIERR err = 0 ;
//
// Construct the RPC data structure necessary.
//
CDhcpSubnetElement cSubnetElement( *pcClient ) ;
do
{
if ( err = cSubnetElement.QueryError() )
{
break ;
}
if ( err = AddElement( cSubnetElement.QueryInfo() ) )
{
break ;
}
err = SetClientInfo( pcClient ) ;
}
while ( FALSE ) ;
return err ;
}
LONG
CDhcpScope :: SetClientInfo (
const CDhcpClient * pcClient
)
{
APIERR err = 0 ;
//
// Construct the RPC data structure necessary.
//
CDhcpClientInfo cClientInfo( *pcClient ) ;
if ( (err = cClientInfo.QueryError()) == 0 )
{
err = ::DhcpSetClientInfo( m_scope_id.QueryWcName(),
cClientInfo.QueryInfo() ) ;
}
return err ;
}
//
// DeleteClient(); If it's a reservation, remove it. This
// causes the server to delete the client record. If not,
// use the "delete client" API.
// See comment above on CreateClient() for further details.
//
LONG
CDhcpScope :: DeleteClient (
const CDhcpClient * pcClient
)
{
APIERR err = 0 ;
//
// Construct the RPC data structure necessary.
//
CDhcpSubnetElement cSubnetElement( *pcClient ) ;
do
{
//
//. Verify construction of the API wrapper object.
//
if ( err = cSubnetElement.QueryError() )
{
break ;
}
//
// If this is a reservation, remove it.
//
if ( pcClient->IsReservation() )
{
//
// Remove the reservation element with force.
//
err = RemoveElement( cSubnetElement.QueryInfo(), TRUE ) ;
}
else
{
//
// This is an automatic client. Use a different API.
//
DHCP_SEARCH_INFO searchInfo ;
searchInfo.SearchType = DhcpClientIpAddress ;
searchInfo.SearchInfo.ClientIpAddress = pcClient->QueryIpAddress() ;
err = ::DhcpDeleteClientInfo( m_scope_id.QueryWcName(), & searchInfo ) ;
}
}
while ( FALSE ) ;
return err ;
}
//
// Delete the scope using force if requested.
//
LONG
CDhcpScope :: Delete (
BOOL bUseForce
)
{
return ::DhcpDeleteSubnet( m_scope_id.QueryWcName(),
QueryId(),
bUseForce ? DhcpFullForce : DhcpNoForce ) ;
}
CDhcpEnumScopeElements :: CDhcpEnumScopeElements (
const CDhcpScopeId & cScopeId,
DHCP_SUBNET_ELEMENT_TYPE dhcElementType
)
: m_scope_id( cScopeId ),
m_resume_handle( NULL ),
m_pa_elements( NULL ),
m_c_elements_read( 0 ),
m_c_elements_total( 0 ),
m_element_type( dhcElementType ),
m_c_next( -1 ),
m_c_preferred( DHCP_RPC_PREFERRED_SIZE ),
m_pip_subnet( NULL ),
m_p_subnet_info( NULL )
{
}
CDhcpEnumScopeElements :: CDhcpEnumScopeElements (
const CHostName & cHostName
)
: m_scope_id( cHostName, DHCP_IP_ADDRESS_INVALID ),
m_resume_handle( NULL ),
m_pa_elements( NULL ),
m_c_elements_read( 0 ),
m_c_elements_total( 0 ),
m_element_type( (DHCP_SUBNET_ELEMENT_TYPE) DHC_ENUM_INVALID ),
m_c_next( -1 ),
m_c_preferred( DHCP_RPC_PREFERRED_SIZE ),
m_pip_subnet( NULL ),
m_p_subnet_info( NULL )
{
}
CDhcpEnumScopeElements :: ~ CDhcpEnumScopeElements ()
{
FreeRpcMemory( m_pip_subnet ) ;
FreeRpcMemory( m_p_subnet_info ) ;
FreeRpcMemory( m_pa_elements );
}
const DHCP_SUBNET_ELEMENT_DATA *
CDhcpEnumScopeElements :: QueryElement(
DHCP_SUBNET_ELEMENT_TYPE dhcElementType
) const
{
if ( dhcElementType != m_element_type )
{
return NULL ;
}
ASSERT( m_c_next >= 0 && m_c_next < (INT)m_c_elements_read ) ;
ASSERT( m_pa_elements != NULL ) ;
if ( m_pa_elements == NULL )
{
return NULL ;
}
ASSERT( m_c_next < (INT)m_pa_elements->NumElements ) ;
if ( m_c_next < 0
|| m_c_next >= (INT)m_pa_elements->NumElements
|| m_c_next >= (INT)m_c_elements_read )
{
return NULL ;
}
return & m_pa_elements->Elements[ m_c_next ] ;
}
const DHCP_IP_RANGE *
CDhcpEnumScopeElements :: QueryRange () const
{
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement = QueryElement( DhcpIpRanges ) ;
if ( pdhcElement == NULL )
{
return NULL ;
}
return pdhcElement->Element.IpRange ;
}
const DHCP_HOST_INFO *
CDhcpEnumScopeElements :: QueryHostInfo () const
{
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement = QueryElement( DhcpSecondaryHosts ) ;
if ( pdhcElement == NULL )
{
return NULL ;
}
return pdhcElement->Element.SecondaryHost ;
}
const DHCP_IP_RESERVATION *
CDhcpEnumScopeElements :: QueryReservation () const
{
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement = QueryElement( DhcpReservedIps ) ;
if ( pdhcElement == NULL )
{
return NULL ;
}
return pdhcElement->Element.ReservedIp ;
}
const DHCP_IP_RANGE *
CDhcpEnumScopeElements :: QueryExcludedRange () const
{
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement = QueryElement( DhcpExcludedIpRanges ) ;
if ( pdhcElement == NULL )
{
return NULL ;
}
return pdhcElement->Element.ExcludeIpRange ;
}
const DHCP_IP_CLUSTER *
CDhcpEnumScopeElements :: QueryUsedCluster () const
{
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement = QueryElement( DhcpIpUsedClusters ) ;
if ( pdhcElement == NULL )
{
return NULL ;
}
return pdhcElement->Element.IpUsedCluster ;
}
const DHCP_SUBNET_INFO *
CDhcpEnumScopeElements :: QueryScopeInfo ()
{
if ( m_c_next >= (INT)m_c_elements_read )
{
return NULL ;
}
ASSERT( m_pip_subnet != NULL ) ;
DHCP_IP_ADDRESS dhipa = m_pip_subnet->Elements[m_c_next] ;
FreeRpcMemory( m_p_subnet_info ) ;
m_p_subnet_info = NULL ;
TRACEEOLID( "CDhcpEnumScopeElements: get info for scope " << & dhipa ) ;
LONG err = ::DhcpGetSubnetInfo( m_scope_id,
dhipa,
& m_p_subnet_info ) ;
if ( err )
{
SetApiErr( err ) ;
}
return m_p_subnet_info ;
}
//
// Public "next item" function. Call the proper protected variant.
//
BOOL
CDhcpEnumScopeElements :: Next ()
{
return m_element_type == (DHCP_SUBNET_ELEMENT_TYPE) DHC_ENUM_INVALID
? NextSubnet()
: NextElement() ;
}
BOOL
CDhcpEnumScopeElements :: NextSubnet ()
{
LONG err = 0 ;
if ( m_c_next < 0 || m_c_next + 1 >= (INT)m_c_elements_read )
{
//
// Time to call the API again.
//
if ( m_c_next >= 0 && m_c_next + 1 >= (INT)m_c_elements_total )
{
//
// No point in calling the API.
//
return FALSE ;
}
FreeRpcMemory( m_pip_subnet ) ;
m_pip_subnet = NULL ;
m_pa_elements = NULL ;
err = ::DhcpEnumSubnets( m_scope_id,
& m_resume_handle,
m_c_preferred,
& m_pip_subnet,
& m_c_elements_read,
& m_c_elements_total ) ;
if ( err )
{
if ( err != ERROR_NO_MORE_ITEMS )
{
SetApiErr( err ) ;
}
}
else
{
//
// BUGBUG: Get Madan to fix this
//
if ( m_c_elements_read == 0 )
{
err = ERROR_NO_MORE_ITEMS ;
}
}
if ( err )
{
m_c_elements_read = 0 ;
}
m_c_next = 0 ;
}
else
{
m_c_next++ ;
}
return err == 0 ;
}
//
// Retrieve the next element from the internal buffer or get more via the API.
//
BOOL
CDhcpEnumScopeElements :: NextElement ()
{
LONG err = 0 ;
if ( m_c_next < 0 || m_c_next + 1 >= (INT)m_c_elements_read )
{
//
// Time to call the API again.
//
if ( m_c_next >= 0 && m_c_next >= (INT)m_c_elements_total )
{
//
// No point in calling the API.
//
return FALSE ;
}
FreeRpcMemory( m_pa_elements ) ;
m_pa_elements = NULL ;
m_c_elements_total = m_c_elements_read = 0 ;
err = ::DhcpEnumSubnetElements( m_scope_id,
m_scope_id.QueryId(),
m_element_type,
& m_resume_handle,
m_c_preferred,
& m_pa_elements,
& m_c_elements_read,
& m_c_elements_total ) ;
if ( err == 0 || err == ERROR_MORE_DATA )
{
//
// BUGBUG: Get Madan to fix this.
//
if ( m_c_elements_read == 0 )
{
if ( m_pa_elements != NULL )
{
FreeRpcMemory( m_pa_elements ) ;
m_pa_elements = NULL ;
}
err = ERROR_NO_MORE_ITEMS ;
}
else
{
err = 0 ;
}
m_c_next = 0 ;
}
else
{
if ( err != ERROR_NO_MORE_ITEMS )
{
SetApiErr( err ) ;
}
ASSERT( m_pa_elements == NULL ) ;
}
}
else
{
m_c_next++ ;
}
return err == 0 ;
}
CDhcpEnumOptionValues :: CDhcpEnumOptionValues (
const CDhcpScopeId & cScopeId,
DHCP_OPTION_SCOPE_TYPE dhcOptionType
)
: m_scope_id( cScopeId ),
m_resume_handle( NULL ),
m_pa_elements( NULL ),
m_c_elements_read( 0 ),
m_c_elements_total( 0 ),
m_c_next( -1 ),
m_c_preferred( DHCP_RPC_PREFERRED_SIZE )
{
CLEAR_TO_ZEROES( & dhcOptionInfo ) ;
dhcOptionInfo.ScopeType = dhcOptionType ;
if ( dhcOptionType == DhcpSubnetOptions )
{
dhcOptionInfo.ScopeInfo.SubnetScopeInfo = cScopeId.QueryId() ;
}
}
CDhcpEnumOptionValues :: CDhcpEnumOptionValues (
const CDhcpScopeId & cScopeId,
const DHCP_RESERVED_SCOPE & dhcReservedScope
)
: m_scope_id( cScopeId ),
m_resume_handle( NULL ),
m_pa_elements( NULL ),
m_c_elements_read( 0 ),
m_c_elements_total( 0 ),
m_c_next( -1 ),
m_c_preferred( DHCP_RPC_PREFERRED_SIZE )
{
dhcResScope = dhcReservedScope ;
CLEAR_TO_ZEROES( & dhcOptionInfo ) ;
dhcOptionInfo.ScopeType = DhcpReservedOptions ;
dhcOptionInfo.ScopeInfo.ReservedScopeInfo = dhcResScope ;
}
CDhcpEnumOptionValues :: ~ CDhcpEnumOptionValues ()
{
FreeRpcMemory( m_pa_elements ) ;
}
//
// Set to access next element; returns FALSE if exhausted.
//
BOOL
CDhcpEnumOptionValues :: Next ()
{
LONG err = 0 ;
if ( m_c_next < 0 || m_c_next + 1 >= (INT)m_c_elements_read )
{
//
// Time to call the API again.
//
if ( m_c_next >= 0 && m_c_next + 1 >= (INT)m_c_elements_total )
{
//
// No point in calling the API.
//
return FALSE ;
}
FreeRpcMemory( m_pa_elements ) ;
m_pa_elements = NULL ;
err = ::DhcpEnumOptionValues( m_scope_id,
& dhcOptionInfo,
& m_resume_handle,
m_c_preferred,
& m_pa_elements,
& m_c_elements_read,
& m_c_elements_total ) ;
if ( err )
{
SetApiErr( err ) ;
}
else
{
//
// BUGBUG: What's this? Get a fix
//
if ( m_c_elements_read == 0 )
{
TRACEEOLID( "DhcpEnumOptionValues() returned no error but no elements were read" ) ;
err = ERROR_NO_MORE_ITEMS ;
}
m_c_next = 0 ;
}
}
else
{
m_c_next++ ;
}
return err == 0 ;
}
//
// Access next element from enumeration.
//
const DHCP_OPTION_VALUE *
CDhcpEnumOptionValues :: QueryNext () const
{
if ( m_c_next < 0 )
{
return NULL ;
}
ASSERT( m_c_next < (INT)m_c_elements_read ) ;
ASSERT( m_pa_elements != NULL ) ;
ASSERT( m_c_next < (INT)m_pa_elements->NumElements ) ;
return & m_pa_elements->Values[ m_c_next ] ;
}
BOOL
CDhcpScope :: InitInfo (
const DHCP_SUBNET_INFO * pdhcSubnetInfo
)
{
LONG err = 0 ;
BOOL bCallApi ;
DHCP_SUBNET_INFO * pdhcSnInfo = NULL ;
//
// Call the API if necessary.
//
if ( bCallApi = pdhcSubnetInfo == NULL )
{
err = ::DhcpGetSubnetInfo( m_scope_id,
m_scope_id.QueryId(),
& pdhcSnInfo ) ;
pdhcSubnetInfo = pdhcSnInfo ;
}
CATCH_MEM_EXCEPTION
{
do
{
if ( err )
{
break;
}
m_subnet_state = pdhcSubnetInfo->SubnetState ;
TRACEEOLID( "CDhcpScope :: InitInfo "
<< m_scope_id
<< " is in state "
<< (int) m_subnet_state ) ;
m_ip_mask = pdhcSubnetInfo->SubnetMask ;
if ( (! ::UtilSetWchar( m_str_name, pdhcSubnetInfo->SubnetName ))
|| (! ::UtilSetWchar( m_str_comment, pdhcSubnetInfo->SubnetComment ) ) )
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
//
// Add the host's IP address to the host list.
// CODEWORK: These should be enumerated from the scope.
//
m_aip_host_addresses.Add( m_scope_id.QueryIpAddress() ) ;
//
// BUGBUG: Should the error from this be recorded?
// What if the scope was not properly constructed?
//
GetIpRange() ;
} while ( FALSE ) ;
}
END_MEM_EXCEPTION( err ) ;
SetApiErr( err ) ;
if ( bCallApi )
{
FreeRpcMemory( pdhcSnInfo ) ;
}
return err == 0 ;
}
//
// Get the IP range for this scope from the server
//
LONG
CDhcpScope :: GetIpRange ()
{
LONG err ;
const DHCP_IP_RANGE * pIpRange ;
CDhcpEnumScopeElements cEnumElements( m_scope_id, DhcpIpRanges ) ;
do
{
if ( err = cEnumElements.QueryError() )
{
break ;
}
if ( ! cEnumElements.Next() )
{
err = cEnumElements.QueryApiErr() ;
break;
}
pIpRange = cEnumElements.QueryRange() ;
if ( pIpRange == NULL )
{
//
// Scope/subnet is degenerate.
// BUGBUG: better error code.
//
err = ERROR_INVALID_PARAMETER ;
break ;
}
m_ip_range = *pIpRange ;
} while ( FALSE ) ;
return err ;
}
LONG
CDhcpScope :: SetInfo ()
{
LONG err = 0 ;
CDhcpScopeInfo cScopeInfo( *this ) ;
do
{
if ( err = cScopeInfo.QueryError() )
{
break ;
}
err = ::DhcpSetSubnetInfo( m_scope_id,
m_scope_id.QueryId(),
cScopeInfo.QueryInfo() ) ;
} while ( FALSE ) ;
if ( err == 0 )
{
SetDirty( TRUE ) ;
}
return err ;
}
//
// Initialize the DWORD array containing the IP addresses of the
// hosts in this scope
//
LONG
CDhcpScope :: InitHostAddressArray ()
{
return ERROR_INVALID_FUNCTION ;
}
//
// Enumerate a list of IP ranges configured for exclusion.
//
LONG
CDhcpScope :: FillExceptionList (
CObOwnedList * pobExcp
)
{
LONG err = 0 ;
const DHCP_IP_RANGE * pdhipr ;
CDhcpEnumScopeElements cEnumElem( QueryScopeId(), DhcpExcludedIpRanges ) ;
//
// Verify construction of the enumerator.
//
if ( err = cEnumElem.QueryError() )
{
return err ;
}
//
// Drain the list
//
pobExcp->RemoveAll() ;
CATCH_MEM_EXCEPTION
{
//
// Walk the enumeration, creating copies as we go.
//
while ( cEnumElem.Next() )
{
if ( (pdhipr = cEnumElem.QueryExcludedRange()) == NULL )
{
break ;
}
pobExcp->AddTail( new CDhcpIpRange( *pdhipr ) ) ;
}
}
END_MEM_EXCEPTION(err)
if ( err )
{
//
// Discard incomplete information set.
//
pobExcp->RemoveAll() ;
}
return err ;
}
//
// Remove a data element from this scope/subnet; PROTECTED
//
LONG
CDhcpScope :: RemoveElement (
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement,
BOOL bForce
)
{
return ::DhcpRemoveSubnetElement( m_scope_id,
m_scope_id.QueryId(),
pdhcElement,
bForce ? DhcpFullForce : DhcpNoForce ) ;
}
//
// Delete the subnet
//
LONG
CDhcpScope :: DeleteSubnet (
BOOL bForce
)
{
return (::DhcpDeleteSubnet( m_scope_id,
m_scope_id.QueryId(),
bForce ? DhcpFullForce : DhcpNoForce));
}
//
// Add a data element to this scope/subnet: PROTECTED.
//
LONG
CDhcpScope :: AddElement (
const DHCP_SUBNET_ELEMENT_DATA * pdhcElement
)
{
TRACEEOLID( m_scope_id << ", add element type " << (int) pdhcElement->ElementType );
return ::DhcpAddSubnetElement( m_scope_id,
m_scope_id.QueryId(),
pdhcElement ) ;
}
//
// Store a list of IP ranges to exclude
//
LONG
CDhcpScope :: StoreExceptionList (
CObOwnedList * pobExcp,
CObOwnedList * pobExcpDeleted,
BOOL bJustDirty
)
{
CObListIter obli( *pobExcp ) ;
CObListIter obliDel( *pobExcpDeleted ) ;
DHCP_SUBNET_ELEMENT_DATA dhcElement ;
DHCP_IP_RANGE dhipr ;
CDhcpIpRange * pobIpRange ;
LONG errDel = 0,
err = 0,
errAdd = 0 ;
//
// First, delete the elements of the deletion list.
// Errors are ignored, since some of the elements are
//
while ( pobIpRange = (CDhcpIpRange *) obliDel.Next() )
{
dhcElement.ElementType = DhcpExcludedIpRanges ;
dhipr = *pobIpRange ;
dhcElement.Element.ExcludeIpRange = & dhipr ;
TRACEEOLID( m_scope_id
<< ", remove excluded range "
<< dhipr );
err = RemoveElement( & dhcElement ) ;
if ( err != 0 && err != ERROR_DHCP_INVALID_RANGE && errDel == 0 )
{
errDel = pobIpRange->SetApiErr( err ) ;
}
}
while ( pobIpRange = (CDhcpIpRange *) obli.Next() )
{
if ( pobIpRange->IsDirty() || ! bJustDirty )
{
dhcElement.ElementType = DhcpExcludedIpRanges ;
dhipr = *pobIpRange ;
dhcElement.Element.ExcludeIpRange = & dhipr ;
TRACEEOLID( m_scope_id
<< ", add excluded range "
<< dhipr );
err = AddElement( & dhcElement ) ;
if ( err != 0 && errAdd == 0 )
{
errAdd = pobIpRange->SetApiErr( err ) ;
}
}
}
return errAdd ? errAdd : errDel ;
}
//
// Create a new scope on this host
//
LONG
CHostName :: CreateScope (
const CDhcpScopeInfo & cScopeInfo
)
{
return ::DhcpCreateSubnet( QueryWcName(),
cScopeInfo.QuerySubnetAddress(),
cScopeInfo.QueryInfo() ) ;
}
//
// Call the the get version number API,
// to determine the DHCP version of this
// host.
//
// Return TRUE for success.
//
BOOL
CHostName::SetVersionNumber()
{
ASSERT(m_wc_name != NULL);
if (m_wc_name == NULL)
{
SetWcName();
}
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dw = ::DhcpGetVersion(m_wc_name, &dwMajorVersion, &dwMinorVersion);
TRACEEOLID ( "DhcpVersion returned " << dw << ". Version is " << dwMajorVersion << "." << dwMinorVersion);
if (dw == RPC_S_PROCNUM_OUT_OF_RANGE)
{
//
// Only in 3.5 was this API not present, so
// set the version to 1.0, and reset the error
//
TRACEEOLID("API Not present, version 1.0 assumed");
dwMajorVersion = 1;
dwMinorVersion = 0;
dw = ERROR_SUCCESS;
}
if (dw == ERROR_SUCCESS)
{
m_liDhcpVersion.LowPart = dwMajorVersion;
m_liDhcpVersion.HighPart = dwMinorVersion;
ASSERT(m_liDhcpVersion.QuadPart >= CHostName::liNT35.QuadPart);
#ifdef _DEBUG
if (m_liDhcpVersion.QuadPart >= CHostName::liNT35.QuadPart)
{
TRACEEOLID( "NT 3.5 API's Supported");
}
if (m_liDhcpVersion.QuadPart >= CHostName::liNT351.QuadPart)
{
TRACEEOLID( "NT 3.51 API's Supported");
}
if (m_liDhcpVersion.QuadPart > CHostName::liNT351.QuadPart)
{
TRACEEOLID( "Service is newer than admin tool");
}
#endif // _DEBUG
return TRUE;
}
return FALSE;
}
//
// Fill a list with option type information from the given scope.
//
LONG
CObListParamTypes ::FillFromScope (
const CDhcpScope & cScope
)
{
//
// Use new API to get the param types
//
LPDHCP_OPTION_ARRAY OptionsArray = NULL;
DWORD OptionsRead;
DWORD OptionsTotal;
DWORD i;
LPDHCP_OPTION Options;
DWORD NumOptions;
LONG err = cScope.EnumOptions (
&OptionsArray,
&OptionsRead,
&OptionsTotal);
if ( err )
{
return err ;
}
//
// Discard all the old data
//
RemoveAll() ;
SetDirty( FALSE ) ;
if (OptionsArray == NULL)
{
// This happens when stressing the server. Perhaps when server is OOM.
return ERROR_OUTOFMEMORY;
}
CATCH_MEM_EXCEPTION
{
Options = OptionsArray->Options;
NumOptions = OptionsArray->NumElements;
if ((NumOptions > 0) && (Options == NULL))
{
ASSERT(FALSE && "Data Inconsistency");
return ERROR_OUTOFMEMORY; // Just in case
}
for( i = 0; i < NumOptions; i++, Options++ )
{
//
// Create the new type object.
//
CDhcpParamType * pdhcType = new CDhcpParamType( *Options ) ;
pdhcType->SetDirty(FALSE);
//
// BUGBUG
//
ASSERT( ! pdhcType->IsDirty() ) ;
//
// Add the new host to the list.
//
AddTail( pdhcType ) ;
//
// BUGBUG
//
ASSERT( ! pdhcType->IsDirty() ) ;
}
}
END_MEM_EXCEPTION(err)
::DhcpRpcFreeMemory( OptionsArray );
OptionsArray = NULL;
/*
CDhcpEnumOptionValues cEnumValues( cScope.QueryScopeId(), m_en_category ) ;
LONG err = cEnumValues.QueryError() ;
if ( err )
{
return err ;
}
// Discard all the old data
RemoveAll() ;
SetDirty( FALSE ) ;
CATCH_MEM_EXCEPTION
{
while ( cEnumValues.Next() )
{
// Create the new type object.
CDhcpParamType * pdhcType = new CDhcpParamType( cScope, *cEnumValues.QueryNext() ) ;
// BUGBUG
ASSERT( ! pdhcType->IsDirty() ) ;
// Add the new host to the list.
AddTail( pdhcType ) ;
// BUGBUG
ASSERT( ! pdhcType->IsDirty() ) ;
}
}
END_MEM_EXCEPTION(err)
*/
return err ;
}
LONG
CObListParamTypes :: FillParams (
const CDhcpScope & cScope,
const CObListParamTypes & colTypes
)
{
CDhcpEnumOptionValues * pcEnumOptions = NULL ;
LONG err = 0 ;
//
// Discard all the old data
//
RemoveAll() ;
SetDirty( FALSE ) ;
CATCH_MEM_EXCEPTION
{
//
// Construct the value enumerator according to the category of information.
//
if ( m_en_category == DhcpReservedOptions )
{
DHCP_RESERVED_SCOPE dhcResvScope ;
dhcResvScope.ReservedIpAddress = m_ip_reservation ;
dhcResvScope.ReservedIpSubnetAddress = cScope.QueryId() ;
pcEnumOptions = new CDhcpEnumOptionValues( cScope.QueryScopeId(), dhcResvScope ) ;
}
else
{
pcEnumOptions = new CDhcpEnumOptionValues( cScope.QueryScopeId(), m_en_category ) ;
}
if ( (err = pcEnumOptions->QueryError()) == 0 )
{
while ( pcEnumOptions->Next() )
{
const DHCP_OPTION_VALUE * pdhcOptionValue = pcEnumOptions->QueryNext() ;
ASSERT( pdhcOptionValue != NULL ) ;
//
// Try to find the reference type in the other list.
//
CDhcpParamType * pdhcTypeRef = colTypes.Find( pdhcOptionValue->OptionID ) ;
if ( pdhcTypeRef )
{
//
// We found it. Construct using enumerated value and base type info.
//
CDhcpParamType * pdhcType = new CDhcpParamType( *pdhcTypeRef, *pdhcOptionValue ) ;
AddTail( pdhcType ) ;
}
}
}
}
END_MEM_EXCEPTION(err)
delete pcEnumOptions ;
return err ;
}
CDhcpEnumClientInfo :: CDhcpEnumClientInfo (
const CDhcpScopeId & cScopeId
)
: m_scope_id( cScopeId ),
m_resume_handle( NULL ),
m_pa_info_array( NULL ),
m_c_elements_read( 0 ),
m_c_elements_total( 0 ),
m_c_next( -1 ),
m_c_preferred( DHCP_RPC_PREFERRED_SIZE )
{
}
CDhcpEnumClientInfo :: ~ CDhcpEnumClientInfo ()
{
FreeRpcMemory( m_pa_info_array ) ;
m_pa_info_array = NULL ;
}
//
// Set to access next element; returns FALSE if exhausted.
//
BOOL
CDhcpEnumClientInfo :: Next ()
{
LONG err = 0 ;
if ( m_c_next < 0 || m_c_next + 1 >= (INT)m_c_elements_read )
{
//
// Time to call the API again.
//
if ( m_c_next >= 0 && m_c_next + 1 >= (INT)m_c_elements_total )
{
//
// No point in calling the API.
//
return FALSE ;
}
FreeRpcMemory( m_pa_info_array ) ;
m_pa_info_array = NULL ;
err = ::DhcpEnumSubnetClients( m_scope_id.QueryWcName(),
m_scope_id.QueryId(),
& m_resume_handle,
m_c_preferred,
& m_pa_info_array,
& m_c_elements_read,
& m_c_elements_total ) ;
if (err == ERROR_MORE_DATA)
{
err = ERROR_SUCCESS;
}
if ( err )
{
SetApiErr( err ) ;
}
else
{
if ( m_c_elements_read == 0 )
{
TRACEEOLID( "DhcpEnumSubnetClients() returned no error but no elements were read" ) ;
err = ERROR_NO_MORE_ITEMS ;
}
m_c_next = 0 ;
}
}
else
{
m_c_next++ ;
}
if (err)
{
// We got an error, so pretend the list is empty
return FALSE;
}
// Otherwise verify if the next element *really* exists
return (NULL != QueryNext());
}
//
// Access next element from enumeration.
//
const DHCP_CLIENT_INFO *
CDhcpEnumClientInfo :: QueryNext () const
{
if ( m_c_next < 0 || m_pa_info_array == NULL)
{
return NULL ;
}
ASSERT( m_c_next < (INT)m_c_elements_read ) ;
ASSERT( m_pa_info_array != NULL ) ;
ASSERT( m_c_next < (INT)m_pa_info_array->NumElements ) ;
return m_pa_info_array->Clients[ m_c_next ] ;
}
// End of DHCPAPI.CPP