mirror of https://github.com/lianthony/NT4.0
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.
498 lines
12 KiB
498 lines
12 KiB
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corp., 1995 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
dhcpopt.cpp
|
|
Defines the class behaviors for the application.
|
|
|
|
FILE HISTORY:
|
|
|
|
This program reads a CSV-formatted Excel spreadsheet containing the standard
|
|
(globally defined) DHCP option information. This data is parsed into
|
|
a CObListParamTypes, each element of which contains a default value.
|
|
|
|
Here are a couple of example lines:
|
|
|
|
|
|
255,End,Generated,-,y,y,1,Indicates end of options in DHCP packet,
|
|
21,Max DG reassembly size,Short,-,n,n,2,Maximum size datagram for reass. by client; max 576,
|
|
22,Default time-to-live,Octet,-,?,y,1,default TTL for client's use on outgoing DGs,
|
|
|
|
The fields, in order, are:
|
|
|
|
Option number, numeric. if this is empty or non-numeric, the line is skipped.
|
|
Option name, string.
|
|
Option type, string. one of "generated", "IP addr", "string", etc.
|
|
Array flag, character: 'Y' if it's an array.
|
|
Length, numeric: length of each element.
|
|
Description, string: comment info
|
|
Remark, string: ignored
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "options.h"
|
|
#include "dhcpopt.h" // From the MC File.
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
const char * pszResourceName = "DHCPOPT" ;
|
|
const char * pszResourceType = "TEXT" ;
|
|
const int cchFieldMax = 500 ;
|
|
|
|
enum OPT_FIELD
|
|
{
|
|
OPTF_OPTION,
|
|
OPTF_NAME,
|
|
OPTF_TYPE,
|
|
OPTF_ARRAY_FLAG,
|
|
OPTF_LENGTH,
|
|
OPTF_DESCRIPTION,
|
|
OPTF_REMARK,
|
|
OPTF_MAX
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
int eOptType ;
|
|
const char * pszOptTypeName ;
|
|
} OPT_TOKEN ;
|
|
|
|
OPT_TOKEN aOptToken [] =
|
|
{
|
|
{ DhcpIpAddressOption, "IP Addr" },
|
|
{ DhcpIpAddressOption, "IPAddr" },
|
|
{ DhcpIpAddressOption, "IP Address" },
|
|
{ DhcpIpAddressOption, "IP Pairs" },
|
|
{ DhcpByteOption, "byte" },
|
|
{ DhcpByteOption, "boolean" },
|
|
{ DhcpByteOption, "octet" },
|
|
{ DhcpWordOption, "short" },
|
|
{ DhcpDWordOption, "long" },
|
|
{ DhcpDWordDWordOption, "double" },
|
|
{ DhcpStringDataOption, "string" },
|
|
{ DhcpBinaryDataOption, "binary" },
|
|
{ -1, "generated" },
|
|
{ -1, NULL }
|
|
};
|
|
|
|
|
|
int
|
|
recognizeToken (
|
|
OPT_TOKEN * apToken,
|
|
const char * pszToken
|
|
)
|
|
{
|
|
int i ;
|
|
for ( i = 0 ;
|
|
apToken[i].pszOptTypeName && ::lstrcmpi( apToken[i].pszOptTypeName, pszToken ) != 0 ;
|
|
i++ ) ;
|
|
|
|
return apToken[i].eOptType ;
|
|
}
|
|
|
|
const char *
|
|
skipToNextLine (
|
|
const char * pszLine
|
|
)
|
|
{
|
|
for ( ; *pszLine && *pszLine != '\n' ; pszLine++ ) ;
|
|
if ( *pszLine )
|
|
{
|
|
pszLine++ ; // Don't overscan buffer delimiter.
|
|
}
|
|
return pszLine ;
|
|
}
|
|
|
|
BOOL
|
|
skipWs (
|
|
const char * * ppszLine
|
|
)
|
|
{
|
|
const char * 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 ;
|
|
}
|
|
|
|
const char *
|
|
scanNextField (
|
|
const char * pszLine,
|
|
char * pszOut,
|
|
int cFieldSize
|
|
)
|
|
{
|
|
//
|
|
// Skip junk; return NULL if end-of-buffer.
|
|
//
|
|
if ( ! skipWs( & pszLine ) )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
int cch = 0 ;
|
|
BOOL bDone = FALSE ;
|
|
char * pszField = pszOut ;
|
|
char 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
|
|
allDigits (
|
|
const char * psz
|
|
)
|
|
{
|
|
for ( ; *psz ; psz++ )
|
|
{
|
|
if ( ! isdigit( *psz ) )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
scanNextParamType (
|
|
const char * * ppszText,
|
|
CDhcpParamType * * ppParamType
|
|
)
|
|
{
|
|
char szField [ cchFieldMax ] ;
|
|
char szName [ cchFieldMax ] ;
|
|
char szComment [ cchFieldMax ] ;
|
|
BOOL bResult = TRUE ;
|
|
BOOL bArray = FALSE ;
|
|
int eofld, cch, itype, cbLgt ;
|
|
const char * pszText = *ppszText ;
|
|
CDhcpParamType * pParamType = NULL ;
|
|
DHCP_OPTION_ID did ;
|
|
DHCP_OPTION_DATA_TYPE dtype ;
|
|
|
|
for ( eofld = OPTF_OPTION ;
|
|
pszText = scanNextField( pszText, szField, sizeof szField ) ;
|
|
eofld++ )
|
|
{
|
|
cch = ::strlen( szField ) ;
|
|
|
|
switch ( eofld )
|
|
{
|
|
case OPTF_OPTION:
|
|
if ( cch > 0 && allDigits( szField ) )
|
|
{
|
|
did = (DHCP_OPTION_ID) ::atoi( szField ) ;
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE ;
|
|
}
|
|
break ;
|
|
|
|
case OPTF_NAME:
|
|
if ( ::strlen( szField ) == 0 )
|
|
{
|
|
bResult = FALSE ;
|
|
break ;
|
|
}
|
|
::strcpy( szName, szField ) ;
|
|
break ;
|
|
|
|
case OPTF_TYPE:
|
|
if ( (itype = recognizeToken( aOptToken, szField )) < 0 )
|
|
{
|
|
TRACEEOLID( "options CSV ID " << did
|
|
<< ", cannot recognize type " << 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 = ::atoi( szField ) ;
|
|
break ;
|
|
case OPTF_DESCRIPTION:
|
|
::strcpy( 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 )
|
|
{
|
|
pParamType = new CDhcpParamType( did, dtype, szName, szComment,
|
|
bArray ? DhcpArrayTypeOption
|
|
: DhcpUnaryElementTypeOption ) ;
|
|
bResult = pParamType->QueryError() == 0 ;
|
|
}
|
|
|
|
if ( bResult )
|
|
{
|
|
*ppParamType = pParamType ;
|
|
}
|
|
else
|
|
{
|
|
delete pParamType ;
|
|
*ppParamType = NULL ;
|
|
}
|
|
|
|
*ppszText = pszText ;
|
|
return pszText != NULL ;
|
|
}
|
|
|
|
//
|
|
// Build the master list of default (global) parameter types and default values.
|
|
//
|
|
CObListParamTypes *
|
|
CDhcpApp :: QueryMasterOptionList ()
|
|
{
|
|
APIERR err = 0 ;
|
|
CObListParamTypes * poblTypes = NULL ;
|
|
CDhcpParamType * pParamType ;
|
|
HRSRC hRes = NULL ;
|
|
HGLOBAL hText = NULL ;
|
|
char * pszText = NULL ;
|
|
const char * pcszText ;
|
|
size_t cchText;
|
|
LPTSTR * szParms;
|
|
char szUnknown[] = "(Unknown)"; // This is just to prevent a GP fault (should not be in resource)
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
do
|
|
{
|
|
/*
|
|
hRes = ::FindResource( m_hInstance,
|
|
pszResourceName,
|
|
pszResourceType ) ;
|
|
if ( hRes == NULL )
|
|
{
|
|
TRACEEOLID( "Unable to find options CSV file resource " << pszResourceName ) ;
|
|
break ;
|
|
}
|
|
|
|
cchText = ::SizeofResource( m_hInstance, hRes ) ;
|
|
|
|
if ( (hText = ::LoadResource( m_hInstance, hRes )) == NULL )
|
|
{
|
|
TRACEEOLID( "Unable to load options CSV file resource " << pszResourceName ) ;
|
|
break ;
|
|
}
|
|
pszText = new char[ cchText + 2 ] ;
|
|
::memcpy( (void *) pszText, ::LockResource( hText ), cchText ) ;
|
|
|
|
for ( cch = 0 ; cch < cchText ; cch++ )
|
|
{
|
|
if ( pszText[cch] == 0 || pszText[cch] == 0x1a )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
pszText[cch] = 0 ;
|
|
*/
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
// BUGBUG (t-danmo): The extra 16 entries are for safety
|
|
// when calling FormatMessage().
|
|
szParms = new LPTSTR[IDS_OPTION_MAX+16];
|
|
|
|
TRACEEOLID("Now building list of option parameters");
|
|
|
|
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);
|
|
szParms[i] = new TCHAR[strOptionText.GetLength()+1];
|
|
::strcpy(szParms[i], (LPCSTR)strOptionText);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to load the string from the resource
|
|
// for some reason.
|
|
//
|
|
TRACEEOLID("WARNING: Failed to load option text " << IDS_OPTION1 + i);
|
|
err = ::GetLastError();
|
|
szParms[i] = szUnknown; // Prevent from GP faulting
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
cchText = ::FormatMessageA(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_FROM_HMODULE
|
|
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
NULL, // hModule
|
|
DHCP_OPTIONS, // dwMessageId loaded from a system dll
|
|
0L, // dwLanguageId
|
|
OUT (LPTSTR)&pszText,
|
|
0,
|
|
(va_list *)szParms
|
|
);
|
|
|
|
if (cchText == 0)
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Walk the resource, parsing each line. If the line converts
|
|
// to a tangible type, add it to the list.
|
|
//
|
|
poblTypes = new CObListParamTypes ;
|
|
|
|
for ( pcszText = pszText ; scanNextParamType( & pcszText, & pParamType ) ; )
|
|
{
|
|
if ( pParamType )
|
|
{
|
|
poblTypes->AddTail( pParamType ) ;
|
|
}
|
|
}
|
|
|
|
} while ( FALSE ) ;
|
|
}
|
|
END_MEM_EXCEPTION( err )
|
|
|
|
//delete pszText ;
|
|
|
|
//if ( hText )
|
|
//{
|
|
//UnlockResource( hText ) ;
|
|
//::FreeResource( hText ) ;
|
|
//}
|
|
|
|
for (int i = 0; i < IDS_OPTION_MAX; ++i)
|
|
{
|
|
if (szParms[i] != szUnknown)
|
|
delete[] szParms[i];
|
|
}
|
|
|
|
delete[] szParms;
|
|
::LocalFree(pszText);
|
|
|
|
return poblTypes ;
|
|
}
|
|
|
|
// End of DHCPMOPT.CPP
|