Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4611 lines
154 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Rplpull.c
  5. Abstract:
  6. This module implements the pull functionality of the WINS replicator
  7. Functions:
  8. GetReplicasNew
  9. GetVersNo
  10. RplPullPullEntries
  11. SubmitTimerReqs
  12. SubmitTimer
  13. SndPushNtf
  14. HdlPushNtf
  15. EstablishComm
  16. RegGrpRpl
  17. IsTimeoutToBeIgnored
  18. InitRplProcess
  19. Reconfig
  20. RplPullInit
  21. RplPullRegRepl
  22. Portability:
  23. This module is portable
  24. Author:
  25. Pradeep Bahl (PradeepB) Jan-1993
  26. Revision History:
  27. Modification date Person Description of modification
  28. ----------------- ------- ----------------------------
  29. --*/
  30. /*
  31. * Includes
  32. */
  33. #include <time.h>
  34. #include <stdlib.h>
  35. #include <search.h>
  36. #include "wins.h"
  37. #include <winsock2.h>
  38. #include "comm.h"
  39. #include "assoc.h"
  40. #include "winsque.h"
  41. #include "rpl.h"
  42. #include "rplpull.h"
  43. #include "rplpush.h"
  44. #include "rplmsgf.h"
  45. #include "nms.h"
  46. #include "nmsnmh.h"
  47. #include "nmsdb.h"
  48. #include "winsmsc.h"
  49. #include "winsevt.h"
  50. #include "winscnf.h"
  51. #include "winstmm.h"
  52. #include "winsintf.h"
  53. /*
  54. * Local Macro Declarations
  55. */
  56. //
  57. // defines to use for retrying communication with a remote WINS on a
  58. // communication failure exception (when trying to establish a connection).
  59. //
  60. // The retries are done before moving on in the list to the next WINS
  61. // (if one is there). When MAX_RETRIES_TO_BE_DONE retries have been done,
  62. // we do not retry again until the next replication cycle at which
  63. // time the whole process is repeated).
  64. //
  65. // The number of replication cycles this process of retries is to be
  66. // continued is a registry parameter
  67. //
  68. //
  69. // NOTE:
  70. // Since TCP/IP's retry strategy has been improved (more retries than before)
  71. // and made a registry parameter, we now probably don't need to do the retries
  72. //
  73. #define MAX_RETRIES_TO_BE_DONE (0) //0 for testing only
  74. //
  75. // Time to wait before flushing for the Rpl Pull thread
  76. //
  77. #define FLUSH_TIME (2000) //2 secs
  78. //
  79. // Note: Don't make the retry time interval too large since communications
  80. // with Remote WINS servers is established in sequence. 20 secs
  81. // is not bad.
  82. //
  83. #define RETRY_TIME_INTVL (20000) //in millisecs
  84. #define FIVE_MINUTES 300
  85. /*
  86. * Local Typedef Declarations
  87. */
  88. /*
  89. * Global Variable Definitions
  90. */
  91. HANDLE RplPullCnfEvtHdl; //handle to event signaled by main
  92. //thread when a configuration change
  93. //has to be given to the Pull handler
  94. //thread
  95. BOOL fRplPullAddDiffInCurrRplCycle; //indicates whether the address
  96. //of any entry in this WINS's db
  97. //changed as a result of
  98. //replication
  99. #if 0
  100. BOOL fRplPullTriggeredWins; //indicates that during the current
  101. //replication cycle, one or more
  102. //WINS's were triggered. This
  103. //when TRUE, then if the above
  104. //"AddDiff.." flag is TRUE, it means
  105. //that the PULL thread should trigger
  106. //all PULL Pnrs that have an INVALID
  107. //metric in their UpdateCount field
  108. //(of the RPL_CONFIG_T struct)
  109. BOOL fRplPullTrigger; //Indication to the PULL thread to
  110. //trigger Pull pnrs since one or more
  111. //address changed. fRplPullTriggerWins
  112. //has got be FALSE when this is true
  113. #endif
  114. BOOL fRplPullContinueSent = FALSE;
  115. //
  116. // This array is indexed by the owner id. of an RQ server that has entries in
  117. // our database. Each owner's max. version number is stored in this array
  118. //
  119. PRPL_VERS_NOS_T pRplPullOwnerVersNo;
  120. DWORD RplPullMaxNoOfWins = RPL_MAX_OWNERS_INITIALLY;
  121. DWORD RplPullCnfMagicNo; //stores the id. of the current WinsCnf
  122. //structure that the Pull thread
  123. // is operating with
  124. /*
  125. * Local Variable Definitions
  126. */
  127. /*
  128. pPushPnrVersNoTbl -- Table whose some (or all) entries are
  129. initialized at replication time.
  130. */
  131. /*
  132. pPushPnrVersNoTbl
  133. This table stores the Max. version number pertaining to each WINS server
  134. that owns entries in the local database of Push Partners
  135. Note: The table is STATIC for now. We might change it to be a dynamic one
  136. later.
  137. The first dimension indicates the Push Pnr. The second dimension indicates
  138. the owner WINS that has records in the Push Pnr's local db
  139. */
  140. STATIC PRPL_VERS_NOS_T pPushPnrVersNoTbl;
  141. //
  142. // Var. that stores the handles to the timer requests that have been
  143. // submitted
  144. //
  145. STATIC WINSTMM_TIMER_REQ_ACCT_T SetTimeReqs;
  146. STATIC BOOL sfPulled = FALSE;//indicates whether the PULL thread pulled
  147. //anything from a WINS. Set by PullEntries.
  148. //Looked at by HdlPushNtf
  149. /*
  150. * Local Function Prototype Declarations
  151. */
  152. STATIC
  153. VOID
  154. GetReplicasNew(
  155. IN PRPL_CONFIG_REC_T pPullCnfRecs,
  156. IN RPL_REC_TRAVERSAL_E RecTrv_e //indicates how we have to
  157. //interpret the above list
  158. );
  159. VOID
  160. ConductChkNew(
  161. PPUSHPNR_DATA_T pPushPnrData,
  162. VERS_NO_T vnMaxLocal,
  163. VERS_NO_T vnMaxRemote);
  164. STATIC
  165. VOID
  166. GetVersNo(
  167. PPUSHPNR_DATA_T pPushPnrData //info about Push Pnr
  168. );
  169. STATIC
  170. VOID
  171. SubmitTimerReqs(
  172. IN PRPL_CONFIG_REC_T pPullCnfRecs
  173. );
  174. STATIC
  175. VOID
  176. SubmitTimer(
  177. LPVOID pWrkItm,
  178. IN PRPL_CONFIG_REC_T pPullCnfRec,
  179. BOOL fResubmit
  180. );
  181. STATIC
  182. VOID
  183. SndPushNtf(
  184. PQUE_RPL_REQ_WRK_ITM_T pWrkItm
  185. );
  186. STATIC
  187. VOID
  188. HdlPushNtf(
  189. PQUE_RPL_REQ_WRK_ITM_T pWrkItm
  190. );
  191. STATIC
  192. VOID
  193. EstablishComm(
  194. IN PRPL_CONFIG_REC_T pPullCnfRecs,
  195. IN BOOL fAllocPushPnrData,
  196. IN PPUSHPNR_DATA_T *ppPushPnrData,
  197. IN RPL_REC_TRAVERSAL_E RecTrv_e,
  198. OUT LPDWORD pNoOfPushPnrs
  199. );
  200. STATIC
  201. STATUS
  202. RegGrpRepl(
  203. LPBYTE pName,
  204. DWORD NameLen,
  205. DWORD Flag,
  206. DWORD OwnerId,
  207. VERS_NO_T VersNo,
  208. DWORD NoOfAdds,
  209. PCOMM_ADD_T pNodeAdd,
  210. PCOMM_ADD_T pOwnerWinsAdd
  211. );
  212. STATIC
  213. BOOL
  214. IsTimeoutToBeIgnored(
  215. PQUE_TMM_REQ_WRK_ITM_T pWrkItm
  216. );
  217. STATIC
  218. VOID
  219. InitRplProcess(
  220. PWINSCNF_CNF_T pWinsCnf
  221. );
  222. STATIC
  223. VOID
  224. Reconfig(
  225. PWINSCNF_CNF_T pWinsCnf
  226. );
  227. VOID
  228. AddressChangeNotification(
  229. PWINSCNF_CNF_T pWinsCnf
  230. );
  231. STATIC
  232. VOID
  233. PullSpecifiedRange(
  234. PCOMM_HDL_T pDlgHdl,
  235. PWINSINTF_PULL_RANGE_INFO_T pPullRangeInfo,
  236. BOOL fAdjMinVersNo,
  237. DWORD RplType
  238. );
  239. STATIC
  240. VOID
  241. DeleteWins(
  242. PCOMM_ADD_T pWinsAdd
  243. );
  244. BOOL
  245. AcceptPersona(
  246. PCOMM_ADD_T pWinsAdd
  247. );
  248. VOID
  249. FilterPersona(
  250. PPUSHPNR_DATA_T pPushData
  251. );
  252. //
  253. // Function definitions
  254. //
  255. DWORD
  256. RplPullInit (
  257. LPVOID pWinsCnfArg
  258. )
  259. /*++
  260. Routine Description:
  261. This is the initialization (startup function) of the PULL thread.
  262. It does the following:
  263. Arguments:
  264. pWinsCnfArg - Address of the WINS configuration block
  265. Externals Used:
  266. None
  267. Return Value:
  268. Success status codes -- WINS_SUCCESS
  269. Error status codes -- WINS_FAILURE
  270. Error Handling:
  271. Called by:
  272. ERplInit
  273. Side Effects:
  274. Comments:
  275. None
  276. --*/
  277. {
  278. PQUE_RPL_REQ_WRK_ITM_T pWrkItm;
  279. HANDLE ThdEvtArr[3];
  280. DWORD ArrInd;
  281. DWORD RetVal;
  282. BOOL fIsTimerWrkItm; //indicates whether
  283. //it is a timer wrk
  284. //item
  285. PWINSCNF_CNF_T pWinsCnf = pWinsCnfArg;
  286. PRPL_CONFIG_REC_T paPullCnfRecs = pWinsCnf->PullInfo.pPullCnfRecs;
  287. PRPL_CONFIG_REC_T paCnfRec = paPullCnfRecs;
  288. SYSTEMTIME LocalTime;
  289. BOOL bRecoverable = FALSE;
  290. while(TRUE)
  291. {
  292. try
  293. {
  294. if (!bRecoverable)
  295. {
  296. //
  297. // Initialize self with the db engine
  298. //
  299. NmsDbThdInit(WINS_E_RPLPULL);
  300. NmsDbOpenTables(WINS_E_RPLPULL);
  301. DBGMYNAME("Replicator Pull Thread");
  302. //
  303. // Create the event handle to wait for configuration changes. This
  304. // event is signaled by the main thread when it needs to reinit
  305. // the Pull handler component of the Replicator
  306. //
  307. WinsMscCreateEvt(
  308. RPL_PULL_CNF_EVT_NM,
  309. FALSE, //auto-reset
  310. &RplPullCnfEvtHdl
  311. );
  312. ThdEvtArr[0] = NmsTermEvt;
  313. ThdEvtArr[1] = QueRplPullQueHd.EvtHdl;
  314. ThdEvtArr[2] = RplPullCnfEvtHdl;
  315. //
  316. // If logging is turned on, specify the wait time for flushing
  317. // NOTE: We override the wait time we specified for all sessions
  318. // for this thread because that wait time is too less (100 msecs) and
  319. // will cause unnecessary overhead.
  320. //
  321. if (WinsCnf.fLoggingOn)
  322. {
  323. //
  324. // Set flush time to 2 secs.
  325. //
  326. NmsDbSetFlushTime(FLUSH_TIME);
  327. }
  328. /*
  329. Loop forever doing the following:
  330. Pull replicas from the Pull Partners specified in the
  331. work item.
  332. Block on the event until signalled (it will get signalled
  333. if one of the following happens:
  334. 1)the configuration changes
  335. 2)the timer for another replication expires
  336. 3)WINS is terminating
  337. do the needful
  338. */
  339. //
  340. // Wait until signaled by the TCP thd. Will be signaled after
  341. // the TCP listener thread has inserted an entry for the WINS
  342. // in the NmsDbOwnAddTbl
  343. //
  344. WinsMscWaitInfinite( RplSyncWTcpThdEvtHdl );
  345. //
  346. // Do startup replication only if there is atleast one PUSH pnr
  347. //
  348. if (paPullCnfRecs != NULL)
  349. {
  350. try {
  351. InitRplProcess(pWinsCnf);
  352. }
  353. except(EXCEPTION_EXECUTE_HANDLER) {
  354. DBGPRINTEXC("RplPullInit");
  355. DBGPRINT0(EXC, "RplPullInit: Exception during init time replication\n");
  356. }
  357. }
  358. NmsDbCloseTables();
  359. bRecoverable = TRUE;
  360. } // end if (!bRecoverable)
  361. while(TRUE)
  362. {
  363. /*
  364. * Block until signalled
  365. */
  366. WinsMscWaitUntilSignaled(
  367. ThdEvtArr,
  368. 3,
  369. &ArrInd,
  370. FALSE
  371. );
  372. if (ArrInd == 0)
  373. {
  374. //WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_ORDERLY_SHUTDOWN);
  375. WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
  376. }
  377. /*
  378. * loop forever until all work items have been handled
  379. */
  380. while(TRUE)
  381. {
  382. /*
  383. * dequeue the request from the queue
  384. */
  385. RetVal = QueGetWrkItm(
  386. QUE_E_RPLPULL,
  387. (LPVOID)&pWrkItm
  388. );
  389. if (RetVal == WINS_NO_REQ)
  390. {
  391. break;
  392. }
  393. WinsMscChkTermEvt(
  394. #ifdef WINSDBG
  395. WINS_E_RPLPULL,
  396. #endif
  397. FALSE
  398. );
  399. fIsTimerWrkItm = FALSE;
  400. NmsDbOpenTables(WINS_E_RPLPULL);
  401. DBGPRINT1(RPLPULL, "RplPullInit: Dequeued a work item. Cmd Type is (%d)\n", pWrkItm->CmdTyp_e);
  402. switch(pWrkItm->CmdTyp_e)
  403. {
  404. case(QUE_E_CMD_TIMER_EXPIRED):
  405. //
  406. // We may want to ignore this timeout if it
  407. // pertains to a previous configuration
  408. //
  409. if (
  410. !IsTimeoutToBeIgnored(
  411. (PQUE_TMM_REQ_WRK_ITM_T)pWrkItm
  412. )
  413. )
  414. {
  415. WinsIntfSetTime(
  416. &LocalTime,
  417. WINSINTF_E_PLANNED_PULL);
  418. #ifdef WINSDBG
  419. DBGPRINT5(REPL, "STARTING A REPLICATION CYCLE on %d/%d at %d.%d.%d (hr.mts.sec)\n",
  420. LocalTime.wMonth,
  421. LocalTime.wDay,
  422. LocalTime.wHour,
  423. LocalTime.wMinute,
  424. LocalTime.wSecond);
  425. DBGPRINT5(RPLPULL, "STARTING A REPLICATION CYCLE on %d/%d at %d.%d.%d (hr.mts.sec)\n",
  426. LocalTime.wMonth,
  427. LocalTime.wDay,
  428. LocalTime.wHour,
  429. LocalTime.wMinute,
  430. LocalTime.wSecond);
  431. #endif
  432. GetReplicasNew(
  433. ((PQUE_TMM_REQ_WRK_ITM_T)pWrkItm)->
  434. pClientCtx,
  435. RPL_E_VIA_LINK //use the pNext field to
  436. //get to the next record
  437. );
  438. DBGPRINT0(RPLPULL, "REPLICATION CYCLE END\n");
  439. /*Resubmit the timer request*/
  440. SubmitTimer(
  441. pWrkItm,
  442. ((PQUE_TMM_REQ_WRK_ITM_T)pWrkItm)
  443. ->pClientCtx,
  444. TRUE //it is a resubmission
  445. );
  446. }
  447. //
  448. // Set the flag so that we do not free
  449. // the work item. It was resubmitted
  450. //
  451. fIsTimerWrkItm = TRUE;
  452. break;
  453. //
  454. // Pull in replicas
  455. //
  456. case(QUE_E_CMD_REPLICATE):
  457. //
  458. // Make sure that we are not using old info
  459. //
  460. if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
  461. ((PRPL_CONFIG_REC_T)(pWrkItm->pClientCtx))->fTemp)
  462. {
  463. WinsIntfSetTime(
  464. &LocalTime,
  465. WINSINTF_E_ADMIN_TRIG_PULL);
  466. GetReplicasNew( pWrkItm->pClientCtx,
  467. RPL_E_NO_TRAVERSAL );
  468. if (
  469. ((PRPL_CONFIG_REC_T)
  470. (pWrkItm->pClientCtx))->fTemp
  471. )
  472. {
  473. WinsMscDealloc(pWrkItm->pClientCtx);
  474. }
  475. }
  476. else
  477. {
  478. DBGPRINT0(ERR, "RplPullInit: Can not honor this request since the configuration under the PARTNERS key may have changed\n");
  479. WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CNF_CHANGE);
  480. }
  481. break;
  482. //
  483. // Pull range of records
  484. //
  485. case(QUE_E_CMD_PULL_RANGE):
  486. //
  487. // Make sure that we are not using old info
  488. //
  489. if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
  490. ((PRPL_CONFIG_REC_T)((PWINSINTF_PULL_RANGE_INFO_T)(pWrkItm->pClientCtx))->pPnr)->fTemp)
  491. {
  492. //
  493. // Pull the specified range. If the Pnr
  494. // record is temp, this function will
  495. // deallocate it.
  496. //
  497. PullSpecifiedRange(NULL, pWrkItm->pClientCtx, FALSE,
  498. ((PRPL_CONFIG_REC_T)(((PWINSINTF_PULL_RANGE_INFO_T)(pWrkItm->pClientCtx))->pPnr))->RplType);
  499. //
  500. // Deallocate the client ctx
  501. //
  502. WinsMscDealloc(pWrkItm->pClientCtx);
  503. }
  504. else
  505. {
  506. DBGPRINT0(ERR, "RplPullInit: Can not honor this request since the configuration under the PARTNERS key may have changed\n");
  507. WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CNF_CHANGE);
  508. }
  509. break;
  510. //
  511. //reconfigure
  512. //
  513. case(QUE_E_CMD_CONFIG):
  514. Reconfig(pWrkItm->pClientCtx);
  515. break;
  516. //
  517. // Delete WINS from the Owner Add table (delete records
  518. // also
  519. //
  520. case(QUE_E_CMD_DELETE_WINS):
  521. DeleteWins(pWrkItm->pClientCtx);
  522. break;
  523. //
  524. // ip addr of this machine changed, modify the own - addr table
  525. case(QUE_E_CMD_ADDR_CHANGE):
  526. AddressChangeNotification(pWrkItm->pClientCtx);
  527. break;
  528. //
  529. //Push notification. Local message from an NBT thread,
  530. //from an RPC thread (Push Trigger) or from this thread
  531. //itself
  532. //
  533. case(QUE_E_CMD_SND_PUSH_NTF_PROP):
  534. case(QUE_E_CMD_SND_PUSH_NTF):
  535. //
  536. // Make sure that we are not using old info
  537. //
  538. if ((pWrkItm->MagicNo == RplPullCnfMagicNo) ||
  539. ((PRPL_CONFIG_REC_T)(pWrkItm->pClientCtx))->fTemp)
  540. {
  541. SndPushNtf(pWrkItm);
  542. }
  543. break;
  544. //
  545. //Push notification from a remote WINS. Forwarded to Pull
  546. //thread by the Push thread
  547. //
  548. case(QUE_E_CMD_HDL_PUSH_NTF):
  549. HdlPushNtf(pWrkItm);
  550. break;
  551. default:
  552. DBGPRINT1(ERR,
  553. "RplPullInit: Invalid command code = (%d)\n",
  554. pWrkItm->CmdTyp_e);
  555. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  556. break;
  557. } // end of switch
  558. NmsDbCloseTables();
  559. //
  560. // deallocate the work item only if it is not a timer work item
  561. // We don't deallocate a timer work item here because of two
  562. // reasons:
  563. //
  564. // 1) it is reused
  565. // 2) it is allocated from the timer work item heap
  566. //
  567. if (!fIsTimerWrkItm)
  568. {
  569. /*
  570. * deallocate the work item
  571. */
  572. QueDeallocWrkItm( RplWrkItmHeapHdl, pWrkItm );
  573. }
  574. } //while(TRUE) for getting all work items
  575. } //while (TRUE)
  576. } // end of try
  577. except(EXCEPTION_EXECUTE_HANDLER)
  578. {
  579. if (bRecoverable)
  580. {
  581. DBGPRINTEXC("RplPullInit");
  582. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_EXC);
  583. }
  584. else
  585. {
  586. DBGPRINTEXC("RplPullInit");
  587. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_ABNORMAL_SHUTDOWN);
  588. //
  589. // If NmsDbThdInit comes back with an exception, it is possible
  590. // that the session has not yet been started. Passing
  591. // WINS_DB_SESSION_EXISTS however is ok
  592. //
  593. WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
  594. }
  595. } // end of except {.. }
  596. } // end of while(TRUE)
  597. //
  598. // We never reach here
  599. //
  600. ASSERT(0);
  601. return(WINS_FAILURE);
  602. }
  603. //////////////////////////////////////////////////////////////////////////////////
  604. //------------------- GetReplicasNew() -------------------------------------------
  605. // This call replaces the original GetReplicas() function due to several issues
  606. // hidden in that one.
  607. // ft: 06/06/2000
  608. //
  609. // Parameters:
  610. // 1) pPullCnfRecs: gives the info about the partners where the records are to be pulled
  611. // 2) RecvTrv_e: tells which of the partners from the first parameter should be involved
  612. // in the replication. This parameter can be either RPL_E_VIA_LINK, RPL_E_NO_TRAVERSAL
  613. // or RPL_E_IN_SEQ. It is used only at the end of the path:
  614. // EstablishComm()->WinsCnfGetNextRplCnfRec()
  615. //
  616. VOID
  617. GetReplicasNew (
  618. IN PRPL_CONFIG_REC_T pPullCnfRecs, // info about the (pull) repl partners to use
  619. IN RPL_REC_TRAVERSAL_E RecTrv_e // repl partner retrieval method
  620. )
  621. {
  622. // The type & variable naming here is confusing. We are not dealing with push
  623. // partners, but with pull partners, meaning "partners from which this server
  624. // is currently pulling records". This is how WINSSNAP & WINSMON are both naming
  625. // these kind of partners. I preserve though the original type naming (and hence
  626. // the original variable naming) just to limit the size of the change.
  627. PPUSHPNR_DATA_T pPushPnrData; // info on the connections to the partners
  628. DWORD nPushPnrData; // number of elements in pPushPnrData
  629. DWORD i, j; // general use counters
  630. DBGENTER("GetReplicasNew\n");
  631. // Establish communications with the Pull Partners
  632. // For each of the partners in the list, the call below attempts to open a connection
  633. // to the server (if needed). All the nPushPnrData partners to which the connection
  634. // is established successfully are specified in the array (PPUSHPNR_DATA_T)pPushPnrData.
  635. EstablishComm(
  636. pPullCnfRecs, // IN - info about the replication partners
  637. TRUE, // IN - pPushPnrData should be allocated
  638. &pPushPnrData, // OUT - info on the connections to the partners
  639. RecTrv_e, // IN - which of the partners should we connect to
  640. &nPushPnrData); // OUT - number of elements in pPushPnrData
  641. // NOTE: regardless the number of partners, pPushPnrData gets allocated so it will
  642. // be unconditionally deallocated later.
  643. //
  644. // --Checkpoint-------------
  645. // At this point, pPushPnrData[i].PushPnrId == i+1.
  646. // The link between pPushPnrData[i] and the corresponding RPL_CONFIG_REC_T is done
  647. // through (RPL_CONFIG_REC_T)pPushPnrData[i].pPullCnfRec
  648. // -------------------------
  649. //
  650. // Contact each of the partners in pPushPnrData and get its OwnerAddr<->VersNo maps.
  651. // The map of each partner is stored in (PRPL_ADD_VERS_NO)pPushPnrData[i].pAddVers
  652. // The size of the map is stored in (DWORD)pPushPnrData[i].NoOfMaps
  653. for (i = 0; i < nPushPnrData; ) // no 3rd part for this "for"
  654. {
  655. PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]); // get pointer to the current partner
  656. try
  657. {
  658. GetVersNo(pPnrData);
  659. i++;
  660. }
  661. except(EXCEPTION_EXECUTE_HANDLER)
  662. {
  663. // an exception was raised inside GetVersNo()
  664. DWORD ExcCode = GetExceptionCode();
  665. // dump the error
  666. DBGPRINT2(
  667. EXC, "GetReplicasNew->GetVersNo(%x); hit exception = (%x).\n",
  668. pPnrData->pPullCnfRec->WinsAdd.Add.IPAdd,
  669. ExcCode);
  670. // log the error
  671. WINSEVT_LOG_M(
  672. ExcCode,
  673. (ExcCode == WINS_EXC_COMM_FAIL) ? WINS_EVT_CONN_ABORTED : WINS_EVT_SFT_ERR);
  674. // update the replication counters for that partner
  675. (VOID)InterlockedIncrement(&pPnrData->pPullCnfRec->NoOfCommFails);
  676. (VOID)InterlockedDecrement(&pPnrData->pPullCnfRec->NoOfRpls);
  677. // Delete the dialog
  678. ECommEndDlg(&pPnrData->DlgHdl);
  679. // If there is a persistent dialog, it has to be marked as
  680. // "no longer active"
  681. if (pPnrData->fPrsConn)
  682. ECOMM_INIT_DLG_HDL_M(&(pPnrData->pPullCnfRec->PrsDlgHdl));
  683. // one of the partners could not be contacted, so
  684. // eliminate it from the pPnrData array
  685. nPushPnrData--;
  686. // adjust the array such that the active partners are kept compact
  687. // the PushPnrId is also changed to keep true the assertion
  688. // pPushPnrData[i].PushPnrId == i+1;
  689. if (i != nPushPnrData)
  690. {
  691. DWORD origPushPnrId = pPushPnrData[i].PushPnrId;
  692. // !!! whole PUSHPNR_DATA_T structure is copied here !!!
  693. pPushPnrData[i] = pPushPnrData[nPushPnrData];
  694. pPushPnrData[i].PushPnrId = origPushPnrId;
  695. }
  696. // since the counter "i" is not incremented, the partner that
  697. // has just been moved will be the one considered next
  698. continue;
  699. } // end of exception handler
  700. } // end of for loop for looping over Push Pnrs
  701. // --Checkpoint--------------
  702. // At this point, pPushPnrData contains only the partners for which a connection
  703. // could be established, nPushPnrData is updated to count only these partners
  704. // and the pPushPnrData[i].PushPnrId == i+1 still holds.
  705. // (PRPL_ADD_VERS_NO)pPushPnrData[i].pAddVers gives the map OwnerAddr<->VersNo as
  706. // known by that replication partner. (DWORD)pPushPnrData[i].NoOfMaps gives the
  707. // number of entries in the map.
  708. // --------------------------
  709. DBGPRINT1(RPLPULL, "GetReplicasNew: Active PushPnrs = (%d)\n", nPushPnrData);
  710. // do stuff only if there is at least someone to talk to
  711. if (nPushPnrData > 0)
  712. {
  713. // array giving info on what owner should be pulled from what repl partner
  714. // the array starts with the image of the local OwnerId<->VersNo mapping and
  715. // grows dynamically for as many new Owners are retrieved in the mappings
  716. // of the other replication partners.
  717. PPUSHPNR_TO_PULL_FROM_T pPushPnrToPullFrom;
  718. DWORD nPushPnrToPullFrom; // size of the array
  719. VERS_NO_T vnLocalMax; // maximum local version number
  720. // depending on the server's state, get the maximum local version number
  721. //
  722. // If WINS is "init time paused", RplPullOwnerversNo will
  723. // have the max. version no. of locally owned records. We
  724. // can not use NmsNmhMyMaxVersNo since it may have been
  725. // adjusted to a higher value
  726. //
  727. if (fWinsCnfInitStatePaused)
  728. {
  729. vnLocalMax = pRplPullOwnerVersNo[0].StartVersNo;
  730. }
  731. else
  732. {
  733. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  734. NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo, vnLocalMax) ;
  735. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  736. }
  737. // Initialize (PPUSHPNR_TO_PULL_FROM_T)pPushPnrToPullFrom. This is copying the local
  738. // image of the OwnerId<->VersNo mapping. Any entry in this table having pPushPnrData
  739. // set to NULL means the local server has the highest VersNo for that particular Owner
  740. nPushPnrToPullFrom = NmsDbNoOfOwners;
  741. WinsMscAlloc(
  742. nPushPnrToPullFrom * sizeof(RPL_VERS_NOS_T),
  743. (LPVOID *)&pPushPnrToPullFrom);
  744. for (i = 0; i < NmsDbNoOfOwners; i++)
  745. {
  746. // avoid copying info for old owners that were deleted already from the
  747. // internal tables (pNmsDbOwnAddTbl & pPushPnrToPullFrom)
  748. // for those, the entry slot will look like (NULL, 0:0) so they basically
  749. // won't be taken into account for replication
  750. if (pNmsDbOwnAddTbl[i].WinsState_e != NMSDB_E_WINS_DELETED)
  751. {
  752. pPushPnrToPullFrom[i].pPushPnrData = NULL;
  753. pPushPnrToPullFrom[i].VersNo = pRplPullOwnerVersNo[i].VersNo;
  754. }
  755. }
  756. // reset the maximum local number to what we got before.
  757. pPushPnrToPullFrom[0].VersNo = vnLocalMax;
  758. // --Checkpoint--------------
  759. // At this point, pPushPnrToPullFrom is copying the OwnerId<->VersNo mapping
  760. // from the local server. Entry at index 0 contains the highest local VersNo,
  761. // all the others contain each owner's highest VersNo as it is known locally.
  762. // Each entry has pPushPnrData set to NULL as they don't refer yet to any
  763. // repl partner info. Later, pPushPnrData will point to the structure corresponding
  764. // to the repl partner with the highest VersNo for the corresponding owner.
  765. // --------------------------
  766. // We attempt now to do a merge of all the maps we got from each of the partners.
  767. // The merge means identifying which partner has the highest VersNo for
  768. // each of the OwnerAddr. In the same time, some of the OwnerAddr we just got
  769. // might not be already present in the local OwnerId<->OwnerAddr (pNmsDbOwnAddTbl)
  770. // and OwnerId<->VersNo (pRplPullOwnerVersNo)tables. So we need to get a new
  771. // OwnerId for these ones and adjust appropriately the internal tables & the
  772. // OwnerId<->OwnerAddr db table. This is done through RplFindOwnerId().
  773. //
  774. // for each active replication partner ...
  775. for (i = 0; i < nPushPnrData; i++)
  776. {
  777. // get pointer to the current partner's data
  778. PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]);
  779. // for each of the replication partner's map entry ...
  780. for (j = 0; j < pPnrData->NoOfMaps; j++)
  781. {
  782. // get the pointer to the current (OwnerAddr<->VersNo) map entry
  783. PRPL_ADD_VERS_NO_T pPnrMapEntry = &(pPnrData->pAddVers[j]);
  784. BOOL fAllocNew; // true if this is a brand new owner
  785. DWORD OwnerId;
  786. // filter out owners that are not supposed to be accepted
  787. // (either a persona non-grata or not a persona grata)
  788. if (!AcceptPersona(&(pPnrMapEntry->OwnerWinsAdd)))
  789. continue;
  790. // Locate or allocate an OwnerId for this owner
  791. // No need to enter the critical section RplOwnAddTblCrtSec since
  792. // only the Pull thread changes the NmsDbNoOfOwners value (apart
  793. // from the main thread at initialization). RplFindOwnerId changes
  794. // this value only if it is asked to allocate a new entry)
  795. // Though NmsDbGetDataRecs (called by Rpc threads, Push thread, and
  796. // scavenger thread) calls RplFindOwnerId, that call is not asking
  797. // for new OwnerId allocation.
  798. fAllocNew = TRUE;
  799. RplFindOwnerId(
  800. &(pPnrMapEntry->OwnerWinsAdd),
  801. &fAllocNew,
  802. &OwnerId,
  803. WINSCNF_E_INITP_IF_NON_EXISTENT,
  804. WINSCNF_LOW_PREC);
  805. if (nPushPnrToPullFrom < NmsDbNoOfOwners)
  806. {
  807. // if this is an owner we didn't hear of yet, RplFindOwnerId is enlarging
  808. // dynamically the internal tables (pNmsDbOwnAddTbl & pRplPullOwnerVersNo)
  809. // so we need to do the same
  810. nPushPnrToPullFrom = NmsDbNoOfOwners;
  811. // note: the memory that is added to the array is zero-ed by the call
  812. WINSMSC_REALLOC_M(
  813. nPushPnrToPullFrom * sizeof(RPL_VERS_NOS_T),
  814. (LPVOID *)&pPushPnrToPullFrom);
  815. }
  816. // it is guaranteed now, OwnerId is within the range of the pPushPnrToPullFrom.
  817. if (fAllocNew)
  818. {
  819. // if a new OwnerId was generated (either new slot into the tables or
  820. // an old slot has been reused) this means the partner is coming up with
  821. // a new owner: obviously he's the one having the most recent info on
  822. // that partner (at least for now)
  823. pPushPnrToPullFrom[OwnerId].pPushPnrData = pPnrData;
  824. pPushPnrToPullFrom[OwnerId].VersNo = pPnrMapEntry->VersNo;
  825. }
  826. else
  827. {
  828. // the owner already exists in the list, so we need to check whether the
  829. // info on this owner is not more recent on a different partner (or on this
  830. // local server)
  831. if ( LiGtr(pPnrMapEntry->VersNo, pPushPnrToPullFrom[OwnerId].VersNo) )
  832. {
  833. // yes it is, so we need to update the entry in the pPushPndToPullFrom
  834. // table such that it points to this partner and shows the new greater
  835. // version number.
  836. pPushPnrToPullFrom[OwnerId].VersNo = pPnrMapEntry->VersNo;
  837. pPushPnrToPullFrom[OwnerId].pPushPnrData = pPnrData;
  838. }
  839. // else the info is not the most recent one, so just ignore it.
  840. } // end checking the OwnerId
  841. } // end looping through partner's map entries
  842. } // end looping through the list of partners
  843. // --Checkpoint--------------
  844. // At this point pPushPnrToPullFrom contains the union of all the OwnerId<->VersNo mappings
  845. // from all the partners. Each entry contains the highest VersNo known across all partners
  846. // for the corresponding owner, and points to the partner that came with this info (or NULL
  847. // if the highest VersNo was already known locally).
  848. // --------------------------
  849. // start pulling each owner from the partner able to provide the most up-to-date information
  850. // (having the highest version number).
  851. // start doing so from the entry '1' in the pPushPnrToPullFrom since entry '0' corresponds
  852. // to the local owner. That one will be handled later
  853. for (i = 1; i < NmsDbNoOfOwners; i++)
  854. {
  855. PPUSHPNR_TO_PULL_FROM_T pPushPartner = &(pPushPnrToPullFrom[i]);
  856. VERS_NO_T vnToPullFrom;
  857. // if pPushPnrData member is null this means the local server has the highest version
  858. // number for this owner. So nothing to pull from anyone here
  859. // the same, if fDlgStarted is NULL this means that partner hit an exception previously
  860. // and its dialog has been shut down. Don't attempt to get back to that partner in this
  861. // case.
  862. if (pPushPartner->pPushPnrData == NULL ||
  863. !pPushPartner->pPushPnrData->fDlgStarted)
  864. continue;
  865. // set the local variable vnToPullFrom to the first version number that is not known
  866. // locally (one more than the highest known)
  867. NMSNMH_INC_VERS_NO_M(pRplPullOwnerVersNo[i].VersNo, vnToPullFrom);
  868. try
  869. {
  870. // eventually we got here: start pulling
  871. RplPullPullEntries(
  872. &(pPushPartner->pPushPnrData->DlgHdl), // active dialog to use
  873. i, // owner id
  874. pPushPartner->VersNo, // max VersNo
  875. vnToPullFrom, // min VersNo
  876. WINS_E_RPLPULL, // the client is the replicator
  877. NULL, // pointer to rsp buffer (used only by scavenger)
  878. TRUE, // update counters
  879. pPushPartner->pPushPnrData->RplType); // replication type for this partner
  880. }
  881. except (EXCEPTION_EXECUTE_HANDLER)
  882. {
  883. DWORD ExcCode = GetExceptionCode();
  884. // dump the error
  885. DBGPRINT2(
  886. EXC,
  887. "GetReplicasNew->RplPullPullEntries(%x): hit exception (%x)\n",
  888. pPushPartner->pPushPnrData->pPullCnfRec->WinsAdd.Add.IPAdd,
  889. ExcCode);
  890. // log the error
  891. WINSEVT_LOG_M(
  892. WINS_FAILURE,
  893. ExcCode == WINS_EXC_COMM_FAIL ? WINS_EVT_CONN_ABORTED : WINS_EVT_SFT_ERR);
  894. // ----bug #120788----
  895. // If an exception happens at this point, the persistent connection is left open and it might just
  896. // happen that the remote partner is still pushing data. This could fill up the TCP window
  897. // and could have the sender blocked indefinitely in RplPushInit->HandleSndEntriesReq.
  898. // Because of this the remote sender will be unable to push out data, and given that the
  899. // same thread is the one that is sending out the VersNo table (see the beginning of this
  900. // function) subsequent replications will not be possible over the same connection.
  901. // FIX: in case anything goes wrong such that we get to this exception handler
  902. // just close the connection even if it is persistent. This causes any remote WINS to break
  903. // out from HandleSndEntriesReq and avoid getting stuck.
  904. ECommEndDlg(&(pPushPartner->pPushPnrData->DlgHdl));
  905. // If there is a persistent dialog, it has to be marked as "no longer active"
  906. if (pPushPartner->pPushPnrData->fPrsConn)
  907. ECOMM_INIT_DLG_HDL_M(&(pPushPartner->pPushPnrData->pPullCnfRec->PrsDlgHdl));
  908. // Closing the dialog is not enough. Some other owners might be pulled out from the same
  909. // partner. We shouldn't allow that, so just ban that partner for this replication cycle.
  910. pPushPartner->pPushPnrData->fDlgStarted = FALSE;
  911. // since we dropped down this connection and we won't look at it further lets delete its
  912. // mapping also
  913. if (pPushPartner->pPushPnrData->NoOfMaps)
  914. WinsMscDealloc(pPushPartner->pPushPnrData->pAddVers);
  915. } // end except handler
  916. } // end looping through owners list
  917. // --Checkpoint--------------
  918. // Nothing has changed in the pPushPnrToPullFrom array except probably some dialogs that were shut down
  919. // because of exceptions in RplPullPullEntries. Owners handled by these partners were simply skipped.
  920. // At this point all replication is done, the most recent information about each owner apart has been
  921. // brought down from the partners that were holding it.
  922. // --------------------------
  923. // one more thing is left to be done: Check whether there is not a remote WINS partner
  924. // pretending to have more up-to-date information about the local WINS.
  925. if (pPushPnrToPullFrom[0].pPushPnrData != NULL &&
  926. pPushPnrToPullFrom[0].pPushPnrData->fDlgStarted)
  927. {
  928. ConductChkNew(
  929. pPushPnrToPullFrom[0].pPushPnrData,
  930. vnLocalMax,
  931. pPushPnrToPullFrom[0].VersNo);
  932. }
  933. // release the pPushPnrToPullFrom buffer
  934. WinsMscDealloc(pPushPnrToPullFrom);
  935. } // end "if there are active partners" case
  936. // cleanup starts here..
  937. for (i = 0; i < nPushPnrData; i++)
  938. {
  939. PPUSHPNR_DATA_T pPnrData = &(pPushPnrData[i]);
  940. if (pPnrData->fDlgStarted == TRUE)
  941. {
  942. if (!pPnrData->fPrsConn)
  943. ECommEndDlg(&(pPnrData->DlgHdl));
  944. //Deallocate the memory pointed to by PushPnrData structure
  945. if (pPnrData->NoOfMaps)
  946. WinsMscDealloc(pPnrData->pAddVers);
  947. }
  948. }
  949. // deallocate the memory containing push pnr info.
  950. WinsMscDealloc(pPushPnrData);
  951. // If Wins is in the init time paused state, unpause it.
  952. //
  953. if (fWinsCnfInitStatePaused)
  954. {
  955. //inform sc to send a continue to WINS.
  956. EnterCriticalSection(&RplVersNoStoreCrtSec);
  957. fRplPullContinueSent = TRUE;
  958. WinsMscSendControlToSc(SERVICE_CONTROL_CONTINUE);
  959. LeaveCriticalSection(&RplVersNoStoreCrtSec);
  960. }
  961. DBGLEAVE("GetReplicasNew\n");
  962. }
  963. //------------------- END OF GetReplicasNew() ------------------------------------
  964. //////////////////////////////////////////////////////////////////////////////////
  965. //////////////////////////////////////////////////////////////////////////////////
  966. //------------------- ConductChkNew() --------------------------------------------
  967. // This call replaces the original ConductChk() function due to major redesign in
  968. // replicator's code.
  969. // ft: 06/06/2000
  970. //
  971. // Parameters:
  972. // 1) pPushPnrData: points to the replication partner that seems to have more
  973. // up-to-date information on self
  974. // 2) vnMaxLocal: maximum local version number as detected before the replication
  975. // started
  976. // 3) vnMaxRemote: maximum version number of the local server as known by the
  977. // remote partner
  978. //
  979. VOID
  980. ConductChkNew(
  981. PPUSHPNR_DATA_T pPushPnrData,
  982. VERS_NO_T vnMaxLocal,
  983. VERS_NO_T vnMaxRemote)
  984. {
  985. RPL_CONFIG_REC_T Pnr;
  986. WINSINTF_PULL_RANGE_INFO_T PullRangeInfo;
  987. BOOL fVersNoAdj = FALSE;
  988. DBGENTER("ConductChkNew\n");
  989. Pnr.WinsAdd = pPushPnrData->WinsAdd;
  990. Pnr.MagicNo = 0;
  991. Pnr.RetryCount = 0;
  992. Pnr.LastCommFailTime = 0;
  993. Pnr.LastCommTime = 0;
  994. Pnr.PushNtfTries = 0;
  995. Pnr.fTemp = FALSE; // We want the buffer to be deallocated by thread
  996. PullRangeInfo.OwnAdd.Type = WINSINTF_TCP_IP;
  997. PullRangeInfo.OwnAdd.Len = sizeof(COMM_IP_ADD_T);
  998. PullRangeInfo.OwnAdd.IPAdd = NmsLocalAdd.Add.IPAdd;
  999. PullRangeInfo.MaxVersNo = vnMaxRemote;
  1000. PullRangeInfo.MinVersNo = vnMaxLocal;
  1001. PullRangeInfo.pPnr = &Pnr;
  1002. NMSNMH_INC_VERS_NO_M(PullRangeInfo.MinVersNo, PullRangeInfo.MinVersNo);
  1003. DBGPRINT5(
  1004. RPLPULL, "ConductCheckNew(%x): Checking range [%x:%x - %x:%x]\n",
  1005. Pnr.WinsAdd.Add.IPAdd,
  1006. vnMaxLocal.HighPart, vnMaxLocal.LowPart,
  1007. vnMaxRemote.HighPart, vnMaxRemote.LowPart);
  1008. // We are pulling our own records. We want to store all.
  1009. PullSpecifiedRange(
  1010. &(pPushPnrData->DlgHdl),
  1011. &PullRangeInfo,
  1012. TRUE, //adjust min to NmsNmhMyMaxVersNo.
  1013. WINSCNF_RPL_DEFAULT_TYPE);
  1014. // If the version number is greater than the version counter value (this is
  1015. // different from the first entry of RplPullOwnerVersNo table since we look
  1016. // in the registry to determine its value).
  1017. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  1018. if (LiGtr(vnMaxRemote, NmsNmhMyMaxVersNo))
  1019. {
  1020. NmsNmhMyMaxVersNo.QuadPart = vnMaxRemote.QuadPart + 1;
  1021. fVersNoAdj = TRUE;
  1022. }
  1023. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  1024. if (fVersNoAdj)
  1025. {
  1026. #ifdef WINSDBG
  1027. vnMaxRemote.QuadPart += 1;
  1028. DBGPRINT2(
  1029. RPLPULL, "ConductCheck: Local VersNo adjusted to %x:%x\n",
  1030. vnMaxRemote.HighPart, vnMaxRemote.LowPart);
  1031. #endif
  1032. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_ADJ_VERS_NO);
  1033. }
  1034. DBGLEAVE("ConductCheckNew\n");
  1035. }
  1036. //------------------- END OF ConductChkNew() ------------------------------------
  1037. //////////////////////////////////////////////////////////////////////////////////
  1038. VOID
  1039. GetVersNo(
  1040. PPUSHPNR_DATA_T pPushPnrData //info about Push Pnr
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. This function does the following:
  1045. formats a "get address to Version Number mapping" request,
  1046. sends it and waits for response
  1047. Unformats the response
  1048. Arguments:
  1049. pPushPnrData - Information about the Push Pnr which needs to
  1050. be contacted in order to get the version number
  1051. info.
  1052. Externals Used:
  1053. None
  1054. Return Value:
  1055. None
  1056. Error Handling:
  1057. Called by:
  1058. GetReplicasNew
  1059. Side Effects:
  1060. Comments:
  1061. Some optimization can be affected by the caller of this function
  1062. --*/
  1063. {
  1064. BYTE Msg[RPLMSGF_ADDVERSMAP_REQ_SIZE]; //Buffer that will contain
  1065. //the request to send
  1066. DWORD MsgLen; //Msg Length
  1067. LPBYTE pRspMsg; //ptr to Rsp message
  1068. DWORD RspMsgLen = 0; //Rsp msg length
  1069. #if SUPPORT612WINS > 0
  1070. BOOL fIsPnrBeta1Wins;
  1071. #endif
  1072. DBGENTER("GetVersNo\n");
  1073. /*
  1074. * format the request to ask for version numbers
  1075. */
  1076. RplMsgfFrmAddVersMapReq( Msg + COMM_N_TCP_HDR_SZ, &MsgLen );
  1077. /*
  1078. * Send "send me IP address - Version Number" messages to the
  1079. * Push Pnr
  1080. *
  1081. * NOTE: If there is a communication failure or if the other WINS
  1082. * brings down the link, this function will raise a COMM_FAIL
  1083. * exception (caught in the caller of GetVersNo)
  1084. */
  1085. ECommSndCmd(
  1086. &pPushPnrData->DlgHdl,
  1087. Msg + COMM_N_TCP_HDR_SZ,
  1088. MsgLen,
  1089. &pRspMsg,
  1090. &RspMsgLen
  1091. );
  1092. #if SUPPORT612WINS > 0
  1093. COMM_IS_PNR_BETA1_WINS_M(&pPushPnrData->DlgHdl, fIsPnrBeta1Wins);
  1094. #endif
  1095. /*
  1096. * Unformat the Rsp Message
  1097. */
  1098. RplMsgfUfmAddVersMapRsp(
  1099. #if SUPPORT612WINS > 0
  1100. fIsPnrBeta1Wins,
  1101. #endif
  1102. pRspMsg + 4, //past the opcodes
  1103. &(pPushPnrData->NoOfMaps),
  1104. NULL,
  1105. &pPushPnrData->pAddVers
  1106. );
  1107. #ifdef WINSDBG
  1108. {
  1109. DWORD i;
  1110. struct in_addr InAddr;
  1111. PRPL_ADD_VERS_NO_T pAddVers; //maps
  1112. DBGPRINT1(RPLPULL, " %d Add-Vers Mappings retrieved.\n",
  1113. pPushPnrData->NoOfMaps);
  1114. for (i=0, pAddVers = pPushPnrData->pAddVers; i < pPushPnrData->NoOfMaps; i++, pAddVers++)
  1115. {
  1116. InAddr.s_addr = htonl(
  1117. pAddVers->OwnerWinsAdd.Add.IPAdd
  1118. );
  1119. DBGPRINT3(RPLPULL,"Add (%s) - MaxVersNo (%lu %lu)\n",
  1120. inet_ntoa(InAddr),
  1121. pAddVers->VersNo.HighPart,
  1122. pAddVers->VersNo.LowPart
  1123. );
  1124. }
  1125. }
  1126. #endif
  1127. ECommFreeBuff(pRspMsg - COMM_HEADER_SIZE); //decrement to begining
  1128. //of buff
  1129. DBGLEAVE("GetVersNo\n");
  1130. return;
  1131. }
  1132. VOID
  1133. RplPullPullEntries(
  1134. PCOMM_HDL_T pDlgHdl,
  1135. DWORD dwOwnerId,
  1136. VERS_NO_T MaxVersNo,
  1137. VERS_NO_T MinVersNo,
  1138. WINS_CLIENT_E Client_e,
  1139. LPBYTE *ppRspBuff,
  1140. BOOL fUpdCntrs,
  1141. DWORD RplType
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. This function is called to pull replicas for a particular owner from
  1146. a Push Pnr.
  1147. Arguments:
  1148. pDlgHdl - Dialogue with the Push Pnr
  1149. dwOwnerId - Owner Id. of WINS whose records are to be pulled.
  1150. MaxVersNo - Max. Vers. No. in the set of replicas to pull
  1151. MinVersNo - Min. Vers. No. in the set of replicas to pull
  1152. Client_e - indicates who the client is
  1153. ppRspBuff - address of pointer to response buffer if client is
  1154. WINS_E_NMSSCV -- Scavenger thread executing VerifyIfClutter
  1155. Externals Used:
  1156. None
  1157. Return Value:
  1158. None
  1159. Error Handling:
  1160. Called by:
  1161. GetReplicasNew
  1162. Side Effects:
  1163. Comments:
  1164. None
  1165. --*/
  1166. {
  1167. BYTE Buff[RPLMSGF_SNDENTRIES_REQ_SIZE];
  1168. DWORD MsgLen;
  1169. LPBYTE pRspBuff;
  1170. DWORD RspMsgLen = 0;
  1171. DWORD NoOfRecs;
  1172. BYTE Name[NMSDB_MAX_NAM_LEN];
  1173. DWORD NameLen;
  1174. BOOL fGrp;
  1175. DWORD NoOfAdds;
  1176. COMM_ADD_T NodeAdd[NMSDB_MAX_MEMS_IN_GRP * 2]; //twice the # of
  1177. //members because
  1178. //for each member
  1179. //we have an owner
  1180. DWORD Flag;
  1181. VERS_NO_T VersNo, TmpVersNo;
  1182. DWORD i;
  1183. LPBYTE pTmp;
  1184. PCOMM_ADD_T pWinsAdd;
  1185. PNMSDB_WINS_STATE_E pWinsState_e;
  1186. PVERS_NO_T pStartVersNo;
  1187. STATUS RetStat = WINS_SUCCESS;
  1188. #if SUPPORT612WINS > 0
  1189. BOOL fIsPnrBeta1Wins;
  1190. #endif
  1191. DBGENTER("RplPullPullEntries\n");
  1192. #if SUPPORT612WINS > 0
  1193. COMM_IS_PNR_BETA1_WINS_M(pDlgHdl, fIsPnrBeta1Wins);
  1194. #endif
  1195. WinsMscChkTermEvt(
  1196. #ifdef WINSDBG
  1197. Client_e,
  1198. #endif
  1199. FALSE
  1200. );
  1201. sfPulled = FALSE; //we haven't pulled anything yet.
  1202. RPL_FIND_ADD_BY_OWNER_ID_M(
  1203. dwOwnerId,
  1204. pWinsAdd,
  1205. pWinsState_e,
  1206. pStartVersNo
  1207. );
  1208. while(TRUE)
  1209. {
  1210. #ifdef WINSDBG
  1211. {
  1212. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  1213. PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  1214. struct in_addr InAdd;
  1215. InAdd.s_addr = htonl(pWinsAdd->Add.IPAdd);
  1216. DBGPRINT2(RPLPULL, "Going to Pull Entries owned by WINS with Owner Id = (%d) and address = (%s)\n", dwOwnerId, inet_ntoa(InAdd));
  1217. InAdd.s_addr = htonl(pAssocCtx->RemoteAdd.sin_addr.s_addr);
  1218. DBGPRINT5(RPLPULL, "RplPullPullEntries: Range of records is = (%lu %lu) to (%lu %lu) and is being pulled from WINS with address - (%s)\n",
  1219. MinVersNo.HighPart,
  1220. MinVersNo.LowPart,
  1221. MaxVersNo.HighPart,
  1222. MaxVersNo.LowPart,
  1223. inet_ntoa(InAdd)
  1224. );
  1225. }
  1226. #endif
  1227. /*
  1228. * Format the "send me data entries" message
  1229. */
  1230. RplMsgfFrmSndEntriesReq(
  1231. #if SUPPORT612WINS > 0
  1232. fIsPnrBeta1Wins,
  1233. #endif
  1234. Buff + COMM_N_TCP_HDR_SZ,
  1235. pWinsAdd,
  1236. MaxVersNo,
  1237. MinVersNo,
  1238. RplType,
  1239. &MsgLen
  1240. );
  1241. FUTURES("In case a huge range is being pulled, change the sTimeToWait")
  1242. FUTURES("in comm.c to a higher timeout value so that select does not")
  1243. FUTURES("time out")
  1244. /*
  1245. * send the cmd to the Push Pnr and read in the response
  1246. */
  1247. ECommSndCmd(
  1248. pDlgHdl,
  1249. Buff + COMM_N_TCP_HDR_SZ,
  1250. MsgLen,
  1251. &pRspBuff,
  1252. &RspMsgLen
  1253. );
  1254. DBGPRINT0(RPLPULL, "RplPull: Received Response from Push pnr\n");
  1255. if (Client_e == WINS_E_NMSSCV)
  1256. {
  1257. *ppRspBuff = pRspBuff;
  1258. /*--ft: 01/07/200 moved to ChkConfNUpd--
  1259. if (WinsCnf.LogDetailedEvts > 0)
  1260. {
  1261. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  1262. PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  1263. DWORD IpPartner = pAssocCtx->RemoteAdd.sin_addr.s_addr;
  1264. WinsEvtLogDetEvt(TRUE, WINS_EVT_REC_PULLED, TEXT("Verification"), __LINE__, "ddd", IpPartner, pWinsAdd->Add.IPAdd, 0);
  1265. }
  1266. --tf--*/
  1267. DBGLEAVE("RplPullPullEntries\n");
  1268. return;
  1269. }
  1270. pTmp = pRspBuff + 4; //past the opcode
  1271. PERF("Speed this up by moving it into RplPullRegRepl")
  1272. /*
  1273. * Get the no of records from the response
  1274. */
  1275. RplMsgfUfmSndEntriesRsp(
  1276. #if SUPPORT612WINS > 0
  1277. fIsPnrBeta1Wins,
  1278. #endif
  1279. &pTmp,
  1280. &NoOfRecs,
  1281. Name,
  1282. &NameLen,
  1283. &fGrp,
  1284. &NoOfAdds,
  1285. NodeAdd,
  1286. &Flag,
  1287. &TmpVersNo,
  1288. TRUE /*Is it first time*/
  1289. );
  1290. DBGPRINT1(RPLPULL, "RplPullPullEntries: No of Records pulled are (%d)\n",
  1291. NoOfRecs);
  1292. if (WinsCnf.LogDetailedEvts > 0)
  1293. {
  1294. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  1295. PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  1296. DWORD IpPartner = pAssocCtx->RemoteAdd.sin_addr.s_addr;
  1297. WinsEvtLogDetEvt(TRUE, WINS_EVT_REC_PULLED, TEXT("Pull replication"), __LINE__, "ddd", IpPartner, pWinsAdd->Add.IPAdd, NoOfRecs);
  1298. }
  1299. if (NoOfRecs > 0)
  1300. {
  1301. if (RplPullRegRepl(
  1302. Name,
  1303. NameLen,
  1304. Flag,
  1305. dwOwnerId,
  1306. TmpVersNo,
  1307. NoOfAdds,
  1308. NodeAdd,
  1309. pWinsAdd,
  1310. RplType
  1311. ) == WINS_SUCCESS)
  1312. {
  1313. VersNo = TmpVersNo;
  1314. /*
  1315. * Repeat until all replicas have been retrieved from the
  1316. * response buffer
  1317. */
  1318. for (i=1; i<NoOfRecs; i++)
  1319. {
  1320. RplMsgfUfmSndEntriesRsp(
  1321. #if SUPPORT612WINS > 0
  1322. fIsPnrBeta1Wins,
  1323. #endif
  1324. &pTmp,
  1325. &NoOfRecs,
  1326. Name,
  1327. &NameLen,
  1328. &fGrp,
  1329. &NoOfAdds, //will be > 1 only if fGrp is
  1330. // is TRUE and it is a special
  1331. //group
  1332. NodeAdd,
  1333. &Flag,
  1334. &TmpVersNo,
  1335. FALSE /*Is it first time*/
  1336. );
  1337. if (RplPullRegRepl(
  1338. Name,
  1339. NameLen,
  1340. Flag,
  1341. dwOwnerId,
  1342. TmpVersNo,
  1343. NoOfAdds,
  1344. NodeAdd,
  1345. pWinsAdd,
  1346. RplType
  1347. ) != WINS_SUCCESS)
  1348. {
  1349. DBGPRINT5(ERR, "RplPullPullEntries: Could not register record.\nName=(%s[%x])\nVersNo=(%d %d)\ndwOwnerId=(%d)\n", Name, Name[15], TmpVersNo.HighPart, TmpVersNo.LowPart, dwOwnerId);
  1350. break;
  1351. }
  1352. else
  1353. {
  1354. VersNo = TmpVersNo;
  1355. }
  1356. } //end of for (looping over all records starting from
  1357. //the second one
  1358. sfPulled = TRUE;
  1359. }
  1360. else
  1361. {
  1362. DBGPRINT5(ERR, "RplPullPullEntries: Could not register record.\nName=(%s[%x])\nVersNo=(%d %d)\ndwOwnerId=(%d)\n", Name, Name[15], TmpVersNo.HighPart, TmpVersNo.LowPart, dwOwnerId);
  1363. RetStat = WINS_FAILURE;
  1364. }
  1365. DBGPRINT2(RPLPULL,
  1366. "RplPullPullEntries. Max. Version No pulled = (%d %d)\n",
  1367. VersNo.HighPart, VersNo.LowPart
  1368. );
  1369. }
  1370. else // NoOfRecs == 0
  1371. {
  1372. DBGPRINT0(RPLPULL, "RplPullPullEntries: 0 records pulled\n");
  1373. }
  1374. //
  1375. // Let us free the response buffer
  1376. //
  1377. ECommFreeBuff(pRspBuff - COMM_HEADER_SIZE);
  1378. //
  1379. // let us store the max. version number pulled from the Push Pnr
  1380. // in the RplPullOwnerVersNo array. This array is looked at by
  1381. // the Push thread and RPC threads so we have to synchronize
  1382. // with them
  1383. //
  1384. // NOTE NOTE NOTE
  1385. // It is possible that one or more group (normal or
  1386. // special) records clashed with records in the db.
  1387. // During conflict resolution, the ownership of the
  1388. // record in the db may not get changed
  1389. // (See ClashAtReplGrpMems). Thus, even though the
  1390. // version number counter for the WINS whose replicas
  1391. // were pulled gets updated it is possible that there
  1392. // may not be any (or there may be less than what got pulled)
  1393. // records for that owner in the db. In such a
  1394. // case, a third WINS that tries to pull records owned by
  1395. // such a WINS may end up pulling 0 (or less number of) records.
  1396. // This is normal and correct behavior
  1397. //
  1398. //
  1399. //
  1400. // If the number of
  1401. // records pulled is greater than 1, update the counters.
  1402. //
  1403. if (NoOfRecs > 0)
  1404. {
  1405. if (RetStat == WINS_SUCCESS)
  1406. {
  1407. //
  1408. // fUpdCntrs will be FALSE if we have pulled as a result of a
  1409. // PULL RANGE request from the administrator. For all other
  1410. // cases, it is TRUE. If FALSE, we will update the counter
  1411. // only if the highest version number that we successfully
  1412. // pulled is greater than what is there in our counter for
  1413. // the WINS server.
  1414. //
  1415. if ( fUpdCntrs
  1416. ||
  1417. LiGtr(VersNo, (pRplPullOwnerVersNo+dwOwnerId)->VersNo)
  1418. )
  1419. {
  1420. EnterCriticalSection(&RplVersNoStoreCrtSec);
  1421. //
  1422. // NOTE: Store the max. version number pulled and not the
  1423. // MaxVersNo that we specified. This is because, if we have
  1424. // not pulled released records, then if they get changed to
  1425. // ACTIVE prior to a future replication cycle (version number
  1426. // remains unchanged when a released record changes to an
  1427. // ACTIVE record due to a name registration), we will pull them.
  1428. //
  1429. (pRplPullOwnerVersNo+dwOwnerId)->VersNo = VersNo;
  1430. LeaveCriticalSection(&RplVersNoStoreCrtSec);
  1431. //
  1432. // We will pull our own records only due to a Pull Range
  1433. // request. PullSpecifiedRange calls this function
  1434. // from inside the NmsNmhNamRegCrtSec Section.
  1435. //
  1436. if (dwOwnerId == NMSDB_LOCAL_OWNER_ID)
  1437. {
  1438. if (LiGeq(VersNo, NmsNmhMyMaxVersNo))
  1439. {
  1440. NMSNMH_INC_VERS_COUNTER_M(VersNo, NmsNmhMyMaxVersNo);
  1441. }
  1442. }
  1443. //
  1444. // If vers. number pulled is smaller than the Max. Vers no,
  1445. // specified, check if it is because of the limit we have set
  1446. // for the max. number or records that can be replicated
  1447. // at a time. If yes, pull again.
  1448. //
  1449. if (
  1450. LiLtr(VersNo, MaxVersNo)
  1451. &&
  1452. (NoOfRecs == RPL_MAX_LIMIT_FOR_RPL)
  1453. )
  1454. {
  1455. MinVersNo = VersNo;
  1456. NMSNMH_INC_VERS_NO_M(MinVersNo, MinVersNo);
  1457. /*
  1458. * We may have been signaled by the main thread
  1459. * Check it.
  1460. */
  1461. WinsMscChkTermEvt(
  1462. #ifdef WINSDBG
  1463. Client_e,
  1464. #endif
  1465. FALSE
  1466. );
  1467. continue;
  1468. }
  1469. }
  1470. } //if RetStat == 0
  1471. } // if NoOfRecs > 0
  1472. else // no of records pulled in is zero
  1473. {
  1474. //
  1475. // if the number of records pulled in is 0, then check if
  1476. // we have any records for the owner in the database.
  1477. // If there are none and fUpdCtrs is FALSE, meaning
  1478. // that this is a PULL SPECIFIED RANGE request from the
  1479. // administrator, delete the record for the owner from
  1480. // the in-memory and database tables
  1481. //
  1482. if (
  1483. (LiEqlZero((pRplPullOwnerVersNo+dwOwnerId)->VersNo))
  1484. &&
  1485. (!fUpdCntrs)
  1486. &&
  1487. (dwOwnerId != NMSDB_LOCAL_OWNER_ID)
  1488. )
  1489. {
  1490. EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
  1491. try {
  1492. (pNmsDbOwnAddTbl+dwOwnerId)->WinsState_e =
  1493. NMSDB_E_WINS_DELETED;
  1494. NmsDbWriteOwnAddTbl(
  1495. NMSDB_E_DELETE_REC,
  1496. dwOwnerId,
  1497. NULL, //address of WINS
  1498. NMSDB_E_WINS_DELETED,
  1499. NULL,
  1500. NULL
  1501. );
  1502. } // end of try
  1503. finally {
  1504. LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
  1505. }
  1506. }
  1507. break; //break out of the while loop
  1508. } // end of else
  1509. break;
  1510. } //end of while (TRUE)
  1511. DBGLEAVE("RplPullPullEntries\n");
  1512. return;
  1513. }
  1514. VOID
  1515. SubmitTimerReqs(
  1516. PRPL_CONFIG_REC_T pPullCnfRecs
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This function goes through the array of configuration records
  1521. submitting a timer request for each config. record that specifies
  1522. a time interval
  1523. Note: a single timer request is submitted for all records that
  1524. have the same time interval specified in them.
  1525. Arguments:
  1526. pPullCnfRecs - Array of Pull Configuration records
  1527. Externals Used:
  1528. None
  1529. Return Value:
  1530. None
  1531. Error Handling:
  1532. Called by:
  1533. InitRplProcess
  1534. Side Effects:
  1535. Comments:
  1536. The records in the pPullCnfRecs array are traversed in sequence
  1537. This function is called only at Init/Reconfig time
  1538. --*/
  1539. {
  1540. DBGENTER("SubmitTimerReqs\n");
  1541. try {
  1542. SetTimeReqs.NoOfSetTimeReqs = 0;
  1543. for(
  1544. ;
  1545. pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
  1546. pPullCnfRecs = (PRPL_CONFIG_REC_T) (
  1547. (LPBYTE)pPullCnfRecs + RPL_CONFIG_REC_SIZE
  1548. )
  1549. )
  1550. {
  1551. //
  1552. // Submit a timer request only if we have not submitted one
  1553. // already for the same time interval value
  1554. //
  1555. if (!pPullCnfRecs->fLinked)
  1556. {
  1557. //
  1558. // If it has an invalid time interval, check that
  1559. // it is not a one time only replication record
  1560. //
  1561. if (pPullCnfRecs->TimeInterval == RPL_INVALID_METRIC)
  1562. {
  1563. if (!pPullCnfRecs->fSpTime)
  1564. {
  1565. continue;
  1566. }
  1567. else // a specific time is given
  1568. {
  1569. //
  1570. // If Init time replication is specified,
  1571. // we must have done replication
  1572. // (in InitTimeRpl).
  1573. // We should check if SpTimeIntvl <= 0. If
  1574. // it is, we skip this record. The time for
  1575. // Specific time replication is past. In any
  1576. // case, we just pulled (in InitTimeRpl)
  1577. //
  1578. if (
  1579. (WinsCnf.PullInfo.InitTimeRpl)
  1580. &&
  1581. (pPullCnfRecs->SpTimeIntvl <= 0)
  1582. )
  1583. {
  1584. continue;
  1585. }
  1586. }
  1587. }
  1588. SubmitTimer(
  1589. NULL, //NULL means, SubmitTimer should
  1590. //allocate its own work item
  1591. pPullCnfRecs,
  1592. FALSE //it is not a resubmission
  1593. );
  1594. }
  1595. } // end of for loop
  1596. }
  1597. except(EXCEPTION_EXECUTE_HANDLER) {
  1598. DBGPRINTEXC("SubmitTimerReqs\n");
  1599. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  1600. }
  1601. DBGLEAVE("SubmitTimerReqs\n");
  1602. return;
  1603. }
  1604. VOID
  1605. SubmitTimer(
  1606. LPVOID pWrkItm,
  1607. PRPL_CONFIG_REC_T pPullCnfRec,
  1608. BOOL fResubmit
  1609. )
  1610. /*++
  1611. Routine Description:
  1612. This function is called to submit a single timer request
  1613. It is passed the address of a pull configuration record that
  1614. may have other pull config. records linked to it. Records
  1615. are linked if they require replication to happen at the same time.
  1616. Arguments:
  1617. pWrkItm - Work item to submit after initialization
  1618. pPullCnfRec - Address of a configuration record pertaining to a
  1619. Push Pnr
  1620. fResubmit - indicates whether this work item was submitted earlier (
  1621. and is now being resubmitted)
  1622. Externals Used:
  1623. None
  1624. Return Value:
  1625. None
  1626. Error Handling:
  1627. Called by:
  1628. SubmitTimerReqs(), RplPullInit()
  1629. Side Effects:
  1630. Comments:
  1631. None
  1632. --*/
  1633. {
  1634. time_t AbsTime;
  1635. DWORD TimeInt;
  1636. BOOL fTimerSet = FALSE;
  1637. DWORD LastMaxVal = 0;
  1638. LPVOID pStartOfPullGrp = pPullCnfRec;
  1639. PRPL_CONFIG_REC_T pSvPtr = pPullCnfRec;
  1640. BOOL fSubmit = TRUE;
  1641. ASSERT(pPullCnfRec);
  1642. //
  1643. // Let us check all linked records.
  1644. // We stop at the first one with a Retry Count <=
  1645. // MaxNoOfRetries specified in WinsCnf. If found, we submit a timer,
  1646. // else we return
  1647. //
  1648. for (
  1649. ;
  1650. pPullCnfRec != NULL;
  1651. pPullCnfRec = WinsCnfGetNextRplCnfRec(
  1652. pPullCnfRec,
  1653. RPL_E_VIA_LINK //get the
  1654. //linked rec
  1655. )
  1656. )
  1657. {
  1658. //
  1659. // If the number of retries have exceeded the max. no. allowed,
  1660. // check if we should submit a timer request for it now.
  1661. //
  1662. if (pPullCnfRec->RetryCount > WinsCnf.PullInfo.MaxNoOfRetries)
  1663. {
  1664. if (pPullCnfRec->RetryAfterThisManyRpl
  1665. < (DWORD)((pPullCnfRec->TimeInterval >
  1666. WINSCNF_MAX_WAIT_BEFORE_RETRY_RPL) ? 0 : WINSCNF_RETRY_AFTER_THIS_MANY_RPL
  1667. ))
  1668. {
  1669. pPullCnfRec->RetryAfterThisManyRpl++;
  1670. //
  1671. // Is this record closer to a retry than
  1672. // the any other we have seen so far. If
  1673. // yes, then save the value of the
  1674. // RetryAfterThisManyRpl field and the
  1675. // address of the record. Note: A record
  1676. // with an invalid time interval but with
  1677. // a specific time will never be encountered
  1678. // by this section of the code (because
  1679. // fSpTime will be set to FALSE -- see below;
  1680. // Also, see SubmitTimerReqs)
  1681. //
  1682. if (pPullCnfRec->RetryAfterThisManyRpl >
  1683. LastMaxVal)
  1684. {
  1685. pSvPtr = pPullCnfRec;
  1686. LastMaxVal =
  1687. pPullCnfRec->RetryAfterThisManyRpl;
  1688. }
  1689. continue; //check the next record
  1690. }
  1691. else
  1692. {
  1693. pPullCnfRec->RetryAfterThisManyRpl = 0;
  1694. //pPullCnfRec->RetryAfterThisManyRpl = 1;
  1695. pPullCnfRec->RetryCount = 0;
  1696. }
  1697. }
  1698. FUTURES("Get rid of the if below")
  1699. //
  1700. // If this is a retry and TimeInterval is valid, use the retry time
  1701. // interval. If time interval is invalid, it means that we tried
  1702. // to establish comm. at a specific time.
  1703. //
  1704. if ((pPullCnfRec->RetryCount != 0) && (pPullCnfRec->TimeInterval != RPL_INVALID_METRIC))
  1705. {
  1706. // TimeInt = WINSCNF_RETRY_TIME_INT;
  1707. TimeInt = pPullCnfRec->TimeInterval;
  1708. }
  1709. else // this is not a retry
  1710. {
  1711. //
  1712. // Specific time replication is done only once at
  1713. // the particular time specified. After that
  1714. // replication is driven by the TimeInterval value
  1715. //
  1716. if (pPullCnfRec->fSpTime)
  1717. {
  1718. TimeInt = (DWORD)pPullCnfRec->SpTimeIntvl;
  1719. pPullCnfRec->fSpTime = FALSE;
  1720. }
  1721. else
  1722. {
  1723. if (pPullCnfRec->TimeInterval
  1724. != RPL_INVALID_METRIC)
  1725. {
  1726. TimeInt = pPullCnfRec->TimeInterval;
  1727. }
  1728. else
  1729. {
  1730. //
  1731. // Since we have submitted a request
  1732. // for all records in this chain
  1733. // atleast once, break out of the
  1734. // loop (All records in this chain
  1735. // have an invalid time interval).
  1736. //
  1737. fSubmit = FALSE;
  1738. break; // we have already submitted
  1739. // this one time only request
  1740. }
  1741. }
  1742. }
  1743. //
  1744. // Set fTimerSet to TRUE to indicate that there is atleast
  1745. // one partner for which we will be submitting a timer request.
  1746. //
  1747. fTimerSet = TRUE;
  1748. //
  1749. // We need to submit the request. Break out of the loop
  1750. //
  1751. break;
  1752. }
  1753. //
  1754. // Do we need to submit a timer request
  1755. //
  1756. if (fSubmit)
  1757. {
  1758. //
  1759. // If fTimerSet is FALSE,
  1760. // it means that communication could not be established
  1761. // with any member of the group (despite WinsCnf.MaxNoOfRetries
  1762. // retries with each). We should compute the time interval to the
  1763. // earliest retry that we should do.
  1764. //
  1765. if (!fTimerSet)
  1766. {
  1767. // fixes #391314
  1768. if (WINSCNF_RETRY_AFTER_THIS_MANY_RPL == pSvPtr->RetryAfterThisManyRpl)
  1769. {
  1770. TimeInt = pSvPtr->TimeInterval;
  1771. }
  1772. else
  1773. {
  1774. TimeInt = pSvPtr->TimeInterval *
  1775. (WINSCNF_RETRY_AFTER_THIS_MANY_RPL -
  1776. pSvPtr->RetryAfterThisManyRpl);
  1777. }
  1778. pSvPtr->RetryAfterThisManyRpl = 0;
  1779. pSvPtr->RetryCount = 0;
  1780. }
  1781. (void)time(&AbsTime);
  1782. if( pSvPtr->LastRplTime == 0 ) {
  1783. //
  1784. // This is our first replication. Just add the interval to
  1785. // the current time.
  1786. //
  1787. AbsTime += TimeInt;
  1788. pSvPtr->LastRplTime = AbsTime;
  1789. } else {
  1790. //
  1791. // We have replicated before. We need to make sure that
  1792. // our replication time is at an interval based on the time
  1793. // the last replication started.
  1794. //
  1795. do {
  1796. pSvPtr->LastRplTime += TimeInt;
  1797. } while( pSvPtr->LastRplTime <= AbsTime );
  1798. AbsTime = pSvPtr->LastRplTime;
  1799. }
  1800. DBGPRINT3(RPLPULL, "SubmitTimer: %s a Timer Request for (%d) secs to expire at abs. time = (%d)\n",
  1801. fResubmit ? "Resubmitting" : "Submitting", TimeInt, AbsTime);
  1802. WinsTmmInsertEntry(
  1803. pWrkItm,
  1804. WINS_E_RPLPULL,
  1805. QUE_E_CMD_SET_TIMER,
  1806. fResubmit,
  1807. AbsTime,
  1808. TimeInt,
  1809. &QueRplPullQueHd,
  1810. pStartOfPullGrp,
  1811. pSvPtr->MagicNo,
  1812. &SetTimeReqs
  1813. );
  1814. }
  1815. return;
  1816. }
  1817. VOID
  1818. SndPushNtf(
  1819. PQUE_RPL_REQ_WRK_ITM_T pWrkItm
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. This function is called to push a notification to a remote WINS (Pull
  1824. Partner) that a certain number of updates have been done.
  1825. It can be called either as a result of a version number update or from
  1826. HdlPushNtf() to propagate a net trigger.
  1827. Arguments:
  1828. pConfigRec - Configuration record of the Push Pnr to whome the
  1829. notification needs to be sent
  1830. Externals Used:
  1831. None
  1832. Return Value:
  1833. None
  1834. Error Handling:
  1835. Called by:
  1836. RplPullInit()
  1837. Side Effects:
  1838. Comments:
  1839. None
  1840. --*/
  1841. {
  1842. LPBYTE pBuff;
  1843. DWORD MsgLen;
  1844. COMM_HDL_T DlgHdl;
  1845. DWORD i;
  1846. PRPL_ADD_VERS_NO_T pPullAddVersNoTbl;
  1847. PRPL_ADD_VERS_NO_T pPullAddVersNoTblTmp;
  1848. PCOMM_ADD_T pWinsAdd;
  1849. PNMSDB_WINS_STATE_E pWinsState_e;
  1850. PVERS_NO_T pStartVersNo;
  1851. time_t CurrentTime;
  1852. BOOL fStartDlg = FALSE;
  1853. volatile PRPL_CONFIG_REC_T pConfigRec = pWrkItm->pClientCtx;
  1854. DWORD NoOfOwnersActive = 0;
  1855. #if SUPPORT612WINS > 0
  1856. BOOL fIsPnrBeta1Wins;
  1857. #endif
  1858. DWORD StartOwnerId;
  1859. DWORD EndOwnerId;
  1860. BOOL fPullAddVersNoTblAlloc = FALSE;
  1861. DWORD SizeOfBuff;
  1862. BOOL fBuffAlloc = FALSE;
  1863. #if PRSCONN
  1864. BOOL fDlgActive = TRUE;
  1865. #endif
  1866. RPLMSGF_MSG_OPCODE_E Opcd_e;
  1867. DBGENTER("SndPushNtf\n");
  1868. //
  1869. // No need for entering a critical section while using pConfigRec,
  1870. // since only the Pull thread deallocates it on reconfiguration
  1871. // (check Reconfig)
  1872. //
  1873. //
  1874. // Check whether we want to try sending or not. We will not try if
  1875. // we have had 2 comm. failure in the past 5 mts. This is to guard
  1876. // against the case where a lot of push request get queued up for
  1877. // the pull thread for communicating with a wins with which comm
  1878. // has been lost.
  1879. //
  1880. (void)time(&CurrentTime);
  1881. #define PUSH_TRY_LIMIT 2
  1882. if (
  1883. ((CurrentTime - pConfigRec->LastCommFailTime) < FIVE_MINUTES)
  1884. &&
  1885. (pConfigRec->PushNtfTries >= PUSH_TRY_LIMIT) //try two times
  1886. )
  1887. {
  1888. 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",
  1889. pConfigRec->PushNtfTries,
  1890. pConfigRec->WinsAdd.Add.IPAdd);
  1891. WINSEVT_LOG_D_M(pConfigRec->WinsAdd.Add.IPAdd, WINS_EVT_NO_NTF_PERS_COMM_FAIL);
  1892. return;
  1893. }
  1894. //
  1895. // If it is a push notification without propagate, we should send all
  1896. // our maps. If it is a push with propagate, we should send only one
  1897. // map -- If we are initiating the trigger, we should send map of
  1898. // records owned by us. If not, we should send the map of records
  1899. // owned by the WINS that initiated the trigger
  1900. //
  1901. if ( pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF)
  1902. {
  1903. StartOwnerId = 0;
  1904. EndOwnerId = StartOwnerId + NmsDbNoOfOwners;
  1905. }
  1906. else
  1907. {
  1908. BOOL fAllocNew = FALSE;
  1909. COMM_ADD_T WinsAdd;
  1910. STATUS RetStat;
  1911. //
  1912. // If we are propagating a net trigger and the address in pMsg is
  1913. // not our own, it means that the trigger came from a new WINS. If
  1914. // it is our own, it means that the trigger came from an old WINS(3.5)
  1915. // or 3.51 beta/RC1. In this case we should send all of our maps.
  1916. //
  1917. if (
  1918. (pWrkItm->pMsg)
  1919. &&
  1920. (PtrToUlong(pWrkItm->pMsg) != NmsLocalAdd.Add.IPAdd)
  1921. )
  1922. {
  1923. //
  1924. // we are propagating a net trigger. pMsg above will not be NULL
  1925. // only if we are propagating a net trigger
  1926. //
  1927. COMM_INIT_ADD_M(&WinsAdd, PtrToUlong(pWrkItm->pMsg));
  1928. RetStat = RplFindOwnerId(
  1929. &WinsAdd,
  1930. &fAllocNew, //don't assign
  1931. &StartOwnerId,
  1932. WINSCNF_E_IGNORE_PREC,
  1933. WINSCNF_LOW_PREC
  1934. );
  1935. if (RetStat == WINS_FAILURE)
  1936. {
  1937. ASSERTMSG("DROPPING PROPAGATE\n", FALSE);
  1938. //
  1939. // log an event and return
  1940. //
  1941. 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);
  1942. return;
  1943. }
  1944. EndOwnerId = StartOwnerId + 1;
  1945. }
  1946. else
  1947. {
  1948. //
  1949. // Either we are initiating the trigger or we are propagating
  1950. // one sent by a 3.5 or a 3.51 BETA/RC1 WINS
  1951. //
  1952. if (!pWrkItm->pMsg)
  1953. {
  1954. //
  1955. // We are initiating a trigger. Just send one map (records
  1956. // owned by us)
  1957. //
  1958. StartOwnerId = 0;
  1959. EndOwnerId = 1;
  1960. }
  1961. else
  1962. {
  1963. //
  1964. // Send all the maps except our own since we don't know who
  1965. // initiated the trigger. Not sending ours lowers the
  1966. // probability of this trigger process continuing indefinitely
  1967. //
  1968. //
  1969. // Actually no need to test this since we will never
  1970. // have this case (HdlPushNtf() must have pulled records
  1971. // of atleast one other WINS).
  1972. //
  1973. if (NmsDbNoOfOwners == 1)
  1974. {
  1975. //
  1976. // nothing to propagate. Just return
  1977. //
  1978. return;
  1979. }
  1980. else
  1981. {
  1982. StartOwnerId = 1;
  1983. }
  1984. EndOwnerId = NmsDbNoOfOwners;
  1985. }
  1986. }
  1987. }
  1988. //
  1989. // If we are trying after a comm. failure
  1990. //
  1991. if (pConfigRec->PushNtfTries == PUSH_TRY_LIMIT)
  1992. {
  1993. pConfigRec->PushNtfTries = 0;
  1994. }
  1995. FUTURES("If/When we start having persistent dialogues, we should check if we")
  1996. FUTURES("already have a dialogue with the WINS. If there is one, we should")
  1997. FUTURES("use that. To find this out, loop over all Pull Config Recs to see")
  1998. FUTURES("if there is match (use the address as the search key")
  1999. try {
  2000. #if PRSCONN
  2001. //
  2002. // If the pnr is not a persistent pnr or if it is one but the dlg with it
  2003. // is not active
  2004. //
  2005. if (
  2006. (!pConfigRec->fPrsConn)
  2007. ||
  2008. !ECommIsBlockValid(&pConfigRec->PrsDlgHdl)
  2009. ||
  2010. (((CurrentTime - pConfigRec->LastCommTime) > FIVE_MINUTES) &&
  2011. !(fDlgActive = ECommIsDlgActive(&pConfigRec->PrsDlgHdl)))
  2012. )
  2013. {
  2014. if (!fDlgActive)
  2015. {
  2016. ECommEndDlg(&pConfigRec->PrsDlgHdl);
  2017. }
  2018. //
  2019. // Init the pEnt field to NULL so that ECommEndDlg (in the
  2020. // exception handler) called as a result of an exception from
  2021. // behaves fine.
  2022. //
  2023. DlgHdl.pEnt = NULL;
  2024. //
  2025. // Start a dialogue. Don't retry if there is comm. failure
  2026. //
  2027. ECommStartDlg(
  2028. &pConfigRec->WinsAdd,
  2029. COMM_E_RPL,
  2030. &DlgHdl
  2031. );
  2032. //
  2033. // If the pnr is not NT 5, we can not send a PRS opcode to it (it will just
  2034. // chuck it. The macro below will set the fPrsConn field of the partner
  2035. // record to FALSE if the partner is not an NT 5+ partner
  2036. //
  2037. if (pConfigRec->fPrsConn)
  2038. {
  2039. ECOMM_IS_PNR_POSTNT4_WINS_M(&DlgHdl, pConfigRec->fPrsConn);
  2040. }
  2041. if (pConfigRec->fPrsConn)
  2042. {
  2043. pConfigRec->PrsDlgHdl = DlgHdl;
  2044. }
  2045. }
  2046. else
  2047. {
  2048. DlgHdl = pConfigRec->PrsDlgHdl;
  2049. }
  2050. #else
  2051. //
  2052. // Init the pEnt field to NULL so that ECommEndDlg (in the
  2053. // exception handler) called as a result of an exception from
  2054. // behaves fine.
  2055. //
  2056. DlgHdl.pEnt = NULL;
  2057. //
  2058. // Start a dialogue. Don't retry if there is comm. failure
  2059. //
  2060. ECommStartDlg(
  2061. &pConfigRec->WinsAdd,
  2062. COMM_E_RPL,
  2063. &DlgHdl
  2064. );
  2065. #endif
  2066. fStartDlg = TRUE;
  2067. pConfigRec->LastCommFailTime = 0;
  2068. if (pConfigRec->PushNtfTries > 0)
  2069. {
  2070. pConfigRec->PushNtfTries = 0;
  2071. }
  2072. /*
  2073. * Get the max. version no for entries owned by self
  2074. * No need to enter a critical section before retrieving
  2075. * the version number.
  2076. *
  2077. * The reason we subtract 1 from NmsNmhMyMaxVersNo is because
  2078. * it contains the version number to be given to the next record
  2079. * to be registered/updated.
  2080. */
  2081. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  2082. EnterCriticalSection(&RplVersNoStoreCrtSec);
  2083. NMSNMH_DEC_VERS_NO_M(
  2084. NmsNmhMyMaxVersNo,
  2085. pRplPullOwnerVersNo->VersNo
  2086. );
  2087. LeaveCriticalSection(&RplVersNoStoreCrtSec);
  2088. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  2089. WinsMscAlloc(
  2090. sizeof(RPL_ADD_VERS_NO_T) * (EndOwnerId - StartOwnerId),
  2091. (LPVOID *)&pPullAddVersNoTbl
  2092. );
  2093. fPullAddVersNoTblAlloc = TRUE;
  2094. //
  2095. // Initialize PullAddVersNoTbl array
  2096. //
  2097. for (i=StartOwnerId; i < EndOwnerId; i++)
  2098. {
  2099. RPL_FIND_ADD_BY_OWNER_ID_M(i, pWinsAdd, pWinsState_e, pStartVersNo);
  2100. if (*pWinsState_e == NMSDB_E_WINS_ACTIVE)
  2101. {
  2102. (pPullAddVersNoTbl + NoOfOwnersActive)->VersNo = (pRplPullOwnerVersNo+i)->VersNo;
  2103. (pPullAddVersNoTbl + NoOfOwnersActive)->OwnerWinsAdd = *pWinsAdd;
  2104. NoOfOwnersActive++;
  2105. }
  2106. }
  2107. #if SUPPORT612WINS > 0
  2108. COMM_IS_PNR_BETA1_WINS_M(&DlgHdl, fIsPnrBeta1Wins);
  2109. #endif
  2110. //
  2111. // format the Push notification message. This message is exactly same
  2112. // as the Address to Version Number Mapping message except the opcode
  2113. //
  2114. SizeOfBuff = RPLMSGF_ADDVERSMAP_RSP_SIZE_M(NoOfOwnersActive);
  2115. WinsMscAlloc(SizeOfBuff, (LPVOID *)&pBuff);
  2116. fBuffAlloc = TRUE;
  2117. #if PRSCONN
  2118. //
  2119. // Send a PRS opcode if we are supposed to be forming a persistent conn
  2120. //
  2121. if (pConfigRec->fPrsConn)
  2122. {
  2123. Opcd_e = (pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF) ? RPLMSGF_E_UPDATE_NTF_PRS : RPLMSGF_E_UPDATE_NTF_PROP_PRS;
  2124. }
  2125. else
  2126. #endif
  2127. {
  2128. Opcd_e = (pWrkItm->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF) ? RPLMSGF_E_UPDATE_NTF : RPLMSGF_E_UPDATE_NTF_PROP;
  2129. }
  2130. RplMsgfFrmAddVersMapRsp(
  2131. #if SUPPORT612WINS > 0
  2132. fIsPnrBeta1Wins,
  2133. #endif
  2134. Opcd_e,
  2135. pBuff + COMM_N_TCP_HDR_SZ,
  2136. SizeOfBuff - COMM_N_TCP_HDR_SZ,
  2137. pPullAddVersNoTbl,
  2138. NoOfOwnersActive,
  2139. (pWrkItm->pMsg != NULL) ? PtrToUlong(pWrkItm->pMsg) : NmsLocalAdd.Add.IPAdd,
  2140. //
  2141. // pMsg above will be Non-NULL only for the case
  2142. // when we are propagating the net upd. ntf.
  2143. //
  2144. &MsgLen
  2145. );
  2146. //
  2147. // send the message to the remote WINS. Use an existent dialogue
  2148. // if there with the remote WINS
  2149. //
  2150. ECommSendMsg(
  2151. &DlgHdl,
  2152. NULL, //no need for address since this is a TCP conn
  2153. pBuff + COMM_N_TCP_HDR_SZ,
  2154. MsgLen
  2155. );
  2156. #if PRSCONN
  2157. pConfigRec->LastCommTime = CurrentTime;
  2158. if (!pConfigRec->fPrsConn)
  2159. #endif
  2160. {
  2161. //
  2162. // Ask ComSys (TCP listener thread) to monitor the dialogue
  2163. //
  2164. ECommProcessDlg(
  2165. &DlgHdl,
  2166. COMM_E_NTF_START_MON
  2167. );
  2168. }
  2169. } // end of try {..}
  2170. except(EXCEPTION_EXECUTE_HANDLER) {
  2171. DWORD ExcCode = GetExceptionCode();
  2172. DBGPRINT2(EXC, "SndPushNtf -PULL thread. Got Exception (%x). WinsAdd = (%x)\n", ExcCode, pConfigRec->WinsAdd.Add.IPAdd);
  2173. WINSEVT_LOG_M(ExcCode, WINS_EVT_RPLPULL_PUSH_NTF_EXC);
  2174. if (ExcCode == WINS_EXC_COMM_FAIL)
  2175. {
  2176. pConfigRec->LastCommFailTime = CurrentTime;
  2177. NOTE("Causes an access violation when compiled with no debugs. Haven't")
  2178. NOTE("figured out why. This code is not needed")
  2179. pConfigRec->PushNtfTries++; //increment count of tries.
  2180. }
  2181. if (fStartDlg)
  2182. {
  2183. //
  2184. // End the dialogue.
  2185. //
  2186. ECommEndDlg(&DlgHdl);
  2187. #if PRSCONN
  2188. if (pConfigRec->fPrsConn)
  2189. {
  2190. ECOMM_INIT_DLG_HDL_M(&(pConfigRec->PrsDlgHdl));
  2191. }
  2192. #endif
  2193. }
  2194. } //end of exception handler
  2195. if (fPullAddVersNoTblAlloc)
  2196. {
  2197. WinsMscDealloc(pPullAddVersNoTbl);
  2198. }
  2199. //
  2200. // If this is a temporary configuration record, we need to deallocate it
  2201. // It can be a temporary config. record only if
  2202. // 1)We are executing here due to an rpc request
  2203. //
  2204. if (pConfigRec->fTemp)
  2205. {
  2206. WinsMscDealloc(pConfigRec);
  2207. }
  2208. //
  2209. // dealloc the buffer we allocated
  2210. //
  2211. if (fBuffAlloc)
  2212. {
  2213. WinsMscDealloc(pBuff);
  2214. }
  2215. //
  2216. // In the normal case, the connection will be terminated by the other side.
  2217. //
  2218. DBGLEAVE("SndPushNtf\n");
  2219. return;
  2220. }
  2221. VOID
  2222. EstablishComm(
  2223. IN PRPL_CONFIG_REC_T pPullCnfRecs,
  2224. IN BOOL fAllocPushPnrData,
  2225. IN PPUSHPNR_DATA_T *ppPushPnrData,
  2226. IN RPL_REC_TRAVERSAL_E RecTrv_e,
  2227. OUT LPDWORD pNoOfPushPnrs
  2228. )
  2229. /*++
  2230. Routine Description:
  2231. This function is called to establish communications with
  2232. all the WINS servers i(Push Pnrs) specified by the the config records
  2233. Arguments:
  2234. pPullCnfRecs - Pull Config records
  2235. pPushPnrData - Array of data records each pertaining to a PUSH pnr
  2236. RecTrv_e - indicates whether the list of configuration records
  2237. is to be traversed in sequence
  2238. pNoOfPushPnrs - No of Push Pnrs
  2239. Externals Used:
  2240. None
  2241. Return Value:
  2242. VOID
  2243. Error Handling:
  2244. Called by:
  2245. GetReplicasNew
  2246. Side Effects:
  2247. Comments:
  2248. On return from this function, pPushPnrData will have zero or more
  2249. partners starting from index 0 with which dlg could be started.
  2250. PushPnrId will start from 1 (if dlg. could be established with
  2251. atleast one partner) and can be any number in the range 1
  2252. to MAX_RPL_OWNERS (the number indicates the iteration of the for
  2253. loop at which this WINS was encountered)
  2254. --*/
  2255. {
  2256. #define INITIAL_NO_OF_PNRS 30
  2257. volatile DWORD i;
  2258. volatile DWORD NoOfRetries = 0;
  2259. DWORD TotNoOfPushPnrSlots = INITIAL_NO_OF_PNRS;
  2260. PPUSHPNR_DATA_T pPushPnrData;
  2261. #if PRSCONN
  2262. time_t CurrentTime;
  2263. BOOL fDlgActive;
  2264. #endif
  2265. DBGENTER("EstablishComm\n");
  2266. *pNoOfPushPnrs = 0;
  2267. //
  2268. // if the client wants this function to allocate pPushPnrData
  2269. //
  2270. if (fAllocPushPnrData)
  2271. {
  2272. WinsMscAlloc(sizeof(PUSHPNR_DATA_T) * TotNoOfPushPnrSlots, (LPVOID *)ppPushPnrData);
  2273. }
  2274. pPushPnrData = *ppPushPnrData;
  2275. /*
  2276. Start a dialogue with all Push Partners specified in the
  2277. Pull Cnf Recs passed as input argument and get
  2278. the version numbers of the different owners kept
  2279. in the database of these Push Pnrs
  2280. i = 0 for self's data
  2281. */
  2282. #if PRSCONN
  2283. (void)time(&CurrentTime);
  2284. #endif
  2285. for (
  2286. i = 1;
  2287. pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
  2288. // no third expression
  2289. )
  2290. {
  2291. try
  2292. {
  2293. #if PRSCONN
  2294. fDlgActive = TRUE;
  2295. //
  2296. // If this partner is not a persistent conn. pnr or if he is one
  2297. // but the dlg that we have with it is not valid, start a dlg
  2298. // with him. A dlg may not be valid either because we never
  2299. // formed one with pnr or because it got disconnected as
  2300. // a result of the pnr terminating.
  2301. //
  2302. // there is a corner case: two servers, A<->B replication partners
  2303. // A pulls records from B and then on B WINS is restarted. Then, any
  2304. // communication that A attempts with B in less than five minutes will
  2305. // fail. This is because A will still think the connection is up.
  2306. // A can't do otherwise, because there would be too much overhead in
  2307. // testing each time the TCP connection (see CommIsDlgActive).
  2308. // This check has to be done at least at certain intervals (5min).
  2309. if (
  2310. (!pPullCnfRecs->fPrsConn)
  2311. ||
  2312. !ECommIsBlockValid(&pPullCnfRecs->PrsDlgHdl)
  2313. ||
  2314. (((CurrentTime - pPullCnfRecs->LastCommTime) > FIVE_MINUTES) &&
  2315. !(fDlgActive = ECommIsDlgActive(&pPullCnfRecs->PrsDlgHdl)))
  2316. )
  2317. {
  2318. //
  2319. // if the dlg is gone, end it so that the dlg block gets
  2320. // deallocated.
  2321. //
  2322. if (!fDlgActive)
  2323. {
  2324. ECommEndDlg(&pPullCnfRecs->PrsDlgHdl);
  2325. }
  2326. #endif
  2327. //
  2328. // Let us make sure that we don't try to establish
  2329. // communications with a WINS whose retry count is
  2330. // over. If this is such a WINS's record, get the
  2331. // next WINS's record and continue. If there is
  2332. // no WINS left to establish comm with, break out of
  2333. // the for loop
  2334. //
  2335. //
  2336. if (pPullCnfRecs->RetryCount > WinsCnf.PullInfo.MaxNoOfRetries)
  2337. {
  2338. pPullCnfRecs = WinsCnfGetNextRplCnfRec(
  2339. pPullCnfRecs,
  2340. RecTrv_e
  2341. );
  2342. if (pPullCnfRecs == NULL)
  2343. {
  2344. break; // break out of the for loop
  2345. }
  2346. continue;
  2347. }
  2348. ECommStartDlg(
  2349. &pPullCnfRecs->WinsAdd,
  2350. COMM_E_RPL,
  2351. &pPushPnrData->DlgHdl
  2352. );
  2353. pPushPnrData->fDlgStarted = TRUE;
  2354. #if PRSCONN
  2355. //
  2356. // If the dlg is supposed to be persistent, store it as such
  2357. //
  2358. if (pPullCnfRecs->fPrsConn)
  2359. {
  2360. pPullCnfRecs->PrsDlgHdl = pPushPnrData->DlgHdl;
  2361. pPushPnrData->fPrsConn = TRUE;
  2362. }
  2363. }
  2364. else //There is a pers dlg and it is very much active
  2365. {
  2366. pPushPnrData->DlgHdl = pPullCnfRecs->PrsDlgHdl;
  2367. pPushPnrData->fPrsConn = TRUE;
  2368. pPushPnrData->fDlgStarted = TRUE;
  2369. //
  2370. // No need to set fPrsConn field of PushPnrData to FALSE
  2371. // Memory is initialized to 0 by default
  2372. //
  2373. }
  2374. //
  2375. // It is ok to set it here as against after the data is sent
  2376. //
  2377. pPullCnfRecs->LastCommTime = CurrentTime;
  2378. #endif
  2379. pPushPnrData->RplType = pPullCnfRecs->RplType;
  2380. //
  2381. // Note: Don't use RplFindOwnerId to get the owner id.
  2382. // corresponding to the Wins with which communication
  2383. // is being established because doing so will create an
  2384. // entry for the WINS in the table. If this partner
  2385. // turns out to be bogus, we will have to remove
  2386. // the entry later.
  2387. //
  2388. // We will do this later.
  2389. //
  2390. pPushPnrData->PushPnrId = i;
  2391. pPushPnrData->WinsAdd = pPullCnfRecs->WinsAdd;
  2392. pPushPnrData->pPullCnfRec = pPullCnfRecs;
  2393. //
  2394. // we were able to establish comm., so let us init the
  2395. // LastCommFailTime to 0. NOTE: Currently, this field
  2396. // is not used for pull partners.
  2397. //
  2398. pPullCnfRecs->LastCommFailTime = 0;
  2399. //
  2400. // Reset the retry counter back to 0
  2401. //
  2402. NoOfRetries = 0;
  2403. (VOID)InterlockedIncrement(&pPullCnfRecs->NoOfRpls);
  2404. //
  2405. // reinit Retry Count to 0
  2406. //
  2407. pPullCnfRecs->RetryCount = 0;
  2408. //
  2409. // Note: These should get incremented only if there is
  2410. // no exception. That is why they are here versus in the
  2411. // as expr3 of the for clause
  2412. //
  2413. pPushPnrData++;
  2414. (*pNoOfPushPnrs)++;
  2415. if (fAllocPushPnrData && (*pNoOfPushPnrs == TotNoOfPushPnrSlots))
  2416. {
  2417. WINSMSC_REALLOC_M(sizeof(PUSHPNR_DATA_T) * (TotNoOfPushPnrSlots * 2), ppPushPnrData);
  2418. pPushPnrData = (*ppPushPnrData) + TotNoOfPushPnrSlots;
  2419. TotNoOfPushPnrSlots *= 2;
  2420. }
  2421. i++;
  2422. WinsMscChkTermEvt(
  2423. #ifdef WINSDBG
  2424. WINS_E_RPLPULL,
  2425. #endif
  2426. FALSE
  2427. );
  2428. //
  2429. // Note: the following
  2430. // is required even when an exception is raised. Therefore
  2431. // it is repeated inside the exception handler code.
  2432. //
  2433. pPullCnfRecs = WinsCnfGetNextRplCnfRec(
  2434. pPullCnfRecs,
  2435. RecTrv_e
  2436. );
  2437. if (pPullCnfRecs == NULL)
  2438. {
  2439. break; // break out of the for loop
  2440. }
  2441. } // end of try blk
  2442. except(EXCEPTION_EXECUTE_HANDLER) {
  2443. DBGPRINTEXC("EstablishComm");
  2444. if (GetExceptionCode() == WINS_EXC_COMM_FAIL)
  2445. {
  2446. #ifdef WINSDBG
  2447. struct in_addr InAddr;
  2448. InAddr.s_addr = htonl( pPullCnfRecs->WinsAdd.Add.IPAdd );
  2449. DBGPRINT1(EXC, "EstablishComm: Got a comm. fail with WINS at address = (%s)\n", inet_ntoa(InAddr));
  2450. #endif
  2451. WinsMscChkTermEvt(
  2452. #ifdef WINSDBG
  2453. WINS_E_RPLPULL,
  2454. #endif
  2455. FALSE
  2456. );
  2457. //
  2458. // Store the time (for use in SndPushNtf)
  2459. //
  2460. #if PRSCONN
  2461. pPullCnfRecs->LastCommFailTime = CurrentTime;
  2462. #else
  2463. (VOID)time(&(pPullCnfRecs->LastCommFailTime));
  2464. #endif
  2465. //
  2466. // Check if we have exhausted the max. no. of retries
  2467. // we are allowed in one replication cycle. If not,
  2468. // sleep for some time (20sec) and try again..
  2469. //
  2470. // --ft: 07/10: comment out this piece of code since
  2471. // MAX_RETRIES_TO_BE_DONE is set to 0 (#def)
  2472. //
  2473. //if (NoOfRetries < MAX_RETRIES_TO_BE_DONE)
  2474. //{
  2475. // // Maybe the remote WINS is coming up. We should
  2476. // // give it a chance to come up. Let us sleep for
  2477. // // some time.
  2478. // //
  2479. // Sleep(RETRY_TIME_INTVL);
  2480. // NoOfRetries++;
  2481. // continue;
  2482. //}
  2483. (VOID)InterlockedIncrement(&pPullCnfRecs->NoOfCommFails);
  2484. //
  2485. // Only Communication failure exception is to
  2486. // be consumed.
  2487. //
  2488. // We will retry at the next replication time.
  2489. //
  2490. // Note: the comparison operator needs to be <= and not
  2491. // < (this is required for the 0 retry case). If we
  2492. // use <, a timer request would be submitted for
  2493. // the WINS (by SubmitTimerReqs following GetReplicasNew
  2494. // in RplPullInit which will result in a retry.
  2495. //
  2496. if (pPullCnfRecs->RetryCount <= WinsCnf.PullInfo.MaxNoOfRetries)
  2497. {
  2498. pPullCnfRecs->RetryCount++;
  2499. //
  2500. // We will now retry at the next
  2501. // replication time.
  2502. //
  2503. CHECK("A retry time interval different than the replication time interval")
  2504. CHECK("could be used here. Though this will complicate the code, it may")
  2505. CHECK("be a good idea to do it if the replication time interval is large")
  2506. CHECK("Alternatively, considering that we have already retried a certain")
  2507. CHECK("no. of times, we can put the onus on the administrator to trigger")
  2508. CHECK("replication. I need to think this some more")
  2509. }
  2510. else //max. no of retries done
  2511. {
  2512. WINSEVT_LOG_M(
  2513. WINS_FAILURE,
  2514. WINS_EVT_CONN_RETRIES_FAILED
  2515. );
  2516. DBGPRINT0(ERR, "Could not connect to WINS. All retries failed\n");
  2517. }
  2518. //
  2519. // Go to the next configuration record based on the
  2520. // value of the RecTrv_e flag
  2521. //
  2522. pPullCnfRecs = WinsCnfGetNextRplCnfRec(
  2523. pPullCnfRecs,
  2524. RecTrv_e
  2525. );
  2526. if (pPullCnfRecs == NULL)
  2527. {
  2528. break; //break out of the for loop
  2529. }
  2530. }
  2531. else
  2532. {
  2533. //
  2534. // A non comm failure error is serious. It needs
  2535. // to be propagated up
  2536. //
  2537. WINS_RERAISE_EXC_M();
  2538. }
  2539. } //end of exception handler
  2540. } // end of for loop for looping over config records
  2541. DBGLEAVE("EstablishComm\n");
  2542. return;
  2543. }
  2544. VOID
  2545. HdlPushNtf(
  2546. PQUE_RPL_REQ_WRK_ITM_T pWrkItm
  2547. )
  2548. /*++
  2549. Routine Description:
  2550. This function is called to handle a push notification received from
  2551. a remote WINS.
  2552. Arguments:
  2553. pWrkItm - the work item that the Pull thread pulled from its queue
  2554. Externals Used:
  2555. None
  2556. Return Value:
  2557. None
  2558. Error Handling:
  2559. Called by:
  2560. RplPullInit
  2561. Side Effects:
  2562. Comments:
  2563. None
  2564. --*/
  2565. {
  2566. BOOL fFound = FALSE;
  2567. PUSHPNR_DATA_T PushPnrData[1];
  2568. DWORD OwnerId;
  2569. DWORD i;
  2570. VERS_NO_T MinVersNo;
  2571. VERS_NO_T MaxVersNo;
  2572. RPLMSGF_MSG_OPCODE_E Opcode_e;
  2573. BOOL fPulled = FALSE;
  2574. BOOL fAllocNew;
  2575. #if SUPPORT612WINS > 0
  2576. BOOL fIsPnrBeta1Wins;
  2577. #endif
  2578. DWORD InitiatorWinsIpAdd;
  2579. #if PRSCONN
  2580. BOOL fImplicitConnPrs;
  2581. time_t CurrentTime;
  2582. BOOL fDlgActive = TRUE;
  2583. COMM_HDL_T DlgHdl;
  2584. PCOMM_HDL_T pDlgHdl = &DlgHdl;
  2585. PRPL_CONFIG_REC_T pPnr;
  2586. #endif
  2587. DWORD ExcCode = WINS_EXC_INIT;
  2588. DBGENTER("HdlPushNtf - PULL thread\n");
  2589. #if SUPPORT612WINS > 0
  2590. COMM_IS_PNR_BETA1_WINS_M(&pWrkItm->DlgHdl, fIsPnrBeta1Wins);
  2591. #endif
  2592. #if 0
  2593. COMM_INIT_ADD_FROM_DLG_HDL_M(&PnrAdd, pWrkItm->DlgHdl);
  2594. #endif
  2595. //
  2596. // We want to pull all records starting from the min vers. no.
  2597. //
  2598. WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
  2599. //
  2600. // Get the opcode from the message
  2601. //
  2602. RPLMSGF_GET_OPC_FROM_MSG_M(pWrkItm->pMsg, Opcode_e);
  2603. //
  2604. // Unformat the message to get the owner to version number maps
  2605. //
  2606. RplMsgfUfmAddVersMapRsp(
  2607. #if SUPPORT612WINS > 0
  2608. fIsPnrBeta1Wins,
  2609. #endif
  2610. pWrkItm->pMsg + 4, //past the opcodes
  2611. &(PushPnrData[0].NoOfMaps),
  2612. &InitiatorWinsIpAdd, //Wins that initiated
  2613. //the prop
  2614. &PushPnrData[0].pAddVers
  2615. );
  2616. //
  2617. // Free the buffer that carried the message. We don't need it anymore
  2618. //
  2619. ECommFreeBuff(pWrkItm->pMsg - COMM_HEADER_SIZE); //decrement to
  2620. // begining
  2621. //of buff
  2622. #if PRSCONN
  2623. (VOID)time(&CurrentTime);
  2624. //
  2625. // We determine whether or not the partner has formed a persistent
  2626. // connection with us from the opcode
  2627. //
  2628. fImplicitConnPrs = ((Opcode_e == RPLMSGF_E_UPDATE_NTF_PRS) || (Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP_PRS));
  2629. FUTURES("When we start having persistent dialogues, we should check if we")
  2630. FUTURES("already have a dialogue with the WINS. If there is one, we should")
  2631. FUTURES("use that. To find this out, loop over all Pull Config Recs to see")
  2632. FUTURES("if there is match (use the address as the search key")
  2633. //
  2634. // If the connection formed with us is persistent, get the
  2635. // config record or the pnr. Nobody can change the config
  2636. // rec array except the current thread (pull thread)
  2637. //
  2638. if (fImplicitConnPrs)
  2639. {
  2640. if ((pPnr = RplGetConfigRec(RPL_E_PULL, &pWrkItm->DlgHdl,NULL)) != NULL)
  2641. {
  2642. //
  2643. // if the pnr is not persistent for pulling or if it
  2644. // is persistent but the dlg is invalid, start it. Store
  2645. // the dlg hdl in a temp var.
  2646. //
  2647. if ((!pPnr->fPrsConn)
  2648. ||
  2649. !ECommIsBlockValid(&pPnr->PrsDlgHdl)
  2650. ||
  2651. (((CurrentTime - pPnr->LastCommTime) > FIVE_MINUTES) &&
  2652. !(fDlgActive = ECommIsDlgActive(&pPnr->PrsDlgHdl))))
  2653. {
  2654. //
  2655. // If the dlg is inactive, end it so that we start from
  2656. // a clean slate.
  2657. //
  2658. if (!fDlgActive)
  2659. {
  2660. ECommEndDlg(&pPnr->PrsDlgHdl);
  2661. }
  2662. ECommStartDlg(
  2663. &pPnr->WinsAdd,
  2664. COMM_E_RPL,
  2665. pDlgHdl
  2666. );
  2667. if (pPnr->fPrsConn)
  2668. {
  2669. pPnr->PrsDlgHdl = *pDlgHdl;
  2670. }
  2671. }
  2672. else
  2673. {
  2674. pDlgHdl = &pPnr->PrsDlgHdl;
  2675. }
  2676. }
  2677. else
  2678. {
  2679. //
  2680. // Apparently a window where a reconfig of this
  2681. // WINS caused the remote guy to be removed as a pull
  2682. // pnr. This is a window because the push thread
  2683. // checks whether the remote guy is a pnr prior to
  2684. // handing the request to the pull thread. We will in
  2685. // this case just bail out
  2686. //
  2687. ASSERTMSG("window condition. Pnr no longer there. Did you reconfigure in the very recent past If yes, hit go, else log it", FALSE);
  2688. ECommEndDlg(&pWrkItm->DlgHdl);
  2689. DBGPRINT0(FLOW, "LEAVE: HdlPushNtf - PULL thread\n");
  2690. return;
  2691. }
  2692. }
  2693. else
  2694. {
  2695. pDlgHdl = &pWrkItm->DlgHdl;
  2696. }
  2697. #endif
  2698. //
  2699. // loop over all WINS address - Version number maps sent to us
  2700. // by the remote client
  2701. //
  2702. try {
  2703. PRPL_ADD_VERS_NO_T pAddVers;
  2704. // filter personas grata / non grata from the list of OwnerAddress<->VersionNo
  2705. // given to us by the remote pusher
  2706. FilterPersona(&(PushPnrData[0]));
  2707. pAddVers = PushPnrData[0].pAddVers;
  2708. // at this point all WINS in PushPnrData are allowed by the lists of personas grata/non-grata
  2709. for (i=0; i < PushPnrData[0].NoOfMaps; i++, pAddVers++)
  2710. {
  2711. fAllocNew = TRUE;
  2712. RplFindOwnerId(
  2713. &pAddVers->OwnerWinsAdd,
  2714. &fAllocNew, //allocate entry if not existent
  2715. &OwnerId,
  2716. WINSCNF_E_INITP_IF_NON_EXISTENT,
  2717. WINSCNF_LOW_PREC
  2718. );
  2719. //
  2720. // If the local WINS has older information than the remote
  2721. // WINS, pull the new information. Here we are comparing
  2722. // the highest version number in the local db for a particular
  2723. // WINS with the highest version number that the remote Pusher
  2724. // has. NOTE: if the map sent by the PULL PNR pertains to
  2725. // self, it means that we went down and came up with a truncated
  2726. // database (partners have replicas). DON"T PULL these records
  2727. //
  2728. if (
  2729. (OwnerId != NMSDB_LOCAL_OWNER_ID)
  2730. )
  2731. {
  2732. //
  2733. // If the max. vers. number is less than or equal to
  2734. // what we have, don't pull
  2735. //
  2736. if (LiLeq(
  2737. pAddVers->VersNo,
  2738. (pRplPullOwnerVersNo+OwnerId)->VersNo
  2739. )
  2740. )
  2741. {
  2742. continue; //check the next owner
  2743. }
  2744. NMSNMH_INC_VERS_NO_M(
  2745. (pRplPullOwnerVersNo+OwnerId)->VersNo,
  2746. MinVersNo
  2747. );
  2748. //
  2749. // Pull Entries
  2750. //
  2751. RplPullPullEntries(
  2752. pDlgHdl,
  2753. OwnerId,
  2754. MaxVersNo, //inited to 0
  2755. MinVersNo,
  2756. WINS_E_RPLPULL,
  2757. NULL,
  2758. TRUE, //update counters
  2759. PtrToUlong (pWrkItm->pClientCtx)
  2760. );
  2761. //
  2762. // If atleast one valid record was pulled by WINS, sfPulled
  2763. // will be set to TRUE. Since this can get reset by the
  2764. // next call to RplPullPullEntries, let us save it.
  2765. //
  2766. if (sfPulled)
  2767. {
  2768. fPulled = TRUE;
  2769. }
  2770. }
  2771. } //end of for{} over all wins address - version # maps
  2772. } // end of try {}
  2773. except (EXCEPTION_EXECUTE_HANDLER) {
  2774. ExcCode = GetExceptionCode();
  2775. DBGPRINT1(EXC, "HdlPushNtf: Encountered exception %x\n", ExcCode);
  2776. if (ExcCode == WINS_EXC_COMM_FAIL)
  2777. {
  2778. COMM_IP_ADD_T RemoteIPAdd;
  2779. COMM_GET_IPADD_M(&pWrkItm->DlgHdl, &RemoteIPAdd);
  2780. DBGPRINT1(EXC, "HdlPushNtf: Communication Failure with Remote Wins having address = (%x)\n", RemoteIPAdd);
  2781. }
  2782. WINSEVT_LOG_M(ExcCode, WINS_EVT_EXC_PUSH_TRIG_PROC);
  2783. }
  2784. if (PushPnrData[0].NoOfMaps > 0)
  2785. {
  2786. WinsMscDealloc(PushPnrData[0].pAddVers);
  2787. }
  2788. //
  2789. // If opcode indicates push propagation and we did pull atleast one
  2790. // record from the WINS that sent us the Push notification, do the
  2791. // propagation now. We do not propagate to the guy who sent us
  2792. // the trigger.
  2793. //
  2794. // Note: We never propagate if this update notification has made its way
  2795. // back to us because of some loop. We also don't propagate it if
  2796. // we have been told not to by the admin.
  2797. //
  2798. if (((Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP)
  2799. #if PRSCONN
  2800. || (Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP_PRS)
  2801. #endif
  2802. ) && fPulled && !COMM_MY_IP_ADD_M(InitiatorWinsIpAdd) && (WinsCnf.PushInfo.PropNetUpdNtf == DO_PROP_NET_UPD_NTF))
  2803. {
  2804. COMM_ADD_T WinsAdd;
  2805. COMM_INIT_ADD_FR_DLG_HDL_M(&WinsAdd, &pWrkItm->DlgHdl);
  2806. //
  2807. // We need to synchronize with the NBT threads
  2808. //
  2809. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  2810. //
  2811. // Check whether we have any PULL pnrs. (We need to access WinsCnf
  2812. // from within the NmsNmhNamRegCrtSec)
  2813. //
  2814. // We do this test here instead of in the RPL_PUSH_NTF_M macro to
  2815. // localize the overhead to this function only. Note: If the
  2816. // Initiator WINS address is 0, it means that it is a Daytona WINS (not
  2817. // a PPC release WINS). In such a case, we put our own address. This
  2818. // has the advantage of stopping propagations in a loop of new WINSs if
  2819. // they have gone around the loop once..
  2820. //
  2821. if (WinsCnf.PushInfo.NoOfPullPnrs != 0)
  2822. {
  2823. try
  2824. {
  2825. RPL_PUSH_NTF_M(
  2826. RPL_PUSH_PROP,
  2827. (InitiatorWinsIpAdd == 0) ? ULongToPtr(NmsLocalAdd.Add.IPAdd) : ULongToPtr(InitiatorWinsIpAdd),
  2828. &WinsAdd, //don't want to send to this guy.
  2829. NULL
  2830. );
  2831. }
  2832. except(EXCEPTION_EXECUTE_HANDLER)
  2833. {
  2834. DBGPRINTEXC("HdlPushNtf: Exception while propagating a trigger");
  2835. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_PUSH_PROP_FAILED);
  2836. }
  2837. }
  2838. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  2839. }
  2840. //
  2841. // End the dlg. The right dlg will get terminated.
  2842. // Note: The dlg is explicit (if we establishd it) or implicit (established
  2843. // by the remote client).
  2844. //
  2845. // So, if the remote connection is not persistent or if it is but we
  2846. // the pnr is not persistent for pulling (meaning we established an
  2847. // explicit connection with it, end the dlg. pDlgHdl points to the right
  2848. // dlg
  2849. //
  2850. #if PRSCONN
  2851. if (!fImplicitConnPrs || !pPnr->fPrsConn)
  2852. {
  2853. ECommEndDlg(pDlgHdl);
  2854. }
  2855. else
  2856. {
  2857. //
  2858. // if we are here, it means that we pPnr is set to a Partner. If
  2859. // we had a comm. failure with it, we should end the Prs Dlg with
  2860. // it.
  2861. //
  2862. if (ExcCode == WINS_EXC_COMM_FAIL)
  2863. {
  2864. ECommEndDlg(&pPnr->PrsDlgHdl);
  2865. }
  2866. }
  2867. #else
  2868. ECommEndDlg(pDlgHdl);
  2869. #endif
  2870. DBGPRINT0(FLOW, "LEAVE: HdlPushNtf - PULL thread\n");
  2871. return;
  2872. }
  2873. STATUS
  2874. RegGrpRepl(
  2875. LPBYTE pName,
  2876. DWORD NameLen,
  2877. DWORD Flag,
  2878. DWORD OwnerId,
  2879. VERS_NO_T VersNo,
  2880. DWORD NoOfAdds,
  2881. PCOMM_ADD_T pNodeAdd,
  2882. PCOMM_ADD_T pOwnerWinsAdd
  2883. )
  2884. /*++
  2885. Routine Description:
  2886. This function is called to register a replica of a group entry
  2887. Arguments:
  2888. Externals Used:
  2889. None
  2890. Return Value:
  2891. None
  2892. Error Handling:
  2893. Called by:
  2894. RplPullPullEntries
  2895. Side Effects:
  2896. Comments:
  2897. None
  2898. --*/
  2899. {
  2900. NMSDB_NODE_ADDS_T GrpMems;
  2901. DWORD i; //for loop counter
  2902. DWORD n = 0; //index into the NodeAdd array
  2903. BYTE EntTyp;
  2904. BOOL fAllocNew;
  2905. STATUS RetStat;
  2906. GrpMems.NoOfMems = 0;
  2907. DBGENTER("RegGrpRepl\n");
  2908. EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(Flag);
  2909. //
  2910. // Check if it is a special group or a multihomed entry
  2911. //
  2912. if (EntTyp != NMSDB_NORM_GRP_ENTRY)
  2913. {
  2914. CHECK("I think I have now stopped sending timed out records");
  2915. //
  2916. // If we did not get any member. This can only mean that
  2917. // all members of this group/multihomed entry have timed out
  2918. // at the remote WINS.
  2919. //
  2920. if (NoOfAdds != 0)
  2921. {
  2922. GrpMems.NoOfMems = NoOfAdds;
  2923. for (i = 0; i < NoOfAdds; i++)
  2924. {
  2925. //
  2926. // The first address is the address of
  2927. // the WINS that is the owner of the
  2928. // member.
  2929. //
  2930. fAllocNew = TRUE;
  2931. RplFindOwnerId(
  2932. &pNodeAdd[n++],
  2933. &fAllocNew, //assign if not there
  2934. &GrpMems.Mem[i].OwnerId,
  2935. WINSCNF_E_INITP_IF_NON_EXISTENT,
  2936. WINSCNF_LOW_PREC
  2937. );
  2938. //
  2939. // The next address is the address of the
  2940. // member
  2941. //
  2942. GrpMems.Mem[i].Add = pNodeAdd[n++];
  2943. }
  2944. }
  2945. #ifdef WINSDBG
  2946. else //no members
  2947. {
  2948. if (NMSDB_ENTRY_STATE_M(Flag) != NMSDB_E_TOMBSTONE)
  2949. {
  2950. DBGPRINT0(EXC, "RegGrpRepl: The replica of a special group without any members is not a TOMBSTONE\n");
  2951. WINSEVT_LOG_M(
  2952. WINS_FAILURE,
  2953. WINS_EVT_RPL_STATE_ERR
  2954. );
  2955. WINS_RAISE_EXC_M(WINS_EXC_RPL_STATE_ERR);
  2956. }
  2957. }
  2958. #endif
  2959. }
  2960. else // it is a normal group
  2961. {
  2962. NOTE("On a clash with a special group, this owner id. will be stored which")
  2963. NOTE("can be misleading")
  2964. GrpMems.NoOfMems = 1;
  2965. GrpMems.Mem[0].OwnerId = OwnerId; //misleading (see ClashAtRegGrpRpl()
  2966. //in nmsnmh.c - clash between normal
  2967. //grp and special grp.
  2968. GrpMems.Mem[0].Add = *pNodeAdd;
  2969. }
  2970. RetStat = NmsNmhReplGrpMems(
  2971. pName,
  2972. NameLen,
  2973. EntTyp,
  2974. &GrpMems,
  2975. Flag,
  2976. OwnerId,
  2977. VersNo,
  2978. pOwnerWinsAdd
  2979. );
  2980. DBGLEAVE("RegGrpRepl\n");
  2981. return(RetStat);
  2982. }
  2983. BOOL
  2984. IsTimeoutToBeIgnored(
  2985. PQUE_TMM_REQ_WRK_ITM_T pWrkItm
  2986. )
  2987. /*++
  2988. Routine Description:
  2989. This function is called to determine if the timeout that the
  2990. PULL thread received needs to be ignored
  2991. Arguments:
  2992. pWrkItm - Timeout work itm
  2993. Externals Used:
  2994. None
  2995. Return Value:
  2996. TRUE if the timeout needs to be ignored
  2997. FALSE otherwise
  2998. Error Handling:
  2999. Called by:
  3000. RplPullInit
  3001. Side Effects:
  3002. Comments:
  3003. None
  3004. --*/
  3005. {
  3006. BOOL fRetVal = FALSE;
  3007. try {
  3008. //
  3009. // If this is the timeout based on old config
  3010. // ignore it. If the old configuration memory blocks
  3011. // have not been deallocated as yet, deallocate them
  3012. //
  3013. if (pWrkItm->MagicNo != RplPullCnfMagicNo)
  3014. {
  3015. //
  3016. // Deallocate the work item and deallocate
  3017. // the configuration block
  3018. //
  3019. WinsTmmDeallocReq(pWrkItm);
  3020. fRetVal = TRUE;
  3021. }
  3022. }
  3023. except (EXCEPTION_EXECUTE_HANDLER) {
  3024. DBGPRINTEXC("IsTimeoutToBeIgnored");
  3025. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  3026. }
  3027. return(fRetVal);
  3028. }
  3029. VOID
  3030. InitRplProcess(
  3031. PWINSCNF_CNF_T pWinsCnf
  3032. )
  3033. /*++
  3034. Routine Description:
  3035. This function is called to start the replication process. This
  3036. comprises of getting the replicas if the InitTimeRpl field
  3037. is set to 1. Timer requests are also submitted.
  3038. Arguments:
  3039. pWinsCnf - pointer to the Wins Configuration structure
  3040. Externals Used:
  3041. None
  3042. Return Value:
  3043. None
  3044. Error Handling:
  3045. Called by:
  3046. RplPullInit()
  3047. Side Effects:
  3048. Comments:
  3049. None
  3050. --*/
  3051. {
  3052. PRPL_CONFIG_REC_T pPullCnfRecs = pWinsCnf->PullInfo.pPullCnfRecs;
  3053. BOOL fAllocNew;
  3054. DWORD OwnerWinsId;
  3055. STATUS RetStat;
  3056. //
  3057. // Initialize Owner-Id table with new entries if any
  3058. //
  3059. for (
  3060. ;
  3061. pPullCnfRecs->WinsAdd.Add.IPAdd != INADDR_NONE;
  3062. //no third expression
  3063. )
  3064. {
  3065. fAllocNew = TRUE;
  3066. RetStat = RplFindOwnerId(
  3067. &pPullCnfRecs->WinsAdd,
  3068. &fAllocNew,
  3069. &OwnerWinsId,
  3070. WINSCNF_E_INITP,
  3071. pPullCnfRecs->MemberPrec
  3072. );
  3073. if (RetStat == WINS_FAILURE)
  3074. {
  3075. FUTURES("Improve error recovery")
  3076. //
  3077. // We have hit the limit. Break out of the loop
  3078. // but carry on in the hope that the situation
  3079. // will correct itself by the time we replicate.
  3080. // If InitTimeReplication is TRUE, there is no
  3081. // chance of the table entries getting freed up.
  3082. // Even if some entries get freed, when we make
  3083. // an entry for the WINS which we couldn't insert now,
  3084. // it will take LOW_PREC.
  3085. //
  3086. break;
  3087. }
  3088. pPullCnfRecs = WinsCnfGetNextRplCnfRec(
  3089. pPullCnfRecs,
  3090. RPL_E_IN_SEQ
  3091. );
  3092. }
  3093. //
  3094. // Do init time replication if not prohibited by the config
  3095. // info.
  3096. //
  3097. if (pWinsCnf->PullInfo.InitTimeRpl)
  3098. {
  3099. /*
  3100. * Pull replicas and handle them
  3101. */
  3102. GetReplicasNew(
  3103. pWinsCnf->PullInfo.pPullCnfRecs,
  3104. RPL_E_IN_SEQ //records are in sequence
  3105. );
  3106. }
  3107. //
  3108. // For all Push partners with which replication has to be done
  3109. // periodically, submit timer requests
  3110. //
  3111. SubmitTimerReqs(pWinsCnf->PullInfo.pPullCnfRecs);
  3112. return;
  3113. } // InitRplProcess()
  3114. VOID
  3115. Reconfig(
  3116. PWINSCNF_CNF_T pWinsCnf
  3117. )
  3118. /*++
  3119. Routine Description:
  3120. This function is called to reconfigure the PULL handler
  3121. Arguments:
  3122. pNewWinsCnf - New Configuration
  3123. Externals Used:
  3124. None
  3125. Return Value:
  3126. None
  3127. Error Handling:
  3128. Called by:
  3129. RplPullInit when it gets the CONFIGURE message
  3130. Side Effects:
  3131. Comments:
  3132. None
  3133. --*/
  3134. {
  3135. BOOL fNewInfo = FALSE;
  3136. BOOL fValidReq = FALSE;
  3137. #if PRSCONN
  3138. PRPL_CONFIG_REC_T pOldPnr, pNewPnr;
  3139. DWORD i, n;
  3140. #endif
  3141. DBGENTER("Reconfig (PULL)\n");
  3142. //
  3143. // synchronize with rpc threads and with the push thread
  3144. //
  3145. EnterCriticalSection(&WinsCnfCnfCrtSec);
  3146. try {
  3147. //
  3148. // Get the latest magic no (set by the main thread)
  3149. //
  3150. RplPullCnfMagicNo = WinsCnfCnfMagicNo;
  3151. //
  3152. // If the latest magic no is not the same as the one
  3153. // in this configuration block, we can ignore this
  3154. // configuration request
  3155. //
  3156. if (WinsCnfCnfMagicNo == pWinsCnf->MagicNo)
  3157. {
  3158. fValidReq = TRUE;
  3159. DBGPRINT1(RPLPULL, "Reconfig: Magic No (%d) match\n", WinsCnfCnfMagicNo);
  3160. //
  3161. // Initialize the Push records if required
  3162. //
  3163. // Note: NBT threads look at Push config
  3164. // records after doing registrations. Therefore
  3165. // we should enter the critical section before
  3166. // changing WinsCnf
  3167. //
  3168. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  3169. try {
  3170. if (WinsCnf.PushInfo.pPushCnfRecs != NULL)
  3171. {
  3172. #if PRSCONN
  3173. //
  3174. // Copy the statistics info
  3175. //
  3176. pOldPnr = WinsCnf.PushInfo.pPushCnfRecs;
  3177. for (i = 0; i < WinsCnf.PushInfo.NoOfPullPnrs; i++)
  3178. {
  3179. pNewPnr = pWinsCnf->PushInfo.pPushCnfRecs;
  3180. for (n=0; n < pWinsCnf->PushInfo.NoOfPullPnrs; n++)
  3181. {
  3182. if (pNewPnr->WinsAdd.Add.IPAdd == pOldPnr->WinsAdd.Add.IPAdd)
  3183. {
  3184. pNewPnr->LastCommFailTime = pOldPnr->LastCommFailTime;
  3185. pNewPnr->LastCommTime = pOldPnr->LastCommFailTime;
  3186. //
  3187. // If the partner stays persistent, init the dlg
  3188. // hdl.
  3189. //
  3190. if (pNewPnr->fPrsConn && (pNewPnr->fPrsConn == pOldPnr->fPrsConn))
  3191. {
  3192. pNewPnr->PrsDlgHdl = pOldPnr->PrsDlgHdl;
  3193. }
  3194. else
  3195. {
  3196. //
  3197. // The partner was persistent but is no
  3198. // longer so. Terminate the dlg
  3199. //
  3200. if (pOldPnr->fPrsConn)
  3201. {
  3202. ECommEndDlg(&pOldPnr->PrsDlgHdl);
  3203. }
  3204. }
  3205. break;
  3206. }
  3207. pNewPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pNewPnr + RPL_CONFIG_REC_SIZE);
  3208. }
  3209. pOldPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pOldPnr + RPL_CONFIG_REC_SIZE);
  3210. }
  3211. #endif
  3212. WinsMscDealloc(WinsCnf.PushInfo.pPushCnfRecs);
  3213. }
  3214. WinsCnf.PushInfo = pWinsCnf->PushInfo;
  3215. //
  3216. // Initialize the push records
  3217. //
  3218. if (pWinsCnf->PushInfo.pPushCnfRecs != NULL)
  3219. {
  3220. PERF("Do the following along with the stuff under PRSCONN")
  3221. RPLPUSH_INIT_PUSH_RECS_M(&WinsCnf);
  3222. }
  3223. }
  3224. except(EXCEPTION_EXECUTE_HANDLER) {
  3225. DBGPRINTEXC("Reconfig (PULL thread)");
  3226. //
  3227. // Log a message
  3228. //
  3229. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR);
  3230. }
  3231. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  3232. //
  3233. // We need to first get rid of all timer requests that
  3234. // we made based on the previous configuration
  3235. //
  3236. if (WinsCnf.PullInfo.pPullCnfRecs != NULL)
  3237. {
  3238. #if !PRSCONN
  3239. PRPL_CONFIG_REC_T pOldPnr, pNewPnr;
  3240. DWORD i, n;
  3241. #endif
  3242. fNewInfo = TRUE;
  3243. //
  3244. // Cancel (and deallocate) all requests that we might have
  3245. // submitted
  3246. //
  3247. WinsTmmDeleteReqs(WINS_E_RPLPULL);
  3248. //
  3249. // Copy the statistics info
  3250. //
  3251. pOldPnr = WinsCnf.PullInfo.pPullCnfRecs;
  3252. for (i = 0; i < WinsCnf.PullInfo.NoOfPushPnrs; i++)
  3253. {
  3254. pNewPnr = pWinsCnf->PullInfo.pPullCnfRecs;
  3255. for (n=0; n < pWinsCnf->PullInfo.NoOfPushPnrs; n++)
  3256. {
  3257. if (pNewPnr->WinsAdd.Add.IPAdd == pOldPnr->WinsAdd.Add.IPAdd)
  3258. {
  3259. pNewPnr->NoOfRpls = pOldPnr->NoOfRpls;
  3260. pNewPnr->NoOfCommFails = pOldPnr->NoOfCommFails;
  3261. #if PRSCONN
  3262. pNewPnr->LastCommFailTime = pOldPnr->LastCommFailTime;
  3263. pNewPnr->LastCommTime = pOldPnr->LastCommFailTime;
  3264. //
  3265. // If the partner stays persistent, init the dlg
  3266. // hdl.
  3267. //
  3268. if (pNewPnr->fPrsConn && (pNewPnr->fPrsConn == pOldPnr->fPrsConn))
  3269. {
  3270. pNewPnr->PrsDlgHdl = pOldPnr->PrsDlgHdl;
  3271. }
  3272. else
  3273. {
  3274. //
  3275. // The partner was persistent but is no
  3276. // longer so. Terminate the dlg
  3277. //
  3278. if (pOldPnr->fPrsConn)
  3279. {
  3280. ECommEndDlg(&pOldPnr->PrsDlgHdl);
  3281. }
  3282. }
  3283. #endif
  3284. break;
  3285. }
  3286. pNewPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pNewPnr + RPL_CONFIG_REC_SIZE);
  3287. }
  3288. pOldPnr = (PRPL_CONFIG_REC_T)((LPBYTE)pOldPnr + RPL_CONFIG_REC_SIZE);
  3289. }
  3290. //
  3291. // Deallocate the memory holding the pull configuration blocks
  3292. //
  3293. //
  3294. WinsMscDealloc(WinsCnf.PullInfo.pPullCnfRecs);
  3295. }
  3296. //
  3297. // Initialize with the new information
  3298. //
  3299. WinsCnf.PullInfo = pWinsCnf->PullInfo;
  3300. }
  3301. #ifdef WINSDBG
  3302. else
  3303. {
  3304. DBGPRINT2(RPLPULL, "Reconfig: Magic Nos different. WinsCnfCnfMagicNo=(%d), pWinsCnf->MagicNo = (%d)\n", WinsCnfCnfMagicNo, pWinsCnf->MagicNo);
  3305. }
  3306. #endif
  3307. }
  3308. except(EXCEPTION_EXECUTE_HANDLER) {
  3309. DBGPRINTEXC("Reconfig: Pull Thread");
  3310. }
  3311. //
  3312. // synchronize with rpc threads doing WinsStatus/WinsTrigger
  3313. //
  3314. LeaveCriticalSection(&WinsCnfCnfCrtSec);
  3315. if (fValidReq)
  3316. {
  3317. if (WinsCnf.pPersonaList != NULL)
  3318. {
  3319. WinsMscDealloc(WinsCnf.pPersonaList);
  3320. }
  3321. WinsCnf.fPersonaGrata = pWinsCnf->fPersonaGrata;
  3322. WinsCnf.NoOfPersona = pWinsCnf->NoOfPersona;
  3323. WinsCnf.pPersonaList = pWinsCnf->pPersonaList;
  3324. //
  3325. // Start the replication process if there are PULL records
  3326. // in the new configuration
  3327. //
  3328. if (WinsCnf.PullInfo.pPullCnfRecs != NULL)
  3329. {
  3330. InitRplProcess(&WinsCnf);
  3331. }
  3332. }
  3333. //
  3334. // Deallocate the new config structure
  3335. //
  3336. WinsCnfDeallocCnfMem(pWinsCnf);
  3337. DBGLEAVE("Reconfig (PULL)\n");
  3338. return;
  3339. } // Reconfig()
  3340. VOID
  3341. AddressChangeNotification(
  3342. PWINSCNF_CNF_T pWinsCnf
  3343. )
  3344. /*++
  3345. Routine Description:
  3346. This function is called to handle address change of the local
  3347. machine.
  3348. Arguments:
  3349. pNewWinsCnf - New Configuration
  3350. Externals Used:
  3351. None
  3352. Return Value:
  3353. None
  3354. Error Handling:
  3355. Side Effects:
  3356. Comments:
  3357. None
  3358. --*/
  3359. {
  3360. DBGENTER("AddressChangeNotification\n");
  3361. //
  3362. // if our address has changed, the following routine
  3363. // will reinitialize the owner address table with own address
  3364. //
  3365. InitOwnAddTbl();
  3366. DBGLEAVE("AddressChangeNotification\n");
  3367. return;
  3368. } // AddressChangeNotification()
  3369. VOID
  3370. PullSpecifiedRange(
  3371. PCOMM_HDL_T pDlgHdl,
  3372. PWINSINTF_PULL_RANGE_INFO_T pPullRangeInfo,
  3373. BOOL fAdjustMin,
  3374. DWORD RplType
  3375. )
  3376. /*++
  3377. Routine Description:
  3378. This function is called to pull a specified range of records from
  3379. a remote WINS server
  3380. Arguments:
  3381. Externals Used:
  3382. None
  3383. Return Value:
  3384. None
  3385. Error Handling:
  3386. Called by:
  3387. Side Effects:
  3388. Comments:
  3389. None
  3390. --*/
  3391. {
  3392. PUSHPNR_DATA_T PushPnrData[1];
  3393. DWORD NoOfPushPnrs = 1;
  3394. DWORD OwnerId;
  3395. BOOL fEnterCrtSec = FALSE;
  3396. PRPL_CONFIG_REC_T pPnr = pPullRangeInfo->pPnr;
  3397. COMM_ADD_T OwnAdd;
  3398. BOOL fAllocNew = TRUE;
  3399. PPUSHPNR_DATA_T pPushPnrData = PushPnrData;
  3400. //
  3401. // Establish communications with the Push Pnr
  3402. //
  3403. // When this function returns, the 'NoOfPushPnrs' entries of
  3404. // PushPnrData array will be initialized.
  3405. //
  3406. if (pDlgHdl == NULL)
  3407. {
  3408. EstablishComm(
  3409. pPnr,
  3410. FALSE,
  3411. &pPushPnrData,
  3412. RPL_E_NO_TRAVERSAL,
  3413. &NoOfPushPnrs
  3414. );
  3415. }
  3416. else
  3417. {
  3418. PushPnrData[0].DlgHdl = *pDlgHdl;
  3419. }
  3420. try {
  3421. //
  3422. // if communication could be established above, NoOfPushPnrs will
  3423. // be 1
  3424. //
  3425. if (NoOfPushPnrs == 1)
  3426. {
  3427. //
  3428. // Get owner id. of WINS whose entries are to be pulled
  3429. //
  3430. OwnAdd.AddTyp_e = pPullRangeInfo->OwnAdd.Type;
  3431. OwnAdd.AddLen = pPullRangeInfo->OwnAdd.Len;
  3432. OwnAdd.Add.IPAdd = pPullRangeInfo->OwnAdd.IPAdd;
  3433. PERF("for the case where pDlgHdl != NULL, the Owner Id is 0. See GetReplicasNew->ConductChkNew")
  3434. PERF("We could make use of that to go around the RplFindOwnerId call")
  3435. (VOID)RplFindOwnerId(
  3436. &OwnAdd,
  3437. &fAllocNew,//allocate a new entry if WINS is not found
  3438. &OwnerId,
  3439. WINSCNF_E_INITP_IF_NON_EXISTENT,
  3440. WINSCNF_LOW_PREC
  3441. );
  3442. //
  3443. // if a new entry was not allocated, it means that there are
  3444. // records for this owner in the database. We might have to
  3445. // delete some or all.
  3446. //
  3447. // If the local WINS owns the records, enter the critical section
  3448. // so that NmsNmhMyMaxVersNo is not changed by Nbt or Rpl threads
  3449. // while we are doing our work here
  3450. //
  3451. if (!fAllocNew)
  3452. {
  3453. if (OwnerId == NMSDB_LOCAL_OWNER_ID)
  3454. {
  3455. //
  3456. // See NOTE NOTE NOTE below.
  3457. //
  3458. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  3459. fEnterCrtSec = TRUE;
  3460. //
  3461. // If we have not been told to adjust the min. vers. no,
  3462. // delete all records that have a version number greater
  3463. // than the minimum to be pulled
  3464. //
  3465. if (LiLtr(pPullRangeInfo->MinVersNo, NmsNmhMyMaxVersNo))
  3466. {
  3467. if (!fAdjustMin)
  3468. {
  3469. NmsDbDelDataRecs(
  3470. OwnerId,
  3471. pPullRangeInfo->MinVersNo,
  3472. pPullRangeInfo->MaxVersNo,
  3473. FALSE, //do not enter critical section
  3474. FALSE //one shot deletion
  3475. );
  3476. }
  3477. else
  3478. {
  3479. pPullRangeInfo->MinVersNo = NmsNmhMyMaxVersNo;
  3480. }
  3481. }
  3482. }
  3483. else//records to be pulled are owned by some other WINS server
  3484. {
  3485. if (LiLeq(pPullRangeInfo->MinVersNo,
  3486. (pRplPullOwnerVersNo+OwnerId)->VersNo))
  3487. {
  3488. NmsDbDelDataRecs(
  3489. OwnerId,
  3490. pPullRangeInfo->MinVersNo,
  3491. pPullRangeInfo->MaxVersNo,
  3492. TRUE, //enter critical section
  3493. FALSE //one shot deletion
  3494. );
  3495. }
  3496. }
  3497. }
  3498. //
  3499. // Pull Entries.
  3500. //
  3501. // NOTE NOTE NOTE
  3502. //
  3503. // RplPullPullEntries will update NmsNmhMyMaxVersNo counter if
  3504. // we pull our own records with the highest version number being
  3505. // pulled being > NmsNmhMyMaxVersNo. For the above case,
  3506. // RplPullPullEntries assumes that we are inside the
  3507. // NmsNmhNamRegCrtSec critical section.
  3508. //
  3509. if (LiGeq(pPullRangeInfo->MaxVersNo, pPullRangeInfo->MinVersNo))
  3510. {
  3511. RplPullPullEntries(
  3512. &PushPnrData[0].DlgHdl,
  3513. OwnerId, //owner id
  3514. pPullRangeInfo->MaxVersNo, //Max vers. no to be pulled
  3515. pPullRangeInfo->MinVersNo, //Min vers. no to be pulled
  3516. WINS_E_RPLPULL,
  3517. NULL,
  3518. FALSE, //don't update RplOwnAddTblVersNo counters
  3519. //unless pulled version number is > what
  3520. //we currently have.
  3521. RplType
  3522. );
  3523. }
  3524. } // end of if (NoOfPushPnrs == 1)
  3525. }
  3526. except(EXCEPTION_EXECUTE_HANDLER) {
  3527. DWORD ExcCode = GetExceptionCode();
  3528. DBGPRINT1(EXC, "PullSpecifiedRange: Got exception %x", ExcCode);
  3529. WINSEVT_LOG_M(ExcCode, WINS_EVT_PULL_RANGE_EXC);
  3530. }
  3531. if (fEnterCrtSec)
  3532. {
  3533. //
  3534. // The following assumes that we enter the critical section
  3535. // in this function only when pulling our own records. This
  3536. // is true currently.
  3537. // If the min. vers. no. specified for pulling is <
  3538. // the Min. for scavenging, adjust the min. for scavenging.
  3539. // Note: We may not have pulled this minimum but we adjust
  3540. // the min. for scavenging regardless. This is to save
  3541. // the overhead that would exist if we were to adopt the
  3542. // approach of having RplPullPullEntries do the same (we
  3543. // would need to pass an arg. to it; Note: This function
  3544. // will be used in rare situations by an admin.
  3545. //
  3546. // We need to synchronize with the Scavenger thread.
  3547. //
  3548. if (LiGtr(NmsScvMinScvVersNo, pPullRangeInfo->MinVersNo))
  3549. {
  3550. NmsScvMinScvVersNo = pPullRangeInfo->MinVersNo;
  3551. }
  3552. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  3553. }
  3554. if (pPnr->fTemp)
  3555. {
  3556. WinsMscDealloc(pPullRangeInfo->pPnr);
  3557. }
  3558. if (pDlgHdl == NULL)
  3559. {
  3560. #if PRSCONN
  3561. if (!PushPnrData[0].fPrsConn)
  3562. {
  3563. //
  3564. // End the dialogue
  3565. //
  3566. ECommEndDlg(&PushPnrData[0].DlgHdl);
  3567. }
  3568. #else
  3569. ECommEndDlg(&PushPnrData[0].DlgHdl);
  3570. #endif
  3571. }
  3572. return;
  3573. } //PullSpecifiedRange()
  3574. STATUS
  3575. RplPullRegRepl(
  3576. LPBYTE pName,
  3577. DWORD NameLen,
  3578. DWORD Flag,
  3579. DWORD OwnerId,
  3580. VERS_NO_T VersNo,
  3581. DWORD NoOfAdds,
  3582. PCOMM_ADD_T pNodeAdd,
  3583. PCOMM_ADD_T pOwnerWinsAdd,
  3584. DWORD RplType
  3585. )
  3586. /*++
  3587. Routine Description:
  3588. This function is called to register a replica.
  3589. Arguments:
  3590. Externals Used:
  3591. None
  3592. Return Value:
  3593. None
  3594. Error Handling:
  3595. Called by:
  3596. Side Effects:
  3597. Comments:
  3598. It is called by RplPullPullEntries and by ChkConfNUpd in nmsscv.c
  3599. --*/
  3600. {
  3601. STATUS RetStat;
  3602. try {
  3603. //
  3604. // If this is a unique replica, call NmsNmhReplRegInd
  3605. //
  3606. if (NMSDB_ENTRY_TYPE_M(Flag) == NMSDB_UNIQUE_ENTRY)
  3607. {
  3608. //
  3609. // If only spec. grps and pdc name are to be replicated and
  3610. // this name is not a pdc name, skip it
  3611. //
  3612. #if 0
  3613. if ((RplType & WINSCNF_RPL_SPEC_GRPS_N_PDC)
  3614. && (!NMSDB_IS_IT_PDC_NM_M(pName)))
  3615. {
  3616. DBGPRINT1(RPLPULL, "RplPullRegRepl: Ignoring unique record - name = (%s)\n", pName);
  3617. return(WINS_SUCCESS);
  3618. }
  3619. #endif
  3620. RetStat = NmsNmhReplRegInd(
  3621. pName,
  3622. NameLen,
  3623. pNodeAdd,
  3624. Flag,
  3625. OwnerId,
  3626. VersNo,
  3627. pOwnerWinsAdd //add. of WINS owning the record
  3628. );
  3629. }
  3630. else // it is either a normal or a special group or a multihomed
  3631. // entry
  3632. {
  3633. #if 0
  3634. if ((RplType & WINSCNF_RPL_SPEC_GRPS_N_PDC)
  3635. &&
  3636. (!NMSDB_ENTRY_SPEC_GRP_M(NMSDB_ENTRY_TYPE_M(Flag))))
  3637. {
  3638. DBGPRINT1(RPLPULL, "RplPullRegRepl: Ignoring non-SG record - name = (%s)\n", pName);
  3639. return(WINS_SUCCESS);
  3640. }
  3641. #endif
  3642. RetStat = RegGrpRepl(
  3643. pName,
  3644. NameLen,
  3645. Flag,
  3646. OwnerId,
  3647. VersNo,
  3648. NoOfAdds,
  3649. pNodeAdd,
  3650. pOwnerWinsAdd //add. of WINS owning the record
  3651. );
  3652. }
  3653. }
  3654. except(EXCEPTION_EXECUTE_HANDLER) {
  3655. DWORD ExcCode = GetExceptionCode();
  3656. DBGPRINT1(EXC, "RplPullRegRepl: Got Exception %x", ExcCode);
  3657. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RPLPULL_EXC);
  3658. RetStat = WINS_FAILURE;
  3659. }
  3660. if (RetStat == WINS_FAILURE)
  3661. {
  3662. WinsEvtLogDetEvt(FALSE, NMSDB_ENTRY_TYPE_M(Flag) == NMSDB_UNIQUE_ENTRY ? WINS_EVT_RPL_REG_UNIQUE_ERR : WINS_EVT_RPL_REG_GRP_MEM_ERR,
  3663. NULL, __LINE__, "sddd", pName,
  3664. pOwnerWinsAdd->Add.IPAdd,
  3665. VersNo.LowPart, VersNo.HighPart);
  3666. WINSEVT_LOG_M(pNodeAdd->Add.IPAdd, WINS_EVT_RPL_REG_ERR);
  3667. //
  3668. // If WINS has been directed to continue replication on error,
  3669. // change RetStat to fool the caller into thinking that
  3670. // the replica registration was successful.
  3671. //
  3672. if (!WinsCnf.fNoRplOnErr)
  3673. {
  3674. RetStat = WINS_SUCCESS;
  3675. }
  3676. }
  3677. return(RetStat);
  3678. } // RplPullRegRepl()
  3679. VOID
  3680. DeleteWins(
  3681. PCOMM_ADD_T pWinsAdd
  3682. )
  3683. /*++
  3684. Routine Description:
  3685. This function deletes all records belonging to a WINS. It
  3686. also removes the entry of the WINS from the Owner-Add database
  3687. table. It marks the entry as deleted in the in-memory table so
  3688. that it can be reused if need be.
  3689. Arguments:
  3690. pWinsAdd - Address of WINS whose entry is to be removed
  3691. Externals Used:
  3692. None
  3693. Return Value:
  3694. None
  3695. Error Handling:
  3696. Called by:
  3697. Side Effects:
  3698. Comments:
  3699. None
  3700. --*/
  3701. {
  3702. BOOL fAllocNew = FALSE;
  3703. DWORD OwnerId;
  3704. STATUS RetStat;
  3705. DWORD fEnterCrtSec = FALSE;
  3706. DWORD ExcCode = WINS_SUCCESS;
  3707. //
  3708. // Find the owner id of the WINS. If the WINS is not in the table
  3709. // return
  3710. //
  3711. RetStat = RplFindOwnerId(
  3712. pWinsAdd,
  3713. &fAllocNew,
  3714. &OwnerId,
  3715. WINSCNF_E_IGNORE_PREC,
  3716. WINSCNF_LOW_PREC
  3717. );
  3718. if (RetStat == WINS_SUCCESS)
  3719. {
  3720. if (OwnerId == NMSDB_LOCAL_OWNER_ID)
  3721. {
  3722. //
  3723. // We always keep the entry for the local WINS.
  3724. //
  3725. DBGPRINT0(ERR, "DeleteWins: Sorry, you can not delete the local WINS\n");
  3726. //WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_DELETE_LOCAL_WINS_DISALLOWED);
  3727. }
  3728. else
  3729. {
  3730. VERS_NO_T MinVersNo;
  3731. VERS_NO_T MaxVersNo;
  3732. WINSEVT_STRS_T EvtStrs;
  3733. WCHAR String[WINS_MAX_NAME_SZ];
  3734. struct in_addr InAddr;
  3735. InAddr.s_addr = htonl(pWinsAdd->Add.IPAdd);
  3736. (VOID)WinsMscConvertAsciiStringToUnicode(
  3737. inet_ntoa( InAddr),
  3738. (LPBYTE)String,
  3739. WINS_MAX_NAME_SZ);
  3740. EvtStrs.NoOfStrs = 1;
  3741. EvtStrs.pStr[0] = String;
  3742. WINSEVT_LOG_INFO_STR_D_M(WINS_EVT_DEL_OWNER_STARTED, &EvtStrs);
  3743. WINS_ASSIGN_INT_TO_VERS_NO_M(MinVersNo, 0);
  3744. WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0);
  3745. //
  3746. // Need to synchronize with NBT threads or rpc threads that
  3747. // might be modifying these records. NmsDelDataRecs will
  3748. // enter the critical section
  3749. //
  3750. #if 0
  3751. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  3752. #endif
  3753. try {
  3754. //
  3755. // Delete all records
  3756. //
  3757. RetStat = NmsDbDelDataRecs(
  3758. OwnerId,
  3759. MinVersNo,
  3760. MaxVersNo,
  3761. TRUE, //enter critical section
  3762. TRUE //fragmented deletion
  3763. );
  3764. //
  3765. // If all records were deleted, mark entry as deleted.
  3766. //
  3767. if (RetStat == WINS_SUCCESS)
  3768. {
  3769. EnterCriticalSection(&RplVersNoStoreCrtSec);
  3770. WINS_ASSIGN_INT_TO_LI_M((pRplPullOwnerVersNo+OwnerId)->VersNo, 0);
  3771. LeaveCriticalSection(&RplVersNoStoreCrtSec);
  3772. //
  3773. // Delete the entry for the WINS from the db table
  3774. // and mark WINS as deleted in the in-memory table.
  3775. //
  3776. // This way, we will free up entries in the table.
  3777. //
  3778. EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
  3779. fEnterCrtSec = TRUE;
  3780. (pNmsDbOwnAddTbl+OwnerId)->WinsState_e = NMSDB_E_WINS_DELETED;
  3781. //
  3782. // Delete entry from the owner-Add table
  3783. //
  3784. NmsDbWriteOwnAddTbl(
  3785. NMSDB_E_DELETE_REC,
  3786. OwnerId,
  3787. NULL,
  3788. NMSDB_E_WINS_DELETED,
  3789. NULL,
  3790. NULL
  3791. );
  3792. }
  3793. else
  3794. {
  3795. DBGPRINT2(ERR, "DeleteWins: Could not delete one or more records of WINS with owner Id = (%d) and address = (%x)\n", OwnerId,
  3796. pWinsAdd->Add.IPAdd);
  3797. }
  3798. } //end of try
  3799. except(EXCEPTION_EXECUTE_HANDLER) {
  3800. ExcCode = GetExceptionCode();
  3801. DBGPRINT1(EXC, "DeleteWins: Got Exception (%x)\n", ExcCode);
  3802. RetStat = WINS_FAILURE;
  3803. } // end of exception handler
  3804. if (fEnterCrtSec)
  3805. {
  3806. LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
  3807. }
  3808. if (RetStat == WINS_FAILURE)
  3809. {
  3810. //
  3811. // There is no danger of pWinsAdd being NULL. See WinsDeleteWins
  3812. //
  3813. WinsEvtLogDetEvt(FALSE, WINS_EVT_COULD_NOT_DELETE_WINS_RECS,
  3814. NULL, __LINE__, "dd", pWinsAdd->Add.IPAdd,
  3815. ExcCode );
  3816. //
  3817. // Since we are leaving the database in an inconsistent state,
  3818. // mark the WINS as inconsistent
  3819. //
  3820. (pNmsDbOwnAddTbl+OwnerId)->WinsState_e = NMSDB_E_WINS_INCONSISTENT;
  3821. } else {
  3822. WINSEVT_LOG_INFO_STR_D_M(WINS_EVT_DEL_OWNER_COMPLETED, &EvtStrs);
  3823. }
  3824. } // end of else
  3825. } // end of if (WINS is in own-add table)
  3826. //
  3827. // deallocate the buffer
  3828. //
  3829. WinsMscDealloc(pWinsAdd);
  3830. return;
  3831. }
  3832. BOOL
  3833. AcceptPersona(
  3834. PCOMM_ADD_T pWinsAdd
  3835. )
  3836. /*++
  3837. Routine Description:
  3838. Accept a persona in either of the two situations:
  3839. - PersonaType setting points to 'Persona Grata list', the list exists and
  3840. the address is in the list.
  3841. - PersonaType setting points to 'Persona Non-Grata list' and either the list
  3842. doesn't exist or the address is not there.
  3843. Side effects:
  3844. - If none of the two settings is defined (PersonaType & PersonaList)
  3845. this is like a non-existant 'Persona Non-Grata list' which means all WINS
  3846. will be accepted.
  3847. - If only PersonaType exists and it says 'Persona Grata list' this is like
  3848. a non-existant Persona Grata list hence no WINS will be accepted!
  3849. Arguments:
  3850. pWinsAdd - address of the WINS to check
  3851. Return Value:
  3852. TRUE if the WINS pWinsAdd is a persona grata/non-grata (depending on fGrata),
  3853. FALSE otherwise
  3854. Called by:
  3855. FilterPersona()
  3856. --*/
  3857. {
  3858. PRPL_ADD_VERS_NO_T pPersona = NULL;
  3859. DBGPRINT1(RPLPULL, "AcceptPersona check for address=(%x)\n", pWinsAdd->Add.IPAdd);
  3860. // if the list exists, look for the address in it
  3861. if (WinsCnf.pPersonaList != NULL)
  3862. pPersona = bsearch(
  3863. pWinsAdd,
  3864. WinsCnf.pPersonaList,
  3865. (size_t)WinsCnf.NoOfPersona,
  3866. sizeof(COMM_ADD_T),
  3867. ECommCompareAdd);;
  3868. if (WinsCnf.fPersonaGrata)
  3869. // if the list is 'persona grata', the address has to be there in order to
  3870. // be accepted.
  3871. return (pPersona != NULL);
  3872. else
  3873. // otherwise, WINS is accepted if either the list doesn't exist or the address
  3874. // is not there
  3875. return (pPersona == NULL);
  3876. }
  3877. VOID
  3878. FilterPersona(
  3879. PPUSHPNR_DATA_T pPushData
  3880. )
  3881. /*++
  3882. Routine Description:
  3883. Filters out from the PUSHPNR_DATA_T structure those OwnerAddress<->VersionNo mappings
  3884. that are denied by persona grata/non-grata list. This routine adjustes from that structure
  3885. only the NoOfMaps field and moves around elements in the array pointed by pAddVers
  3886. (bubbling up the ones that are accepted).
  3887. Arguments:
  3888. pPushData - pointer to the PUSHPNR_DATA_T providing the mapping table
  3889. Called by:
  3890. HdlPushNtf
  3891. --*/
  3892. {
  3893. DWORD i, newNoOfMaps;
  3894. PRPL_ADD_VERS_NO_T pAddVers = pPushData->pAddVers;
  3895. // in most common case, none of 'PersonaType' or 'PersonaList' is defined. This means
  3896. // we deny no WINS so we don't need to filter anything - then get out right away.
  3897. if (!WinsCnf.fPersonaGrata && WinsCnf.pPersonaList == NULL)
  3898. return;
  3899. for (i = 0, newNoOfMaps = 0; i < pPushData->NoOfMaps; i++)
  3900. {
  3901. if (AcceptPersona(&(pAddVers[i].OwnerWinsAdd)))
  3902. {
  3903. // if the decision is to accept this WINS, move it to the top of the list
  3904. // over the ones that were rejected. If none was rejected yet, no memory
  3905. // operation is performed.
  3906. if (newNoOfMaps < i)
  3907. {
  3908. memcpy(&pAddVers[newNoOfMaps], &pAddVers[i], sizeof(RPL_ADD_VERS_NO_T));
  3909. }
  3910. // since this wins was accepted, increment the counter of accepted wins.
  3911. newNoOfMaps++;
  3912. }
  3913. }
  3914. // only the first newNoOfMaps have to be considered from now on
  3915. pPushData->NoOfMaps = newNoOfMaps;
  3916. // just in case no WINS was accepted, cleanup the pAddVers array
  3917. if (pPushData->NoOfMaps == 0 && pPushData->pAddVers != NULL)
  3918. {
  3919. WinsMscDealloc(pPushData->pAddVers);
  3920. pPushData->pAddVers = NULL;
  3921. }
  3922. }
  3923. VOID
  3924. RplPullAllocVersNoArray(
  3925. PRPL_VERS_NOS_T *ppRplOwnerVersNo,
  3926. DWORD CurrentNo
  3927. )
  3928. {
  3929. if (*ppRplOwnerVersNo != NULL)
  3930. {
  3931. DWORD MemSize = sizeof(RPL_VERS_NOS_T) * (CurrentNo + 100);
  3932. WINSMSC_REALLOC_M( MemSize, (LPVOID *)ppRplOwnerVersNo );
  3933. }
  3934. else
  3935. {
  3936. DWORD MemSize = sizeof(RPL_VERS_NOS_T) * (CurrentNo + 100);
  3937. WinsMscAlloc(
  3938. MemSize,
  3939. (LPVOID *)ppRplOwnerVersNo
  3940. );
  3941. }
  3942. return;
  3943. }