/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* general.cpp General classes for the DHCP snapin FILE HISTORY: */ #include "stdafx.h" #include "options.h" #include "nodes.h" const TCHAR g_szDefaultHelpTopic[] = _T("\\help\\dhcpconcepts.chm::/sag_dhcptopnode.htm"); ///////////////////////////////////////////////////////////////////// // // CTimerArray implementation // ///////////////////////////////////////////////////////////////////// CTimerMgr::CTimerMgr() { } CTimerMgr::~CTimerMgr() { CTimerDesc * pTimerDesc; for (INT_PTR i = GetUpperBound(); i >= 0; --i) { pTimerDesc = GetAt(i); if (pTimerDesc->uTimer != 0) FreeTimer(i); delete pTimerDesc; } } int CTimerMgr::AllocateTimer ( ITFSNode * pNode, CDhcpServer * pServer, UINT uTimerValue, TIMERPROC TimerProc ) { CSingleLock slTimerMgr(&m_csTimerMgr); // get a lock on the timer mgr for the scope of this // function. slTimerMgr.Lock(); CTimerDesc * pTimerDesc = NULL; // look for an empty slot for (INT_PTR i = GetUpperBound(); i >= 0; --i) { pTimerDesc = GetAt(i); if (pTimerDesc->uTimer == 0) break; } // did we find one? if not allocate one if (i < 0) { pTimerDesc = new CTimerDesc; Add(pTimerDesc); i = GetUpperBound(); } // // fix null pointer dereference // if ( pTimerDesc == NULL ) { return -1; } pTimerDesc->uTimer = SetTimer(NULL, (UINT) i, uTimerValue, TimerProc); if (pTimerDesc->uTimer == 0) return -1; pTimerDesc->spNode.Set(pNode); pTimerDesc->pServer = pServer; pTimerDesc->timerProc = TimerProc; return (int)i; } void CTimerMgr::FreeTimer ( UINT_PTR uEventId ) { CSingleLock slTimerMgr(&m_csTimerMgr); // get a lock on the timer mgr for the scope of this // function. slTimerMgr.Lock(); CTimerDesc * pTimerDesc; Assert(uEventId <= (UINT) GetUpperBound()); if (uEventId > (UINT) GetUpperBound()) return; pTimerDesc = GetAt((int) uEventId); ::KillTimer(NULL, pTimerDesc->uTimer); pTimerDesc->spNode.Release(); pTimerDesc->pServer = NULL; pTimerDesc->uTimer = 0; } CTimerDesc * CTimerMgr::GetTimerDesc ( UINT_PTR uEventId ) { CSingleLock slTimerMgr(&m_csTimerMgr); // the caller of this function should lock the timer mgr // while accessing this pointer CTimerDesc * pTimerDesc; for (INT_PTR i = GetUpperBound(); i >= 0; --i) { pTimerDesc = GetAt(i); if (pTimerDesc->uTimer == uEventId) return pTimerDesc; } return NULL; } void CTimerMgr::ChangeInterval ( UINT_PTR uEventId, UINT uNewInterval ) { CSingleLock slTimerMgr(&m_csTimerMgr); // get a lock on the timer mgr for the scope of this // function. slTimerMgr.Lock(); Assert(uEventId <= (UINT) GetUpperBound()); if (uEventId > (UINT) GetUpperBound()) return; CTimerDesc tempTimerDesc; CTimerDesc * pTimerDesc; pTimerDesc = GetAt((int) uEventId); // kill the old timer ::KillTimer(NULL, pTimerDesc->uTimer); // set a new one with the new interval pTimerDesc->uTimer = ::SetTimer(NULL, (UINT) uEventId, uNewInterval, pTimerDesc->timerProc); } ///////////////////////////////////////////////////////////////////// // // CDhcpClient implementation // ///////////////////////////////////////////////////////////////////// CDhcpClient::CDhcpClient ( const DHCP_CLIENT_INFO * pdhcClientInfo ) : m_bReservation( FALSE ) { Assert(pdhcClientInfo); InitializeData(pdhcClientInfo); m_bClientType = CLIENT_TYPE_UNSPECIFIED; } CDhcpClient::CDhcpClient ( const DHCP_CLIENT_INFO_V4 * pdhcClientInfo ) : m_bReservation( FALSE ) { Assert(pdhcClientInfo); InitializeData(reinterpret_cast(pdhcClientInfo)); m_bClientType = pdhcClientInfo->bClientType; } void CDhcpClient::InitializeData ( const DHCP_CLIENT_INFO * pdhcClientInfo ) { DWORD err = 0; CATCH_MEM_EXCEPTION { m_dhcpIpAddress = pdhcClientInfo->ClientIpAddress; m_dhcpIpMask = pdhcClientInfo->SubnetMask; m_dtExpires = pdhcClientInfo->ClientLeaseExpires; if ( pdhcClientInfo->ClientName ) { m_strName = pdhcClientInfo->ClientName; } if ( pdhcClientInfo->ClientComment ) { m_strComment = pdhcClientInfo->ClientComment; } if ( pdhcClientInfo->OwnerHost.HostName ) { m_strHostName = pdhcClientInfo->OwnerHost.HostName; } if ( pdhcClientInfo->OwnerHost.NetBiosName ) { m_strHostNetbiosName = pdhcClientInfo->OwnerHost.NetBiosName; } // // Convert the hardware addres // for ( DWORD i = 0 ; i < pdhcClientInfo->ClientHardwareAddress.DataLength ; i++ ) { m_baHardwareAddress.SetAtGrow( i, pdhcClientInfo->ClientHardwareAddress.Data[i] ) ; } } END_MEM_EXCEPTION( err ) ; } CDhcpClient::~CDhcpClient() { } CDhcpClient::CDhcpClient() : m_dhcpIpAddress( 0 ), m_dhcpIpMask( 0 ), m_dhcpIpHost( 0 ), m_bReservation( FALSE ) { m_dtExpires.dwLowDateTime = DHCP_DATE_TIME_ZERO_LOW ; m_dtExpires.dwHighDateTime = DHCP_DATE_TIME_ZERO_HIGH ; } void CDhcpClient::SetHardwareAddress ( const CByteArray & caByte ) { INT_PTR cMax = caByte.GetSize(); m_baHardwareAddress.SetSize( cMax ); for ( int i = 0 ; i < cMax ; i++ ) { m_baHardwareAddress.SetAt( i, caByte.GetAt( i ) ); } } ///////////////////////////////////////////////////////////////////// // // CDhcpIpRange implementation // ///////////////////////////////////////////////////////////////////// CDhcpIpRange::CDhcpIpRange ( DHCP_IP_RANGE dhcpIpRange ) { *this = dhcpIpRange; m_RangeType = DhcpIpRanges; } CDhcpIpRange::CDhcpIpRange() { m_dhcpIpRange.StartAddress = DHCP_IP_ADDRESS_INVALID; m_dhcpIpRange.EndAddress = DHCP_IP_ADDRESS_INVALID; m_RangeType = DhcpIpRanges; } CDhcpIpRange::~CDhcpIpRange() { } // // Sort helper function // /*int CDhcpIpRange::OrderByAddress ( const CObjectPlus * pobIpRange ) const { const CDhcpIpRange * pipr = (CDhcpIpRange *) pobIpRange; // // Derive a comparison result for the end address // int iEndResult = QueryAddr( FALSE ) < QueryAddr( FALSE ) ? -1 : QueryAddr( FALSE ) != QueryAddr( FALSE ); // // Use start address as major sort key, end address as minor. // return QueryAddr( TRUE ) < pipr->QueryAddr( TRUE ) ? -1 : ( QueryAddr( TRUE ) != pipr->QueryAddr( TRUE ) ? 1 : iEndResult ); } */ CDhcpIpRange & CDhcpIpRange::operator = ( const DHCP_IP_RANGE dhcpIpRange ) { m_dhcpIpRange = dhcpIpRange; return *this; } DHCP_IP_ADDRESS CDhcpIpRange::SetAddr ( DHCP_IP_ADDRESS dhcpIpAddress, BOOL bStart ) { DHCP_IP_ADDRESS dhcpIpAddressOld; if ( bStart ) { dhcpIpAddressOld = m_dhcpIpRange.StartAddress; m_dhcpIpRange.StartAddress = dhcpIpAddress; } else { dhcpIpAddressOld = m_dhcpIpRange.EndAddress; m_dhcpIpRange.EndAddress = dhcpIpAddress; } return dhcpIpAddressOld; } BOOL CDhcpIpRange::IsOverlap ( DHCP_IP_RANGE dhcpIpRange ) { BOOL bOverlap = FALSE; if (m_dhcpIpRange.StartAddress <= dhcpIpRange.StartAddress) { if (m_dhcpIpRange.StartAddress == dhcpIpRange.StartAddress) { bOverlap = TRUE; } else if (m_dhcpIpRange.EndAddress >= dhcpIpRange.StartAddress) { bOverlap = TRUE; } } else if (m_dhcpIpRange.StartAddress <= dhcpIpRange.EndAddress) { bOverlap = TRUE; } return bOverlap; } // // Return TRUE if this range is an improper subset of the given range. // BOOL CDhcpIpRange::IsSubset ( DHCP_IP_RANGE dhcpIpRange ) { return (dhcpIpRange.StartAddress <= m_dhcpIpRange.StartAddress) && (dhcpIpRange.EndAddress >= m_dhcpIpRange.EndAddress); } // // Return TRUE if this range is an improper superset of the given range. // BOOL CDhcpIpRange::IsSuperset ( DHCP_IP_RANGE dhcpIpRange ) { return (dhcpIpRange.StartAddress >= m_dhcpIpRange.StartAddress) && (dhcpIpRange.EndAddress <= m_dhcpIpRange.EndAddress); } void CDhcpIpRange::SetRangeType(UINT uRangeType) { m_RangeType = uRangeType; } UINT CDhcpIpRange::GetRangeType() { return m_RangeType; } ///////////////////////////////////////////////////////////////////// // // CDhcpOptionValue implementation // ///////////////////////////////////////////////////////////////////// CDhcpOptionValue::CDhcpOptionValue ( DHCP_OPTION_DATA_TYPE dhcpOptionDataType, INT cUpperBound ) : m_dhcpOptionDataType( dhcpOptionDataType ), m_nUpperBound( -1 ), m_pdhcpOptionDataStruct(NULL) { m_dhcpOptionValue.pCObj = NULL; LONG err = InitValue( dhcpOptionDataType, cUpperBound ); if ( err ) { ASSERT(FALSE); //ReportError( err ); } } // // Copy constructor. // CDhcpOptionValue::CDhcpOptionValue ( const CDhcpOptionValue & cOptionValue ) : m_dhcpOptionDataType( DhcpByteOption ), m_nUpperBound( -1 ), m_pdhcpOptionDataStruct(NULL) { DWORD err = 0; m_dhcpOptionValue.pCObj = NULL; err = SetData(&cOptionValue); if ( err ) { ASSERT(FALSE); //ReportError( err ); } } CDhcpOptionValue::CDhcpOptionValue ( const CDhcpOptionValue * pdhcpValue ) : m_dhcpOptionDataType( DhcpByteOption ), m_nUpperBound( -1 ), m_pdhcpOptionDataStruct(NULL) { LONG err = 0; m_dhcpOptionValue.pCObj = NULL; ASSERT( pdhcpValue != NULL ); err = SetData(pdhcpValue); if (err) { ASSERT(FALSE); //ReportError( err ); } } CDhcpOptionValue::CDhcpOptionValue ( const DHCP_OPTION & dhpType ) : m_dhcpOptionDataType( DhcpByteOption ), m_nUpperBound( -1 ), m_pdhcpOptionDataStruct(NULL) { LONG err = 0; m_dhcpOptionValue.pCObj = NULL; err = SetData((const LPDHCP_OPTION_DATA) &dhpType.DefaultValue); if ( err ) { ASSERT(FALSE); //ReportError( err ); } } CDhcpOptionValue::CDhcpOptionValue ( const DHCP_OPTION_VALUE & dhpOptionValue ) : m_dhcpOptionDataType( DhcpByteOption ), m_nUpperBound( -1 ), m_pdhcpOptionDataStruct(NULL) { LONG err = 0; m_dhcpOptionValue.pCObj = NULL; err = SetData((const LPDHCP_OPTION_DATA) &dhpOptionValue.Value); if ( err ) { ASSERT(FALSE); //ReportError( err ); } } CDhcpOptionValue::~ CDhcpOptionValue () { FreeValue(); if (m_pdhcpOptionDataStruct) FreeOptionDataStruct(); } CDhcpOptionValue & CDhcpOptionValue::operator = ( const CDhcpOptionValue & dhpValue ) { SetData(&dhpValue); return *this; } BOOL CDhcpOptionValue::SetDataType ( DHCP_OPTION_DATA_TYPE dhcType, INT cUpperBound ) { if ( dhcType > DhcpEncapsulatedDataOption ) { return FALSE; } InitValue( dhcType, cUpperBound ); return TRUE; } void CDhcpOptionValue::SetUpperBound ( INT cNewBound ) { if (cNewBound <= 0) cNewBound = 1; if (m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption) { m_nUpperBound = cNewBound; } switch ( m_dhcpOptionDataType ) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: case DhcpIpAddressOption: m_dhcpOptionValue.paDword->SetSize( cNewBound ); break; case DhcpStringDataOption: m_dhcpOptionValue.paString->SetSize( cNewBound ); break; case DhcpDWordDWordOption: m_dhcpOptionValue.paDwordDword->SetSize( cNewBound ); break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: m_dhcpOptionValue.paBinary->SetSize( cNewBound ); break; default: Trace0("CDhcpOptionValue: attempt to set upper bound on invalid value type"); ASSERT( FALSE ); break; } } BOOL CDhcpOptionValue::IsValid () const { return m_nUpperBound > 0; } void CDhcpOptionValue::FreeValue () { // // If there's not a value, return now. // if ( m_dhcpOptionValue.pCObj == NULL || m_nUpperBound < 0 ) { m_dhcpOptionValue.pCObj = NULL; return; } switch ( m_dhcpOptionDataType ) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: case DhcpIpAddressOption: delete m_dhcpOptionValue.paDword; break; case DhcpStringDataOption: delete m_dhcpOptionValue.paString; break; case DhcpDWordDWordOption: delete m_dhcpOptionValue.paDwordDword; break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: delete m_dhcpOptionValue.paBinary; break; default: ASSERT( FALSE ); delete m_dhcpOptionValue.pCObj; break; } m_nUpperBound = -1; m_dhcpOptionDataType = DhcpByteOption; m_dhcpOptionValue.pCObj = NULL; } // // Initialize the data value properly // LONG CDhcpOptionValue::InitValue ( DHCP_OPTION_DATA_TYPE dhcDataType, // The type of value INT cUpperBound, // Maximum upper bound BOOL bProvideDefaultValue // Should an empty default value be provided? ) { LONG err = 0; // // Release any older value. // FreeValue(); // // Initialize the new value // m_dhcpOptionDataType = dhcDataType; m_nUpperBound = cUpperBound <= 0 ? 1 : cUpperBound; CATCH_MEM_EXCEPTION { switch ( m_dhcpOptionDataType ) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: case DhcpIpAddressOption: m_dhcpOptionValue.paDword = new CDWordArray; if ( bProvideDefaultValue) { m_dhcpOptionValue.paDword->SetAtGrow( 0, 0 ); } break; case DhcpStringDataOption: m_dhcpOptionValue.paString = new CStringArray; if ( bProvideDefaultValue ) { m_dhcpOptionValue.paString->SetAtGrow( 0, _T("") ); } break; case DhcpDWordDWordOption: m_dhcpOptionValue.paDwordDword = new CDWordDWordArray; if ( bProvideDefaultValue ) { DWORD_DWORD dwdwValue; dwdwValue.DWord1 = 0; dwdwValue.DWord2 = 0; m_dhcpOptionValue.paDwordDword->SetAtGrow( 0, dwdwValue ); } break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: m_dhcpOptionValue.paBinary = new CByteArray; if ( bProvideDefaultValue ) { m_dhcpOptionValue.paBinary->SetAtGrow( 0, 0 ); } break; default: err = IDS_INVALID_OPTION_DATA; break; } } END_MEM_EXCEPTION(err) return err; } void CDhcpOptionValue::RemoveAll() { // Remove all the entries for this option value LONG err = 0; err = InitValue( QueryDataType(), QueryUpperBound(), TRUE ); ASSERT( err == 0 ); } // CDhcpOptionValue::RemoveAll() LONG CDhcpOptionValue::SetData ( const DHCP_OPTION_DATA * podData ) { LONG err = 0; if ( err = InitValue( podData->Elements[0].OptionType, podData->NumElements, FALSE ) ) { return err; } CATCH_MEM_EXCEPTION { for ( INT i = 0; i < m_nUpperBound; i++ ) { const DHCP_OPTION_DATA_ELEMENT * pElem = &podData->Elements[i]; switch ( m_dhcpOptionDataType ) { case DhcpByteOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pElem->Element.ByteOption ); break; case DhcpWordOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pElem->Element.WordOption ); break; case DhcpDWordOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pElem->Element.DWordOption ); break; case DhcpIpAddressOption: m_dhcpOptionValue.paDword->Add(pElem->Element.IpAddressOption ); break; case DhcpDWordDWordOption: { /* CByteArray * paByte = m_dhcpOptionValue.paBinary; paByte->SetSize( (sizeof (DWORD) / sizeof (BYTE)) * 2 ); DWORD dw = pElem->Element.DWordDWordOption.DWord1; for ( INT j = 0; j < 4; j++ ) { paByte->SetAtGrow(j, (UCHAR)(dw & 0xff) ); dw >>= 8; } dw = pElem->Element.DWordDWordOption.DWord2; for ( ; j < 8; j++ ) { paByte->SetAtGrow(j, (UCHAR)(dw & 0xff) ); dw >>= 8; } */ m_dhcpOptionValue.paDwordDword->SetAtGrow(i, pElem->Element.DWordDWordOption); } break; case DhcpStringDataOption: { CString strTemp; if ( pElem->Element.StringDataOption == NULL ) { strTemp = _T(""); } else { strTemp = pElem->Element.StringDataOption; } m_dhcpOptionValue.paString->SetAtGrow(i, strTemp); } break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: { CByteArray * paByte = m_dhcpOptionValue.paBinary; INT c = pElem->Element.BinaryDataOption.DataLength; paByte->SetSize( c ); for ( INT j = 0; j < c; j++ ) { paByte->SetAtGrow(j, pElem->Element.BinaryDataOption.Data[j] ); } } break; default: err = IDS_INVALID_OPTION_DATA; } // End switch if ( err ) { break; } } // End for } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::SetData ( const CDhcpOptionValue * pOptionValue ) { LONG err = 0; if ( err = InitValue( pOptionValue->QueryDataType(), pOptionValue->QueryUpperBound(), FALSE ) ) { return err; } CATCH_MEM_EXCEPTION { for ( INT i = 0; i < m_nUpperBound; i++ ) { switch ( m_dhcpOptionDataType ) { case DhcpByteOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pOptionValue->m_dhcpOptionValue.paDword->GetAt(i)); break; case DhcpWordOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pOptionValue->m_dhcpOptionValue.paDword->GetAt(i)); break; case DhcpDWordOption: m_dhcpOptionValue.paDword->SetAtGrow(i, pOptionValue->m_dhcpOptionValue.paDword->GetAt(i)); break; case DhcpIpAddressOption: m_dhcpOptionValue.paDword->Add(pOptionValue->m_dhcpOptionValue.paDword->GetAt(i)); break; case DhcpDWordDWordOption: { /* CByteArray * paByte = m_dhcpOptionValue.paBinary; paByte->SetSize( (sizeof (DWORD) / sizeof (BYTE)) * 2 ); for ( INT j = 0; j < 8; j++ ) { paByte->SetAtGrow(j, pOptionValue->m_dhcpOptionValue.paBinary->GetAt(j)); } */ m_dhcpOptionValue.paDwordDword->Add(pOptionValue->m_dhcpOptionValue.paDwordDword->GetAt(i)); } break; case DhcpStringDataOption: { m_dhcpOptionValue.paString->SetAtGrow(i, pOptionValue->m_dhcpOptionValue.paString->GetAt(i)); } break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: { CByteArray * paByte = m_dhcpOptionValue.paBinary; INT_PTR c = pOptionValue->m_dhcpOptionValue.paBinary->GetSize(); paByte->SetSize( c ); for ( INT_PTR j = 0; j < c; j++ ) { paByte->SetAtGrow(j, pOptionValue->m_dhcpOptionValue.paBinary->GetAt(j)); } } break; default: err = IDS_INVALID_OPTION_DATA; } // End switch if ( err ) { break; } } // End for } END_MEM_EXCEPTION(err) return err; } INT CDhcpOptionValue::QueryBinary ( INT index ) const { if ( m_dhcpOptionValue.paBinary->GetUpperBound() < index ) { return -1; } return m_dhcpOptionValue.paBinary->GetAt( index ); } const CByteArray * CDhcpOptionValue::QueryBinaryArray () const { return m_dhcpOptionValue.paBinary; } // // Return a string representation of the current value. // // If fLineFeed is true, seperate each individual value // by a linefeed. Otherwise, by a comma. // LONG CDhcpOptionValue::QueryDisplayString ( CString & strResult, BOOL fLineFeed ) const { CString strBuf; INT i, c; LONG err = 0; LPCTSTR pszDwordDwordMask = _T("0x%08lX%08lX"); LPCTSTR pszMaskDec = _T("%ld"); LPCTSTR pszMaskHex = _T("0x%x"); LPCTSTR pszMaskStr1 = _T("%s"); LPCTSTR pszMaskStr2 = _T("\"%s\""); LPCTSTR pszMaskBin = _T("%2.2x"); LPCTSTR pszMask; LPCTSTR pszMaskEllipsis = _T("..."); LPCTSTR pszSepComma = _T(", "); LPCTSTR pszSepLF = _T("\r\n"); CATCH_MEM_EXCEPTION { strResult.Empty(); for ( i = 0; i < m_nUpperBound; i++ ) { strBuf.Empty(); if ( i ) { strResult += fLineFeed ? pszSepLF : pszSepComma; } switch ( QueryDataType()) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: pszMask = pszMaskHex; strBuf.Format(pszMask, QueryNumber(i)); break; case DhcpStringDataOption: pszMask = m_nUpperBound > 1 ? pszMaskStr2 : pszMaskStr1; strBuf.Format( pszMask, m_dhcpOptionValue.paString->ElementAt( i )); break; case DhcpIpAddressOption: if (!QueryIpAddr(i)) { // Set the string to "" iff the list is empty if (!i) strResult.LoadString (IDS_INFO_FORMAT_IP_NONE); break; } ::UtilCvtIpAddrToWstr(QueryIpAddr(i), &strBuf); break; case DhcpDWordDWordOption: { DWORD_DWORD dwdwValue = QueryDwordDword(i); pszMask = pszDwordDwordMask; strBuf.Format(pszMask, dwdwValue.DWord1, dwdwValue.DWord2); } break; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: for ( c = 0; c < m_dhcpOptionValue.paBinary->GetSize(); c++ ) { if (c) { strBuf += _T(" "); } DWORD dwValue = (BYTE) m_dhcpOptionValue.paBinary->GetAt( c ); CString strTemp; strTemp.Format(pszMaskBin, dwValue); strBuf += strTemp; } // for break; default: strResult.LoadString(IDS_INFO_TYPNAM_INVALID); break; } // switch strResult += strBuf; } // for } // CATCH.... END_MEM_EXCEPTION(err) return err; } // // Return a string representation of the current value. // // LONG CDhcpOptionValue::QueryRouteArrayDisplayString ( CString & strResult ) const { BOOL fLineFeed = FALSE; CString strBuf; INT i, c; LONG err = 0; LPCTSTR pszDwordDwordMask = _T("0x%08lX%08lX"); LPCTSTR pszMaskDec = _T("%ld"); LPCTSTR pszMaskHex = _T("0x%x"); LPCTSTR pszMaskStr1 = _T("%s"); LPCTSTR pszMaskStr2 = _T("\"%s\""); LPCTSTR pszMaskBin = _T("%2.2x"); LPCTSTR pszMask; LPCTSTR pszMaskEllipsis = _T("..."); LPCTSTR pszSepComma = _T(", "); LPCTSTR pszSepLF = _T("\r\n"); CATCH_MEM_EXCEPTION { strResult.Empty(); int bEmpty = TRUE; for ( i = 0; i < m_nUpperBound; i++ ) { if ( i ) { strResult += fLineFeed ? pszSepLF : pszSepComma; } int nDataSize = (int)m_dhcpOptionValue.paBinary->GetSize(); LPBYTE pData = (LPBYTE) m_dhcpOptionValue.paBinary->GetData(); // convert pData to list of ip addresses as per RFC while( nDataSize > sizeof(DWORD) ) { // first 1 byte contains the # of bits in subnetmask nDataSize --; BYTE nBitsMask = *pData ++; DWORD Mask = (~0); if( nBitsMask < 32 ) Mask <<= (32-nBitsMask); // based on the # of bits, the next few bytes contain // the subnet address for the 1-bits of subnet mask int nBytesDest = (nBitsMask+7)/8; if( nBytesDest > 4 ) nBytesDest = 4; DWORD Dest = 0; memcpy( &Dest, pData, nBytesDest ); pData += nBytesDest; nDataSize -= nBytesDest; // subnet address is obviously in network order. Dest = ntohl(Dest); // now the four bytes would be the router address DWORD Router = 0; if( nDataSize < sizeof(DWORD) ) { Assert( FALSE ); break; } memcpy(&Router, pData, sizeof(DWORD)); Router = ntohl( Router ); pData += sizeof(DWORD); nDataSize -= sizeof(DWORD); // now fill the list box.. CString strDest, strMask, strRouter; ::UtilCvtIpAddrToWstr(Dest, &strDest); ::UtilCvtIpAddrToWstr(Mask, &strMask); ::UtilCvtIpAddrToWstr(Router, &strRouter); strBuf += strDest; strBuf += fLineFeed ? pszSepLF : pszSepComma; strBuf += strMask; strBuf += fLineFeed ? pszSepLF : pszSepComma; strBuf += strRouter; bEmpty = FALSE; strBuf += pszSepLF; } strResult += strBuf; } if( bEmpty ) { strResult.LoadString( IDS_INFO_FORMAT_IP_NONE ); } } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::SetString ( LPCTSTR pszNewValue, INT index ) { if ( m_dhcpOptionDataType != DhcpStringDataOption ) { return ERROR_INVALID_PARAMETER; } ASSERT( m_dhcpOptionValue.paString != NULL ); LONG err = 0; CATCH_MEM_EXCEPTION { m_dhcpOptionValue.paString->SetAtGrow( index, pszNewValue ); } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::RemoveString ( INT index ) { if ( m_dhcpOptionDataType != DhcpStringDataOption ) { return ERROR_INVALID_PARAMETER; } ASSERT( m_dhcpOptionValue.paString != NULL ); LONG err = 0; CATCH_MEM_EXCEPTION { m_dhcpOptionValue.paString->RemoveAt( index ); } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::SetNumber ( INT nValue, INT index ) { if ( m_dhcpOptionDataType != DhcpByteOption && m_dhcpOptionDataType != DhcpWordOption && m_dhcpOptionDataType != DhcpDWordOption && m_dhcpOptionDataType != DhcpIpAddressOption && m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption ) { return ERROR_INVALID_PARAMETER; } ASSERT( m_dhcpOptionValue.paDword != NULL ); LONG err = 0; CATCH_MEM_EXCEPTION { if ( m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption) { m_dhcpOptionValue.paDword->SetAtGrow( index, (DWORD) nValue ); } else { m_dhcpOptionValue.paBinary->SetAtGrow( index, (BYTE) nValue ); } } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::RemoveNumber ( INT index ) { if ( m_dhcpOptionDataType != DhcpByteOption && m_dhcpOptionDataType != DhcpWordOption && m_dhcpOptionDataType != DhcpDWordOption && m_dhcpOptionDataType != DhcpIpAddressOption && m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption ) { return ERROR_INVALID_PARAMETER; } ASSERT( m_dhcpOptionValue.paDword != NULL ); LONG err = 0; CATCH_MEM_EXCEPTION { if ( m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption ) { m_dhcpOptionValue.paDword->RemoveAt( index ); } else { m_dhcpOptionValue.paBinary->RemoveAt( index ); } } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::QueryNumber ( INT index ) const { if ( m_dhcpOptionDataType != DhcpByteOption && m_dhcpOptionDataType != DhcpWordOption && m_dhcpOptionDataType != DhcpDWordOption && m_dhcpOptionDataType != DhcpIpAddressOption && m_dhcpOptionDataType != DhcpBinaryDataOption && m_dhcpOptionDataType != DhcpEncapsulatedDataOption ) { return -1; } LONG cResult; if ( m_dhcpOptionDataType == DhcpBinaryDataOption || m_dhcpOptionDataType == DhcpEncapsulatedDataOption ) { ASSERT( m_dhcpOptionValue.paBinary != NULL ); cResult = index < m_dhcpOptionValue.paBinary->GetSize() ? m_dhcpOptionValue.paBinary->GetAt( index ) : -1; } else { ASSERT( m_dhcpOptionValue.paDword != NULL ); cResult = index < m_dhcpOptionValue.paDword->GetSize() ? m_dhcpOptionValue.paDword->GetAt( index ) : -1; } return cResult; } LPCTSTR CDhcpOptionValue::QueryString ( INT index ) const { if ( m_dhcpOptionDataType != DhcpStringDataOption ) { return NULL; } const CString & str = m_dhcpOptionValue.paString->ElementAt( index ); return str; } DHCP_IP_ADDRESS CDhcpOptionValue::QueryIpAddr ( INT index ) const { return (DHCP_IP_ADDRESS) QueryNumber( index ); } LONG CDhcpOptionValue::SetIpAddr ( DHCP_IP_ADDRESS dhcIpAddr, INT index ) { return SetNumber( (INT) dhcIpAddr, index ); } LONG CDhcpOptionValue::RemoveIpAddr ( INT index ) { return RemoveNumber( index ); } BOOL CDhcpOptionValue :: CreateBinaryData ( const DHCP_BINARY_DATA * podBin, DHCP_BINARY_DATA * pobData ) { // // Note: CObject::operator new asserts if data length is zero // pobData->Data = new BYTE [ podBin->DataLength + 1 ] ; if ( pobData == NULL ) { return FALSE ; } pobData->DataLength = podBin->DataLength ; ::memcpy( pobData->Data, podBin->Data, pobData->DataLength ) ; return TRUE ; } BOOL CDhcpOptionValue :: CreateBinaryData ( const CByteArray * paByte, DHCP_BINARY_DATA * pobData ) { // // Note: CObject::operator new asserts if data length is zero // pobData->Data = new BYTE [ (UINT) (paByte->GetSize() + 1) ] ; if ( pobData == NULL ) { return NULL ; } pobData->DataLength = (DWORD) paByte->GetSize() ; for ( INT i = 0 ; i < paByte->GetSize() ; i++ ) { pobData->Data[i] = paByte->GetAt( i ) ; } return TRUE ; } DWORD_DWORD CDhcpOptionValue::QueryDwordDword ( int index ) const { return m_dhcpOptionValue.paDwordDword->ElementAt( index ); } LONG CDhcpOptionValue::SetDwordDword ( DWORD_DWORD dwdwValue, int index ) { LONG err = 0; CATCH_MEM_EXCEPTION { m_dhcpOptionValue.paDwordDword->SetAtGrow( index, dwdwValue ); } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::RemoveDwordDword ( int index ) { LONG err = 0; CATCH_MEM_EXCEPTION { m_dhcpOptionValue.paDwordDword->RemoveAt( index ); } END_MEM_EXCEPTION(err) return err; } LONG CDhcpOptionValue::CreateOptionDataStruct ( // const CDhcpOptionValue * pdhcpOptionValue, LPDHCP_OPTION_DATA * ppOptionData, BOOL bForceType ) { DHCP_OPTION_DATA * podNew = NULL ; DHCP_OPTION_DATA_ELEMENT * podeNew ; LONG err = 0 ; FreeOptionDataStruct() ; INT cElem = QueryUpperBound(); INT cElemMin = cElem ? cElem : 1; INT i, cBytes ; TCHAR * pwcsz ; if ( cElem < 0 || (cElem < 1 && ! bForceType) ) { //ASSERT( FALSE ) ; return ERROR_INVALID_PARAMETER ; } CATCH_MEM_EXCEPTION { // // Allocate the base structure and the array of elements. // cBytes = sizeof *podNew + (cElemMin * sizeof *podeNew) ; podNew = (DHCP_OPTION_DATA *) new BYTE [ cBytes ] ; podeNew = (DHCP_OPTION_DATA_ELEMENT *) ( ((BYTE *) podNew) + sizeof *podNew ) ; ::ZeroMemory(podNew, cBytes); podNew->NumElements = cElem; podNew->Elements = podeNew; // // Initialize each element. If we're forcing an option type def, // just initialize to empty data. // if ( cElem == 0 && bForceType ) { podNew->NumElements = 1 ; podeNew[0].OptionType = QueryDataType() ; switch ( podeNew[0].OptionType ) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: case DhcpIpAddressOption: case DhcpDWordDWordOption: podeNew[0].Element.DWordDWordOption.DWord1 = 0 ; podeNew[0].Element.DWordDWordOption.DWord2 = 0 ; break ; case DhcpStringDataOption: podeNew[0].Element.StringDataOption = new WCHAR [1] ; podeNew[0].Element.StringDataOption[0] = 0 ; break ; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: podeNew[0].Element.BinaryDataOption.DataLength = 0 ; podeNew[0].Element.BinaryDataOption.Data = new BYTE [1] ; break ; default: err = IDS_INVALID_OPTION_DATA ; } } else for ( i = 0 ; i < cElem ; i++ ) { podeNew[i].OptionType = QueryDataType() ; switch ( podeNew[i].OptionType ) { case DhcpByteOption: podeNew[i].Element.ByteOption = (BYTE) QueryNumber( i ) ; break ; case DhcpWordOption: podeNew[i].Element.WordOption = (WORD) QueryNumber( i ) ; break ; case DhcpDWordOption: podeNew[i].Element.DWordOption = QueryNumber( i ) ; break ; case DhcpDWordDWordOption: podeNew[i].Element.DWordDWordOption = QueryDwordDword( i ); break ; case DhcpIpAddressOption: podeNew[i].Element.IpAddressOption = QueryIpAddr( i ) ; break ; case DhcpStringDataOption: { //CString * pstrTemp = new CString (QueryString(i)); CString strTemp = QueryString(i); int nLength = strTemp.GetLength() + 1; TCHAR * pString = new TCHAR[nLength]; ::ZeroMemory(pString, nLength * sizeof(TCHAR)); ::CopyMemory(pString, strTemp, strTemp.GetLength() * sizeof(TCHAR)); podeNew[i].Element.StringDataOption = pString; break; } case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: podNew->NumElements = 1; if ( !CreateBinaryData(QueryBinaryArray(), &podeNew[i].Element.BinaryDataOption) ) { err = ERROR_NOT_ENOUGH_MEMORY ; break ; } break ; default: err = IDS_INVALID_OPTION_DATA ; } if ( err ) { break ; } } } END_MEM_EXCEPTION(err) if ( err == 0 ) { m_pdhcpOptionDataStruct = podNew; *ppOptionData = podNew; } return err ; } LONG CDhcpOptionValue::FreeOptionDataStruct() { LONG err = 0; if ( m_pdhcpOptionDataStruct == NULL ) { return 0 ; } // // We must deconstruct the struct build in CreateData() // INT cElem = m_pdhcpOptionDataStruct->NumElements ; for ( INT i = 0 ; i < cElem ; i++ ) { switch ( m_pdhcpOptionDataStruct->Elements[i].OptionType ) { case DhcpByteOption: case DhcpWordOption: case DhcpDWordOption: case DhcpDWordDWordOption: case DhcpIpAddressOption: break; case DhcpStringDataOption: delete m_pdhcpOptionDataStruct->Elements[i].Element.StringDataOption ; break ; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: delete m_pdhcpOptionDataStruct->Elements[i].Element.BinaryDataOption.Data ; break ; default: err = IDS_INVALID_OPTION_DATA ; break; } if ( err ) { break ; } } // // Finally, delete the main structure // delete m_pdhcpOptionDataStruct ; m_pdhcpOptionDataStruct = NULL ; return err ; } ///////////////////////////////////////////////////////////////////// // // CDhcpOption implementation // ///////////////////////////////////////////////////////////////////// // // Normal constructor: just wrapper the data given // CDhcpOption::CDhcpOption ( const DHCP_OPTION & dhpOption ) : m_dhcpOptionValue( dhpOption ), m_dhcpOptionId( dhpOption.OptionID ), m_dhcpOptionType( dhpOption.OptionType ), m_bDirty(FALSE), m_dwErr(0) { LONG err = 0 ; CATCH_MEM_EXCEPTION { if ( !(SetName(dhpOption.OptionName) && SetComment(dhpOption.OptionComment) ) ) { err = ERROR_NOT_ENOUGH_MEMORY ; } } END_MEM_EXCEPTION(err) if ( err ) { ASSERT(FALSE); //ReportError( err ) ; } } // // Constructor taking just a value structure. We must query // the scope for the name, etc. // CDhcpOption::CDhcpOption ( const DHCP_OPTION_VALUE & dhcpOptionValue, LPCTSTR pszVendor, LPCTSTR pszUserClass ) : m_dhcpOptionValue( dhcpOptionValue ), m_dhcpOptionId( dhcpOptionValue.OptionID ), m_bDirty(FALSE), m_dwErr(0), m_strVendor(pszVendor), m_strClassName(pszUserClass) { } // // Copy constructor // CDhcpOption::CDhcpOption ( const CDhcpOption & dhcpOption ) : m_dhcpOptionId( dhcpOption.m_dhcpOptionId ), m_dhcpOptionType( dhcpOption.m_dhcpOptionType ), m_strName( dhcpOption.m_strName ), m_strComment( dhcpOption.m_strComment ), m_dhcpOptionValue( dhcpOption.QueryDataType() ), m_bDirty(FALSE), m_dwErr(0), m_strVendor( dhcpOption.m_strVendor ), m_strClassName ( dhcpOption.m_strClassName ) { m_dhcpOptionValue = dhcpOption.QueryValue(); } // // Constructor using a base type and an overriding value. // CDhcpOption::CDhcpOption ( const CDhcpOption & dhpType, const DHCP_OPTION_VALUE & dhcOptionValue ) : m_dhcpOptionId( dhpType.m_dhcpOptionId ), m_dhcpOptionType( dhpType.QueryOptType() ), m_strName( dhpType.m_strName ), m_strComment( dhpType.m_strComment ), m_dhcpOptionValue( dhcOptionValue ), m_bDirty(FALSE), m_dwErr(0), m_strVendor(dhpType.m_strVendor), m_strClassName(dhpType.m_strClassName) { } // // Constructor for dynamic instances // CDhcpOption::CDhcpOption ( DHCP_OPTION_ID nId, DHCP_OPTION_DATA_TYPE dhcType, LPCTSTR pszOptionName, LPCTSTR pszComment, DHCP_OPTION_TYPE dhcOptType ) : m_dhcpOptionId( nId ), m_dhcpOptionType( dhcOptType ), m_dhcpOptionValue( dhcType, TRUE ), m_strName( pszOptionName ), m_strComment( pszComment ), m_bDirty(FALSE), m_dwErr(0) { } CDhcpOption::~ CDhcpOption () { } INT CDhcpOption::MaxSizeOfType ( DHCP_OPTION_DATA_TYPE dhcType ) { INT nResult = -1 ; switch ( dhcType ) { case DhcpByteOption: nResult = sizeof(CHAR) ; break ; case DhcpWordOption: nResult = sizeof(WORD) ; break ; case DhcpDWordOption: nResult = sizeof(DWORD) ; break ; case DhcpIpAddressOption: nResult = sizeof(DHCP_IP_ADDRESS) ; break ; case DhcpDWordDWordOption: nResult = sizeof(DWORD_DWORD); break ; case DhcpBinaryDataOption: case DhcpEncapsulatedDataOption: case DhcpStringDataOption: nResult = STRING_LENGTH_MAX ; break ; default: break; } return nResult ; } void CDhcpOption::SetOptType ( DHCP_OPTION_TYPE dhcOptType ) { m_dhcpOptionType = dhcOptType; } LONG CDhcpOption::Update ( const CDhcpOptionValue & dhpOptionValue ) { m_dhcpOptionValue = dhpOptionValue; return 0; } BOOL CDhcpOption::SetName ( LPCTSTR pszName ) { m_strName = pszName; return TRUE; } BOOL CDhcpOption::SetComment ( LPCTSTR pszComment ) { m_strComment = pszComment; return TRUE; } void CDhcpOption::QueryDisplayName ( CString & cStr ) const { cStr.Format(_T("%3.3d %s"), (int) QueryId(), (LPCTSTR) m_strName); } /*--------------------------------------------------------------------------- Class COptionValueEnum Enumerates the options for a given level. Generates a list of nodes. Author: EricDav ---------------------------------------------------------------------------*/ COptionValueEnum::COptionValueEnum() { } /*--------------------------------------------------------------------------- COptionValueEnum::Init() - Author: EricDav ---------------------------------------------------------------------------*/ DWORD COptionValueEnum::Init ( LPCTSTR pServer, LARGE_INTEGER & liVersion, DHCP_OPTION_SCOPE_INFO & dhcpOptionScopeInfo ) { m_strServer = pServer; m_liVersion.QuadPart = liVersion.QuadPart; m_dhcpOptionScopeInfo = dhcpOptionScopeInfo; return 0; } /*--------------------------------------------------------------------------- COptionValueEnum::Copy() Copies another value enum Author: EricDav ---------------------------------------------------------------------------*/ void COptionValueEnum::Copy(COptionValueEnum * pEnum) { CDhcpOption * pOption = NULL; pEnum->Reset(); while (pOption = pEnum->Next()) { AddTail(pOption); } m_liVersion.QuadPart = pEnum->m_liVersion.QuadPart; m_dhcpOptionScopeInfo = pEnum->m_dhcpOptionScopeInfo; } /*--------------------------------------------------------------------------- COptionValueEnum::Remove() removes an option from the list Author: EricDav ---------------------------------------------------------------------------*/ void COptionValueEnum::Remove(DHCP_OPTION_ID optionId, LPCTSTR pszVendor, LPCTSTR pszClass) { CDhcpOption * pOption = NULL; Reset(); while (pOption = Next()) { if ( pOption->QueryId() == optionId && (lstrcmp(pOption->GetVendor(), pszVendor) == 0) && (lstrcmp(pOption->GetClassName(), pszClass) == 0) ) { COptionList::Remove(pOption); delete pOption; break; } } } /*--------------------------------------------------------------------------- COptionValueEnum::Enum() Calls the appropriate enum function depending upon version Author: EricDav ---------------------------------------------------------------------------*/ DWORD COptionValueEnum::Enum() { DWORD dwErr; RemoveAll(); if (m_liVersion.QuadPart >= DHCP_NT5_VERSION) { // enumerate standard plus the vendor and class ID based options dwErr = EnumOptionsV5(); } else { // Enumerate the standard options dwErr = EnumOptions(); } // reset our position pointer to the head Reset(); return dwErr; } /*--------------------------------------------------------------------------- COptionValueEnum::EnumOptions() Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD COptionValueEnum::EnumOptions() { LPDHCP_OPTION_VALUE_ARRAY pOptionValues = NULL; DWORD dwOptionsRead = 0, dwOptionsTotal = 0; DWORD err = ERROR_SUCCESS; HRESULT hr = hrOK; DHCP_RESUME_HANDLE dhcpResumeHandle = NULL; err = ::DhcpEnumOptionValues((LPWSTR) ((LPCTSTR) m_strServer), &m_dhcpOptionScopeInfo, &dhcpResumeHandle, 0xFFFFFFFF, &pOptionValues, &dwOptionsRead, &dwOptionsTotal); Trace4("Server %s - DhcpEnumOptionValues returned %lx, read %d, Total %d.\n", m_strServer, err, dwOptionsRead, dwOptionsTotal); if (dwOptionsRead && dwOptionsTotal && pOptionValues) { for (DWORD i = 0; i < dwOptionsRead; i++) { // // Filter out the "special" option values that we don't want the // user to see. // // CODEWORK: don't filter vendor specifc options... all vendor // specifc options are visible. // if (FilterOption(pOptionValues->Values[i].OptionID)) continue; // // Create the result pane item for this element // CDhcpOption * pOption = new CDhcpOption(pOptionValues->Values[i], NULL, NULL); AddTail(pOption); } ::DhcpRpcFreeMemory(pOptionValues); } if (err == ERROR_NO_MORE_ITEMS) err = ERROR_SUCCESS; return err; } /*--------------------------------------------------------------------------- COptionValueEnum::EnumOptionsV5() Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD COptionValueEnum::EnumOptionsV5() { LPDHCP_OPTION_VALUE_ARRAY pOptionValues = NULL; LPDHCP_ALL_OPTION_VALUES pAllOptions = NULL; DWORD dwNumOptions, err, i; err = ::DhcpGetAllOptionValues((LPWSTR) ((LPCTSTR) m_strServer), 0, &m_dhcpOptionScopeInfo, &pAllOptions); Trace2("Server %s - DhcpGetAllOptionValues (Global) returned %lx\n", m_strServer, err); if (err == ERROR_NO_MORE_ITEMS || err == ERROR_SUCCESS) { if (pAllOptions == NULL) { // This happens when stressing the server. Perhaps when server is OOM. err = ERROR_OUTOFMEMORY; return err; } // get the list of options (vendor and non-vendor) defined for // the NULL class (no class) for (i = 0; i < pAllOptions->NumElements; i++) { CreateOptions(pAllOptions->Options[i].OptionsArray, pAllOptions->Options[i].ClassName, pAllOptions->Options[i].VendorName); } if (pAllOptions) ::DhcpRpcFreeMemory(pAllOptions); } if (err == ERROR_NO_MORE_ITEMS) err = ERROR_SUCCESS; return err; } /*--------------------------------------------------------------------------- COptionValueEnum::CreateOptions() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT COptionValueEnum::CreateOptions ( LPDHCP_OPTION_VALUE_ARRAY pOptionValues, LPCTSTR pClassName, LPCTSTR pszVendor ) { HRESULT hr = hrOK; SPITFSNode spNode; CDhcpOptionItem * pOptionItem; CString strDynBootpClassName; if (pOptionValues == NULL) return hr; Trace1("COptionValueEnum::CreateOptions - Creating %d options\n", pOptionValues->NumElements); COM_PROTECT_TRY { for (DWORD i = 0; i < pOptionValues->NumElements; i++) { // // Filter out the "special" option values that we don't want the // user to see. // // don't filter vendor specifc options... all vendor // specifc options are visible. // // also don't filter out class based options // except for dynamic bootp class if ( (FilterOption(pOptionValues->Values[i].OptionID) && pClassName == NULL && !pszVendor) || (FilterOption(pOptionValues->Values[i].OptionID) && (pClassName && m_strDynBootpClassName.CompareNoCase(pClassName) == 0) && !pszVendor) ) { continue; } // // Create the option // CDhcpOption * pOption = new CDhcpOption(pOptionValues->Values[i], pszVendor, pClassName); AddTail(pOption); } } COM_PROTECT_CATCH return hr; } ///////////////////////////////////////////////////////////////////// // // CDhcpDefaultOptionsOnServer implementation // ///////////////////////////////////////////////////////////////////// LPCTSTR pszResourceName = _T("DHCPOPT") ; LPCTSTR pszResourceType = _T("TEXT") ; const int cchFieldMax = 500 ; OPT_TOKEN aOptToken [] = { { DhcpIpAddressOption, _T("IP Addr") }, { DhcpIpAddressOption, _T("IPAddr") }, { DhcpIpAddressOption, _T("IP Address") }, { DhcpIpAddressOption, _T("IP Pairs") }, { DhcpByteOption, _T("byte") }, { DhcpByteOption, _T("boolean") }, { DhcpByteOption, _T("octet") }, { DhcpWordOption, _T("short") }, { DhcpDWordOption, _T("long") }, { DhcpDWordDWordOption, _T("double") }, { DhcpStringDataOption, _T("string") }, { DhcpBinaryDataOption, _T("binary") }, { DhcpEncapsulatedDataOption, _T("encapsulated") }, { -1, _T("generated") }, { -1, NULL } }; CDhcpDefaultOptionsOnServer::CDhcpDefaultOptionsOnServer() { m_pos = NULL; } CDhcpDefaultOptionsOnServer::~CDhcpDefaultOptionsOnServer() { RemoveAll(); } LONG CDhcpDefaultOptionsOnServer::RemoveAll() { // // Clean the list of all old entries // while (!m_listOptions.IsEmpty()) { delete m_listOptions.RemoveHead(); } return 0; } CDhcpOption * CDhcpDefaultOptionsOnServer::First() { Reset(); return Next(); } CDhcpOption * CDhcpDefaultOptionsOnServer::Next() { return m_pos == NULL ? NULL : m_listOptions.GetNext( m_pos ) ; } void CDhcpDefaultOptionsOnServer::Reset() { m_pos = m_listOptions.GetCount() ? m_listOptions.GetHeadPosition() : NULL ; } CDhcpOption * CDhcpDefaultOptionsOnServer::Find ( DHCP_OPTION_ID dhcpOptionId, LPCTSTR pszVendor ) { POSITION pos = m_listOptions.GetHeadPosition(); CDhcpOption* pCurrent; CDhcpOption* pFound = NULL; CString strVendor = pszVendor; while (pos != NULL) { pCurrent = m_listOptions.GetNext(pos); // check the options IDs and the vendor classes match if ( (pCurrent->QueryId() == dhcpOptionId) && ( (!pszVendor && !pCurrent->GetVendor()) || (pCurrent->GetVendor() && (strVendor.CompareNoCase(pCurrent->GetVendor()) == 0) ) ) ) { pFound = pCurrent; break; } } return pFound; } // Sorts the options by ID LONG CDhcpDefaultOptionsOnServer::SortById() { return m_listOptions.SortById(); } LONG CDhcpDefaultOptionsOnServer::Enumerate ( LPCWSTR pServer, LARGE_INTEGER liVersion ) { if (liVersion.QuadPart >= DHCP_NT5_VERSION) { return EnumerateV5(pServer); } else { return EnumerateV4(pServer); } } LONG CDhcpDefaultOptionsOnServer::EnumerateV4 ( LPCWSTR pServer ) { // // Use new API to get the param types // LPDHCP_OPTION_ARRAY pOptionsArray = NULL; DHCP_RESUME_HANDLE dhcpResumeHandle = NULL; LPDHCP_OPTION Options, pCurOption; DWORD i; DWORD dwNumOptions; DWORD dwOptionsRead; LONG err; err = ::DhcpEnumOptions(pServer, &dhcpResumeHandle, 0xFFFFFFFF, // get all. &pOptionsArray, &dwOptionsRead, &m_dwOptionsTotal ); if ( err ) { return err; } // // Discard all the old data // RemoveAll() ; if (pOptionsArray == NULL) { // This happens when stressing the server. Perhaps when server is OOM. return ERROR_OUTOFMEMORY; } try { Options = pOptionsArray->Options; dwNumOptions = pOptionsArray->NumElements; if ((dwNumOptions > 0) && (Options == NULL)) { ASSERT(FALSE && _T("Data Inconsistency")); return ERROR_OUTOFMEMORY; // Just in case } for(i = 0; i < dwNumOptions; i++) { // // Create the new type object. // pCurOption = Options + i; CDhcpOption * pdhcpOption = new CDhcpOption(*pCurOption); // // Add the new host to the list. // m_listOptions.AddTail(pdhcpOption); } } catch (...) { err = ERROR_NOT_ENOUGH_MEMORY; } ::DhcpRpcFreeMemory(pOptionsArray); pOptionsArray = NULL; Reset(); return err; } LONG CDhcpDefaultOptionsOnServer::EnumerateV5 ( LPCWSTR pServer ) { // // Use new API to get the param types // LPDHCP_OPTION Options, pCurOption; DWORD i; DWORD dwNumOptions = 0; DWORD dwOptionsRead = 0; DWORD dwFlags = 0; LONG err = 0; LPDHCP_ALL_OPTIONS pAllOptions = NULL; err = ::DhcpGetAllOptions((LPWSTR) pServer, dwFlags, &pAllOptions); if ( err ) { if ( NULL != pAllOptions ) { ::DhcpRpcFreeMemory( pAllOptions ); } return err; } // // Discard all the old data // RemoveAll() ; if (pAllOptions == NULL) { // This happens when stressing the server. Perhaps when server is OOM. return ERROR_OUTOFMEMORY; } try { // first pull out the non-vendor options if (pAllOptions->NonVendorOptions != NULL) { Options = pAllOptions->NonVendorOptions->Options; dwNumOptions = pAllOptions->NonVendorOptions->NumElements; } if ((dwNumOptions > 0) && (Options == NULL)) { ASSERT(FALSE && _T("Data Inconsistency")); ::DhcpRpcFreeMemory( pAllOptions ); return ERROR_OUTOFMEMORY; // Just in case } for (i = 0; i < dwNumOptions; i++) { // // Create the new type object. // pCurOption = Options + i; CDhcpOption * pdhcpOption = new CDhcpOption(*pCurOption); // // Add the new host to the list. // m_listOptions.AddTail(pdhcpOption); } // now the vendor options for (i = 0; i < pAllOptions->NumVendorOptions; i++) { pCurOption = &pAllOptions->VendorOptions[i].Option; CDhcpOption * pdhcpOption = new CDhcpOption(*pCurOption); pdhcpOption->SetVendor(pAllOptions->VendorOptions[i].VendorName); // // Add the new host to the list. // m_listOptions.AddTail(pdhcpOption); } } catch (...) { err = ERROR_NOT_ENOUGH_MEMORY; } if (pAllOptions) ::DhcpRpcFreeMemory(pAllOptions); SortById(); Reset(); return err; } ///////////////////////////////////////////////////////////////////// // // CDhcpDefaultOptionsMasterList implementation // ///////////////////////////////////////////////////////////////////// CDhcpDefaultOptionsMasterList::CDhcpDefaultOptionsMasterList() { m_pos = NULL; } CDhcpDefaultOptionsMasterList::~CDhcpDefaultOptionsMasterList() { // // Delete all entries in the list // while (!m_listOptions.IsEmpty()) { delete m_listOptions.RemoveHead(); } } CDhcpOption * CDhcpDefaultOptionsMasterList::First() { Reset(); return Next(); } CDhcpOption * CDhcpDefaultOptionsMasterList::Next() { return m_pos == NULL ? NULL : m_listOptions.GetNext( m_pos ) ; } void CDhcpDefaultOptionsMasterList::Reset() { m_pos = m_listOptions.GetCount() ? m_listOptions.GetHeadPosition() : NULL ; } int CDhcpDefaultOptionsMasterList::GetCount() { return (int)m_listOptions.GetCount(); } long CDhcpDefaultOptionsMasterList::BuildList() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); LONG err = 0 ; CDhcpOption * pOption; HRSRC hRes = NULL ; HGLOBAL hText = NULL ; LPTSTR pszText = NULL ; LPCTSTR pcszText ; size_t cchText = 0; UINT uBufSize = 0; LPTSTR * szParms; TCHAR szUnknown[] = _T("(Unknown)"); // This is just to prevent a GP fault (should not be in resource) CATCH_MEM_EXCEPTION { do { // // IMPORTANT!!! There is no way to determine from the .mc file how many // options are defined. This number is therefore hard-coded // here, and should reflect the highest parameter number in // the .mc file. // // The extra 16 entries are for safety // when calling FormatMessage(). szParms = new LPTSTR[IDS_OPTION_MAX + 16]; Trace0("BuildList - Now building list of option parameters\n"); CString strOptionText; // Initialize the extra entries to something that will not GP fault. for (int i = 0; i < 16; i++) { szParms[IDS_OPTION_MAX+i] = szUnknown; } // // Don't mess with the order of the ID definitions!!! // for (i = 0; i < IDS_OPTION_MAX; ++i) { if (strOptionText.LoadString(IDS_OPTION1 + i)) { ASSERT(strOptionText.GetLength() > 0); uBufSize += strOptionText.GetLength(); szParms[i] = new TCHAR[strOptionText.GetLength()+1]; ::_tcscpy(szParms[i], (LPCTSTR)strOptionText); } else { // // Failed to load the string from the resource // for some reason. // CString strTemp; strTemp.LoadString(IDS_OPTION1 + i); Trace1("BuildList - WARNING: Failed to load option text %s\n", strTemp); err = ::GetLastError(); szParms[i] = szUnknown; // Prevent from GP faulting break; } } if (err != ERROR_SUCCESS) { break; } // allocate a buffer big enough to hold the data uBufSize *= sizeof(TCHAR); uBufSize *= 2; pszText = (LPTSTR) malloc(uBufSize); if (pszText == NULL) { err = ERROR_OUTOFMEMORY; break; } // // Since we are a COM object, get our instance handle to use so that FormatMessage // looks in the right place for our resources. // HINSTANCE hInst = _Module.GetModuleInstance(); while (cchText == 0) { cchText = ::FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, (HMODULE) hInst, // hModule DHCP_OPTIONS, // dwMessageId loaded from a system dll 0L, // dwLanguageId OUT (LPTSTR)pszText, uBufSize/sizeof(TCHAR), (va_list *)szParms); if (cchText == 0) { err = ::GetLastError(); Trace1("BuildList - FormatMessage failed - error %d\n", err); // grow the buffer and try again uBufSize += uBufSize/2; LPTSTR pTemp = (LPTSTR) realloc(pszText, uBufSize); if ( NULL == pTemp ) { err = ERROR_OUTOFMEMORY; break; } else { pszText = pTemp; } } else { // done break; } } // // Walk the resource, parsing each line. If the line converts // to a tangible type, add it to the list. // for ( pcszText = pszText ; pcszText ; ) { scanNextParamType( &pcszText, &pOption); if ( pOption ) { m_listOptions.AddTail(pOption) ; } } } while ( FALSE ) ; } END_MEM_EXCEPTION( err ) for (int i = 0; i < IDS_OPTION_MAX; ++i) { if (szParms[i] != szUnknown) delete[] szParms[i]; } delete[] szParms; free(pszText); Reset(); return NOERROR; } BOOL CDhcpDefaultOptionsMasterList::scanNextParamType ( LPCTSTR * ppszText, CDhcpOption * * ppOption ) { TCHAR szField [ cchFieldMax ] ; TCHAR szName [ cchFieldMax ] ; TCHAR szComment [ cchFieldMax ] ; BOOL bResult = TRUE ; BOOL bArray = FALSE ; int eofld, cch, itype, cbLgt ; LPCTSTR pszText = *ppszText ; CDhcpOption * pOption = NULL ; const DWORD INVALID_OPTION_ID = 0xFFFF; DHCP_OPTION_ID did = INVALID_OPTION_ID; DHCP_OPTION_DATA_TYPE dtype = (DHCP_OPTION_DATA_TYPE)0; for ( eofld = OPTF_OPTION ; pszText = scanNextField( pszText, szField, sizeof szField ) ; eofld++ ) { cch = ::_tcslen( szField ) ; switch ( eofld ) { case OPTF_OPTION: if ( cch > 0 && allDigits( szField ) ) { did = (DHCP_OPTION_ID) ::_ttoi( szField ) ; } else { bResult = FALSE; } break ; case OPTF_NAME: if ( ::_tcslen( szField ) == 0 ) { bResult = FALSE; break ; } ::_tcscpy( szName, szField ) ; break ; case OPTF_TYPE: if ( (itype = recognizeToken( aOptToken, szField )) < 0 ) { Trace2("options CSV ID %d, cannot reconize type %s\n", did, szField); bResult = FALSE ; break ; } dtype = (DHCP_OPTION_DATA_TYPE) itype ; break ; case OPTF_ARRAY_FLAG: bArray = szField[0] == 'y' || szField[0] == 'Y' ; break ; case OPTF_LENGTH: cbLgt = ::_ttoi( szField ) ; break ; case OPTF_DESCRIPTION: ::_tcscpy( szComment, szField ) ; break ; case OPTF_REMARK: case OPTF_MAX: break ; } if ( eofld == OPTF_REMARK || ! bResult ) { pszText = skipToNextLine( pszText ) ; if ( *pszText == 0 ) { pszText = NULL ; } break; } } if (( bResult ) && ( INVALID_OPTION_ID != did )) { pOption = new CDhcpOption( did, dtype, szName, szComment, bArray ? DhcpArrayTypeOption : DhcpUnaryElementTypeOption ) ; } if ( bResult ) { *ppOption = pOption ; } else { delete pOption ; *ppOption = NULL ; } *ppszText = pszText ; return pszText != NULL ; } LPCTSTR CDhcpDefaultOptionsMasterList::scanNextField ( LPCTSTR pszLine, LPTSTR pszOut, int cFieldSize ) { // // Skip junk; return NULL if end-of-buffer. // if ( ! skipWs( & pszLine ) ) { return NULL ; } int cch = 0 ; BOOL bDone = FALSE ; LPTSTR pszField = pszOut ; TCHAR ch ; if ( *pszLine == '\"' ) { // // Quoted string. // while ( ch = *++pszLine ) { if ( ch == '\r' ) { continue ; } if ( ch == '\n' || ch == '\"' || cch == cFieldSize ) { break ; } *pszField++ = ch ; cch++ ; } if ( ch == '\"' ) { pszLine++ ; } } else while ( ! bDone ) { ch = *pszLine++ ; ASSERT( ch != 0 ) ; switch ( ch ) { case '\n': pszLine-- ; // Don't scan past the NL case ',': case '\r': bDone = TRUE ; break ; default: if ( cch < cFieldSize ) { *pszField++ = ch ; cch++ ; } break ; } } // // Trim spaces off the end of the field. // while ( pszField > pszOut && *(pszField-1) == ' ' ) { pszField-- ; } *pszField = 0 ; return pszLine ; } BOOL CDhcpDefaultOptionsMasterList::allDigits ( LPCTSTR psz ) { for ( ; *psz ; psz++ ) { if ( ! isdigit( *psz ) ) { return FALSE ; } } return TRUE ; } int CDhcpDefaultOptionsMasterList::recognizeToken ( OPT_TOKEN * apToken, LPCTSTR pszToken ) { int i ; for ( i = 0 ; apToken[i].pszOptTypeName && ::lstrcmpi( apToken[i].pszOptTypeName, pszToken ) != 0 ; i++ ) ; return apToken[i].eOptType ; } LPCTSTR CDhcpDefaultOptionsMasterList::skipToNextLine ( LPCTSTR pszLine ) { for ( ; *pszLine && *pszLine != '\n' ; pszLine++ ) ; if ( *pszLine ) { pszLine++ ; // Don't overscan buffer delimiter. } return pszLine ; } BOOL CDhcpDefaultOptionsMasterList::skipWs ( LPCTSTR * ppszLine ) { LPCTSTR pszLine ; BOOL bResult = FALSE ; for ( pszLine = *ppszLine ; *pszLine ; pszLine++ ) { switch ( *pszLine ) { case ' ': case '\r': case '\t': break ; default: bResult = TRUE ; break ; } if ( bResult ) { break ; } } *ppszLine = pszLine ; return *pszLine != 0 ; }