|
|
/*++
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; 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; } else { // if this is not one of our replication partners, get the
// generic (default) "OnlyDynRecs"
EnterCriticalSection(&WinsCnfCnfCrtSec); fOnlyDynRecs = WinsCnf.PushInfo.fOnlyDynRecs; LeaveCriticalSection(&WinsCnfCnfCrtSec); }
#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; }
// make sure any previous thread heap is cleaned up - NmsDbGetDataRecs will
// create a new heap and allocate memory.
if (pTls->HeapHdl != NULL) { // destroying the heap deletes all the memory allocated in it
WinsMscHeapDestroy(pTls->HeapHdl); pTls->HeapHdl = NULL; }
/*
* * 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 );
// NmsDbGetDataRecs from above is supposed to have already created the heap!
ASSERT(pTls->HeapHdl != NULL); //
// 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
// make sure any previous thread heap is cleaned up before getting out of this call
if (pTls->HeapHdl != NULL) { // destroying the heap deletes all the memory allocated in it
WinsMscHeapDestroy(pTls->HeapHdl); pTls->HeapHdl = NULL; }
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()
|