2636 lines
68 KiB
C
2636 lines
68 KiB
C
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
database.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the functions for interfacing with the JET
|
|
database API.
|
|
|
|
Author:
|
|
|
|
Madan Appiah (madana) 10-Sep-1993
|
|
Manny Weiser (mannyw) 14-Dec-1992
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "dhcppch.h"
|
|
#include <dhcpupg.h>
|
|
#include <mdhcpsrv.h>
|
|
|
|
extern
|
|
DWORD
|
|
DhcpOpenMCastDbTable(
|
|
JET_SESID SessId,
|
|
JET_DBID DbId
|
|
);
|
|
|
|
#define MAX_NO_SESSIONS 10
|
|
#define DATABASE_SYS_FILE "system.mdb"
|
|
#define DATABASE_LOG_FILE "Dhcp.log"
|
|
#define DATABASE_TMP_FILE "Dhcp.tmp"
|
|
#define DATABASE_BASE_NAME "j50"
|
|
|
|
#define CLIENT_TABLE_NAME "ClientTable"
|
|
|
|
#define IPADDRESS_STRING "IpAddress"
|
|
#define HARDWARE_ADDRESS_STRING "HardwareAddress"
|
|
#define STATE_STRING "State"
|
|
#define MACHINE_INFO_STRING "MachineInformation"
|
|
#define MACHINE_NAME_STRING "MachineName"
|
|
#define LEASE_TERMINATE_STRING "LeaseTerminates"
|
|
#define SUBNET_MASK_STRING "SubnetMask"
|
|
#define SERVER_IP_ADDRESS_STRING "ServerIpAddress"
|
|
#define SERVER_NAME_STRING "ServerName"
|
|
#define CLIENT_TYPE "ClientType"
|
|
|
|
//
|
|
// Structure of the DHCP database is as below.
|
|
//
|
|
// Tables - currently DHCP has only one table.
|
|
//
|
|
// 1. ClientTable - this table has 6 columns.
|
|
//
|
|
// Columns :
|
|
//
|
|
// Name Type
|
|
//
|
|
// 1. IpAddress JET_coltypLong - 4-byte integer, signed.
|
|
// 2. HwAddress JET_coltypBinary - Binary data, < 255 bytes.
|
|
// 3. State JET_coltypUnsignedByte - 1-byte integer, unsigned.
|
|
// 4. MachineInfo JET_coltypBinary - Binary data, < 255 bytes.
|
|
// 5. MachineName JET_coltypBinary - Binary data, < 255 bytes.
|
|
// 6. LeaseTermination JET_coltypCurrency - 8-byte integer, signed
|
|
// 7. SubnetMask JET_coltypLong - 4-byte integer, signed
|
|
// 8. ServerIpAddress JET_coltypLong - 4-byte integer, signed
|
|
// 9. ServerName JET_coltypBinary - Binary data, < 255 bytes
|
|
// 10 ClientType JET_coltypUnsignedByte - 1-byte integer, unsigned
|
|
//
|
|
|
|
//
|
|
// global data structure.
|
|
// ColName and ColType are constant, so they are initialized here.
|
|
// ColType is initialized when the database is created or reopened.
|
|
//
|
|
|
|
|
|
STATIC TABLE_INFO ClientTable[] = {
|
|
{ IPADDRESS_STRING , 0, JET_coltypLong },
|
|
{ HARDWARE_ADDRESS_STRING , 0, JET_coltypBinary },
|
|
{ STATE_STRING , 0, JET_coltypUnsignedByte },
|
|
{ MACHINE_INFO_STRING , 0, JET_coltypBinary }, // must modify MACHINE_INFO_SIZE if this changes
|
|
{ MACHINE_NAME_STRING , 0, JET_coltypBinary },
|
|
{ LEASE_TERMINATE_STRING , 0, JET_coltypCurrency },
|
|
{ SUBNET_MASK_STRING , 0, JET_coltypLong },
|
|
{ SERVER_IP_ADDRESS_STRING, 0, JET_coltypLong },
|
|
{ SERVER_NAME_STRING , 0, JET_coltypBinary },
|
|
{ CLIENT_TYPE , 0, JET_coltypUnsignedByte }
|
|
};
|
|
|
|
JET_INSTANCE JetInstance = 0;
|
|
|
|
#define CLIENT_TABLE_NUM_COLS (sizeof(ClientTable) / sizeof(TABLE_INFO))
|
|
|
|
DWORD
|
|
DhcpMapJetError(
|
|
JET_ERR JetError,
|
|
LPSTR CallerInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps the Jet database errors to Windows error.
|
|
|
|
Arguments:
|
|
|
|
JetError - an error JET function call.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
if( JetError == JET_errSuccess ) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
if( JetError < 0 ) {
|
|
|
|
DWORD Error;
|
|
|
|
//
|
|
// Jet Errors.
|
|
//
|
|
|
|
switch( JetError ) {
|
|
case JET_errNoCurrentRecord:
|
|
Error = ERROR_NO_MORE_ITEMS;
|
|
break;
|
|
|
|
case JET_errRecordNotFound: // record not found
|
|
DhcpPrint(( DEBUG_JET, "Jet Record not found.\n" ));
|
|
|
|
Error = ERROR_DHCP_JET_ERROR;
|
|
break;
|
|
|
|
case JET_errKeyDuplicate :
|
|
DhcpAssert(FALSE);
|
|
Error = ERROR_DHCP_JET_ERROR;
|
|
|
|
break;
|
|
|
|
default:
|
|
DhcpPrint(( DEBUG_JET, "Jet Function call failed, %ld.\n",
|
|
JetError ));
|
|
|
|
DhcpServerJetEventLog(
|
|
EVENT_SERVER_JET_ERROR,
|
|
EVENTLOG_ERROR_TYPE,
|
|
JetError,
|
|
CallerInfo);
|
|
|
|
Error = ERROR_DHCP_JET_ERROR;
|
|
}
|
|
|
|
return(Error);
|
|
}
|
|
|
|
//
|
|
// Jet Warnings.
|
|
//
|
|
|
|
DhcpPrint(( DEBUG_JET, "Jet Function call retured warning %ld.\n",
|
|
JetError ));
|
|
|
|
switch( JetError ) {
|
|
|
|
case JET_wrnColumnNull:
|
|
case JET_wrnDatabaseAttached:
|
|
break;
|
|
|
|
default:
|
|
DhcpServerJetEventLog(
|
|
EVENT_SERVER_JET_WARNING,
|
|
EVENTLOG_WARNING_TYPE,
|
|
JetError,
|
|
CallerInfo);
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetOpenKey(
|
|
char *ColumnName,
|
|
PVOID Key,
|
|
DWORD KeySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a key for the named index.
|
|
|
|
Arguments:
|
|
|
|
ColumnName - The column name of an index column.
|
|
|
|
Key - The key to look up.
|
|
|
|
KeySize - The size of the specified key, in bytes.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetSetCurrentIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnName );
|
|
|
|
Error = DhcpMapJetError( JetError, "DhcpJetOpenKey:SetCurrentIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError( JetError, ColumnName );
|
|
return(Error);
|
|
}
|
|
|
|
JetError = JetMakeKey(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
Key,
|
|
KeySize,
|
|
JET_bitNewKey );
|
|
|
|
Error = DhcpMapJetError( JetError, "DhcpJetOpenKey:MakeKey" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError( JetError, ColumnName );
|
|
return(Error);
|
|
}
|
|
|
|
JetError = JetSeek( DhcpGlobalJetServerSession, DhcpGlobalClientTableHandle, JET_bitSeekEQ );
|
|
return( DhcpMapJetError( JetError, "DhcpJetOpenKey:JetSeek" ));
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetBeginTransaction(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions starts a dhcp database transaction.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetBeginTransaction( DhcpGlobalJetServerSession );
|
|
|
|
Error = DhcpMapJetError( JetError, "DhcpJetBeginTransaction" );
|
|
return(Error);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetRollBack(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions rolls back a dhcp database transaction.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetRollback(
|
|
DhcpGlobalJetServerSession,
|
|
0 ); // Rollback the last transaction.
|
|
|
|
Error = DhcpMapJetError( JetError, "DhcpJetRollBack" );
|
|
return(Error);
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetCommitTransaction(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions commits a dhcp database transaction.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetCommitTransaction(
|
|
DhcpGlobalJetServerSession,
|
|
JET_bitCommitLazyFlush);
|
|
|
|
Error = DhcpMapJetError( JetError, "DhcpJetCommitTransaction" );
|
|
return(Error);
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetPrepareUpdate(
|
|
char *ColumnName,
|
|
PVOID Key,
|
|
DWORD KeySize,
|
|
BOOL NewRecord
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function prepares the database for the creation of a new record,
|
|
or updating an existing record.
|
|
|
|
Arguments:
|
|
|
|
ColumnName - The column name of an index column.
|
|
|
|
Key - The key to update/create.
|
|
|
|
KeySize - The size of the specified key, in bytes.
|
|
|
|
NewRecord - TRUE to create the key, FALSE to update an existing key.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
if ( !NewRecord ) {
|
|
JetError = JetSetCurrentIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnName );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetPrepareUpdate:SetCurrentIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError( JetError, ColumnName );
|
|
return( Error );
|
|
}
|
|
|
|
JetError = JetMakeKey(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
Key,
|
|
KeySize,
|
|
JET_bitNewKey );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetPrepareUpdate:MakeKey" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError( JetError, ColumnName );
|
|
return( Error );
|
|
}
|
|
|
|
JetError = JetSeek(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
JET_bitSeekEQ );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetPrepareUpdate:Seek");
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError( JetError, ColumnName );
|
|
return( Error );
|
|
}
|
|
|
|
}
|
|
|
|
JetError = JetPrepareUpdate(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
NewRecord ? JET_prepInsert : JET_prepReplace );
|
|
|
|
return( DhcpMapJetError( JetError, "JetPrepareUpdate:PrepareUpdate" ));
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetCommitUpdate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function commits an update to the database. The record specified
|
|
by the last call to DhcpJetPrepareUpdate() is committed.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
|
|
JetError = JetUpdate(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
NULL,
|
|
0,
|
|
NULL );
|
|
|
|
return( DhcpMapJetError( JetError, "DhcpJetCommitUpdate" ));
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetSetValue(
|
|
JET_COLUMNID KeyColumnId,
|
|
PVOID Data,
|
|
DWORD DataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function updates the value of an entry in the current record.
|
|
|
|
Arguments:
|
|
|
|
KeyColumnId - The Id of the column (value) to update.
|
|
|
|
Data - A pointer to the new value for the column.
|
|
|
|
DataSize - The size of the data, in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetSetColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
KeyColumnId,
|
|
Data,
|
|
DataSize,
|
|
0,
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetSetValue:Setcolumn") ;
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetGetValue(
|
|
JET_COLUMNID ColumnId,
|
|
PVOID Data,
|
|
PDWORD DataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function read the value of an entry in the current record.
|
|
|
|
Arguments:
|
|
|
|
ColumnId - The Id of the column (value) to read.
|
|
|
|
Data - Pointer to a location where the data that is read from the
|
|
database returned, or pointer to a location where data is.
|
|
|
|
DataSize - if the pointed value is non-zero then the Data points to
|
|
a buffer otherwise this function allocates buffer for return data
|
|
and returns buffer pointer in Data.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
DWORD ActualDataSize;
|
|
DWORD NewActualDataSize;
|
|
LPBYTE DataBuffer = NULL;
|
|
|
|
if( *DataSize != 0 ) {
|
|
|
|
JetError = JetRetrieveColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnId,
|
|
Data,
|
|
*DataSize,
|
|
DataSize,
|
|
0,
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetGetValue:RetrieveColumn1" );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// determine the size of data.
|
|
//
|
|
|
|
JetError = JetRetrieveColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnId,
|
|
NULL,
|
|
0,
|
|
&ActualDataSize,
|
|
0,
|
|
NULL );
|
|
|
|
//
|
|
// JET_wrnBufferTruncated is expected warning.
|
|
//
|
|
|
|
if( JetError != JET_wrnBufferTruncated ) {
|
|
Error = DhcpMapJetError( JetError, "JetGetValue:RetrieveColumn2" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
Error = ERROR_SUCCESS;
|
|
}
|
|
|
|
if( ActualDataSize == 0 ) {
|
|
//
|
|
// field is NULL.
|
|
//
|
|
*(LPBYTE *)Data = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
DataBuffer = MIDL_user_allocate( ActualDataSize );
|
|
|
|
if( DataBuffer == NULL ) {
|
|
*(LPBYTE *)Data = NULL;
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
JetError = JetRetrieveColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnId,
|
|
DataBuffer,
|
|
ActualDataSize,
|
|
&NewActualDataSize,
|
|
0,
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "JetGetValue:RetrieveColumn3" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpAssert( ActualDataSize == NewActualDataSize );
|
|
*(LPBYTE *)Data = DataBuffer;
|
|
*DataSize = ActualDataSize;
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// freeup local buffer.
|
|
//
|
|
|
|
if( DataBuffer != NULL ) {
|
|
MIDL_user_free( DataBuffer );
|
|
}
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetPrepareSearch(
|
|
char *ColumnName,
|
|
BOOL SearchFromStart,
|
|
PVOID Key,
|
|
DWORD KeySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function prepares for a search of the client database.
|
|
|
|
Arguments:
|
|
|
|
ColumnName - The column name to use as the index column.
|
|
|
|
SearchFromStart - If TRUE, search from the first record in the
|
|
database. If FALSE, search from the specified key.
|
|
|
|
Key - The key to start the search.
|
|
|
|
KeySize - The size, in bytes, of key.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
|
|
JetError = JetSetCurrentIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
ColumnName );
|
|
|
|
Error = DhcpMapJetError( JetError, "PrepareSearch:SetCurrentIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError(JetError, ColumnName );
|
|
return( Error );
|
|
}
|
|
|
|
if ( SearchFromStart ) {
|
|
JetError = JetMove(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
JET_MoveFirst,
|
|
0 );
|
|
} else {
|
|
JetError = JetMakeKey(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
Key,
|
|
KeySize,
|
|
JET_bitNewKey );
|
|
|
|
Error = DhcpMapJetError( JetError, "PrepareSearch:MakeKey" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpMapJetError(JetError, ColumnName);
|
|
return( Error );
|
|
}
|
|
|
|
JetError = JetSeek(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
JET_bitSeekGT );
|
|
}
|
|
|
|
return( DhcpMapJetError( JetError, "PrepareSearch:Move/Seek" ));
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetNextRecord(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function advances to the next record in a search.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
|
|
JetError = JetMove(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
JET_MoveNext,
|
|
0 );
|
|
|
|
return( DhcpMapJetError( JetError, "JetNextRecord" ) );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpJetDeleteCurrentRecord(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function deletes the current record.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
|
|
JetError = JetDelete( DhcpGlobalJetServerSession, DhcpGlobalClientTableHandle );
|
|
return( DhcpMapJetError( JetError, "DeleteCurrentRecord:Delete" ) );
|
|
}
|
|
|
|
|
|
|
|
DHCP_IP_ADDRESS
|
|
DhcpJetGetSubnetMaskFromIpAddress(
|
|
DHCP_IP_ADDRESS IpAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the SubnetMask of the specified client.
|
|
|
|
Arguments:
|
|
|
|
IpAddress - Client address.
|
|
|
|
|
|
Return Value:
|
|
|
|
SubnetMask of the client.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD Error;
|
|
DWORD Size;
|
|
DHCP_IP_ADDRESS SubnetAddress = 0;
|
|
|
|
Error = DhcpJetOpenKey(
|
|
DhcpGlobalClientTable[IPADDRESS_INDEX].ColName,
|
|
&IpAddress,
|
|
sizeof(IpAddress) );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
return( SubnetAddress );
|
|
}
|
|
|
|
Size = sizeof(SubnetAddress);
|
|
Error = DhcpJetGetValue(
|
|
DhcpGlobalClientTable[SUBNET_MASK_INDEX].ColHandle,
|
|
(LPBYTE)&SubnetAddress,
|
|
&Size );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
SubnetAddress = 0;
|
|
return( SubnetAddress );
|
|
}
|
|
|
|
DhcpAssert( Size == sizeof(SubnetAddress) );
|
|
|
|
return( SubnetAddress );
|
|
}
|
|
|
|
|
|
BOOL
|
|
DhcpGetIpAddressFromHwAddress(
|
|
LPBYTE HardwareAddress,
|
|
BYTE HardwareAddressLength,
|
|
LPDHCP_IP_ADDRESS IpAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function looks up the IP address corresponding to the given
|
|
hardware address.
|
|
|
|
Arguments:
|
|
|
|
HardwareAddress - The hardware to look up.
|
|
HardwareAddressLength - The length of the hardware address.
|
|
IpAddress - Returns the corresponding IP address.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The IP address was found.
|
|
FALSE - The IP address could not be found. *IpAddress = -1.
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
DWORD Size;
|
|
|
|
Error = DhcpJetOpenKey(
|
|
DhcpGlobalClientTable[HARDWARE_ADDRESS_INDEX].ColName,
|
|
HardwareAddress,
|
|
HardwareAddressLength );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Get the ip address information for this client.
|
|
//
|
|
|
|
Size = sizeof( *IpAddress );
|
|
|
|
Error = DhcpJetGetValue(
|
|
DhcpGlobalClientTable[IPADDRESS_INDEX].ColHandle,
|
|
(LPBYTE)IpAddress,
|
|
&Size );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DhcpGetHwAddressFromIpAddress(
|
|
DHCP_IP_ADDRESS IpAddress,
|
|
PBYTE HardwareAddress,
|
|
DWORD HardwareAddressLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function looks up the IP address corresponding to the given
|
|
hardware address.
|
|
|
|
Arguments:
|
|
|
|
IpAddress - Ipaddress of a record whose hw address is requested.
|
|
HardwareAddress - pointer to a buffer where the hw address is returned.
|
|
HardwareAddressLength - length of the above buffer.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The IP address was found.
|
|
FALSE - The IP address could not be found. *IpAddress = -1.
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
DWORD Size;
|
|
|
|
Error = DhcpJetOpenKey(
|
|
DhcpGlobalClientTable[IPADDRESS_INDEX].ColName,
|
|
&IpAddress,
|
|
sizeof(IpAddress) );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Get the ip address information for this client.
|
|
//
|
|
|
|
Error = DhcpJetGetValue(
|
|
DhcpGlobalClientTable[HARDWARE_ADDRESS_INDEX].ColHandle,
|
|
HardwareAddress,
|
|
&HardwareAddressLength );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
DhcpCreateAndInitDatabase(
|
|
CHAR *Connect,
|
|
JET_DBID *DatabaseHandle,
|
|
JET_GRBIT JetBits
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates DHCP database and initializes it.
|
|
|
|
Arguments:
|
|
|
|
Connect - database type. NULL specifies the default engine (blue).
|
|
|
|
DatabaseHandle - pointer database handle returned.
|
|
|
|
JetBits - Create flags.
|
|
|
|
Return Value:
|
|
|
|
JET errors.
|
|
|
|
--*/
|
|
{
|
|
|
|
JET_ERR JetError;
|
|
DWORD Error;
|
|
JET_COLUMNDEF ColumnDef;
|
|
CHAR *IndexKey;
|
|
DWORD i;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
//
|
|
// Create Database.
|
|
//
|
|
|
|
if ( ( strlen( DhcpGlobalOemDatabasePath ) + strlen( DhcpGlobalOemDatabaseName ) + 2 ) < MAX_PATH )
|
|
{
|
|
strcpy( DBFilePath, DhcpGlobalOemDatabasePath );
|
|
strcat( DBFilePath, DHCP_KEY_CONNECT_ANSI );
|
|
strcat( DBFilePath, DhcpGlobalOemDatabaseName );
|
|
}
|
|
|
|
//
|
|
// Convert name to ANSI
|
|
//
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
|
|
JetError = JetCreateDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
DBFilePath,
|
|
Connect,
|
|
DatabaseHandle,
|
|
JetBits );
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateDatabase" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create Table.
|
|
//
|
|
|
|
JetError = JetCreateTable(
|
|
DhcpGlobalJetServerSession,
|
|
*DatabaseHandle,
|
|
CLIENT_TABLE_NAME,
|
|
DB_TABLE_SIZE,
|
|
DB_TABLE_DENSITY,
|
|
&DhcpGlobalClientTableHandle );
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateTable" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create columns.
|
|
//
|
|
|
|
//
|
|
// Init fields of columndef that do not change between addition of
|
|
// columns
|
|
//
|
|
|
|
ColumnDef.cbStruct = sizeof(ColumnDef);
|
|
ColumnDef.columnid = 0;
|
|
ColumnDef.wCountry = 1;
|
|
ColumnDef.langid = DB_LANGID;
|
|
ColumnDef.cp = DB_CP;
|
|
ColumnDef.wCollate = 0;
|
|
ColumnDef.cbMax = 0;
|
|
ColumnDef.grbit = 0; // variable length binary and text data.
|
|
|
|
|
|
for ( i = 0; i < CLIENT_TABLE_NUM_COLS; i++ ) {
|
|
|
|
ColumnDef.coltyp = DhcpGlobalClientTable[i].ColType;
|
|
JetError = JetAddColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[i].ColName,
|
|
&ColumnDef,
|
|
NULL, // no optinal value.
|
|
0,
|
|
&DhcpGlobalClientTable[i].ColHandle );
|
|
|
|
Error = DhcpMapJetError( JetError, "AddColumn" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// finally create index.
|
|
//
|
|
|
|
IndexKey = "+" IPADDRESS_STRING "\0";
|
|
JetError = JetCreateIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[IPADDRESS_INDEX].ColName,
|
|
JET_bitIndexPrimary,
|
|
// ?? JET_bitIndexClustered will degrade frequent
|
|
// update response time.
|
|
IndexKey,
|
|
strlen(IndexKey) + 2, // for two termination chars
|
|
50
|
|
);
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
IndexKey = "+" HARDWARE_ADDRESS_STRING "\0";
|
|
JetError = JetCreateIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[HARDWARE_ADDRESS_INDEX].ColName,
|
|
JET_bitIndexUnique,
|
|
IndexKey,
|
|
strlen(IndexKey) + 2, // for two termination chars
|
|
50
|
|
);
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
IndexKey = "+" MACHINE_NAME_STRING "\0";
|
|
JetError = JetCreateIndex(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[MACHINE_NAME_INDEX].ColName,
|
|
JET_bitIndexIgnoreNull,
|
|
IndexKey,
|
|
strlen(IndexKey) + 2, // for two termination chars + 2, // for two termination chars
|
|
50
|
|
);
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateIndex" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = DhcpOpenMCastDbTable(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalDatabaseHandle);
|
|
|
|
Cleanup:
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
DhcpPrint(( DEBUG_JET, "Database creation failed, %ld.\n", Error ));
|
|
}
|
|
else {
|
|
|
|
DhcpPrint(( DEBUG_JET, "Succssfully Created DHCP database ..\n" ));
|
|
}
|
|
|
|
return(Error);
|
|
}
|
|
|
|
DWORD
|
|
DhcpSetJetParameters(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets all the jet system params.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
|
|
JET_ERR JetError;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
DWORD Error;
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
// First check registry DynLoadJet parameter for value:
|
|
// If it does not exist, then proceed, otherwise,
|
|
// set DhcpGlobalDynLoadJet to this value!
|
|
// Delete the key afterwards, anyways... so that things
|
|
// work right the next time dhcp comes up.
|
|
|
|
// this is to be done.
|
|
|
|
DhcpPrint((DEBUG_MISC, "DhcpJetSetParameters: entered\n"));
|
|
|
|
//
|
|
// set checkpoint file path.
|
|
//
|
|
if ( ( strlen( DhcpGlobalOemDatabasePath ) + 2 ) < MAX_PATH )
|
|
{
|
|
strcpy( DBFilePath, DhcpGlobalOemDatabasePath );
|
|
strcat( DBFilePath, DHCP_KEY_CONNECT_ANSI );
|
|
}
|
|
|
|
//
|
|
// Convert OemPath to Ansi..
|
|
//
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
|
|
DhcpPrint(( DEBUG_MISC,
|
|
"Jet: Using the filepath: %s \n",
|
|
DBFilePath ));
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramSystemPath,
|
|
0,
|
|
DBFilePath );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam SystemPath : %ld\n", JetError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramBaseName,
|
|
0,
|
|
DATABASE_BASE_NAME );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam paramBaseName : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramLogFileSize,
|
|
1024, // 1024kb - default is 5mb
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam paramLogFileSize : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
strcpy( DBFilePath, DhcpGlobalOemDatabasePath );
|
|
strcat( DBFilePath, DHCP_KEY_CONNECT_ANSI );
|
|
|
|
//
|
|
// Convert OEM to ANSI
|
|
//
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
|
|
// maybe TempPath is just a directory name!!
|
|
// the upgrade.doc Appendix is not very clear..
|
|
// It says: TempPath is a pathname and not a filename
|
|
// anymore.... (JET97)
|
|
// Clarification from: cheen liao: pathnames should
|
|
// end in '\' ==> only directory names allowed.
|
|
|
|
DhcpPrint(( DEBUG_MISC, "Jet: tempPath = %s\n",
|
|
DBFilePath ));
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramTempPath,
|
|
0,
|
|
DBFilePath );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam: TempPath : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The max number of buffers for database usage
|
|
//
|
|
// The default number is 500. 600 events are allocated for 500
|
|
// buffers -- Ian 10/21/93. Each buffer is 4K. By keeping the
|
|
// number small, we impact performamce
|
|
//
|
|
|
|
// If you change the # of buffers, be sure to change
|
|
// JET_paramStartFlushThreshold and StopFlushThreshold also!!!
|
|
// Those numbers are percentages of this!
|
|
|
|
// Note that for JET97, JET_paramMaxBuffers has been redefined
|
|
// as JET_paramCacheSizeMax!
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramCacheSizeMax,
|
|
500, // larger buffers take more space but are good for perf
|
|
NULL ); //ignored
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam CacheSizeMax : %ld\n", JetError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramCacheSizeMin,
|
|
4 * MAX_NO_SESSIONS,//see comment near JET_paramMaxSessions on this number
|
|
NULL
|
|
);
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam MaxBuffers : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The max. number of buffers to store old version of a record
|
|
// (snapshot at the start of a transaction) Each version store is 16k
|
|
// bytes. A version store stores structures that hold information
|
|
// derived from a snapshot of the database prior to an insert (20 bytes
|
|
// roughly) or update (size of the record + 20 bytes).
|
|
//
|
|
// For small transactions (i.e. a transaction around each update),
|
|
// this number should be >= the max. number of sessions that can be
|
|
// updating/inserting at the same time. Each session will have one
|
|
// version bucket. Since 16k of version bucket size can result in a
|
|
// lot of wastage per session (since each record is < .5k, and on the
|
|
// average around 50 bytes), it may be better to specify the max. size
|
|
// of the version bucket (<< 16k). Ian will provide a system param for
|
|
// this if we absolutely need it
|
|
//
|
|
// since we serialize the database access with the dhcp server, num.
|
|
// of session will be one.
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramMaxVerPages,
|
|
1500, // 1
|
|
NULL);
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam paramMaxVerPages: %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the File Control Block Param
|
|
//
|
|
// This is the max. number of tables that can be open at any time.
|
|
// If multiple threads open the same table they use the same FCB.
|
|
// FCB is 1 per table/index. Now, for a create database, we need
|
|
// atleast 18 FCBS and 18 IDBS. However apart from create database
|
|
// and ddl operations, we don't need to have these tables open.
|
|
// Default value is 300. Size of an FCB is 112 bytes.
|
|
//
|
|
// we have just one table.
|
|
//
|
|
|
|
// For __JET97, maxopentables and maxopentableindexes are combined
|
|
// here .. So, the # here should be 18 + maxopentableindexes.
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramMaxOpenTables,
|
|
18 + 18 , //10
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam MaxOpenTables: %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the File Usage Control Block to 100. This parameter indicates
|
|
// the max. number of cursors that can be open at any one time. This
|
|
// is therefore dependent on the the max. number of sessions that we
|
|
// can have running concurrently. For each session, there would be 4
|
|
// cursors (for the two tables) + a certain number of internal cursors.
|
|
// For good measure we add a pad. Default value is 300. Size of each
|
|
// is 200 bytes. We use MAX_SESSIONS * 4 + pad (around 100)
|
|
//
|
|
// MAX_SESSION = 1
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramMaxCursors,
|
|
100, //32
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam MaxCursors: %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the number of index description blocks. This is one per
|
|
// table/index. We have two tables each with two indices. We use 9i
|
|
// (see comment for FCBs above). Default value is 300. Size of each
|
|
// is 128 bytes.
|
|
//
|
|
// We have only 2 indices.
|
|
//
|
|
|
|
// note that this parameter is subsumed in JET_paramMaxOpenTables.
|
|
// so, to change this, a corresponding change must be effected there.
|
|
// : JET97
|
|
|
|
|
|
|
|
//
|
|
// Set the Sort Control block. This should be 1 per concurrent Create
|
|
// Index. Default value is 20. Size of each is 612 bytes. In the
|
|
// case of WINS, the main thread creates the indices. We therefore set
|
|
// it to 1.
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramMaxTemporaryTables,
|
|
1,
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam MaxTemporaryTables : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the Number for the Database Attribute Block
|
|
//
|
|
// This is max. number of Open Databases done. Since we can have a
|
|
// max of MAX_NO_SESSIONS at one time. This should be equal to that
|
|
// number (since we have just one database) Default number is 100.
|
|
// Size is 14 bytes
|
|
//
|
|
|
|
//
|
|
// The min percentage of buffers not yet dirtied before
|
|
// background flushing begins
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramStartFlushThreshold,
|
|
(unsigned int) (0.80 * 50) , // 50 is JET_paramMaxBuffer
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam BfThrshldLowPrcnt : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The max percentage of buffers not yet dirtied before
|
|
// background flushing begins
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramStopFlushThreshold,
|
|
(unsigned int) (1.00 * 50 ) , // 50 is JET_parmaMaxBuffer
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam ThrshldHiPrcnt : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// The max. number of sessions that can be open at any time
|
|
//
|
|
// Note: Jet does not preallocate resources corresponding to the max.
|
|
// value. It allocates them dynamically upto the limit -- according to
|
|
// Ian Jose 7/12/93
|
|
//
|
|
// When checked with Ian again on 10/21, he said that they are
|
|
// allocated statically
|
|
//
|
|
|
|
//
|
|
// Note that paramMaxSessions mut be atleast fourtimes > MinBufferSize
|
|
// according to Cheen Liao (10/30/97) - RameshV
|
|
// Just looked at wins code and it appears like
|
|
// Min cache size must be atlast 4 times the size of # of sessions
|
|
// according to Cheen. Presume its my fault in inverting the ienqueality..
|
|
// -- RameshV 05/18/98.
|
|
// so we carefully fix the MinBufferSize variable..
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0,
|
|
JET_paramMaxSessions,
|
|
MAX_NO_SESSIONS,
|
|
NULL );
|
|
|
|
|
|
if( DhcpGlobalDatabaseLoggingFlag ) {
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance, (JET_SESID)0, JET_paramRecovery, 0,
|
|
"on"
|
|
);
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam Recovery %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The number of log sectors. Each sector is 512 bytes. We should
|
|
// keep the size more than the threshold so that if the threshold is
|
|
// reached and flushing starts, Jet can still continue to log in the
|
|
// spare sectors. Point to note is that if the log rate is faster than
|
|
// the flush rate, then the Jet engine thread will not be able to log
|
|
// when the entire buffer is filled up. It will then wait until
|
|
// space becomes available.
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramLogBuffers,
|
|
30, // 30 sectors
|
|
NULL ); //ignored
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam LogBuffers %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the number of log buffers dirtied before they are
|
|
// flushed. This number should always be less than the number
|
|
// for LogBuffers so that spare sectors are there for concurrent
|
|
// logging. Also, we should make this number high enough to
|
|
// handle burst of traffic.
|
|
//
|
|
|
|
// For JET97 this is automaticall set as half of LogBuffers.. and
|
|
// cannot be set by user..
|
|
|
|
//
|
|
// Set the wait time (in msecs) to wait prior to flushing the
|
|
// log on commit transaction to allow other users (sessions) to
|
|
// share the flush
|
|
//
|
|
// This is the time after which the user (a session) will ask
|
|
// the log manager to flush. If we specify 0 here than it means
|
|
// flush every time a transaction commits. In the DHCP server
|
|
// case, every insertion or modification is done under an
|
|
// implicit transaction. So, it means that there will be
|
|
// a flush after every such transaction. It has been seen on a
|
|
// 486/66 (Cheen Liao) machine that it takes roughly 16 msecs to
|
|
// do the flush. The time it takes to do the flush is dependent
|
|
// upon the type of disk (how fast it is), the CPU speed,
|
|
// the type of file system etc. We can for now go with the
|
|
// assumption that it is in the range 15-25 msecs. I am pushing
|
|
// for this WaitTime to be made a session specific param so that
|
|
// it can be changed on the fly if the admin. finds that
|
|
// the DHCP server is slow due to the WaitTime being very low or
|
|
// if it finds it to be so large that in case of a crash, there
|
|
// is possibility to loose a lot of data.
|
|
|
|
|
|
//
|
|
// Making this session specific is also very important for
|
|
// replication where we do want to set it to a high value (high
|
|
// enough to ensure that most of the records that need to be
|
|
// inserted are inserted before a flush action takes place. The
|
|
// wait time would be set every time a bunch of records are pulled
|
|
// in for replication. It will be computed based on the number of
|
|
// records pulled in and the time it takes to insert one record in
|
|
// the jet buffer. The wait time should preferably be < than the
|
|
// above computed time (it does not have to be).
|
|
|
|
// NOTE: In the Pull thread, I will need to start two sessions,
|
|
// one for updating the OwnerId-Version number table (0 wait time)
|
|
// and the other to update the name-address mapping table (wait
|
|
// time computed based on the factors mentioned above)
|
|
|
|
|
|
//
|
|
// The following will set the WaitLogFlush time for all sessions.
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramWaitLogFlush,
|
|
100, //wait 100 msecs after commit
|
|
//before flushing
|
|
NULL); //ignored
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetSetSysParam: WaitLogFlush : %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// There does not seem to be any need to set Log Flush Period.
|
|
//
|
|
|
|
//
|
|
// set the log file path
|
|
//
|
|
|
|
strcpy( DBFilePath, DhcpGlobalOemDatabasePath );
|
|
strcat( DBFilePath, DHCP_KEY_CONNECT_ANSI );
|
|
|
|
//
|
|
// Convert OEM to ANSI
|
|
//
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen( DBFilePath) );
|
|
|
|
//
|
|
// jet does't allow us to set the LOG file name for some
|
|
// technical resons.
|
|
//
|
|
// strcat( DBFilePath, DATABASE_LOG_FILE );
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID)0, //SesId - ignored
|
|
JET_paramLogFilePath,
|
|
0,
|
|
DBFilePath );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( NO_ERROR != Error ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// Now set the JET_paramCheckFormatWhenOpenFail so that opening
|
|
// the oldformat database would retrun JET_errDatabaseXXXFormat
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID) 0,
|
|
JET_paramCheckFormatWhenOpenFail,
|
|
1,
|
|
NULL);
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"JetSetSystemParmater failed on ChkFmtWhnOpnFail\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// dont restore if the old logs are not matching
|
|
//
|
|
|
|
JetError = JetSetSystemParameter(
|
|
&JetInstance,
|
|
(JET_SESID) 0,
|
|
JET_paramDeleteOutOfRangeLogs,
|
|
1,
|
|
NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, "SetSysParam" );
|
|
if ( Error != ERROR_SUCCESS )
|
|
{
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"JetSetSystemParameter failed on DeleteOutOfRangeLogs\n"));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"DhcpJetSetParameters failed, %ld.\n", Error ));
|
|
}
|
|
return( Error );
|
|
}
|
|
|
|
VOID
|
|
DhcpTerminateJet()
|
|
/*++
|
|
This routine ends the jet session and terminates the jet engine.
|
|
--*/
|
|
{
|
|
DWORD JetError;
|
|
|
|
if( DhcpGlobalJetServerSession != 0 ) {
|
|
JetError = JetEndSession( DhcpGlobalJetServerSession, 0 );
|
|
DhcpPrint((DEBUG_MISC, "JetEndSession\n")); // JET TRACE
|
|
DhcpMapJetError( JetError, "EndSession" );
|
|
DhcpGlobalJetServerSession = 0;
|
|
}
|
|
JetError = JetTerm2( JetInstance, JET_bitTermComplete );
|
|
DhcpMapJetError( JetError, "JetTerm/JetTerm2" );
|
|
}
|
|
|
|
static ULONG InitCount = 0;
|
|
|
|
|
|
DWORD __stdcall
|
|
DhcpUpgradeAddDbEntry(
|
|
IN PDHCP_RECORD Rec
|
|
);
|
|
|
|
DWORD
|
|
UpgradeDhcpDatabase(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = DhcpUpgConvertTempToDhcpDb( DhcpUpgradeAddDbEntry );
|
|
|
|
if( NO_ERROR != Error ) {
|
|
|
|
DhcpServerEventLog(
|
|
EVENT_SERVER_DATABASE_CONVERSION,
|
|
EVENTLOG_ERROR_TYPE,
|
|
Error );
|
|
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DhcpDeleteFiles(
|
|
LPSTR DatabasePath,
|
|
LPSTR Files
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete files .
|
|
|
|
Arguments:
|
|
|
|
DatabasePath - full path name where the database is restored.
|
|
|
|
Files - files to be deleted (can have wild char. in filename).
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
CHAR CurrentDir[ MAX_PATH ];
|
|
HANDLE HSearch = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATAA FileData;
|
|
|
|
CHAR DstFile[ MAX_PATH ];
|
|
LPSTR DstFileNamePtr;
|
|
|
|
//
|
|
// Read and save current directory to restore CD at the end.
|
|
//
|
|
|
|
if( GetCurrentDirectoryA( MAX_PATH, CurrentDir ) == 0 ) {
|
|
Error = GetLastError();
|
|
DhcpPrint(( DEBUG_JET,
|
|
"GetCurrentDirctoryA failed, Error = %ld.\n", Error ));
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// set current directory to backup path.
|
|
//
|
|
|
|
if( SetCurrentDirectoryA( DatabasePath ) == FALSE ) {
|
|
Error = GetLastError();
|
|
DhcpPrint(( DEBUG_JET,
|
|
"SetCurrentDirctoryA failed, Error = %ld.\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Start file serach on current dir.
|
|
//
|
|
|
|
HSearch = FindFirstFileA( Files, &FileData );
|
|
|
|
if( HSearch == INVALID_HANDLE_VALUE ) {
|
|
Error = GetLastError();
|
|
DhcpPrint(( DEBUG_JET,
|
|
"FindFirstFileA failed (Files = %s), Error = %ld.\n",
|
|
Files, Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// delete files.
|
|
//
|
|
|
|
for( ;; ) {
|
|
|
|
if( DeleteFileA( FileData.cFileName ) == FALSE ) {
|
|
|
|
Error = GetLastError();
|
|
DhcpPrint(( DEBUG_JET,
|
|
"CopyFileA failed, Error = %ld.\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Find next file.
|
|
//
|
|
|
|
if ( FindNextFileA( HSearch, &FileData ) == FALSE ) {
|
|
|
|
Error = GetLastError();
|
|
|
|
if( Error == ERROR_NO_MORE_FILES ) {
|
|
break;
|
|
}
|
|
|
|
DhcpPrint(( DEBUG_JET,
|
|
"FindNextFileA failed, Error = %ld.\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( HSearch != INVALID_HANDLE_VALUE ) {
|
|
FindClose( HSearch );
|
|
}
|
|
|
|
if( ERROR_NO_MORE_FILES == Error ) Error = NO_ERROR;
|
|
if( ERROR_FILE_NOT_FOUND == Error ) Error = NO_ERROR;
|
|
|
|
//
|
|
// reset current currectory.
|
|
//
|
|
|
|
SetCurrentDirectoryA( CurrentDir );
|
|
|
|
return( Error );
|
|
}
|
|
|
|
DWORD
|
|
DhcpInitializeDatabaseEx(
|
|
IN BOOL fReadOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function initializes the DHCP database. If the DHCP database
|
|
exists then it open the database and initialize all ColumnIds,
|
|
otherwise it creates a new database and obtains ColumnsIds.
|
|
|
|
Arguments:
|
|
fReadOnly -- this parameter is set to TRUE only if it is
|
|
called from outside the service -- in this case nothing new
|
|
must be created..
|
|
|
|
Return Value:
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
JET_COLUMNDEF columnDef;
|
|
DWORD Error;
|
|
DWORD i;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
BOOL fRunUpgradeStuff = FALSE;
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
if( 0 != InitCount ) return ERROR_SUCCESS;
|
|
|
|
//
|
|
// If upgrade is not completed yet, delete all the log files
|
|
// and remember this so that soon after the database is
|
|
// created, the upgrade code can be run
|
|
//
|
|
|
|
if( !fReadOnly && TRUE == DhcpCheckIfDatabaseUpgraded(FALSE) ) {
|
|
CHAR DBFilePath[MAX_PATH];
|
|
|
|
fRunUpgradeStuff = TRUE;
|
|
|
|
if ( strlen( DhcpGlobalOemDatabasePath ) < MAX_PATH )
|
|
strcpy( DBFilePath, DhcpGlobalOemDatabasePath );
|
|
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
|
|
Error = DhcpDeleteFiles( DBFilePath, "j50*.log" );
|
|
if( NO_ERROR != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "Delete log files: 0x%lx\n",
|
|
Error));
|
|
return Error;
|
|
}
|
|
|
|
Error = DhcpDeleteFiles( DBFilePath, "*.mdb" );
|
|
if( NO_ERROR != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "Delete mdb files: 0x%lx\n",
|
|
Error ));
|
|
return Error;
|
|
}
|
|
} // if upgrade
|
|
|
|
LOCK_DATABASE();
|
|
|
|
DhcpPrint((DEBUG_MISC, "Entering DhcpInitializeDatabase\n"));
|
|
Error = DhcpSetJetParameters();
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// -------------------------------------------------------------------
|
|
//
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"Calling JetInit\n" ));
|
|
JetError = JetInit( &JetInstance );
|
|
DhcpPrint((DEBUG_MISC,"DhcpInitializeDatabase: JetInit(_): %ld\n", JetError));
|
|
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"After Calling JetInit\n" ));
|
|
|
|
Error = DhcpMapJetError( JetError, "JetInit" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
JetError = JetBeginSession(
|
|
JetInstance,
|
|
&DhcpGlobalJetServerSession,
|
|
"admin",
|
|
"" );
|
|
|
|
if( *(DWORD *)(DhcpGlobalJetServerSession) == -1 ) {
|
|
DhcpPrint((DEBUG_MISC, "JetBeginSession returned -1 session!\n"));
|
|
}
|
|
|
|
DhcpPrint((DEBUG_MISC, "JetBeginSession\n")); //JET TRACE
|
|
Error = DhcpMapJetError( JetError, "JetBeginSEssion" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetBeginSession: %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Attach the database so that it always looks at the place where
|
|
// we want to.
|
|
//
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
if ( ( strlen( DhcpGlobalOemDatabasePath ) + strlen( DhcpGlobalOemDatabaseName) + 2 ) < MAX_PATH )
|
|
{
|
|
strcpy(DBFilePath, DhcpGlobalOemDatabasePath );
|
|
strcat(DBFilePath, DHCP_KEY_CONNECT_ANSI );
|
|
strcat(DBFilePath, DhcpGlobalOemDatabaseName );
|
|
}
|
|
|
|
//
|
|
// Convert OEM to ANSI
|
|
//
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
|
|
//
|
|
// detach all previous installation of dhcp databases.
|
|
//
|
|
|
|
DhcpPrint((DEBUG_MISC, "Trying to JetDetachDb(%ld)\n", DhcpGlobalJetServerSession)); // JET TRACE
|
|
JetError = JetDetachDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
NULL );
|
|
|
|
DhcpPrint((DEBUG_MISC, "JetDetachDatabase\n")); // JET TRACE
|
|
|
|
Error = DhcpMapJetError( JetError, "JetDetachDatabase" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "DhcpDetachDatabase: %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// attach current dhcp database file.
|
|
//
|
|
|
|
DhcpPrint((DEBUG_MISC, "Trying to JetAttachDatabase %s\n", DBFilePath));
|
|
JetError = JetAttachDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
DBFilePath,
|
|
0 );
|
|
|
|
DhcpPrint((DEBUG_MISC, "JetAttachDatabase\n")); // JET TRACE
|
|
|
|
//
|
|
// if the database is not found, it is ok. We will create it later.
|
|
//
|
|
|
|
if ( JetError != JET_errFileNotFound ) {
|
|
|
|
Error = DhcpMapJetError( JetError, "AttachDatabase" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "DhcpMapJetError %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// hook the client table pointer.
|
|
//
|
|
|
|
DhcpGlobalClientTable = ClientTable;
|
|
DhcpAssert( CLIENT_TABLE_NUM_COLS == MAX_INDEX );
|
|
|
|
JetError = JetOpenDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
DBFilePath, // full path and file name.
|
|
NULL, // default engine
|
|
&DhcpGlobalDatabaseHandle,
|
|
0 );
|
|
|
|
DhcpPrint((DEBUG_MISC, "JetOpenDatabase\n")); // JET TRACE
|
|
//
|
|
// if no database exists then create one and also initize it for
|
|
// use.
|
|
//
|
|
|
|
if( !fReadOnly && JetError == JET_errDatabaseNotFound ) {
|
|
|
|
Error = DhcpCreateAndInitDatabase(
|
|
NULL, // default engine
|
|
&DhcpGlobalDatabaseHandle,
|
|
0 );
|
|
|
|
|
|
DhcpPrint((DEBUG_MISC, "JetCreateAndInitDatabase\n")); // JET TRACE
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = DhcpMapJetError( JetError, "CreateAndInitDb" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "DhcpOpenDatabase %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// database is successfully opened, open table and columns now.
|
|
//
|
|
|
|
JetError = JetOpenTable(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalDatabaseHandle,
|
|
CLIENT_TABLE_NAME,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&DhcpGlobalClientTableHandle );
|
|
DhcpPrint((DEBUG_MISC, "JetOpenTable\n")); // JET TRACE
|
|
|
|
Error = DhcpMapJetError( JetError, "OpenTable" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "DhcpOpenTable %ld\n", JetError ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
for ( i = 0; i < CLIENT_TABLE_NUM_COLS; i++ ) {
|
|
|
|
JetError = JetGetTableColumnInfo(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[i].ColName,
|
|
&columnDef,
|
|
sizeof(columnDef),
|
|
0);
|
|
DhcpPrint((DEBUG_MISC, "JetCreateTableColumnInfo\n")); // JET TRACE
|
|
|
|
//
|
|
// if the column doesn't exist, add it now.
|
|
//
|
|
|
|
if ( JET_errColumnNotFound == JetError )
|
|
{
|
|
JET_COLUMNDEF ColumnDef;
|
|
|
|
ColumnDef.cbStruct = sizeof( ColumnDef );
|
|
ColumnDef.columnid = 0;
|
|
ColumnDef.wCountry = 1;
|
|
ColumnDef.langid = DB_LANGID;
|
|
ColumnDef.cp = DB_CP;
|
|
ColumnDef.wCollate = 0;
|
|
ColumnDef.cbMax = 0;
|
|
ColumnDef.grbit = 0;
|
|
|
|
ColumnDef.coltyp = DhcpGlobalClientTable[i].ColType;
|
|
JetError = JetAddColumn(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle,
|
|
DhcpGlobalClientTable[i].ColName,
|
|
&ColumnDef,
|
|
NULL,
|
|
0,
|
|
&DhcpGlobalClientTable[i].ColHandle );
|
|
DhcpPrint((DEBUG_MISC, "JetAddColumn\n")); // JET TRACE
|
|
}
|
|
|
|
Error = DhcpMapJetError( JetError, "AddColumn" );
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint((DEBUG_MISC, "JetTableColumnInfo %ld\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpGlobalClientTable[i].ColHandle = columnDef.columnid;
|
|
}
|
|
|
|
Error = DhcpOpenMCastDbTable(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalDatabaseHandle);
|
|
|
|
Cleanup:
|
|
DhcpPrint((DEBUG_MISC, "Exiting DhcpInitializeDatabase %ld\n", Error));
|
|
|
|
if( ERROR_SUCCESS == Error ) {
|
|
InitCount ++;
|
|
if( fRunUpgradeStuff ) {
|
|
Error = UpgradeDhcpDatabase();
|
|
if( NO_ERROR != Error ) {
|
|
DhcpPrint((DEBUG_MISC, "UpgradeDhcpDatabase: 0x%lx\n", Error));
|
|
}
|
|
}
|
|
}
|
|
|
|
if( NO_ERROR != Error ) {
|
|
|
|
//
|
|
// terminate/cleanup jet session, if we are not successful.
|
|
//
|
|
|
|
if( DhcpGlobalClientTableHandle != 0 ) {
|
|
JetError = JetCloseTable(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle );
|
|
DhcpMapJetError( JetError, "CloseTable" );
|
|
DhcpPrint((DEBUG_MISC, "JetCloseTable\n")); // JET TRACE
|
|
DhcpGlobalClientTableHandle = 0;
|
|
}
|
|
|
|
if( DhcpGlobalDatabaseHandle != 0 ) {
|
|
JetError = JetCloseDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalDatabaseHandle,
|
|
0 );
|
|
DhcpPrint((DEBUG_MISC, "JetCloseDatabase\n")); // JET TRACE
|
|
DhcpMapJetError( JetError, "CloseDatabse" );
|
|
DhcpGlobalDatabaseHandle = 0;
|
|
}
|
|
|
|
DhcpTerminateJet();
|
|
}
|
|
|
|
UNLOCK_DATABASE();
|
|
return( Error );
|
|
}
|
|
|
|
DWORD
|
|
DhcpInitializeDatabase(
|
|
VOID
|
|
)
|
|
{
|
|
return DhcpInitializeDatabaseEx( FALSE );
|
|
}
|
|
|
|
VOID
|
|
DhcpCleanupDatabase(
|
|
IN DWORD ErrorCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function cleans up the JET database data structures after
|
|
gracefully shutting down the JET.
|
|
|
|
Arguments:
|
|
ErrorCode - Supplies the error code of the failure
|
|
|
|
Return Value:
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
JET_ERR JetError;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
char *backupPrefix = "\\New";
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
//
|
|
// Convert path to ANSI
|
|
//
|
|
if( NULL != DhcpGlobalOemJetBackupPath ) {
|
|
if ( ( strlen( DhcpGlobalOemJetBackupPath ) + strlen( backupPrefix ) ) < MAX_PATH )
|
|
strcpy(DBFilePath, DhcpGlobalOemJetBackupPath );
|
|
strcat(DBFilePath, backupPrefix );
|
|
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
}
|
|
|
|
if( 0 == InitCount ) return;
|
|
InitCount --;
|
|
if( 0 != InitCount ) return;
|
|
|
|
LOCK_DATABASE();
|
|
|
|
//
|
|
// do full database backup before shutdown, so that it can
|
|
// restored to another machine without loss of any database changes.
|
|
//
|
|
|
|
if( (DhcpGlobalClientTableHandle != 0) &&
|
|
(DhcpGlobalDatabaseHandle != 0) ) {
|
|
|
|
//
|
|
// backup the database only if we are not halting the system due
|
|
// to a database error, otherwise we may potentially spoil the
|
|
// good backup database.
|
|
//
|
|
|
|
if( ErrorCode != ERROR_DHCP_JET_ERROR ) {
|
|
|
|
//
|
|
// don't backup the data while the system is shutting down
|
|
// since the backup may take several mins.
|
|
//
|
|
|
|
if ( !DhcpGlobalSystemShuttingDown ) {
|
|
|
|
Error = DhcpBackupDatabase( DhcpGlobalOemJetBackupPath, TRUE );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
DhcpServerEventLog(
|
|
EVENT_SERVER_DATABASE_BACKUP,
|
|
EVENTLOG_ERROR_TYPE,
|
|
Error );
|
|
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"DhcpBackupDatabase failed, %ld.\n", Error ));
|
|
}
|
|
}
|
|
}
|
|
} // if
|
|
|
|
if( DhcpGlobalClientTableHandle != 0 ) {
|
|
JetError = JetCloseTable(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalClientTableHandle );
|
|
DhcpMapJetError( JetError, "CloseTable" );
|
|
DhcpGlobalClientTableHandle = 0;
|
|
}
|
|
|
|
if( DhcpGlobalDatabaseHandle != 0 ) {
|
|
JetError = JetCloseDatabase(
|
|
DhcpGlobalJetServerSession,
|
|
DhcpGlobalDatabaseHandle,
|
|
0 );
|
|
DhcpMapJetError( JetError, "CloseDatabase" );
|
|
DhcpGlobalDatabaseHandle = 0;
|
|
}
|
|
|
|
|
|
DhcpTerminateJet();
|
|
|
|
UNLOCK_DATABASE();
|
|
|
|
DeleteCriticalSection(&DhcpGlobalJetDatabaseCritSect);
|
|
|
|
//
|
|
// HACK: Delete jet log files as restore sometimes seems to cause
|
|
// corruption as old log files are copied back this needs dhcp server
|
|
// to be started twice
|
|
//
|
|
|
|
Error = DhcpDeleteFiles( DhcpGlobalOemDatabasePath, "j50*.log" );
|
|
if ( Error == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// delete the ancient logs from the backup directory as well
|
|
//
|
|
|
|
Error = DhcpDeleteFiles( DBFilePath, "j50*.log" );
|
|
}
|
|
|
|
}
|
|
|
|
DWORD
|
|
DhcpBackupDatabase(
|
|
LPSTR BackupPath,
|
|
BOOL FullBackup
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions backup the JET database. FullBackup copies the
|
|
database file and all log files. Incremental backup copies only
|
|
the log files that are modified since the last backup.
|
|
|
|
Arguments:
|
|
|
|
BackupPath - full path name where the database is backed up.
|
|
|
|
FullBackup - set to TRUE if full backup is required.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
JET_ERR JetError;
|
|
JET_GRBIT BackupBits = 0;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
|
|
DBFilePath[ 0 ] = '\0';
|
|
|
|
//
|
|
// Convert path to ANSI
|
|
//
|
|
if( NULL != BackupPath ) {
|
|
if ( strlen( BackupPath ) < MAX_PATH )
|
|
strcpy(DBFilePath, BackupPath);
|
|
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
BackupPath = DBFilePath;
|
|
}
|
|
|
|
//
|
|
// According to the jetapi.doc, we don't need to take any locks while backing up..
|
|
//
|
|
|
|
DhcpPrint(( DEBUG_JET,
|
|
"DhcpBackupDatabase (%s) called.\n", BackupPath ));
|
|
|
|
BackupBits = JET_bitBackupAtomic | JET_bitBackupFullWithAllLogs;
|
|
|
|
JetError = JetBackup( BackupPath, BackupBits, NULL );
|
|
|
|
Error = DhcpMapJetError( JetError, (BackupPath)? "JetBackup" : "JetBackupToNULL");
|
|
|
|
DhcpPrint(( DEBUG_JET,
|
|
"DhcpBackupDatabase (FULL) completed.\n" ));
|
|
|
|
return( Error );
|
|
} // DhcpBackupDatabase()
|
|
DWORD
|
|
DhcpRestoreDatabase(
|
|
LPSTR BackupPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function restores the database from the backup path to
|
|
the working directory. It also plays pack the log files from the
|
|
backup path first and then the log files from working path. After
|
|
this restore the database should be brought back to the state when
|
|
the last successful update on the database was performed.
|
|
|
|
Arguments:
|
|
|
|
BackupPath - full path name where the database is backed up.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
JET_ERR JetError;
|
|
CHAR DBFilePath[MAX_PATH];
|
|
|
|
//
|
|
// Convert path to ANSI
|
|
//
|
|
|
|
ASSERT( NULL != BackupPath );
|
|
strcpy(DBFilePath, BackupPath);
|
|
OemToCharBuffA(DBFilePath, DBFilePath, strlen(DBFilePath) );
|
|
BackupPath = DBFilePath;
|
|
|
|
DhcpPrint(( DEBUG_JET, "DhcpRestoreDatabase(%s) called.\n", BackupPath ));
|
|
|
|
LOCK_DATABASE();
|
|
|
|
Error = DhcpSetJetParameters();
|
|
|
|
do {
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
// goto Cleanup;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// HACK! delete all log files in the database directory. The
|
|
// reason for doing this is because, JetRestore just copies
|
|
// over the backed up database and log files and replays all
|
|
// the logfiles -- including the ones present before the restore.
|
|
// This is obviously no good as the logs could have been
|
|
// there after the backup...
|
|
//
|
|
|
|
DhcpPrint(( DEBUG_MISC,
|
|
"BackupPath = %s, DhcpGlobalOemJetBackupPath = %s\n",
|
|
BackupPath, DhcpGlobalOemJetBackupPath ));
|
|
|
|
if( _stricmp(BackupPath, DhcpGlobalOemJetBackupPath) ) {
|
|
|
|
Error = DhcpDeleteFiles( DhcpGlobalOemDatabasePath, "j50*.log" );
|
|
if( NO_ERROR != Error ) {
|
|
// goto Cleanup;
|
|
break;
|
|
}
|
|
} // if
|
|
|
|
//
|
|
// Since DHCP has only one database and we need to restore it, it is
|
|
// not necessary to specify the list of databases to restore, so the
|
|
// parameters 2, 3, and 4 are set to ZERO.
|
|
//
|
|
JetError = JetRestore( BackupPath,
|
|
0); // restore all databases.
|
|
|
|
Error = DhcpMapJetError( JetError, "JetRestore" );
|
|
} // do
|
|
while ( FALSE );
|
|
|
|
// Cleanup:
|
|
|
|
if( NO_ERROR != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "Restore failed: 0x%lx\n", Error));
|
|
|
|
// if( _stricmp( DhcpGlobalOemJetBackupPath, BackupPath )) {
|
|
// JetError = DhcpRestoreDatabase(
|
|
// DhcpGlobalOemBackupPath );
|
|
// ASSERT( NO_ERROR != JetError );
|
|
// }
|
|
} // if
|
|
|
|
UNLOCK_DATABASE();
|
|
return( Error );
|
|
} // DhcpRestoreDatabase()
|
|
|
|
DWORD __stdcall
|
|
DhcpUpgradeAddDbEntry(
|
|
IN PDHCP_RECORD Rec
|
|
)
|
|
{
|
|
WCHAR Name[512], Info[512];
|
|
WCHAR *pName, *pInfo;
|
|
DWORD Address, ScopeId;
|
|
|
|
pName = pInfo = NULL;
|
|
|
|
//
|
|
// Add a DHCP or madcap record
|
|
//
|
|
|
|
if( Rec->fMcast == FALSE ) {
|
|
if( NULL != Rec->Info.Dhcp.Name ) {
|
|
pName = Name;
|
|
while( *pName = *Rec->Info.Dhcp.Name ) {
|
|
pName ++; Rec->Info.Dhcp.Name ++;
|
|
}
|
|
pName = Name;
|
|
}
|
|
|
|
if( NULL != Rec->Info.Dhcp.Info ) {
|
|
pInfo = Info;
|
|
while( *pInfo = *Rec->Info.Dhcp.Info ) {
|
|
pInfo ++; Rec->Info.Dhcp.Info ++;
|
|
}
|
|
pInfo = Info;
|
|
}
|
|
|
|
return CreateClientDBEntry(
|
|
ntohl(Rec->Info.Dhcp.Address),
|
|
ntohl(Rec->Info.Dhcp.Mask),
|
|
Rec->Info.Dhcp.HwAddr, Rec->Info.Dhcp.HwLen,
|
|
*(DATE_TIME *)&Rec->Info.Dhcp.ExpTime, pName, pInfo,
|
|
INADDR_LOOPBACK, Rec->Info.Dhcp.State,
|
|
Rec->Info.Dhcp.Type );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fake name and info for madcap
|
|
//
|
|
|
|
if( NULL != Rec->Info.Mcast.Info ) {
|
|
pInfo = Info;
|
|
while( *pInfo = *Rec->Info.Mcast.Info ) {
|
|
pInfo ++; Rec->Info.Mcast.Info ++;
|
|
}
|
|
pInfo = Info;
|
|
}
|
|
|
|
Address = ntohl(Rec->Info.Mcast.Address);
|
|
ScopeId = ntohl(Rec->Info.Mcast.ScopeId);
|
|
|
|
return MadcapCreateClientEntry(
|
|
(PVOID)&Address, sizeof(Address), ScopeId,
|
|
Rec->Info.Mcast.ClientId, Rec->Info.Mcast.HwLen,
|
|
pInfo, *(DATE_TIME *)&Rec->Info.Mcast.Start,
|
|
*(DATE_TIME *)&Rec->Info.Mcast.End,
|
|
INADDR_ANY, Rec->Info.Mcast.State, 0, FALSE );
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
DhcpOpenAndReadDatabaseConfig(
|
|
IN LPSTR OemDatabaseName,
|
|
IN LPSTR OemDatabasePath,
|
|
OUT PM_SERVER *Server
|
|
)
|
|
{
|
|
BOOL LoadStrings(VOID);
|
|
VOID FreeStrings(VOID);
|
|
DWORD Error;
|
|
|
|
//
|
|
// Initialize required globals so that InitDatabase can be called.
|
|
//
|
|
|
|
DhcpGlobalOemDatabasePath = OemDatabasePath;
|
|
DhcpGlobalOemDatabaseName = OemDatabaseName;
|
|
if( FALSE == LoadStrings() ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
DhcpGlobalDatabaseLoggingFlag = TRUE;
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
|
|
try {
|
|
InitializeCriticalSection(&DhcpGlobalJetDatabaseCritSect);
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
Error = GetLastError( );
|
|
return Error;
|
|
}
|
|
|
|
Error = DhcpInitializeDatabaseEx(TRUE);
|
|
DeleteCriticalSection(&DhcpGlobalJetDatabaseCritSect);
|
|
|
|
//
|
|
// Read config, uninitialize everything and return
|
|
//
|
|
|
|
if( NO_ERROR == Error ) Error = DhcpReadConfigInfo( Server );
|
|
|
|
FreeStrings();
|
|
DhcpTerminateJet();
|
|
DhcpGlobalOemDatabasePath = NULL;
|
|
DhcpGlobalOemDatabaseName = NULL;
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
DhcpOpenAndWriteDatabaseConfig(
|
|
IN LPSTR OemDatabaseName,
|
|
IN LPSTR OemDatabasePath,
|
|
IN PM_SERVER Server
|
|
)
|
|
{
|
|
BOOL LoadStrings(VOID);
|
|
VOID FreeStrings(VOID);
|
|
DWORD Error;
|
|
|
|
//
|
|
// Initialize required globals so that InitDatabase can be called.
|
|
//
|
|
|
|
DhcpGlobalOemDatabasePath = OemDatabasePath;
|
|
DhcpGlobalOemDatabaseName = OemDatabaseName;
|
|
if( FALSE == LoadStrings() ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
DhcpGlobalDatabaseLoggingFlag = TRUE;
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
|
|
try {
|
|
InitializeCriticalSection(&DhcpGlobalJetDatabaseCritSect);
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Error = GetLastError( );
|
|
return Error;
|
|
}
|
|
|
|
Error = DhcpInitializeDatabaseEx(TRUE);
|
|
DeleteCriticalSection(&DhcpGlobalJetDatabaseCritSect);
|
|
|
|
//
|
|
// write config, uninitialize everything and return
|
|
//
|
|
|
|
if( NO_ERROR == Error ) {
|
|
Error = DhcpOpenConfigTable(
|
|
DhcpGlobalJetServerSession, DhcpGlobalDatabaseHandle );
|
|
|
|
if( NO_ERROR == Error ) {
|
|
|
|
Error = DhcpSaveConfigInfo(
|
|
Server, FALSE, FALSE, 0, 0, 0 );
|
|
}
|
|
}
|
|
|
|
FreeStrings();
|
|
DhcpTerminateJet();
|
|
DhcpGlobalOemDatabasePath = NULL;
|
|
DhcpGlobalOemDatabaseName = NULL;
|
|
|
|
return Error;
|
|
}
|
|
|