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

1394 lines
42 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
rplpush.c
Abstract:
This module contains functions of the PUSH handler component
of the Replicator.
These functions handle the pull requests from a Pull Partner
Functions:
RplPushInit
ExecuteWrkItm
HandleAddVersMapReq
HandleSndEntriesReq
HandleUpdNtf
HandleUpdVersNoReq
Portability:
This module is portable
Author:
Pradeep Bahl (PradeepB) Jan-1993
Revision History:
Modification date Person Description of modification
----------------- ------- ----------------------------
--*/
/*
* Includes
*/
#include "wins.h"
#include "nmsnmh.h"
#include "nms.h"
#include "rpl.h"
#include "rplmsgf.h"
#include "rplpush.h"
#include "rplpull.h"
#include "winsevt.h"
#include "winsque.h"
#include "nmsdb.h"
#include "winsmsc.h"
#include "winscnf.h"
#include "comm.h"
/*
* Local Macro Declarations
*/
//
// The amount of time the push thread will wait after its last activity
// before exiting. This is kept to be 5 mts for now.
//
// It is a good idea to keep it less than the Min. Replication time
// interval
//
#define WAIT_TIME_BEFORE_EXITING (300000)
/*
* Local Typedef Declarations
*/
/*
* Global Variable Definitions
*/
HANDLE RplPushCnfEvtHdl;
BOOL fRplPushThdExists = FALSE;
/*
* Local Variable Definitions
*/
/*
* Local Function Prototype Declarations
*/
STATIC
STATUS
HandleAddVersMapReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
STATUS
HandleSndEntriesReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
HandleUpdNtf(
#if PRSCONN
BOOL fPrsConn,
#endif
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
HandleUpdVersNoReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
STATIC
VOID
ExecuteWrkItm(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
);
/* prototypes for functions local to this module go here */
STATUS
RplPushInit(
LPVOID pParam
)
/*++
Routine Description:
This function is the start function of the Push Thread.
The function blocks on an auto-reset event variable until signalled
When signalled it
dequeues a work item from from its work queue and executes it
Arguments:
pParam
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInit
Side Effects:
Comments:
None
--*/
{
HANDLE ThdEvtArr[2];
PQUE_RPL_REQ_WRK_ITM_T pWrkItm;
DWORD ArrInd;
DWORD RetVal;
BOOL fSignaled;
UNREFERENCED_PARAMETER(pParam);
try {
//
// Initialize the thd
//
NmsDbThdInit(WINS_E_RPLPUSH);
DBGMYNAME("Replicator Push Thread\n");
//
// We do this at each thread creation to save on STATIC storage. This
// way when the thread is not there we don't consume resources.
//
ThdEvtArr[0] = NmsTermEvt;
ThdEvtArr[1] = QueRplPushQueHd.EvtHdl;
while(TRUE)
{
try {
/*
* Block until signaled or until timer expiry
*/
WinsMscWaitTimedUntilSignaled(
ThdEvtArr,
2,
&ArrInd,
WAIT_TIME_BEFORE_EXITING,
&fSignaled
);
//
// If the wait was interrupted due to a termination signal or
// if the wait timed out, exit the thread.
//
if (!fSignaled || (ArrInd == 0))
{
//
// if the thread has timed out, we need to exit it. Before
// we do that, we check whether some thread sneaked in
// a message after the timeout
//
if (!fSignaled)
{
PQUE_HD_T pQueHd = pWinsQueQueHd[QUE_E_RPLPUSH];
//
// QueGetWrkItm also enters the Push thread's critical
// section. I don't want to write a separate function
// or overload the QueGetWrkItem function to avoid
// the double entry into the critical section.
//
EnterCriticalSection(&pQueHd->CrtSec);
RetVal = QueGetWrkItm(
QUE_E_RPLPUSH,
(LPVOID)&pWrkItm
);
//
// if we got a request execute it.
//
if (RetVal != WINS_NO_REQ)
{
LeaveCriticalSection(&pQueHd->CrtSec);
NmsDbOpenTables(WINS_E_RPLPUSH);
ExecuteWrkItm(pWrkItm);
NmsDbCloseTables();
}
else
{
//
// set the flag to FALSE so that if a message
// comes for this Push thread, it is created.
//
fRplPushThdExists = FALSE;
WinsThdPool.ThdCount--;
WinsThdPool.RplThds[WINSTHD_RPL_PUSH_INDEX].
fTaken = FALSE;
//
// Be sure to close the handle, otherwise
// the thread object will stay.
//
CloseHandle(
WinsThdPool.RplThds[WINSTHD_RPL_PUSH_INDEX].
ThdHdl
);
LeaveCriticalSection(&pQueHd->CrtSec);
WinsMscTermThd(WINS_SUCCESS,
WINS_DB_SESSION_EXISTS);
}
}
else //signaled for termination by the main thread
{
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_RPLPUSH,
(LPVOID)&pWrkItm
);
if (RetVal == WINS_NO_REQ)
{
break;
}
NmsDbOpenTables(WINS_E_RPLPUSH);
ExecuteWrkItm(pWrkItm);
NmsDbCloseTables();
//
// Check for termination here since WINS could be under
// stress with a large number of messages in the queue.
// We don't want to delay the stop.
//
WinsMscChkTermEvt(
#ifdef WINSDBG
WINS_E_RPLPUSH,
#endif
FALSE
);
}
} // end of try
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("Replicator Push thread");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_EXC);
}
} // end of while
} // end of try
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("Replicator Push thread");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_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);
}
//
// We should never get here.
//
return(WINS_FAILURE);
}
VOID
ExecuteWrkItm(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
The function executes a work item. The work item can either be
a push notification request from within this WINS (from an NBT thread)
or a replication request (from a remote WINS)
Arguments:
pWrkItm - ptr to a work item
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPushInit
Side Effects:
Comments:
None
--*/
{
RPLMSGF_MSG_OPCODE_E PullReqType_e;
#if PRSCONN
BOOL fPrsConn = FALSE;
#endif
BOOL fPushNtf = FALSE;
//
// get the opcode
//
RplMsgfUfmPullPnrReq(
pWrkItm->pMsg,
pWrkItm->MsgLen,
&PullReqType_e
);
switch(PullReqType_e)
{
case(RPLMSGF_E_ADDVERSNO_MAP_REQ):
HandleAddVersMapReq(pWrkItm);
#ifdef WINSDBG
NmsCtrs.RplPushCtrs.NoAddVersReq++;
#endif
break;
case(RPLMSGF_E_SNDENTRIES_REQ):
HandleSndEntriesReq(pWrkItm);
#ifdef WINSDBG
NmsCtrs.RplPushCtrs.NoSndEntReq++;
#endif
break;
#if PRSCONN
case(RPLMSGF_E_UPDATE_NTF_PRS):
case(RPLMSGF_E_UPDATE_NTF_PROP_PRS):
fPrsConn = TRUE;
#endif
case(RPLMSGF_E_UPDATE_NTF):
case(RPLMSGF_E_UPDATE_NTF_PROP):
fPushNtf = TRUE;
#if PRSCONN
HandleUpdNtf(fPrsConn, pWrkItm);
#else
HandleUpdNtf(pWrkItm);
#endif
#ifdef WINSDBG
NmsCtrs.RplPushCtrs.NoUpdNtfReq++;
#endif
break;
case(RPLMSGF_E_UPDVERSNO_REQ):
#ifdef WINSDBG
NmsCtrs.RplPushCtrs.NoUpdVersReq++;
#endif
HandleUpdVersNoReq(pWrkItm);
break;
default:
#ifdef WINSDBG
NmsCtrs.RplPushCtrs.NoInvReq++;
#endif
DBGPRINT1(ERR, "RplPush: ExecuteWrkItm: Invalid Opcode (%d)\n",
PullReqType_e);
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
break;
}
//
// If the message is not an update notification,
// Free the message buffer. For an update
// notification, the message is handed to
// the PULL thread to handle. Therefore, we should not free it
// The work items needs to be freed always since we always allocate
// a new work item when queuing a request.
//
if ( !fPushNtf)
{
ECommFreeBuff(pWrkItm->pMsg - COMM_HEADER_SIZE);
}
//
// Deallocate the work item
//
QueDeallocWrkItm( RplWrkItmHeapHdl, pWrkItm );
return;
}
STATUS
HandleAddVersMapReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function handles a "send address - version # " request
Arguments:
pWrkItm - Work item that carries the request and associated info
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
LPBYTE pRspBuff;
DWORD RspMsgLen;
PRPL_ADD_VERS_NO_T pPullAddNVersNo;
DWORD i = 0;
DWORD MaxNoOfOwners;
PRPL_CONFIG_REC_T pPnr;
COMM_ADD_T WinsAdd;
BOOL fRplPnr = FALSE;
BOOL fExc = FALSE;
struct in_addr InAddr;
PCOMM_ADD_T pWinsAdd;
PNMSDB_WINS_STATE_E pWinsState_e;
DWORD SizeOfBuff;
BOOL fRspBuffAlloc = FALSE;
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DBGENTER("HandleAddVersMapReq\n");
//
// We need to handle this request only if
// either the WINS that sent this message is one of our
// pull pnrs or if the fRplOnlyWCnfPnrs in the registry is FALSE
//
EnterCriticalSection(&WinsCnfCnfCrtSec);
try {
if (WinsCnf.fRplOnlyWCnfPnrs)
{
if ((pPnr = WinsCnf.PushInfo.pPushCnfRecs) != NULL)
{
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
//
// Search for the Cnf record for the WINS we want to
// send the PUSH notification to/Replicate with.
//
for (
;
(pPnr->WinsAdd.Add.IPAdd != INADDR_NONE)
&&
!fRplPnr;
// no third expression
)
{
//
// Check if this is the one we want
//
if (pPnr->WinsAdd.Add.IPAdd == WinsAdd.Add.IPAdd)
{
//
// We are done. Set the fRplPnr flag to TRUE so that
// we break out of the loop.
//
// Note: Don't use break since that would cause
// a search for a 'finally' block
//
fRplPnr = TRUE;
continue; //so that we break out of the loop
}
//
// Get the next record that follows this one sequentially
//
pPnr = WinsCnfGetNextRplCnfRec(
pPnr,
RPL_E_IN_SEQ //seq. traversal
);
}
}
}
else
{
fRplPnr = TRUE;
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleAddVersMapReq");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_EXC_PULL_TRIG_PROC);
fExc = TRUE;
}
LeaveCriticalSection(&WinsCnfCnfCrtSec);
try {
if (fRplPnr)
{
VERS_NO_T MinOwnVersNo;
BOOL fOwnInited = FALSE;
DWORD TotNoOfOwners;
MaxNoOfOwners = 0;
WINS_ASSIGN_INT_TO_LI_M(MinOwnVersNo, 1);
DBGPRINT1(TMP, "HandleAddVersMap: WINS (%x) made an AddVersMap request\n", WinsAdd.Add.IPAdd);
EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
TotNoOfOwners = NmsDbNoOfOwners;
LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
WinsMscAlloc(sizeof(RPL_ADD_VERS_NO_T) * TotNoOfOwners, &pPullAddNVersNo);
//
// If version counter value > 1, we will send it
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
if (LiGtr(NmsNmhMyMaxVersNo, MinOwnVersNo))
{
/*
* Get the max. version no for entries owned by self
*
* 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.
*/
NMSNMH_DEC_VERS_NO_M(
NmsNmhMyMaxVersNo,
pPullAddNVersNo->VersNo
);
pPullAddNVersNo->OwnerWinsAdd = NmsLocalAdd;
pPullAddNVersNo->StartVersNo = NmsDbStartVersNo;
MaxNoOfOwners++;
fOwnInited = TRUE;
}
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
//
// BUG 26196
// Note: These critical sections are taken in the order given below
// by the RPC thread executing GetConfig
//
EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
EnterCriticalSection(&RplVersNoStoreCrtSec);
try {
for (i = 1; i < TotNoOfOwners; i++)
{
//
// If the highest version number for an owner as identified
// by the RplPullOwnerVersNo table is zero, there is no
// need to send the mapping of this owner. The reason
// we may have a such an entry in our in-memory table is
// because 1)All records of the owner got deleted. Local
// WINS got terminated and reinvoked. On reinvocation, it
// did not find any records in the db.
// 2)Local WINS received a Pull range
// request for an owner that it did not know about.
// Since Pull Range request comes in as a
// "SndEntries" request, the Push thread has
// no way of distinguishing it from a normal
// 2 message pull request. For a 2 message
// request, "SndEntries" request will always
// have a subset of the WINS servers that
// have records in our db.
//
if (LiGtrZero((pRplPullOwnerVersNo+i)->VersNo) &&
(pNmsDbOwnAddTbl+i)->WinsState_e == NMSDB_E_WINS_ACTIVE)
{
PVERS_NO_T pStartVersNo;
(pPullAddNVersNo+MaxNoOfOwners)->VersNo = (pRplPullOwnerVersNo+i)->VersNo;
//
// Note: Since RplPullOwnerVersNo[i] is > 0, the
// State of the entry can not be deleted (see
// RplPullPullEntrie)
//
RPL_FIND_ADD_BY_OWNER_ID_M(i, pWinsAdd, pWinsState_e,
pStartVersNo);
(pPullAddNVersNo+MaxNoOfOwners)->OwnerWinsAdd = *pWinsAdd;
(pPullAddNVersNo+MaxNoOfOwners++)->StartVersNo = *pStartVersNo;
DBGPRINT3(RPLPUSH, "HandleAddVersMap:Owner Add (%x) - Vers. No (%d %d)\n", pWinsAdd->Add.IPAdd, (pRplPullOwnerVersNo+i)->VersNo.HighPart, (pRplPullOwnerVersNo+i)->VersNo.LowPart);
}
PERF("Speed it up by using pointer arithmetic")
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleAddVersMapReq");
DBGPRINT1(EXC, "HandleAddVersMapReq: Exc. while checking vers. nos of owners\n", GetExceptionCode());
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_EXC_PULL_TRIG_PROC);
}
//
// Let us initialize RplPullOwnerVersNo entry for the local WINS
//
// This is done so that if we later on pull from the remote WINS,
// we don't end up pulling our own records
//
if (fOwnInited)
{
pRplPullOwnerVersNo->VersNo = pPullAddNVersNo->VersNo;
pRplPullOwnerVersNo->StartVersNo = pPullAddNVersNo->StartVersNo;
DBGPRINT3(RPLPUSH, "HandleAddVersMap: Owner Add (%x) - Vers. No (%d %d)\n", NmsLocalAdd.Add.IPAdd, (pRplPullOwnerVersNo+i)->VersNo.HighPart, (pRplPullOwnerVersNo+i)->VersNo.LowPart);
}
LeaveCriticalSection(&RplVersNoStoreCrtSec);
LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(&pWrkItm->DlgHdl, fIsPnrBeta1Wins);
#endif
SizeOfBuff = RPLMSGF_ADDVERSMAP_RSP_SIZE_M(MaxNoOfOwners);
WinsMscAlloc(SizeOfBuff, &pRspBuff);
fRspBuffAlloc = TRUE;
/*
* format the response
*/
RplMsgfFrmAddVersMapRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
RPLMSGF_E_ADDVERSNO_MAP_RSP,
pRspBuff + COMM_N_TCP_HDR_SZ,
SizeOfBuff - COMM_N_TCP_HDR_SZ,
pPullAddNVersNo,
MaxNoOfOwners,
0,
&RspMsgLen
);
//
// Free the memory we allocated earlier
//
WinsMscDealloc(pPullAddNVersNo);
/*
* Send the response. We don't check the return code. ECommSndRsp
* may have failed due to communication failure. There is nothing
* more to be done for either the success of failure case.
*/
(VOID)ECommSndRsp(
&pWrkItm->DlgHdl,
pRspBuff + COMM_N_TCP_HDR_SZ,
RspMsgLen
);
//
// We don't end the dialogue. It will get terminated when
// the initiator terminates it.
//
}
else
{
if (!fExc)
{
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
DBGPRINT1(RPLPUSH, "HandleAddVersMapReq: Got a pull request message from a WINS to which we are not allowed to push replicas. Address of WINS is (%x)\n",
WinsAdd.Add.IPAdd
);
COMM_HOST_TO_NET_L_M(WinsAdd.Add.IPAdd,InAddr.s_addr);
WinsMscLogEvtStrs(COMM_NETFORM_TO_ASCII_M(&InAddr),
WINS_EVT_ADD_VERS_MAP_REQ_NOT_ACCEPTED,
TRUE);
}
//
// We need to end the dialogue. The work item and the message
// will get deallocated by the caller
//
//
// End the implicit dialogue
//
(VOID)ECommEndDlg(&pWrkItm->DlgHdl);
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleAddVersMapReq");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_EXC);
}
if (fRspBuffAlloc)
{
WinsMscDealloc(pRspBuff);
}
DBGLEAVE("HandleAddVersMapReq\n")
return(WINS_SUCCESS);
}
STATUS
HandleSndEntriesReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function handles the "send data entries req"
Arguments:
pWrkItm - Work item carrying info about the "Send Entries" request from
a remote WINS
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
RplPushInit()
Side Effects:
Comments:
None
--*/
{
COMM_ADD_T WinsAdd; /*address of WINS server whose records
*are being requested*/
VERS_NO_T MaxVers, MinVers; /*max. amd min. versions of
*records*/
FUTURES("use NMSDB_ROW_INFO_T structure - Maybe")
PRPL_REC_ENTRY_T pBuff;
LPBYTE pStartBuff = NULL;
DWORD RspBufLen;
DWORD NoOfRecs = 0;
DWORD i;
LPBYTE pNewPos;
LPBYTE pTxBuff;
LPBYTE pStartTxBuff;
STATUS RetStat;
PWINSTHD_TLS_T pTls;
BOOL fGetDataRecs = FALSE;
PRPL_CONFIG_REC_T pPnr;
BOOL fOnlyDynRecs = FALSE;
DWORD RplType = WINSCNF_RPL_DEFAULT_TYPE;
DWORD RplTypeFMsg;
BYTE Name[1]; //dummy to prevent RtlCopyMemory from
//barfing
COMM_ADD_T ReqWinsAdd;
#if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins;
#endif
DBGENTER("HandleSndEntriesReq\n");
GET_TLS_M(pTls);
pTls->HeapHdl = NULL;
//#ifdef WINSDBG
try {
//#endif
//
// Check if this is one of our configured partners. If yes,
// pass the value of fOnlyDynRecs to NmsDbGetDataRecs.
//
// We allow access to even those WINSs that are not partners since
// we need to let them do revalidation of replicas (except for
// this replication activity, all other from non-configured partners
// is stopped at the first step - HandleAddVersMapReq).
//
if ((pPnr = RplGetConfigRec(RPL_E_PUSH, &pWrkItm->DlgHdl, NULL)) != NULL)
{
fOnlyDynRecs = pPnr->fOnlyDynRecs;
RplType = pPnr->RplType;
}
#if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(&pWrkItm->DlgHdl, fIsPnrBeta1Wins);
#endif
/*
* Unformat the request message
*/
RplMsgfUfmSndEntriesReq(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
pWrkItm->pMsg + 4, /*past the
*opcode */
&WinsAdd,
&MaxVers,
&MinVers,
&RplTypeFMsg
);
// ASSERTMSG("Min. Vers. No is >= Max. Vers. No", LiGeq(MaxVers, MinVers));
FUTURES("Check if the request is a PULL RANGE request. If it is, honor it")
FUTURES("only if the Requesting WINS is under the PUSH key or RplOnlyWCnfPnrs")
FUTURES("is set to 0")
COMM_INIT_ADD_FR_DLG_HDL_M(&ReqWinsAdd, &pWrkItm->DlgHdl);
#ifdef WINSDBG
DBGPRINT2(TMP, "HandleSndEntriesReq: WINS (%x) made a SndEntries request for Owner = (%x) \n", ReqWinsAdd.Add.IPAdd, WinsAdd.Add.IPAdd);
DBGPRINT4(TMP, "HandleSndEntriesReq: Min Vers No (%d %d); Max Vers No = (%d %d)\n", MinVers.HighPart, MinVers.LowPart, MaxVers.HighPart, MaxVers.LowPart);
#endif
if (RplType == WINSCNF_RPL_DEFAULT_TYPE)
{
DBGPRINT2(RPLPUSH, "HandleSndEntriesReq: Pnr (%x) is requesting replication of type (%x)\n", ReqWinsAdd.Add.IPAdd, RplTypeFMsg);
// WINSEVT_LOG_INFO_M(ReqWinsAdd.Add.IPAdd, WINS_EVT_PNR_PARTIAL_RPL_TYPE);
RplType = RplTypeFMsg;
}
/*
*
* Call database manager function to get the records. No need
* to check the return status here
*/
(VOID)NmsDbGetDataRecs(
WINS_E_RPLPUSH,
THREAD_PRIORITY_NORMAL, //not looked at
MinVers,
MaxVers,
0, //not of use here
LiEqlZero(MaxVers) ? TRUE : FALSE, //if max. vers.
//no. is zero,
//we want all
//recs.
FALSE, //not looked at in this call
NULL, //must be NULL since we are not
//doing scavenging of clutter
&WinsAdd,
fOnlyDynRecs,
RplType,
(LPVOID *)&pStartBuff,
&RspBufLen,
&NoOfRecs
);
fGetDataRecs = TRUE;
//
// Allocate a buffer for transmitting the records. Even if the
// above function failed, we still should have received a buffer
// from it (pStartBuff). Note: RspBufLen contains the size of memory
// required for a flattened stream of records.
//
pStartTxBuff = WinsMscHeapAlloc(pTls->HeapHdl, RspBufLen);
pTxBuff = pStartTxBuff + COMM_N_TCP_HDR_SZ;
pBuff = (PRPL_REC_ENTRY_T)pStartBuff;
DBGPRINT4(RPLPUSH, "Formatting 1st record for sending --name (%s)\nfGrp (%d)\nVersNo (%d %d)\n", pBuff->pName/*pBuff->Name*/,
pBuff->fGrp,
pBuff->VersNo.HighPart,
pBuff->VersNo.LowPart
);
/*
* format the response
*
* Note: It is quite possible that NmsDbGetDataRecs retrieved 0
* records. Even if it did, we are still assured of getting
* a buffer of the RPL_CONFIG_REC_SIZE size. Since at the
* time of allocation, memory is 'zero'ed by default, we
* won't run into any problems in the following function
* call. Check out this function to reassure yourself.
*
* Like mentioned in NmsDbGetDataRecs, the following call
* will serve to format a valid response to the remote WINS
*/
RplMsgfFrmSndEntriesRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
pTxBuff,
NoOfRecs,
NOTE("expedient HACK - for now. Later on modify FrmSndEntriesRsp ")
NoOfRecs ? pBuff->pName : Name,
pBuff->NameLen,
pBuff->fGrp,
pBuff->NoOfAdds,
pBuff->NodeAdd,
pBuff->Flag,
pBuff->VersNo,
TRUE, /*First time*/
&pNewPos
);
PERF("Change RplFrmSndEntriesRsp so that it does the looping itself")
for (i = 1; i < NoOfRecs; i++)
{
pBuff = (PRPL_REC_ENTRY_T)((LPBYTE)pBuff + RPL_REC_ENTRY_SIZE);
// DBGPRINT4(RPLPUSH, "Formatting record for sending --name (%s)\nfGrp (%d)\nVersNo (%d %d)\n", pBuff->pName/*pBuff->Name*/, pBuff->fGrp, pBuff->VersNo.HighPart, pBuff->VersNo.LowPart);
/*
* Format the response
*/
RplMsgfFrmSndEntriesRsp(
#if SUPPORT612WINS > 0
fIsPnrBeta1Wins,
#endif
pNewPos,
NoOfRecs, //not used by func
pBuff->pName,
pBuff->NameLen,
pBuff->fGrp,
pBuff->NoOfAdds,
pBuff->NodeAdd,
pBuff->Flag,
pBuff->VersNo,
FALSE, /*Not First time*/
&pNewPos
);
}
RspBufLen = (ULONG) (pNewPos - pTxBuff);
/*
* Call ECommSndRsp to send the response.
*/
RetStat = ECommSndRsp(
&pWrkItm->DlgHdl,
pTxBuff,
RspBufLen
);
#ifdef WINSDBG
{
// COMM_IP_ADD_T IPAdd;
struct in_addr InAdd;
// COMM_GET_IPADD_M(&pWrkItm->DlgHdl, &IPAdd);
InAdd.s_addr = htonl(ReqWinsAdd.Add.IPAdd);
if (RetStat != WINS_SUCCESS)
{
DBGPRINT2(RPLPUSH, "HandleSndEntriesReq: ERROR: Could not send (%d) records to WINS with address = (%s)\n",
NoOfRecs,
inet_ntoa(InAdd)
);
}
else
{
DBGPRINT2(RPLPUSH, "HandleSndEntriesReq: Sent (%d) records to WINS with address = (%s)\n",
NoOfRecs,
inet_ntoa(InAdd)
);
}
}
#endif
//#ifdef WINSDBG
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleSndEntriesReq");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_EXC);
} //end of exception handler
//#endif
if (fGetDataRecs)
{
//
// Free the buffer, allocated by NmsDbGetDataRecs and the Tx Buff
//
// The work item and the message it holds are freed by the caller
//
pBuff = (PRPL_REC_ENTRY_T)pStartBuff;
for (i=0; i<NoOfRecs; i++)
{
DWORD EntType;
if (pBuff->pName != NULL)
{
WinsMscHeapFree(pTls->HeapHdl, pBuff->pName);
}
EntType = NMSDB_ENTRY_TYPE_M(pBuff->Flag);
if (((EntType == NMSDB_SPEC_GRP_ENTRY) || (EntType == NMSDB_MULTIHOMED_ENTRY)) && (pBuff->pNodeAdd != NULL))
{
WinsMscHeapFree(pTls->HeapHdl, pBuff->pNodeAdd);
}
pBuff = (PRPL_REC_ENTRY_T)((LPBYTE)pBuff + RPL_REC_ENTRY_SIZE);
}
WinsMscHeapFree(pTls->HeapHdl, pStartBuff);
WinsMscHeapFree(pTls->HeapHdl, pStartTxBuff);
WinsMscHeapDestroy(pTls->HeapHdl);
}
DBGLEAVE("HandleSndEntriesReq\n");
return(WINS_SUCCESS);
}
VOID
HandleUpdNtf(
#if PRSCONN
BOOL fPrsConn,
#endif
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function is called to handle an update notification message
received from a remote WINS
Arguments:
fPrsConn - Indicates whether the connection is persistent or not
pWrkItm - Work Item containing the message and other relevant info
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPushInit()
Side Effects:
Comments:
None
--*/
{
PRPL_CONFIG_REC_T pPnr;
COMM_ADD_T WinsAdd;
BOOL fRplPnr = FALSE;
BOOL fExc = FALSE;
struct in_addr InAddr;
DWORD RplType;
DBGENTER("HandleUpdNtf - PUSH thread\n");
//
// We need to forward this request to the PULL thread only if
// either the WINS that sent this notification is one of our
// push pnrs or if the fRplOnlyWCnfPnrs in the registry is FALSE
//
FUTURES("user RplGetConfigRec instead of the following code")
EnterCriticalSection(&WinsCnfCnfCrtSec);
try {
if (WinsCnf.fRplOnlyWCnfPnrs)
{
if ((pPnr = WinsCnf.PullInfo.pPullCnfRecs) != NULL)
{
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
//
// Search for the Cnf record for the WINS we want to
// send the PUSH notification to/Replicate with.
//
for (
;
(pPnr->WinsAdd.Add.IPAdd != INADDR_NONE)
&&
!fRplPnr;
// no third expression
)
{
//
// Check if this is the one we want
//
if (pPnr->WinsAdd.Add.IPAdd == WinsAdd.Add.IPAdd)
{
//
// We are done. Set the fRplPnr flag to TRUE so that
// we break out of the loop.
//
// Note: Don't use break since that would cause
// a search for a 'finally' block
//
fRplPnr = TRUE;
RplType = pPnr->RplType;
continue; //so that we break out of the loop
}
//
// Get the next record that follows this one sequentially
//
pPnr = WinsCnfGetNextRplCnfRec(
pPnr,
RPL_E_IN_SEQ //seq. traversal
);
}
}
}
else
{
fRplPnr = TRUE;
RplType = WinsCnf.PullInfo.RplType;
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleUpdNtf");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_EXC_PUSH_TRIG_PROC);
fExc = TRUE;
}
LeaveCriticalSection(&WinsCnfCnfCrtSec);
#ifdef WINSDBG
try {
#endif
if (fRplPnr)
{
//
// Inform the TCP listener thread that it should stop
// monitoring the dialogue since we are handing it over to
// the PULL thread
//
#if PRSCONN
if (!fPrsConn)
#endif
{
if (!ECommProcessDlg(&pWrkItm->DlgHdl, COMM_E_NTF_STOP_MON))
{
//
// Free the buffer
//
ECommFreeBuff(pWrkItm->pMsg - COMM_HEADER_SIZE);
DBGPRINT0(ERR, "HandleUpdNtf - PUSH thread. No Upd Ntf could be sent. It could be because the link went down\n");
return;
}
else
{
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
COMM_HOST_TO_NET_L_M(WinsAdd.Add.IPAdd,InAddr.s_addr);
WinsMscLogEvtStrs(COMM_NETFORM_TO_ASCII_M(&InAddr),
WINS_EVT_UPD_NTF_ACCEPTED, TRUE);
}
}
//
// Forward the request to the Pull thread
//
ERplInsertQue(
WINS_E_RPLPUSH,
QUE_E_CMD_HDL_PUSH_NTF,
&pWrkItm->DlgHdl,
pWrkItm->pMsg, //msg containing the push ntf
pWrkItm->MsgLen, //msg length
ULongToPtr(RplType), //context to pass
0 //no magic no
);
//
// The Pull thread will now terminate the dlg
//
}
else //we need to reject this trigger
{
if (!fExc)
{
COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
DBGPRINT1(RPLPUSH, "HandleUpdNtf: Got a push trigger from a WINS with which we are not allowed to pull replicas. Address of WINS is (%d)\n",
WinsAdd.Add.IPAdd
);
COMM_HOST_TO_NET_L_M(WinsAdd.Add.IPAdd,InAddr.s_addr);
WinsMscLogEvtStrs(COMM_NETFORM_TO_ASCII_M(&InAddr),
WINS_EVT_UPD_NTF_NOT_ACCEPTED, TRUE);
}
//
// We need to first deallocate the message and then end the
// dialogue. The work item will get deallocated by the caller
//
//
// Free the buffer
//
ECommFreeBuff(pWrkItm->pMsg - COMM_HEADER_SIZE);
//
// End the implicit dialogue
//
(VOID)ECommEndDlg(&pWrkItm->DlgHdl);
}
#ifdef WINSDBG
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleUpdNtf");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_EXC);
}
#endif
DBGLEAVE("HandleUpdNtf - PUSH thread\n");
return;
}
VOID
HandleUpdVersNoReq(
PQUE_RPL_REQ_WRK_ITM_T pWrkItm
)
/*++
Routine Description:
This function is called to handle an update version number
request received from a remote WINS
This message is sent by a remote WINS as a result of a clash
during replication.
Arguments:
pWrkItm - work item
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
RplPushInit()
Side Effects:
Comments:
None
--*/
{
BYTE Name[NMSDB_MAX_NAM_LEN];
DWORD NameLen;
BYTE Rcode;
DWORD RspBuffLen;
BYTE RspBuff[RPLMSGF_UPDVERSNO_RSP_SIZE];
COMM_ADD_T WinsAdd;
struct in_addr InAddr;
DBGENTER("HandleUpdVerdNoReq\n");
#ifdef WINSDBG
try {
#endif
//
// log an event
//
COMM_GET_IPADD_M(&pWrkItm->DlgHdl, &WinsAdd.Add.IPAdd);
COMM_HOST_TO_NET_L_M(WinsAdd.Add.IPAdd,InAddr.s_addr);
WinsMscLogEvtStrs(COMM_NETFORM_TO_ASCII_M(&InAddr), WINS_EVT_REM_WINS_INF, TRUE);
/*
* Unformat the request message
*/
RplMsgfUfmUpdVersNoReq(
pWrkItm->pMsg + 4, /*past the
*opcode */
Name,
&NameLen
);
//
// handle the request
//
NmsNmhUpdVersNo( Name, NameLen, &Rcode, &WinsAdd );
//
//Format the response
//
RplMsgfFrmUpdVersNoRsp(
RspBuff + COMM_N_TCP_HDR_SZ,
Rcode,
&RspBuffLen
);
//
// Send the response. No need to check the return code.
//
(VOID)ECommSndRsp(
&pWrkItm->DlgHdl,
RspBuff + COMM_N_TCP_HDR_SZ,
RspBuffLen
);
//
// No need to end the dialogue. The initiator of the dlg will end it.
//
#ifdef WINSDBG
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("HandleUpdVersNoReq");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPUSH_EXC);
}
#endif
DBGLEAVE("HandleUpdVerdNoReq\n");
return;
} // HandleUpdVersNoReq()