Leaked source code of windows server 2003
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.

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