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

2448 lines
58 KiB

  1. /*+
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. nmschl.c
  5. Abstract:
  6. This module contains the name challenge functions
  7. Functions:
  8. NmsChlInit
  9. NmsChlHdlNamReg
  10. ChlThdInitFn
  11. HandleWrkItm
  12. WaitForRsp
  13. ProcRsp
  14. ChlUpdateDb
  15. InfRemWins
  16. Portability:
  17. This module is portable
  18. Author:
  19. Pradeep Bahl (PradeepB) Jan-1993
  20. Revision History:
  21. Modification date Person Description of modification
  22. ----------------- ------- ----------------------------
  23. --*/
  24. /*
  25. * Includes
  26. */
  27. #include <time.h>
  28. #include "wins.h"
  29. #include "nms.h"
  30. #include "nmsdb.h"
  31. #include "winsque.h"
  32. #include "comm.h"
  33. #include "winsthd.h"
  34. #include "winsmsc.h"
  35. #include "winsevt.h"
  36. #include "winscnf.h"
  37. #include "nmsnmh.h"
  38. #include "nmschl.h"
  39. #include "nmsmsgf.h"
  40. #include "rplmsgf.h"
  41. /*
  42. * Local Macro Declarations
  43. */
  44. //
  45. // Computation of the time it can take for a WINS to conduct a challenge
  46. // (in msecs)
  47. //
  48. #define WACK_TTL (((1 << WinsCnf.MaxNoOfRetries) * \
  49. WinsCnf.RetryInterval) + \
  50. WAIT_PAD)
  51. //
  52. // WAIT_PAD is used to increase the TTL sent to an NBT node that sent us the
  53. // name registration request. The pad is on top of the TTL we compute
  54. // (WACK_TLL) above to determine how much time WINS will take to conduct
  55. // the challenge. The pad is supposed to take care of the situation where
  56. // WINS is dragging its feet due to a sudden transient peak in network
  57. // load or cpu load.
  58. #define WAIT_PAD 500 //500 msecs in case WINS is very
  59. //busy
  60. /*
  61. * Global Variable Definitions
  62. */
  63. //
  64. // heap used to allocate work items for the challenge request and response
  65. // queues
  66. //
  67. HANDLE NmsChlHeapHdl;
  68. /*
  69. * Local Variable Definitions
  70. */
  71. //
  72. // It maintains a running count of how many responses to queries/releases are
  73. // pending
  74. //
  75. DWORD scPendingRsp = 0;
  76. //
  77. // The maximum # of requests that the name challenge manager sends at any
  78. // one time. This number is never allowed to go over
  79. // NMSCHL_MAX_CHL_REQ_AT_ONE_TIME. In fact after one series of
  80. // challenges are over (i.e. either they have timed out or we have received
  81. // responses for them, this counter is reinitialized to 0)
  82. //
  83. // This var. is reinitialized to zero when a batch of challenge requests
  84. // is acquired from the one or more of the challenge request queues
  85. //
  86. // It maintains the total # of requests acquired from the request queues.
  87. //
  88. DWORD sMaxTransId = 0;
  89. #ifdef WINSDBG
  90. DWORD NmsChlNoOfReqNbt;
  91. DWORD NmsChlNoOfReqRpl;
  92. DWORD NmsChlNoNoRsp;
  93. DWORD NmsChlNoInvRsp;
  94. DWORD NmsChlNoRspDropped;
  95. DWORD NmsChlNoReqDequeued;
  96. DWORD NmsChlNoRspDequeued;
  97. DWORD NmsChlNoReqAtHdOfList;
  98. #endif
  99. //
  100. // We have a dimension 1 larger than the max. number of challenge requests
  101. // handled at one time so that we can terminate the list with a NULL.
  102. //
  103. STATIC PCHL_REQ_WRK_ITM_T spReqWrkItmArr[NMSCHL_MAX_CHL_REQ_AT_ONE_TIME + 1];
  104. /*
  105. * Local Function Prototype Declarations
  106. */
  107. STATIC
  108. DWORD
  109. ChlThdInitFn(
  110. IN LPVOID pThreadParam
  111. );
  112. STATIC
  113. STATUS
  114. HandleWrkItm(
  115. PCHL_REQ_WRK_ITM_T *ppaWrkItm,
  116. DWORD MaxTransId,
  117. BOOL fRetry
  118. );
  119. STATIC
  120. STATUS
  121. WaitForRsp(
  122. VOID
  123. );
  124. STATIC
  125. STATUS
  126. ProcRsp(
  127. VOID
  128. );
  129. STATIC
  130. STATUS
  131. ChlUpdateDb(
  132. BOOL fUpdVersNoOfCnfRec,
  133. WINS_CLIENT_E Client_e,
  134. PNMSDB_ROW_INFO_T pRowInfo,
  135. DWORD OwnerIdInCnf,
  136. BOOL fRefreshOnly
  137. );
  138. STATIC
  139. VOID
  140. InfRemWins(
  141. PCHL_REQ_WRK_ITM_T pWrkItm
  142. );
  143. STATIC
  144. STATUS
  145. ProcAddList(
  146. PCHL_REQ_WRK_ITM_T pReqWrkItm,
  147. PNMSMSGF_CNT_ADD_T pCntAdd,
  148. LPBOOL pfAdded
  149. );
  150. /* prototypes for functions local to this module go here */
  151. STATUS
  152. NmsChlInit(
  153. VOID
  154. )
  155. /*++
  156. Routine Description:
  157. This function is called to initialize the name challenge component
  158. Arguments:
  159. None
  160. Externals Used:
  161. None
  162. Return Value:
  163. WINS_SUCCESS or a failure code. The function can also raise an
  164. exception in case of fatal errors
  165. Error Handling:
  166. Called by:
  167. Init in nms.c
  168. Side Effects:
  169. Comments:
  170. None
  171. --*/
  172. {
  173. STATUS RetStat = WINS_SUCCESS;
  174. /*
  175. * Create heap for allocating name challenge work items
  176. */
  177. DBGPRINT0(HEAP_CRDL, "NmsChlInit: Chl. Mgr. heap\n");
  178. NmsChlHeapHdl = WinsMscHeapCreate(
  179. 0, /*to have mutual exclusion */
  180. NMSCHL_INIT_BUFF_HEAP_SIZE
  181. );
  182. //
  183. // Initialize the spReqWrkItmArr elements to NULL
  184. //
  185. // ANSI C should do it for us (all externals are initialized
  186. // automatically, but I am taking no chances). This is
  187. // init time overhead.
  188. //
  189. WINSMSC_FILL_MEMORY_M((void *)spReqWrkItmArr, sizeof(spReqWrkItmArr), 0);
  190. //
  191. // Create the response event handle. This event is signaled
  192. // by the UDP listener thread when it stores a response
  193. // in the spReqWrkItmArr array
  194. //
  195. WinsMscCreateEvt(
  196. TEXT("WinsNmsChlRspEvt"),
  197. FALSE, //auto-reset
  198. &QueNmsCrqQueHd.EvtHdl
  199. );
  200. //
  201. // Initialize the critical section for the response queue
  202. //
  203. InitializeCriticalSection(&QueNmsCrqQueHd.CrtSec);
  204. //
  205. //Initialize the queue head for the response queue
  206. //
  207. InitializeListHead(&QueNmsCrqQueHd.Head);
  208. //
  209. // Since this thread deals with two request queues instead of
  210. // one, we need to create one more
  211. // critical section and event handle and initialize the
  212. // queue head of this other queue. The second queue
  213. // will be created when we create the thread
  214. //
  215. InitializeListHead(&QueNmsRrcqQueHd.Head);
  216. WinsMscCreateEvt(
  217. TEXT("WinsNmsChlReplReqEvt"),
  218. FALSE, //Auto Reset
  219. &QueNmsRrcqQueHd.EvtHdl
  220. );
  221. InitializeCriticalSection(&QueNmsRrcqQueHd.CrtSec);
  222. //
  223. //
  224. // Create the name challenge thread. This function will
  225. // initialize the critical section and the Evt handle passed
  226. // to it
  227. //
  228. RetStat = WinsMscSetUpThd(
  229. &QueNmsNrcqQueHd, //queue head
  230. ChlThdInitFn, //init function
  231. NULL, // no param
  232. &WinsThdPool.ChlThd[0].ThdHdl,
  233. &WinsThdPool.ChlThd[0].ThdId
  234. );
  235. if (RetStat == WINS_SUCCESS)
  236. {
  237. WinsThdPool.ChlThd[0].fTaken = TRUE;
  238. WinsThdPool.ThdCount++; //increment the thread count
  239. }
  240. return(RetStat);
  241. } // NmsChlInit()
  242. STATUS
  243. NmsChlHdlNamReg(
  244. IN NMSCHL_CMD_TYP_E CmdTyp_e,
  245. IN WINS_CLIENT_E Client_e,
  246. IN PCOMM_HDL_T pDlgHdl,
  247. IN MSG_T pMsg,
  248. IN MSG_LEN_T MsgLen,
  249. IN DWORD QuesNamSecLen,
  250. IN PNMSDB_ROW_INFO_T pNodeToReg,
  251. IN PNMSDB_STAT_INFO_T pNodeInCnf,
  252. // IN PCOMM_ADD_T pAddOfNodeInCnf,
  253. IN PCOMM_ADD_T pAddOfRemWins
  254. )
  255. /*++
  256. Routine Description:
  257. This function is called to handle a name registration that resulted
  258. in a conflict
  259. Arguments:
  260. CmdTyp_e - Type of command (challenge, challenge and release if
  261. challenge succeeds, release -- see nmschl.h)
  262. Client_e - client (nms or replicator)
  263. pDlgHdl - Dlg hdl (only if client is nms)
  264. pMsg - Buffer containing request (only if client is nms)
  265. Msglen - length of above buffer
  266. QuesNamSecLen - Length of question name section in buffer
  267. pNodeToreq - Info about name to register
  268. pAddOfNodeInCnf - address of node in conflict (i.e. has name) with the
  269. node trying to register
  270. Externals Used:
  271. None
  272. Return Value:
  273. WINS_SUCCESS or a failure code. The function can also raise an
  274. exception in case of fatal errors
  275. Error Handling:
  276. Called by:
  277. NmsNmhNamRegInd, NmsNmhNamRegGrp (in an Nbt thread)
  278. Side Effects:
  279. Comments:
  280. None
  281. --*/
  282. {
  283. STATUS RetStat = WINS_SUCCESS;
  284. #if USENETBT == 0
  285. BYTE aBuff[COMM_DATAGRAM_SIZE];
  286. #else
  287. BYTE aBuff[COMM_DATAGRAM_SIZE + COMM_NETBT_REM_ADD_SIZE];
  288. #endif
  289. DWORD BuffLen;
  290. DBGENTER("NmsChlHdlNamReg\n");
  291. //
  292. // Before inserting the request, send a WACK. The Time period
  293. // in the TTL should be equal to WinsCnf.RetryInterval
  294. //
  295. // Note: WACK is sent only if pDlgHdl is NON-NULL since that
  296. // implies that the request is from an NBT thread
  297. //
  298. if (pDlgHdl != NULL)
  299. {
  300. COMM_ADD_T NodeToSendWACKTo;
  301. DWORD WackTtl;
  302. if (NMSDB_ENTRY_MULTIHOMED_M(pNodeInCnf->EntTyp))
  303. {
  304. WackTtl = pNodeInCnf->NodeAdds.NoOfMems * WACK_TTL;
  305. }
  306. else
  307. {
  308. WackTtl = WACK_TTL;
  309. }
  310. //
  311. // Format the WACK
  312. //
  313. NmsMsgfFrmWACK(
  314. #if USENETBT == 0
  315. aBuff,
  316. #else
  317. aBuff + COMM_NETBT_REM_ADD_SIZE,
  318. #endif
  319. &BuffLen,
  320. pMsg,
  321. QuesNamSecLen,
  322. WackTtl
  323. );
  324. //
  325. // We extract the address from the DlgHdl and don't use
  326. // the address passed in the name packet since a node
  327. // can register a name with an address different than
  328. // its own.
  329. //
  330. // RFCs are silent about the above
  331. //
  332. NodeToSendWACKTo.AddLen = COMM_IP_ADD_SIZE;
  333. COMM_GET_IPADD_M(pDlgHdl, &NodeToSendWACKTo.Add.IPAdd);
  334. NodeToSendWACKTo.AddTyp_e = COMM_ADD_E_TCPUDPIP;
  335. DBGPRINT2(CHL, "NmsChlHdlNamReg: Sending WACK to node with name = (%s) and address = (%X)\n", pNodeToReg->pName, NodeToSendWACKTo.Add.IPAdd);
  336. //
  337. // Send the WACK. Use the explicit NBT dlg handle since the
  338. // WACK has to be sent as a UDP packet.
  339. //
  340. ECommSendMsg(
  341. &CommExNbtDlgHdl,
  342. &NodeToSendWACKTo,
  343. #if USENETBT == 0
  344. aBuff,
  345. #else
  346. aBuff + COMM_NETBT_REM_ADD_SIZE,
  347. #endif
  348. BuffLen
  349. );
  350. }
  351. WINSMSC_COPY_MEMORY_M(
  352. pNodeToReg->Name,
  353. pNodeToReg->pName,
  354. pNodeToReg->NameLen
  355. );
  356. //
  357. // Insert the request in the challenge queue so that the challenge
  358. // thread can get it
  359. //
  360. RetStat = QueInsertChlReqWrkItm(
  361. CmdTyp_e,
  362. Client_e,
  363. pDlgHdl,
  364. pMsg,
  365. MsgLen,
  366. QuesNamSecLen,
  367. pNodeToReg,
  368. pNodeInCnf,
  369. pAddOfRemWins
  370. );
  371. #ifdef WINSDBG
  372. if (Client_e == WINS_E_NMSNMH)
  373. {
  374. NmsChlNoOfReqNbt++;
  375. }
  376. else
  377. {
  378. NmsChlNoOfReqRpl++;
  379. }
  380. #endif
  381. DBGLEAVE("NmsChlHdlNamReg\n");
  382. return(RetStat);
  383. } // NmsChlHdlNamReg()
  384. DWORD
  385. ChlThdInitFn(
  386. IN LPVOID pThreadParam
  387. )
  388. /*++
  389. Routine Description:
  390. This is the initialization function for the name challenge thread
  391. Arguments:
  392. pThreadParam - NOT USED
  393. Externals Used:
  394. None
  395. Return Value:
  396. This function should never return. If it returns it means there
  397. is some problem. WINS_FAILURE is returned when this happens
  398. Error Handling:
  399. Called by:
  400. NmsChlInit
  401. Side Effects:
  402. A name challenge thread is created
  403. Comments:
  404. None
  405. --*/
  406. {
  407. STATUS RetStat = WINS_SUCCESS;
  408. HANDLE ThdEvtHdlArray[3];
  409. DWORD ArrInd; //index of hdl signaled
  410. PCHL_REQ_WRK_ITM_T pWrkItm = NULL;
  411. BOOL fTablesOpen = FALSE;
  412. BOOL bRecoverable = FALSE;
  413. UNREFERENCED_PARAMETER(pThreadParam);
  414. while(TRUE)
  415. {
  416. try {
  417. if (!bRecoverable)
  418. {
  419. /*
  420. Initialize the thread with the database
  421. */
  422. NmsDbThdInit(WINS_E_NMSCHL);
  423. DBGMYNAME("Name Challenge Thread");
  424. /*
  425. * Initialize the array of handles on which the challenge thread will
  426. * wait.
  427. */
  428. ThdEvtHdlArray[0] = NmsTermEvt; //termination event var
  429. ThdEvtHdlArray[1] = QueNmsNrcqQueHd.EvtHdl; //work queue event var
  430. ThdEvtHdlArray[2] = QueNmsRrcqQueHd.EvtHdl; //work queue event var
  431. bRecoverable = TRUE;
  432. }
  433. while (TRUE)
  434. {
  435. WinsMscWaitUntilSignaled(
  436. ThdEvtHdlArray,
  437. sizeof(ThdEvtHdlArray)/sizeof(HANDLE),
  438. &ArrInd,
  439. FALSE
  440. );
  441. //
  442. // if NmsTermEvt was signaled, terminate self
  443. //
  444. if (ArrInd == 0)
  445. {
  446. WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
  447. }
  448. while (TRUE)
  449. {
  450. scPendingRsp = 0; //reinit TransId Counter to 0
  451. sMaxTransId = 0; //reinit MaxTransId Counter to 0
  452. RetStat = QueRemoveChlReqWrkItm(
  453. ThdEvtHdlArray[ArrInd],
  454. (LPVOID *)spReqWrkItmArr,
  455. &sMaxTransId
  456. );
  457. if (RetStat == WINS_NO_REQ)
  458. {
  459. break; //break out of while loop
  460. }
  461. else // one or more items were dequeued
  462. {
  463. #ifdef WINSDBG
  464. NmsChlNoReqDequeued += sMaxTransId;
  465. #endif
  466. NmsDbOpenTables(WINS_E_NMSCHL);
  467. fTablesOpen = TRUE;
  468. scPendingRsp = sMaxTransId;
  469. QueChlWaitForRsp();
  470. //
  471. // If HandleWrkItm fails, it will raise
  472. // an exception
  473. //
  474. HandleWrkItm(
  475. spReqWrkItmArr,
  476. sMaxTransId,
  477. FALSE //not a retry
  478. );
  479. //
  480. // Wait for responses to all requests sent
  481. // WaitForRsp() function will return only
  482. // after all requests are done with
  483. // as a result of responses having been
  484. // received for them, they having timed out
  485. // after the requisite number of retries or
  486. // a mix of both.
  487. //
  488. WaitForRsp();
  489. QueChlNoWaitForRsp();
  490. NmsDbCloseTables();
  491. fTablesOpen = FALSE;
  492. }
  493. } // end of while (TRUE)
  494. } // end of while (TRUE)
  495. } // end of try {..}
  496. except (EXCEPTION_EXECUTE_HANDLER) {
  497. if (bRecoverable)
  498. {
  499. DWORD No;
  500. DWORD ExcCode = GetExceptionCode();
  501. DBGPRINTEXC("ChlThdInitFn: Name Challenge Thread");
  502. //
  503. // If ExcCode is NBT_ERR, it could mean that the main thread
  504. // closed the netbt handle.
  505. //
  506. if ( ExcCode == WINS_EXC_NBT_ERR)
  507. {
  508. if (WinsCnf.State_e == WINSCNF_E_TERMINATING)
  509. {
  510. WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
  511. }
  512. else
  513. {
  514. //if ((WinsCnf.State_e != WINSCNF_E_PAUSED) && (!fWinsCnfInitStatePaused))
  515. {
  516. WINSEVT_LOG_M(ExcCode, WINS_EVT_CHL_EXC);
  517. }
  518. }
  519. }
  520. else
  521. {
  522. WINSEVT_LOG_M(ExcCode, WINS_EVT_CHL_EXC);
  523. }
  524. if(fTablesOpen)
  525. {
  526. NmsDbCloseTables();
  527. fTablesOpen = FALSE;
  528. }
  529. //
  530. // For all requests that were never sent, free them
  531. //
  532. for (No=0; No < sMaxTransId; No++)
  533. {
  534. if (spReqWrkItmArr[No] != NULL)
  535. {
  536. if (spReqWrkItmArr[No]->pMsg != NULL)
  537. {
  538. ECommFreeBuff(spReqWrkItmArr[No]->pMsg);
  539. }
  540. QueDeallocWrkItm(NmsChlHeapHdl, spReqWrkItmArr[No]);
  541. }
  542. }
  543. QueChlNoWaitForRsp();
  544. } // end of if (bRecoverable)
  545. else // if (bRecoverable)
  546. {
  547. DBGPRINTEXC("ChlThdInitFn: Name Challenge Thread");
  548. //
  549. // If NmsDbThdInit comes back with an exception, it is possible
  550. // that the session has not yet been started. Passing
  551. // WINS_DB_SESSION_EXISTS however is ok
  552. //
  553. //
  554. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_CHL_ABNORMAL_SHUTDOWN);
  555. WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
  556. } // if (bRecoverable)
  557. } // exception handler
  558. } // while(TRUE)
  559. //
  560. // We should never get here
  561. //
  562. return(WINS_FAILURE);
  563. } // ChlThdInitFn()
  564. STATUS
  565. HandleWrkItm(
  566. IN PCHL_REQ_WRK_ITM_T *ppaWrkItm,
  567. IN DWORD MaxTransId,
  568. IN BOOL fRetry
  569. )
  570. /*++
  571. Routine Description:
  572. This function is called to send a name query to the node that
  573. was confliciting
  574. Arguments:
  575. ppaWrkItm - Address of an array of pointers to work items that
  576. got queued in one or more of the challenge queues
  577. MaxTransId - One more than the index of the last filled entry in
  578. the array
  579. fRetry - indicates whether HandleWrkItm is being called to
  580. retry a request
  581. Externals Used:
  582. None
  583. Return Value:
  584. Success status codes -- WINS_SUCCESS
  585. Error status codes -- WINS_FAILURE
  586. Error Handling:
  587. Called by:
  588. ChlThdInitFn(), WaitForRsp
  589. Side Effects:
  590. Comments:
  591. None
  592. --*/
  593. {
  594. #if USENETBT == 0
  595. BYTE Buff[COMM_DATAGRAM_SIZE];
  596. #else
  597. BYTE Buff[COMM_DATAGRAM_SIZE + COMM_NETBT_REM_ADD_SIZE];
  598. #endif
  599. MSG_LEN_T MsgLen;
  600. LPBYTE pName = NULL;
  601. DWORD NameLen = 0;
  602. PCOMM_ADD_T pAddOfNodeInCnf = NULL;
  603. NMSCHL_CMD_TYP_E CmdTyp_e;
  604. NMSMSGF_NODE_TYP_E NodeTyp_e;
  605. DWORD cPendingRsp = 0; //count of pending
  606. //responses
  607. volatile DWORD i;
  608. DBGENTER("HandleWrkItm\n");
  609. PERF("For retries, reuse the buffer sent for the initial try. This means")
  610. PERF("that I need to allocate it and store it in the request work item")
  611. PERF("instead of using the stack for it")
  612. UNREFERENCED_PARAMETER(fRetry);
  613. //
  614. // Loop over all slots of the array that were filled as a result of
  615. // the acquisition of requests from the challenge request queue(s)
  616. //
  617. FUTURES("Remove the exception handler out of production code")
  618. try {
  619. DBGPRINT1(CHL, "HandleWrkItm: Max Trans. Id = (%d)\n", MaxTransId);
  620. for(
  621. i = 0;
  622. i < MaxTransId;
  623. ppaWrkItm++, i++
  624. )
  625. {
  626. //
  627. // if we have hit an empty slot, it means that this function
  628. // has been called to retry one or more requests that
  629. // did not get satisfied in the first wait period. The empty
  630. // slot indicates that a request that occupied this slot
  631. // got satisfied in one of the earlier retries. Just
  632. // skip the empty slot
  633. //
  634. if (fRetry && (*ppaWrkItm == NULL))
  635. {
  636. DBGPRINT1(CHL, "HandleWrkItm: HIT a NULL entry. Trans. Id = (%d)\n", i);
  637. continue;
  638. }
  639. (*ppaWrkItm)->NodeToReg.pName = (*ppaWrkItm)->NodeToReg.Name;
  640. CmdTyp_e = (*ppaWrkItm)->CmdTyp_e;
  641. NodeTyp_e = (*ppaWrkItm)->NodeToReg.NodeTyp;
  642. pName = (*ppaWrkItm)->NodeToReg.pName;
  643. //
  644. // if the first character is 0x1B, swap the bytes
  645. // This is for supporting the browser. See
  646. // NmsMsgfProcNbtReq
  647. //
  648. if (*pName == 0x1B)
  649. {
  650. WINS_SWAP_BYTES_M(pName, pName + 15);
  651. }
  652. NameLen = (*ppaWrkItm)->NodeToReg.NameLen;
  653. //
  654. // get the last address (the only address unless the node in
  655. // conflict is a multihomed node) from the list of addresses
  656. //
  657. pAddOfNodeInCnf = &((*ppaWrkItm)->NodeAddsInCnf.Mem[
  658. (*ppaWrkItm)->NoOfAddsToUse - 1
  659. ].Add);
  660. //
  661. // If the command is directing us to do a challenge, send a
  662. // name query
  663. //
  664. if (
  665. (CmdTyp_e == NMSCHL_E_CHL)
  666. ||
  667. (CmdTyp_e == NMSCHL_E_CHL_N_REL_N_INF)
  668. ||
  669. (CmdTyp_e == NMSCHL_E_CHL_N_REL)
  670. )
  671. {
  672. DBGPRINT3(CHL, "HandleWrkItm: Sending Name Query Request with Transid = (%d) to node with name = (%s) and address = (%X)\n", i, pName, pAddOfNodeInCnf->Add.IPAdd);
  673. NmsMsgfFrmNamQueryReq(
  674. i, //Transaction Id
  675. #if USENETBT == 0
  676. Buff,
  677. #else
  678. Buff + COMM_NETBT_REM_ADD_SIZE,
  679. #endif
  680. &MsgLen,
  681. pName,
  682. NameLen
  683. );
  684. (*ppaWrkItm)->ReqTyp_e = NMSMSGF_E_NAM_QUERY;
  685. }
  686. else // has to be NMSCHL_E_REL or NMSCHL_E_REL_N_INF or
  687. // NMSCHL_E_REL_ONLY
  688. {
  689. DBGPRINT3(CHL,
  690. "HandleWrkItm: Sending Name Release Request with Transid = (%d) to node with name = (%s) and address = (%X)\n", i, pName, pAddOfNodeInCnf->Add.IPAdd);
  691. NmsMsgfFrmNamRelReq(
  692. i, //Transaction Id
  693. #if USENETBT == 0
  694. Buff,
  695. #else
  696. Buff + COMM_NETBT_REM_ADD_SIZE,
  697. #endif
  698. &MsgLen,
  699. pName,
  700. NameLen,
  701. NodeTyp_e,
  702. pAddOfNodeInCnf
  703. );
  704. (*ppaWrkItm)->ReqTyp_e = NMSMSGF_E_NAM_REL;
  705. }
  706. ECommSendMsg(
  707. &CommExNbtDlgHdl,
  708. pAddOfNodeInCnf,
  709. #if USENETBT == 0
  710. Buff,
  711. #else
  712. Buff + COMM_NETBT_REM_ADD_SIZE,
  713. #endif
  714. MsgLen
  715. );
  716. cPendingRsp++;
  717. }
  718. //
  719. // Do a sanity check
  720. //
  721. #ifdef WINSDBG
  722. if (cPendingRsp != scPendingRsp)
  723. {
  724. DBGPRINT2(EXC, "SOFTWARE ERROR. THE COUNT OF PENDING RESPONSES (%d) AS COMPUTED BY THE HandleWrkItm FN DOES NOT MATCH WITH THE EXPECTED ONE (%d)\n\n", cPendingRsp, scPendingRsp);
  725. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  726. }
  727. #endif
  728. }
  729. except(EXCEPTION_EXECUTE_HANDLER) {
  730. DBGPRINTEXC("HandleWrkItm");
  731. //
  732. // if the exception is an nbt error, it is expected if wins is in
  733. // the paused state. Do not reraise the exception if this is the
  734. // case. We want to go through our WaitRsp() function so that
  735. // the new records (replicas or registrations) get registered.
  736. // If this results in an inconsistent db, it will straighten
  737. // itself out soon after WINS is unpaused.
  738. //
  739. //if (!((GetExceptionCode() == WINS_EXC_NBT_ERR) && (WinsCnf.State_e ==
  740. // WINSCNF_E_PAUSED) || (fWinsCnfInitStatePaused)))
  741. {
  742. WINS_RERAISE_EXC_M();
  743. }
  744. #if 0
  745. else
  746. {
  747. //
  748. // For all requests that were never sent, free them
  749. //
  750. for (No=0; No < sMaxTransId; No++, pReqWrkItm++)
  751. {
  752. if (pReqWrkItm != NULL)
  753. {
  754. if (pReqWrkItm->pMsg != NULL)
  755. {
  756. ECommFreeBuff(pReqWrkItm->pMsg);
  757. }
  758. QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
  759. }
  760. }
  761. #endif
  762. } // end of except { .. }
  763. DBGLEAVE("HandleWrkItm\n");
  764. return(WINS_SUCCESS);
  765. } // HandleWrkItm()
  766. STATUS
  767. WaitForRsp(
  768. VOID
  769. )
  770. /*++
  771. Routine Description:
  772. This function is responsible for waiting for responses to all
  773. requests that have been sent until either they time out or their
  774. responses are received.
  775. Arguments:
  776. None
  777. Externals Used:
  778. None
  779. Return Value:
  780. WINS_SUCCESS or a failure code. The function can also raise an
  781. exception in case of fatal errors
  782. Error Handling:
  783. Called by:
  784. Side Effects:
  785. Comments:
  786. None
  787. --*/
  788. {
  789. HANDLE ThdEvtHdlArray[2];
  790. DWORD Count = 0;
  791. DWORD TickCntSv;
  792. DWORD TickCnt = 0;
  793. DWORD TimeLeft;
  794. BOOL fSignaled = TRUE; //was an event signaled
  795. DWORD ArrInd = 0; //Not used
  796. DWORD i = 0;
  797. NMSMSGF_ERR_CODE_E Rcode_e = NMSMSGF_E_SRV_ERR;
  798. PCHL_REQ_WRK_ITM_T pReqWrkItm;
  799. NMSMSGF_RSP_INFO_T RspInfo;
  800. BOOL fNewTry = TRUE;
  801. /*
  802. * Initialize the array of handles on which the challenge thread will
  803. * wait.
  804. */
  805. ThdEvtHdlArray[0] = NmsTermEvt; //termination event var
  806. ThdEvtHdlArray[1] = QueNmsCrqQueHd.EvtHdl; //work queue event var
  807. FUTURES("Remove the try out of production level code")
  808. try {
  809. while(TRUE)
  810. {
  811. if (fNewTry)
  812. {
  813. //
  814. // Get the number of msecs that have
  815. // elapsed since windows was started
  816. //
  817. TickCntSv = GetTickCount();
  818. TimeLeft = (1 << Count) * WinsCnf.RetryInterval;
  819. }
  820. //
  821. // Check if we have exhausted all retries for this batch of
  822. // requests
  823. //
  824. if (Count == WinsCnf.MaxNoOfRetries)
  825. {
  826. //
  827. // CleanUp all spReqWrkItmArr entries which have not
  828. // been satisfied as yet.
  829. //
  830. for (i = 0; i < sMaxTransId; i++)
  831. {
  832. if (spReqWrkItmArr[i] != NULL)
  833. {
  834. #ifdef WINSDBG
  835. NmsChlNoNoRsp++;
  836. #endif
  837. pReqWrkItm = spReqWrkItmArr[i];
  838. //
  839. // Decrement the count of addresses to send query or
  840. // release to.
  841. //
  842. pReqWrkItm->NoOfAddsToUse--;
  843. //
  844. //
  845. // If there are no more addresses to challenge/release
  846. //
  847. if (pReqWrkItm->NoOfAddsToUse == 0)
  848. {
  849. //
  850. // Just in case the record to register is a UNIQUE
  851. // record. No need to have an if (will add overhead)
  852. //
  853. pReqWrkItm->NodeToReg.pNodeAdd =
  854. &pReqWrkItm->AddToReg;
  855. //
  856. // In case the row we are putting in the database is
  857. // one given to use by the Replicator, we don't
  858. // need to set Rcode_e. However, to avoid an if
  859. // test, we just set it. It will remain unused
  860. //
  861. if (pReqWrkItm->CmdTyp_e != NMSCHL_E_REL_ONLY)
  862. {
  863. if (
  864. ChlUpdateDb(
  865. FALSE,
  866. pReqWrkItm->Client_e,
  867. &pReqWrkItm->NodeToReg,
  868. pReqWrkItm->OwnerIdInCnf,
  869. FALSE //not just a refresh
  870. ) == WINS_SUCCESS
  871. )
  872. {
  873. DBGPRINT0(CHL, "WaitForRsp:Database Updated\n");
  874. //
  875. // if the remote WINS has to be notified of
  876. // the update, do so
  877. //
  878. if(pReqWrkItm->CmdTyp_e ==
  879. NMSCHL_E_REL_N_INF)
  880. {
  881. InfRemWins(pReqWrkItm);
  882. }
  883. Rcode_e = NMSMSGF_E_SUCCESS;
  884. }
  885. else
  886. {
  887. Rcode_e = NMSMSGF_E_SRV_ERR;
  888. WINSEVT_LOG_M(
  889. WINS_FAILURE,
  890. WINS_EVT_CHLSND_REG_RSP_ERR
  891. );
  892. DBGPRINT0(CHL, "WaitForRsp:Server Error\n");
  893. }
  894. }
  895. //
  896. // Send a response only if the registration request
  897. // was sent by an NBT node
  898. //
  899. if (
  900. (pReqWrkItm->Client_e == WINS_E_NMSNMH)
  901. &&
  902. (!pReqWrkItm->NodeToReg.fStatic)
  903. &&
  904. (!pReqWrkItm->NodeToReg.fAdmin)
  905. )
  906. {
  907. RspInfo.pMsg = pReqWrkItm->pMsg;
  908. RspInfo.MsgLen = pReqWrkItm->MsgLen;
  909. RspInfo.QuesNamSecLen =
  910. pReqWrkItm->QuesNamSecLen;
  911. RspInfo.Rcode_e = Rcode_e;
  912. if (Rcode_e == NMSMSGF_E_SUCCESS)
  913. {
  914. EnterCriticalSection(&WinsCnfCnfCrtSec);
  915. RspInfo.RefreshInterval =
  916. WinsCnf.RefreshInterval;
  917. LeaveCriticalSection(&WinsCnfCnfCrtSec);
  918. }
  919. NmsNmhSndNamRegRsp(
  920. &pReqWrkItm->DlgHdl,
  921. &RspInfo
  922. );
  923. }
  924. //
  925. // deallocate the req wrk items
  926. //
  927. QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
  928. }
  929. else // we haven't yet dealt with all the addresses. So,
  930. // let us requeue the work item.
  931. {
  932. //
  933. // Reinsert the work item since there are other
  934. // addresses that we need to handle in HandleWrkItm()
  935. //
  936. DBGPRINT2(CHL, "WaitForRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
  937. QueInsertWrkItmAtHdOfList(
  938. &pReqWrkItm->Head,
  939. pReqWrkItm->QueTyp_e,
  940. NULL
  941. );
  942. }
  943. //
  944. // Reinit the array entry to obliterate the
  945. // possibility of error (see ProcRsp)
  946. //
  947. spReqWrkItmArr[i] = NULL;
  948. scPendingRsp--; //actually there is no need for this
  949. //since scPendingRsp will be inited
  950. //after dequeing requests
  951. } // end of if
  952. } //end of for loop for looping over sReqWrkItm array
  953. break; //break out of the while(TRUE) loop
  954. }
  955. else //count is != WinsCnf.MaxNoOfRetries
  956. {
  957. WinsMscWaitTimedUntilSignaled(
  958. ThdEvtHdlArray,
  959. sizeof(ThdEvtHdlArray)/sizeof(HANDLE),
  960. &ArrInd,
  961. TimeLeft,
  962. &fSignaled
  963. );
  964. //
  965. // if signaled, it means a response item is in the response
  966. // queue.
  967. //
  968. if (fSignaled)
  969. {
  970. DWORD TicksToSub;
  971. //
  972. // If signaled for termination, do it
  973. //
  974. if (ArrInd == 0)
  975. {
  976. WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
  977. }
  978. DBGPRINT0(CHL, "WaitForRsp: Received a response\n");
  979. #ifdef WINSDBG
  980. NmsChlNoRspDequeued++;
  981. #endif
  982. ProcRsp();
  983. //
  984. // If no responses are expected, break out of loop
  985. //
  986. if (scPendingRsp == 0)
  987. {
  988. break; //break out of the while loop
  989. }
  990. //
  991. // Get the number of msecs that have
  992. // elapsed since windows was started
  993. //
  994. TickCnt = GetTickCount();
  995. //
  996. // If there has been a wrap around (will happen every 49.7
  997. // days of Windows being up
  998. //
  999. if (TickCnt < TickCntSv)
  1000. {
  1001. TicksToSub = (TickCnt + (MAXULONG - TickCntSv));
  1002. }
  1003. else
  1004. {
  1005. TicksToSub = TickCnt - TickCntSv;
  1006. }
  1007. //
  1008. // We don't want to subtract a biger number from a
  1009. // smaller number. This will result in a huge value for
  1010. // TimeLeft making the challenge thread block forever.
  1011. //
  1012. if (TimeLeft > TicksToSub)
  1013. {
  1014. TimeLeft -= TicksToSub;
  1015. fNewTry = FALSE;
  1016. }
  1017. else
  1018. {
  1019. Count++; //increment the count of retries
  1020. if ( Count != WinsCnf.MaxNoOfRetries)
  1021. {
  1022. //
  1023. // The Retry time interval being over, let us
  1024. // retry all those requests that did not get
  1025. // satisfied (i.e. no responses yet)
  1026. //
  1027. HandleWrkItm(
  1028. spReqWrkItmArr,
  1029. sMaxTransId,
  1030. TRUE //it is a retry
  1031. );
  1032. //
  1033. // We have waited for the entire allowed
  1034. // wait time. Time to do a retry
  1035. //
  1036. fNewTry = TRUE;
  1037. }
  1038. }
  1039. }
  1040. else
  1041. {
  1042. Count++; //increment the count of retries
  1043. if ( Count != WinsCnf.MaxNoOfRetries)
  1044. {
  1045. //
  1046. // The Retry time interval being over, let us
  1047. // retry all those requests that did not get
  1048. // satisfied (i.e. no responses yet)
  1049. //
  1050. HandleWrkItm(
  1051. spReqWrkItmArr,
  1052. sMaxTransId,
  1053. TRUE //it is a retry
  1054. );
  1055. fNewTry = TRUE;
  1056. }
  1057. }
  1058. }
  1059. } // end of while (TRUE)
  1060. } // end of try ..
  1061. except(EXCEPTION_EXECUTE_HANDLER) {
  1062. DBGPRINTEXC("WaitForRsp");
  1063. //
  1064. // must be some serious error. Reraise the exception
  1065. //
  1066. WINS_RERAISE_EXC_M();
  1067. } // end of except { ..}
  1068. return(WINS_SUCCESS);
  1069. } // WaitForRsp()
  1070. STATUS
  1071. ProcRsp(
  1072. VOID
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This function is called to process one or more work items
  1077. queued on the challenge response queue.
  1078. This response can be to name query or name release requests sent
  1079. earlier
  1080. Arguments:
  1081. None
  1082. Externals Used:
  1083. None
  1084. Return Value:
  1085. Success status codes -- WINS_SUCCESS
  1086. Error status codes -- WINS_FAILURE
  1087. Error Handling:
  1088. Called by:
  1089. WaitForRsp()
  1090. Side Effects:
  1091. Comments:
  1092. None
  1093. --*/
  1094. {
  1095. DWORD TransId = 0;
  1096. NMSMSGF_NAM_REQ_TYP_E Opcode_e = NMSMSGF_E_NAM_QUERY;
  1097. BYTE Name[NMSMSGF_RFC_MAX_NAM_LEN];
  1098. DWORD NameLen;
  1099. // COMM_IP_ADD_T IPAdd;
  1100. NMSMSGF_CNT_ADD_T CntAdd;
  1101. NMSMSGF_ERR_CODE_E Rcode_e;
  1102. PCHL_REQ_WRK_ITM_T pReqWrkItm;
  1103. STATUS RetVal;
  1104. PCHL_RSP_WRK_ITM_T pRspWrkItm;
  1105. STATUS RetStat = WINS_SUCCESS;
  1106. LPBYTE pNameToComp;
  1107. DWORD NameLenUsedInComp;
  1108. BOOL fAdded;
  1109. BOOL fGroup;
  1110. DBGENTER("ProcRsp\n");
  1111. while (TRUE)
  1112. {
  1113. //dequeue each response and process
  1114. RetVal = QueRemoveChlRspWrkItm(&pRspWrkItm);
  1115. if (RetVal == WINS_NO_REQ)
  1116. {
  1117. break;
  1118. }
  1119. if (
  1120. NmsMsgfUfmNamRsp(
  1121. pRspWrkItm->pMsg,
  1122. &Opcode_e,
  1123. &TransId,
  1124. Name,
  1125. &NameLen,
  1126. &CntAdd,
  1127. &Rcode_e,
  1128. &fGroup
  1129. ) == WINS_FAILURE
  1130. )
  1131. {
  1132. //
  1133. // Throw away response
  1134. //
  1135. ECommFreeBuff(pRspWrkItm->pMsg);
  1136. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1137. #ifdef WINSDBG
  1138. NmsChlNoInvRsp++;
  1139. #endif
  1140. continue;
  1141. }
  1142. //
  1143. // Get the request corresponding to the response.
  1144. //
  1145. if (TransId >= sMaxTransId)
  1146. {
  1147. //
  1148. // Throw away response
  1149. //
  1150. DBGPRINT3(ERR, "ProcRsp: Rsp: Name = (%s); Transid = (%d), Opcode_e = (%d). Being rejected (TOO LARGE TRANS. ID)\n", Name, TransId, Opcode_e);
  1151. ECommFreeBuff(pRspWrkItm->pMsg);
  1152. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1153. #ifdef WINSDBG
  1154. NmsChlNoInvRsp++;
  1155. #endif
  1156. continue;
  1157. }
  1158. pReqWrkItm = spReqWrkItmArr[TransId];
  1159. if (!pReqWrkItm)
  1160. {
  1161. //
  1162. // Throw this response away
  1163. //
  1164. ECommFreeBuff(pRspWrkItm->pMsg);
  1165. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1166. #ifdef WINSDBG
  1167. NmsChlNoInvRsp++;
  1168. #endif
  1169. continue;
  1170. }
  1171. //
  1172. // First and foremost check whether the response is for one of
  1173. // the current requests (we want to guard against mismatching
  1174. // the response to a request (the response could be for an old
  1175. // request that is no longer in our spReqWrkItmArr array.
  1176. //
  1177. //
  1178. // Compare the Name and the Opcode from where the
  1179. // response came with the same in the request
  1180. //
  1181. pNameToComp = pReqWrkItm->NodeToReg.pName;
  1182. NameLenUsedInComp = pReqWrkItm->NodeToReg.NameLen;
  1183. RetVal = (ULONG) WINSMSC_COMPARE_MEMORY_M(
  1184. Name,
  1185. pNameToComp,
  1186. NameLenUsedInComp
  1187. );
  1188. if (
  1189. (RetVal != NameLenUsedInComp )
  1190. ||
  1191. ( pReqWrkItm->ReqTyp_e != Opcode_e )
  1192. )
  1193. {
  1194. //
  1195. // Throw this response away
  1196. //
  1197. DBGPRINT5(ERR, "ProcRsp: Mismatch between response and request. Req/Res Name (%s/%s); ReqType_e/Opcode_e = (%d/%d). TransId = (%d)\n", pNameToComp, Name, pReqWrkItm->ReqTyp_e, Opcode_e, TransId);
  1198. WINSEVT_LOG_INFO_D_M(
  1199. WINS_SUCCESS,
  1200. WINS_EVT_REQ_RSP_MISMATCH
  1201. );
  1202. ECommFreeBuff(pRspWrkItm->pMsg);
  1203. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1204. #ifdef WINSDBG
  1205. NmsChlNoInvRsp++;
  1206. #endif
  1207. continue;
  1208. }
  1209. //
  1210. // We have a valid response
  1211. //
  1212. DBGPRINT3(CHL, "ProcRsp: (%s) Response is for name = (%s); 16th char (%X)\n", Opcode_e == NMSMSGF_E_NAM_REL ? "RELEASE" : "QUERY", Name, Name[15]);
  1213. //
  1214. // Decrement the count of addresses to send query or release
  1215. // to. We send query/release to the next address in the list
  1216. // if we get back a negative response to the current one. This
  1217. // is just for extra safety (in case we have one or more
  1218. // addresses in our list that are no longer valid for the name)
  1219. //
  1220. pReqWrkItm->NoOfAddsToUse--;
  1221. if (Opcode_e == NMSMSGF_E_NAM_REL)
  1222. {
  1223. //
  1224. // If there are more addresses for sending the releases
  1225. // to, insert the work item at the head of the queue
  1226. //
  1227. if ( (Rcode_e != NMSMSGF_E_SUCCESS) &&
  1228. (pReqWrkItm->NoOfAddsToUse > 0))
  1229. {
  1230. //
  1231. // The request has been processed. Init its
  1232. // position in the array. Also,
  1233. // decrement scPendingRsp.
  1234. //
  1235. spReqWrkItmArr[TransId] = NULL;
  1236. scPendingRsp--;
  1237. //
  1238. // Now, we have to send the RELEASE to the next
  1239. // address on the list . This
  1240. // request has to be processed in the same
  1241. // way as all the other requests that are
  1242. // queued on our request queues (i.e. retry
  1243. // a certain number of times using a certain
  1244. // time interval). Since we are in the
  1245. // middle of an execution of a batch of
  1246. // requests, queue this request at the head
  1247. // of the next batch of requests.
  1248. //
  1249. DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
  1250. QueInsertWrkItmAtHdOfList(
  1251. &pReqWrkItm->Head,
  1252. pReqWrkItm->QueTyp_e,
  1253. NULL
  1254. );
  1255. //
  1256. // Throw the response away
  1257. //
  1258. ECommFreeBuff(pRspWrkItm->pMsg);
  1259. //
  1260. // deallocate the response buffer
  1261. //
  1262. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1263. return(WINS_SUCCESS);
  1264. }
  1265. //
  1266. // Either the name was released or we have exhausted
  1267. // the list of addresses without getting a positive
  1268. // release response
  1269. //
  1270. //
  1271. // Update the database. Note: There is no need to
  1272. // check the Rcode_e value since even if the release
  1273. // request failed, we will overwrite the entry
  1274. //
  1275. // A release is sent as a result of a clash during
  1276. // replication only, so a client id. of WINS_E_RPLPULL
  1277. // is correct.
  1278. //
  1279. if (pReqWrkItm->CmdTyp_e == NMSCHL_E_REL)
  1280. {
  1281. pReqWrkItm->NodeToReg.pNodeAdd =
  1282. &pReqWrkItm->AddToReg;
  1283. if (ChlUpdateDb(
  1284. FALSE,
  1285. WINS_E_RPLPULL,
  1286. &pReqWrkItm->NodeToReg,
  1287. pReqWrkItm->OwnerIdInCnf,
  1288. FALSE //not just a refresh
  1289. ) != WINS_SUCCESS
  1290. )
  1291. {
  1292. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
  1293. DBGPRINT0(CHL, "ProcRsp:COULD NOT UPDATE THE DB AFTER A RELEASE \n");
  1294. Rcode_e = NMSMSGF_E_SRV_ERR;
  1295. }
  1296. else
  1297. {
  1298. //
  1299. // if the remote WINS has to be notified of
  1300. // the update.
  1301. //
  1302. // NOTE: This code won't be executed.
  1303. //
  1304. if(spReqWrkItmArr[TransId]->CmdTyp_e ==
  1305. NMSCHL_E_REL_N_INF)
  1306. {
  1307. InfRemWins(
  1308. spReqWrkItmArr[TransId]
  1309. );
  1310. }
  1311. Rcode_e = NMSMSGF_E_SUCCESS;
  1312. }
  1313. }
  1314. }
  1315. else // it is a name query response
  1316. {
  1317. #ifdef WINSDBG
  1318. {
  1319. DWORD i;
  1320. for (i=0; i<CntAdd.NoOfAdds;i++)
  1321. {
  1322. DBGPRINT2(CHL, "ProcRsp: Address (%d) is (%X)\n", (i+1),CntAdd.Add[i].Add.IPAdd);
  1323. }
  1324. }
  1325. #endif
  1326. //
  1327. // if the challenge succeded, we may need
  1328. // to update the database
  1329. //
  1330. if (Rcode_e != NMSMSGF_E_SUCCESS ||
  1331. pReqWrkItm->fGroupInCnf != fGroup)
  1332. {
  1333. //
  1334. // a negative name query response was received
  1335. // OR Record type (unique vs group) doesn't match
  1336. // (the second check is to consider the case of
  1337. // a node which used the same name first as unique
  1338. // and then as group)
  1339. //
  1340. //
  1341. // If there are no more addresses to query
  1342. //
  1343. if (pReqWrkItm->NoOfAddsToUse == 0)
  1344. {
  1345. //
  1346. // Update the database
  1347. //
  1348. pReqWrkItm->NodeToReg.pNodeAdd =
  1349. &pReqWrkItm->AddToReg;
  1350. if (ChlUpdateDb(
  1351. FALSE,
  1352. pReqWrkItm->Client_e,
  1353. &pReqWrkItm->NodeToReg,
  1354. pReqWrkItm->OwnerIdInCnf,
  1355. FALSE
  1356. ) == WINS_SUCCESS
  1357. )
  1358. {
  1359. //
  1360. // Set Rcode_e to SUCCESS
  1361. //
  1362. Rcode_e = NMSMSGF_E_SUCCESS;
  1363. }
  1364. else
  1365. {
  1366. Rcode_e = NMSMSGF_E_SRV_ERR;
  1367. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
  1368. }
  1369. }
  1370. else
  1371. {
  1372. //
  1373. // We need to challenge (query) the next
  1374. // address in the list of addresses
  1375. //
  1376. spReqWrkItmArr[TransId] = NULL;
  1377. scPendingRsp--;
  1378. DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
  1379. QueInsertWrkItmAtHdOfList(
  1380. &pReqWrkItm->Head,
  1381. pReqWrkItm->QueTyp_e,
  1382. NULL
  1383. );
  1384. //
  1385. // Throw this response away
  1386. //
  1387. ECommFreeBuff(pRspWrkItm->pMsg);
  1388. //
  1389. // deallocate the response buffer
  1390. //
  1391. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1392. return(WINS_SUCCESS);
  1393. }
  1394. }
  1395. else // positive name query response received
  1396. {
  1397. //
  1398. // if the cmd is CHL_N_REL, we need to now tell
  1399. // the remote node to release the name.
  1400. //
  1401. if (CntAdd.NoOfAdds == 1)
  1402. {
  1403. //
  1404. // Note: the CmdType_e will be CHL_N_REL
  1405. // only if the client is WINS_E_RPLPULL
  1406. //
  1407. if (pReqWrkItm->CmdTyp_e == NMSCHL_E_CHL_N_REL)
  1408. {
  1409. DWORD No;
  1410. //
  1411. // We need to tell the remote node
  1412. // release all names.
  1413. //
  1414. pReqWrkItm->CmdTyp_e = NMSCHL_E_REL_ONLY;
  1415. spReqWrkItmArr[TransId] = NULL;
  1416. scPendingRsp--;
  1417. //
  1418. // We need to update the Version
  1419. // no of the conflicting entry
  1420. //
  1421. (VOID)ChlUpdateDb(
  1422. TRUE, //update vers. no.
  1423. WINS_E_NMSNMH, //to speed fn up
  1424. &pReqWrkItm->NodeToReg,
  1425. pReqWrkItm->OwnerIdInCnf,
  1426. FALSE
  1427. );
  1428. //
  1429. // Tell the remote guy to release
  1430. // the name. Copy the addresses of
  1431. // into the proper field
  1432. //
  1433. pReqWrkItm->NoOfAddsToUse =
  1434. pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
  1435. ASSERT(pReqWrkItm->NoOfAddsToUse <= NMSDB_MAX_MEMS_IN_GRP);
  1436. for (No=0; No < pReqWrkItm->NoOfAddsToUse; No++)
  1437. {
  1438. *(pReqWrkItm->NodeAddsInCnf.Mem + No) = *(pReqWrkItm->NodeToReg.NodeAdds.Mem + No);
  1439. }
  1440. pReqWrkItm->NodeAddsInCnf.NoOfMems
  1441. = pReqWrkItm->NoOfAddsToUse;
  1442. DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d); request REL_ONLY\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
  1443. QueInsertWrkItmAtHdOfList(
  1444. &pReqWrkItm->Head,
  1445. pReqWrkItm->QueTyp_e,
  1446. NULL
  1447. );
  1448. //
  1449. // Throw this response away
  1450. //
  1451. ECommFreeBuff(pRspWrkItm->pMsg);
  1452. //
  1453. // deallocate the response buffer
  1454. //
  1455. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1456. return(WINS_SUCCESS);
  1457. }
  1458. }
  1459. //
  1460. // If more than one address was returned in the
  1461. // query response, it means that the challenged
  1462. // node is a multi-homed node. Actually, a multihomed
  1463. // node could return just one address too. This is
  1464. // because it might have just come up and the name
  1465. // may not have yet been registered for the multiple
  1466. // adapters.
  1467. //
  1468. // Note: We execute the else code if the
  1469. // record to register is a special group
  1470. //
  1471. if (
  1472. !NMSDB_ENTRY_GRP_M(pReqWrkItm->NodeToReg.EntTyp)
  1473. )
  1474. {
  1475. //
  1476. // Check if we need to update the db
  1477. //
  1478. RetStat = ProcAddList(
  1479. pReqWrkItm,
  1480. &CntAdd,
  1481. &fAdded
  1482. );
  1483. if (RetStat == WINS_FAILURE)
  1484. {
  1485. //
  1486. // There is atleast one address in the
  1487. // list to register that is not in the
  1488. // list of addresses returned. This means
  1489. // that at least one of the addresses to
  1490. // register is not claimed by the node
  1491. // that responded. We can not honor
  1492. // this registration
  1493. //
  1494. //
  1495. // NAME ACTIVE error
  1496. //
  1497. Rcode_e = NMSMSGF_E_ACT_ERR;
  1498. }
  1499. else
  1500. {
  1501. //
  1502. // Update the database
  1503. //
  1504. pReqWrkItm->NodeToReg.pNodeAdd =
  1505. &pReqWrkItm->AddToReg;
  1506. if (ChlUpdateDb(
  1507. FALSE,
  1508. pReqWrkItm->Client_e,
  1509. &pReqWrkItm->NodeToReg,
  1510. pReqWrkItm->OwnerIdInCnf,
  1511. !fAdded
  1512. ) == WINS_SUCCESS
  1513. )
  1514. {
  1515. //
  1516. // Set Rcode_e to SUCCESS
  1517. //
  1518. Rcode_e = NMSMSGF_E_SUCCESS;
  1519. }
  1520. else
  1521. {
  1522. Rcode_e = NMSMSGF_E_SRV_ERR;
  1523. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
  1524. }
  1525. }
  1526. }
  1527. CHECK("Should a local multihomed node be told to release the name if it ")
  1528. CHECK("with a replica. This is what is done for the local unique/remote unique")
  1529. CHECK("name clash. It seems the right strategy but may need to be rethought")
  1530. else // entry to register is a group
  1531. {
  1532. //
  1533. // set Rcode_e to Error code
  1534. //
  1535. Rcode_e = NMSMSGF_E_ACT_ERR;
  1536. }
  1537. }
  1538. }
  1539. //
  1540. // The request has been processed. Init its position
  1541. // in the array. Send the response to the waiting node
  1542. // This will free the buffer too.
  1543. //
  1544. // Also, decrement scPendingRsp. This was incremented by
  1545. // HandleWrkItm for each query/release sent.
  1546. //
  1547. spReqWrkItmArr[TransId] = NULL;
  1548. scPendingRsp--;
  1549. //
  1550. // Send a registration response only if the client that
  1551. // submitted the request was an NBT thread.
  1552. //
  1553. if (
  1554. (pReqWrkItm->Client_e == WINS_E_NMSNMH)
  1555. &&
  1556. (!pReqWrkItm->NodeToReg.fStatic)
  1557. &&
  1558. (!pReqWrkItm->NodeToReg.fAdmin)
  1559. )
  1560. {
  1561. NMSMSGF_RSP_INFO_T RspInfo;
  1562. RspInfo.pMsg = pReqWrkItm->pMsg;
  1563. RspInfo.MsgLen = pReqWrkItm->MsgLen;
  1564. RspInfo.QuesNamSecLen = pReqWrkItm->QuesNamSecLen;
  1565. RspInfo.Rcode_e = Rcode_e;
  1566. if (Rcode_e == NMSMSGF_E_SUCCESS)
  1567. {
  1568. EnterCriticalSection(&WinsCnfCnfCrtSec);
  1569. RspInfo.RefreshInterval = WinsCnf.RefreshInterval;
  1570. LeaveCriticalSection(&WinsCnfCnfCrtSec);
  1571. DBGPRINT0(CHL, "ProcRsp: Sending a Positive name registration response\n");
  1572. }
  1573. #ifdef WINSDBG
  1574. else
  1575. {
  1576. DBGPRINT0(CHL, "ProcRsp: Sending a negative name registration response\n");
  1577. }
  1578. #endif
  1579. NmsNmhSndNamRegRsp(
  1580. &pReqWrkItm->DlgHdl,
  1581. &RspInfo
  1582. );
  1583. }
  1584. //
  1585. // Throw this response away
  1586. //
  1587. ECommFreeBuff(pRspWrkItm->pMsg);
  1588. //
  1589. // deallocate the req and rsp wrk items
  1590. //
  1591. QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
  1592. QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
  1593. }
  1594. DBGLEAVE("ProcRsp\n");
  1595. return(WINS_SUCCESS);
  1596. } // ProcRsp()
  1597. STATUS
  1598. ChlUpdateDb(
  1599. BOOL fUpdVersNoOfCnfRec,
  1600. WINS_CLIENT_E Client_e,
  1601. PNMSDB_ROW_INFO_T pRowInfo,
  1602. DWORD OwnerIdInCnf,
  1603. BOOL fRefreshOnly
  1604. )
  1605. /*++
  1606. Routine Description:
  1607. This function is called to update the database. It is called
  1608. by ProcRsp and by ChlThdInitFn when challenge succeeds
  1609. Arguments:
  1610. Client_e - id of client that submitted the request
  1611. pRowInfo - info about the record to be inserted
  1612. Externals Used:
  1613. None
  1614. Return Value:
  1615. Success status codes -- WINS_SUCCESS
  1616. Error status codes -- WINS_FAILURE
  1617. Error Handling:
  1618. Called by:
  1619. WaitForRsp(), ProcRsp()
  1620. Side Effects:
  1621. Comments:
  1622. None
  1623. --*/
  1624. {
  1625. NMSDB_STAT_INFO_T StatInfo;
  1626. STATUS RetStat = WINS_SUCCESS;
  1627. BOOL fIncVersNo = FALSE;
  1628. DBGENTER("ChlUpdateDb\n");
  1629. //
  1630. // update the time
  1631. //
  1632. PERF("We can avoid this call to time, since we called time earlier before we")
  1633. PERF("challenge. In the worst case that time will be off by a 2.5-3")
  1634. PERF("unless the thread is preempted for a long time")
  1635. PERF("assuming a name challenge and release took place. In the best case")
  1636. PERF("it will be off by 1.25-1.5 secs (if just a challenge). We can add ")
  1637. PERF("1.25 secs to that time and avoid the overhead of a function call")
  1638. (void)time(&pRowInfo->TimeStamp);
  1639. if (((Client_e == WINS_E_NMSNMH) && !fRefreshOnly) ||
  1640. fUpdVersNoOfCnfRec)
  1641. {
  1642. fIncVersNo = TRUE;
  1643. }
  1644. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  1645. if (pRowInfo->OwnerId == NMSDB_LOCAL_OWNER_ID)
  1646. {
  1647. pRowInfo->TimeStamp += WinsCnf.RefreshInterval;
  1648. }
  1649. else
  1650. {
  1651. pRowInfo->TimeStamp += WinsCnf.VerifyInterval;
  1652. }
  1653. try
  1654. {
  1655. //
  1656. // If the client (the one that submitted the challenge request) is
  1657. // an NBT thread, we need to store the new version number. If the
  1658. // client is the replicator, we use the version number in the
  1659. // record
  1660. //
  1661. if (fIncVersNo)
  1662. {
  1663. pRowInfo->VersNo = NmsNmhMyMaxVersNo;
  1664. }
  1665. StatInfo.OwnerId = OwnerIdInCnf;
  1666. if (*(pRowInfo->pName+15) == 0x1B)
  1667. {
  1668. WINS_SWAP_BYTES_M(pRowInfo->pName, pRowInfo->pName+15);
  1669. }
  1670. //
  1671. // If the vers. no of the local record needs to be updated, do so.
  1672. //
  1673. if (fUpdVersNoOfCnfRec)
  1674. {
  1675. RetStat = NmsDbUpdateVersNo (FALSE, pRowInfo, &StatInfo);
  1676. }
  1677. else
  1678. {
  1679. RetStat = NmsDbSeekNUpdateRow(
  1680. pRowInfo,
  1681. &StatInfo
  1682. );
  1683. }
  1684. if ((RetStat == WINS_SUCCESS) && (StatInfo.StatCode == NMSDB_SUCCESS))
  1685. {
  1686. //
  1687. // If the client is an NBT thread, we increment the version
  1688. // number since the record we inserted in the db is
  1689. // owned by us (we could also check the owner id here). If
  1690. // the client is the replicator thread, we don't do anything
  1691. //
  1692. if (fIncVersNo)
  1693. {
  1694. NMSNMH_INC_VERS_COUNTER_M(
  1695. NmsNmhMyMaxVersNo,
  1696. NmsNmhMyMaxVersNo
  1697. );
  1698. //
  1699. // if fAddChgTrigger is TRUE, we pass RPL_PUSH_PROP
  1700. // as the first parameter. Its value is TRUE. See
  1701. // rpl.h
  1702. //
  1703. RPL_PUSH_NTF_M(
  1704. (WinsCnf.PushInfo.fAddChgTrigger ? RPL_PUSH_PROP :
  1705. RPL_PUSH_NO_PROP), NULL, NULL, NULL);
  1706. }
  1707. }
  1708. else
  1709. {
  1710. DBGPRINT1(ERR, "ChlUpdateDb: Update of record with name (%s) FAILED\n", pRowInfo->pName);
  1711. RetStat = WINS_FAILURE;
  1712. }
  1713. }
  1714. except (EXCEPTION_EXECUTE_HANDLER)
  1715. {
  1716. DBGPRINTEXC("ChlUpdateDb")
  1717. WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_CANT_UPDATE_DB);
  1718. }
  1719. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  1720. DBGLEAVE("ChlUpdateDb\n");
  1721. return (RetStat);
  1722. } //ChlUpdateDb()
  1723. VOID
  1724. InfRemWins(
  1725. PCHL_REQ_WRK_ITM_T pWrkItm
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This function is called when a remote WINS has to be
  1730. told to change the version stamp of a record that was
  1731. pulled by the local WINS at replication. The need for this
  1732. has arisen because the pulled record collided with a record
  1733. owned by the local WINS (both records being in the active
  1734. state).
  1735. Arguments:
  1736. pWrkItm - the work item that got queued to the name challenge
  1737. manager
  1738. Externals Used:
  1739. None
  1740. Return Value:
  1741. None
  1742. Error Handling:
  1743. Called by:
  1744. ProcRsp
  1745. Side Effects:
  1746. Comments:
  1747. None
  1748. --*/
  1749. {
  1750. COMM_HDL_T DlgHdl;
  1751. BYTE ReqBuff[RPLMSGF_UPDVERSNO_REQ_SIZE];
  1752. LPBYTE pRspBuff;
  1753. DWORD ReqBuffLen;
  1754. DWORD RspBuffLen;
  1755. NMSMSGF_ERR_CODE_E Rcode_e = 0; //init to 0. This is initialization
  1756. //is important since we update
  1757. //the LSB of Rcode_e with the
  1758. //the return status
  1759. DBGENTER("InfRemWins\n");
  1760. try {
  1761. //
  1762. // Log an event since this is an important event to monitor (at
  1763. // least initially)
  1764. //
  1765. NONPORT("Change the following for transport independence")
  1766. WINSEVT_LOG_INFO_D_M(pWrkItm->AddOfRemWins.Add.IPAdd,
  1767. WINS_EVT_INF_REM_WINS);
  1768. //
  1769. // Start a dialogue to send the update version number request
  1770. //
  1771. //
  1772. // Init the pEnt field to NULL so that ECommEndDlg (in the
  1773. // exception handler) called as a result of an exception from
  1774. // behaves fine.
  1775. //
  1776. DlgHdl.pEnt = NULL;
  1777. ECommStartDlg(
  1778. &pWrkItm->AddOfRemWins,
  1779. COMM_E_RPL,
  1780. &DlgHdl
  1781. );
  1782. RplMsgfFrmUpdVersNoReq(
  1783. &ReqBuff[COMM_N_TCP_HDR_SZ],
  1784. pWrkItm->NodeToReg.pName,
  1785. pWrkItm->NodeToReg.NameLen,
  1786. &ReqBuffLen
  1787. );
  1788. //
  1789. // Send the "Update Version number" request
  1790. //
  1791. ECommSndCmd(
  1792. &DlgHdl,
  1793. &ReqBuff[COMM_N_TCP_HDR_SZ],
  1794. ReqBuffLen,
  1795. &pRspBuff,
  1796. &RspBuffLen
  1797. );
  1798. //
  1799. // decipher the reponse to get the result code sent by the
  1800. // remote WINS
  1801. //
  1802. RplMsgfUfmUpdVersNoRsp(
  1803. pRspBuff + 4, //past the opcode
  1804. (LPBYTE)&Rcode_e
  1805. );
  1806. if (Rcode_e != NMSMSGF_E_SUCCESS)
  1807. {
  1808. DBGPRINT0(ERR, "Remote WINS could not update the version no. of its record");
  1809. WINSEVT_LOG_M(pWrkItm->AddOfRemWins.Add.IPAdd, WINS_EVT_REM_WINS_CANT_UPD_VERS_NO);
  1810. FUTURES("Take some corrective action -- maybe")
  1811. }
  1812. //
  1813. // deallocate the request and response buffers
  1814. //
  1815. #if 0
  1816. WinsMscDealloc(pReqBuff);
  1817. #endif
  1818. ECommFreeBuff(pRspBuff - COMM_HEADER_SIZE);
  1819. } // end of try block
  1820. except (EXCEPTION_EXECUTE_HANDLER) {
  1821. DWORD ExcCode = GetExceptionCode();
  1822. DBGPRINT1(EXC, "InfRemWins: Got exception (%x)\n", ExcCode );
  1823. if (ExcCode == WINS_EXC_COMM_FAIL)
  1824. {
  1825. DBGPRINT1(ERR, "InfRemWins: Could not inform WINS (%x) that it should update the version number for a record", pWrkItm->AddOfRemWins.Add.IPAdd);
  1826. //
  1827. //insert a timer request for retrying
  1828. //
  1829. FUTURES("Incorporate code to insert a timer request so that we can retry")
  1830. }
  1831. else
  1832. {
  1833. //severe error.
  1834. DBGPRINT0(ERR, "InfRemWins: Some severe error was encountered\n");
  1835. }
  1836. WINSEVT_LOG_M(ExcCode, WINS_EVT_INF_REM_WINS_EXC);
  1837. }
  1838. //
  1839. // End the dialogue
  1840. //
  1841. ECommEndDlg( &DlgHdl );
  1842. DBGLEAVE("InfRemWins\n");
  1843. return;
  1844. } // InfRemWins()
  1845. STATUS
  1846. ProcAddList(
  1847. PCHL_REQ_WRK_ITM_T pReqWrkItm,
  1848. PNMSMSGF_CNT_ADD_T pCntAdd,
  1849. LPBOOL pfAdded
  1850. )
  1851. /*++
  1852. Routine Description:
  1853. Arguments:
  1854. pWrkItm - the work item that got queued to the name challenge
  1855. manager
  1856. pCntAdd - List of addresses returned on a query
  1857. Externals Used:
  1858. None
  1859. Return Value:
  1860. None
  1861. Error Handling:
  1862. Called by:
  1863. ProcRsp
  1864. Side Effects:
  1865. Comments:
  1866. The function will never be called when the state
  1867. of the entry to register is a TOMBSTONE or if the entry to register
  1868. is a group.
  1869. --*/
  1870. {
  1871. DWORD i, n;
  1872. DWORD NoOfAddsToReg;
  1873. STATUS RetStat = WINS_SUCCESS;
  1874. PNMSDB_GRP_MEM_ENTRY_T pMem;
  1875. PCOMM_ADD_T pAddInRsp;
  1876. DBGENTER("ProcAddList\n");
  1877. *pfAdded = FALSE; //no address of conflicting entry has yet been
  1878. //added to list of addresses of record to register
  1879. //
  1880. // If the node to register is a unique record
  1881. //
  1882. if (pReqWrkItm->NodeToReg.EntTyp == NMSDB_UNIQUE_ENTRY)
  1883. {
  1884. NoOfAddsToReg = 1;
  1885. pReqWrkItm->NodeToReg.NodeAdds.Mem[0].Add =
  1886. pReqWrkItm->AddToReg;
  1887. pReqWrkItm->NodeToReg.NodeAdds.Mem[0].OwnerId =
  1888. pReqWrkItm->NodeToReg.OwnerId;
  1889. pReqWrkItm->NodeToReg.NodeAdds.Mem[0].TimeStamp =
  1890. pReqWrkItm->NodeToReg.TimeStamp;
  1891. pReqWrkItm->NodeToReg.NodeAdds.NoOfMems = 1;
  1892. }
  1893. else // has to be multihomed (see comment above)
  1894. {
  1895. NoOfAddsToReg = pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
  1896. //
  1897. // The addresses are already there in NodeToReg.NodeAdds structure
  1898. //
  1899. }
  1900. //
  1901. // If the address(es) to register are not a subset of the addresses
  1902. // returned (i.e. atleast one address to register is not there in
  1903. // the list returned), we return FAILURE.
  1904. //
  1905. //
  1906. // Loop over all addresses to register
  1907. //
  1908. for (i=0; i < NoOfAddsToReg; i++)
  1909. {
  1910. //
  1911. // Compare with each address returned to see if there is
  1912. // a match. Note: pCntAdd->NoOfAdds is > 1 (this function
  1913. // isn't called otherwise).
  1914. //
  1915. for (n=0; n < pCntAdd->NoOfAdds; n++)
  1916. {
  1917. PERF("use pointer arithmetic")
  1918. if (pReqWrkItm->NodeToReg.NodeAdds.Mem[i].Add.Add.IPAdd ==
  1919. pCntAdd->Add[n].Add.IPAdd)
  1920. {
  1921. //
  1922. // There is a match, break out so that we can
  1923. // can get to the next address in the list of
  1924. // addresses to register
  1925. //
  1926. break;
  1927. }
  1928. }
  1929. //
  1930. // if there was no match, we have an address to register that
  1931. // either the queried (challenged) node does not have or refuses
  1932. // to divulge to us. We must reject the registration/refresh
  1933. //
  1934. if (n == pCntAdd->NoOfAdds)
  1935. {
  1936. RetStat = WINS_FAILURE;
  1937. break;
  1938. }
  1939. }
  1940. //
  1941. // The address(es) to register are a subset of the addresses returned
  1942. // by the node (on a query)
  1943. //
  1944. if ( RetStat == WINS_SUCCESS)
  1945. {
  1946. DWORD Index;
  1947. //
  1948. // Remove those members in the conflicting record that are
  1949. // not in the list returned by the node
  1950. //
  1951. for (
  1952. i=0, pMem = pReqWrkItm->NodeAddsInCnf.Mem;
  1953. i < min(pReqWrkItm->NodeAddsInCnf.NoOfMems,
  1954. NMSMSGF_MAX_NO_MULTIH_ADDS);
  1955. i++, pMem++
  1956. )
  1957. {
  1958. pAddInRsp = pCntAdd->Add;
  1959. for (n=0; n < pCntAdd->NoOfAdds; n++, pAddInRsp++)
  1960. {
  1961. PERF("use pointer arithmetic")
  1962. if (pMem->Add.Add.IPAdd == pAddInRsp->Add.IPAdd)
  1963. {
  1964. //
  1965. // There is a match, break out so that we can
  1966. // can get to the next address in the list of
  1967. // addresses in the conflicting record
  1968. //
  1969. break;
  1970. }
  1971. }
  1972. if (n == pCntAdd->NoOfAdds)
  1973. {
  1974. //
  1975. // remove the conflicting member from the list
  1976. // This is done by setting its address to NONE. Later
  1977. // on, we simply won't add this address.
  1978. //
  1979. DBGPRINT3(CHL, "ProcAddList: Removing member (%x) from list of name = (%s)[%x]\n", pMem->Add.Add.IPAdd, pReqWrkItm->NodeToReg.Name, pReqWrkItm->NodeToReg.Name[15]);
  1980. pMem->Add.Add.IPAdd = INADDR_NONE;
  1981. }
  1982. }
  1983. DBGPRINT0(CHL, "ProcAddList: Add conflicting record members\n");
  1984. //
  1985. // The record in conflict has to be ACTIVE
  1986. // (otherwise this function wouldn't have been called -- See
  1987. // the clash functions in nmsnmh.c). We add all those addresses
  1988. // in the active conflicting record to the list of addresses in
  1989. // the record to register that are not there in it already
  1990. //
  1991. //
  1992. // Add to list of addresses to register all the addresses in
  1993. // the conflicting record. Note: The conflicting record
  1994. // will not have any address in common with the record
  1995. // to register (common addresses were removed in the clash
  1996. // handling functions of nmsnmh.c via MemInGrp())
  1997. //
  1998. //
  1999. // NOTE: the NoOfMems of the NodeAddsInCnf field is guaranteed
  2000. // to be > 0
  2001. //
  2002. //
  2003. // Also NOTE: If the challenged node returned us a list > 25 members
  2004. // long and our list of members to register can no accommodate
  2005. // all the members that need to be added, we will just add those
  2006. // that can be added without violating the NMSMSGF_MAX_NO_MULTIH_ADDS
  2007. // constraint. The members added could be 0 if we already have
  2008. // the first 25 in our list. Neverthless we will update our
  2009. // db entry. This is because some of the conflicting record's
  2010. // members may be old. They will get removed this way (we don't
  2011. // compare the list returned by the challenged node with what is
  2012. // in the conflicting record currently, so old entries will be
  2013. // there until they are scavenged or fall off).
  2014. //
  2015. Index = pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
  2016. pMem = pReqWrkItm->NodeAddsInCnf.Mem;
  2017. for ( i=0;
  2018. i < min(pReqWrkItm->NodeAddsInCnf.NoOfMems,
  2019. (NMSMSGF_MAX_NO_MULTIH_ADDS - Index));
  2020. i++, pMem++
  2021. )
  2022. {
  2023. //
  2024. // we need to add the conflicting record's
  2025. // address into the registering record's
  2026. // list of addresses
  2027. //
  2028. if (pMem->Add.Add.IPAdd != INADDR_NONE)
  2029. {
  2030. pReqWrkItm->NodeToReg.NodeAdds.Mem[
  2031. pReqWrkItm->NodeToReg.NodeAdds.NoOfMems
  2032. ] = *pMem;
  2033. pReqWrkItm->NodeToReg.NodeAdds.NoOfMems++;
  2034. }
  2035. }
  2036. //
  2037. // Setting *pfAdded to TRUE will increment the version number.
  2038. // We do want to increment the version number because
  2039. // the reason we are here means one of the following:
  2040. //
  2041. // 1)We got a refresh (unique) for an address not in the
  2042. // conf. rec.
  2043. // 2)We got a registration for an address that is/is not
  2044. // there in the conflicting record.
  2045. //
  2046. // For the first case above, we definitely want to increment
  2047. // the version no. For the second case, it is not strictly
  2048. // required but is preferable for syncing up entries at
  2049. // different WINS servers right away.
  2050. //
  2051. *pfAdded = TRUE;
  2052. //
  2053. // If the record to register was a unique record
  2054. // change its type to MULTIHOMED.
  2055. //
  2056. if ( NMSDB_ENTRY_UNIQUE_M(pReqWrkItm->NodeToReg.EntTyp) )
  2057. {
  2058. pReqWrkItm->NodeToReg.EntTyp = NMSDB_MULTIHOMED_ENTRY;
  2059. }
  2060. }
  2061. DBGLEAVE("ProcAddList\n");
  2062. return(RetStat);
  2063. }
  2064.