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.

1665 lines
46 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. winsdb.cpp
  7. Wins database enumerator
  8. FILE HISTORY:
  9. Oct 13 1997 EricDav Modified
  10. */
  11. #include "stdafx.h"
  12. #include "wins.h"
  13. #include "search.h"
  14. #include "winsdb.h"
  15. #include "tfschar.h"
  16. IMPLEMENT_ADDREF_RELEASE(CWinsDatabase);
  17. IMPLEMENT_SIMPLE_QUERYINTERFACE(CWinsDatabase, IWinsDatabase)
  18. DEBUG_DECLARE_INSTANCE_COUNTER(CWinsDatabase)
  19. CWinsDatabase::CWinsDatabase()
  20. : m_cRef(1), m_fFiltered(FALSE), m_fInitialized(FALSE), m_bShutdown(FALSE), m_hrLastError(hrOK)
  21. {
  22. DEBUG_INCREMENT_INSTANCE_COUNTER(CWinsDatabase);
  23. SetCurrentState(WINSDB_NORMAL);
  24. m_hBinding = NULL;
  25. m_hThread = NULL;
  26. m_hStart = NULL;
  27. m_hAbort = NULL;
  28. m_dwOwner = (DWORD)-1;
  29. m_strPrefix = NULL;
  30. m_dwRecsCount = 0;
  31. m_bEnableCache = FALSE;
  32. }
  33. CWinsDatabase::~CWinsDatabase()
  34. {
  35. DEBUG_DECREMENT_INSTANCE_COUNTER(CWinsDatabase);
  36. m_bShutdown = TRUE;
  37. if (m_strPrefix != NULL)
  38. delete m_strPrefix;
  39. SetEvent(m_hAbort);
  40. SetEvent(m_hStart);
  41. if (WaitForSingleObject(m_hThread, 30000) != WAIT_OBJECT_0)
  42. {
  43. Trace0("WinsDatabase destructor thread never died!\n");
  44. // TerminateThread
  45. }
  46. CloseHandle(m_hAbort);
  47. CloseHandle(m_hStart);
  48. CloseHandle(m_hThread);
  49. }
  50. /*!--------------------------------------------------------------------------
  51. CWinsDatabase::Init
  52. Implementation of IWinsDatabase::Init
  53. Author: EricDav, v-shubk
  54. ---------------------------------------------------------------------------*/
  55. HRESULT
  56. CWinsDatabase::Init()
  57. {
  58. HRESULT hr = hrOK;
  59. WINSDB_STATE uCurrentState;
  60. m_dwRecsCount = 0;
  61. COM_PROTECT_TRY
  62. {
  63. CORg (GetCurrentState(&uCurrentState));
  64. if (uCurrentState != WINSDB_NORMAL)
  65. {
  66. Trace1("WinsDatabase::Init - called when database busy - state %d\n", uCurrentState);
  67. return E_FAIL;
  68. }
  69. CORg (m_cMemMan.Initialize());
  70. CORg (m_IndexMgr.Initialize());
  71. m_hrLastError = hrOK;
  72. CORg (SetCurrentState(WINSDB_LOADING));
  73. COM_PROTECT_ERROR_LABEL;
  74. }
  75. COM_PROTECT_CATCH
  76. return hr;
  77. }
  78. /*!--------------------------------------------------------------------------
  79. CWinsDatabase::Start
  80. Implementation of IWinsDatabase::Start
  81. Author: EricDav, v-shubk
  82. ---------------------------------------------------------------------------*/
  83. HRESULT
  84. CWinsDatabase::Start()
  85. {
  86. // signal the thread to start loading
  87. SetEvent(m_hStart);
  88. return hrOK;
  89. }
  90. /*!--------------------------------------------------------------------------
  91. CWinsDatabase::Initialize
  92. Implementation of IWinsDatabase::Initialize
  93. Author: EricDav, v-shubk
  94. ---------------------------------------------------------------------------*/
  95. HRESULT
  96. CWinsDatabase::Initialize(LPCOLESTR pszName, LPCOLESTR pszIP)
  97. {
  98. HRESULT hr = hrOK;
  99. DWORD dwError;
  100. DWORD dwThreadId;
  101. COM_PROTECT_TRY
  102. {
  103. m_strName = pszName;
  104. m_strIp = pszIP;
  105. CORg (m_cMemMan.Initialize());
  106. CORg (m_IndexMgr.Initialize());
  107. m_hStart = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  108. if (m_hStart == NULL)
  109. {
  110. dwError = ::GetLastError();
  111. Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hStart %d\n", dwError);
  112. return HRESULT_FROM_WIN32(dwError);
  113. }
  114. m_hAbort = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  115. if (m_hAbort == NULL)
  116. {
  117. dwError = ::GetLastError();
  118. Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hAbort %d\n", dwError);
  119. return HRESULT_FROM_WIN32(dwError);
  120. }
  121. m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, &dwThreadId);
  122. if (m_hThread == NULL)
  123. {
  124. dwError = ::GetLastError();
  125. Trace1("WinsDatabase::Init - CreateThread Failed %d\n", dwError);
  126. return HRESULT_FROM_WIN32(dwError);
  127. }
  128. m_fInitialized = TRUE;
  129. COM_PROTECT_ERROR_LABEL;
  130. }
  131. COM_PROTECT_CATCH
  132. return hr;
  133. }
  134. /*!--------------------------------------------------------------------------
  135. CWinsDatabase::GetName
  136. Implementation of IWinsDatabase::GetName
  137. Author: EricDav, v-shubk
  138. ---------------------------------------------------------------------------*/
  139. HRESULT
  140. CWinsDatabase::GetName(LPOLESTR pszName, UINT cchMax)
  141. {
  142. HRESULT hr = hrOK;
  143. LPCTSTR pBuf;
  144. COM_PROTECT_TRY
  145. {
  146. if (cchMax < (UINT) (m_strName.GetLength() / sizeof(TCHAR)))
  147. return E_FAIL;
  148. StrnCpy(pszName, (LPCTSTR) m_strName, cchMax);
  149. }
  150. COM_PROTECT_CATCH
  151. return hr;
  152. }
  153. /*!--------------------------------------------------------------------------
  154. CWinsDatabase::GetIP
  155. Implementation of IWinsDatabase::GetIP
  156. Author: EricDav, v-shubk
  157. ---------------------------------------------------------------------------*/
  158. HRESULT
  159. CWinsDatabase::GetIP(LPOLESTR pszIP, UINT cchMax)
  160. {
  161. HRESULT hr = hrOK;
  162. LPCTSTR pBuf;
  163. COM_PROTECT_TRY
  164. {
  165. if (cchMax < (UINT) (m_strIp.GetLength() / sizeof(TCHAR)))
  166. return E_FAIL;
  167. StrnCpy(pszIP, (LPCTSTR) m_strIp, cchMax);
  168. }
  169. COM_PROTECT_CATCH
  170. return hr;
  171. }
  172. /*!--------------------------------------------------------------------------
  173. CWinsDatabase::Stop
  174. Implementation of IWinsDatabase::Stop
  175. Author: EricDav, v-shubk
  176. ---------------------------------------------------------------------------*/
  177. HRESULT
  178. CWinsDatabase::Stop()
  179. {
  180. HRESULT hr = hrOK;
  181. WINSDB_STATE uState;
  182. COM_PROTECT_TRY
  183. {
  184. CORg (GetCurrentState(&uState));
  185. if (uState != WINSDB_LOADING)
  186. return hr;
  187. SetEvent(m_hAbort);
  188. CORg (SetCurrentState(WINSDB_NORMAL));
  189. COM_PROTECT_ERROR_LABEL;
  190. }
  191. COM_PROTECT_CATCH
  192. return hr;
  193. }
  194. /*!--------------------------------------------------------------------------
  195. CWinsDatabase::Clear
  196. Clears the wins DB of all records
  197. Author: EricDav, v-shubk
  198. ---------------------------------------------------------------------------*/
  199. HRESULT
  200. CWinsDatabase::Clear()
  201. {
  202. HRESULT hr = hrOK;
  203. WINSDB_STATE uState;
  204. COM_PROTECT_TRY
  205. {
  206. CORg (GetCurrentState(&uState));
  207. if (uState == WINSDB_SORTING ||
  208. uState == WINSDB_FILTERING)
  209. return E_FAIL;
  210. if (uState == WINSDB_LOADING)
  211. {
  212. SetEvent(m_hAbort);
  213. CORg (SetCurrentState(WINSDB_NORMAL));
  214. }
  215. CORg (m_cMemMan.Initialize());
  216. CORg (m_IndexMgr.Initialize());
  217. m_dwOwner = (DWORD)-1;
  218. if (m_strPrefix != NULL)
  219. delete m_strPrefix;
  220. m_strPrefix = NULL;
  221. COM_PROTECT_ERROR_LABEL;
  222. }
  223. COM_PROTECT_CATCH
  224. return hr;
  225. }
  226. /*!--------------------------------------------------------------------------
  227. CWinsDatabase::GetLastError
  228. Returns the last error for async calls
  229. Author: EricDav, v-shubk
  230. ---------------------------------------------------------------------------*/
  231. HRESULT
  232. CWinsDatabase::GetLastError(HRESULT * pLastError)
  233. {
  234. HRESULT hr = hrOK;
  235. WINSDB_STATE uState;
  236. COM_PROTECT_TRY
  237. {
  238. if (pLastError)
  239. *pLastError = m_hrLastError;
  240. }
  241. COM_PROTECT_CATCH
  242. return hr;
  243. }
  244. /*!--------------------------------------------------------------------------
  245. CWinsDatabase::Sort
  246. Implementation of IWinsDatabase::Sort
  247. Author: EricDav, v-shubk
  248. ---------------------------------------------------------------------------*/
  249. HRESULT
  250. CWinsDatabase::Sort(WINSDB_SORT_TYPE SortType, DWORD dwSortOptions)
  251. {
  252. HRESULT hr = hrOK;
  253. WINSDB_STATE uState;
  254. COM_PROTECT_TRY
  255. {
  256. CORg (GetCurrentState(&uState));
  257. if (uState != WINSDB_NORMAL)
  258. return E_FAIL;
  259. CORg (SetCurrentState(WINSDB_SORTING));
  260. m_IndexMgr.Sort(SortType, dwSortOptions);
  261. CORg (SetCurrentState(WINSDB_NORMAL));
  262. COM_PROTECT_ERROR_LABEL;
  263. }
  264. COM_PROTECT_CATCH
  265. return hr;
  266. }
  267. /*!--------------------------------------------------------------------------
  268. CWinsDatabase::GetHRow
  269. Implementation of IWinsDatabase::GetHRow
  270. returns the HRow in the current sorted index
  271. Author: EricDav, v-shubk
  272. ---------------------------------------------------------------------------*/
  273. HRESULT
  274. CWinsDatabase::GetHRow(UINT uIndex,
  275. LPHROW hRow)
  276. {
  277. Assert(uIndex >= 0);
  278. HRESULT hr = hrOK;
  279. WINSDB_STATE uState;
  280. int nCurrentCount;
  281. COM_PROTECT_TRY
  282. {
  283. CORg (GetCurrentCount(&nCurrentCount));
  284. if (uIndex > (UINT) nCurrentCount)
  285. return E_FAIL;
  286. CORg (GetCurrentState(&uState));
  287. if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
  288. return E_FAIL;
  289. m_IndexMgr.GetHRow(uIndex, hRow);
  290. COM_PROTECT_ERROR_LABEL;
  291. }
  292. COM_PROTECT_CATCH
  293. return hr;
  294. }
  295. /*!--------------------------------------------------------------------------
  296. CWinsDatabase::GetRows
  297. Implementation of IWinsDatabase::GetRows
  298. Author: EricDav, v-shubk
  299. ---------------------------------------------------------------------------*/
  300. HRESULT CWinsDatabase::GetRows( ULONG uNumberOfRows,
  301. ULONG uStartPos,
  302. HROW* pHRow,
  303. int* nNumberOfRowsReturned)
  304. {
  305. int nCurrentCount;
  306. WINSDB_STATE uState;
  307. HRESULT hr = hrOK;
  308. int nReturnedRows = 0;
  309. int i;
  310. HROW hrowCur;
  311. Assert (uStartPos >= 0);
  312. COM_PROTECT_TRY
  313. {
  314. CORg (GetCurrentState(&uState));
  315. if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
  316. return E_FAIL;
  317. CORg (GetCurrentCount(&nCurrentCount));
  318. Assert ((int) uStartPos <= nCurrentCount);
  319. if (uStartPos > (UINT) nCurrentCount)
  320. return E_FAIL;
  321. for (i = (int) uStartPos; i < (int) (uStartPos + uNumberOfRows); i++)
  322. {
  323. if( i > nCurrentCount )
  324. {
  325. break;
  326. }
  327. CORg (m_IndexMgr.GetHRow(i, &hrowCur));
  328. // if the row is marked deleted, don't add it to the array
  329. // REVIEW: directly accessing memory here.. we may want to change this
  330. // to go through the memory manager
  331. if ( ((LPWINSDBRECORD) hrowCur)->szRecordName[17] & WINSDB_INTERNAL_DELETED )
  332. {
  333. continue;
  334. }
  335. // fill in the data
  336. pHRow[i-uStartPos] = hrowCur;
  337. nReturnedRows++;
  338. }
  339. COM_PROTECT_ERROR_LABEL;
  340. }
  341. COM_PROTECT_CATCH
  342. if (nNumberOfRowsReturned)
  343. *nNumberOfRowsReturned = nReturnedRows;
  344. return hr;
  345. }
  346. /*!--------------------------------------------------------------------------
  347. CWinsDatabase::GetData
  348. Implementation of IWinsDatabase::GetData
  349. returns the HRow in the current sorted index
  350. Author: EricDav, v-shubk
  351. ---------------------------------------------------------------------------*/
  352. HRESULT CWinsDatabase::GetData(HROW hRow,
  353. LPWINSRECORD pRecordData)
  354. {
  355. HRESULT hr = E_FAIL;
  356. COM_PROTECT_TRY
  357. {
  358. CORg (m_cMemMan.GetData(hRow, pRecordData));
  359. COM_PROTECT_ERROR_LABEL;
  360. }
  361. COM_PROTECT_CATCH
  362. return hr;
  363. }
  364. /*!--------------------------------------------------------------------------
  365. CWinsDatabase::FindRow
  366. Implementation of IWinsDatabase::FindRow
  367. Author: EricDav, v-shubk
  368. ---------------------------------------------------------------------------*/
  369. HRESULT
  370. CWinsDatabase::FindRow(LPCOLESTR pszName,
  371. HROW hrowStart,
  372. HROW * phRow)
  373. {
  374. HRESULT hr = E_FAIL;
  375. WinsRecord ws;
  376. int nIndex, nPos, nCurrentCount;
  377. HROW hrowCur;
  378. HROW hrowFound = NULL;
  379. char szName[MAX_PATH];
  380. CString strTemp(pszName);
  381. // this should be OEM
  382. WideToMBCS(strTemp, szName, WINS_NAME_CODE_PAGE);
  383. COM_PROTECT_TRY
  384. {
  385. CORg (m_IndexMgr.GetIndex(hrowStart, &nIndex));
  386. /////
  387. CORg(GetHRow(nIndex, &hrowCur));
  388. CORg (m_IndexMgr.GetIndex(hrowCur, &nIndex));
  389. CORg (GetCurrentCount(&nCurrentCount));
  390. if(nIndex != -1)
  391. {
  392. CORg(GetHRow(nIndex, &hrowCur));
  393. for (nPos = nIndex + 1; nPos < nCurrentCount; nPos++)
  394. {
  395. CORg(GetHRow(nPos, &hrowCur));
  396. CORg(GetData(hrowCur, &ws));
  397. if(!_strnicmp(ws.szRecordName, szName, strlen(szName) ))
  398. {
  399. hrowFound = hrowCur;
  400. hr = hrOK;
  401. break;
  402. }
  403. }
  404. }
  405. COM_PROTECT_ERROR_LABEL;
  406. }
  407. COM_PROTECT_CATCH
  408. if (phRow)
  409. *phRow = hrowFound;
  410. return hr;
  411. }
  412. /*!--------------------------------------------------------------------------
  413. CWinsDatabase::GetTotalCount
  414. Implementation of IWinsDatabase::GetTotalCount
  415. Author: EricDav, v-shubk
  416. ---------------------------------------------------------------------------*/
  417. HRESULT
  418. CWinsDatabase::GetTotalCount(int * nTotalCount)
  419. {
  420. HRESULT hr = hrOK;
  421. COM_PROTECT_TRY
  422. {
  423. *nTotalCount = m_IndexMgr.GetTotalCount();
  424. }
  425. COM_PROTECT_CATCH
  426. return hr;
  427. }
  428. /*!--------------------------------------------------------------------------
  429. CWinsDatabase::GetCurrentCount
  430. Implementation of IWinsDatabase::GetCurrentCount
  431. returns the HRow in the current sorted index
  432. Author: EricDav, v-shubk
  433. ---------------------------------------------------------------------------*/
  434. HRESULT
  435. CWinsDatabase::GetCurrentCount(int * nCurrentCount)
  436. {
  437. HRESULT hr = hrOK;
  438. COM_PROTECT_TRY
  439. {
  440. if (m_DBState == WINSDB_SORTING)
  441. *nCurrentCount = 0;
  442. else
  443. *nCurrentCount = m_IndexMgr.GetCurrentCount();
  444. }
  445. COM_PROTECT_CATCH
  446. return hr;
  447. }
  448. /*!--------------------------------------------------------------------------
  449. CWinsDatabase::GetCurrentScanned(int * nCurrentScanned)
  450. Implementation of IWinsDatabase::GetCurrentScanned
  451. returns the total number of records that were read from the server
  452. Author: EricDav, v-shubk
  453. ---------------------------------------------------------------------------*/
  454. HRESULT
  455. CWinsDatabase::GetCurrentScanned(int * nCurrentCount)
  456. {
  457. HRESULT hr = hrOK;
  458. COM_PROTECT_TRY
  459. {
  460. *nCurrentCount = m_dwRecsCount;
  461. }
  462. COM_PROTECT_CATCH
  463. return hr;
  464. }
  465. /*!--------------------------------------------------------------------------
  466. CWinsDatabase::AddRecord
  467. Implementation of IWinsDatabase::AddRecord
  468. Author: EricDav, v-shubk
  469. ---------------------------------------------------------------------------*/
  470. HRESULT
  471. CWinsDatabase::AddRecord(const LPWINSRECORD pRecordData)
  472. {
  473. HRESULT hr = hrOK;
  474. COM_PROTECT_TRY
  475. {
  476. // critical sections taken care by the memory manager
  477. HROW hrow = NULL;
  478. CORg (m_cMemMan.AddData(*pRecordData, &hrow));
  479. CORg (m_IndexMgr.AddHRow(hrow));
  480. COM_PROTECT_ERROR_LABEL;
  481. }
  482. COM_PROTECT_CATCH
  483. return hrOK;
  484. }
  485. /*!--------------------------------------------------------------------------
  486. CWinsDatabase::DeleteRecord
  487. Implementation of IWinsDatabase::DeleteRecord
  488. Author: EricDav, v-shubk
  489. ---------------------------------------------------------------------------*/
  490. HRESULT
  491. CWinsDatabase::DeleteRecord(HROW hrowRecord)
  492. {
  493. HRESULT hr = hrOK;
  494. WINSDB_STATE uState;
  495. COM_PROTECT_TRY
  496. {
  497. CORg (GetCurrentState(&uState));
  498. if (uState != WINSDB_NORMAL)
  499. return E_FAIL;
  500. // make sure the hrow is a valid one
  501. if (!m_cMemMan.IsValidHRow(hrowRecord))
  502. return E_FAIL;
  503. // Tell the memmgr to delete this record
  504. CORg (m_cMemMan.Delete(hrowRecord));
  505. // now tell the index manager to remove this hrow
  506. CORg (m_IndexMgr.RemoveHRow(hrowRecord));
  507. COM_PROTECT_ERROR_LABEL;
  508. }
  509. COM_PROTECT_CATCH
  510. return hr;
  511. }
  512. /*!--------------------------------------------------------------------------
  513. CWinsDatabase::GetCurrentState
  514. Implementation of IWinsDatabase::GetCurrentState
  515. Author: EricDav, v-shubk
  516. ---------------------------------------------------------------------------*/
  517. HRESULT
  518. CWinsDatabase::GetCurrentState(WINSDB_STATE * pState)
  519. {
  520. CSingleLock cl(&m_csState);
  521. cl.Lock();
  522. *pState = m_DBState;
  523. return hrOK;
  524. }
  525. /*!--------------------------------------------------------------------------
  526. CWinsDatabase::SetCurrentState
  527. Helper function to set the current state, protected
  528. Author: EricDav, v-shubk
  529. ---------------------------------------------------------------------------*/
  530. HRESULT
  531. CWinsDatabase::SetCurrentState(WINSDB_STATE winsdbState)
  532. {
  533. CSingleLock cl(&m_csState);
  534. cl.Lock();
  535. m_DBState = winsdbState;
  536. return hrOK;
  537. }
  538. /*!--------------------------------------------------------------------------
  539. CWinsDatabase::FilterRecords
  540. Implementation of IWinsDatabase::FilterRecords
  541. Author: EricDav, v-shubk
  542. ---------------------------------------------------------------------------*/
  543. HRESULT
  544. CWinsDatabase::FilterRecords
  545. (
  546. WINSDB_FILTER_TYPE FilterType,
  547. DWORD dwParam1,
  548. DWORD dwParam2)
  549. {
  550. HRESULT hr = E_NOTIMPL;
  551. WINSDB_STATE uState ;
  552. COM_PROTECT_TRY
  553. {
  554. // fail if the state is other then WINSDB_NORMAL
  555. CORg (GetCurrentState(&uState));
  556. if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
  557. return E_FAIL;
  558. // if in the loading state the readrecords function takes care
  559. if(uState != WINSDB_LOADING)
  560. CORg (SetCurrentState(WINSDB_FILTERING));
  561. // do the filtering here, rebuild the filtered name Index
  562. m_IndexMgr.Filter(FilterType, dwParam1, dwParam2);
  563. if(uState != WINSDB_LOADING)
  564. CORg (SetCurrentState(WINSDB_NORMAL));
  565. COM_PROTECT_ERROR_LABEL;
  566. }
  567. COM_PROTECT_CATCH
  568. return hr;
  569. }
  570. /*!--------------------------------------------------------------------------
  571. CWinsDatabase::AddFilter
  572. Adds the filters specified to the list
  573. Author: EricDav, v-shubk
  574. ---------------------------------------------------------------------------*/
  575. HRESULT
  576. CWinsDatabase::AddFilter(WINSDB_FILTER_TYPE FilterType, DWORD dwParam1, DWORD dwParam2, LPCOLESTR strParam3)
  577. {
  578. HRESULT hr = hrOK;
  579. COM_PROTECT_TRY
  580. {
  581. // for filter by type, dwParam1 is the type, dwParam2 is show/not show
  582. m_IndexMgr.AddFilter(FilterType, dwParam1, dwParam2, strParam3);
  583. }
  584. COM_PROTECT_CATCH
  585. return hr;
  586. }
  587. /*!--------------------------------------------------------------------------
  588. CWinsDatabase::ClearFilter
  589. CLears all the filters
  590. Author: EricDav, v-shubk
  591. ---------------------------------------------------------------------------*/
  592. HRESULT
  593. CWinsDatabase::ClearFilter(WINSDB_FILTER_TYPE FilterType)
  594. {
  595. HRESULT hr = hrOK;
  596. COM_PROTECT_TRY
  597. {
  598. //CFilteredIndexName *pFilterName = (CFilteredIndexName *)m_IndexMgr.GetFilteredNameIndex();
  599. //pFilterName->ClearFilter();
  600. m_IndexMgr.ClearFilter(FilterType);
  601. }
  602. COM_PROTECT_CATCH
  603. return hr;
  604. }
  605. /*!--------------------------------------------------------------------------
  606. CWinsDatabase::SetActiveView
  607. Implementation of IWinsDatabase::SetActiveView
  608. Author: EricDav, v-shubk
  609. ---------------------------------------------------------------------------*/
  610. HRESULT
  611. CWinsDatabase::SetActiveView(WINSDB_VIEW_TYPE ViewType)
  612. {
  613. HRESULT hr = hrOK;
  614. COM_PROTECT_TRY
  615. {
  616. m_IndexMgr.SetActiveView(ViewType);
  617. }
  618. COM_PROTECT_CATCH
  619. return hr;
  620. }
  621. /*!--------------------------------------------------------------------------
  622. CWinsDatabase::Execute()
  623. The background thread calls into this to execute
  624. Author: EricDav, v-shubk
  625. ---------------------------------------------------------------------------*/
  626. DWORD
  627. CWinsDatabase::Execute()
  628. {
  629. DWORD dwStatus = 0;
  630. // wait for the other thread to signal us to start doing something
  631. while (::WaitForSingleObject(m_hStart, INFINITE) == WAIT_OBJECT_0)
  632. {
  633. if (m_bShutdown)
  634. break;
  635. Trace0("WinsDatabase::Execute - start event signaled\n");
  636. WINSINTF_BIND_DATA_T wbdBindData;
  637. handle_t hBinding = NULL;
  638. do
  639. {
  640. // enumerate leases here
  641. SetCurrentState(WINSDB_LOADING);
  642. // now that the server name and ip are valid, call
  643. // WINSBind function directly.
  644. WINSINTF_ADD_T waWinsAddress;
  645. DWORD dwStatus;
  646. CString strNetBIOSName;
  647. // call WinsBind function with the IP address
  648. wbdBindData.fTcpIp = 1;
  649. wbdBindData.pPipeName = NULL;
  650. // convert wbdBindData.pServerAdd to wide char again as one of the internal
  651. // functions expects a wide char string, this is done in WinsABind which is bypassed for
  652. // unicode compatible apps
  653. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) m_strIp;
  654. if ((hBinding = ::WinsBind(&wbdBindData)) == NULL)
  655. {
  656. dwStatus = ::GetLastError();
  657. Trace1("WinsDatabase::Execute - WinsBind failed %lx\n", dwStatus);
  658. break;
  659. }
  660. #ifdef WINS_CLIENT_APIS
  661. dwStatus = ::WinsGetNameAndAdd(
  662. hBinding,
  663. &waWinsAddress,
  664. (BYTE *)strNetBIOSName.GetBuffer(128));
  665. #else
  666. dwStatus = ::WinsGetNameAndAdd(
  667. &waWinsAddress,
  668. (BYTE *)strNetBIOSName.GetBuffer(128));
  669. #endif WINS_CLIENT_APIS
  670. strNetBIOSName.ReleaseBuffer();
  671. if (dwStatus == ERROR_SUCCESS)
  672. {
  673. if(m_dwOwner == (DWORD)-1)
  674. dwStatus = ReadRecords(hBinding);
  675. else
  676. dwStatus = ReadRecordsByOwner(hBinding);
  677. break;
  678. }
  679. else
  680. {
  681. Trace1("WinsDatabase::Execute - WinsGetNameAndAdd failed %lx\n", dwStatus);
  682. break;
  683. }
  684. } while (FALSE);
  685. SetCurrentState(WINSDB_NORMAL);
  686. if(hBinding)
  687. {
  688. // call winsunbind here, the handle is invalid after this and that's fine
  689. WinsUnbind(&wbdBindData, hBinding);
  690. hBinding = NULL;
  691. }
  692. Trace0("WinsDatabase::Execute - all done, going to sleep now...\n");
  693. } // while !Start
  694. Trace0("WinsDatabase::Execute - exiting\n");
  695. return dwStatus;
  696. }
  697. /*!--------------------------------------------------------------------------
  698. CWinsDatabase::ReadRecords
  699. Reads records from the WINS server
  700. Author: EricDav, v-shubk
  701. ---------------------------------------------------------------------------*/
  702. DWORD
  703. CWinsDatabase::ReadRecords(handle_t hBinding)
  704. {
  705. DWORD dwStatus = ERROR_SUCCESS;
  706. DWORD err = ERROR_SUCCESS;
  707. CWinsResults winsResults;
  708. err = winsResults.Update(hBinding);
  709. WINSINTF_RECS_T Recs;
  710. Recs.pRow = NULL;
  711. DWORD NoOfRecsDesired = 500;
  712. DWORD TypeOfRecs = 4;
  713. BOOL fReadAllRecords ;
  714. PWINSINTF_RECORD_ACTION_T pRow;
  715. enum {ST_SCAN_1B_NAME, ST_SCAN_NORM_NAME} State;
  716. LPBYTE pLastName;
  717. UINT nLastNameLen, nLastBuffLen;
  718. pLastName = NULL;
  719. nLastNameLen = 0;
  720. nLastBuffLen = 0;
  721. #ifdef DEBUG
  722. CTime timeStart, timeFinish;
  723. timeStart = CTime::GetCurrentTime();
  724. #endif
  725. m_dwRecsCount = 0;
  726. // initialize the state machine. If we have a name prefix filter we
  727. // start in ST_INIT_1B since we look first for the 1B names. These are
  728. // particular in a sense their type byte - i.e. 0x1B - has been swapped
  729. // with the first byte from the name. Consequently we need to do the same
  730. // to allow WINS to look first for these names. Once we get over the 1B zone
  731. // of our names, we restore the first byte and initiate another cycle for
  732. // the rest of the name.
  733. if (m_strPrefix != NULL)
  734. {
  735. nLastNameLen = nLastBuffLen = strlen(m_strPrefix) + 1;
  736. pLastName = (LPBYTE) new CHAR[nLastBuffLen];
  737. strcpy((LPSTR)pLastName, m_strPrefix);
  738. pLastName[0] = 0x1B;
  739. State = ST_SCAN_1B_NAME;
  740. }
  741. else
  742. {
  743. State = ST_SCAN_NORM_NAME;
  744. }
  745. do
  746. {
  747. #ifdef WINS_CLIENT_APIS
  748. err = ::WinsGetDbRecsByName(
  749. hBinding,
  750. NULL,
  751. WINSINTF_BEGINNING,
  752. pLastName,
  753. nLastNameLen,
  754. NoOfRecsDesired,
  755. TypeOfRecs,
  756. &Recs);
  757. #else
  758. err = ::WinsGetDbRecsByName(
  759. NULL,
  760. WINSINTF_BEGINNING,
  761. pFromName,
  762. LastNameLen,
  763. NoOfRecsDesired,
  764. TypeOfRecs,
  765. &Recs);
  766. #endif WINS_CLIENT_APIS
  767. // check to see if we need to abort
  768. if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0)
  769. {
  770. Trace0("CWinsDatabase::ReadRecords - abort detected\n");
  771. dwStatus = ERROR_OPERATION_ABORTED;
  772. break;
  773. }
  774. if (err == ERROR_REC_NON_EXISTENT)
  775. {
  776. //
  777. // Not a problem, there simply
  778. // are no records in the database
  779. //
  780. Trace0("WinsDatabase::ReadRecords - no records in the Datbase\n");
  781. fReadAllRecords = TRUE;
  782. err = ERROR_SUCCESS;
  783. break;
  784. }
  785. if (err == ERROR_SUCCESS)
  786. {
  787. fReadAllRecords = Recs.NoOfRecs < NoOfRecsDesired;
  788. if (fReadAllRecords)
  789. Trace0("WinsDatabase::ReadRecords - Recs.NoOfRecs < NoOfRecsDesired, will exit\n");
  790. TRY
  791. {
  792. DWORD i;
  793. pRow = Recs.pRow;
  794. for (i = 0; i < Recs.NoOfRecs; ++i, ++pRow)
  795. {
  796. PWINSINTF_RECORD_ACTION_T pRow1 = Recs.pRow;
  797. WinsRecord wRecord;
  798. HROW hrow = NULL;
  799. WinsIntfToWinsRecord(pRow, wRecord);
  800. if (pRow->OwnerId < (UINT) winsResults.AddVersMaps.GetSize())
  801. {
  802. wRecord.dwOwner = winsResults.AddVersMaps[pRow->OwnerId].Add.IPAdd;
  803. }
  804. else
  805. {
  806. // having a record owned by a server which is not in the version map
  807. // we got just earlier from WINS is not something that usually happens.
  808. // It might happen only if the new owner was added right in between.
  809. // Unlikely since this is a very small window - but if this happens
  810. // just skip the record. From our point of view this owner doesn't exist
  811. // hence the record doesn't belong to the view. It will show up with the
  812. // first refresh.
  813. continue;
  814. }
  815. m_dwRecsCount++;
  816. if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord))
  817. continue;
  818. // add the data to our memory store and
  819. // to the sorted index
  820. m_cMemMan.AddData(wRecord, &hrow);
  821. // if m_bEnableCache is 0 the the filter was checked
  822. m_IndexMgr.AddHRow(hrow, TRUE, !m_bEnableCache);
  823. //Trace1("%d records added to DB\n", m_dwRecsCount);
  824. }
  825. // if we reached the end of the DB there is no need to do
  826. // anything from below. Is just pLastName that needs to be
  827. // freed up - this is done outside the loop, before exiting
  828. // the call.
  829. if (!fReadAllRecords)
  830. {
  831. BOOL fRangeOver = FALSE;
  832. // get to the last record that was retrieved.
  833. --pRow;
  834. // check if the last name retrieved from the server is still
  835. // mathing the pattern prefix (if any) or the range has been
  836. // passed over (fRangeOver)
  837. if (m_strPrefix != NULL)
  838. {
  839. for (UINT i = 0; i < pRow->NameLen && m_strPrefix[i] != 0; i++)
  840. {
  841. if (m_strPrefix[i] != pRow->pName[i])
  842. {
  843. fRangeOver = TRUE;
  844. break;
  845. }
  846. }
  847. }
  848. // here fRangeOver is either TRUE if the name doesn't match the pattern
  849. // prefix or FALSE if the range is not passed yet. This latter thing means
  850. // either the name is included in the prefix or the prefix isn't included in the name
  851. // !!! We might want to invalidate the "name included in the prefix" case.
  852. if (fRangeOver)
  853. {
  854. switch(State)
  855. {
  856. case ST_SCAN_1B_NAME:
  857. // in this state pLastName is definitely not NULL and even more,
  858. // it once copied m_strPrefix. Since pLastName can only grow, it is
  859. // certain it is large enough to cotain m_strPrefix one more time.
  860. strcpy((LPSTR)pLastName, m_strPrefix);
  861. nLastNameLen = strlen((LPCSTR)pLastName);
  862. State = ST_SCAN_NORM_NAME;
  863. break;
  864. case ST_SCAN_NORM_NAME:
  865. // we were scanning normal names and we passed
  866. // over the range of names we are looking for
  867. // so just get out of the loop.
  868. fReadAllRecords = TRUE;
  869. break;
  870. }
  871. }
  872. else
  873. {
  874. // enlarge the pLastName if needed
  875. if (nLastBuffLen < pRow->NameLen+2)
  876. {
  877. if (pLastName != NULL)
  878. delete pLastName;
  879. nLastBuffLen = pRow->NameLen+2;
  880. pLastName = (LPBYTE)new CHAR[nLastBuffLen];
  881. }
  882. // copy in pLastName the name of the last record
  883. strcpy((LPSTR)pLastName, (LPCSTR)(pRow->pName));
  884. if (pRow->NameLen >= 16 && pLastName[15] == 0x1B)
  885. {
  886. CHAR ch = pLastName[15];
  887. pLastName[15] = pLastName[0];
  888. pLastName[0] = ch;
  889. }
  890. strcat((LPSTR)pLastName, "\x01");
  891. nLastNameLen = strlen((LPCSTR)pLastName);
  892. }
  893. }
  894. }
  895. CATCH_ALL(e)
  896. {
  897. err = ::GetLastError();
  898. Trace1("WinsDatabase::ReadRecords - Exception! %d \n", err);
  899. m_hrLastError = HRESULT_FROM_WIN32(err);
  900. }
  901. END_CATCH_ALL
  902. }
  903. else
  904. {
  905. Trace1("WinsDatabase::ReadRecords - GetRecsByName failed! %d \n", err);
  906. m_hrLastError = HRESULT_FROM_WIN32(err);
  907. break;
  908. }
  909. if (Recs.pRow != NULL)
  910. {
  911. ::WinsFreeMem(Recs.pRow);
  912. }
  913. } while(!fReadAllRecords );
  914. if (pLastName != NULL)
  915. delete pLastName;
  916. #ifdef DEBUG
  917. timeFinish = CTime::GetCurrentTime();
  918. CTimeSpan timeDelta = timeFinish - timeStart;
  919. CString strTempTime = timeDelta.Format(_T("%H:%M:%S"));
  920. Trace2("WINS DB - ReadRecords: %d records read, total time %s\n", m_dwRecsCount, strTempTime);
  921. #endif
  922. return dwStatus;
  923. }
  924. /*!--------------------------------------------------------------------------
  925. ThreadProc
  926. -
  927. Author: EricDav, v-shubk
  928. ---------------------------------------------------------------------------*/
  929. DWORD WINAPI
  930. ThreadProc(LPVOID pParam)
  931. {
  932. DWORD dwReturn;
  933. HRESULT hr = hrOK;
  934. COM_PROTECT_TRY
  935. {
  936. CWinsDatabase *pWinsDB = (CWinsDatabase *) pParam;
  937. Trace0("WinsDatabase Background Thread started.\n");
  938. dwReturn = pWinsDB->Execute();
  939. }
  940. COM_PROTECT_CATCH
  941. return dwReturn;
  942. }
  943. /*!--------------------------------------------------------------------------
  944. WinsIntfToWinsRecord
  945. Converts a wins record from the server into the WinsRecord struct
  946. Author: EricDav, v-shubk
  947. ---------------------------------------------------------------------------*/
  948. void
  949. WinsIntfToWinsRecord(PWINSINTF_RECORD_ACTION_T pRecord, WinsRecord & wRecord)
  950. {
  951. ZeroMemory(&wRecord, sizeof(WinsRecord));
  952. //::strcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName);
  953. ::memcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName, pRecord->NameLen);
  954. wRecord.dwExpiration = (ULONG) pRecord->TimeStamp;
  955. wRecord.liVersion = pRecord->VersNo;
  956. wRecord.dwOwner = pRecord->OwnerId;
  957. wRecord.dwNameLen = WINSINTF_NAME_LEN_M(pRecord->NameLen);
  958. wRecord.dwType |= (BYTE) wRecord.szRecordName[15];
  959. // translate the state and types to our own definitions
  960. switch (pRecord->State_e)
  961. {
  962. case WINSINTF_E_TOMBSTONE:
  963. wRecord.dwState |= WINSDB_REC_TOMBSTONE;
  964. break;
  965. case WINSINTF_E_DELETED:
  966. //Trace0("WinsIntfToWinsRecord - deleted record.\n");
  967. wRecord.dwState |= WINSDB_REC_DELETED;
  968. break;
  969. case WINSINTF_E_RELEASED:
  970. //Trace0("WinsIntfToWinsRecord - released record.\n");
  971. wRecord.dwState |= WINSDB_REC_RELEASED;
  972. break;
  973. default: // WINSINTF_E_ACTIVE:
  974. wRecord.dwState |= WINSDB_REC_ACTIVE;
  975. break;
  976. }
  977. switch (pRecord->TypOfRec_e)
  978. {
  979. case WINSINTF_E_NORM_GROUP:
  980. wRecord.dwState |= WINSDB_REC_NORM_GROUP;
  981. break;
  982. case WINSINTF_E_SPEC_GROUP:
  983. wRecord.dwState |= WINSDB_REC_SPEC_GROUP;
  984. break;
  985. case WINSINTF_E_MULTIHOMED:
  986. wRecord.dwState |= WINSDB_REC_MULTIHOMED;
  987. break;
  988. default: // WINSINTF_E_UNIQUE:
  989. wRecord.dwState |= WINSDB_REC_UNIQUE;
  990. break;
  991. }
  992. // now do the type -- move the value into the high word
  993. DWORD dwTemp = (pRecord->TypOfRec_e << 16);
  994. wRecord.dwType |= dwTemp;
  995. // now set the static flag
  996. if (pRecord->fStatic)
  997. wRecord.dwState |= WINSDB_REC_STATIC;
  998. // store all of the IP addrs
  999. wRecord.dwNoOfAddrs = pRecord->NoOfAdds;
  1000. if (pRecord->NoOfAdds > 1)
  1001. {
  1002. Assert(pRecord->NoOfAdds <= WINSDB_MAX_NO_IPADDRS);
  1003. //if (wRecord.dwNoOfAddrs > 4)
  1004. // Trace1("WinsIntfToWinsRecord - record with multiple (>4) IP addrs: %d\n", wRecord.dwNoOfAddrs);
  1005. wRecord.dwState |= WINSDB_REC_MULT_ADDRS;
  1006. for (UINT i = 0; i < pRecord->NoOfAdds; i++)
  1007. wRecord.dwIpAdd[i] = pRecord->pAdd[i].IPAdd;
  1008. }
  1009. else
  1010. {
  1011. if (pRecord->NoOfAdds == 0)
  1012. {
  1013. //Trace2("WinsIntfToWinsRecord - record with NoOfAdds == 0; IP: %lx State: %lx \n", pRecord->Add.IPAdd, wRecord.dwState);
  1014. }
  1015. if (pRecord->Add.IPAdd == 0)
  1016. {
  1017. Trace1("WinsIntfToWinsRecord - record with 0 IP Address! State: %lx \n", wRecord.dwState);
  1018. }
  1019. wRecord.dwIpAdd[0] = pRecord->Add.IPAdd;
  1020. }
  1021. }
  1022. /*!--------------------------------------------------------------------------
  1023. CreateWinsDatabase
  1024. -
  1025. Author: EricDav, v-shubk
  1026. ---------------------------------------------------------------------------*/
  1027. HRESULT
  1028. CreateWinsDatabase(CString& strName, CString& strIP, IWinsDatabase **ppWinsDB)
  1029. {
  1030. AFX_MANAGE_STATE(AfxGetModuleState());
  1031. CWinsDatabase * pWinsDB = NULL;
  1032. HRESULT hr = hrOK;
  1033. SPIWinsDatabase spWinsDB;
  1034. COM_PROTECT_TRY
  1035. {
  1036. pWinsDB = new CWinsDatabase();
  1037. Assert(pWinsDB);
  1038. spWinsDB = pWinsDB;
  1039. CORg(pWinsDB->Initialize(strName, strIP));
  1040. *ppWinsDB = spWinsDB.Transfer();
  1041. COM_PROTECT_ERROR_LABEL;
  1042. }
  1043. COM_PROTECT_CATCH
  1044. return hr;
  1045. }
  1046. /*!--------------------------------------------------------------------------
  1047. CWinsDatabase::SetApiInfo
  1048. Implementation of SetApiInfo of IWinsDatabase
  1049. Author: FlorinT
  1050. ---------------------------------------------------------------------------*/
  1051. HRESULT
  1052. CWinsDatabase::SetApiInfo(DWORD dwOwner, LPCOLESTR strPrefix, BOOL bCache)
  1053. {
  1054. // first cleanup the old prefix
  1055. if (m_strPrefix != NULL)
  1056. {
  1057. delete m_strPrefix;
  1058. m_strPrefix = NULL;
  1059. }
  1060. if (strPrefix != NULL)
  1061. {
  1062. UINT nPxLen = 0;
  1063. LPSTR pPrefix;
  1064. nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR);
  1065. m_strPrefix = new char[nPxLen];
  1066. if (m_strPrefix != NULL)
  1067. {
  1068. #ifdef _UNICODE
  1069. if (WideCharToMultiByte(CP_OEMCP,
  1070. 0,
  1071. strPrefix,
  1072. -1,
  1073. m_strPrefix,
  1074. nPxLen,
  1075. NULL,
  1076. NULL) == 0)
  1077. {
  1078. delete m_strPrefix;
  1079. m_strPrefix = NULL;
  1080. }
  1081. #else
  1082. CharToOem(strPrefix, m_strPrefix);
  1083. #endif
  1084. m_strPrefix = _strupr(m_strPrefix);
  1085. for (pPrefix = m_strPrefix;
  1086. *pPrefix != '\0' && *pPrefix != '*' && *pPrefix != '?';
  1087. pPrefix++);
  1088. *pPrefix = '\0';
  1089. }
  1090. }
  1091. m_dwOwner = dwOwner;
  1092. m_bEnableCache = bCache;
  1093. return hrOK;
  1094. }
  1095. /*!--------------------------------------------------------------------------
  1096. CWinsDatabase::GetCachingFlag
  1097. Implementation of GetCachingFlag of IWinsDatabase
  1098. Author: FlorinT
  1099. ---------------------------------------------------------------------------*/
  1100. HRESULT
  1101. CWinsDatabase::GetCachingFlag(LPBOOL pbCache)
  1102. {
  1103. *pbCache = m_bEnableCache;
  1104. return hrOK;
  1105. }
  1106. /*!--------------------------------------------------------------------------
  1107. CWinsDatabase::ReloadSuggested
  1108. Implementation of ReloadSuggested of IWinsDatabase
  1109. Author: FlorinT
  1110. ---------------------------------------------------------------------------*/
  1111. HRESULT
  1112. CWinsDatabase::ReloadSuggested(DWORD dwOwner, LPCOLESTR strPrefix, LPBOOL pbReload)
  1113. {
  1114. // check whether we filtered on a particular owner.
  1115. if (m_dwOwner != 0xFFFFFFFF)
  1116. {
  1117. // we did filter on owner previously, suggest RELOAD if we now
  1118. // don't want to filter on any owner (dwOwner == 0xffffffff)
  1119. // or the owner we want to filter is different from the original one
  1120. *pbReload = (m_dwOwner != dwOwner);
  1121. }
  1122. else
  1123. {
  1124. // we didn't filter on any owner previously so we either loaded
  1125. // all the records (if no name prefix was specified) or loaded
  1126. // all the records matching the given prefix
  1127. if (m_strPrefix != NULL)
  1128. {
  1129. // we did have a previous prefix to match so we need to see
  1130. // if the new prefix is not by any chance more specific than
  1131. // the original one. In which case there is no need to reload
  1132. LPSTR pPrefix;
  1133. UINT nPxLen;
  1134. UINT i;
  1135. if (strPrefix == NULL)
  1136. {
  1137. // if now we're not filtering by name, since we did previously
  1138. // we definitely need to reload the database
  1139. *pbReload = TRUE;
  1140. return hrOK;
  1141. }
  1142. nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR);
  1143. pPrefix = new char[nPxLen];
  1144. if (pPrefix != NULL)
  1145. {
  1146. #ifdef _UNICODE
  1147. if (WideCharToMultiByte(CP_OEMCP,
  1148. 0,
  1149. strPrefix,
  1150. -1,
  1151. pPrefix,
  1152. nPxLen,
  1153. NULL,
  1154. NULL) == 0)
  1155. {
  1156. delete pPrefix;
  1157. *pbReload = TRUE;
  1158. return hrOK;
  1159. }
  1160. #else
  1161. CharToOem(strPrefix, pPrefix);
  1162. #endif
  1163. pPrefix = _strupr(pPrefix);
  1164. for (i = 0;
  1165. pPrefix[i] != '\0' && pPrefix[i] != '*' && pPrefix[i] != '?';
  1166. i++);
  1167. pPrefix[i] = '\0';
  1168. // we don't suggest database reloading only if the current prefix
  1169. // is a prefix for the new one to be applied. This way, whatever
  1170. // was retrieved previously already contains the names having the
  1171. // new prefix.
  1172. *pbReload = (strncmp(m_strPrefix, pPrefix, strlen(m_strPrefix)) != 0);
  1173. delete pPrefix;
  1174. }
  1175. else
  1176. {
  1177. // couldn't allocate memory -> serious enough to ask a full reload
  1178. *pbReload = TRUE;
  1179. }
  1180. }
  1181. else
  1182. {
  1183. // well, there was no prefix specified last time the db was loaded so
  1184. // we should have the whole database in hand. No need to reload.
  1185. *pbReload = FALSE;
  1186. }
  1187. }
  1188. return hrOK;
  1189. }
  1190. /*!--------------------------------------------------------------------------
  1191. CWinsDatabase::ReadRecordsByOwner
  1192. Reads records from the WINS server for a particular owner
  1193. Author: EricDav, v-shubk
  1194. ---------------------------------------------------------------------------*/
  1195. #define MAX_DESIRED_RECORDS 400
  1196. #define LARGE_GAP_DETECT_COUNT 32
  1197. DWORD
  1198. CWinsDatabase::ReadRecordsByOwner(handle_t hBinding)
  1199. {
  1200. DWORD err;
  1201. CWinsResults winsResults;
  1202. WINSINTF_RECS_T Recs;
  1203. DWORD dwIP;
  1204. LARGE_INTEGER MinVersNo, MaxVersNo;
  1205. LARGE_INTEGER LowestVersNo;
  1206. DWORD dwDesired;
  1207. DWORD dwLargeGapCount;
  1208. WINSINTF_ADD_T OwnerAdd;
  1209. DWORD i;
  1210. err = winsResults.Update(hBinding);
  1211. if (err != ERROR_SUCCESS)
  1212. {
  1213. m_hrLastError = HRESULT_FROM_WIN32(err);
  1214. return err;
  1215. }
  1216. MinVersNo.QuadPart= 0;
  1217. for (i = 0; i < (int)winsResults.NoOfOwners; i++)
  1218. {
  1219. if (m_dwOwner == winsResults.AddVersMaps[i].Add.IPAdd)
  1220. {
  1221. MaxVersNo = winsResults.AddVersMaps[i].VersNo;
  1222. break;
  1223. }
  1224. }
  1225. // if we couldn't find the owner (highly unlikely) get out
  1226. // with error INVALID_PARAMETER.
  1227. if (i == winsResults.NoOfOwners)
  1228. {
  1229. err = ERROR_INVALID_PARAMETER;
  1230. m_hrLastError = HRESULT_FROM_WIN32(err);
  1231. return err;
  1232. }
  1233. m_dwRecsCount = 0;
  1234. OwnerAdd.Type = 0;
  1235. OwnerAdd.Len = 4;
  1236. OwnerAdd.IPAdd = m_dwOwner;
  1237. // This is what the server does to retrieve the records:
  1238. // 1. sets an ascending index on owner & version number.
  1239. // 2. goes to the first record owned by the given owner,
  1240. // having a version number larger or equal to MinVersNo.
  1241. // 3. stop if the record's vers num is higher than the range specified
  1242. // 4. stop if more than 1000 recs have been already received
  1243. // 5. add the new record to the set to return and go to 3.
  1244. //
  1245. dwDesired = MAX_DESIRED_RECORDS;
  1246. dwLargeGapCount = LARGE_GAP_DETECT_COUNT;
  1247. LowestVersNo.QuadPart = 0;
  1248. if (MaxVersNo.QuadPart > dwDesired)
  1249. MinVersNo.QuadPart = MaxVersNo.QuadPart-dwDesired;
  1250. else
  1251. MinVersNo.QuadPart = 0;
  1252. Recs.pRow = NULL;
  1253. while(MaxVersNo.QuadPart >= MinVersNo.QuadPart)
  1254. {
  1255. // clear up the previous array - if any
  1256. if (Recs.pRow != NULL)
  1257. {
  1258. ::WinsFreeMem(Recs.pRow);
  1259. Recs.pRow = NULL;
  1260. }
  1261. // go to WINS to get the data for the given Owner
  1262. #ifdef WINS_CLIENT_APIS
  1263. err = ::WinsGetDbRecs(hBinding, &OwnerAdd, MinVersNo,
  1264. MaxVersNo, &Recs);
  1265. #else
  1266. err = ::WinsGetDbRecs(&OwnerAdd, MinVersNo,
  1267. MaxVersNo, &Recs);
  1268. #endif WINS_CLIENT_APIS
  1269. // if abort was requested, break out with "ABORTED"
  1270. if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0)
  1271. {
  1272. err = ERROR_OPERATION_ABORTED;
  1273. break;
  1274. }
  1275. // if there is any kind of error break out
  1276. if (err != ERROR_SUCCESS)
  1277. {
  1278. if (err == ERROR_REC_NON_EXISTENT)
  1279. {
  1280. // I'm not sure this happens after all. The server side (WINS) has
  1281. // not code path returning such an error code.
  1282. err = ERROR_SUCCESS;
  1283. }
  1284. else
  1285. {
  1286. // if this happens, just get out with the error, and save the
  1287. // meaning of the error
  1288. m_hrLastError = HRESULT_FROM_WIN32(err);
  1289. }
  1290. break;
  1291. }
  1292. // if got less than 1/4 of the size of the range, expand the range
  1293. // to double of what it was + 1. (+1 is important to avoid the effect
  1294. // of dramatic drop down because of DWORD roll-over
  1295. if (Recs.NoOfRecs <= (dwDesired >> 2))
  1296. {
  1297. dwDesired <<= 1;
  1298. dwDesired |= 1;
  1299. }
  1300. // else if got more than 3/4 of the size of the range, split the range in 2
  1301. // but not less than MAX_DESIRED_RECORDS
  1302. else if (Recs.NoOfRecs >= (dwDesired - (dwDesired >> 2)))
  1303. {
  1304. dwDesired = max (MAX_DESIRED_RECORDS, dwDesired >> 1);
  1305. }
  1306. TRY
  1307. {
  1308. DWORD j;
  1309. PWINSINTF_RECORD_ACTION_T pRow;
  1310. for (j = 0, pRow = Recs.pRow; j < Recs.NoOfRecs; j++, ++pRow)
  1311. {
  1312. WinsRecord wRecord;
  1313. HROW hrow = NULL;
  1314. pRow->OwnerId = m_dwOwner;
  1315. WinsIntfToWinsRecord(pRow, wRecord);
  1316. m_dwRecsCount++;
  1317. if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord))
  1318. continue;
  1319. // add the data to our memory store and
  1320. // to the sorted index
  1321. m_cMemMan.AddData(wRecord, &hrow);
  1322. m_IndexMgr.AddHRow(hrow, FALSE, !m_bEnableCache);
  1323. }
  1324. // now setup the new range to search..
  1325. //
  1326. // if this is not the gap boundary detection cycle, the next MaxVersNo
  1327. // needs to go right below the current MinVersNo. Otherwise, MaxVersNo
  1328. // needs to remain untouched!
  1329. if (dwLargeGapCount != 0)
  1330. MaxVersNo.QuadPart = MinVersNo.QuadPart - 1;
  1331. // if no records were found..
  1332. if (Recs.NoOfRecs == 0)
  1333. {
  1334. // ..and we were already in the gap boundary detection cycle..
  1335. if (dwLargeGapCount == 0)
  1336. // ..just break the loop - there are simply no more records
  1337. // for this owner in the database
  1338. break;
  1339. // ..otherwise just decrease the gap boundary detection counter.
  1340. // If it reaches 0, then next cycle we will attempt to see if
  1341. // there is any record closer to the lowest edge of the range by
  1342. // expanding for one time only the whole space.
  1343. dwLargeGapCount--;
  1344. }
  1345. else
  1346. {
  1347. // if we just exited the gap boundary detection cycle by finding some
  1348. // records, set the LowestVersNo to one more than the largest VersNo
  1349. // we found during this cycle.
  1350. if (dwLargeGapCount == 0)
  1351. {
  1352. pRow--;
  1353. LowestVersNo.QuadPart = pRow->VersNo.QuadPart+1;
  1354. }
  1355. // if there were any records found, just reset the gap boundary detection counter.
  1356. dwLargeGapCount = LARGE_GAP_DETECT_COUNT;
  1357. }
  1358. // if the dwLargeGapCount counter is zero, it means the next cycle is a gap boundary detection one
  1359. // which means the range should be set for the whole unexplored space.
  1360. if (dwLargeGapCount != 0 && MaxVersNo.QuadPart > LowestVersNo.QuadPart + dwDesired)
  1361. MinVersNo.QuadPart = MaxVersNo.QuadPart - dwDesired;
  1362. else
  1363. MinVersNo.QuadPart = LowestVersNo.QuadPart;
  1364. }
  1365. CATCH_ALL(e)
  1366. {
  1367. err = ::GetLastError();
  1368. m_hrLastError = HRESULT_FROM_WIN32(err);
  1369. }
  1370. END_CATCH_ALL
  1371. }
  1372. if (Recs.pRow != NULL)
  1373. ::WinsFreeMem(Recs.pRow);
  1374. return err;
  1375. }