windows-nt/Source/XPSP1/NT/net/wins/server/msc/winscnf.c

5461 lines
174 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
winscnf.c
Abstract:
This module contains functions that deal with the configuration
information for the WINS
Portability:
This module is portable
Author:
Pradeep Bahl (PradeepB) Dec-1992
Revision History:
Modification date Person Description of modification
----------------- ------- ----------------------------
--*/
/*
* Includes
*/
#include "wins.h"
#include <winsock2.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <search.h>
#include "comm.h"
#include "winreg.h"
#include "winsevt.h"
#include "winsmsc.h"
#include "winscnf.h"
#include "nms.h"
#include "nmsnmh.h"
#include "rpl.h"
#include "rplpush.h"
#include "winsintf.h"
#include "nmfilter.h"
#include <resapi.h>
/*
* Local Macro Declarations
*/
//
// Size of max string that a user can input in a REG_SZ field
//
#define MAX_SZ_SIZE 80
#define REG_M(fn, evt, exc) \
{ \
if((fn) != ERROR_SUCCESS) \
{ \
WINSEVT_LOG_M( \
WINS_FATAL_ERR, \
(evt) \
); \
WINS_RAISE_EXC_M((exc)); \
} \
}
//
// pointer to default path for log file. If you change this to a NON NULL
// value, make sure you don't try to free the memory in SetSystemParam
// in nmsdb.c
//
#define DEFAULT_LOG_PATH NULL
#define _WINS_CFG_KEY \
TEXT("System\\CurrentControlSet\\Services\\Wins")
#define _WINS_CFG_PARAMETERS_KEY TEXT("Parameters")
#define _WINS_CFG_PARTNERS_KEY TEXT("Partners")
#define _WINS_CFG_CC_KEY TEXT("Parameters\\ConsistencyCheck")
#define _WINS_CFG_PULL_KEY TEXT("Partners\\Pull")
#define _WINS_CFG_PUSH_KEY TEXT("Partners\\Push")
#define _WINS_CFG_DATAFILES_KEY TEXT("Parameters\\Datafiles")
#define _WINS_CFG_SPEC_GRP_MASKS_KEY TEXT("Parameters\\InternetGrpMasks")
#define _WINS_LOG_KEY \
TEXT("System\\CurrentControlSet\\Services\\EventLog\\Application\\WinsInt")
#define _WINS_MSGFILE_SKEY TEXT("EventMessageFile")
#define _WINS_LOG_FILE_NAME TEXT("%SystemRoot%\\System32\\winsevnt.dll")
#define _RPL_CLASS TEXT("RplClass")//class for Rpl Pull and Push
//keys
//
// The start version number should never be allowed to go above this number
// This will avoid a wrap around.
//
#define MAX_START_VERS_NO 0x0FFFFFFF
//
// Names of event variables used for notification purposes
//
#ifdef WINSDBG
#define WINS_KEY_CHG_EVT_NM TEXT("WinsKChgEvt")
#define PARAMETERS_KEY_CHG_EVT_NM TEXT("WinsParamatersKChgEvt")
#define PARTNERS_KEY_CHG_EVT_NM TEXT("WinsPartenersKChgEvt")
#define CNF_CHG_EVT_NM TEXT("WinsConfigChangeEvt")
#else
#define WINS_KEY_CHG_EVT_NM NULL
#define PARAMETERS_KEY_CHG_EVT_NM NULL
#define PARTNERS_KEY_CHG_EVT_NM NULL
#define CNF_CHG_EVT_NM NULL
#endif
//
// Values for the fStaticInit field of the configuration data structure
//
#define DO_STATIC_INIT TRUE
#define DONT_DO_STATIC_INIT FALSE
//
// defines for the InitTimeRpl and InitTimePush fields of WinsCnf
//
#define DO_INIT_TIME_RPL 1
#define NO_INIT_TIME_RPL 0
//
// NO_LIMIT_CHK_FLAG - for easing the task of testers
//
// If this flag is set in LogDetailedEvts DWORD, WINS skips all
// checks for the min. values of the time intervals and Update Count.
// This kind of operation of WINS is unsupported and is being provided
// only to help out testers
//
#define NO_LIMIT_CHK_FLAG 0x80000000 //MSB is set.
//
// If ErrEvt passed is 0, we don't log any message. NOTE: a WINS event
// can never have 0 as its value (checkout winsevnt.mc)
//
#define QUERY_VALUE_M(Key, Str, ValTyp, Var, ErrEvt, DefVal) \
{ \
DWORD Sz = sizeof((Var)); \
if (RegQueryValueEx( \
(Key), \
(Str), \
NULL, \
&(ValTyp), \
(LPBYTE)&(Var), \
&Sz \
) != ERROR_SUCCESS \
) \
{ \
if ((ErrEvt) != 0) \
{ \
WINSEVT_LOG_INFO_M( \
WINS_SUCCESS, \
(ErrEvt) \
); \
} \
Var = DefVal; \
} \
}
/*
* Local Typedef Declarations
*/
/*
* Global Variable Definitions
*/
CRITICAL_SECTION WinsCnfCnfCrtSec; //used for reinitialization
//of certain fields of the
//WinsCnf structure
BOOL fWinsCnfRplEnabled = TRUE; //replication is enabled
BOOL fWinsCnfScvEnabled = TRUE; //scavenging is enabled
FUTURES("use #ifdef PERF around the following three perf. mon. vars")
BOOL fWinsCnfPerfMonEnabled = FALSE; //perf. mon is disabled
BOOL fWinsCnfHighResPerfCntr = FALSE; //indicates whether the
//hardware supports a high
//performance counter
LARGE_INTEGER LiWinsCnfPerfCntrFreq; //indicates the frequency of
//the counter
BOOL fWinsCnfReadNextTimeVersNo = FALSE;
DWORD WinsCnfCnfMagicNo = WINSCNF_INITIAL_CNF_MAGIC_NO;
BOOL fWinsCnfInitStatePaused;
//TCHAR WinsCnfDb[WINS_MAX_FILENAME_SZ]; //db file to hold tables
BOOL WinsCnfRegUpdThdExists = FALSE;
//#define MAX_PATH_SIZE 200
PTCHAR pWinsCnfNbtPath;
BOOL sfNoLimitChk = FALSE; //to override the limit checks
//
// NetBt handle
//
HANDLE WinsCnfNbtHandle = NULL;
//
//
// Init the configuration structure with default values
//
WINSCNF_CNF_T WinsCnf = {
WINSCNF_INITIAL_CNF_MAGIC_NO, //id
NOTE("Change 1 to 0 before production")
0, //Log detailed evts
1, //default number of processors
200, //default no. of db buffers
{ 0, NULL}, //Spec.grp mask
WINSCNF_E_INITING, //state
WINSCNF_DEF_REFRESH_INTERVAL,
WINSCNF_MIN_TOMBSTONE_INTERVAL,
WINSCNF_MIN_TOMBSTONE_TIMEOUT,
WINSCNF_MIN_VERIFY_INTERVAL,
WINSCNF_SCV_CHUNK,
WINSCNF_DEF_CHL_MAX_RETRIES,
WINSCNF_DEF_INIT_CHL_RETRY_INTVL,
WINSCNF_DB_NAME_ASCII, //db file name
0, //no of STATIC files
NULL, //ptr to file names
DONT_DO_STATIC_INIT,
(HANDLE)0, //notify event handle (WINS)
(HANDLE)0, //not. evt hdl (PARAMETSRS)
(HANDLE)0, //not. evt hdl (PARTNERS)
(HANDLE)0, //Config change handle
(HANDLE)0, //log event handle
(DWORD)WINSINTF_E_NORMAL,
WINSTHD_DEF_NO_NBT_THDS,
WINSCNF_SCV_PRIORITY_LVL,
WINSCNF_MIN_VALID_RPL_INTVL,//max Rpl
//Time Intvl
TRUE, //rpl. only with cnf partners
TRUE, //add 1B to responses to 1C name queries
#if MCAST > 0
FALSE, //no rpl. with self found pnrs
WINSCNF_DEF_MCAST_TTL,
WINSCNF_DEF_MCAST_INTVL,
#endif
TRUE, //logging is on
NULL, //current directory
NULL, //no backup directory
FALSE, //Do backup on term flg
FALSE, //PStatic flag
0, //type of persona list (0 = non-grata)
0, //number of addresses in persona list
NULL, //persona list
WINSCNF_RPL_DEFAULT_TYPE, //def. rpl
TRUE, //No rpl on error
TRUE, //no persistent connections
//
// CC initialization
//
MAXULONG, //CC Time Int
FALSE, //SpTime Set
MAXULONG, //Sp Time
WINSCNF_CC_DEF_RECS_AAT,
WINSCNF_CC_DEF_USE_RPL_PNRS,
FALSE, //no spoofing
FALSE, // no randomization of 1C list.
//
//PullInfo initialization
//
WINSCNF_MAX_COMM_RETRIES, //comm.
//failure
//retries
0, //no of Push Pnrs
NULL,//ptr to Pull Pnrs records
DO_INIT_TIME_RPL, //do init time
//pulling
WINSCNF_RPL_DEFAULT_TYPE,
TRUE, // persistent connections
//
// PushInfo initialization
//
TRUE, // trigger on address change
//of owned entry
0, //no of Pull Pnrs
0, //no of Push recs with valid
//update count
NULL,//ptr to Push Pnrs records
DO_INIT_TIME_RPL, //init time
//pushing disabled
DO_PROP_NET_UPD_NTF, //prop net upd
//ntfs.
WINSCNF_RPL_DEFAULT_TYPE,
TRUE // persistent connections
};
/*
* Local Variable Definitions
*/
STATIC BOOL sfVersNoUpdThdExists = FALSE;
STATIC BOOL sfVersNoChanged = FALSE;
STATIC HKEY sConfigRoot; //HKEY for the WINS root
STATIC HKEY sParametersKey; //HKEY for the PARAMETERS subkey
STATIC HKEY sCCKey; //HKEY for the CC subkey
STATIC HKEY sPartnersKey; //HKEY for PARTNERS subkey
STATIC HKEY sLogRoot; //HKEY for the log root
FUTURES("Might want to change these to auto variables later")
STATIC TCHAR sWinsCfgKey[] = _WINS_CFG_KEY;
STATIC TCHAR sWinsLogKey[] = _WINS_LOG_KEY;
STATIC TCHAR sWinsMsgFileSKey[] = _WINS_MSGFILE_SKEY;
//
// flags that indicate to WinsCnfOpenSubKeys() whether the corresponding keys
// exist.
//
STATIC BOOL sfParametersKeyExists = FALSE;
STATIC BOOL sfPartnersKeyExists = FALSE;
STATIC BOOL sfParametersKeyOpen = FALSE;
STATIC BOOL sfPartnersKeyOpen = FALSE;
TCHAR sLogFilePath[WINS_MAX_FILENAME_SZ]; //path to log file
/*
* Local Function Prototype Declarations
*/
/* prototypes for functions local to this module go here */
STATIC
VOID
LnkWSameMetricValRecs(
PWINSCNF_CNF_T pWinsCnf,
PRPL_CONFIG_REC_T pCnfRec
);
STATIC
int
__cdecl
CompUpdCnt(
CONST LPVOID pElem1,
CONST LPVOID pElem2
);
STATIC
VOID
GetPnrInfo(
RPL_RR_TYPE_E RRType_e,
PWINSCNF_CNF_T pWinsCnf
);
STATIC
VOID
GetKeyInfo(
IN HKEY Key,
IN WINSCNF_KEY_E KeyTyp_e,
OUT LPDWORD pNoOfSubKeys,
OUT LPDWORD pNoOfVals
);
STATIC
BOOL
SanityChkParam(
PWINSCNF_CNF_T pWinsCnf
);
STATIC
VOID
ChkWinsSubKeys(
VOID
);
STATIC
VOID
GetSpTimeData(
HKEY SubKey,
LPSYSTEMTIME pCurrTime,
LPBOOL pfSpTime,
LPDWORD pSpTimeIntvl
);
STATIC
VOID
ReadSpecGrpMasks(
PWINSCNF_CNF_T pWinsCnf
);
VOID
GetOwnerList(
PWINSCNF_CNF_T pWinsCnf
);
VOID
ReadCCInfo(
PWINSCNF_CNF_T pWinsCnf
);
#if MCAST > 0
STATIC
DWORD
SetVal(
HKEY RootKey,
LPWSTR pName,
DWORD ValType,
LPWSTR pVal,
DWORD ValSize
);
#endif
#ifdef WINSDBG
STATIC
VOID
PrintRecs(
RPL_RR_TYPE_E RRType_e,
PWINSCNF_CNF_T pWinsCnf
);
#endif
/*function defs*/
STATUS
WinsCnfInitConfig(
VOID
)
/*++
Routine Description:
This function opens the registry and reads in all the configuration
information from it.
Arguments:
None
Externals Used:
WinsCnf
Called by:
Init() in nms.c
Comments:
None
Return Value:
Success status codes --
Error status codes --
--*/
{
DWORD NewKeyInd;
LONG RetVal;
/*
First and foremost, open (or create if non-existent) the log file
*/
#if 0
InitLog();
#endif
RetVal = RegCreateKeyEx(
HKEY_LOCAL_MACHINE, //predefined key value
sWinsCfgKey, //subkey for WINS
0, //must be zero (reserved)
TEXT("Class"), //class -- may change in future
REG_OPTION_NON_VOLATILE, //non-volatile information
KEY_ALL_ACCESS, //we desire all access to the keyo
NULL, //let key have default sec. attributes
&sConfigRoot, //handle to key
&NewKeyInd //is it a new key (out arg)
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_N_RET_M(
WINS_FATAL_ERR,
WINS_EVT_CANT_OPEN_WINS_KEY,
WINS_FATAL_ERR
);
}
//
// Initialize the critical section that guards the fields used
// by Scavenger thread
//
InitializeCriticalSection(&WinsCnfCnfCrtSec);
InitializeCriticalSection(&g_cs1BFilter);
/*
First create the events that will be passed to the
RegNotifyChangeKeyValue function
*/
try {
WinsMscCreateEvt(
WINS_KEY_CHG_EVT_NM,
FALSE, //auto reset event
&WinsCnf.WinsKChgEvtHdl
);
WinsMscCreateEvt(
PARAMETERS_KEY_CHG_EVT_NM,
FALSE, //auto reset event
&WinsCnf.ParametersKChgEvtHdl
);
WinsMscCreateEvt(
PARTNERS_KEY_CHG_EVT_NM,
FALSE, //auto reset event
&WinsCnf.PartnersKChgEvtHdl
);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsCnfInitConfig");
WINSEVT_LOG_M(WINS_FATAL_ERR, WINS_EVT_CANT_CREATE_REG_EVT);
return(WINS_FAILURE);
}
//
// Create the event that this main thread will set when configuration changes
// The main thread sets this event to notify the scavenger thread (for now)
// about the changes
//
WinsMscCreateEvt(
CNF_CHG_EVT_NM,
FALSE, //auto reset event
&WinsCnf.CnfChgEvtHdl
);
//
// Opens the Partners and Parameters keys
//
WinsCnfOpenSubKeys();
//
// Read in the registry information
//
WinsCnfReadRegInfo(&WinsCnf);
/*
Ask to be notified when the Configuration key or any of the subkeys
change
*/
WinsCnfAskToBeNotified(WINSCNF_E_WINS_KEY);
return(WINS_SUCCESS);
}
VOID
WinsCnfReadPartnerInfo(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function gets all the information pertaining to the Partners of this
WINS. Under the configuration key above, there are two Keys PULL and PUSH.
Under each key, there can be one or more keys (IP addresses). The values
for each IP address key are:
Time Interval (for both Pull and Push IP address keys)
Update Count (for Push IP address keys)
Arguments:
pWinsCnf - Address of Wins Configuration structure
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Init function of the Replicator.
Side Effects:
Comments:
Note: This function should never be called when inside the
NmsNmhNamRegCrtSec, otherwise a deadlock can occur with the Pull
thread (check out Reconfig in rplpull.c)
--*/
{
DWORD ValTyp;
//
// Initialize the MaxRplTimeInterval field to 0. After we have read
// both the PULL and PUSH key information from the registry, the above
// field will contain the max. replication time interval specified for
// pulling and pushing replicas
//
pWinsCnf->MaxRplTimeInterval = 0;
pWinsCnf->PullInfo.NoOfPushPnrs = 0;
pWinsCnf->PullInfo.pPullCnfRecs = NULL;
pWinsCnf->PullInfo.RplType = WINSCNF_RPL_DEFAULT_TYPE;
pWinsCnf->PushInfo.NoOfPullPnrs = 0;
pWinsCnf->PushInfo.pPushCnfRecs = NULL;
pWinsCnf->PushInfo.fAddChgTrigger = FALSE;
pWinsCnf->PushInfo.RplType = WINSCNF_RPL_DEFAULT_TYPE;
//
// Since we are again reading the info about the Partners key, increment
// the magic no. No other thread increments this no. The thread that
// looks at this no is the Pull thread.
//
EnterCriticalSection(&WinsCnfCnfCrtSec);
pWinsCnf->MagicNo = ++WinsCnfCnfMagicNo;
LeaveCriticalSection(&WinsCnfCnfCrtSec);
try {
GetOwnerList(pWinsCnf); // get list of persona (grata / non-grata)
//
// Read in the RplType DWORD. Even if no partners are defined, we do this
// in case this WINS is open to all partners (i.e. fOnlyWCnfPnrs is FALSE)
//
QUERY_VALUE_M(
sPartnersKey,
WINSCNF_RPL_TYPE_NM,
ValTyp,
pWinsCnf->RplType,
0, // no logging
WINSCNF_RPL_DEFAULT_TYPE
);
GetPnrInfo(RPL_E_PULL, pWinsCnf);
GetPnrInfo(RPL_E_PUSH, pWinsCnf);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
//
// If there is some problem with the registry, we don't want
// to bugcheck WINS. It can proceed with default values.
// Since we have already logged the errors, the administrator
// can take corrective action if necessary
//
if (
(ExcCode != WINS_EXC_CANT_OPEN_KEY)
&&
(ExcCode != WINS_EXC_CANT_QUERY_KEY)
&&
(ExcCode != WINS_EXC_CANT_CLOSE_KEY)
)
{
WINS_RERAISE_EXC_M();
}
}
return;
}
STATUS
WinsCnfInitLog(
VOID
)
/*++
Routine Description:
This function open (or creates) a log file for registering events
Arguments:
None
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
WinsCnfInitConfig
Side Effects:
Comments:
None
--*/
{
LONG RetVal = ERROR_SUCCESS;
STATUS RetStat = WINS_SUCCESS;
#ifdef WINS_INTERACTIVE
DWORD NewKeyInd;
TCHAR Buff[160];
DWORD dwData;
RetVal = RegCreateKeyEx(
HKEY_LOCAL_MACHINE, //predefined key value
sWinsLogKey, //subkey for WINS
0, //must be zero (reserved)
TEXT("Class"), //class -- may change in future
REG_OPTION_NON_VOLATILE, //non-volatile information
KEY_ALL_ACCESS, //we desire all access to the keyo
NULL, //let key have default sec. attributes
&sLogRoot, //handle to key
&NewKeyInd //is it a new key (out arg) -- not
//looked at
);
if (RetVal != ERROR_SUCCESS)
{
return(WINS_FAILURE);
}
/*
Set the event id message file name
*/
lstrcpy(Buff, _WINS_LOG_FILE_NAME);
/*
Add the Event-ID message-file name to the subkey
*/
RetVal = RegSetValueEx(
sLogRoot, //key handle
sWinsMsgFileSKey, //value name
0, //must be zero
REG_EXPAND_SZ, //value type
(LPBYTE)Buff,
(lstrlen(Buff) + 1) * sizeof(TCHAR) //length of value data
);
if (RetVal != ERROR_SUCCESS)
{
return(WINS_FAILURE);
}
/*
Set the supported data types flags
*/
dwData = EVENTLOG_ERROR_TYPE |
EVENTLOG_WARNING_TYPE |
EVENTLOG_INFORMATION_TYPE;
RetVal = RegSetValueEx (
sLogRoot, //subkey handle
TEXT("TypesSupported"), //value name
0, //must be zero
REG_DWORD, //value type
(LPBYTE)&dwData, //Address of value data
sizeof(DWORD) //length of value data
);
if (RetVal != ERROR_SUCCESS)
{
return(WINS_FAILURE);
}
/*
* Done with the key. Close it
*/
RetVal = RegCloseKey(sLogRoot);
if (RetVal != ERROR_SUCCESS)
{
return(WINS_FAILURE);
}
#endif
WinsCnf.LogHdl = RegisterEventSource(
(LPCTSTR)NULL, //use local machine
TEXT("Wins")
);
if (WinsCnf.LogHdl == NULL)
{
DBGPRINT1(ERR, "InitLog: RegisterEventSource error = (%x)\n", GetLastError());
return(WINS_FAILURE);
}
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_LOG_INITED);
return(RetStat);
}
VOID
LnkWSameMetricValRecs(
PWINSCNF_CNF_T pWinsCnf,
PRPL_CONFIG_REC_T pCnfRec
)
/*++
Routine Description:
This function is called to link a configuration record with all
other configuration records with the same metric value. The metric
to use depends upon the type of the record. If it is a PULL record,
the metric is "Time Interval". If the record is a PUSH record,
the metric is "Update Count"
Arguments:
pWinsCnf - Address of configuration block
pCnfRec - Configuration Record to link.
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsCnfReadPartnerInfo
Side Effects:
Comments:
The record to be linked is the last record in the buffer of
records of the same type.
--*/
{
PRPL_CONFIG_REC_T pTmp;
DWORD OffMetricToComp;
LONG MetricVal;
//
// Set the variables used later based on the record type
//
if (pCnfRec->RRTyp_e == RPL_E_PULL)
{
pTmp = pWinsCnf->PullInfo.pPullCnfRecs;
MetricVal = pCnfRec->TimeInterval;
OffMetricToComp = offsetof(RPL_CONFIG_REC_T, TimeInterval);
}
else //it is a PUSH record
{
pTmp = pWinsCnf->PushInfo.pPushCnfRecs;
MetricVal = pCnfRec->UpdateCount;
OffMetricToComp = offsetof(RPL_CONFIG_REC_T, UpdateCount);
}
//
// Link in this record at the end of the linked list of
// records with the same metric value in the buffer pointed by
// the starting value of pTmp (set above).
//
for (
;
pTmp != pCnfRec; //until we reach this record
pTmp = (PRPL_CONFIG_REC_T)((LPBYTE)pTmp + RPL_CONFIG_REC_SIZE)
)
{
//
// If Metric Value is same, go to end of linked list and
// link in the record
//
if (*((LONG *)((LPBYTE)pTmp + OffMetricToComp)) == MetricVal)
{
//
// Note: if the metric is UpdateCount (Push records)
// then, the following if will fail.
//
//
// If both records have a specific time for replication,
// that time must agree too
//
if (pTmp->fSpTime && pCnfRec->fSpTime)
{
//
// If specific time is not the same, go to the
// next record in the array
//
if (pTmp->SpTimeIntvl != pCnfRec->SpTimeIntvl)
{
continue;
}
}
for(
;
pTmp->pNext != NULL;
pTmp = pTmp->pNext
)
; //NULL body
pTmp->pNext = pCnfRec;
//
// Set flag to indicate that this record has
// been linked. Used in SubmitTimerReqs in rplpull.c
//
pCnfRec->fLinked = TRUE;
break; //record is linked. break out of the loop
}
} //end of for { .. } for looping over all records in the buffer
//
// Make pNext to NULL since this is the last record in the buffer
// buffer of Config Records (also in the chain if records with
// the same metric)
//
pCnfRec->pNext = NULL;
return;
}
VOID
WinsCnfSetLastUpdCnt(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called at initialization/reinitialization time if
InitTimePush registry variable is set to 1) to set the LastVersNo
field of all Push Configuration records to the value of the
NmsNmhMyMAxVersNo counter. This is done to avoid Push Notifications
to be sent at Init time.
Arguments:
pWinsCnf - Wins Configuration Info
Externals Used:
NmsNmhMyMaxVersNo
Return Value:
None
Error Handling:
Called by:
NmsDbInit, Reinit (in nms.c)
Side Effects:
Comments:
This function is called only after the local Database
Name-Address mapping table has been read and NmsNmhMyMaxVersNo
counter initialized (see GetMaxVersNos in nmsdb.c). Also,
this function is called only if the counter value is > 0
--*/
{
PRPL_CONFIG_REC_T pCnfRec = pWinsCnf->PushInfo.pPushCnfRecs;
for (
; //null expr 1
pCnfRec->WinsAdd.Add.IPAdd != INADDR_NONE;
pCnfRec = (PRPL_CONFIG_REC_T)(
(LPBYTE) pCnfRec + RPL_CONFIG_REC_SIZE
)
)
{
//
// If the Update count field is invalid, go to the next record
//
if (pCnfRec->UpdateCount == RPL_INVALID_METRIC)
{
continue;
}
pCnfRec->LastVersNo = NmsNmhMyMaxVersNo;
}
return;
}
VOID
GetPnrInfo(
RPL_RR_TYPE_E RRType_e,
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to read PULL/PUSH records
Arguments:
RRType_e - Type of Information to read (PULL or PUSH records)
pWinsCnf - Configuration structure
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsCnfReadPartnerInfo
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
HKEY CnfKey;
TCHAR KeyName[20]; // will hold name of subkey of
// PULL/PUSH records. These keys are IP
// addresses for which 20 is a
// big enough size
CHAR AscKeyName[20];
DWORD KeyNameSz;
FILETIME LastWrite;
DWORD BuffSize;
HKEY SubKey;
DWORD ValTyp;
DWORD Sz;
PRPL_CONFIG_REC_T paCnfRecs;
DWORD NoOfPnrs = 0; //# of valid PULL or PUSH pnrs
DWORD NoOfPnrsSv; //# of valid PULL or PUSH pnrs saved
DWORD NoOfVals;
DWORD InitTime;
DWORD IndexOfPnr = 0; //total # of pnrs
DWORD RplType;
SYSTEMTIME CurrTime;
//
// Get the current time. It may be needed if we have partners with SpTime
// specified.
//
if (RRType_e == RPL_E_PULL)
{
GetLocalTime(&CurrTime);
}
/*
* Open the key (PULL/PUSH)
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
RRType_e == RPL_E_PULL ?
_WINS_CFG_PULL_KEY :
_WINS_CFG_PUSH_KEY, //subkey for WINS
0, //must be zero (reserved)
KEY_READ, //we desire read access to the keyo
&CnfKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
WINS_SUCCESS,
RRType_e == RPL_E_PULL ?
WINS_EVT_CANT_OPEN_PULL_KEY :
WINS_EVT_CANT_OPEN_PUSH_KEY
);
}
else //key was successfully opened
{
/*
* Query the key. The subkeys are IP addresses of PULL
* partners.
*/
GetKeyInfo(
CnfKey,
(RRType_e == RPL_E_PULL ? WINSCNF_E_PULL_KEY :
WINSCNF_E_PUSH_KEY),
&NoOfPnrs,
&NoOfVals //ignored
);
if (NoOfPnrs == 0)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
RRType_e == RPL_E_PULL ?
WINS_EVT_NO_SUBKEYS_UNDER_PULL :
WINS_EVT_NO_SUBKEYS_UNDER_PUSH
);
}
else
{
//
// Since we have one or more Partners to replicate with,
// read in the value of the InitTimeReplication attribute
// of all such Partners
//
QUERY_VALUE_M(
CnfKey,
WINSCNF_INIT_TIME_RPL_NM,
ValTyp,
InitTime,
0, //WINS_EVT_CANT_GET_INITRPL_VAL,
DO_INIT_TIME_RPL
);
//
// Since we have one or more Partners to replicate with,
// read in the value of the RplType attribute
//
QUERY_VALUE_M(
CnfKey,
WINSCNF_RPL_TYPE_NM,
ValTyp,
RplType,
0,
pWinsCnf->RplType
);
#if PRSCONN
QUERY_VALUE_M(
CnfKey,
WINSCNF_PRS_CONN_NM,
ValTyp,
pWinsCnf->fPrsConn,
0,
TRUE
);
#endif
//
// Allocate buffer big enough to hold data for
// the number of subkeys found under the PULL key
//
BuffSize = RPL_CONFIG_REC_SIZE * (NoOfPnrs + 1);
WinsMscAlloc( BuffSize, &paCnfRecs);
if (RRType_e == RPL_E_PULL)
{
pWinsCnf->PullInfo.pPullCnfRecs = paCnfRecs;
QUERY_VALUE_M(
CnfKey,
WINSCNF_RETRY_COUNT_NM,
ValTyp,
pWinsCnf->PullInfo.MaxNoOfRetries,
0, //WINS_EVT_CANT_GET_RETRY_COUNT,
WINSCNF_MAX_COMM_RETRIES
);
}
else
{
//
// Get the value of the field that indicates
// whether we should send a trigger when the
// address of an owned entry changes.
//
Sz = sizeof(pWinsCnf->PushInfo.fAddChgTrigger);
RetVal = RegQueryValueEx(
CnfKey,
WINSCNF_ADDCHG_TRIGGER_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->PushInfo.fAddChgTrigger,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->PushInfo.fAddChgTrigger = FALSE;
}
else
{
pWinsCnf->PushInfo.fAddChgTrigger =
(pWinsCnf->PushInfo.fAddChgTrigger >= 1);
}
QUERY_VALUE_M(
CnfKey,
WINSCNF_PROP_NET_UPD_NTF,
ValTyp,
pWinsCnf->PushInfo.PropNetUpdNtf,
0, //no event
DO_PROP_NET_UPD_NTF
);
pWinsCnf->PushInfo.pPushCnfRecs = paCnfRecs;
pWinsCnf->PushInfo.NoPushRecsWValUpdCnt = 0;
}
/*
* For each key, get the values (Time Interval/UpdateCount,
* etc)
*/
NoOfPnrsSv = NoOfPnrs; //save the number that we got from the
//GetkeyInfo function
for(
IndexOfPnr = 0, NoOfPnrs = 0;
NoOfPnrs < NoOfPnrsSv; //no of valid pnrs < the total #
IndexOfPnr++
)
{
KeyNameSz = sizeof(KeyName)/sizeof(TCHAR); //init before every call
RetVal = RegEnumKeyEx(
CnfKey,
IndexOfPnr, //Index Of Pnr
KeyName,
&KeyNameSz,
NULL, //reserved
NULL, //don't need class name
NULL, //ptr to var. to hold class name
&LastWrite //not looked at by us
);
if (RetVal != ERROR_SUCCESS)
{
//
// No more ip address keys to get
//
break;
}
//
// Store pointer to the Wins Config structure in
// the configuration record
//
paCnfRecs->pWinsCnf = pWinsCnf;
//
// pWinsCnf->MagicNo contains the value of
// WinsCnfCnfMagicNo
//
paCnfRecs->MagicNo = pWinsCnf->MagicNo;
paCnfRecs->RRTyp_e = RRType_e;
#ifdef UNICODE
if (wcstombs(AscKeyName, KeyName, KeyNameSz) == -1)
{
DBGPRINT0(ERR,
"Conversion not possible in the current locale\n");
}
AscKeyName[KeyNameSz] = EOS;
NONPORT("Call a comm function to do this")
paCnfRecs->WinsAdd.Add.IPAdd = inet_addr(AscKeyName);
#else
paCnfRecs->WinsAdd.Add.IPAdd = inet_addr(KeyName);
#endif
//
// inet_addr returns bytes in network byte order
// (Left to Right). Let us convert this into host
// order. This will avoid confusion later on. All
// formatting functions expect address to be in host
// order.
//
paCnfRecs->WinsAdd.AddLen = COMM_IP_ADD_SIZE;
paCnfRecs->WinsAdd.AddTyp_e = COMM_ADD_E_TCPUDPIP;
paCnfRecs->WinsAdd.Add.IPAdd = ntohl(
paCnfRecs->WinsAdd.Add.IPAdd
);
if (COMM_ADDRESS_SAME_M(&NmsLocalAdd, &paCnfRecs->WinsAdd))
{
//
// Invalid partner. Ignore. NoOfPnrs will
// not be incremented. Also, the buffer
// pointer stays the same
//
continue;
}
RetVal = RegOpenKeyEx(
CnfKey,
KeyName,
0, //reserved; must be 0
KEY_READ,
&SubKey
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_M(
WINS_FATAL_ERR,
RRType_e == RPL_E_PULL ?
WINS_EVT_CANT_OPEN_PULL_SUBKEY :
WINS_EVT_CANT_OPEN_PUSH_SUBKEY
);
FUTURES("It is possible that the user deleted the key. Recover from this")
if (RRType_e == RPL_E_PULL)
{
pWinsCnf->PullInfo.NoOfPushPnrs = 0;
WinsMscDealloc(pWinsCnf->PullInfo.pPullCnfRecs);
pWinsCnf->PullInfo.pPullCnfRecs = NULL;
}
else
{
pWinsCnf->PushInfo.NoOfPullPnrs = 0;
WinsMscDealloc(pWinsCnf->PushInfo.pPushCnfRecs);
pWinsCnf->PushInfo.pPushCnfRecs = NULL;
}
WINS_RAISE_EXC_M(WINS_EXC_CANT_OPEN_KEY);
}
FUTURES("Maybe, we will support a time interval attribute for Push records")
FUTURES("when that is done, LnkRecsWSameMetric would need to be updated")
if (RRType_e == RPL_E_PULL)
{
//
// Read in specific time for replication if one
// has been specified
//
GetSpTimeData(SubKey, &CurrTime, &paCnfRecs->fSpTime, &paCnfRecs->SpTimeIntvl);
Sz = sizeof(paCnfRecs->TimeInterval);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_RPL_INTERVAL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&paCnfRecs->TimeInterval,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_PULL_TIMEINT
);
paCnfRecs->TimeInterval = RPL_INVALID_METRIC;
}
else // a value was read in
{
//
// If the time interval is less than or
// equal to the minimum allowed, use the
// default minimum
//
if (paCnfRecs->TimeInterval
< WINSCNF_MIN_VALID_RPL_INTVL)
{
paCnfRecs->TimeInterval =
WINSCNF_MIN_VALID_RPL_INTVL;
}
if (
(DWORD)paCnfRecs->TimeInterval >
pWinsCnf->MaxRplTimeInterval
)
{
pWinsCnf->MaxRplTimeInterval =
paCnfRecs->TimeInterval;
}
}
//
// Read in the precedence level. This can currently
// be either HIGH (> 0) or LOW (0).
//
Sz = sizeof(paCnfRecs->MemberPrec);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_MEMBER_PREC_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&paCnfRecs->MemberPrec,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
paCnfRecs->MemberPrec = WINSCNF_LOW_PREC;
}
else
{
paCnfRecs->MemberPrec =
(paCnfRecs->MemberPrec > 0) ?
WINSCNF_HIGH_PREC : WINSCNF_LOW_PREC;
}
#if PRSCONN
QUERY_VALUE_M(
SubKey,
WINSCNF_PRS_CONN_NM,
ValTyp,
paCnfRecs->fPrsConn,
0,
pWinsCnf->fPrsConn
);
#endif
}
else // it is a PUSH record
{
//
// Currently, we don't support periodic
// or specific time replication for Push
// records
//
paCnfRecs->fSpTime = FALSE;
#if PRSCONN
QUERY_VALUE_M(
SubKey,
WINSCNF_PRS_CONN_NM,
ValTyp,
paCnfRecs->fPrsConn,
0,
pWinsCnf->fPrsConn
);
#endif
Sz = sizeof(paCnfRecs->UpdateCount);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_UPDATE_COUNT_NM,
NULL,
&ValTyp,
(LPBYTE)&paCnfRecs->UpdateCount,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
paCnfRecs->UpdateCount =
RPL_INVALID_METRIC;
}
else
{
paCnfRecs->LastVersNo.QuadPart = 0;
#if PRSCONN
if (!paCnfRecs->fPrsConn && !sfNoLimitChk)
#else
if (!sfNoLimitChk)
#endif
{
if (paCnfRecs->UpdateCount <
WINSCNF_MIN_VALID_UPDATE_CNT)
{
paCnfRecs->UpdateCount =
WINSCNF_MIN_VALID_UPDATE_CNT;
}
}
else
{
if (paCnfRecs->UpdateCount == 0)
{
paCnfRecs->UpdateCount = 1;
}
}
pWinsCnf->PushInfo.NoPushRecsWValUpdCnt++;
}
}
#if MCAST > 0
Sz = sizeof(paCnfRecs->fSelfFnd);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_SELF_FND_NM,
NULL,
&ValTyp,
(LPBYTE)&paCnfRecs->fSelfFnd,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
paCnfRecs->fSelfFnd = FALSE;
}
#endif
Sz = sizeof(paCnfRecs->fOnlyDynRecs);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_ONLY_DYN_RECS_NM,
NULL,
&ValTyp,
(LPBYTE)&paCnfRecs->fOnlyDynRecs,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
paCnfRecs->fOnlyDynRecs = FALSE;
}
QUERY_VALUE_M(
SubKey,
WINSCNF_RPL_TYPE_NM,
ValTyp,
paCnfRecs->RplType,
0,
pWinsCnf->RplType
);
if (paCnfRecs->RplType != 0)
{
WINSEVT_LOG_INFO_M(paCnfRecs->WinsAdd.Add.IPAdd, WINS_EVT_PARTIAL_RPL_TYPE);
}
#if PRSCONN
if (paCnfRecs->fPrsConn != 0)
{
paCnfRecs->fPrsConn = TRUE;
}
#endif
REG_M(
RegCloseKey(SubKey),
WINS_EVT_CANT_CLOSE_KEY,
WINS_EXC_CANT_CLOSE_KEY
);
//
// Initialize the retry count to 0 and the fLinked flag
// to FALSE
//
//used when pulling
//
paCnfRecs->RetryCount = 0;
paCnfRecs->fLinked = FALSE;
//
// Initialize the following to 0 so that once we stop
// communicating with a WINS we can start again when
// the following count reaches
// WINSCNF_RETRY_AFTER_THIS_MANY_RPL
//
paCnfRecs->RetryAfterThisManyRpl = 0;
#if PRSCONN
ECOMM_INIT_DLG_HDL_M(&paCnfRecs->PrsDlgHdl);
paCnfRecs->LastCommTime = 0;
#endif
//
// Initialize LastCommFailTime to 0. Used by
// SndPushNtf in rplpull.c
//
paCnfRecs->LastCommFailTime = 0;
paCnfRecs->PushNtfTries = 0;
//
// Link the record with other PULL records with the same
// Time Interval
//
LnkWSameMetricValRecs(pWinsCnf, paCnfRecs);
//
// Mark the record as permanent (i.e. it will stay
// around until a reconfiguration or until the process
// terminates
//
paCnfRecs->fTemp = FALSE;
NoOfPnrs++;
paCnfRecs = (PRPL_CONFIG_REC_T)(
(LPBYTE)paCnfRecs +
RPL_CONFIG_REC_SIZE);
} // end of for {..} for looping over subkeys of PULL
//
// GetReplicasNew expects the list to be terminated with a
// record with INADDR_NONE as the address
//
paCnfRecs->WinsAdd.Add.IPAdd = INADDR_NONE;
if (RRType_e == RPL_E_PULL)
{
pWinsCnf->PullInfo.NoOfPushPnrs = NoOfPnrs;
pWinsCnf->PullInfo.InitTimeRpl = InitTime;
pWinsCnf->PullInfo.RplType = RplType;
}
else
{
pWinsCnf->PushInfo.NoOfPullPnrs = NoOfPnrs;
pWinsCnf->PushInfo.InitTimePush = InitTime;
pWinsCnf->PushInfo.RplType = RplType;
//
// Now that we are done with the Push record list,
//let us sort it on the update count field
//
//
// Sort the array in increasing order of Update Counts
//
FUTURES("May use qsort to optimize the update notification process")
CHECK("Not sure yet whether sorting would optimize it")
#if 0
CHECK("this is resulting in compilation warnings. haven't figured out")
CHECK("yet why.")
qsort(
pWinsCnf->pPushCnfRecs, //start of array
(size_t)pWinsCnf->NoOfPullPnrs,//no of elements
RPL_CONFIG_REC_SIZE, //size of each
//element
CompUpdCnt //compare func
);
#endif
} //end of else (It is PULL key)
} // end of else (NoOfPnrs == 0)
/*
* Close the key
*/
REG_M(
RegCloseKey(CnfKey),
WINS_EVT_CANT_CLOSE_KEY,
WINS_EXC_CANT_CLOSE_KEY
);
} //end of else (key could not be opened)
#if 0
#ifdef WINSDBG
PrintRecs(RRType_e, pWinsCnf);
#endif
#endif
return;
} // GetPnrInfo
VOID
GetOwnerList(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function reads the list of owners whose records should be or should not be pulled
from a partner WINS.
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
DWORD dwValType; // type of the reg value
LPSTR pValName; // pointer to the reg
LPBYTE pValData; // pointer to the reg value's data
DWORD dwValDataLen; // length of the reg value's data
DBGENTER("GetOwnerList\n");
// query for the type of persona (grata (1) / non-grata (0))
pWinsCnf->fPersonaGrata = 0;
dwValDataLen = sizeof(DWORD);
RetVal = RegQueryValueExA(
sPartnersKey, // reg key [HKLM\System\CCS\Services\Wins\Partners]
WINSCNF_PERSONA_MODE_NM, // name of the value: "PersonaType"
NULL, // reserved; must be NULL
&dwValType, // type of the value: should get REG_DWORD
(LPVOID)&(pWinsCnf->fPersonaGrata), // value data
&dwValDataLen); // size of the value's data
// if this call didn't succeed, we go on with the default which is 0, 'non-grata'
// get the actual entry we're going to pick the list of addresses from
pValName = pWinsCnf->fPersonaGrata ?
WINSCNF_PERSONA_GRATA_NM :
WINSCNF_PERSONA_NON_GRATA_NM;
// get the size of the data from the registry
// since Sz is 0, if there are any personas
// grata/non-grata then we should get ERROR_MORE_DATA
// if we get a different error than just remove the current list
dwValDataLen = 0;
RetVal = RegQueryValueExA(
sPartnersKey, // reg key [HKLM\System\CCS\Services\Wins\Partners]
pValName, // name of the value: "PersonaList"
NULL, // reserved; must be NULL
&dwValType, // type of the value: should get REG_MULTI_SZ
(LPVOID)&pValData, // dummy address
&dwValDataLen); // initially 0 since we try to determine the actual size
// this call should return ERROR_MORE_DATA for a REG_MULTI_SZ value
// clear-up the old buffer
if (pWinsCnf->pPersonaList != NULL)
{
WinsMscDealloc(pWinsCnf->pPersonaList);
}
pWinsCnf->NoOfPersona = 0;
pWinsCnf->pPersonaList = NULL;
// check if there is a valid value, with the expected type; return if not
if (RetVal != ERROR_MORE_DATA || dwValType != REG_MULTI_SZ)
{
DBGLEAVE("GetOwnerList\n");
return;
}
// allocate the needed buffer
WinsMscAlloc(dwValDataLen, &pValData);
// now query for the data value with a buffer large enough
RetVal = RegQueryValueExA(
sPartnersKey,
pValName,
NULL, // reserved; must be NULL
&dwValType,
(LPVOID)pValData, // now this is the real address
&dwValDataLen);
// ERROR_SUCCESS is expected here
if (RetVal == ERROR_SUCCESS)
{
LPBYTE pString = pValData;
// count in nAddr the number of addresses in the string
for( pWinsCnf->NoOfPersona=0; *pString; pWinsCnf->NoOfPersona++)
pString+= strlen(pString)+1;
// see if there are any addresses there
if (pWinsCnf->NoOfPersona > 0)
{
COMM_IP_ADD_T IpAdd;
// allocate an array of nAddr COMM_ADD_T structures
WinsMscAlloc(
(pWinsCnf->NoOfPersona) * sizeof(COMM_ADD_T),
&(pWinsCnf->pPersonaList));
// loop through the string of addresses and convert
// them to COMM_IP_ADD_T structures
for (pString = pValData, pWinsCnf->NoOfPersona = 0;
*pString;
pString += strlen(pString) + 1)
{
if ((IpAdd = inet_addr(pString)) != -1)
{
// initialize a COMM_ADD_T structure only if the string token is
// indeed an IP address
(pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].AddTyp_e = COMM_ADD_E_TCPUDPIP;
(pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].AddLen = COMM_IP_ADD_SIZE;
(pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].Add.IPAdd = ntohl(IpAdd);
DBGPRINT2(
DET,
"GetOwnerList: Address[%d] = %x\n",
pWinsCnf->NoOfPersona,
(pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].Add.IPAdd);
pWinsCnf->NoOfPersona++;
} //end 'if valid ip address'
} //end 'for each token in the string'
// if there are at least two addresses in the list,
// sort them in ascending order
if (pWinsCnf->NoOfPersona > 1)
{
qsort(pWinsCnf->pPersonaList,
(size_t)pWinsCnf->NoOfPersona,
sizeof(COMM_ADD_T),
ECommCompareAdd);
}
else
{
DBGPRINT0(DET, "GetOwnerList: No valid address found\n");
} //end 'if there are more than two addresses picked up'
} //end 'if there are any tokens at all'
} //end 'if string could be read successfully from the registry'
// the string buffer is no longer needed here
WinsMscDealloc(pValData);
#ifdef WINSDBG
{
DWORD tstNAddrs;
PCOMM_ADD_T tstPAddrs;
DWORD i;
DBGPRINT1(
DET,
"GetOwnerList: Persona %sGrata List:\n",
pWinsCnf->fPersonaGrata ? "" : "Non-");
tstNAddrs = pWinsCnf->NoOfPersona;
tstPAddrs = pWinsCnf->pPersonaList;
for (i = 0; i < tstNAddrs; i++)
{
DBGPRINT2(
DET,
"GetOwnerList:PersonaList[%d] = %08x\n",
i,
tstPAddrs[i].Add.IPAdd);
}
}
#endif
DBGLEAVE("GetOwnerList\n");
return;
}
LONG
ReadClusterIp(
HKEY KeyHandle,
DWORD *IpAddress
)
{
DWORD Sz;
LONG RetVal;
DWORD ValTyp;
TCHAR DirPath[WINS_MAX_FILENAME_SZ];
*IpAddress = 0;
// Read the wins cluster name
Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR);
RetVal = RegQueryValueEx(
KeyHandle,
WINSCNF_CLUSTER_RESOURCE_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)DirPath,
&Sz
);
if ((RetVal == ERROR_SUCCESS) && (DirPath[0] != (TCHAR)EOS))
{
HCLUSTER hCluster;
HRESOURCE hResource;
CHAR IpAddressStr[sizeof ("xxx.xxx.xxx.xxx")];
WCHAR IpAddressWStr[sizeof ("xxx.xxx.xxx.xxx")];
DWORD i;
HMODULE Dll1, Dll2;
#define FUNC_TBL_ENTRY( _Dll, _Name ) { _Dll, &(#_Name)[1], NULL }
#define CALL_FUNC( _Func) (PVOID)( *FuncTbl[_Func].FuncHdl )
enum {
_OpenCluster,
_OpenClusterResource,
_CloseCluster,
_CloseClusterResource,
_ResUtilGetResourceDependentIPAddressProps
};
struct {
HMODULE *Dll;
LPCSTR FuncName;
FARPROC FuncHdl;
} FuncTbl[] = {
FUNC_TBL_ENTRY( &Dll1,_OpenCluster),
FUNC_TBL_ENTRY( &Dll1,_OpenClusterResource),
FUNC_TBL_ENTRY( &Dll1,_CloseCluster),
FUNC_TBL_ENTRY( &Dll1,_CloseClusterResource),
FUNC_TBL_ENTRY( &Dll2,_ResUtilGetResourceDependentIPAddressProps)
};
DBGPRINT1(DET, "WinsCnfReadWinsInfo: ClusterResourceName is (%ws)\n", DirPath);
hCluster = NULL;
hResource = NULL;
Dll1 = Dll2 = NULL;
do {
Dll1 = LoadLibrary(TEXT("clusapi.dll"));
if (!Dll1) {
RetVal = GetLastError();
break;
}
Dll2 = LoadLibrary(TEXT("resutils.dll"));
if (!Dll2) {
RetVal = GetLastError();
break;
}
for (i=0; i<(sizeof(FuncTbl)/sizeof(FuncTbl[0])); i++) {
FuncTbl[i].FuncHdl = GetProcAddress(*FuncTbl[i].Dll, FuncTbl[i].FuncName);
if (!FuncTbl[i].FuncHdl) {
RetVal = GetLastError();
break;
}
}
if (i<(sizeof(FuncTbl)/sizeof(FuncTbl[0]))) {
break;
}
hCluster = CALL_FUNC(_OpenCluster)( NULL );
if (!hCluster) {
RetVal = GetLastError();
break;
}
hResource = CALL_FUNC(_OpenClusterResource)(hCluster, DirPath);
if (!hResource) {
RetVal = GetLastError();
break;
}
Sz = sizeof (IpAddressWStr);
RetVal = PtrToLong(CALL_FUNC(_ResUtilGetResourceDependentIPAddressProps)(
hResource,
IpAddressWStr,
&Sz,
NULL,
NULL,
NULL,
NULL
));
if (ERROR_SUCCESS != RetVal) {
break;
}
WinsMscConvertUnicodeStringToAscii((LPBYTE)IpAddressWStr, IpAddressStr, sizeof(IpAddressStr));
*IpAddress = ntohl(inet_addr(IpAddressStr));
DBGPRINT1(DET, "ReadClusterIp: Cluster IpAddress is (%lx)\n", *IpAddress);
} while ( FALSE );
if( hResource ) CALL_FUNC(_CloseClusterResource)(hResource);
if( hCluster ) CALL_FUNC(_CloseCluster) (hCluster);
if ( Dll1 ) FreeLibrary(Dll1);
if ( Dll2 ) FreeLibrary(Dll2);
}
return RetVal;
}
extern DOM_CACHE_T sDomCache;
VOID
WinsCnfReadWinsInfo(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function reads information (excluding subkeys) about
the local WINS
Arguments:
None
Externals Used:
sConfigRoot,
Return Value:
None
Error Handling:
Called by:
WinsCnfInitConfig
Side Effects:
Comments:
None
--*/
{
DWORD Sz;
LONG RetVal;
DWORD ValTyp;
VERS_NO_T MaxVersNo;
WINSEVT_STRS_T EvtStr;
TCHAR DirPath[WINS_MAX_FILENAME_SZ];
TCHAR Path2[WINS_MAX_FILENAME_SZ];
LPTSTR pHoldFileName;
DWORD fUse351Db;
DWORD fUse4Db;
EvtStr.NoOfStrs = 1;
try {
#if defined(DBGSVC) && !defined(WINS_INTERACTIVE)
//
// Read the value of WinsDbg. Though this value is
// being used concurrently by multiple threads (at reinit time), we
// don't enter any critical section here. This value
// is used only for debugging
//
WinsCnfReadWinsDbgFlagValue();
#endif
Sz = sizeof(pWinsCnf->LogDetailedEvts);
(VOID)RegQueryValueEx(
sParametersKey,
WINSCNF_LOG_DETAILED_EVTS_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->LogDetailedEvts,
&Sz
);
// Read in the 1B filter. If the "Filter1BRequests" is there and it is a REG_MULTI_SZ
// then the filter is created for each of the names specified there. When R_WinsGetBrowserNames
// is called, the database is filtered only for the name present in the filter.
RetVal = RegQueryValueExW(
sParametersKey,
WINSCNF_FILTER1BREQUESTS_NM,
NULL,
&ValTyp,
NULL,
&Sz);
if (RetVal == ERROR_SUCCESS && ValTyp == REG_MULTI_SZ)
{
LPWSTR str1BFilters = NULL;
LPWSTR p1BFilter;
WinsMscAlloc(Sz, &str1BFilters);
if (RegQueryValueExW(
sParametersKey,
WINSCNF_FILTER1BREQUESTS_NM,
NULL,
&ValTyp,
(LPBYTE)str1BFilters,
&Sz) == ERROR_SUCCESS)
{
EnterCriticalSection(&g_cs1BFilter);
try
{
g_p1BFilter = InitNmFilter(g_p1BFilter);
p1BFilter = str1BFilters;
do
{
DWORD nLenFilter = wcslen(p1BFilter);
CHAR strOemName[17];
OEM_STRING oemString;
UNICODE_STRING unicodeString;
if (nLenFilter == 0)
break;
memset(strOemName, ' ', 16);
strOemName[16]=0;
if (nLenFilter > 15)
p1BFilter[16]=L'\0';
RtlInitUnicodeString(&unicodeString, p1BFilter);
RtlInitString(&oemString, strOemName);
RtlUpcaseUnicodeStringToOemString(&oemString, &unicodeString, FALSE);
strOemName[strlen(strOemName)] = ' ';
strOemName[15] = strOemName[0];
strOemName[0] = 0x1B;
InsertNmInFilter(g_p1BFilter, strOemName, 16);
p1BFilter += nLenFilter+1;
}
while(TRUE);
}
finally
{
LeaveCriticalSection(&g_cs1BFilter);
}
}
WinsMscDealloc(str1BFilters);
}
else
{
// if the reg key is not there, reset the filter - all names will be returned.
EnterCriticalSection(&g_cs1BFilter);
try
{
g_p1BFilter = DestroyNmFilter(g_p1BFilter);
}
finally
{
g_p1BFilter = NULL;
LeaveCriticalSection(&g_cs1BFilter);
}
}
sDomCache.bRefresh = TRUE;
//
// Read in the fAdd1Bto1CQueries parameter. Default is TRUE
// meaning: when processing name queries for 1C names, prepend the
// response with the 1B name (browser name).
//
pWinsCnf->fAdd1Bto1CQueries = TRUE;
Sz = sizeof(pWinsCnf->fAdd1Bto1CQueries);
(VOID)RegQueryValueEx(
sParametersKey,
WINSCNF_ADD1BTO1CQUERIES_NM,
NULL,
&ValTyp,
(LPBYTE)&pWinsCnf->fAdd1Bto1CQueries,
&Sz
);
//
// Read in the cap value on the number of worker threads.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_MAX_NO_WRK_THDS_NM,
ValTyp,
pWinsCnf->MaxNoOfWrkThds,
0,
0 //WINSTHD_DEF_NO_NBT_THDS
);
//
// Check if the user needs to override our checks.
//
sfNoLimitChk = pWinsCnf->MaxNoOfWrkThds & NO_LIMIT_CHK_FLAG;
if (sfNoLimitChk)
{
WINSEVT_LOG_M(pWinsCnf->LogDetailedEvts, WINS_EVT_INTERNAL_FEATURE);
pWinsCnf->MaxNoOfWrkThds &= ~NO_LIMIT_CHK_FLAG;
}
if (pWinsCnf->MaxNoOfWrkThds > WINSTHD_MAX_NO_NBT_THDS)
{
pWinsCnf->MaxNoOfWrkThds = WINSTHD_MAX_NO_NBT_THDS;
}
if (pWinsCnf->MaxNoOfWrkThds < WINSTHD_MIN_NO_NBT_THDS)
{
pWinsCnf->MaxNoOfWrkThds = WINSTHD_MIN_NO_NBT_THDS;
}
#if 0
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
ReadSpecGrpMasks(pWinsCnf);
}
#endif
#if DYNLOADJET
//
// Read in the cap value on the number of worker threads.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_USE_351DB_NM,
ValTyp,
fUse351Db,
0,
0 //Use 500 db
);
//
// If set to a non-zero value, we need to load jet.dll
//
if (fUse351Db)
{
DynLoadJetVersion = DYN_LOAD_JET_200;
} else {
QUERY_VALUE_M(
sParametersKey,
WINSCNF_USE_4DB_NM,
ValTyp,
fUse4Db,
0,
0 //Use 500 db
);
//
// If set to a non-zero value, we need to load jet.dll
//
if (fUse4Db)
{
DynLoadJetVersion = DYN_LOAD_JET_500;
}
}
#endif
//
// Read in the refresh Interval
//
Sz = sizeof(pWinsCnf->RefreshInterval);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_REFRESH_INTVL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->RefreshInterval,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_REFRESH_INTERVAL_VAL
);
pWinsCnf->RefreshInterval = WINSCNF_DEF_REFRESH_INTERVAL;
}
else
{
if (!sfNoLimitChk)
{
if (pWinsCnf->RefreshInterval <
WINSCNF_MIN_REFRESH_INTERVAL)
{
pWinsCnf->RefreshInterval = WINSCNF_MIN_REFRESH_INTERVAL;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_REFRESH_INTVL_NM,
pWinsCnf->RefreshInterval);
}
}
else
{
if (pWinsCnf->RefreshInterval < 60)
{
pWinsCnf->RefreshInterval = 60;
}
}
}
//
// Read in the Initial Challenge Retry Interval
//
Sz = sizeof(pWinsCnf->RetryInterval);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_INIT_CHL_RETRY_INTVL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->RetryInterval,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_INIT_CHL_RETRY_INTVL_VAL
);
pWinsCnf->RetryInterval = WINSCNF_DEF_INIT_CHL_RETRY_INTVL;
}
else
{
if (!sfNoLimitChk)
{
if (pWinsCnf->RetryInterval <
WINSCNF_MIN_INIT_CHL_RETRY_INTVL)
{
pWinsCnf->RetryInterval = WINSCNF_MIN_INIT_CHL_RETRY_INTVL;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_INIT_CHL_RETRY_INTVL_NM,
pWinsCnf->RetryInterval);
}
}
else
{
if (pWinsCnf->RetryInterval < WINSCNF_MIN_INIT_CHL_RETRY_INTVL)
{
pWinsCnf->RetryInterval = WINSCNF_MIN_INIT_CHL_RETRY_INTVL;
}
}
}
//
// Read in the Initial Challenge Max. No. of Retries
//
Sz = sizeof(pWinsCnf->MaxNoOfRetries);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_CHL_MAX_RETRIES_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->MaxNoOfRetries,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_CHL_MAX_RETRIES_VAL
);
pWinsCnf->MaxNoOfRetries = WINSCNF_DEF_CHL_MAX_RETRIES;
}
else
{
if (!sfNoLimitChk)
{
if (pWinsCnf->MaxNoOfRetries <
WINSCNF_MIN_CHL_MAX_RETRIES)
{
pWinsCnf->MaxNoOfRetries = WINSCNF_MIN_CHL_MAX_RETRIES;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_CHL_MAX_RETRIES_NM,
pWinsCnf->MaxNoOfRetries);
}
}
else
{
if (pWinsCnf->MaxNoOfRetries < WINSCNF_MIN_CHL_MAX_RETRIES)
{
pWinsCnf->MaxNoOfRetries = WINSCNF_MIN_CHL_MAX_RETRIES;
}
}
}
//
// Read in the tombstone Interval
//
Sz = sizeof(pWinsCnf->TombstoneInterval);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_TOMBSTONE_INTVL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->TombstoneInterval,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_TOMBSTONE_INTERVAL_VAL
);
pWinsCnf->TombstoneInterval =
WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval);
}
else
{
if ( !sfNoLimitChk)
{
if (pWinsCnf->TombstoneInterval <
WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval) )
{
pWinsCnf->TombstoneInterval =
WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval);
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_TOMBSTONE_INTVL_NM,
pWinsCnf->TombstoneInterval);
}
}
else
{
if (pWinsCnf->TombstoneInterval < 60)
{
pWinsCnf->TombstoneInterval = 60;
}
}
}
//
// Read in the tombstone timeout
//
Sz = sizeof(pWinsCnf->TombstoneTimeout);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_TOMBSTONE_TMOUT_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->TombstoneTimeout,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_TOMBSTONE_TIMEOUT_VAL
);
pWinsCnf->TombstoneTimeout = pWinsCnf->RefreshInterval;
}
else
{
if (!sfNoLimitChk)
{
if (pWinsCnf->TombstoneTimeout < pWinsCnf->RefreshInterval)
{
pWinsCnf->TombstoneTimeout = pWinsCnf->RefreshInterval;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_TOMBSTONE_TMOUT_NM,
pWinsCnf->TombstoneTimeout);
}
}
else
{
if (pWinsCnf->TombstoneTimeout < 60)
{
pWinsCnf->TombstoneTimeout = 60;
}
}
}
//
// Read in the Verify Interval
//
Sz = sizeof(pWinsCnf->VerifyInterval);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_VERIFY_INTVL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->VerifyInterval,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_VERIFY_INTERVAL_VAL
);
pWinsCnf->VerifyInterval =
WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval);
}
else
{
if ( !sfNoLimitChk)
{
if (pWinsCnf->VerifyInterval <
WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval))
{
pWinsCnf->VerifyInterval =
WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval);
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_VERIFY_INTVL_NM,
pWinsCnf->VerifyInterval);
}
}
else
{
if (pWinsCnf->VerifyInterval < 60)
{
pWinsCnf->VerifyInterval = 60;
}
}
}
ReadCCInfo(pWinsCnf);
//
// Check if the admin. wants us to do pull/push replications with
// pnrs found by self.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_BURST_HANDLING_NM,
ValTyp,
pWinsCnf->fDoSpoofing,
0,
TRUE
);
if (pWinsCnf->fDoSpoofing)
{
pWinsCnf->fDoSpoofing = TRUE; //for robustness
}
#if MCAST > 0
//
// Check if the admin. wants us to do pull/push replications with
// pnrs found by self.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_USE_SELF_FND_PNRS_NM,
ValTyp,
pWinsCnf->fUseSelfFndPnrs,
0,
FALSE
);
if (pWinsCnf->fUseSelfFndPnrs)
{
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
Sz = sizeof(pWinsCnf->McastTtl);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_MCAST_TTL_NM,
NULL,
&ValTyp,
(LPBYTE)&pWinsCnf->McastTtl,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->McastTtl = WINSCNF_DEF_MCAST_TTL;
}
else
{
if (
(pWinsCnf->McastTtl < WINSCNF_MIN_MCAST_TTL)
||
(pWinsCnf->McastTtl > WINSCNF_MAX_MCAST_TTL)
)
{
pWinsCnf->McastTtl = WINSCNF_DEF_MCAST_TTL;
}
}
}
Sz = sizeof(pWinsCnf->McastIntvl);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_MCAST_INTVL_NM,
NULL,
&ValTyp,
(LPBYTE)&pWinsCnf->McastIntvl,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->McastIntvl = WINSCNF_DEF_MCAST_INTVL;
}
else
{
if ( pWinsCnf->McastIntvl < WINSCNF_MIN_MCAST_INTVL )
{
pWinsCnf->McastIntvl = WINSCNF_MIN_MCAST_INTVL;
}
}
}
#endif
//
// Check if replication is to be done only with configured partners.
// If set to TRUE, it means that an administrator will not be allowed
// to trigger replication to/from a WINS that this WINS does not know
// about. Default value is FALSE
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_RPL_ONLY_W_CNF_PNRS_NM,
ValTyp,
pWinsCnf->fRplOnlyWCnfPnrs,
0,
TRUE
);
//
// Robust programming (in case the registry has a value other than 1
// and later on we compare the value with TRUE)
//
if (pWinsCnf->fRplOnlyWCnfPnrs != FALSE)
{
pWinsCnf->fRplOnlyWCnfPnrs = TRUE;
}
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
(VOID)WinsMscAlloc(WINS_MAX_FILENAME_SZ, &(pWinsCnf->pWinsDb));
//
// Read in the name of the database file
//
FUTURES("when jet supports UNICODE in its api, change this")
Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_DB_FILE_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)DirPath,
&Sz
);
if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS))
{
WinsMscDealloc(pWinsCnf->pWinsDb);
pWinsCnf->pWinsDb = WINSCNF_DB_NAME_ASCII;
}
else
{
if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName))
{
WinsMscDealloc(pWinsCnf->pWinsDb);
pWinsCnf->pWinsDb = WINSCNF_DB_NAME_ASCII;
}
else
{
WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pWinsDb, WINS_MAX_FILENAME_SZ);
DBGPRINT1(DET, "WinsCnfReadWinsInfo: Db file path is (%s)\n", pWinsCnf->pWinsDb);
}
}
RetVal = ReadClusterIp(
sParametersKey,
&WinsClusterIpAddress
);
if (ERROR_SUCCESS == RetVal) {
NmsLocalAdd.Add.IPAdd = WinsClusterIpAddress;
} else {
DBGPRINT1(DET, "ReadClusterIp: Returned (%ld)\n", RetVal);
}
}
//
// Read in the PriorityClassHigh value. Default is normal
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_PRIORITY_CLASS_HIGH_NM,
ValTyp,
pWinsCnf->WinsPriorityClass,
0,
WINSINTF_E_NORMAL
);
if (pWinsCnf->WinsPriorityClass != WINSINTF_E_NORMAL)
{
if (WinsCnf.WinsPriorityClass != WINSINTF_E_HIGH)
{
WinsSetPriorityClass(WINSINTF_E_HIGH);
}
}
else
{
if (WinsCnf.WinsPriorityClass != WINSINTF_E_NORMAL)
{
WinsSetPriorityClass(WINSINTF_E_NORMAL);
}
}
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
//
// Read in the InitTimeState value. Default is FALSE
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_INIT_TIME_PAUSE_NM,
ValTyp,
fWinsCnfInitStatePaused,
0,
FALSE
);
//
// Read in the name of the recovery file
//
(VOID)WinsMscAlloc(WINS_MAX_FILENAME_SZ, &(pWinsCnf->pLogFilePath));
Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_LOG_FILE_PATH_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)DirPath,
&Sz
);
if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS))
{
DBGPRINT1(ERR, "WinsCnfReadInfo: RetVal=(%x)\n", RetVal);
WinsMscDealloc(pWinsCnf->pLogFilePath);
pWinsCnf->pLogFilePath = DEFAULT_LOG_PATH;
}
else
{
if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName))
{
DBGPRINT0(ERR, "WinsCnfReadInfo:WinsMscGetName returned FALSE\n");
WinsMscDealloc(pWinsCnf->pLogFilePath);
pWinsCnf->pLogFilePath = DEFAULT_LOG_PATH;
}
else
{
DBGPRINT1(DET, "WinsCnfReadInfo:pHoldFileName=%s\n", pHoldFileName);
WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pLogFilePath, WINS_MAX_FILENAME_SZ);
}
}
//
// Check if user wants logging to be turned on.
// In case of Q servers, the user would not wish the logging to be
// turned on
//
Sz = sizeof(pWinsCnf->fLoggingOn);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_LOG_FLAG_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->fLoggingOn,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
//
// default is to turn on logging
//
pWinsCnf->fLoggingOn = TRUE;
}
else
{
//
// If user has specified logging, get the path to the log
// file if specified by user
//
if (pWinsCnf->fLoggingOn)
{
pWinsCnf->fLoggingOn = TRUE;
}
}
}
//
// Check to see if STATIC initialization of the WINS database needs
// to be done
//
Sz = sizeof(pWinsCnf->fStaticInit);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_STATIC_INIT_FLAG_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->fStaticInit,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->fStaticInit = FALSE;
}
else
{
//
// Safe programming (just in case a maintainer of this code
// assumes a BOOL field to have just TRUE and FALSE values
//
pWinsCnf->fStaticInit = pWinsCnf->fStaticInit > 0 ? TRUE : FALSE;
}
//
// If Static Initialization needs to be done, read in the name of
// the file that contains the data.
//
if(pWinsCnf->fStaticInit)
{
WinsCnfGetNamesOfDataFiles(pWinsCnf);
}
//
// Assign MaxVersNo with the default value
//
WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
//
// If the WINS server is just coming up (i.e. it is not a reinit),
// then read in the starting value of the version number counter
// if present in the registry
//
Sz = sizeof(DWORD);
(VOID)RegQueryValueEx(
sParametersKey,
WINSCNF_INIT_VERSNO_VAL_LW_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&MaxVersNo.LowPart,
&Sz
);
(VOID)RegQueryValueEx(
sParametersKey,
WINSCNF_INIT_VERSNO_VAL_HW_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&MaxVersNo.HighPart,
&Sz
);
//
// if we read in a value for the version counter
//
if (LiGtrZero(MaxVersNo) && (MaxVersNo.HighPart == 0) &&
(MaxVersNo.LowPart < MAX_START_VERS_NO))
{
//
// Use WinsCnf, not pWinsCnf since at initialization time, we always
// read into WinsCnf. At reinit, the State_e field in the WinsCnf
// structure allocated may have garbage (actually will be 0 since we
// initialize allocated memory to zero -- I might change in the
// future to improve performance)
//
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
//
// Min. Vers. to start scavenging from.
//
// NOTE: if we find local records or the special record then
// NmsScvMinScvVersNo will get changed (check out GetMaxVersNos
// in nmsdb.c
//
NmsNmhMyMaxVersNo = MaxVersNo;
NmsScvMinScvVersNo = NmsNmhMyMaxVersNo;
NmsVersNoToStartFromNextTime.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize);
NmsHighWaterMarkVersNo.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize);
}
else // this must be a reconfiguration
{
EnterCriticalSection(&NmsNmhNamRegCrtSec);
//
// change the value of the version counter if
// the new value is more than it.
//
if (LiGtr(MaxVersNo, NmsNmhMyMaxVersNo))
{
NmsNmhMyMaxVersNo = MaxVersNo;
WINSEVT_LOG_INFO_M(MaxVersNo.LowPart,
WINS_EVT_VERS_COUNTER_CHANGED);
}
NmsVersNoToStartFromNextTime.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize);
NmsHighWaterMarkVersNo.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize);
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
}
}
if (WinsCnf.State_e == WINSCNF_E_INITING)
{
//
// Check if a port has been assigned by the user.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_WINS_PORT_NO_NM,
ValTyp,
CommWinsTcpPortNo,
0,
COMM_DEFAULT_IP_PORT
);
DBGPRINT1(DET, "WinsCnfReadWinsInfo: Port No is (%d)\n", CommWinsTcpPortNo);
//
// Check if WINS should continue replication in case of an
// error in replication.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_NO_RPL_ON_ERR_NM,
ValTyp,
WinsCnf.fNoRplOnErr,
0,
TRUE
);
//
// Assign MaxVersNo with the default value
//
WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
//
// Read in the value specified in the registry for the version
// number that we should use when starting.
//
Sz = sizeof(DWORD);
(VOID)RegQueryValueEx(
sConfigRoot,
WINSCNF_INT_VERSNO_NEXTTIME_LW_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&MaxVersNo.LowPart,
&Sz
);
(VOID)RegQueryValueEx(
sConfigRoot,
WINSCNF_INT_VERSNO_NEXTTIME_HW_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&MaxVersNo.HighPart,
&Sz
);
//
// if we read in a value for the version counter and it is greater
// than the high-water mark currently there
//
if (LiGtr(MaxVersNo, NmsHighWaterMarkVersNo))
{
fWinsCnfReadNextTimeVersNo = TRUE;
//
// Use WinsCnf, not pWinsCnf since at initialization time,
// we always read into WinsCnf. At reinit, the State_e field
// in the WinsCnf structure allocated may have garbage
// (actually will be 0 since we initialize allocated memory
// to zero -- I might change in the future to improve
// performance)
//
//
// Min. Vers. to start scavenging from.
//
// NOTE: if we find local records or the special record then
// NmsScvMinScvVersNo will get changed (check out GetMaxVersNos
// in nmsdb.c
//
if (LiLtr(NmsNmhMyMaxVersNo, MaxVersNo))
{
NmsNmhMyMaxVersNo = MaxVersNo;
NmsScvMinScvVersNo = NmsNmhMyMaxVersNo;
}
NmsVersNoToStartFromNextTime.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize);
NmsHighWaterMarkVersNo.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize);
}
} //end of if state is INITING
//
// Check to see if a backup directory has been specified for the WINS
// database
//
//
// Read in the name of the recovery file
//
Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_BACKUP_DIR_PATH_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)DirPath,
&Sz
);
if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS))
{
pWinsCnf->pBackupDirPath = NULL;
}
else
{
if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName))
{
pWinsCnf->pBackupDirPath = NULL;
}
else
{
WinsMscAlloc(Sz + sizeof(WINS_BACKUP_DIR_ASCII), &pWinsCnf->pBackupDirPath);
FUTURES("When Jet starts taking UNICODE input, get rid of this")
WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pBackupDirPath, WINS_MAX_FILENAME_SZ);
strcat(pWinsCnf->pBackupDirPath, WINS_BACKUP_DIR_ASCII);
//
// No need to look at the return code.
//
CreateDirectoryA(pWinsCnf->pBackupDirPath, NULL);
}
}
//
// Check to see if the admin. has told WINS to do a backup on
// termination
//
Sz = sizeof(pWinsCnf->fDoBackupOnTerm);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_DO_BACKUP_ON_TERM_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->fDoBackupOnTerm,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->fDoBackupOnTerm = FALSE;
}
//
// Check to see if static records have to be treated as p-static
//
Sz = sizeof(pWinsCnf->fPStatic);
RetVal = RegQueryValueEx(
sParametersKey,
WINSCNF_MIGRATION_ON_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->fPStatic,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
pWinsCnf->fPStatic = FALSE;
}
//
// Read max wins registration que len.
//
QUERY_VALUE_M(
sParametersKey,
WINSCNF_BURST_QUE_SIZE_NM,
ValTyp,
QueOtherNbtWrkQueMaxLen,
0,
WINS_QUEUE_HWM
);
if (QueOtherNbtWrkQueMaxLen < WINS_QUEUE_HWM_MIN) {
QueOtherNbtWrkQueMaxLen = WINS_QUEUE_HWM_MIN;
} else if (QueOtherNbtWrkQueMaxLen > WINS_QUEUE_HWM_MAX) {
QueOtherNbtWrkQueMaxLen = WINS_QUEUE_HWM_MAX;
}
// Read whether or not we randomize 1c list retrieval.
QUERY_VALUE_M(
sParametersKey,
WINSCNF_RANDOMIZE_1C_LIST_NM,
ValTyp,
WinsCnf.fRandomize1CList,
0,
FALSE
);
} // end of try ..
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsCnfReadWinsInfo");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_SFT_ERR);
}
return;
}
VOID
ReadCCInfo(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
Function to read in CC info
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
SYSTEMTIME CurrTime;
DWORD Sz;
LONG RetVal;
DWORD ValTyp;
VERS_NO_T MaxVersNo;
WINSEVT_STRS_T EvtStr;
DBGENTER("ReadCCInfo\n");
//
// Open the Consistency Chk Key
//
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
_WINS_CFG_CC_KEY,
0, //must be zero (reserved)
KEY_READ | KEY_WRITE, //we desire read/write access
// to the key
&sCCKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_OPEN_CC_KEY
);
pWinsCnf->CC.TimeInt = MAXULONG;
return;
}
Sz = sizeof(pWinsCnf->CC.TimeInt);
RetVal = RegQueryValueEx(
sCCKey,
WINSCNF_CC_INTVL_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->CC.TimeInt,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_CC_INTERVAL_VAL
);
pWinsCnf->CC.TimeInt = WINSCNF_CC_DEF_INTERVAL;
}
else
{
if ( !sfNoLimitChk)
{
if (pWinsCnf->CC.TimeInt < WINSCNF_CC_MIN_INTERVAL)
{
pWinsCnf->CC.TimeInt = WINSCNF_CC_MIN_INTERVAL;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL,
NULL, __LINE__, "ud",
WINSCNF_CC_INTVL_NM,
pWinsCnf->CC.TimeInt);
}
}
else
{
if (pWinsCnf->CC.TimeInt < 60)
{
pWinsCnf->CC.TimeInt = 60;
}
}
}
Sz = sizeof(pWinsCnf->CC.MaxRecsAAT);
RetVal = RegQueryValueEx(
sCCKey,
WINSCNF_CC_MAX_RECS_AAT_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->CC.MaxRecsAAT,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_CC_MAX_RECS_AAT_VAL
);
pWinsCnf->CC.MaxRecsAAT = WINSCNF_CC_DEF_RECS_AAT;
}
else
{
if (pWinsCnf->CC.MaxRecsAAT < WINSCNF_CC_MIN_RECS_AAT)
{
if ( !sfNoLimitChk)
{
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_MAX_RECS_AAT,
NULL, __LINE__, "udd",
WINSCNF_CC_MAX_RECS_AAT_NM,
WINSCNF_CC_MIN_RECS_AAT,
pWinsCnf->CC.MaxRecsAAT);
pWinsCnf->CC.MaxRecsAAT = WINSCNF_CC_MIN_RECS_AAT;
}
else
{
if (pWinsCnf->CC.MaxRecsAAT < 2)
{
pWinsCnf->CC.MaxRecsAAT = 2;
}
}
}
}
Sz = sizeof(pWinsCnf->CC.fUseRplPnrs);
RetVal = RegQueryValueEx(
sCCKey,
WINSCNF_CC_USE_RPL_PNRS_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&pWinsCnf->CC.fUseRplPnrs,
&Sz
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_INFO_D_M(
WINS_SUCCESS,
WINS_EVT_CANT_GET_CC_USE_RPL_PNRS_VAL
);
pWinsCnf->CC.fUseRplPnrs = WINSCNF_CC_DEF_USE_RPL_PNRS;
}
GetLocalTime(&CurrTime);
GetSpTimeData(sCCKey, &CurrTime, &pWinsCnf->CC.fSpTime, &pWinsCnf->CC.SpTimeInt);
REG_M(
RegCloseKey(sCCKey),
WINS_EVT_CANT_CLOSE_KEY,
WINS_EXC_CANT_CLOSE_KEY
);
DBGLEAVE("ReadCCInfo\n");
return;
}
#if USENETBT > 0
//------------------------------------------------------------------------
STATUS
WinsCnfReadNbtDeviceName(
VOID
)
/*++
Routine Description:
This procedure reads the registry to get the name of NBT to bind to.
That name is stored in the Linkage section under the Netbt key.
Arguments:
Return Value:
0 if successful, -1 otherwise.
--*/
{
PTCHAR SubKeyLinkage=NETBT_LINKAGE_KEY;
HKEY Key;
PTCHAR pLinkage=TEXT("Export");
LONG Type;
LONG Status;
LONG Status2;
ULONG Size;
//
// Open the NETBT key
//
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SubKeyLinkage,
0,
KEY_READ,
&Key);
if (Status == ERROR_SUCCESS)
{
//
// now read the linkage values
//
Status = RegQueryValueEx(Key,
pLinkage,
NULL,
&Type,
NULL,
&Size);
if (Status != ERROR_SUCCESS)
{
DBGPRINT0(ERR, "Error closing the Registry key\n");
WINSEVT_LOG_M(Status, WINS_EVT_QUERY_NETBT_KEY_ERR);
(VOID)RegCloseKey(Key);
return(WINS_FAILURE);
}
else
{
//
// Let us allocate a buffer that is big enough to hold all the
// data
//
WinsMscAlloc(Size, (LPVOID *)&pWinsCnfNbtPath);
//
// now read the linkage values
//
Status = RegQueryValueEx(Key,
pLinkage,
NULL,
&Type,
(LPBYTE)pWinsCnfNbtPath,
&Size);
Status2 = RegCloseKey(Key);
if ((Status != ERROR_SUCCESS) || (Status2 != ERROR_SUCCESS))
{
DBGPRINT0(ERR, "Error closing the Registry key\n");
WINSEVT_LOG_M(Status, WINS_EVT_QUERY_NETBT_KEY_ERR);
return(WINS_FAILURE);
}
}
}
else
{
WINSEVT_LOG_D_M(Status, WINS_EVT_OPEN_NETBT_KEY_ERR);
return(WINS_FAILURE);
}
return(WINS_SUCCESS);
}
#endif
VOID
WinsCnfReadRegInfo(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to read the registry in order to populate the
WinsCnf structure
Arguments:
None
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsCnfInitConfig
Side Effects:
Comments:
None
--*/
{
try {
if (sfParametersKeyExists)
{
/*
Read in the registry information pertaining to WINS
*/
WinsCnfReadWinsInfo(pWinsCnf);
}
if (sfPartnersKeyExists)
{
//
// Read the PUSH/PULL records and other global information used for
// replication
//
WinsCnfReadPartnerInfo(pWinsCnf);
}
//
// Do a sanity check on the params. We are not interested in the
// return code
//
(VOID)SanityChkParam(pWinsCnf);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsCnfReadRegInfo");
//
// If we encountered an exception at boot time, we do not want to
// reraise the exception, since we want to come up and continue on
// For the non-initing case, the exception that we raise will be caught
// in Reinit(). For the boot time case, it is ok to come up with the
// defaults (an event message is being logged) - in WinsCnf.
// In the non-init case, the defaults are not in the memory used to
// read in the parameters (WinsCnf is initialized with stuff in
// this memory block later).
//
if (WinsCnf.State_e != WINSCNF_E_INITING)
{
WINS_RERAISE_EXC_M();
}
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR);
}
return;
}
VOID
WinsCnfCopyWinsCnf(
WINS_CLIENT_E Client_e,
PWINSCNF_CNF_T pSrc
)
/*++
Routine Description:
This function is called to copy relevant information from a WINS
Cnf structure to the master (external) Wins Cnf structure
Arguments:
pSrc - WinsCnf stucture to copy from
Externals Used:
WinsCnf
Return Value:
None
Error Handling:
Called by:
RplPullInit
Side Effects:
Comments:
This function may be enhanced in the future
Note: this function is called only by the main thread
--*/
{
BOOL fScvParamChg = FALSE;
if (Client_e == WINS_E_WINSCNF)
{
FUTURES("Queue a message to the Scavenger thread passing it pSrc")
FUTURES("That will avoid this synchronization overhead")
//
// We need to synchronize with the scavenger thread and
// RPC threads that might be looking at fRplOnlyWCnfPnrs
//
EnterCriticalSection(&WinsCnfCnfCrtSec);
//
// Also need to synchronize with the nbt threads doing
// name registrations/refreshes
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
//
// Sanity check the parameters
//
fScvParamChg = SanityChkParam(pSrc);
if (fScvParamChg)
{
//
// Initialize the scavenging stuff.
//
WinsCnf.RefreshInterval = pSrc->RefreshInterval;
WinsCnf.TombstoneInterval = pSrc->TombstoneInterval;
WinsCnf.TombstoneTimeout = pSrc->TombstoneTimeout;
WinsCnf.CC = pSrc->CC;
WinsCnf.ScvThdPriorityLvl = pSrc->ScvThdPriorityLvl;
}
//
// Store the verify interval since SanityChkParam does
// not set fScvParamChg if VerifyINterval has changed.
//
WinsCnf.VerifyInterval = pSrc->VerifyInterval;
WinsCnf.fRplOnlyWCnfPnrs = pSrc->fRplOnlyWCnfPnrs;
WinsCnf.LogDetailedEvts = pSrc->LogDetailedEvts;
WinsCnf.fAdd1Bto1CQueries = pSrc->fAdd1Bto1CQueries;
WinsCnf.fPStatic = pSrc->fPStatic;
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
WinsCnf.fDoSpoofing = pSrc->fDoSpoofing;
WinsCnf.MaxNoOfWrkThds = pSrc->MaxNoOfWrkThds;
WinsCnf.fDoBackupOnTerm = pSrc->fDoBackupOnTerm;
#if MCAST > 0
WinsCnf.fUseSelfFndPnrs = pSrc->fUseSelfFndPnrs;
WinsCnf.McastIntvl = pSrc->McastIntvl;
#endif
#if PRSCONN
WinsCnf.fPrsConn = pSrc->fPrsConn;
#endif
if (WinsCnf.fDoBackupOnTerm && pSrc->pBackupDirPath != NULL)
{
if (WinsCnf.pBackupDirPath != NULL)
{
WinsMscDealloc(WinsCnf.pBackupDirPath);
}
WinsCnf.pBackupDirPath = pSrc->pBackupDirPath;
}
LeaveCriticalSection(&WinsCnfCnfCrtSec);
// return;
}
else
{
if (Client_e == WINS_E_RPLPULL)
{
EnterCriticalSection(&WinsCnfCnfCrtSec);
//
// Copy the Scavenging parameters into the cnf structure
// just allocated so that we can compare them for
// compatibility with the new max. replication time interval
// (since the Partners key was signaled, the replication
// stuff might have changed)
//
pSrc->RefreshInterval = WinsCnf.RefreshInterval;
pSrc->TombstoneInterval = WinsCnf.TombstoneInterval;
pSrc->TombstoneTimeout = WinsCnf.TombstoneTimeout;
pSrc->VerifyInterval = WinsCnf.VerifyInterval;
//
// Wasteful here and in SanityChkParam
//
PERF("Pass an argument to SanityChk so that we don't have to do this")
PERF("See similar remark in SanityChk")
pSrc->CC = WinsCnf.CC;
//
// Sanity check the parameters.
//
// Sanity checking of the parameters is done here in
// the main thread instead of in the PULL thread because
// we don't want a situation where two different threads
// (the main thread for changes to the PARAMETERS key)
// and the PULL thread (for changes in the PARTNERS key)
// updating the WinsCnf structure
//
// Also, as an aside, we don't copy the PullInfo information
// into WinsCnf here to avoid unnecessary complication and
// synchronization that would ensue by the fact that we
// would then have two threads (main thread) and the PULL
// thread accessing that field (check Reconfig() in
// rplpull.c).
//
FUTURES("When we start supporting time interval as an attribute of PUSHing")
FUTURES("move this check inside the NmsNmhNamRegCrtSec below")
fScvParamChg = SanityChkParam(pSrc);
//
// If one or more scavenging parameters have changed,
// update WinsCnf and signal the Scavenger thread.
//
if (fScvParamChg)
{
WinsCnf.RefreshInterval = pSrc->RefreshInterval;
WinsCnf.TombstoneInterval = pSrc->TombstoneInterval;
WinsCnf.TombstoneTimeout = pSrc->TombstoneTimeout;
//
// If SanityChkParam changed Tombstone interval, then
// verify interval has also changed.
//
WinsCnf.VerifyInterval = pSrc->VerifyInterval;
}
WinsCnf.MaxRplTimeInterval = pSrc->MaxRplTimeInterval;
WinsCnf.RplType = pSrc->RplType;
LeaveCriticalSection(&WinsCnfCnfCrtSec);
}
}
//
// If the scavenging params have changed we need to signal
// the scavenger thread
//
if (fScvParamChg)
{
WinsMscSignalHdl(WinsCnf.CnfChgEvtHdl);
}
return;
}
LPVOID
WinsCnfGetNextRplCnfRec(
PRPL_CONFIG_REC_T pCnfRec,
RPL_REC_TRAVERSAL_E RecTrv_e
)
/*++
Routine Description:
This function is called to get to the next configuration record
Arguments:
pCnfRec - The current configuration record in a buffer of configuration
records
RecTrv_e - indicates how the next one should be retrieved. If set to
TRUE, it means that the next record to be retrieved is one
that follows the current record in the buffer. If set to
FALSE, the next record is retrieved using the pNext field
of the current configuration record
Externals Used:
None
Return Value:
address of the next configuration record
Error Handling:
Called by:
EstablishComm in rplpull.c, WinsPushTrigger() in wins.c
Side Effects:
Comments:
None
--*/
{
//
// If no traversal is desired, return NULL as the next record
//
if (RecTrv_e == RPL_E_NO_TRAVERSAL)
{
return(NULL);
}
//
// Go to the next configuration record in a way specified
// by the value of the RecTrv_e flag.
//
if(RecTrv_e == RPL_E_IN_SEQ)
{
pCnfRec = (PRPL_CONFIG_REC_T)(
(LPBYTE)pCnfRec + RPL_CONFIG_REC_SIZE);
}
else // RPL_E_VIA_LINK
{
return(pCnfRec->pNext);
}
return(pCnfRec);
}
VOID
WinsCnfAskToBeNotified(
WINSCNF_KEY_E KeyToMonitor_e
)
/*++
Routine Description:
This function is called to request that WINS be notified when
the information pertaining to WINS and its subkeys in the registry
changes
Arguments:
KeyToMonitor_e
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Reinit() in nms.c
WinsCnfOpenSubKeys()
WinsCnfInitConfig()
Side Effects:
Comments:
None
--*/
{
DWORD NotifyFilter = 0;
LONG RetVal;
DWORD Error;
#define CHK_RET_VAL_M { \
if (RetVal != ERROR_SUCCESS) \
{ \
DBGPRINT1(ERR, "WinsAskToBeNotified: Error = (%d)\n", RetVal); \
WINSEVT_LOG_M( \
WINS_FATAL_ERR, \
WINS_EVT_REG_NTFY_FN_ERR \
); \
} \
}
/*
* Set the notify filter. Ask to be notified for all changes.
*/
NotifyFilter = REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_CHANGE_ATTRIBUTES |
REG_NOTIFY_CHANGE_LAST_SET |
REG_NOTIFY_CHANGE_SECURITY ;
switch(KeyToMonitor_e)
{
case(WINSCNF_E_WINS_KEY):
// DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: WINS Key\n");
RetVal = RegNotifyChangeKeyValue(
sConfigRoot,
TRUE, //report changes in key and all subkeys
REG_NOTIFY_CHANGE_NAME,
WinsCnf.WinsKChgEvtHdl,
TRUE //Async signaling is what we want
);
CHK_RET_VAL_M;
break;
case(WINSCNF_E_PARAMETERS_KEY):
// DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: PARAMETERS Key\n");
RetVal = RegNotifyChangeKeyValue(
sParametersKey,
TRUE, //report changes in key and all subkeys
NotifyFilter,
WinsCnf.ParametersKChgEvtHdl,
TRUE //Async signaling is what we want
);
CHK_RET_VAL_M;
break;
case(WINSCNF_E_PARTNERS_KEY):
// DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: PARTNERS Key\n");
RetVal = RegNotifyChangeKeyValue(
sPartnersKey,
TRUE, //report changes in key and all subkeys
NotifyFilter,
WinsCnf.PartnersKChgEvtHdl,
TRUE //Async signaling is what we want
);
CHK_RET_VAL_M;
break;
FUTURES("Remove the following case")
//
// The following case would never get exercised.
//
case(WINSCNF_E_ALL_KEYS):
RetVal = RegNotifyChangeKeyValue(
sConfigRoot,
TRUE, //report changes in key and all subkeys
REG_NOTIFY_CHANGE_NAME,
WinsCnf.WinsKChgEvtHdl,
TRUE //Async signaling is what we want
);
CHK_RET_VAL_M;
if (sfParametersKeyExists)
{
RetVal = RegNotifyChangeKeyValue(
sParametersKey,
TRUE, //report changes in key and
//all subkeys
NotifyFilter,
WinsCnf.ParametersKChgEvtHdl,
TRUE //Async signaling is what we
// want
);
if (RetVal != ERROR_SUCCESS)
{
Error = GetLastError();
if (Error == ERROR_BADKEY)
{
//
// Key must not be there
//
sfParametersKeyExists = FALSE;
}
else
{
DBGPRINT1(ERR,
"WinsCnfAskToBeNotified: RegNotifyChangeKeyValue error = (%d)\n",
Error);
}
}
}
if (sfPartnersKeyExists)
{
RetVal = RegNotifyChangeKeyValue(
sPartnersKey,
TRUE, //report changes in key and
//all subkeys
NotifyFilter,
WinsCnf.PartnersKChgEvtHdl,
TRUE //Async signaling is what we
//want
);
if (RetVal != ERROR_SUCCESS)
{
Error = GetLastError();
if (Error == ERROR_BADKEY)
{
//
// Key must not be there
//
sfPartnersKeyExists = FALSE;
}
else
{
DBGPRINT1(ERR,
"WinsCnfAskToBeNotified: RegNotifyChangeKeyValue error = (%d)\n",
Error);
}
}
}
break;
default:
DBGPRINT1(ERR, "WinsCnfAskToBeNotified: Wrong Hdl (%d)\n",
KeyToMonitor_e);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
break;
}
return;
}
VOID
WinsCnfDeallocCnfMem(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to deallocate the Wins Cnf structure and
memory associated with it
Arguments:
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Reconfig in rplpull.c
Side Effects:
Comments:
None
--*/
{
try {
//
// Deallocate the buffer holding one or more names of files used
// for STATIC initialization of WINS
//
if (pWinsCnf->pStaticDataFile != NULL)
{
WinsMscDealloc(pWinsCnf->pStaticDataFile);
}
WinsMscDealloc(pWinsCnf);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsCnfDeallocCnfMem");
DBGPRINT0(EXC, "WinsCnfDeallocCnfMem: Got an exception\n");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR);
}
return;
}
VOID
GetKeyInfo(
IN HKEY Key,
IN WINSCNF_KEY_E KeyType_e,
OUT LPDWORD pNoOfSubKeys,
OUT LPDWORD pNoOfVals
)
/*++
Routine Description:
This function is called to get the number of subkeys under a key
Arguments:
Key - Key whose subkey count has to be determined
KeyType_e
pNoOfSubKeys
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
GetPnrInfo()
Side Effects:
Comments:
None
--*/
{
TCHAR ClsStr[40];
DWORD ClsStrSz = sizeof(ClsStr);
DWORD LongestKeyLen;
DWORD LongestKeyClassLen;
DWORD LongestValueNameLen;
DWORD LongestValueDataLen;
DWORD SecDesc;
LONG RetVal;
FILETIME LastWrite;
/*
Query the key. The subkeys are IP addresses of PULL
partners.
*/
RetVal = RegQueryInfoKey(
Key,
ClsStr,
&ClsStrSz,
NULL, //must be NULL, reserved
pNoOfSubKeys,
&LongestKeyLen,
&LongestKeyClassLen,
pNoOfVals,
&LongestValueNameLen,
&LongestValueDataLen,
&SecDesc,
&LastWrite
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_M(
WINS_FATAL_ERR,
KeyType_e == WINSCNF_E_DATAFILES_KEY ?
WINS_EVT_CANT_QUERY_DATAFILES_KEY :
((KeyType_e == WINSCNF_E_PULL_KEY) ?
WINS_EVT_CANT_QUERY_PULL_KEY :
((KeyType_e == WINSCNF_E_PUSH_KEY) ?
WINS_EVT_CANT_QUERY_PUSH_KEY :
WINS_EVT_CANT_QUERY_SPEC_GRP_MASKS_KEY))
);
WINS_RAISE_EXC_M(WINS_EXC_CANT_QUERY_KEY);
}
return;
}
VOID
WinsCnfOpenSubKeys(
VOID
)
/*++
Routine Description:
This function opens the subkeys of the WINS key. The subkeys are
the PARTNERS key and the PARAMETERS key.
Arguments:
None
Externals Used:
sfParamatersKeyExists
sfPartnersKeyExists
Return Value:
None
Error Handling:
Called by:
WinsCnfInitConfig()
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
//
// Check if the Parameters and Partners Keys are present
//
ChkWinsSubKeys();
//
// Try to open the Parameters key if it exists
//
if ((sfParametersKeyExists) && (!sfParametersKeyOpen))
{
/*
* Open the Parameters key
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
_WINS_CFG_PARAMETERS_KEY,
0, //must be zero (reserved)
KEY_READ | KEY_WRITE, //we desire read/write access
// to the key
&sParametersKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
WINS_SUCCESS,
WINS_EVT_CANT_OPEN_PARAMETERS_KEY
);
sfParametersKeyExists = FALSE;
}
else
{
sfParametersKeyOpen = TRUE;
WinsCnfAskToBeNotified(WINSCNF_E_PARAMETERS_KEY);
}
}
//
// Try to open the Partners key if it exists
//
if ((sfPartnersKeyExists) && (!sfPartnersKeyOpen))
{
/*
* Open the Partners key
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
_WINS_CFG_PARTNERS_KEY,
0, //must be zero(reserved)
KEY_READ, //we desire read
//access to the key
&sPartnersKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
WINS_SUCCESS,
WINS_EVT_CANT_OPEN_KEY
);
sfPartnersKeyExists = FALSE;
}
else
{
sfPartnersKeyOpen = TRUE;
WinsCnfAskToBeNotified(WINSCNF_E_PARTNERS_KEY);
}
}
return;
} //WinsCnfOpenSubKeys()
BOOL
SanityChkParam(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to ensure that the time intervals for
scavenging specified in WinsCnf are compatible with the ones
used for replication
Arguments:
pWinsCnf - ptr to the WINS configuration
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsCnfCopyWinsCnf (during reinitialization of the WINS), by
WinsCnfReadRegInfo() during initialization of the WINS
Side Effects:
The scavenging intervals could be affected
Comments:
This function must be called from inside the critical section
guarded by WinsCnfCnfCrtSec except at process initialization.
--*/
{
DWORD MinTombInterval;
BOOL fScvParamChg = FALSE;
WINSEVT_STRS_T EvtStr;
EvtStr.NoOfStrs = 1;
DBGENTER("SanityChkParam\n");
//
// Get the minimum tombstone time interval
//
MinTombInterval = WINSCNF_MAKE_TOMB_INTVL_M(pWinsCnf->RefreshInterval,
pWinsCnf->MaxRplTimeInterval);
//
// Make the actual equal to the min. if it is less
//
if (!sfNoLimitChk && (pWinsCnf->TombstoneInterval < MinTombInterval))
{
DBGPRINT2(FLOW, "SanityChkParam: Adjusting Tombstone Interval from (%d) to (%d)\n", pWinsCnf->TombstoneInterval, MinTombInterval);
FUTURES("This is actually a warning. Use a different macro or enhance it")
FUTURES("Currently, it will log this message as an informational")
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL_R,
NULL, __LINE__, "ud",
WINSCNF_TOMBSTONE_INTVL_NM,
MinTombInterval );
pWinsCnf->TombstoneInterval = MinTombInterval;
//
// Verify Interval is dependent on the tombstone interval
//
pWinsCnf->VerifyInterval = WINSCNF_MAKE_VERIFY_INTVL_M(MinTombInterval);
fScvParamChg = TRUE;
}
//
// reusing the var. The time interval is for tombstone timeout
//
MinTombInterval =
WINSCNF_MAKE_TOMBTMOUT_INTVL_M(pWinsCnf->MaxRplTimeInterval);
if (!sfNoLimitChk && (pWinsCnf->TombstoneTimeout < MinTombInterval))
{
DBGPRINT2(FLOW, "SanityChkParam: Adjusting Tombstone Timeout from (%d) to (%d)\n", pWinsCnf->TombstoneInterval, MinTombInterval);
pWinsCnf->TombstoneTimeout = MinTombInterval;
WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL_R,
NULL, __LINE__, "ud",
WINSCNF_TOMBSTONE_TMOUT_NM,
MinTombInterval );
if (!fScvParamChg)
{
fScvParamChg = TRUE;
}
}
if (!fScvParamChg)
{
PERF("Pass an argument to SanityChk so that we don't have to do this")
PERF("for CC for the case where we just read the partner info. See")
PERF("WinsCnfCopyWinsCnf for the case where client_e is WINS_E_RPLPULL")
if (
(WinsCnf.RefreshInterval != pWinsCnf->RefreshInterval)
||
(WinsCnf.TombstoneInterval != pWinsCnf->TombstoneInterval)
||
(WinsCnf.TombstoneTimeout != pWinsCnf->TombstoneTimeout)
||
(WinsCnf.CC.TimeInt != pWinsCnf->CC.TimeInt)
||
(WinsCnf.CC.SpTimeInt != pWinsCnf->CC.SpTimeInt)
||
(WinsCnf.CC.fUseRplPnrs != pWinsCnf->CC.fUseRplPnrs)
||
(WinsCnf.CC.MaxRecsAAT != pWinsCnf->CC.MaxRecsAAT)
)
{
fScvParamChg = TRUE;
}
}
DBGLEAVE("SanityChkParam\n");
return(fScvParamChg);
}
STATUS
WinsCnfGetNamesOfDataFiles(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function gets the names of all the datafiles that need to
be used for initializing WINS.
Arguments:
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
HKEY DFKey;
DWORD BuffSize;
STATUS RetStat = WINS_SUCCESS;
PWINSCNF_DATAFILE_INFO_T pSaveDef;
DWORD NoOfSubKeys;
DBGENTER("WinsCnfGetNamesOfDataFiles\n");
//
// Store timestamp of initialization in the statistics structure
//
WinsIntfSetTime(NULL, WINSINTF_E_INIT_DB);
//
// Set up the default name
//
//
// First allocate the buffer that will hold the default file name
//
WinsMscAlloc(WINSCNF_FILE_INFO_SZ, &pWinsCnf->pStaticDataFile);
lstrcpy(pWinsCnf->pStaticDataFile->FileNm, WINSCNF_STATIC_DATA_NAME);
//
// The default name contains a %<string>% in it. Therefore, specify
// the type as EXPAND_SZ
//
pWinsCnf->pStaticDataFile->StrType = REG_EXPAND_SZ;
pWinsCnf->NoOfDataFiles = 1;
pSaveDef = pWinsCnf->pStaticDataFile; //save the address
/*
* Open the DATAFILES key
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
_WINS_CFG_DATAFILES_KEY,
0, //must be zero (reserved)
KEY_READ, //we desire read access to the keyo
&DFKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
WINS_SUCCESS,
WINS_EVT_CANT_OPEN_DATAFILES_KEY
);
DBGLEAVE("WinsCnfGetNamesOfDataFiles\n");
return(FALSE);
}
else
try {
{
//
// Get the count of data files listed under the DATAFILES
// key
//
GetKeyInfo(
DFKey,
WINSCNF_E_DATAFILES_KEY,
&NoOfSubKeys, //ignored
&pWinsCnf->NoOfDataFiles
);
}
if (pWinsCnf->NoOfDataFiles > 0)
{
DWORD Index;
PWINSCNF_DATAFILE_INFO_T pTmp;
TCHAR ValNmBuff[MAX_PATH];
DWORD ValNmBuffSz = MAX_PATH;
//
// Allocate buffer big enough to hold data for
// the number of subkeys found under the PULL key
//
BuffSize = WINSCNF_FILE_INFO_SZ * pWinsCnf->NoOfDataFiles;
WinsMscAlloc( BuffSize, &pWinsCnf->pStaticDataFile);
/*
* Enumerate the values
*/
for(
Index = 0, pTmp = pWinsCnf->pStaticDataFile;
Index < pWinsCnf->NoOfDataFiles;
// no third expression
)
{
ValNmBuffSz = sizeof(ValNmBuff)/sizeof(TCHAR); //init before
//every call
BuffSize = sizeof(pWinsCnf->pStaticDataFile->FileNm);
RetVal = RegEnumValue(
DFKey,
Index, //key
ValNmBuff,
&ValNmBuffSz,
(LPDWORD)NULL, //reserved
&pTmp->StrType,
(LPBYTE)(pTmp->FileNm),//ptr to var. to
//hold name of
//datafile
&BuffSize //not looked at by us
);
if (RetVal != ERROR_SUCCESS)
{
continue;
}
//
// if StrType is not REG_SZ or REG_EXPAND_SZ, go to
// the next Value
//
if (
(pTmp->StrType != REG_EXPAND_SZ)
&&
(pTmp->StrType != REG_SZ)
)
{
continue;
}
Index++;
pTmp = (PWINSCNF_DATAFILE_INFO_T)((LPBYTE)pTmp +
WINSCNF_FILE_INFO_SZ);
}
//
// If not even one valid name was retrieved, get rid of the
// buffer
//
if (Index == 0)
{
//
// Get rid of the buffer
//
WinsMscDealloc((LPBYTE)pWinsCnf->pStaticDataFile);
//
// We will use the default
//
pWinsCnf->pStaticDataFile = pSaveDef;
}
else
{
//
// Get rid of the default name buffer
//
WinsMscDealloc((LPBYTE)pSaveDef);
}
pWinsCnf->NoOfDataFiles = Index;
}
} // end of try ..
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsCnfGetNamesOfDataFiles");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
RetStat = WINS_FAILURE;
}
REG_M(
RegCloseKey(DFKey),
WINS_EVT_CANT_CLOSE_KEY,
WINS_EXC_CANT_CLOSE_KEY
);
DBGLEAVE("WinsCnfGetNamesOfDataFiles\n");
return(RetStat);
}
VOID
WinsCnfCloseKeys(
VOID
)
/*++
Routine Description:
This function closes the the open keys. The keys closed are
the WINS key, the PARTNERS key, and the PARAMETERS key.
Arguments:
None
Externals Used:
sfParametersKeyExists
sfPartnersKeyExists
Return Value:
None
Error Handling:
Called by:
Reinit()
Side Effects:
Comments:
We don't look at the return code of RegCloseKey. This is because
we might call this function even with the key not being open (not
the case currently).
--*/
{
//
// Close the PARAMETERS key if it is open
//
if (sfParametersKeyOpen)
{
(VOID)RegCloseKey(sParametersKey);
}
//
// Close the PARTNERS key if it is open
//
if (sfPartnersKeyOpen)
{
(VOID)RegCloseKey(sPartnersKey);
}
#if 0
//
// NOTE NOTE NOTE: Build 436. If we attempt to close a key that has been
// deleted from the registry NT comes down
//
//
// Close the WINS key
//
(VOID)RegCloseKey(sConfigRoot);
#endif
return;
} //WinsCnfCloseKeys()
VOID
ChkWinsSubKeys(
VOID
)
/*++
Routine Description:
This function is called to check whether we have the PARTNERS
and PARAMETERS sub-keys under the root subkey of WINS.
Arguments:
None
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Reinit() in nms.c
Side Effects:
Comments:
None
--*/
{
DWORD NoOfSubKeys = 0;
DWORD KeyNameSz;
TCHAR KeyName[20];
FILETIME LastWrite;
LONG RetVal;
BOOL fParametersKey = FALSE;
BOOL fPartnersKey = FALSE;
/*
* Get each subkey's name
*/
RetVal = ERROR_SUCCESS;
for(
;
RetVal == ERROR_SUCCESS;
NoOfSubKeys++
)
{
KeyNameSz = sizeof(KeyName)/sizeof(TCHAR); //init before every call
RetVal = RegEnumKeyEx(
sConfigRoot,
NoOfSubKeys, //key
KeyName,
&KeyNameSz,
NULL, //reserved
NULL, //don't need class name
NULL, //ptr to var. to hold class name
&LastWrite //not looked at by us
);
if (RetVal != ERROR_SUCCESS)
{
continue;
}
if (lstrcmp(KeyName, _WINS_CFG_PARAMETERS_KEY) == 0)
{
fParametersKey = TRUE;
}
if (lstrcmp(KeyName, _WINS_CFG_PARTNERS_KEY) == 0)
{
fPartnersKey = TRUE;
}
}
//
// if the Parameters key does not exist but it existed before,
// close the key to get rid of the handle we have
//
if (!fParametersKey)
{
if (sfParametersKeyExists)
{
sfParametersKeyExists = FALSE;
sfParametersKeyOpen = FALSE;
}
}
else
{
sfParametersKeyExists = TRUE;
}
//
// if the Partners key does not exist but it existed before,
// close the key to get rid of the handle we have
//
if (!fPartnersKey)
{
if (sfPartnersKeyExists)
{
sfPartnersKeyExists = FALSE;
sfPartnersKeyOpen = FALSE;
}
}
else
{
sfPartnersKeyExists = TRUE;
}
return;
} //ChkWinsSubKeys()
VOID
GetSpTimeData(
HKEY SubKey,
LPSYSTEMTIME pCurrTime,
LPBOOL pfSpTime,
LPDWORD pSpTimeIntvl
/*++
Routine Description:
This function is called to get the specific time and period information
for a PULL/PUSH record.
Arguments:
SubKey - Key of a WINS under the Pull/Push key
pCnfRFec - ptr to the Conf. record of the WINS
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_NO_SP_TIME
Error Handling:
Called by:
GetPnrInfo
Side Effects:
Comments:
None
--*/
)
{
DWORD ValTyp;
BYTE tSpTime[MAX_SZ_SIZE];
BYTE SpTime[MAX_SZ_SIZE];
LPBYTE pSpTime = SpTime;
DWORD Sz = sizeof(tSpTime);
LONG RetVal;
DWORD Hr = 0;
DWORD Mt = 0;
DWORD Sec = 0;
LONG TimeInt;
// DBGENTER("GetSpTimeData\n");
*pfSpTime = FALSE;
try {
Sz = sizeof(tSpTime);
RetVal = RegQueryValueEx(
SubKey,
WINSCNF_SP_TIME_NM,
NULL, //reserved; must be NULL
&ValTyp,
tSpTime,
&Sz
);
//
// If the user has not specifed a specific time, then we use
// the current time as the specific time. For current time,
// the interval is 0
//
if (RetVal == ERROR_SUCCESS)
{
#ifdef UNICODE
(VOID)WinsMscConvertUnicodeStringToAscii(tSpTime, SpTime, MAX_SZ_SIZE);
#else
pSpTime = tSpTime;
#endif
RetVal = (LONG)sscanf(pSpTime, "%d:%d:%d", &Hr, &Mt, &Sec);
if ((RetVal == EOF) || (RetVal == 0))
{
DBGPRINT1(ERR, "GetSpTime: Wrong time format (%s)\n",
pSpTime);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_TIME_FORMAT);
}
else
{
*pSpTimeIntvl = 0;
if ((Hr <= 23) && (Mt <= 59) && (Sec <= 59))
{
TimeInt = ((Hr * 3600) + (Mt * 60) + Sec) -
((pCurrTime->wHour * 3600) +
(pCurrTime->wMinute * 60) +
pCurrTime->wSecond);
if (TimeInt < 0)
{
*pSpTimeIntvl = (24 * 3600) + TimeInt;
}
else
{
*pSpTimeIntvl = TimeInt;
}
*pfSpTime = TRUE;
DBGPRINT1(DET, "GetSpTimeData: Sp. Time Interval is %d\n",
*pSpTimeIntvl);
}
else
{
DBGPRINT0(DET, "GetSpTimeData: WRONG TIME FORMAT\n");
}
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("GetSpTime");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CONFIG_ERR);
}
// DBGLEAVE("GetSpTimeData\n");
return;
}
#if MCAST > 0
STATUS
WinsCnfAddPnr(
RPL_RR_TYPE_E RRType_e,
LPBYTE pPnrAdd
)
/*++
Routine Description:
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
HKEY CnfKey;
HKEY PnrKey;
DWORD NewKeyInd;
DBGENTER("WinsCnfAddPnr\n");
/*
* Open the key (PULL/PUSH)
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
RRType_e == RPL_E_PULL ?
_WINS_CFG_PULL_KEY :
_WINS_CFG_PUSH_KEY, //subkey for WINS
0, //must be zero (reserved)
KEY_CREATE_SUB_KEY, //we want "subkey create" priv
&CnfKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
RetVal,
RRType_e == RPL_E_PULL ?
WINS_EVT_CANT_OPEN_PULL_KEY :
WINS_EVT_CANT_OPEN_PUSH_KEY
);
return (WINS_FAILURE);
}
//
// Add the pnr
//
RetVal = RegCreateKeyExA(
CnfKey, //predefined key value
pPnrAdd, //subkey for WINS
0, //must be zero (reserved)
"Class", //class -- may change in future
REG_OPTION_NON_VOLATILE, //non-volatile information
KEY_ALL_ACCESS, //we desire all access to the keyo
NULL, //let key have default sec. attributes
&PnrKey, //handle to key
&NewKeyInd //is it a new key (out arg)
);
if (RetVal != ERROR_SUCCESS)
{
WINSEVT_LOG_M(
RetVal,
RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_SUBKEY
: WINS_EVT_CANT_OPEN_PUSH_SUBKEY
);
DBGPRINT3(ERR, "WinsCnfAddPnr: Could not create key with address = (%s) under the %s Key. RetVal = (%d)\n", pPnrAdd,
RRType_e == RPL_E_PULL ? "PULL" : "PUSH",
RetVal);
return(WINS_FAILURE);
}
else
{
if (NewKeyInd != REG_CREATED_NEW_KEY)
{
DBGPRINT2(ERR, "WinsCnfAddPnr: key with address = (%s) under the %s Key already present\n", pPnrAdd, RRType_e == RPL_E_PULL ? "PULL" : "PUSH");
}
else
{
//
// If Pull pnr, add the time interval
//
if (RRType_e == RPL_E_PULL)
{
//
// Add the time interval
//
SetVal(PnrKey, WINSCNF_RPL_INTERVAL_NM, REG_DWORD,
(LPWSTR)WINSCNF_TIME_INT_W_SELF_FND_PNRS, sizeof(DWORD));
}
SetVal(PnrKey, WINSCNF_SELF_FND_NM, REG_DWORD,
(LPWSTR)TRUE, sizeof(DWORD));
}
RegCloseKey(PnrKey);
RegCloseKey(CnfKey);
}
DBGLEAVE("WinsCnfAddPnr\n");
return(WINS_SUCCESS);
}
STATUS
WinsCnfDelPnr(
RPL_RR_TYPE_E RRType_e,
LPBYTE pPnrAdd
)
/*++
Routine Description:
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
HKEY TypeOfPnrKey;
HKEY PnrKey;
//WCHAR Key[160];
WCHAR String[160];
BOOL fSelfFnd;
DWORD Sz;
DWORD ValType;
DBGENTER("WinsCnfDelPnr\n");
WinsMscConvertAsciiStringToUnicode(pPnrAdd, (LPBYTE)String, sizeof(String)/sizeof(WCHAR));
/*
* Open the key (PULL/PUSH)
*/
RetVal = RegOpenKeyEx(
sConfigRoot, //predefined key value
RRType_e == RPL_E_PULL ?
_WINS_CFG_PULL_KEY :
_WINS_CFG_PUSH_KEY,
0, //must be zero (reserved)
KEY_ALL_ACCESS,
&TypeOfPnrKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
CHECK("Is there any need to log this")
WINSEVT_LOG_INFO_M(
WINS_SUCCESS,
RRType_e == RPL_E_PULL ?
WINS_EVT_CANT_OPEN_PULL_KEY :
WINS_EVT_CANT_OPEN_PUSH_KEY
);
//--ft: Prefix bug 444974 - this key has to exist. If absurdly is missing, we won't find
// the partner anyhow.
return (WINS_SUCCESS);
}
RetVal = RegOpenKeyEx(
TypeOfPnrKey, //predefined key value
String,
0, //must be zero (reserved)
KEY_ALL_ACCESS, //we want "subkey create" priv
&PnrKey //handle to key
);
if (RetVal != ERROR_SUCCESS)
{
DBGPRINT3(ERR, "WinsCnfDelPnr: %s Pnr with address = (%s) is Non-existent. RetVal = (%d)",
RRType_e == RPL_E_PULL ? "PULL" : "PUSH", pPnrAdd,
RetVal);
return(WINS_SUCCESS);
}
else
{
Sz = sizeof(fSelfFnd);
RetVal = RegQueryValueEx(
PnrKey,
WINSCNF_SELF_FND_NM,
NULL,
&ValType,
(LPBYTE)&fSelfFnd,
&Sz
);
//
// If SelfFnd is there and it's value is 1, delete it
//
if ((RetVal == ERROR_SUCCESS) && (fSelfFnd == 1))
{
RetVal = RegDeleteKey(TypeOfPnrKey, String);
if (RetVal != ERROR_SUCCESS)
{
DBGPRINT3(ERR, "WinsCnfDelPnr: Could not delete %s Pnr with address = (%s). RetVal = (%d)",
RRType_e == RPL_E_PULL ? "PULL" : "PUSH", pPnrAdd,
RetVal);
RegCloseKey(PnrKey);
return(WINS_FAILURE);
}
}
RegCloseKey(TypeOfPnrKey);
}
DBGLEAVE("WinsCnfDelPnr\n");
return(WINS_SUCCESS);
}
DWORD
SetVal(
HKEY RootKey,
LPWSTR pName,
DWORD ValType,
LPWSTR pVal,
DWORD ValSize
)
{
UINT Status = WINS_SUCCESS;
LONG RetVal;
DWORD Val;
if (ValType == REG_DWORD)
{
Val = PtrToUlong (pVal);
}
RetVal = RegSetValueEx(
RootKey,
pName,
0, //reserved -- must be 0
ValType,
ValType == REG_DWORD ? (LPBYTE)&Val : (LPBYTE)pVal,
ValType == REG_DWORD ? ValSize : lstrlen(pVal)
);
if (RetVal != ERROR_SUCCESS)
{
printf("SetVal: Could not set value of %s\n", pName);
Status = WINS_FAILURE;
}
return(Status);
}
#endif
DWORD
WinsCnfWriteReg(
LPVOID pTmp
)
/*++
Routine Description:
This function write the value of the version counter to be used
at the next invocation.
Arguments:
pTmp - Will be NULL if WinsCnfNextTimeVersNo was found in the registry
when WINS came up.
Externals Used:
NmsHighWaterMarkVersNo
NmsVersNoToStartFromNextTime
NmsNmhNamRegCrtSec
NmsRangeSize
NmsHalfRangeSize
sfVersNoChanged
sfVersNoUpdThdExists
Return Value:
VOID
Error Handling:
Called by:
NMSNMH_INC_VERS_COUNTER_M
Side Effects:
Comments:
None
--*/
{
LONG RetVal;
LONG RetVal2;
VERS_NO_T VersNo;
DBGENTER("WinsCnfWriteReg\n");
EnterCriticalSection(&NmsNmhNamRegCrtSec);
//
// if pTmp is not NULL, it means that either WINS did not find
// Next time's version number in the registry or that the max. version
// number in the db is greater than the high water mark we set at
// initialization. In the former case, we already have the correct
// value in NmsNmhToStartFromNextTime, so the if body is not executed.
//
if (!pTmp || LiLtr(NmsHighWaterMarkVersNo, NmsNmhMyMaxVersNo))
{
NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsVersNoToStartFromNextTime,
NmsHalfRangeSize);
NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsVersNoToStartFromNextTime,
NmsRangeSize);
}
VersNo = NmsVersNoToStartFromNextTime;
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
RetVal = RegSetValueEx(
sConfigRoot,
WINSCNF_INT_VERSNO_NEXTTIME_LW_NM,
0, //reserved -- must be 0
REG_DWORD,
(LPBYTE)&VersNo.LowPart,
sizeof(DWORD)
);
RetVal2 = RegSetValueEx(
sConfigRoot,
WINSCNF_INT_VERSNO_NEXTTIME_HW_NM,
0, //reserved -- must be 0
REG_DWORD,
(LPBYTE)&VersNo.HighPart,
sizeof(DWORD)
);
if ((RetVal != ERROR_SUCCESS) || (RetVal2 != ERROR_SUCCESS))
{
DBGPRINT2(ERR, "WinsCnfWriteReg - Could not set Next time's start version counter value in the registry. The new value is (%d %d)\n", VersNo.HighPart, VersNo.LowPart);
}
EnterCriticalSection(&NmsNmhNamRegCrtSec);
WinsCnfRegUpdThdExists = FALSE;
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
DBGLEAVE("WinsCnfWriteReg\n");
return(WINS_SUCCESS);
}
#if defined (DBGSVC) && !defined (WINS_INTERACTIVE)
VOID
WinsCnfReadWinsDbgFlagValue(
VOID
)
{
DWORD Sz;
DWORD ValTyp;
WinsDbg = 0; //set it to zero now. It was set to a value by Init() in
//nms.c
Sz = sizeof(WinsDbg);
(VOID)RegQueryValueEx(
sParametersKey,
WINSCNF_DBGFLAGS_NM,
NULL, //reserved; must be NULL
&ValTyp,
(LPBYTE)&WinsDbg,
&Sz
);
return;
}
#endif
VOID
ReadSpecGrpMasks(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to read in the special group masks specified
under the SpecialGrpMasks key
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
DWORD NoOfSubKeys;
HKEY SGMKey;
BOOL fKeyOpen = FALSE;
LONG RetVal;
DBGENTER("ReadSpecGrpMasks\n");
try {
/*
* Open the SPEC_GRP_MASKS key
*/
RetVal = RegOpenKeyEx(
sParametersKey, //predefined key value
_WINS_CFG_SPEC_GRP_MASKS_KEY,
0, //must be zero (reserved)
KEY_READ, //we desire read access to the keyo
&SGMKey //handle to key
);
if (RetVal == ERROR_SUCCESS)
{
fKeyOpen = TRUE;
//
// Get the count of data files listed under the DATAFILES
// key
//
GetKeyInfo(
SGMKey,
WINSCNF_E_SPEC_GRP_MASKS_KEY,
&NoOfSubKeys, //ignored
&pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks
);
if (pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks > 0)
{
DWORD Index;
LPBYTE pTmp;
TCHAR ValNmBuff[5];
DWORD ValNmBuffSz;
DWORD StrType;
LPBYTE pByte;
DWORD BuffSize;
CHAR Tmp[WINS_MAX_FILENAME_SZ];
#ifdef UNICODE
WCHAR Str[WINSCNF_SPEC_GRP_MASK_SZ];
#endif
//
// Allocate buffer big enough to hold data for
// the number of subkeys found under the PULL key
//
BuffSize = (WINSCNF_SPEC_GRP_MASK_SZ + 1) *
pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks;
WinsMscAlloc( BuffSize, &pWinsCnf->SpecGrpMasks.pSpecGrpMasks);
/*
* Enumerate the values
*/
for(
Index = 0, pTmp = pWinsCnf->SpecGrpMasks.pSpecGrpMasks;
Index < pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks;
// no third expression
)
{
ValNmBuffSz = sizeof(ValNmBuff)/sizeof(TCHAR); //init before
//every call
BuffSize = WINSCNF_SPEC_GRP_MASK_SZ;
RetVal = RegEnumValue(
SGMKey,
Index, //key
ValNmBuff,
&ValNmBuffSz,
(LPDWORD)NULL, //reserved
&StrType,
#ifdef UNICODE
(LPBYTE)Str,
#else
pTmp,
#endif
&BuffSize
);
if (RetVal != ERROR_SUCCESS)
{
continue;
}
//
// if StrType is not REG_SZ go to the next Value
//
if (StrType != REG_SZ)
{
continue;
}
if (BuffSize != WINSCNF_SPEC_GRP_MASK_SZ)
{
DBGPRINT1(ERR, "ReadSpecGrpMasks: Wrong spec. grp mask (%s)\n", pTmp);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_SPEC_GRP_MASK_M);
continue;
}
else
{
#ifdef UNICODE
WinsMscConvertUnicodeStringToAscii(
(LPBYTE)Str,
(LPBYTE)Tmp,
WINSCNF_SPEC_GRP_MASK_SZ
);
#endif
pByte = (LPBYTE)Tmp;
for (Index = 0; Index < WINSCNF_SPEC_GRP_MASK_SZ;
Index++, pByte++)
{
*pByte = (BYTE)CharUpperA((LPSTR)*pByte);
if (
((*pByte >= '0') && (*pByte <= '9'))
||
((*pByte >= 'A') && (*pByte <= 'F'))
)
{
continue;
}
else
{
break;
}
}
if (Index > WINSCNF_SPEC_GRP_MASK_SZ)
{
DBGPRINT1(ERR, "ReadSpecGrpMasks: Wrong spec. grp mask (%s)\n", pTmp);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_SPEC_GRP_MASK_M);
continue;
}
*(pTmp + WINSCNF_SPEC_GRP_MASK_SZ) = EOS;
}
Index++;
pTmp += WINSCNF_SPEC_GRP_MASK_SZ + 1;
}
//
// If not even one valid name was retrieved, get rid of the
// buffer
//
if (Index == 0)
{
//
// Get rid of the buffer
//
WinsMscDealloc((LPBYTE)pWinsCnf->SpecGrpMasks.pSpecGrpMasks);
}
pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks = Index;
}
} // end of if
} // end of try ..
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("ReadSpecGrpMasks");
WINSEVT_LOG_D_M(GetExceptionCode(), WINS_EVT_CANT_INIT);
}
if (fKeyOpen && RegCloseKey(SGMKey) != ERROR_SUCCESS)
{
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_CLOSE_KEY);
DBGPRINT0(ERR, "ReadSpecGrpMasks: Can not read the spec. grp. mask. key\n");
}
DBGLEAVE("ReadSpecGrpMasks\n");
return;
}
#if 0
int
__cdecl
CompUpdCnt(
CONST LPVOID pElem1,
CONST LPVOID pElem2
)
/*++
Routine Description:
This function is called by qsort crtl function to compare two
elements of the array that has to be sorted
Arguments:
pElem1 - ptr to first element
pElem1 - ptr to second element
Externals Used:
None
Return Value:
-1 if first element is < second element
= 0 if first element is == second element
1 if first element is > second element
Error Handling:
Called by:
qsort (which is called by WinsCnfReadPartnerInfo
Side Effects:
Comments:
Not used currently
--*/
{
CONST PRPL_CONFIG_REC_T pCnfRec1 = pElem1;
CONST PRPL_CONFIG_REC_T pCnfRec2 = pElem2;
if (pCnfRec1->UpdateCount < pCnfRec2->UpdateCount)
{
return(-1);
}
else
{
if (pCnfRec1->UpdateCount == pCnfRec2->UpdateCount)
{
return(0);
}
}
//
// The first record has a higher UpdateCount than the second one
//
return(1);
}
#endif
#ifdef WINSDBG
VOID
PrintRecs(
RPL_RR_TYPE_E RRType_e,
PWINSCNF_CNF_T pWinsCnf
)
{
return;
}
#endif