/*++ 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()