windows-nt/Source/XPSP1/NT/net/wins/server/rpl/rplpull.c
2020-09-26 16:20:57 +08:00

4612 lines
154 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
Rplpull.c
Abstract:
This module implements the pull functionality of the WINS replicator
Functions:
GetReplicasNew
GetVersNo
RplPullPullEntries
SubmitTimerReqs
SubmitTimer
SndPushNtf
HdlPushNtf
EstablishComm
RegGrpRpl
IsTimeoutToBeIgnored
InitRplProcess
Reconfig
RplPullInit
RplPullRegRepl
Portability:
This module is portable
Author:
Pradeep Bahl (PradeepB) Jan-1993
Revision History:
Modification date Person Description of modification
----------------- ------- ----------------------------
--*/
/*
* Includes
*/
#include <time.h>
#include <stdlib.h>
#include <search.h>
#include "wins.h"
#include <winsock2.h>
#include "comm.h"
#include "assoc.h"
#include "winsque.h"
#include "rpl.h"
#include "rplpull.h"
#include "rplpush.h"
#include "rplmsgf.h"
#include "nms.h"
#include "nmsnmh.h"
#include "nmsdb.h"
#include "winsmsc.h"
#include "winsevt.h"
#include "winscnf.h"
#include "winstmm.h"
#include "winsintf.h"
/*
* Local Macro Declarations
*/
//
// defines to use for retrying communication with a remote WINS on a
// communication failure exception (when trying to establish a connection).
//
// The retries are done before moving on in the list to the next WINS
// (if one is there). When MAX_RETRIES_TO_BE_DONE retries have been done,
// we do not retry again until the next replication cycle at which
// time the whole process is repeated).
//
// The number of replication cycles this process of retries is to be
// continued is a registry parameter
//
//
// NOTE:
// Since TCP/IP's retry strategy has been improved (more retries than before)
// and made a registry parameter, we now probably don't need to do the retries
//
#define MAX_RETRIES_TO_BE_DONE (0) //0 for testing only
//
// Time to wait before flushing for the Rpl Pull thread
//
#define FLUSH_TIME (2000) //2 secs
//
// Note: Don't make the retry time interval too large since communications
// with Remote WINS servers is established in sequence. 20 secs
// is not bad.
//
#define RETRY_TIME_INTVL (20000) //in millisecs
#define FIVE_MINUTES 300
/*
* Local Typedef Declarations
*/
/*
* Global Variable Definitions
*/
HANDLE RplPullCnfEvtHdl; //handle to event signaled by main
//thread when a configuration change
//has to be given to the Pull handler
//thread
BOOL fRplPullAddDiffInCurrRplCycle; //indicates whether the address
//of any entry in this WINS's db
//changed as a result of
//replication
#if 0
BOOL fRplPullTriggeredWins; //indicates that during the current
//replication cycle, one or more
//WINS's were triggered. This
//when TRUE, then if the above
//"AddDiff.." flag is TRUE, it means
//that the PULL thread should trigger
//all PULL Pnrs that have an INVALID
//metric in their UpdateCount field
//(of the RPL_CONFIG_T struct)
BOOL fRplPullTrigger; //Indication to the PULL thread to
//trigger Pull pnrs since one or more
//address changed. fRplPullTriggerWins
//has got be FALSE when this is true
#endif
BOOL fRplPullContinueSent = FALSE;
//
// This array is indexed by the owner id. of an RQ server that has entries in
// our database. Each owner's max. version number is stored in this array
//
PRPL_VERS_NOS_T pRplPullOwnerVersNo;
DWORD RplPullMaxNoOfWins = RPL_MAX_OWNERS_INITIALLY;
DWORD RplPullCnfMagicNo; //stores the id. of the current WinsCnf
//structure that the Pull thread
// is operating with
/*
* Local Variable Definitions
*/
/*
pPushPnrVersNoTbl -- Table whose some (or all) entries are
initialized at replication time.
*/
/*
pPushPnrVersNoTbl
This table stores the Max. version number pertaining to each WINS server
that owns entries in the local database of Push Partners
Note: The table is STATIC for now. We might change it to be a dynamic one
later.
The first dimension indicates the Push Pnr. The second dimension indicates
the owner WINS that has records in the Push Pnr's local db
*/
STATIC PRPL_VERS_NOS_T pPushPnrVersNoTbl;
//
// Var. that stores the handles to the timer requests that have been
// submitted
//
STATIC WINSTMM_TIMER_REQ_ACCT_T SetTimeReqs;
STATIC BOOL sfPulled = FALSE;//indicates whether the PULL thread pulled
//anything from a WINS. Set by PullEntries.
//Looked at by HdlPushNtf
/*
* Local Function Prototype Declarations
*/
STATIC
VOID
GetReplicasNew(
IN PRPL_CONFIG_REC_T pPullCnfRecs,
IN RPL_REC_TRAVERSAL_E RecTrv_e //indicates how we have to
//interpret the above list
);
VOID
ConductChkNew(
PPUSHPNR_DATA_T pPushPnrData,
VERS_NO_T vnMaxLocal,
VERS_NO_T vnMaxRemote);
STATIC
VOID
GetVersNo(
PPUSHPNR_DATA_T pPushPnrData //info about Push Pnr
);
STATIC
VOID
SubmitTimerReqs(
IN PRPL_CONFIG_REC_T pPullCnfRecs
);
STATIC
VOID
SubmitTimer(
LPVOID pWrkItm,
IN PRPL_CONFIG_REC_T pPullCnfRec,
BOOL fResubmit
);
STATIC
VOID
SndPushNtf(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
HdlPushNtf(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
EstablishComm(
IN PRPL_CONFIG_REC_T pPullCnfRecs,
IN BOOL fAllocPushPnrData,
IN PPUSHPNR_DATA_T *ppPushPnrData,
IN RPL_REC_TRAVERSAL_E RecTrv_e,
OUT LPDWORD pNoOfPushPnrs
);
STATIC
STATUS
RegGrpRepl(
LPBYTE pName,
DWORD NameLen,
DWORD Flag,
DWORD OwnerId,
VERS_NO_T VersNo,
DWORD NoOfAdds,
PCOMM_ADD_T pNodeAdd,
PCOMM_ADD_T pOwnerWinsAdd
);
STATIC
BOOL
IsTimeoutToBeIgnored(
PQUE_TMM_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
InitRplProcess(
PWINSCNF_CNF_T pWinsCnf
);
STATIC
VOID
Reconfig(
PWINSCNF_CNF_T pWinsCnf
);
VOID
AddressChangeNotification(
PWINSCNF_CNF_T pWinsCnf
);
STATIC
VOID
PullSpecifiedRange(
PCOMM_HDL_T pDlgHdl,
PWINSINTF_PULL_RANGE_INFO_T pPullRangeInfo,
BOOL fAdjMinVersNo,
DWORD RplType
);
STATIC
VOID
DeleteWins(
PCOMM_ADD_T pWinsAdd
);
BOOL
AcceptPersona(
PCOMM_ADD_T pWinsAdd
);
VOID
FilterPersona(
PPUSHPNR_DATA_T pPushData
);
//
// Function definitions
//
DWORD
RplPullInit (
LPVOID pWinsCnfArg
)
/*++
Routine Description:
This is the initialization (startup function) of the PULL thread.
It does the following:
Arguments:
pWinsCnfArg - Address of the WINS configuration block
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInit
Side Effects:
Comments:
None
--*/
{
PQUE_RPL_REQ_WRK_ITM_T pWrkItm;
HANDLE ThdEvtArr[3];
DWORD ArrInd;
DWORD RetVal;
BOOL fIsTimerWrkItm; //indicates whether
//it is a timer wrk
//item
PWINSCNF_CNF_T pWinsCnf = pWinsCnfArg;
PRPL_CONFIG_REC_T paPullCnfRecs = pWinsCnf->PullInfo.pPullCnfRecs;
PRPL_CONFIG_REC_T paCnfRec = paPullCnfRecs;
SYSTEMTIME LocalTime;
BOOL bRecoverable = FALSE;
while(TRUE)
{
try
{
if (!bRecoverable)
{
//
// Initialize self with the db engine
//
NmsDbThdInit(WINS_E_RPLPULL);
NmsDbOpenTables(WINS_E_RPLPULL);
DBGMYNAME("Replicator Pull Thread");
//
// Create the event handle to wait for configuration changes. This
// event is signaled by the main thread when it needs to reinit
// the Pull handler component of the Replicator
//
WinsMscCreateEvt(
RPL_PULL_CNF_EVT_NM,
FALSE, //auto-reset
&RplPullCnfEvtHdl
);
ThdEvtArr[0] = NmsTermEvt;
ThdEvtArr[1] = QueRplPullQueHd.EvtHdl;
ThdEvtArr[2] = RplPullCnfEvtHdl;
//
// If logging is turned on, specify the wait time for flushing
// NOTE: We override the wait time we specified for all sessions
// for this thread because that wait time is too less (100 msecs) and
// will cause unnecessary overhead.
//
if (WinsCnf.fLoggingOn)
{
//
// Set flush time to 2 secs.
//
NmsDbSetFlushTime(FLUSH_TIME);
}
/*
Loop forever doing the following:
Pull replicas from the Pull Partners specified in the
work item.
Block on the event until signalled (it will get signalled
if one of the following happens:
1)the configuration changes
2)the timer for another replication expires
3)WINS is terminating
do the needful
*/
//
// Wait until signaled by the TCP thd. Will be signaled after
// the TCP listener thread has inserted an entry for the WINS
// in the NmsDbOwnAddTbl
//
WinsMscWaitInfinite( RplSyncWTcpThdEvtHdl );
//
// Do startup replication only if there is atleast one PUSH pnr
//
if (paPullCnfRecs != NULL)
{
try {
InitRplProcess(pWinsCnf);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("RplPullInit");
DBGPRINT0(EXC, "RplPullInit: Exception during init time replication\n");
}
}
NmsDbCloseTables();
bRecoverable = TRUE;
} // end if (!bRecoverable)
while(TRUE)
{
/*
* Block until signalled
*/
WinsMscWaitUntilSignaled(
ThdEvtArr,
3,
&ArrInd,
FALSE
);
if (ArrInd == 0)
{
//WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_ORDERLY_SHUTDOWN);
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
}
/*
* loop forever until all work items have been handled
*/
while(TRUE)
{
/*
* dequeue the request from the queue
*/
RetVal = QueGetWrkItm(
QUE_E_RPLPULL,
(LPVOID)&pWrkItm
);
if (RetVal == WINS_NO_REQ)
{
break;
}
WinsMscChkTermEvt(
#ifdef WINSDBG
WINS_E_RPLPULL,
#endif
FALSE
);
fIsTimerWrkItm = FALSE;
NmsDbOpenTables(WINS_E_RPLPULL);
DBGPRINT1(RPLPULL, "RplPullInit: Dequeued a work item. Cmd Type is (%d)\n", pWrkItm->CmdTyp_e);
switch(pWrkItm->CmdTyp_e)
{
case(QUE_E_CMD_TIMER_EXPIRED):
//
// We may want to ignore this timeout if it
// pertains to a previous configuration
//
if (
!IsTimeoutToBeIgnored(
(PQUE_TMM_REQ_WRK_ITM_T)pWrkItm
)
)
{
WinsIntfSetTime(
&LocalTime,
WINSINTF_E_PLANNED_PULL);
#ifdef WINSDBG
DBGPRINT5(REPL, "STARTING A REPLICATION CYCLE on %d/%d at %d.%d.%d (hr.mts.sec)\n",
LocalTime.wMonth,
LocalTime.wDay,
LocalTime.wHour,
LocalTime.wMinute,
LocalTime.wSecond);
DBGPRINT5(RPLPULL, "STARTING A REPLICATION CYCLE on %d/%d at %d.%d.%d (hr.mts.sec)\n",
LocalTime.wMonth,
LocalTime.wDay,
LocalTime.wHour,
LocalTime.wMinute,
LocalTime.wSecond);
#endif
GetReplicasNew(
((PQUE_TMM_REQ_WRK_ITM_T)pWrkItm)->
pClientCtx,
RPL_E_VIA_LINK //use the pNext field to
//get to the next record
);
DBGPRINT0(RPLPULL, "REPLICATION CYCLE END\n");
/*Resubmit the timer request*/
SubmitTimer(
pWrkItm,
((PQUE_TMM_REQ_WRK_ITM_T)pWrkItm)
->pClientCtx,
TRUE //it is a resubmission
);
}
//
// Set the flag so that we do not free
// the work item. It was resubmitted
//
fIsTimerWrkItm = TRUE;
break;
//
// Pull in replicas
//
case(QUE_E_CMD_REPLICATE):
//
// Make sure that we are not using old info
//
if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
((PRPL_CONFIG_REC_T)(pWrkItm->pClientCtx))->fTemp)
{
WinsIntfSetTime(
&LocalTime,
WINSINTF_E_ADMIN_TRIG_PULL);
GetReplicasNew( pWrkItm->pClientCtx,
RPL_E_NO_TRAVERSAL );
if (
((PRPL_CONFIG_REC_T)
(pWrkItm->pClientCtx))->fTemp
)
{
WinsMscDealloc(pWrkItm->pClientCtx);
}
}
else
{
DBGPRINT0(ERR, "RplPullInit: Can not honor this request since the configuration under the PARTNERS key may have changed\n");
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CNF_CHANGE);
}
break;
//
// Pull range of records
//
case(QUE_E_CMD_PULL_RANGE):
//
// Make sure that we are not using old info
//
if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
((PRPL_CONFIG_REC_T)((PWINSINTF_PULL_RANGE_INFO_T)(pWrkItm->pClientCtx))->pPnr)->fTemp)
{
//
// Pull the specified range. If the Pnr
// record is temp, this function will
// deallocate it.
//
PullSpecifiedRange(NULL, pWrkItm->pClientCtx, FALSE,
((PRPL_CONFIG_REC_T)(((PWINSINTF_PULL_RANGE_INFO_T)(pWrkItm->pClientCtx))->pPnr))->RplType);
//
// Deallocate the client ctx
//
WinsMscDealloc(pWrkItm->pClientCtx);
}
else
{
DBGPRINT0(ERR, "RplPullInit: Can not honor this request since the configuration under the PARTNERS key may have changed\n");
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CNF_CHANGE);
}
break;
//
//reconfigure
//
case(QUE_E_CMD_CONFIG):
Reconfig(pWrkItm->pClientCtx);
break;
//
// Delete WINS from the Owner Add table (delete records
// also
//
case(QUE_E_CMD_DELETE_WINS):
DeleteWins(pWrkItm->pClientCtx);
break;
//
// ip addr of this machine changed, modify the own - addr table
case(QUE_E_CMD_ADDR_CHANGE):
AddressChangeNotification(pWrkItm->pClientCtx);
break;
//
//Push notification. Local message from an NBT thread,
//from an RPC thread (Push Trigger) or from this thread
//itself
//
case(QUE_E_CMD_SND_PUSH_NTF_PROP):
case(QUE_E_CMD_SND_PUSH_NTF):
//
// Make sure that we are not using old info
//
if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
((PRPL_CONFIG_REC_T)(pWrkItm->pClientCtx))->fTemp)
{
SndPushNtf(pWrkItm);
}
break;
//
//Push notification from a remote WINS. Forwarded to Pull
//thread by the Push thread
//
case(QUE_E_CMD_HDL_PUSH_NTF):
HdlPushNtf(pWrkItm);
break;
default:
DBGPRINT1(ERR,
"RplPullInit: Invalid command code = (%d)\n",
pWrkItm->CmdTyp_e);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
break;
} // end of switch
NmsDbCloseTables();
//
// deallocate the work item only if it is not a timer work item
// We don't deallocate a timer work item here because of two
// reasons:
//
// 1) it is reused
// 2) it is allocated from the timer work item heap
//
if (!fIsTimerWrkItm)
{
/*
* deallocate the work item
*/
QueDeallocWrkItm( RplWrkItmHeapHdl, pWrkItm );
}
} //while(TRUE) for getting all work items
} //while (TRUE)
} // end of try
except(EXCEPTION_EXECUTE_HANDLER)
{
if (bRecoverable)
{
DBGPRINTEXC("RplPullInit");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_EXC);
}
else
{
DBGPRINTEXC("RplPullInit");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_ABNORMAL_SHUTDOWN);
//
// If NmsDbThdInit comes back with an exception, it is possible
// that the session has not yet been started. Passing
// WINS_DB_SESSION_EXISTS however is ok
//
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
}
} // end of except {.. }
} // end of while(TRUE)
//
// We never reach here
//
ASSERT(0);
return(WINS_FAILURE);
}
//////////////////////////////////////////////////////////////////////////////////
//------------------- GetReplicasNew() -------------------------------------------
// This call replaces the original GetReplicas() function due to several issues
// hidden in that one.
// ft: 06/06/2000
//
// Parameters:
// 1) pPullCnfRecs: gives the info about the partners where the records are to be pulled
// 2) RecvTrv_e: tells which of the partners from the first parameter should be involved
// in the replication. This parameter can be either RPL_E_VIA_LINK, RPL_E_NO_TRAVERSAL
// or RPL_E_IN_SEQ. It is used only at the end of the path:
// EstablishComm()->WinsCnfGetNextRplCnfRec()
//
VOID
GetReplicasNew (
IN PRPL_CONFIG_REC_T pPullCnfRecs, // info about the (pull) repl partners to use
IN RPL_REC_TRAVERSAL_E RecTrv_e // repl partner retrieval method
)
{
// The type & variable naming here is confusing. We are not dealing with push
// partners, but with pull partners, meaning "partners from which this server
// is currently pulling records". This is how WINSSNAP & WINSMON are both naming
// these kind of partners. I preserve though the original type naming (and hence
// the original variable naming) just to limit the size of the change.
PPUSHPNR_DATA_T pPushPnrData; // info on the connections to the partners
DWORD nPushPnrData; // number of elements in pPushPnrData
DWORD i, j; // general use counters
DBGENTER("GetReplicasNew\n");
// Establish communications with the Pull Partners
// For each of the partners in the list, the call below attempts to open a connection
// to the server (if needed). All the nPushPnrData partners to which the connection
// is established successfully are specified in the array (PPUSHPNR_DATA_T)pPushPnrData.
EstablishComm(
pPullCnfRecs, // IN - info about the replication partners
TRUE, // IN - pPushPnrData should be allocated
&pPushPnrData, // OUT - info on the connections to the partners
RecTrv_e, // IN - which of the partners should we connect to
&nPushPnrData); // OUT - number of elements in pPushPnrData
// NOTE: regardless the number of partners, pPushPnrData gets allocated so it will
// be unconditionally deallocated later.
//
// --Checkpoint-------------
// At this point, pPushPnrData[i].PushPnrId == i+1.
// The link between pPushPnrData[i] and the corresponding RPL_CONFIG_REC_T is done
// through (RPL_CONFIG_REC_T)pPushPnrData[i].pPullCnfRec
// -------------------------
//
// Contact each of the partners in pPushPnrData and get its OwnerAddr<->VersNo maps.
// The map of each partner is stored in (PRPL_ADD_VERS_NO)pPushPnrData[i].pAddVers
// The size of the map is stored in (DWORD)pPushPnrData[i].NoOfMaps
for (i = 0; i < nPushPnrData; ) // no 3rd part for this "for"
{
PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]); // get pointer to the current partner
try
{
GetVersNo(pPnrData);
i++;
}
except(EXCEPTION_EXECUTE_HANDLER)
{
// an exception was raised inside GetVersNo()
DWORD ExcCode = GetExceptionCode();
// dump the error
DBGPRINT2(
EXC, "GetReplicasNew->GetVersNo(%x); hit exception = (%x).\n",
pPnrData->pPullCnfRec->WinsAdd.Add.IPAdd,
ExcCode);
// log the error
WINSEVT_LOG_M(
ExcCode,
(ExcCode == WINS_EXC_COMM_FAIL) ? WINS_EVT_CONN_ABORTED : WINS_EVT_SFT_ERR);
// update the replication counters for that partner
(VOID)InterlockedIncrement(&pPnrData->pPullCnfRec->NoOfCommFails);
(VOID)InterlockedDecrement(&pPnrData->pPullCnfRec->NoOfRpls);
// Delete the dialog
ECommEndDlg(&pPnrData->DlgHdl);
// If there is a persistent dialog, it has to be marked as
// "no longer active"
if (pPnrData->fPrsConn)
ECOMM_INIT_DLG_HDL_M(&(pPnrData->pPullCnfRec->PrsDlgHdl));
// one of the partners could not be contacted, so
// eliminate it from the pPnrData array
nPushPnrData--;
// adjust the array such that the active partners are kept compact
// the PushPnrId is also changed to keep true the assertion
// pPushPnrData[i].PushPnrId == i+1;
if (i != nPushPnrData)
{
DWORD origPushPnrId = pPushPnrData[i].PushPnrId;
// !!! whole PUSHPNR_DATA_T structure is copied here !!!
pPushPnrData[i] = pPushPnrData[nPushPnrData];
pPushPnrData[i].PushPnrId = origPushPnrId;
}
// since the counter "i" is not incremented, the partner that
// has just been moved will be the one considered next
continue;
} // end of exception handler
} // end of for loop for looping over Push Pnrs
// --Checkpoint--------------
// At this point, pPushPnrData contains only the partners for which a connection
// could be established, nPushPnrData is updated to count only these partners
// and the pPushPnrData[i].PushPnrId == i+1 still holds.
// (PRPL_ADD_VERS_NO)pPushPnrData[i].pAddVers gives the map OwnerAddr<->VersNo as
// known by that replication partner. (DWORD)pPushPnrData[i].NoOfMaps gives the
// number of entries in the map.
// --------------------------
DBGPRINT1(RPLPULL, "GetReplicasNew: Active PushPnrs = (%d)\n", nPushPnrData);
// do stuff only if there is at least someone to talk to
if (nPushPnrData > 0)
{
// array giving info on what owner should be pulled from what repl partner
// the array starts with the image of the local OwnerId<->VersNo mapping and
// grows dynamically for as many new Owners are retrieved in the mappings
// of the other replication partners.
PPUSHPNR_TO_PULL_FROM_T pPushPnrToPullFrom;
DWORD nPushPnrToPullFrom; // size of the array
VERS_NO_T vnLocalMax; // maximum local version number
// depending on the server's state, get the maximum local version number
//
// If WINS is "init time paused", RplPullOwnerversNo will
// have the max. version no. of locally owned records. We
// can not use NmsNmhMyMaxVersNo since it may have been
// adjusted to a higher value
//
if (fWinsCnfInitStatePaused)
{
vnLocalMax = pRplPullOwnerVersNo[0].StartVersNo;
}
else
{
EnterCriticalSection(&NmsNmhNamRegCrtSec);
NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo, vnLocalMax) ;
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
}
// Initialize (PPUSHPNR_TO_PULL_FROM_T)pPushPnrToPullFrom. This is copying the local
// image of the OwnerId<->VersNo mapping. Any entry in this table having pPushPnrData
// set to NULL means the local server has the highest VersNo for that particular Owner
nPushPnrToPullFrom = NmsDbNoOfOwners;
WinsMscAlloc(
nPushPnrToPullFrom * sizeof(RPL_VERS_NOS_T),
(LPVOID *)&pPushPnrToPullFrom);
for (i = 0; i < NmsDbNoOfOwners; i++)
{
// avoid copying info for old owners that were deleted already from the
// internal tables (pNmsDbOwnAddTbl & pPushPnrToPullFrom)
// for those, the entry slot will look like (NULL, 0:0) so they basically
// won't be taken into account for replication
if (pNmsDbOwnAddTbl[i].WinsState_e != NMSDB_E_WINS_DELETED)
{
pPushPnrToPullFrom[i].pPushPnrData = NULL;
pPushPnrToPullFrom[i].VersNo = pRplPullOwnerVersNo[i].VersNo;
}
}
// reset the maximum local number to what we got before.
pPushPnrToPullFrom[0].VersNo = vnLocalMax;
// --Checkpoint--------------
// At this point, pPushPnrToPullFrom is copying the OwnerId<->VersNo mapping
// from the local server. Entry at index 0 contains the highest local VersNo,
// all the others contain each owner's highest VersNo as it is known locally.
// Each entry has pPushPnrData set to NULL as they don't refer yet to any
// repl partner info. Later, pPushPnrData will point to the structure corresponding
// to the repl partner with the highest VersNo for the corresponding owner.
// --------------------------
// We attempt now to do a merge of all the maps we got from each of the partners.
// The merge means identifying which partner has the highest VersNo for
// each of the OwnerAddr. In the same time, some of the OwnerAddr we just got
// might not be already present in the local OwnerId<->OwnerAddr (pNmsDbOwnAddTbl)
// and OwnerId<->VersNo (pRplPullOwnerVersNo)tables. So we need to get a new
// OwnerId for these ones and adjust appropriately the internal tables & the
// OwnerId<->OwnerAddr db table. This is done through RplFindOwnerId().
//
// for each active replication partner ...
for (i = 0; i < nPushPnrData; i++)
{
// get pointer to the current partner's data
PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]);
// for each of the replication partner's map entry ...
for (j = 0; j < pPnrData->NoOfMaps; j++)
{
// get the pointer to the current (OwnerAddr<->VersNo) map entry
PRPL_ADD_VERS_NO_T pPnrMapEntry = &(pPnrData->pAddVers[j]);
BOOL fAllocNew; // true if this is a brand new owner
DWORD OwnerId;
// filter out owners that are not supposed to be accepted
// (either a persona non-grata or not a persona grata)
if (!AcceptPersona(&(pPnrMapEntry->OwnerWinsAdd)))
continue;
// Locate or allocate an OwnerId for this owner
// No need to enter the critical section RplOwnAddTblCrtSec since
// only the Pull thread changes the NmsDbNoOfOwners value (apart
// from the main thread at initialization). RplFindOwnerId changes
// this value only if it is asked to allocate a new entry)
// Though NmsDbGetDataRecs (called by Rpc threads, Push thread, and
// scavenger thread) calls RplFindOwnerId, that call is not asking
// for new OwnerId allocation.
fAllocNew = TRUE;
RplFindOwnerId(
&(pPnrMapEntry->OwnerWinsAdd),
&fAllocNew,
&OwnerId,
WINSCNF_E_INITP_IF_NON_EXISTENT,
WINSCNF_LOW_PREC);
if (nPushPnrToPullFrom < NmsDbNoOfOwners)
{
// if this is an owner we didn't hear of yet, RplFindOwnerId is enlarging
// dynamically the internal tables (pNmsDbOwnAddTbl & pRplPullOwnerVersNo)
// so we need to do the same
nPushPnrToPullFrom = NmsDbNoOfOwners;
// note: the memory that is added to the array is zero-ed by the call
WINSMSC_REALLOC_M(
nPushPnrToPullFrom * sizeof(RPL_VERS_NOS_T),
(LPVOID *)&pPushPnrToPullFrom);
}
// it is guaranteed now, OwnerId is within the range of the pPushPnrToPullFrom.
if (fAllocNew)
{
// if a new OwnerId was generated (either new slot into the tables or
// an old slot has been reused) this means the partner is coming up with
// a new owner: obviously he's the one having the most recent info on
// that partner (at least for now)
pPushPnrToPullFrom[OwnerId].pPushPnrData = pPnrData;
pPushPnrToPullFrom[OwnerId].VersNo = pPnrMapEntry->VersNo;
}
else
{
// the owner already exists in the list, so we need to check whether the
// info on this owner is not more recent on a different partner (or on this
// local server)
if ( LiGtr(pPnrMapEntry->VersNo, pPushPnrToPullFrom[OwnerId].VersNo) )
{
// yes it is, so we need to update the entry in the pPushPndToPullFrom
// table such that it points to this partner and shows the new greater
// version number.
pPushPnrToPullFrom[OwnerId].VersNo = pPnrMapEntry->VersNo;
pPushPnrToPullFrom[OwnerId].pPushPnrData = pPnrData;
}
// else the info is not the most recent one, so just ignore it.
} // end checking the OwnerId
} // end looping through partner's map entries
} // end looping through the list of partners
// --Checkpoint--------------
// At this point pPushPnrToPullFrom contains the union of all the OwnerId<->VersNo mappings
// from all the partners. Each entry contains the highest VersNo known across all partners
// for the corresponding owner, and points to the partner that came with this info (or NULL
// if the highest VersNo was already known locally).
// --------------------------
// start pulling each owner from the partner able to provide the most up-to-date information
// (having the highest version number).
// start doing so from the entry '1' in the pPushPnrToPullFrom since entry '0' corresponds
// to the local owner. That one will be handled later
for (i = 1; i < NmsDbNoOfOwners; i++)
{
PPUSHPNR_TO_PULL_FROM_T pPushPartner = &(pPushPnrToPullFrom[i]);
VERS_NO_T vnToPullFrom;
// if pPushPnrData member is null this means the local server has the highest version
// number for this owner. So nothing to pull from anyone here
// the same, if fDlgStarted is NULL this means that partner hit an exception previously
// and its dialog has been shut down. Don't attempt to get back to that partner in this
// case.
if (pPushPartner->pPushPnrData == NULL ||
!pPushPartner->pPushPnrData->fDlgStarted)
continue;
// set the local variable vnToPullFrom to the first version number that is not known
// locally (one more than the highest known)
NMSNMH_INC_VERS_NO_M(pRplPullOwnerVersNo[i].VersNo, vnToPullFrom);
try
{
// eventually we got here: start pulling
RplPullPullEntries(
&(pPushPartner->pPushPnrData->DlgHdl), // active dialog to use
i, // owner id
pPushPartner->VersNo, // max VersNo
vnToPullFrom, // min VersNo
WINS_E_RPLPULL, // the client is the replicator
NULL, // pointer to rsp buffer (used only by scavenger)
TRUE, // update counters
pPushPartner->pPushPnrData->RplType); // replication type for this partner
}
except (EXCEPTION_EXECUTE_HANDLER)
{
DWORD ExcCode = GetExceptionCode();
// dump the error
DBGPRINT2(
EXC,
"GetReplicasNew->RplPullPullEntries(%x): hit exception (%x)\n",
pPushPartner->pPushPnrData->pPullCnfRec->WinsAdd.Add.IPAdd,
ExcCode);
// log the error
WINSEVT_LOG_M(
WINS_FAILURE,
ExcCode == WINS_EXC_COMM_FAIL ? WINS_EVT_CONN_ABORTED : WINS_EVT_SFT_ERR);
// ----bug #120788----
// If an exception happens at this point, the persistent connection is left open and it might just
// happen that the remote partner is still pushing data. This could fill up the TCP window
// and could have the sender blocked indefinitely in RplPushInit->HandleSndEntriesReq.
// Because of this the remote sender will be unable to push out data, and given that the
// same thread is the one that is sending out the VersNo table (see the beginning of this
// function) subsequent replications will not be possible over the same connection.
// FIX: in case anything goes wrong such that we get to this exception handler
// just close the connection even if it is persistent. This causes any remote WINS to break
// out from HandleSndEntriesReq and avoid getting stuck.
ECommEndDlg(&(pPushPartner->pPushPnrData->DlgHdl));
// If there is a persistent dialog, it has to be marked as "no longer active"
if (pPushPartner->pPushPnrData->fPrsConn)
ECOMM_INIT_DLG_HDL_M(&(pPushPartner->pPushPnrData->pPullCnfRec->PrsDlgHdl));
// Closing the dialog is not enough. Some other owners might be pulled out from the same
// partner. We shouldn't allow that, so just ban that partner for this replication cycle.
pPushPartner->pPushPnrData->fDlgStarted = FALSE;
// since we dropped down this connection and we won't look at it further lets delete its
// mapping also
if (pPushPartner->pPushPnrData->NoOfMaps)
WinsMscDealloc(pPushPartner->pPushPnrData->pAddVers);
} // end except handler
} // end looping through owners list
// --Checkpoint--------------
// Nothing has changed in the pPushPnrToPullFrom array except probably some dialogs that were shut down
// because of exceptions in RplPullPullEntries. Owners handled by these partners were simply skipped.
// At this point all replication is done, the most recent information about each owner apart has been
// brought down from the partners that were holding it.
// --------------------------
// one more thing is left to be done: Check whether there is not a remote WINS partner
// pretending to have more up-to-date information about the local WINS.
if (pPushPnrToPullFrom[0].pPushPnrData != NULL &&
pPushPnrToPullFrom[0].pPushPnrData->fDlgStarted)
{
ConductChkNew(
pPushPnrToPullFrom[0].pPushPnrData,
vnLocalMax,
pPushPnrToPullFrom[0].VersNo);
}
// release the pPushPnrToPullFrom buffer
WinsMscDealloc(pPushPnrToPullFrom);
} // end "if there are active partners" case
// cleanup starts here..
for (i = 0; i < nPushPnrData; i++)
{
PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]);
if (pPnrData->fDlgStarted == TRUE)
{
if (!pPnrData->fPrsConn)
ECommEndDlg(&(pPnrData->DlgHdl));
//Deallocate the memory pointed to by PushPnrData structure
if (pPnrData->NoOfMaps)
WinsMscDealloc(pPnrData->pAddVers);
}
}
// deallocate the memory containing push pnr info.
WinsMscDealloc(pPushPnrData);
// If Wins is in the init time paused state, unpause it.
//
if (fWinsCnfInitStatePaused)
{
//inform sc to send a continue to WINS.
EnterCriticalSection(&RplVersNoStoreCrtSec);
fRplPullContinueSent = TRUE;
WinsMscSendControlToSc(SERVICE_CONTROL_CONTINUE);
LeaveCriticalSection(&RplVersNoStoreCrtSec);
}
DBGLEAVE("GetReplicasNew\n");
}
//------------------- END OF GetReplicasNew() ------------------------------------
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//------------------- ConductChkNew() --------------------------------------------
// This call replaces the original ConductChk() function due to major redesign in
// replicator's code.
// ft: 06/06/2000
//
// Parameters:
// 1) pPushPnrData: points to the replication partner that seems to have more
// up-to-date information on self
// 2) vnMaxLocal: maximum local version number as detected before the replication
// started
// 3) vnMaxRemote: maximum version number of the local server as known by the
// remote partner
//
VOID
ConductChkNew(
PPUSHPNR_DATA_T pPushPnrData,
VERS_NO_T vnMaxLocal,
VERS_NO_T vnMaxRemote)
{
RPL_CONFIG_REC_T Pnr;
WINSINTF_PULL_RANGE_INFO_T PullRangeInfo;
BOOL fVersNoAdj = FALSE;
DBGENTER("ConductChkNew\n");
Pnr.WinsAdd = pPushPnrData->WinsAdd;
Pnr.MagicNo = 0;
Pnr.RetryCount = 0;
Pnr.LastCommFailTime = 0;
Pnr.LastCommTime = 0;
Pnr.PushNtfTries = 0;
Pnr.fTemp = FALSE; // We want the buffer to be deallocated by thread
PullRangeInfo.OwnAdd.Type = WINSINTF_TCP_IP;
PullRangeInfo.OwnAdd.Len = sizeof(COMM_IP_ADD_T);
PullRangeInfo.OwnAdd.IPAdd = NmsLocalAdd.Add.IPAdd;
PullRangeInfo.MaxVersNo = vnMaxRemote;
PullRangeInfo.MinVersNo = vnMaxLocal;
PullRangeInfo.pPnr = &Pnr;
NMSNMH_INC_VERS_NO_M(PullRangeInfo.MinVersNo, PullRangeInfo.MinVersNo);
DBGPRINT5(
RPLPULL, "ConductCheckNew(%x): Checking range [%x:%x - %x:%x]\n",
Pnr.WinsAdd.Add.IPAdd,
vnMaxLocal.HighPart, vnMaxLocal.LowPart,
vnMaxRemote.HighPart, vnMaxRemote.LowPart);
// We are pulling our own records. We want to store all.
PullSpecifiedRange(
&(pPushPnrData->DlgHdl),
&PullRangeInfo,
TRUE, //adjust min to NmsNmhMyMaxVersNo.
WINSCNF_RPL_DEFAULT_TYPE);
// If the version number is greater than the version counter value (this is
// different from the first entry of RplPullOwnerVersNo table since we look
// in the registry to determine its value).
EnterCriticalSection(&NmsNmhNamRegCrtSec);
if (LiGtr(vnMaxRemote, NmsNmhMyMaxVersNo))
{
NmsNmhMyMaxVersNo.QuadPart = vnMaxRemote.QuadPart + 1;
fVersNoAdj = TRUE;
}
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
if (fVersNoAdj)
{
#ifdef WINSDBG
vnMaxRemote.QuadPart += 1;
DBGPRINT2(
RPLPULL, "ConductCheck: Local VersNo adjusted to %x:%x\n",
vnMaxRemote.HighPart, vnMaxRemote.LowPart);
#endif
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_ADJ_VERS_NO);
}
DBGLEAVE("ConductCheckNew\n");
}
//------------------- END OF ConductChkNew() ------------------------------------
//////////////////////////////////////////////////////////////////////////////////
VOID
GetVersNo(
PPUSHPNR_DATA_T pPushPnrData //info about Push Pnr
)
/*++
Routine Description:
This function does the following:
formats a "get address to Version Number mapping" request,
sends it and waits for response
Unformats the response
Arguments:
pPushPnrData - Information about the Push Pnr which needs to
be contacted in order to get the version number
info.
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
GetReplicasNew
Side Effects:
Comments:
Some optimization can be affected by the caller of this function
--*/
{
BYTE Msg[RPLMSGF_ADDVERSMAP_REQ_SIZE]; //Buffer that will contain
//the request to send
DWORD MsgLen; //Msg Length
LPBYTE pRspMsg; //ptr to Rsp message
DWORD RspMsgLen = 0; //Rsp msg length
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DBGENTER("GetVersNo\n");
/*
* format the request to ask for version numbers
*/
RplMsgfFrmAddVersMapReq( Msg + COMM_N_TCP_HDR_SZ, &MsgLen );
/*
* Send "send me IP address - Version Number" messages to the
* Push Pnr
*
* NOTE: If there is a communication failure or if the other WINS
* brings down the link, this function will raise a COMM_FAIL
* exception (caught in the caller of GetVersNo)
*/
ECommSndCmd(
&pPushPnrData->DlgHdl,
Msg + COMM_N_TCP_HDR_SZ,
MsgLen,
&pRspMsg,
&RspMsgLen
);
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(&pPushPnrData->DlgHdl, fIsPnrBeta1Wins);
#endif
/*
* Unformat the Rsp Message
*/
RplMsgfUfmAddVersMapRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
pRspMsg + 4, //past the opcodes
&(pPushPnrData->NoOfMaps),
NULL,
&pPushPnrData->pAddVers
);
#ifdef WINSDBG
{
DWORD i;
struct in_addr InAddr;
PRPL_ADD_VERS_NO_T pAddVers; //maps
DBGPRINT1(RPLPULL, " %d Add-Vers Mappings retrieved.\n",
pPushPnrData->NoOfMaps);
for (i=0, pAddVers = pPushPnrData->pAddVers; i < pPushPnrData->NoOfMaps; i++, pAddVers++)
{
InAddr.s_addr = htonl(
pAddVers->OwnerWinsAdd.Add.IPAdd
);
DBGPRINT3(RPLPULL,"Add (%s) - MaxVersNo (%lu %lu)\n",
inet_ntoa(InAddr),
pAddVers->VersNo.HighPart,
pAddVers->VersNo.LowPart
);
}
}
#endif
ECommFreeBuff(pRspMsg - COMM_HEADER_SIZE); //decrement to begining
//of buff
DBGLEAVE("GetVersNo\n");
return;
}
VOID
RplPullPullEntries(
PCOMM_HDL_T pDlgHdl,
DWORD dwOwnerId,
VERS_NO_T MaxVersNo,
VERS_NO_T MinVersNo,
WINS_CLIENT_E Client_e,
LPBYTE *ppRspBuff,
BOOL fUpdCntrs,
DWORD RplType
)
/*++
Routine Description:
This function is called to pull replicas for a particular owner from
a Push Pnr.
Arguments:
pDlgHdl - Dialogue with the Push Pnr
dwOwnerId - Owner Id. of WINS whose records are to be pulled.
MaxVersNo - Max. Vers. No. in the set of replicas to pull
MinVersNo - Min. Vers. No. in the set of replicas to pull
Client_e - indicates who the client is
ppRspBuff - address of pointer to response buffer if client is
WINS_E_NMSSCV -- Scavenger thread executing VerifyIfClutter
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
GetReplicasNew
Side Effects:
Comments:
None
--*/
{
BYTE Buff[RPLMSGF_SNDENTRIES_REQ_SIZE];
DWORD MsgLen;
LPBYTE pRspBuff;
DWORD RspMsgLen = 0;
DWORD NoOfRecs;
BYTE Name[NMSDB_MAX_NAM_LEN];
DWORD NameLen;
BOOL fGrp;
DWORD NoOfAdds;
COMM_ADD_T NodeAdd[NMSDB_MAX_MEMS_IN_GRP * 2]; //twice the # of
//members because
//for each member
//we have an owner
DWORD Flag;
VERS_NO_T VersNo, TmpVersNo;
DWORD i;
LPBYTE pTmp;
PCOMM_ADD_T pWinsAdd;
PNMSDB_WINS_STATE_E pWinsState_e;
PVERS_NO_T pStartVersNo;
STATUS RetStat = WINS_SUCCESS;
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DBGENTER("RplPullPullEntries\n");
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(pDlgHdl, fIsPnrBeta1Wins);
#endif
WinsMscChkTermEvt(
#ifdef WINSDBG
Client_e,
#endif
FALSE
);
sfPulled = FALSE; //we haven't pulled anything yet.
RPL_FIND_ADD_BY_OWNER_ID_M(
dwOwnerId,
pWinsAdd,
pWinsState_e,
pStartVersNo
);
while(TRUE)
{
#ifdef WINSDBG
{
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
struct in_addr InAdd;
InAdd.s_addr = htonl(pWinsAdd->Add.IPAdd);
DBGPRINT2(RPLPULL, "Going to Pull Entries owned by WINS with Owner Id = (%d) and address = (%s)\n", dwOwnerId, inet_ntoa(InAdd));
InAdd.s_addr = htonl(pAssocCtx->RemoteAdd.sin_addr.s_addr);
DBGPRINT5(RPLPULL, "RplPullPullEntries: Range of records is = (%lu %lu) to (%lu %lu) and is being pulled from WINS with address - (%s)\n",
MinVersNo.HighPart,
MinVersNo.LowPart,
MaxVersNo.HighPart,
MaxVersNo.LowPart,
inet_ntoa(InAdd)
);
}
#endif
/*
* Format the "send me data entries" message
*/
RplMsgfFrmSndEntriesReq(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
Buff + COMM_N_TCP_HDR_SZ,
pWinsAdd,
MaxVersNo,
MinVersNo,
RplType,
&MsgLen
);
FUTURES("In case a huge range is being pulled, change the sTimeToWait")
FUTURES("in comm.c to a higher timeout value so that select does not")
FUTURES("time out")
/*
* send the cmd to the Push Pnr and read in the response
*/
ECommSndCmd(
pDlgHdl,
Buff + COMM_N_TCP_HDR_SZ,
MsgLen,
&pRspBuff,
&RspMsgLen
);
DBGPRINT0(RPLPULL, "RplPull: Received Response from Push pnr\n");
if (Client_e == WINS_E_NMSSCV)
{
*ppRspBuff = pRspBuff;
/*--ft: 01/07/200 moved to ChkConfNUpd--
if (WinsCnf.LogDetailedEvts > 0)
{
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
DWORD IpPartner = pAssocCtx->RemoteAdd.sin_addr.s_addr;
WinsEvtLogDetEvt(TRUE, WINS_EVT_REC_PULLED, TEXT("Verification"), __LINE__, "ddd", IpPartner, pWinsAdd->Add.IPAdd, 0);
}
--tf--*/
DBGLEAVE("RplPullPullEntries\n");
return;
}
pTmp = pRspBuff + 4; //past the opcode
PERF("Speed this up by moving it into RplPullRegRepl")
/*
* Get the no of records from the response
*/
RplMsgfUfmSndEntriesRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
&pTmp,
&NoOfRecs,
Name,
&NameLen,
&fGrp,
&NoOfAdds,
NodeAdd,
&Flag,
&TmpVersNo,
TRUE /*Is it first time*/
);
DBGPRINT1(RPLPULL, "RplPullPullEntries: No of Records pulled are (%d)\n",
NoOfRecs);
if (WinsCnf.LogDetailedEvts > 0)
{
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
DWORD IpPartner = pAssocCtx->RemoteAdd.sin_addr.s_addr;
WinsEvtLogDetEvt(TRUE, WINS_EVT_REC_PULLED, TEXT("Pull replication"), __LINE__, "ddd", IpPartner, pWinsAdd->Add.IPAdd, NoOfRecs);
}
if (NoOfRecs > 0)
{
if (RplPullRegRepl(
Name,
NameLen,
Flag,
dwOwnerId,
TmpVersNo,
NoOfAdds,
NodeAdd,
pWinsAdd,
RplType
) == WINS_SUCCESS)
{
VersNo = TmpVersNo;
/*
* Repeat until all replicas have been retrieved from the
* response buffer
*/
for (i=1; i<NoOfRecs; i++)
{
RplMsgfUfmSndEntriesRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
&pTmp,
&NoOfRecs,
Name,
&NameLen,
&fGrp,
&NoOfAdds, //will be > 1 only if fGrp is
// is TRUE and it is a special
//group
NodeAdd,
&Flag,
&TmpVersNo,
FALSE /*Is it first time*/
);
if (RplPullRegRepl(
Name,
NameLen,
Flag,
dwOwnerId,
TmpVersNo,
NoOfAdds,
NodeAdd,
pWinsAdd,
RplType
) != WINS_SUCCESS)
{
DBGPRINT5(ERR, "RplPullPullEntries: Could not register record.\nName=(%s[%x])\nVersNo=(%d %d)\ndwOwnerId=(%d)\n", Name, Name[15], TmpVersNo.HighPart, TmpVersNo.LowPart, dwOwnerId);
break;
}
else
{
VersNo = TmpVersNo;
}
} //end of for (looping over all records starting from
//the second one
sfPulled = TRUE;
}
else
{
DBGPRINT5(ERR, "RplPullPullEntries: Could not register record.\nName=(%s[%x])\nVersNo=(%d %d)\ndwOwnerId=(%d)\n", Name, Name[15], TmpVersNo.HighPart, TmpVersNo.LowPart, dwOwnerId);
RetStat = WINS_FAILURE;
}
DBGPRINT2(RPLPULL,
"RplPullPullEntries. Max. Version No pulled = (%d %d)\n",
VersNo.HighPart, VersNo.LowPart
);
}
else // NoOfRecs == 0
{
DBGPRINT0(RPLPULL, "RplPullPullEntries: 0 records pulled\n");
}
//
// Let us free the response buffer
//
ECommFreeBuff(pRspBuff - COMM_HEADER_SIZE);
//
// let us store the max. version number pulled from the Push Pnr
// in the RplPullOwnerVersNo array. This array is looked at by
// the Push thread and RPC threads so we have to synchronize
// with them
//
// NOTE NOTE NOTE
// It is possible that one or more group (normal or
// special) records clashed with records in the db.
// During conflict resolution, the ownership of the
// record in the db may not get changed
// (See ClashAtReplGrpMems). Thus, even though the
// version number counter for the WINS whose replicas
// were pulled gets updated it is possible that there
// may not be any (or there may be less than what got pulled)
// records for that owner in the db. In such a
// case, a third WINS that tries to pull records owned by
// such a WINS may end up pulling 0 (or less number of) records.
// This is normal and correct behavior
//
//
//
// If the number of
// records pulled is greater than 1, update the counters.
//
if (NoOfRecs > 0)
{
if (RetStat == WINS_SUCCESS)
{
//
// fUpdCntrs will be FALSE if we have pulled as a result of a
// PULL RANGE request from the administrator. For all other
// cases, it is TRUE. If FALSE, we will update the counter
// only if the highest version number that we successfully
// pulled is greater than what is there in our counter for
// the WINS server.
//
if ( fUpdCntrs
||
LiGtr(VersNo, (pRplPullOwnerVersNo+dwOwnerId)->VersNo)
)
{
EnterCriticalSection(&RplVersNoStoreCrtSec);
//
// NOTE: Store the max. version number pulled and not the
// MaxVersNo that we specified. This is because, if we have
// not pulled released records, then if they get changed to
// ACTIVE prior to a future replication cycle (version number
// remains unchanged when a released record changes to an
// ACTIVE record due to a name registration), we will pull them.
//
(pRplPullOwnerVersNo+dwOwnerId)->VersNo = VersNo;
LeaveCriticalSection(&RplVersNoStoreCrtSec);
//
// We will pull our own records only due to a Pull Range
// request. PullSpecifiedRange calls this function
// from inside the NmsNmhNamRegCrtSec Section.
//
if (dwOwnerId == NMSDB_LOCAL_OWNER_ID)
{
if (LiGeq(VersNo, NmsNmhMyMaxVersNo))
{
NMSNMH_INC_VERS_COUNTER_M(VersNo, NmsNmhMyMaxVersNo);
}
}
//
// If vers. number pulled is smaller than the Max. Vers no,
// specified, check if it is because of the limit we have set
// for the max. number or records that can be replicated
// at a time. If yes, pull again.
//
if (
LiLtr(VersNo, MaxVersNo)
&&
(NoOfRecs == RPL_MAX_LIMIT_FOR_RPL)
)
{
MinVersNo = VersNo;
NMSNMH_INC_VERS_NO_M(MinVersNo, MinVersNo);
/*
* We may have been signaled by the main thread
* Check it.
*/
WinsMscChkTermEvt(
#ifdef WINSDBG
Client_e,
#endif
FALSE
);
continue;
}
}
} //if RetStat == 0
} // if NoOfRecs > 0
else // no of records pulled in is zero
{
//
// if the number of records pulled in is 0, then check if
// we have any records for the owner in the database.
// If there are none and fUpdCtrs is FALSE, meaning
// that this is a PULL SPECIFIED RANGE request from the
// administrator, delete the record for the owner from
// the in-memory and database tables
//
if (
(LiEqlZero((pRplPullOwnerVersNo+dwOwnerId)->VersNo))
&&
(!fUpdCntrs)
&&
(dwOwnerId != NMSDB_LOCAL_OWNER_ID)
)
{
EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
try {
(pNmsDbOwnAddTbl+dwOwnerId)->WinsState_e =
NMSDB_E_WINS_DELETED;
NmsDbWriteOwnAddTbl(
NMSDB_E_DELETE_REC,
dwOwnerId,
NULL, //address of WINS
NMSDB_E_WINS_DELETED,
NULL,
NULL
);
} // end of try
finally {
LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
}
}
break; //break out of the while loop
} // end of else
break;
} //end of while (TRUE)
DBGLEAVE("RplPullPullEntries\n");
return;
}
VOID
SubmitTimerReqs(
PRPL_CONFIG_REC_T pPullCnfRecs
)
/*++
Routine Description:
This function goes through the array of configuration records
submitting a timer request for each config. record that specifies
a time interval
Note: a single timer request is submitted for all records that
have the same time interval specified in them.
Arguments:
pPullCnfRecs - Array of Pull Configuration records
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
InitRplProcess
Side Effects:
Comments:
The records in the pPullCnfRecs array are traversed in sequence
This function is called only at Init/Reconfig time
--*/
{
DBGENTER("SubmitTimerReqs\n");
try {
SetTimeReqs.NoOfSetTimeReqs = 0;
for(
;
pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
pPullCnfRecs = (PRPL_CONFIG_REC_T) (
(LPBYTE)pPullCnfRecs + RPL_CONFIG_REC_SIZE
)
)
{
//
// Submit a timer request only if we have not submitted one
// already for the same time interval value
//
if (!pPullCnfRecs->fLinked)
{
//
// If it has an invalid time interval, check that
// it is not a one time only replication record
//
if (pPullCnfRecs->TimeInterval == RPL_INVALID_METRIC)
{
if (!pPullCnfRecs->fSpTime)
{
continue;
}
else // a specific time is given
{
//
// If Init time replication is specified,
// we must have done replication
// (in InitTimeRpl).
// We should check if SpTimeIntvl <= 0. If
// it is, we skip this record. The time for
// Specific time replication is past. In any
// case, we just pulled (in InitTimeRpl)
//
if (
(WinsCnf.PullInfo.InitTimeRpl)
&&
(pPullCnfRecs->SpTimeIntvl <= 0)
)
{
continue;
}
}
}
SubmitTimer(
NULL, //NULL means, SubmitTimer should
//allocate its own work item
pPullCnfRecs,
FALSE //it is not a resubmission
);
}
} // end of for loop
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("SubmitTimerReqs\n");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
}
DBGLEAVE("SubmitTimerReqs\n");
return;
}
VOID
SubmitTimer(
LPVOID pWrkItm,
PRPL_CONFIG_REC_T pPullCnfRec,
BOOL fResubmit
)
/*++
Routine Description:
This function is called to submit a single timer request
It is passed the address of a pull configuration record that
may have other pull config. records linked to it. Records
are linked if they require replication to happen at the same time.
Arguments:
pWrkItm - Work item to submit after initialization
pPullCnfRec - Address of a configuration record pertaining to a
Push Pnr
fResubmit - indicates whether this work item was submitted earlier (
and is now being resubmitted)
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
SubmitTimerReqs(), RplPullInit()
Side Effects:
Comments:
None
--*/
{
time_t AbsTime;
DWORD TimeInt;
BOOL fTimerSet = FALSE;
DWORD LastMaxVal = 0;
LPVOID pStartOfPullGrp = pPullCnfRec;
PRPL_CONFIG_REC_T pSvPtr = pPullCnfRec;
BOOL fSubmit = TRUE;
ASSERT(pPullCnfRec);
//
// Let us check all linked records.
// We stop at the first one with a Retry Count <=
// MaxNoOfRetries specified in WinsCnf. If found, we submit a timer,
// else we return
//
for (
;
pPullCnfRec != NULL;
pPullCnfRec = WinsCnfGetNextRplCnfRec(
pPullCnfRec,
RPL_E_VIA_LINK //get the
//linked rec
)
)
{
//
// If the number of retries have exceeded the max. no. allowed,
// check if we should submit a timer request for it now.
//
if (pPullCnfRec->RetryCount > WinsCnf.PullInfo.MaxNoOfRetries)
{
if (pPullCnfRec->RetryAfterThisManyRpl
< (DWORD)((pPullCnfRec->TimeInterval >
WINSCNF_MAX_WAIT_BEFORE_RETRY_RPL) ? 0 : WINSCNF_RETRY_AFTER_THIS_MANY_RPL
))
{
pPullCnfRec->RetryAfterThisManyRpl++;
//
// Is this record closer to a retry than
// the any other we have seen so far. If
// yes, then save the value of the
// RetryAfterThisManyRpl field and the
// address of the record. Note: A record
// with an invalid time interval but with
// a specific time will never be encountered
// by this section of the code (because
// fSpTime will be set to FALSE -- see below;
// Also, see SubmitTimerReqs)
//
if (pPullCnfRec->RetryAfterThisManyRpl >
LastMaxVal)
{
pSvPtr = pPullCnfRec;
LastMaxVal =
pPullCnfRec->RetryAfterThisManyRpl;
}
continue; //check the next record
}
else
{
pPullCnfRec->RetryAfterThisManyRpl = 0;
//pPullCnfRec->RetryAfterThisManyRpl = 1;
pPullCnfRec->RetryCount = 0;
}
}
FUTURES("Get rid of the if below")
//
// If this is a retry and TimeInterval is valid, use the retry time
// interval. If time interval is invalid, it means that we tried
// to establish comm. at a specific time.
//
if ((pPullCnfRec->RetryCount != 0) && (pPullCnfRec->TimeInterval != RPL_INVALID_METRIC))
{
// TimeInt = WINSCNF_RETRY_TIME_INT;
TimeInt = pPullCnfRec->TimeInterval;
}
else // this is not a retry
{
//
// Specific time replication is done only once at
// the particular time specified. After that
// replication is driven by the TimeInterval value
//
if (pPullCnfRec->fSpTime)
{
TimeInt = (DWORD)pPullCnfRec->SpTimeIntvl;
pPullCnfRec->fSpTime = FALSE;
}
else
{
if (pPullCnfRec->TimeInterval
!= RPL_INVALID_METRIC)
{
TimeInt = pPullCnfRec->TimeInterval;
}
else
{
//
// Since we have submitted a request
// for all records in this chain
// atleast once, break out of the
// loop (All records in this chain
// have an invalid time interval).
//
fSubmit = FALSE;
break; // we have already submitted
// this one time only request
}
}
}
//
// Set fTimerSet to TRUE to indicate that there is atleast
// one partner for which we will be submitting a timer request.
//
fTimerSet = TRUE;
//
// We need to submit the request. Break out of the loop
//
break;
}
//
// Do we need to submit a timer request
//
if (fSubmit)
{
//
// If fTimerSet is FALSE,
// it means that communication could not be established
// with any member of the group (despite WinsCnf.MaxNoOfRetries
// retries with each). We should compute the time interval to the
// earliest retry that we should do.
//
if (!fTimerSet)
{
// fixes #391314
if (WINSCNF_RETRY_AFTER_THIS_MANY_RPL == pSvPtr->RetryAfterThisManyRpl)
{
TimeInt = pSvPtr->TimeInterval;
}
else
{
TimeInt = pSvPtr->TimeInterval *
(WINSCNF_RETRY_AFTER_THIS_MANY_RPL -
pSvPtr->RetryAfterThisManyRpl);
}
pSvPtr->RetryAfterThisManyRpl = 0;
pSvPtr->RetryCount = 0;
}
(void)time(&AbsTime);
if( pSvPtr->LastRplTime == 0 ) {
//
// This is our first replication. Just add the interval to
// the current time.
//
AbsTime += TimeInt;
pSvPtr->LastRplTime = AbsTime;
} else {
//
// We have replicated before. We need to make sure that
// our replication time is at an interval based on the time
// the last replication started.
//
do {
pSvPtr->LastRplTime += TimeInt;
} while( pSvPtr->LastRplTime <= AbsTime );
AbsTime = pSvPtr->LastRplTime;
}
DBGPRINT3(RPLPULL, "SubmitTimer: %s a Timer Request for (%d) secs to expire at abs. time = (%d)\n",
fResubmit ? "Resubmitting" : "Submitting", TimeInt, AbsTime);
WinsTmmInsertEntry(
pWrkItm,
WINS_E_RPLPULL,
QUE_E_CMD_SET_TIMER,
fResubmit,
AbsTime,
TimeInt,
&QueRplPullQueHd,
pStartOfPullGrp,
pSvPtr->MagicNo,
&SetTimeReqs
);
}
return;
}
VOID
SndPushNtf(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function is called to push a notification to a remote WINS (Pull
Partner) that a certain number of updates have been done.
It can be called either as a result of a version number update or from
HdlPushNtf() to propagate a net trigger.
Arguments:
pConfigRec - Configuration record of the Push Pnr to whome the
notification needs to be sent
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPullInit()
Side Effects:
Comments:
None
--*/
{
LPBYTE pBuff;
DWORD MsgLen;
COMM_HDL_T DlgHdl;
DWORD i;
PRPL_ADD_VERS_NO_T pPullAddVersNoTbl;
PRPL_ADD_VERS_NO_T pPullAddVersNoTblTmp;
PCOMM_ADD_T pWinsAdd;
PNMSDB_WINS_STATE_E pWinsState_e;
PVERS_NO_T pStartVersNo;
time_t CurrentTime;
BOOL fStartDlg = FALSE;
volatile PRPL_CONFIG_REC_T pConfigRec = pWrkItm->pClientCtx;
DWORD NoOfOwnersActive = 0;
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DWORD StartOwnerId;
DWORD EndOwnerId;
BOOL fPullAddVersNoTblAlloc = FALSE;
DWORD SizeOfBuff;
BOOL fBuffAlloc = FALSE;
#if PRSCONN
BOOL fDlgActive = TRUE;
#endif
RPLMSGF_MSG_OPCODE_E Opcd_e;
DBGENTER("SndPushNtf\n");
//
// No need for entering a critical section while using pConfigRec,
// since only the Pull thread deallocates it on reconfiguration
// (check Reconfig)
//
//
// Check whether we want to try sending or not. We will not try if
// we have had 2 comm. failure in the past 5 mts. This is to guard
// against the case where a lot of push request get queued up for
// the pull thread for communicating with a wins with which comm
// has been lost.
//
(void)time(&CurrentTime);
#define PUSH_TRY_LIMIT 2
if (
((CurrentTime - pConfigRec->LastCommFailTime) < FIVE_MINUTES)
&&
(pConfigRec->PushNtfTries >= PUSH_TRY_LIMIT) //try two times
)
{
DBGPRINT2(ERR, "SndPushNtf: Since we have tried %d times unsuccessfully in the past 5 mts to communicate with the WINS server (%X) , we are returning\n",
pConfigRec->PushNtfTries,
pConfigRec->WinsAdd.Add.IPAdd);
WINSEVT_LOG_D_M(pConfigRec->WinsAdd.Add.IPAdd, WINS_EVT_NO_NTF_PERS_COMM_FAIL);
return;
}
//
// If it is a push notification without propagate, we should send all
// our maps. If it is a push with propagate, we should send only one
// map -- If we are initiating the trigger, we should send map of
// records owned by us. If not, we should send the map of records
// owned by the WINS that initiated the trigger
//
if ( pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF)
{
StartOwnerId = 0;
EndOwnerId = StartOwnerId + NmsDbNoOfOwners;
}
else
{
BOOL fAllocNew = FALSE;
COMM_ADD_T WinsAdd;
STATUS RetStat;
//
// If we are propagating a net trigger and the address in pMsg is
// not our own, it means that the trigger came from a new WINS. If
// it is our own, it means that the trigger came from an old WINS(3.5)
// or 3.51 beta/RC1. In this case we should send all of our maps.
//
if (
(pWrkItm->pMsg)
&&
(PtrToUlong(pWrkItm->pMsg) != NmsLocalAdd.Add.IPAdd)
)
{
//
// we are propagating a net trigger. pMsg above will not be NULL
// only if we are propagating a net trigger
//
COMM_INIT_ADD_M(&WinsAdd, PtrToUlong(pWrkItm->pMsg));
RetStat = RplFindOwnerId(
&WinsAdd,
&fAllocNew, //don't assign
&StartOwnerId,
WINSCNF_E_IGNORE_PREC,
WINSCNF_LOW_PREC
);
if (RetStat == WINS_FAILURE)
{
ASSERTMSG("DROPPING PROPAGATE\n", FALSE);
//
// log an event and return
//
DBGPRINT1(RPLPULL, "SndPushNtf: WEIRD -- Dropping the push with propagate since we did not find the owner (%x) in our table. HOW CAN THAT HAPPEN\n", WinsAdd.Add.IPAdd);
return;
}
EndOwnerId = StartOwnerId + 1;
}
else
{
//
// Either we are initiating the trigger or we are propagating
// one sent by a 3.5 or a 3.51 BETA/RC1 WINS
//
if (!pWrkItm->pMsg)
{
//
// We are initiating a trigger. Just send one map (records
// owned by us)
//
StartOwnerId = 0;
EndOwnerId = 1;
}
else
{
//
// Send all the maps except our own since we don't know who
// initiated the trigger. Not sending ours lowers the
// probability of this trigger process continuing indefinitely
//
//
// Actually no need to test this since we will never
// have this case (HdlPushNtf() must have pulled records
// of atleast one other WINS).
//
if (NmsDbNoOfOwners == 1)
{
//
// nothing to propagate. Just return
//
return;
}
else
{
StartOwnerId = 1;
}
EndOwnerId = NmsDbNoOfOwners;
}
}
}
//
// If we are trying after a comm. failure
//
if (pConfigRec->PushNtfTries == PUSH_TRY_LIMIT)
{
pConfigRec->PushNtfTries = 0;
}
FUTURES("If/When we start having persistent dialogues, we should check if we")
FUTURES("already have a dialogue with the WINS. If there is one, we should")
FUTURES("use that. To find this out, loop over all Pull Config Recs to see")
FUTURES("if there is match (use the address as the search key")
try {
#if PRSCONN
//
// If the pnr is not a persistent pnr or if it is one but the dlg with it
// is not active
//
if (
(!pConfigRec->fPrsConn)
||
!ECommIsBlockValid(&pConfigRec->PrsDlgHdl)
||
(((CurrentTime - pConfigRec->LastCommTime) > FIVE_MINUTES) &&
!(fDlgActive = ECommIsDlgActive(&pConfigRec->PrsDlgHdl)))
)
{
if (!fDlgActive)
{
ECommEndDlg(&pConfigRec->PrsDlgHdl);
}
//
// Init the pEnt field to NULL so that ECommEndDlg (in the
// exception handler) called as a result of an exception from
// behaves fine.
//
DlgHdl.pEnt = NULL;
//
// Start a dialogue. Don't retry if there is comm. failure
//
ECommStartDlg(
&pConfigRec->WinsAdd,
COMM_E_RPL,
&DlgHdl
);
//
// If the pnr is not NT 5, we can not send a PRS opcode to it (it will just
// chuck it. The macro below will set the fPrsConn field of the partner
// record to FALSE if the partner is not an NT 5+ partner
//
if (pConfigRec->fPrsConn)
{
ECOMM_IS_PNR_POSTNT4_WINS_M(&DlgHdl, pConfigRec->fPrsConn);
}
if (pConfigRec->fPrsConn)
{
pConfigRec->PrsDlgHdl = DlgHdl;
}
}
else
{
DlgHdl = pConfigRec->PrsDlgHdl;
}
#else
//
// Init the pEnt field to NULL so that ECommEndDlg (in the
// exception handler) called as a result of an exception from
// behaves fine.
//
DlgHdl.pEnt = NULL;
//
// Start a dialogue. Don't retry if there is comm. failure
//
ECommStartDlg(
&pConfigRec->WinsAdd,
COMM_E_RPL,
&DlgHdl
);
#endif
fStartDlg = TRUE;
pConfigRec->LastCommFailTime = 0;
if (pConfigRec->PushNtfTries > 0)
{
pConfigRec->PushNtfTries = 0;
}
/*
* Get the max. version no for entries owned by self
* No need to enter a critical section before retrieving
* the version number.
*
* The reason we subtract 1 from NmsNmhMyMaxVersNo is because
* it contains the version number to be given to the next record
* to be registered/updated.
*/
EnterCriticalSection(&NmsNmhNamRegCrtSec);
EnterCriticalSection(&RplVersNoStoreCrtSec);
NMSNMH_DEC_VERS_NO_M(
NmsNmhMyMaxVersNo,
pRplPullOwnerVersNo->VersNo
);
LeaveCriticalSection(&RplVersNoStoreCrtSec);
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
WinsMscAlloc(
sizeof(RPL_ADD_VERS_NO_T) * (EndOwnerId - StartOwnerId),
(LPVOID *)&pPullAddVersNoTbl
);
fPullAddVersNoTblAlloc = TRUE;
//
// Initialize PullAddVersNoTbl array
//
for (i=StartOwnerId; i < EndOwnerId; i++)
{
RPL_FIND_ADD_BY_OWNER_ID_M(i, pWinsAdd, pWinsState_e, pStartVersNo);
if (*pWinsState_e == NMSDB_E_WINS_ACTIVE)
{
(pPullAddVersNoTbl + NoOfOwnersActive)->VersNo = (pRplPullOwnerVersNo+i)->VersNo;
(pPullAddVersNoTbl + NoOfOwnersActive)->OwnerWinsAdd = *pWinsAdd;
NoOfOwnersActive++;
}
}
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(&DlgHdl, fIsPnrBeta1Wins);
#endif
//
// format the Push notification message. This message is exactly same
// as the Address to Version Number Mapping message except the opcode
//
SizeOfBuff = RPLMSGF_ADDVERSMAP_RSP_SIZE_M(NoOfOwnersActive);
WinsMscAlloc(SizeOfBuff, (LPVOID *)&pBuff);
fBuffAlloc = TRUE;
#if PRSCONN
//
// Send a PRS opcode if we are supposed to be forming a persistent conn
//
if (pConfigRec->fPrsConn)
{
Opcd_e = (pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF) ? RPLMSGF_E_UPDATE_NTF_PRS : RPLMSGF_E_UPDATE_NTF_PROP_PRS;
}
else
#endif
{
Opcd_e = (pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF) ? RPLMSGF_E_UPDATE_NTF : RPLMSGF_E_UPDATE_NTF_PROP;
}
RplMsgfFrmAddVersMapRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
Opcd_e,
pBuff + COMM_N_TCP_HDR_SZ,
SizeOfBuff - COMM_N_TCP_HDR_SZ,
pPullAddVersNoTbl,
NoOfOwnersActive,
(pWrkItm->pMsg != NULL) ? PtrToUlong(pWrkItm->pMsg) : NmsLocalAdd.Add.IPAdd,
//
// pMsg above will be Non-NULL only for the case
// when we are propagating the net upd. ntf.
//
&MsgLen
);
//
// send the message to the remote WINS. Use an existent dialogue
// if there with the remote WINS
//
ECommSendMsg(
&DlgHdl,
NULL, //no need for address since this is a TCP conn
pBuff + COMM_N_TCP_HDR_SZ,
MsgLen
);
#if PRSCONN
pConfigRec->LastCommTime = CurrentTime;
if (!pConfigRec->fPrsConn)
#endif
{
//
// Ask ComSys (TCP listener thread) to monitor the dialogue
//
ECommProcessDlg(
&DlgHdl,
COMM_E_NTF_START_MON
);
}
} // end of try {..}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT2(EXC, "SndPushNtf -PULL thread. Got Exception (%x). WinsAdd = (%x)\n", ExcCode, pConfigRec->WinsAdd.Add.IPAdd);
WINSEVT_LOG_M(ExcCode, WINS_EVT_RPLPULL_PUSH_NTF_EXC);
if (ExcCode == WINS_EXC_COMM_FAIL)
{
pConfigRec->LastCommFailTime = CurrentTime;
NOTE("Causes an access violation when compiled with no debugs. Haven't")
NOTE("figured out why. This code is not needed")
pConfigRec->PushNtfTries++; //increment count of tries.
}
if (fStartDlg)
{
//
// End the dialogue.
//
ECommEndDlg(&DlgHdl);
#if PRSCONN
if (pConfigRec->fPrsConn)
{
ECOMM_INIT_DLG_HDL_M(&(pConfigRec->PrsDlgHdl));
}
#endif
}
} //end of exception handler
if (fPullAddVersNoTblAlloc)
{
WinsMscDealloc(pPullAddVersNoTbl);
}
//
// If this is a temporary configuration record, we need to deallocate it
// It can be a temporary config. record only if
// 1)We are executing here due to an rpc request
//
if (pConfigRec->fTemp)
{
WinsMscDealloc(pConfigRec);
}
//
// dealloc the buffer we allocated
//
if (fBuffAlloc)
{
WinsMscDealloc(pBuff);
}
//
// In the normal case, the connection will be terminated by the other side.
//
DBGLEAVE("SndPushNtf\n");
return;
}
VOID
EstablishComm(
IN PRPL_CONFIG_REC_T pPullCnfRecs,
IN BOOL fAllocPushPnrData,
IN PPUSHPNR_DATA_T *ppPushPnrData,
IN RPL_REC_TRAVERSAL_E RecTrv_e,
OUT LPDWORD pNoOfPushPnrs
)
/*++
Routine Description:
This function is called to establish communications with
all the WINS servers i(Push Pnrs) specified by the the config records
Arguments:
pPullCnfRecs - Pull Config records
pPushPnrData - Array of data records each pertaining to a PUSH pnr
RecTrv_e - indicates whether the list of configuration records
is to be traversed in sequence
pNoOfPushPnrs - No of Push Pnrs
Externals Used:
None
Return Value:
VOID
Error Handling:
Called by:
GetReplicasNew
Side Effects:
Comments:
On return from this function, pPushPnrData will have zero or more
partners starting from index 0 with which dlg could be started.
PushPnrId will start from 1 (if dlg. could be established with
atleast one partner) and can be any number in the range 1
to MAX_RPL_OWNERS (the number indicates the iteration of the for
loop at which this WINS was encountered)
--*/
{
#define INITIAL_NO_OF_PNRS 30
volatile DWORD i;
volatile DWORD NoOfRetries = 0;
DWORD TotNoOfPushPnrSlots = INITIAL_NO_OF_PNRS;
PPUSHPNR_DATA_T pPushPnrData;
#if PRSCONN
time_t CurrentTime;
BOOL fDlgActive;
#endif
DBGENTER("EstablishComm\n");
*pNoOfPushPnrs = 0;
//
// if the client wants this function to allocate pPushPnrData
//
if (fAllocPushPnrData)
{
WinsMscAlloc(sizeof(PUSHPNR_DATA_T) * TotNoOfPushPnrSlots, (LPVOID *)ppPushPnrData);
}
pPushPnrData = *ppPushPnrData;
/*
Start a dialogue with all Push Partners specified in the
Pull Cnf Recs passed as input argument and get
the version numbers of the different owners kept
in the database of these Push Pnrs
i = 0 for self's data
*/
#if PRSCONN
(void)time(&CurrentTime);
#endif
for (
i = 1;
pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
// no third expression
)
{
try
{
#if PRSCONN
fDlgActive = TRUE;
//
// If this partner is not a persistent conn. pnr or if he is one
// but the dlg that we have with it is not valid, start a dlg
// with him. A dlg may not be valid either because we never
// formed one with pnr or because it got disconnected as
// a result of the pnr terminating.
//
// there is a corner case: two servers, A<->B replication partners
// A pulls records from B and then on B WINS is restarted. Then, any
// communication that A attempts with B in less than five minutes will
// fail. This is because A will still think the connection is up.
// A can't do otherwise, because there would be too much overhead in
// testing each time the TCP connection (see CommIsDlgActive).
// This check has to be done at least at certain intervals (5min).
if (
(!pPullCnfRecs->fPrsConn)
||
!ECommIsBlockValid(&pPullCnfRecs->PrsDlgHdl)
||
(((CurrentTime - pPullCnfRecs->LastCommTime) > FIVE_MINUTES) &&
!(fDlgActive = ECommIsDlgActive(&pPullCnfRecs->PrsDlgHdl)))
)
{
//
// if the dlg is gone, end it so that the dlg block gets
// deallocated.
//
if (!fDlgActive)
{
ECommEndDlg(&pPullCnfRecs->PrsDlgHdl);
}
#endif
//
// Let us make sure that we don't try to establish
// communications with a WINS whose retry count is
// over. If this is such a WINS's record, get the
// next WINS's record and continue. If there is
// no WINS left to establish comm with, break out of
// the for loop
//
//
if (pPullCnfRecs->RetryCount > WinsCnf.PullInfo.MaxNoOfRetries)
{
pPullCnfRecs = WinsCnfGetNextRplCnfRec(
pPullCnfRecs,
RecTrv_e
);
if (pPullCnfRecs == NULL)
{
break; // break out of the for loop
}
continue;
}
ECommStartDlg(
&pPullCnfRecs->WinsAdd,
COMM_E_RPL,
&pPushPnrData->DlgHdl
);
pPushPnrData->fDlgStarted = TRUE;
#if PRSCONN
//
// If the dlg is supposed to be persistent, store it as such
//
if (pPullCnfRecs->fPrsConn)
{
pPullCnfRecs->PrsDlgHdl = pPushPnrData->DlgHdl;
pPushPnrData->fPrsConn = TRUE;
}
}
else //There is a pers dlg and it is very much active
{
pPushPnrData->DlgHdl = pPullCnfRecs->PrsDlgHdl;
pPushPnrData->fPrsConn = TRUE;
pPushPnrData->fDlgStarted = TRUE;
//
// No need to set fPrsConn field of PushPnrData to FALSE
// Memory is initialized to 0 by default
//
}
//
// It is ok to set it here as against after the data is sent
//
pPullCnfRecs->LastCommTime = CurrentTime;
#endif
pPushPnrData->RplType = pPullCnfRecs->RplType;
//
// Note: Don't use RplFindOwnerId to get the owner id.
// corresponding to the Wins with which communication
// is being established because doing so will create an
// entry for the WINS in the table. If this partner
// turns out to be bogus, we will have to remove
// the entry later.
//
// We will do this later.
//
pPushPnrData->PushPnrId = i;
pPushPnrData->WinsAdd = pPullCnfRecs->WinsAdd;
pPushPnrData->pPullCnfRec = pPullCnfRecs;
//
// we were able to establish comm., so let us init the
// LastCommFailTime to 0. NOTE: Currently, this field
// is not used for pull partners.
//
pPullCnfRecs->LastCommFailTime = 0;
//
// Reset the retry counter back to 0
//
NoOfRetries = 0;
(VOID)InterlockedIncrement(&pPullCnfRecs->NoOfRpls);
//
// reinit Retry Count to 0
//
pPullCnfRecs->RetryCount = 0;
//
// Note: These should get incremented only if there is
// no exception. That is why they are here versus in the
// as expr3 of the for clause
//
pPushPnrData++;
(*pNoOfPushPnrs)++;
if (fAllocPushPnrData && (*pNoOfPushPnrs == TotNoOfPushPnrSlots))
{
WINSMSC_REALLOC_M(sizeof(PUSHPNR_DATA_T) * (TotNoOfPushPnrSlots * 2), ppPushPnrData);
pPushPnrData = (*ppPushPnrData) + TotNoOfPushPnrSlots;
TotNoOfPushPnrSlots *= 2;
}
i++;
WinsMscChkTermEvt(
#ifdef WINSDBG
WINS_E_RPLPULL,
#endif
FALSE
);
//
// Note: the following
// is required even when an exception is raised. Therefore
// it is repeated inside the exception handler code.
//
pPullCnfRecs = WinsCnfGetNextRplCnfRec(
pPullCnfRecs,
RecTrv_e
);
if (pPullCnfRecs == NULL)
{
break; // break out of the for loop
}
} // end of try blk
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("EstablishComm");
if (GetExceptionCode() == WINS_EXC_COMM_FAIL)
{
#ifdef WINSDBG
struct in_addr InAddr;
InAddr.s_addr = htonl( pPullCnfRecs->WinsAdd.Add.IPAdd );
DBGPRINT1(EXC, "EstablishComm: Got a comm. fail with WINS at address = (%s)\n", inet_ntoa(InAddr));
#endif
WinsMscChkTermEvt(
#ifdef WINSDBG
WINS_E_RPLPULL,
#endif
FALSE
);
//
// Store the time (for use in SndPushNtf)
//
#if PRSCONN
pPullCnfRecs->LastCommFailTime = CurrentTime;
#else
(VOID)time(&(pPullCnfRecs->LastCommFailTime));
#endif
//
// Check if we have exhausted the max. no. of retries
// we are allowed in one replication cycle. If not,
// sleep for some time (20sec) and try again..
//
// --ft: 07/10: comment out this piece of code since
// MAX_RETRIES_TO_BE_DONE is set to 0 (#def)
//
//if (NoOfRetries < MAX_RETRIES_TO_BE_DONE)
//{
// // Maybe the remote WINS is coming up. We should
// // give it a chance to come up. Let us sleep for
// // some time.
// //
// Sleep(RETRY_TIME_INTVL);
// NoOfRetries++;
// continue;
//}
(VOID)InterlockedIncrement(&pPullCnfRecs->NoOfCommFails);
//
// Only Communication failure exception is to
// be consumed.
//
// We will retry at the next replication time.
//
// Note: the comparison operator needs to be <= and not
// < (this is required for the 0 retry case). If we
// use <, a timer request would be submitted for
// the WINS (by SubmitTimerReqs following GetReplicasNew
// in RplPullInit which will result in a retry.
//
if (pPullCnfRecs->RetryCount <= WinsCnf.PullInfo.MaxNoOfRetries)
{
pPullCnfRecs->RetryCount++;
//
// We will now retry at the next
// replication time.
//
CHECK("A retry time interval different than the replication time interval")
CHECK("could be used here. Though this will complicate the code, it may")
CHECK("be a good idea to do it if the replication time interval is large")
CHECK("Alternatively, considering that we have already retried a certain")
CHECK("no. of times, we can put the onus on the administrator to trigger")
CHECK("replication. I need to think this some more")
}
else //max. no of retries done
{
WINSEVT_LOG_M(
WINS_FAILURE,
WINS_EVT_CONN_RETRIES_FAILED
);
DBGPRINT0(ERR, "Could not connect to WINS. All retries failed\n");
}
//
// Go to the next configuration record based on the
// value of the RecTrv_e flag
//
pPullCnfRecs = WinsCnfGetNextRplCnfRec(
pPullCnfRecs,
RecTrv_e
);
if (pPullCnfRecs == NULL)
{
break; //break out of the for loop
}
}
else
{
//
// A non comm failure error is serious. It needs
// to be propagated up
//
WINS_RERAISE_EXC_M();
}
} //end of exception handler
} // end of for loop for looping over config records
DBGLEAVE("EstablishComm\n");
return;
}
VOID
HdlPushNtf(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function is called to handle a push notification received from
a remote WINS.
Arguments:
pWrkItm - the work item that the Pull thread pulled from its queue
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPullInit
Side Effects:
Comments:
None
--*/
{
BOOL fFound = FALSE;
PUSHPNR_DATA_T PushPnrData[1];
DWORD OwnerId;
DWORD i;
VERS_NO_T MinVersNo;
VERS_NO_T MaxVersNo;
RPLMSGF_MSG_OPCODE_E Opcode_e;
BOOL fPulled = FALSE;
BOOL fAllocNew;
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DWORD InitiatorWinsIpAdd;
#if PRSCONN
BOOL fImplicitConnPrs;
time_t CurrentTime;
BOOL fDlgActive = TRUE;
COMM_HDL_T DlgHdl;
PCOMM_HDL_T pDlgHdl = &DlgHdl;
PRPL_CONFIG_REC_T pPnr;
#endif
DWORD ExcCode = WINS_EXC_INIT;
DBGENTER("HdlPushNtf - PULL thread\n");
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(&pWrkItm->DlgHdl, fIsPnrBeta1Wins);
#endif
#if 0
COMM_INIT_ADD_FROM_DLG_HDL_M(&PnrAdd, pWrkItm->DlgHdl);
#endif
//
// We want to pull all records starting from the min vers. no.
//
WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
//
// Get the opcode from the message
//
RPLMSGF_GET_OPC_FROM_MSG_M(pWrkItm->pMsg, Opcode_e);
//
// Unformat the message to get the owner to version number maps
//
RplMsgfUfmAddVersMapRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
pWrkItm->pMsg + 4, //past the opcodes
&(PushPnrData[0].NoOfMaps),
&InitiatorWinsIpAdd, //Wins that initiated
//the prop
&PushPnrData[0].pAddVers
);
//
// Free the buffer that carried the message. We don't need it anymore
//
ECommFreeBuff(pWrkItm->pMsg - COMM_HEADER_SIZE); //decrement to
// begining
//of buff
#if PRSCONN
(VOID)time(&CurrentTime);
//
// We determine whether or not the partner has formed a persistent
// connection with us from the opcode
//
fImplicitConnPrs = ((Opcode_e == RPLMSGF_E_UPDATE_NTF_PRS) || (Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP_PRS));
FUTURES("When we start having persistent dialogues, we should check if we")
FUTURES("already have a dialogue with the WINS. If there is one, we should")
FUTURES("use that. To find this out, loop over all Pull Config Recs to see")
FUTURES("if there is match (use the address as the search key")
//
// If the connection formed with us is persistent, get the
// config record or the pnr. Nobody can change the config
// rec array except the current thread (pull thread)
//
if (fImplicitConnPrs)
{
if ((pPnr = RplGetConfigRec(RPL_E_PULL, &pWrkItm->DlgHdl,NULL)) != NULL)
{
//
// if the pnr is not persistent for pulling or if it
// is persistent but the dlg is invalid, start it. Store
// the dlg hdl in a temp var.
//
if ((!pPnr->fPrsConn)
||
!ECommIsBlockValid(&pPnr->PrsDlgHdl)
||
(((CurrentTime - pPnr->LastCommTime) > FIVE_MINUTES) &&
!(fDlgActive = ECommIsDlgActive(&pPnr->PrsDlgHdl))))
{
//
// If the dlg is inactive, end it so that we start from
// a clean slate.
//
if (!fDlgActive)
{
ECommEndDlg(&pPnr->PrsDlgHdl);
}
ECommStartDlg(
&pPnr->WinsAdd,
COMM_E_RPL,
pDlgHdl
);
if (pPnr->fPrsConn)
{
pPnr->PrsDlgHdl = *pDlgHdl;
}
}
else
{
pDlgHdl = &pPnr->PrsDlgHdl;
}
}
else
{
//
// Apparently a window where a reconfig of this
// WINS caused the remote guy to be removed as a pull
// pnr. This is a window because the push thread
// checks whether the remote guy is a pnr prior to
// handing the request to the pull thread. We will in
// this case just bail out
//
ASSERTMSG("window condition. Pnr no longer there. Did you reconfigure in the very recent past If yes, hit go, else log it", FALSE);
ECommEndDlg(&pWrkItm->DlgHdl);
DBGPRINT0(FLOW, "LEAVE: HdlPushNtf - PULL thread\n");
return;
}
}
else
{
pDlgHdl = &pWrkItm->DlgHdl;
}
#endif
//
// loop over all WINS address - Version number maps sent to us
// by the remote client
//
try {
PRPL_ADD_VERS_NO_T pAddVers;
// filter personas grata / non grata from the list of OwnerAddress<->VersionNo
// given to us by the remote pusher
FilterPersona(&(PushPnrData[0]));
pAddVers = PushPnrData[0].pAddVers;
// at this point all WINS in PushPnrData are allowed by the lists of personas grata/non-grata
for (i=0; i < PushPnrData[0].NoOfMaps; i++, pAddVers++)
{
fAllocNew = TRUE;
RplFindOwnerId(
&pAddVers->OwnerWinsAdd,
&fAllocNew, //allocate entry if not existent
&OwnerId,
WINSCNF_E_INITP_IF_NON_EXISTENT,
WINSCNF_LOW_PREC
);
//
// If the local WINS has older information than the remote
// WINS, pull the new information. Here we are comparing
// the highest version number in the local db for a particular
// WINS with the highest version number that the remote Pusher
// has. NOTE: if the map sent by the PULL PNR pertains to
// self, it means that we went down and came up with a truncated
// database (partners have replicas). DON"T PULL these records
//
if (
(OwnerId != NMSDB_LOCAL_OWNER_ID)
)
{
//
// If the max. vers. number is less than or equal to
// what we have, don't pull
//
if (LiLeq(
pAddVers->VersNo,
(pRplPullOwnerVersNo+OwnerId)->VersNo
)
)
{
continue; //check the next owner
}
NMSNMH_INC_VERS_NO_M(
(pRplPullOwnerVersNo+OwnerId)->VersNo,
MinVersNo
);
//
// Pull Entries
//
RplPullPullEntries(
pDlgHdl,
OwnerId,
MaxVersNo, //inited to 0
MinVersNo,
WINS_E_RPLPULL,
NULL,
TRUE, //update counters
PtrToUlong (pWrkItm->pClientCtx)
);
//
// If atleast one valid record was pulled by WINS, sfPulled
// will be set to TRUE. Since this can get reset by the
// next call to RplPullPullEntries, let us save it.
//
if (sfPulled)
{
fPulled = TRUE;
}
}
} //end of for{} over all wins address - version # maps
} // end of try {}
except (EXCEPTION_EXECUTE_HANDLER) {
ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "HdlPushNtf: Encountered exception %x\n", ExcCode);
if (ExcCode == WINS_EXC_COMM_FAIL)
{
COMM_IP_ADD_T RemoteIPAdd;
COMM_GET_IPADD_M(&pWrkItm->DlgHdl, &RemoteIPAdd);
DBGPRINT1(EXC, "HdlPushNtf: Communication Failure with Remote Wins having address = (%x)\n", RemoteIPAdd);
}
WINSEVT_LOG_M(ExcCode, WINS_EVT_EXC_PUSH_TRIG_PROC);
}
if (PushPnrData[0].NoOfMaps > 0)
{
WinsMscDealloc(PushPnrData[0].pAddVers);
}
//
// If opcode indicates push propagation and we did pull atleast one
// record from the WINS that sent us the Push notification, do the
// propagation now. We do not propagate to the guy who sent us
// the trigger.
//
// Note: We never propagate if this update notification has made its way
// back to us because of some loop. We also don't propagate it if
// we have been told not to by the admin.
//
if (((Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP)
#if PRSCONN
|| (Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP_PRS)
#endif
) && fPulled && !COMM_MY_IP_ADD_M(InitiatorWinsIpAdd) && (WinsCnf.PushInfo.PropNetUpdNtf == DO_PROP_NET_UPD_NTF))
{
COMM_ADD_T WinsAdd;
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
//
// We need to synchronize with the NBT threads
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
//
// Check whether we have any PULL pnrs. (We need to access WinsCnf
// from within the NmsNmhNamRegCrtSec)
//
// We do this test here instead of in the RPL_PUSH_NTF_M macro to
// localize the overhead to this function only. Note: If the
// Initiator WINS address is 0, it means that it is a Daytona WINS (not
// a PPC release WINS). In such a case, we put our own address. This
// has the advantage of stopping propagations in a loop of new WINSs if
// they have gone around the loop once..
//
if (WinsCnf.PushInfo.NoOfPullPnrs != 0)
{
try
{
RPL_PUSH_NTF_M(
RPL_PUSH_PROP,
(InitiatorWinsIpAdd == 0) ? ULongToPtr(NmsLocalAdd.Add.IPAdd) : ULongToPtr(InitiatorWinsIpAdd),
&WinsAdd, //don't want to send to this guy.
NULL
);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
DBGPRINTEXC("HdlPushNtf: Exception while propagating a trigger");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_PUSH_PROP_FAILED);
}
}
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
}
//
// End the dlg. The right dlg will get terminated.
// Note: The dlg is explicit (if we establishd it) or implicit (established
// by the remote client).
//
// So, if the remote connection is not persistent or if it is but we
// the pnr is not persistent for pulling (meaning we established an
// explicit connection with it, end the dlg. pDlgHdl points to the right
// dlg
//
#if PRSCONN
if (!fImplicitConnPrs || !pPnr->fPrsConn)
{
ECommEndDlg(pDlgHdl);
}
else
{
//
// if we are here, it means that we pPnr is set to a Partner. If
// we had a comm. failure with it, we should end the Prs Dlg with
// it.
//
if (ExcCode == WINS_EXC_COMM_FAIL)
{
ECommEndDlg(&pPnr->PrsDlgHdl);
}
}
#else
ECommEndDlg(pDlgHdl);
#endif
DBGPRINT0(FLOW, "LEAVE: HdlPushNtf - PULL thread\n");
return;
}
STATUS
RegGrpRepl(
LPBYTE pName,
DWORD NameLen,
DWORD Flag,
DWORD OwnerId,
VERS_NO_T VersNo,
DWORD NoOfAdds,
PCOMM_ADD_T pNodeAdd,
PCOMM_ADD_T pOwnerWinsAdd
)
/*++
Routine Description:
This function is called to register a replica of a group entry
Arguments:
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPullPullEntries
Side Effects:
Comments:
None
--*/
{
NMSDB_NODE_ADDS_T GrpMems;
DWORD i; //for loop counter
DWORD n = 0; //index into the NodeAdd array
BYTE EntTyp;
BOOL fAllocNew;
STATUS RetStat;
GrpMems.NoOfMems = 0;
DBGENTER("RegGrpRepl\n");
EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(Flag);
//
// Check if it is a special group or a multihomed entry
//
if (EntTyp != NMSDB_NORM_GRP_ENTRY)
{
CHECK("I think I have now stopped sending timed out records");
//
// If we did not get any member. This can only mean that
// all members of this group/multihomed entry have timed out
// at the remote WINS.
//
if (NoOfAdds != 0)
{
GrpMems.NoOfMems = NoOfAdds;
for (i = 0; i < NoOfAdds; i++)
{
//
// The first address is the address of
// the WINS that is the owner of the
// member.
//
fAllocNew = TRUE;
RplFindOwnerId(
&pNodeAdd[n++],
&fAllocNew, //assign if not there
&GrpMems.Mem[i].OwnerId,
WINSCNF_E_INITP_IF_NON_EXISTENT,
WINSCNF_LOW_PREC
);
//
// The next address is the address of the
// member
//
GrpMems.Mem[i].Add = pNodeAdd[n++];
}
}
#ifdef WINSDBG
else //no members
{
if (NMSDB_ENTRY_STATE_M(Flag) != NMSDB_E_TOMBSTONE)
{
DBGPRINT0(EXC, "RegGrpRepl: The replica of a special group without any members is not a TOMBSTONE\n");
WINSEVT_LOG_M(
WINS_FAILURE,
WINS_EVT_RPL_STATE_ERR
);
WINS_RAISE_EXC_M(WINS_EXC_RPL_STATE_ERR);
}
}
#endif
}
else // it is a normal group
{
NOTE("On a clash with a special group, this owner id. will be stored which")
NOTE("can be misleading")
GrpMems.NoOfMems = 1;
GrpMems.Mem[0].OwnerId = OwnerId; //misleading (see ClashAtRegGrpRpl()
//in nmsnmh.c - clash between normal
//grp and special grp.
GrpMems.Mem[0].Add = *pNodeAdd;
}
RetStat = NmsNmhReplGrpMems(
pName,
NameLen,
EntTyp,
&GrpMems,
Flag,
OwnerId,
VersNo,
pOwnerWinsAdd
);
DBGLEAVE("RegGrpRepl\n");
return(RetStat);
}
BOOL
IsTimeoutToBeIgnored(
PQUE_TMM_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function is called to determine if the timeout that the
PULL thread received needs to be ignored
Arguments:
pWrkItm - Timeout work itm
Externals Used:
None
Return Value:
TRUE if the timeout needs to be ignored
FALSE otherwise
Error Handling:
Called by:
RplPullInit
Side Effects:
Comments:
None
--*/
{
BOOL fRetVal = FALSE;
try {
//
// If this is the timeout based on old config
// ignore it. If the old configuration memory blocks
// have not been deallocated as yet, deallocate them
//
if (pWrkItm->MagicNo != RplPullCnfMagicNo)
{
//
// Deallocate the work item and deallocate
// the configuration block
//
WinsTmmDeallocReq(pWrkItm);
fRetVal = TRUE;
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("IsTimeoutToBeIgnored");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
}
return(fRetVal);
}
VOID
InitRplProcess(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to start the replication process. This
comprises of getting the replicas if the InitTimeRpl field
is set to 1. Timer requests are also submitted.
Arguments:
pWinsCnf - pointer to the Wins Configuration structure
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPullInit()
Side Effects:
Comments:
None
--*/
{
PRPL_CONFIG_REC_T pPullCnfRecs = pWinsCnf->PullInfo.pPullCnfRecs;
BOOL fAllocNew;
DWORD OwnerWinsId;
STATUS RetStat;
//
// Initialize Owner-Id table with new entries if any
//
for (
;
pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
//no third expression
)
{
fAllocNew = TRUE;
RetStat = RplFindOwnerId(
&pPullCnfRecs->WinsAdd,
&fAllocNew,
&OwnerWinsId,
WINSCNF_E_INITP,
pPullCnfRecs->MemberPrec
);
if (RetStat == WINS_FAILURE)
{
FUTURES("Improve error recovery")
//
// We have hit the limit. Break out of the loop
// but carry on in the hope that the situation
// will correct itself by the time we replicate.
// If InitTimeReplication is TRUE, there is no
// chance of the table entries getting freed up.
// Even if some entries get freed, when we make
// an entry for the WINS which we couldn't insert now,
// it will take LOW_PREC.
//
break;
}
pPullCnfRecs = WinsCnfGetNextRplCnfRec(
pPullCnfRecs,
RPL_E_IN_SEQ
);
}
//
// Do init time replication if not prohibited by the config
// info.
//
if (pWinsCnf->PullInfo.InitTimeRpl)
{
/*
* Pull replicas and handle them
*/
GetReplicasNew(
pWinsCnf->PullInfo.pPullCnfRecs,
RPL_E_IN_SEQ //records are in sequence
);
}
//
// For all Push partners with which replication has to be done
// periodically, submit timer requests
//
SubmitTimerReqs(pWinsCnf->PullInfo.pPullCnfRecs);
return;
} // InitRplProcess()
VOID
Reconfig(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to reconfigure the PULL handler
Arguments:
pNewWinsCnf - New Configuration
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPullInit when it gets the CONFIGURE message
Side Effects:
Comments:
None
--*/
{
BOOL fNewInfo = FALSE;
BOOL fValidReq = FALSE;
#if PRSCONN
PRPL_CONFIG_REC_T pOldPnr, pNewPnr;
DWORD i, n;
#endif
DBGENTER("Reconfig (PULL)\n");
//
// synchronize with rpc threads and with the push thread
//
EnterCriticalSection(&WinsCnfCnfCrtSec);
try {
//
// Get the latest magic no (set by the main thread)
//
RplPullCnfMagicNo = WinsCnfCnfMagicNo;
//
// If the latest magic no is not the same as the one
// in this configuration block, we can ignore this
// configuration request
//
if (WinsCnfCnfMagicNo == pWinsCnf->MagicNo)
{
fValidReq = TRUE;
DBGPRINT1(RPLPULL, "Reconfig: Magic No (%d) match\n", WinsCnfCnfMagicNo);
//
// Initialize the Push records if required
//
// Note: NBT threads look at Push config
// records after doing registrations. Therefore
// we should enter the critical section before
// changing WinsCnf
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
try {
if (WinsCnf.PushInfo.pPushCnfRecs != NULL)
{
#if PRSCONN
//
// Copy the statistics info
//
pOldPnr = WinsCnf.PushInfo.pPushCnfRecs;
for (i = 0; i < WinsCnf.PushInfo.NoOfPullPnrs; i++)
{
pNewPnr = pWinsCnf->PushInfo.pPushCnfRecs;
for (n=0; n < pWinsCnf->PushInfo.NoOfPullPnrs; n++)
{
if (pNewPnr->WinsAdd.Add.IPAdd == pOldPnr->WinsAdd.Add.IPAdd)
{
pNewPnr->LastCommFailTime = pOldPnr->LastCommFailTime;
pNewPnr->LastCommTime = pOldPnr->LastCommFailTime;
//
// If the partner stays persistent, init the dlg
// hdl.
//
if (pNewPnr->fPrsConn && (pNewPnr->fPrsConn == pOldPnr->fPrsConn))
{
pNewPnr->PrsDlgHdl = pOldPnr->PrsDlgHdl;
}
else
{
//
// The partner was persistent but is no
// longer so. Terminate the dlg
//
if (pOldPnr->fPrsConn)
{
ECommEndDlg(&pOldPnr->PrsDlgHdl);
}
}
break;
}
pNewPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pNewPnr + RPL_CONFIG_REC_SIZE);
}
pOldPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pOldPnr + RPL_CONFIG_REC_SIZE);
}
#endif
WinsMscDealloc(WinsCnf.PushInfo.pPushCnfRecs);
}
WinsCnf.PushInfo = pWinsCnf->PushInfo;
//
// Initialize the push records
//
if (pWinsCnf->PushInfo.pPushCnfRecs != NULL)
{
PERF("Do the following along with the stuff under PRSCONN")
RPLPUSH_INIT_PUSH_RECS_M(&WinsCnf);
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("Reconfig (PULL thread)");
//
// Log a message
//
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR);
}
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
//
// We need to first get rid of all timer requests that
// we made based on the previous configuration
//
if (WinsCnf.PullInfo.pPullCnfRecs != NULL)
{
#if !PRSCONN
PRPL_CONFIG_REC_T pOldPnr, pNewPnr;
DWORD i, n;
#endif
fNewInfo = TRUE;
//
// Cancel (and deallocate) all requests that we might have
// submitted
//
WinsTmmDeleteReqs(WINS_E_RPLPULL);
//
// Copy the statistics info
//
pOldPnr = WinsCnf.PullInfo.pPullCnfRecs;
for (i = 0; i < WinsCnf.PullInfo.NoOfPushPnrs; i++)
{
pNewPnr = pWinsCnf->PullInfo.pPullCnfRecs;
for (n=0; n < pWinsCnf->PullInfo.NoOfPushPnrs; n++)
{
if (pNewPnr->WinsAdd.Add.IPAdd == pOldPnr->WinsAdd.Add.IPAdd)
{
pNewPnr->NoOfRpls = pOldPnr->NoOfRpls;
pNewPnr->NoOfCommFails = pOldPnr->NoOfCommFails;
#if PRSCONN
pNewPnr->LastCommFailTime = pOldPnr->LastCommFailTime;
pNewPnr->LastCommTime = pOldPnr->LastCommFailTime;
//
// If the partner stays persistent, init the dlg
// hdl.
//
if (pNewPnr->fPrsConn && (pNewPnr->fPrsConn == pOldPnr->fPrsConn))
{
pNewPnr->PrsDlgHdl = pOldPnr->PrsDlgHdl;
}
else
{
//
// The partner was persistent but is no
// longer so. Terminate the dlg
//
if (pOldPnr->fPrsConn)
{
ECommEndDlg(&pOldPnr->PrsDlgHdl);
}
}
#endif
break;
}
pNewPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pNewPnr + RPL_CONFIG_REC_SIZE);
}
pOldPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pOldPnr + RPL_CONFIG_REC_SIZE);
}
//
// Deallocate the memory holding the pull configuration blocks
//
//
WinsMscDealloc(WinsCnf.PullInfo.pPullCnfRecs);
}
//
// Initialize with the new information
//
WinsCnf.PullInfo = pWinsCnf->PullInfo;
}
#ifdef WINSDBG
else
{
DBGPRINT2(RPLPULL, "Reconfig: Magic Nos different. WinsCnfCnfMagicNo=(%d), pWinsCnf->MagicNo = (%d)\n", WinsCnfCnfMagicNo, pWinsCnf->MagicNo);
}
#endif
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("Reconfig: Pull Thread");
}
//
// synchronize with rpc threads doing WinsStatus/WinsTrigger
//
LeaveCriticalSection(&WinsCnfCnfCrtSec);
if (fValidReq)
{
if (WinsCnf.pPersonaList != NULL)
{
WinsMscDealloc(WinsCnf.pPersonaList);
}
WinsCnf.fPersonaGrata = pWinsCnf->fPersonaGrata;
WinsCnf.NoOfPersona = pWinsCnf->NoOfPersona;
WinsCnf.pPersonaList = pWinsCnf->pPersonaList;
//
// Start the replication process if there are PULL records
// in the new configuration
//
if (WinsCnf.PullInfo.pPullCnfRecs != NULL)
{
InitRplProcess(&WinsCnf);
}
}
//
// Deallocate the new config structure
//
WinsCnfDeallocCnfMem(pWinsCnf);
DBGLEAVE("Reconfig (PULL)\n");
return;
} // Reconfig()
VOID
AddressChangeNotification(
PWINSCNF_CNF_T pWinsCnf
)
/*++
Routine Description:
This function is called to handle address change of the local
machine.
Arguments:
pNewWinsCnf - New Configuration
Externals Used:
None
Return Value:
None
Error Handling:
Side Effects:
Comments:
None
--*/
{
DBGENTER("AddressChangeNotification\n");
//
// if our address has changed, the following routine
// will reinitialize the owner address table with own address
//
InitOwnAddTbl();
DBGLEAVE("AddressChangeNotification\n");
return;
} // AddressChangeNotification()
VOID
PullSpecifiedRange(
PCOMM_HDL_T pDlgHdl,
PWINSINTF_PULL_RANGE_INFO_T pPullRangeInfo,
BOOL fAdjustMin,
DWORD RplType
)
/*++
Routine Description:
This function is called to pull a specified range of records from
a remote WINS server
Arguments:
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
PUSHPNR_DATA_T PushPnrData[1];
DWORD NoOfPushPnrs = 1;
DWORD OwnerId;
BOOL fEnterCrtSec = FALSE;
PRPL_CONFIG_REC_T pPnr = pPullRangeInfo->pPnr;
COMM_ADD_T OwnAdd;
BOOL fAllocNew = TRUE;
PPUSHPNR_DATA_T pPushPnrData = PushPnrData;
//
// Establish communications with the Push Pnr
//
// When this function returns, the 'NoOfPushPnrs' entries of
// PushPnrData array will be initialized.
//
if (pDlgHdl == NULL)
{
EstablishComm(
pPnr,
FALSE,
&pPushPnrData,
RPL_E_NO_TRAVERSAL,
&NoOfPushPnrs
);
}
else
{
PushPnrData[0].DlgHdl = *pDlgHdl;
}
try {
//
// if communication could be established above, NoOfPushPnrs will
// be 1
//
if (NoOfPushPnrs == 1)
{
//
// Get owner id. of WINS whose entries are to be pulled
//
OwnAdd.AddTyp_e = pPullRangeInfo->OwnAdd.Type;
OwnAdd.AddLen = pPullRangeInfo->OwnAdd.Len;
OwnAdd.Add.IPAdd = pPullRangeInfo->OwnAdd.IPAdd;
PERF("for the case where pDlgHdl != NULL, the Owner Id is 0. See GetReplicasNew->ConductChkNew")
PERF("We could make use of that to go around the RplFindOwnerId call")
(VOID)RplFindOwnerId(
&OwnAdd,
&fAllocNew,//allocate a new entry if WINS is not found
&OwnerId,
WINSCNF_E_INITP_IF_NON_EXISTENT,
WINSCNF_LOW_PREC
);
//
// if a new entry was not allocated, it means that there are
// records for this owner in the database. We might have to
// delete some or all.
//
// If the local WINS owns the records, enter the critical section
// so that NmsNmhMyMaxVersNo is not changed by Nbt or Rpl threads
// while we are doing our work here
//
if (!fAllocNew)
{
if (OwnerId == NMSDB_LOCAL_OWNER_ID)
{
//
// See NOTE NOTE NOTE below.
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
fEnterCrtSec = TRUE;
//
// If we have not been told to adjust the min. vers. no,
// delete all records that have a version number greater
// than the minimum to be pulled
//
if (LiLtr(pPullRangeInfo->MinVersNo, NmsNmhMyMaxVersNo))
{
if (!fAdjustMin)
{
NmsDbDelDataRecs(
OwnerId,
pPullRangeInfo->MinVersNo,
pPullRangeInfo->MaxVersNo,
FALSE, //do not enter critical section
FALSE //one shot deletion
);
}
else
{
pPullRangeInfo->MinVersNo = NmsNmhMyMaxVersNo;
}
}
}
else//records to be pulled are owned by some other WINS server
{
if (LiLeq(pPullRangeInfo->MinVersNo,
(pRplPullOwnerVersNo+OwnerId)->VersNo))
{
NmsDbDelDataRecs(
OwnerId,
pPullRangeInfo->MinVersNo,
pPullRangeInfo->MaxVersNo,
TRUE, //enter critical section
FALSE //one shot deletion
);
}
}
}
//
// Pull Entries.
//
// NOTE NOTE NOTE
//
// RplPullPullEntries will update NmsNmhMyMaxVersNo counter if
// we pull our own records with the highest version number being
// pulled being > NmsNmhMyMaxVersNo. For the above case,
// RplPullPullEntries assumes that we are inside the
// NmsNmhNamRegCrtSec critical section.
//
if (LiGeq(pPullRangeInfo->MaxVersNo, pPullRangeInfo->MinVersNo))
{
RplPullPullEntries(
&PushPnrData[0].DlgHdl,
OwnerId, //owner id
pPullRangeInfo->MaxVersNo, //Max vers. no to be pulled
pPullRangeInfo->MinVersNo, //Min vers. no to be pulled
WINS_E_RPLPULL,
NULL,
FALSE, //don't update RplOwnAddTblVersNo counters
//unless pulled version number is > what
//we currently have.
RplType
);
}
} // end of if (NoOfPushPnrs == 1)
}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "PullSpecifiedRange: Got exception %x", ExcCode);
WINSEVT_LOG_M(ExcCode, WINS_EVT_PULL_RANGE_EXC);
}
if (fEnterCrtSec)
{
//
// The following assumes that we enter the critical section
// in this function only when pulling our own records. This
// is true currently.
// If the min. vers. no. specified for pulling is <
// the Min. for scavenging, adjust the min. for scavenging.
// Note: We may not have pulled this minimum but we adjust
// the min. for scavenging regardless. This is to save
// the overhead that would exist if we were to adopt the
// approach of having RplPullPullEntries do the same (we
// would need to pass an arg. to it; Note: This function
// will be used in rare situations by an admin.
//
// We need to synchronize with the Scavenger thread.
//
if (LiGtr(NmsScvMinScvVersNo, pPullRangeInfo->MinVersNo))
{
NmsScvMinScvVersNo = pPullRangeInfo->MinVersNo;
}
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
}
if (pPnr->fTemp)
{
WinsMscDealloc(pPullRangeInfo->pPnr);
}
if (pDlgHdl == NULL)
{
#if PRSCONN
if (!PushPnrData[0].fPrsConn)
{
//
// End the dialogue
//
ECommEndDlg(&PushPnrData[0].DlgHdl);
}
#else
ECommEndDlg(&PushPnrData[0].DlgHdl);
#endif
}
return;
} //PullSpecifiedRange()
STATUS
RplPullRegRepl(
LPBYTE pName,
DWORD NameLen,
DWORD Flag,
DWORD OwnerId,
VERS_NO_T VersNo,
DWORD NoOfAdds,
PCOMM_ADD_T pNodeAdd,
PCOMM_ADD_T pOwnerWinsAdd,
DWORD RplType
)
/*++
Routine Description:
This function is called to register a replica.
Arguments:
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Side Effects:
Comments:
It is called by RplPullPullEntries and by ChkConfNUpd in nmsscv.c
--*/
{
STATUS RetStat;
try {
//
// If this is a unique replica, call NmsNmhReplRegInd
//
if (NMSDB_ENTRY_TYPE_M(Flag) == NMSDB_UNIQUE_ENTRY)
{
//
// If only spec. grps and pdc name are to be replicated and
// this name is not a pdc name, skip it
//
#if 0
if ((RplType & WINSCNF_RPL_SPEC_GRPS_N_PDC)
&& (!NMSDB_IS_IT_PDC_NM_M(pName)))
{
DBGPRINT1(RPLPULL, "RplPullRegRepl: Ignoring unique record - name = (%s)\n", pName);
return(WINS_SUCCESS);
}
#endif
RetStat = NmsNmhReplRegInd(
pName,
NameLen,
pNodeAdd,
Flag,
OwnerId,
VersNo,
pOwnerWinsAdd //add. of WINS owning the record
);
}
else // it is either a normal or a special group or a multihomed
// entry
{
#if 0
if ((RplType & WINSCNF_RPL_SPEC_GRPS_N_PDC)
&&
(!NMSDB_ENTRY_SPEC_GRP_M(NMSDB_ENTRY_TYPE_M(Flag))))
{
DBGPRINT1(RPLPULL, "RplPullRegRepl: Ignoring non-SG record - name = (%s)\n", pName);
return(WINS_SUCCESS);
}
#endif
RetStat = RegGrpRepl(
pName,
NameLen,
Flag,
OwnerId,
VersNo,
NoOfAdds,
pNodeAdd,
pOwnerWinsAdd //add. of WINS owning the record
);
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "RplPullRegRepl: Got Exception %x", ExcCode);
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_EXC);
RetStat = WINS_FAILURE;
}
if (RetStat == WINS_FAILURE)
{
WinsEvtLogDetEvt(FALSE, NMSDB_ENTRY_TYPE_M(Flag) == NMSDB_UNIQUE_ENTRY ? WINS_EVT_RPL_REG_UNIQUE_ERR : WINS_EVT_RPL_REG_GRP_MEM_ERR,
NULL, __LINE__, "sddd", pName,
pOwnerWinsAdd->Add.IPAdd,
VersNo.LowPart, VersNo.HighPart);
WINSEVT_LOG_M(pNodeAdd->Add.IPAdd, WINS_EVT_RPL_REG_ERR);
//
// If WINS has been directed to continue replication on error,
// change RetStat to fool the caller into thinking that
// the replica registration was successful.
//
if (!WinsCnf.fNoRplOnErr)
{
RetStat = WINS_SUCCESS;
}
}
return(RetStat);
} // RplPullRegRepl()
VOID
DeleteWins(
PCOMM_ADD_T pWinsAdd
)
/*++
Routine Description:
This function deletes all records belonging to a WINS. It
also removes the entry of the WINS from the Owner-Add database
table. It marks the entry as deleted in the in-memory table so
that it can be reused if need be.
Arguments:
pWinsAdd - Address of WINS whose entry is to be removed
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
BOOL fAllocNew = FALSE;
DWORD OwnerId;
STATUS RetStat;
DWORD fEnterCrtSec = FALSE;
DWORD ExcCode = WINS_SUCCESS;
//
// Find the owner id of the WINS. If the WINS is not in the table
// return
//
RetStat = RplFindOwnerId(
pWinsAdd,
&fAllocNew,
&OwnerId,
WINSCNF_E_IGNORE_PREC,
WINSCNF_LOW_PREC
);
if (RetStat == WINS_SUCCESS)
{
if (OwnerId == NMSDB_LOCAL_OWNER_ID)
{
//
// We always keep the entry for the local WINS.
//
DBGPRINT0(ERR, "DeleteWins: Sorry, you can not delete the local WINS\n");
//WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_DELETE_LOCAL_WINS_DISALLOWED);
}
else
{
VERS_NO_T MinVersNo;
VERS_NO_T MaxVersNo;
WINSEVT_STRS_T EvtStrs;
WCHAR String[WINS_MAX_NAME_SZ];
struct in_addr InAddr;
InAddr.s_addr = htonl(pWinsAdd->Add.IPAdd);
(VOID)WinsMscConvertAsciiStringToUnicode(
inet_ntoa( InAddr),
(LPBYTE)String,
WINS_MAX_NAME_SZ);
EvtStrs.NoOfStrs = 1;
EvtStrs.pStr[0] = String;
WINSEVT_LOG_INFO_STR_D_M(WINS_EVT_DEL_OWNER_STARTED, &EvtStrs);
WINS_ASSIGN_INT_TO_VERS_NO_M(MinVersNo, 0);
WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
//
// Need to synchronize with NBT threads or rpc threads that
// might be modifying these records. NmsDelDataRecs will
// enter the critical section
//
#if 0
EnterCriticalSection(&NmsNmhNamRegCrtSec);
#endif
try {
//
// Delete all records
//
RetStat = NmsDbDelDataRecs(
OwnerId,
MinVersNo,
MaxVersNo,
TRUE, //enter critical section
TRUE //fragmented deletion
);
//
// If all records were deleted, mark entry as deleted.
//
if (RetStat == WINS_SUCCESS)
{
EnterCriticalSection(&RplVersNoStoreCrtSec);
WINS_ASSIGN_INT_TO_LI_M((pRplPullOwnerVersNo+OwnerId)->VersNo, 0);
LeaveCriticalSection(&RplVersNoStoreCrtSec);
//
// Delete the entry for the WINS from the db table
// and mark WINS as deleted in the in-memory table.
//
// This way, we will free up entries in the table.
//
EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
fEnterCrtSec = TRUE;
(pNmsDbOwnAddTbl+OwnerId)->WinsState_e = NMSDB_E_WINS_DELETED;
//
// Delete entry from the owner-Add table
//
NmsDbWriteOwnAddTbl(
NMSDB_E_DELETE_REC,
OwnerId,
NULL,
NMSDB_E_WINS_DELETED,
NULL,
NULL
);
}
else
{
DBGPRINT2(ERR, "DeleteWins: Could not delete one or more records of WINS with owner Id = (%d) and address = (%x)\n", OwnerId,
pWinsAdd->Add.IPAdd);
}
} //end of try
except(EXCEPTION_EXECUTE_HANDLER) {
ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "DeleteWins: Got Exception (%x)\n", ExcCode);
RetStat = WINS_FAILURE;
} // end of exception handler
if (fEnterCrtSec)
{
LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
}
if (RetStat == WINS_FAILURE)
{
//
// There is no danger of pWinsAdd being NULL. See WinsDeleteWins
//
WinsEvtLogDetEvt(FALSE, WINS_EVT_COULD_NOT_DELETE_WINS_RECS,
NULL, __LINE__, "dd", pWinsAdd->Add.IPAdd,
ExcCode );
//
// Since we are leaving the database in an inconsistent state,
// mark the WINS as inconsistent
//
(pNmsDbOwnAddTbl+OwnerId)->WinsState_e = NMSDB_E_WINS_INCONSISTENT;
} else {
WINSEVT_LOG_INFO_STR_D_M(WINS_EVT_DEL_OWNER_COMPLETED, &EvtStrs);
}
} // end of else
} // end of if (WINS is in own-add table)
//
// deallocate the buffer
//
WinsMscDealloc(pWinsAdd);
return;
}
BOOL
AcceptPersona(
PCOMM_ADD_T pWinsAdd
)
/*++
Routine Description:
Accept a persona in either of the two situations:
- PersonaType setting points to 'Persona Grata list', the list exists and
the address is in the list.
- PersonaType setting points to 'Persona Non-Grata list' and either the list
doesn't exist or the address is not there.
Side effects:
- If none of the two settings is defined (PersonaType & PersonaList)
this is like a non-existant 'Persona Non-Grata list' which means all WINS
will be accepted.
- If only PersonaType exists and it says 'Persona Grata list' this is like
a non-existant Persona Grata list hence no WINS will be accepted!
Arguments:
pWinsAdd - address of the WINS to check
Return Value:
TRUE if the WINS pWinsAdd is a persona grata/non-grata (depending on fGrata),
FALSE otherwise
Called by:
FilterPersona()
--*/
{
PRPL_ADD_VERS_NO_T pPersona = NULL;
DBGPRINT1(RPLPULL, "AcceptPersona check for address=(%x)\n", pWinsAdd->Add.IPAdd);
// if the list exists, look for the address in it
if (WinsCnf.pPersonaList != NULL)
pPersona = bsearch(
pWinsAdd,
WinsCnf.pPersonaList,
(size_t)WinsCnf.NoOfPersona,
sizeof(COMM_ADD_T),
ECommCompareAdd);;
if (WinsCnf.fPersonaGrata)
// if the list is 'persona grata', the address has to be there in order to
// be accepted.
return (pPersona != NULL);
else
// otherwise, WINS is accepted if either the list doesn't exist or the address
// is not there
return (pPersona == NULL);
}
VOID
FilterPersona(
PPUSHPNR_DATA_T pPushData
)
/*++
Routine Description:
Filters out from the PUSHPNR_DATA_T structure those OwnerAddress<->VersionNo mappings
that are denied by persona grata/non-grata list. This routine adjustes from that structure
only the NoOfMaps field and moves around elements in the array pointed by pAddVers
(bubbling up the ones that are accepted).
Arguments:
pPushData - pointer to the PUSHPNR_DATA_T providing the mapping table
Called by:
HdlPushNtf
--*/
{
DWORD i, newNoOfMaps;
PRPL_ADD_VERS_NO_T pAddVers = pPushData->pAddVers;
// in most common case, none of 'PersonaType' or 'PersonaList' is defined. This means
// we deny no WINS so we don't need to filter anything - then get out right away.
if (!WinsCnf.fPersonaGrata && WinsCnf.pPersonaList == NULL)
return;
for (i = 0, newNoOfMaps = 0; i < pPushData->NoOfMaps; i++)
{
if (AcceptPersona(&(pAddVers[i].OwnerWinsAdd)))
{
// if the decision is to accept this WINS, move it to the top of the list
// over the ones that were rejected. If none was rejected yet, no memory
// operation is performed.
if (newNoOfMaps < i)
{
memcpy(&pAddVers[newNoOfMaps], &pAddVers[i], sizeof(RPL_ADD_VERS_NO_T));
}
// since this wins was accepted, increment the counter of accepted wins.
newNoOfMaps++;
}
}
// only the first newNoOfMaps have to be considered from now on
pPushData->NoOfMaps = newNoOfMaps;
// just in case no WINS was accepted, cleanup the pAddVers array
if (pPushData->NoOfMaps == 0 && pPushData->pAddVers != NULL)
{
WinsMscDealloc(pPushData->pAddVers);
pPushData->pAddVers = NULL;
}
}
VOID
RplPullAllocVersNoArray(
PRPL_VERS_NOS_T *ppRplOwnerVersNo,
DWORD CurrentNo
)
{
if (*ppRplOwnerVersNo != NULL)
{
DWORD MemSize = sizeof(RPL_VERS_NOS_T) * (CurrentNo + 100);
WINSMSC_REALLOC_M( MemSize, (LPVOID *)ppRplOwnerVersNo );
}
else
{
DWORD MemSize = sizeof(RPL_VERS_NOS_T) * (CurrentNo + 100);
WinsMscAlloc(
MemSize,
(LPVOID *)ppRplOwnerVersNo
);
}
return;
}