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.

3214 lines
97 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ipx\sap\serverdb.c
  5. Abstract:
  6. This module implements SAP Server Table and corresponding API
  7. Author:
  8. Vadim Eydelman 05-15-1995
  9. Revision History:
  10. --*/
  11. #include "sapp.h"
  12. // The table
  13. SERVER_TABLE ServerTable;
  14. // Max number of unsorted servers
  15. ULONG SDBMaxUnsortedServers=SAP_SDB_MAX_UNSORTED_DEF;
  16. // Interval with which to update the sorted list
  17. ULONG SDBSortLatency=SAP_SDB_SORT_LATENCY_DEF;
  18. // Size of heap reserved for the database
  19. ULONG SDBMaxHeapSize=SAP_SDB_MAX_HEAP_SIZE_DEF;
  20. // Local prototypes
  21. BOOL
  22. AcquireAllLocks (
  23. void
  24. );
  25. VOID
  26. ReleaseAllLocks (
  27. void
  28. );
  29. PSERVER_NODE
  30. CreateNode (
  31. IN PIPX_SERVER_ENTRY_P Server,
  32. IN ULONG InterfaceIndex,
  33. IN DWORD Protocol,
  34. IN PUCHAR AdvertisingNode,
  35. IN PSDB_HASH_LIST HashList
  36. );
  37. VOID
  38. ChangeMainNode (
  39. IN PSERVER_NODE oldNode,
  40. IN PSERVER_NODE newNode,
  41. IN PLIST_ENTRY serverLink
  42. );
  43. VOID
  44. DeleteNode (
  45. IN PSERVER_NODE node
  46. );
  47. VOID
  48. DeleteMainNode (
  49. IN PSERVER_NODE node
  50. );
  51. DWORD
  52. DoFindNextNode (
  53. IN PLIST_ENTRY cur,
  54. IN PPROTECTED_LIST list,
  55. IN INT link,
  56. IN DWORD ExclusionFlags,
  57. IN OUT PIPX_SERVER_ENTRY_P Server,
  58. IN OUT PULONG InterfaceIndex OPTIONAL,
  59. IN OUT PULONG Protocol OPTIONAL,
  60. OUT PULONG ObjectID OPTIONAL
  61. );
  62. VOID
  63. DoUpdateSortedList (
  64. void
  65. );
  66. PLIST_ENTRY
  67. FindIntfLink (
  68. ULONG InterfaceIndex
  69. );
  70. PLIST_ENTRY
  71. FindTypeLink (
  72. USHORT Type
  73. );
  74. PLIST_ENTRY
  75. FindSortedLink (
  76. USHORT Type,
  77. PUCHAR Name
  78. );
  79. INT
  80. HashFunction (
  81. PUCHAR Name
  82. );
  83. ULONG
  84. GenerateUniqueID (
  85. PSDB_HASH_LIST HashList
  86. );
  87. /*++
  88. *******************************************************************
  89. C r e a t e S e r v e r T a b l e
  90. Routine Description:
  91. Allocates resources for server table management
  92. Arguments:
  93. UpdateObject - this object will be signalled when 'slow'
  94. sorted list of servers needs to be updated
  95. (UpdateSortedList should be called)
  96. TimerObject - this object will be signalled when server expiration
  97. queue requires processing (ProcessExpirationQueue should
  98. be called)
  99. Return Value:
  100. NO_ERROR - resources were allocated successfully
  101. other - reason of failure (windows error code)
  102. *******************************************************************
  103. --*/
  104. DWORD
  105. CreateServerTable (
  106. HANDLE *UpdateObject,
  107. HANDLE *TimerObject
  108. ) {
  109. DWORD status=NO_ERROR;
  110. INT i;
  111. BOOL res;
  112. // Use private heap for server entries
  113. // to eliminate fragmentation
  114. ServerTable.ST_Heap = HeapCreate (0, 0, SDBMaxHeapSize*1024*1024);
  115. if (ServerTable.ST_Heap!=NULL) {
  116. ServerTable.ST_UpdateTimer = CreateWaitableTimer (
  117. NULL,
  118. TRUE, // Manual reset
  119. NULL);
  120. if (ServerTable.ST_UpdateTimer!=NULL) {
  121. *UpdateObject = ServerTable.ST_UpdateTimer;
  122. ServerTable.ST_ExpirationTimer = CreateWaitableTimer (
  123. NULL,
  124. TRUE, // Manual reset
  125. NULL);
  126. if (ServerTable.ST_ExpirationTimer!=NULL) {
  127. LONGLONG timeout = 0;
  128. *TimerObject = ServerTable.ST_ExpirationTimer;
  129. ServerTable.ST_LastEnumerator = NULL;
  130. ServerTable.ST_ServerCnt = 0;
  131. ServerTable.ST_StaticServerCnt = 0;
  132. ServerTable.ST_TMPListCnt = 0;
  133. ServerTable.ST_DeletedListCnt = 0;
  134. ServerTable.ST_UpdatePending = -1;
  135. InitializeSyncObjPool (&ServerTable.ST_SyncPool);
  136. InitializeProtectedList (&ServerTable.ST_SortedListPRM);
  137. InitializeProtectedList (&ServerTable.ST_SortedListTMP);
  138. InitializeProtectedList (&ServerTable.ST_DeletedList);
  139. InitializeProtectedList (&ServerTable.ST_TypeList);
  140. InitializeProtectedList (&ServerTable.ST_IntfList);
  141. InitializeProtectedList (&ServerTable.ST_ExpirationQueue);
  142. InitializeProtectedList (&ServerTable.ST_ChangedSvrsQueue);
  143. for (i=0; i<SDB_NAME_HASH_SIZE; i++) {
  144. InitializeProtectedList (&ServerTable.ST_HashLists[i].HL_List);
  145. ServerTable.ST_HashLists[i].HL_ObjectID = i;
  146. }
  147. res = SetWaitableTimer (
  148. ServerTable.ST_UpdateTimer,
  149. (PLARGE_INTEGER)&timeout,
  150. 0, // no period
  151. NULL, NULL, // no completion
  152. FALSE); // no need to resume
  153. ASSERTMSG ("Could not set update timer ", res);
  154. res = SetWaitableTimer (
  155. ServerTable.ST_ExpirationTimer,
  156. (PLARGE_INTEGER)&timeout,
  157. 0, // no period
  158. NULL, NULL, // no completion
  159. FALSE); // no need to resume
  160. ASSERTMSG ("Could not set expiration timer ", res);
  161. return NO_ERROR;
  162. }
  163. else {
  164. status = GetLastError ();
  165. Trace (DEBUG_FAILURES, "File: %s, line: %ld."
  166. " Could not create expiration timer (gle:%ld).",
  167. __FILE__, __LINE__, status);
  168. }
  169. CloseHandle (ServerTable.ST_UpdateTimer);
  170. *UpdateObject = NULL;
  171. }
  172. else
  173. {
  174. status = GetLastError ();
  175. Trace (DEBUG_FAILURES, "File: %s, line: %ld."
  176. " Could not create update timer (gle:%ld).",
  177. __FILE__, __LINE__, status);
  178. }
  179. HeapDestroy (ServerTable.ST_Heap);
  180. }
  181. else {
  182. status = GetLastError ();
  183. Trace (DEBUG_FAILURES, "File: %s, line: %ld."
  184. " Could not allocate server table heap (gle:%ld).",
  185. __FILE__, __LINE__, status);
  186. }
  187. return status;
  188. }
  189. /*++
  190. *******************************************************************
  191. D e l e t e S e r v e r T a b l e
  192. Routine Description:
  193. Dispose of server table and associated resources
  194. Arguments:
  195. Return Value:
  196. NO_ERROR - resources were disposed of successfully
  197. other - reason of failure (windows error code)
  198. *******************************************************************
  199. --*/
  200. void
  201. DeleteServerTable (
  202. void
  203. ) {
  204. INT i;
  205. while (InterlockedIncrement (&ServerTable.ST_UpdatePending)>0) {
  206. while (ServerTable.ST_UpdatePending!=-1)
  207. Sleep (100);
  208. }
  209. CloseHandle (ServerTable.ST_ExpirationTimer);
  210. CloseHandle (ServerTable.ST_UpdateTimer);
  211. DeleteProtectedList (&ServerTable.ST_SortedListPRM);
  212. DeleteProtectedList (&ServerTable.ST_SortedListTMP);
  213. DeleteProtectedList (&ServerTable.ST_DeletedList);
  214. DeleteProtectedList (&ServerTable.ST_TypeList);
  215. DeleteProtectedList (&ServerTable.ST_IntfList);
  216. DeleteProtectedList (&ServerTable.ST_ExpirationQueue);
  217. DeleteProtectedList (&ServerTable.ST_ChangedSvrsQueue);
  218. for (i=0; i<SDB_NAME_HASH_SIZE; i++) {
  219. DeleteProtectedList (&ServerTable.ST_HashLists[i].HL_List);
  220. ServerTable.ST_HashLists[i].HL_ObjectID = i;
  221. }
  222. DeleteSyncObjPool (&ServerTable.ST_SyncPool);
  223. HeapDestroy (ServerTable.ST_Heap); // Will also destroy all server entries
  224. }
  225. /*++
  226. *******************************************************************
  227. U p d a t e S e r v e r
  228. Routine Description:
  229. Update server in the table (If entry for server does not exist and
  230. hop count parameter is less than 16, it is added to the table, if entry
  231. for the server exists and hop count parameter is 16, server is marked
  232. for deletion, otherwise server info is updated).
  233. Sorted list of servers is not updated immediately
  234. if new server is added or deleted
  235. Arguments:
  236. Server - server parameters (as it comes from IPX packet)
  237. InterfaceIndex - interface through which knowledge of server was obtained
  238. Protocol - protocol used to obtain server info
  239. TimeToLive - time in sec before server is aged out (INFINITE for no aging)
  240. AdvertisingNode - node that from which this server info was received
  241. NewServer - set to TRUE if server was not in the table before
  242. Return Value:
  243. NO_ERROR - server was added/updated ok
  244. other - reason of failure (windows error code)
  245. *******************************************************************
  246. --*/
  247. DWORD
  248. UpdateServer (
  249. IN PIPX_SERVER_ENTRY_P Server,
  250. IN ULONG InterfaceIndex,
  251. IN DWORD Protocol,
  252. IN ULONG TimeToLive,
  253. IN PUCHAR AdvertisingNode,
  254. IN INT Flags,
  255. OUT BOOL *NewServer OPTIONAL
  256. ) {
  257. PSDB_HASH_LIST HashList;
  258. PLIST_ENTRY cur, intfLink=NULL, serverLink=NULL;
  259. DWORD status=NO_ERROR;
  260. PSERVER_NODE theNode=NULL, mainNode=NULL;
  261. INT res;
  262. //ASSERT ((Flags&(~(SDB_DONT_RESPOND_NODE_FLAG|SDB_DISABLED_NODE_FLAG)))==0);
  263. if (Server->Name[0]==0) {
  264. Trace (DEBUG_SERVERDB, "Illigal server name in UpdateServer.");
  265. return ERROR_INVALID_PARAMETER;
  266. }
  267. if ( Server-> HopCount > IPX_MAX_HOP_COUNT )
  268. {
  269. Trace(
  270. DEBUG_SERVERDB, "\tUpdateServer : Invalid Hop count"
  271. "type: %04x, hops: %d, name: %.48s.\n",
  272. Server->Type,
  273. Server->HopCount,
  274. Server->Name
  275. );
  276. ASSERTERR( FALSE );
  277. return ERROR_INVALID_PARAMETER;
  278. }
  279. //else
  280. //{
  281. // Trace( DEBUG_SERVERDB, "\tUpdateServer : Hop count ok\n" );
  282. //}
  283. if (ARGUMENT_PRESENT(NewServer))
  284. *NewServer = TRUE;
  285. // First try to locate server in hash list
  286. HashList = &ServerTable.ST_HashLists[HashFunction (Server->Name)];
  287. if (!AcquireServerTableList (&HashList->HL_List, TRUE))
  288. return ERROR_GEN_FAILURE;
  289. cur = HashList->HL_List.PL_Head.Flink;
  290. while (cur!=&HashList->HL_List.PL_Head) {
  291. PSERVER_NODE node = CONTAINING_RECORD (cur,
  292. SERVER_NODE,
  293. N_Links[SDB_HASH_TABLE_LINK]);
  294. VALIDATE_NODE(node);
  295. if (!IsEnumerator (node)) {
  296. if (Server->Type == node->SN_Server.Type) {
  297. res = IpxNameCmp (Server->Name, node->SN_Server.Name);
  298. if (res==0) {
  299. if (ARGUMENT_PRESENT(NewServer))
  300. *NewServer = FALSE;
  301. // Loop through all entries in the table for
  302. // this server
  303. do {
  304. // If there is another entry with same interface,
  305. // remember its position in interface list
  306. // so new entry can be inserted quickly if
  307. // necessary
  308. if (InterfaceIndex==node->SN_InterfaceIndex)
  309. intfLink = &node->N_Links[SDB_INTF_LIST_LINK];
  310. if ((InterfaceIndex==node->SN_InterfaceIndex)
  311. && (Protocol == node->SN_Protocol)
  312. && (IpxNodeCmp (AdvertisingNode,
  313. &node->SN_AdvertisingNode)==0)) {
  314. theNode = node; // Exact match
  315. if (((Flags & SDB_DISABLED_NODE_FLAG)
  316. < (node->N_NodeFlags & SDB_DISABLED_NODE_FLAG))
  317. || (((Flags & SDB_DISABLED_NODE_FLAG)
  318. == (node->N_NodeFlags & SDB_DISABLED_NODE_FLAG))
  319. && (Server->HopCount<=node->SN_HopCount))) {
  320. // Hop count is better, than the that
  321. // of the rest, ignore them
  322. if (serverLink==NULL)
  323. serverLink = &theNode->SN_ServerLink;
  324. break;
  325. }
  326. }
  327. else {
  328. // Get the best entry besides the one
  329. // we are updating
  330. if (mainNode==NULL)
  331. mainNode = node;
  332. // Find the place for added/updated entry
  333. // in the list of entries for this server
  334. // (this list is ordered by hop count)
  335. if ((serverLink==NULL)
  336. && (((Flags & SDB_DISABLED_NODE_FLAG)
  337. < (node->N_NodeFlags & SDB_DISABLED_NODE_FLAG))
  338. || (((Flags & SDB_DISABLED_NODE_FLAG)
  339. == (node->N_NodeFlags & SDB_DISABLED_NODE_FLAG))
  340. && (Server->HopCount<=node->SN_HopCount)))) {
  341. serverLink = &node->SN_ServerLink;
  342. // We saw the server and know where
  343. // to place it, break out
  344. if (theNode!=NULL)
  345. break;
  346. }
  347. }
  348. node = CONTAINING_RECORD (node->SN_ServerLink.Flink,
  349. SERVER_NODE,
  350. SN_ServerLink);
  351. VALIDATE_SERVER_NODE(node);
  352. }
  353. // Loop until we are back to best entry
  354. while (!IsMainNode (node));
  355. }
  356. else if (res<0)
  357. // No chance to see the server: the hash is ordered
  358. // be type.name
  359. break;
  360. }
  361. else if (Server->Type<node->SN_Server.Type)
  362. break;
  363. }
  364. cur = cur->Flink;
  365. }
  366. if (theNode!=NULL) {
  367. if ((IpxNetCmp (theNode->SN_Server.Network, Server->Network)!=0)
  368. || (IpxNodeCmp (theNode->SN_Server.Node, Server->Node)!=0)
  369. || (IpxSockCmp (theNode->SN_Server.Socket, Server->Socket)!=0)
  370. ) {
  371. Trace (DEBUG_FAILURES,
  372. "Address change for server %.4x %.48s:\n"
  373. " Old - %.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x:%.2x%.2x\n"
  374. " New - %.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x:%.2x%.2x",
  375. Server->Type, Server->Name,
  376. theNode->SN_Server.Network[0], theNode->SN_Server.Network[1],
  377. theNode->SN_Server.Network[2], theNode->SN_Server.Network[3],
  378. theNode->SN_Server.Node[0], theNode->SN_Server.Node[1],
  379. theNode->SN_Server.Node[2], theNode->SN_Server.Node[3],
  380. theNode->SN_Server.Node[4], theNode->SN_Server.Node[5],
  381. theNode->SN_Server.Socket[0], theNode->SN_Server.Socket[1],
  382. Server->Network[0], Server->Network[1],
  383. Server->Network[2], Server->Network[3],
  384. Server->Node[0], Server->Node[1], Server->Node[2],
  385. Server->Node[3], Server->Node[4], Server->Node[5],
  386. Server->Socket[0], Server->Socket[1]
  387. );
  388. IF_LOG (EVENTLOG_WARNING_TYPE) {
  389. IPX_ADDRESS_BLOCK data[2];
  390. LPSTR str[1] = {(LPSTR)Server->Name};
  391. IpxAddrCpy (&data[0], &theNode->SN_Server);
  392. IpxAddrCpy (&data[1], Server);
  393. RouterLogWarningDataA (RouterEventLogHdl,
  394. ROUTERLOG_IPXSAP_SERVER_ADDRESS_CHANGE,
  395. 1, str,
  396. 24, (LPBYTE)data);
  397. }
  398. IpxAddrCpy (&theNode->SN_Server, Server);
  399. }
  400. // We already have server in the table
  401. if (IsDisabledNode (theNode))
  402. // Just update the hop count
  403. theNode->SN_HopCount = Server->HopCount;
  404. else if (((Flags & SDB_DISABLED_NODE_FLAG)
  405. != (theNode->N_NodeFlags & SDB_DISABLED_NODE_FLAG))
  406. || (Server->HopCount!=theNode->SN_HopCount)) {
  407. // Its hop count changed, we'll have to do something
  408. if (AcquireAllLocks ()) {
  409. theNode->SN_HopCount = Server->HopCount;
  410. if (mainNode==NULL) {
  411. // We haven't seen a node that had or has lower hop count
  412. // theNode is still the best
  413. if (Server->HopCount==IPX_MAX_HOP_COUNT)
  414. DeleteMainNode (theNode);
  415. else {
  416. if (IsEnumerator (CONTAINING_RECORD (
  417. ServerTable.ST_ChangedSvrsQueue.PL_Head.Flink,
  418. SERVER_NODE,
  419. N_Links[SDB_CHANGE_QUEUE_LINK])))
  420. ExpireLRRequests ((PVOID)UlongToPtr(InterfaceIndex));
  421. // Move server to the bottom of change queue
  422. // so those who enumerate through it
  423. // notice that it has changed
  424. RemoveEntryList (&theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  425. InsertHeadList (&ServerTable.ST_ChangedSvrsQueue.PL_Head,
  426. &theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  427. }
  428. }
  429. else if (!IsMainNode (theNode)
  430. && (serverLink==&theNode->SN_ServerLink)
  431. && (Server->HopCount<IPX_MAX_HOP_COUNT))
  432. // theNode was not the best and it is going to stay where
  433. // it is now.
  434. ;
  435. else if (IsMainNode (theNode))
  436. // It was the best node. but we saw something better:
  437. // mainNode!=NULL (was checked above)
  438. ChangeMainNode (theNode, mainNode, serverLink);
  439. else if (serverLink==&mainNode->SN_ServerLink)
  440. // It is moving before the mainNode - becoming the best
  441. ChangeMainNode (mainNode, theNode, serverLink);
  442. else if (Server->HopCount<IPX_MAX_HOP_COUNT) {
  443. // Just moving around the list of entries for the
  444. // server
  445. RemoveEntryList (&theNode->SN_ServerLink);
  446. if (serverLink!=NULL) {
  447. // Going before the serverLink
  448. InsertTailList (serverLink, &theNode->SN_ServerLink);
  449. }
  450. else {
  451. // Going to the end of list (circular list:
  452. // end is right before the beginning
  453. InsertTailList (&mainNode->SN_ServerLink,
  454. &theNode->SN_ServerLink);
  455. }
  456. }
  457. else { // Going away (Server->HopCount>=IPX_MAX_HOP_COUNT)
  458. DeleteNode (theNode);
  459. }
  460. ReleaseAllLocks ();
  461. }
  462. else
  463. status = ERROR_GEN_FAILURE;
  464. }
  465. }
  466. else if (Server->HopCount<IPX_MAX_HOP_COUNT) {
  467. // It is not there and it is not dead.
  468. if (mainNode==NULL) {
  469. PLIST_ENTRY link;
  470. // Add a brand new server
  471. theNode = CreateNode (Server, InterfaceIndex, Protocol,
  472. AdvertisingNode, HashList);
  473. if (theNode!=NULL) {
  474. if (AcquireAllLocks ()) {
  475. if (((intfLink=FindIntfLink (InterfaceIndex))!=NULL)
  476. && ((link=FindTypeLink (Server->Type))!=NULL)) {
  477. ServerTable.ST_ServerCnt += 1;
  478. if (theNode->SN_Protocol==IPX_PROTOCOL_STATIC)
  479. ServerTable.ST_StaticServerCnt += 1;
  480. SetMainNode (theNode);
  481. // Insert in every list
  482. InsertTailList (cur,
  483. &theNode->N_Links[SDB_HASH_TABLE_LINK]);
  484. InsertTailList (link,
  485. &theNode->N_Links[SDB_TYPE_LIST_LINK]);
  486. InsertTailList (intfLink,
  487. &theNode->N_Links[SDB_INTF_LIST_LINK]);
  488. if (IsEnumerator (CONTAINING_RECORD (
  489. ServerTable.ST_ChangedSvrsQueue.PL_Head.Flink,
  490. SERVER_NODE,
  491. N_Links[SDB_CHANGE_QUEUE_LINK])))
  492. ExpireLRRequests ((PVOID)UlongToPtr(InterfaceIndex));
  493. InsertHeadList (&ServerTable.ST_ChangedSvrsQueue.PL_Head,
  494. &theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  495. link = FindSortedLink (Server->Type, Server->Name);
  496. InsertTailList (link,
  497. &theNode->N_Links[SDB_SORTED_LIST_LINK]);
  498. ServerTable.ST_TMPListCnt += 1;
  499. // Signal update if too many nodes
  500. if (ServerTable.ST_TMPListCnt == SDBMaxUnsortedServers)
  501. UpdateSortedList ();
  502. }
  503. else {
  504. HeapFree (ServerTable.ST_Heap, 0, theNode);
  505. status = ERROR_NOT_ENOUGH_MEMORY;
  506. }
  507. ReleaseAllLocks ();
  508. }
  509. else {
  510. HeapFree (ServerTable.ST_Heap, 0, theNode);
  511. status = ERROR_GEN_FAILURE;
  512. }
  513. }
  514. else
  515. status = ERROR_NOT_ENOUGH_MEMORY;
  516. }
  517. // Ok, we consider adding it although we have some entries already
  518. else {
  519. // Check for duplicates (different addresses)
  520. if ((IpxNetCmp (mainNode->SN_Server.Network, Server->Network)!=0)
  521. || (IpxNodeCmp (mainNode->SN_Server.Node, Server->Node)!=0)
  522. || (IpxSockCmp (mainNode->SN_Server.Socket, Server->Socket)!=0)
  523. ) {
  524. Trace (DEBUG_FAILURES,
  525. "Duplicate addresses for server %.4x %.48s:\n"
  526. " 1 - %.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x:%.2x%.2x"
  527. " from if-%ld, node-%.2x%.2x%.2x%.2x%.2x%.2x\n"
  528. " 2 - %.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x:%.2x%.2x"
  529. " from if-%ld, node-%.2x%.2x%.2x%.2x%.2x%.2x",
  530. Server->Type, Server->Name,
  531. mainNode->SN_Server.Network[0], mainNode->SN_Server.Network[1],
  532. mainNode->SN_Server.Network[2], mainNode->SN_Server.Network[3],
  533. mainNode->SN_Server.Node[0], mainNode->SN_Server.Node[1],
  534. mainNode->SN_Server.Node[2], mainNode->SN_Server.Node[3],
  535. mainNode->SN_Server.Node[4], mainNode->SN_Server.Node[5],
  536. mainNode->SN_Server.Socket[0], mainNode->SN_Server.Socket[1],
  537. mainNode->SN_InterfaceIndex,
  538. mainNode->SN_AdvertisingNode[0], mainNode->SN_AdvertisingNode[1],
  539. mainNode->SN_AdvertisingNode[2], mainNode->SN_AdvertisingNode[3],
  540. mainNode->SN_AdvertisingNode[4], mainNode->SN_AdvertisingNode[5],
  541. Server->Network[0], Server->Network[1],
  542. Server->Network[2], Server->Network[3],
  543. Server->Node[0], Server->Node[1], Server->Node[2],
  544. Server->Node[3], Server->Node[4], Server->Node[5],
  545. Server->Socket[0], Server->Socket[1],
  546. InterfaceIndex,
  547. AdvertisingNode[0], AdvertisingNode[1], AdvertisingNode[2],
  548. AdvertisingNode[3], AdvertisingNode[4], AdvertisingNode[5]
  549. );
  550. IF_LOG (EVENTLOG_WARNING_TYPE) {
  551. IPX_ADDRESS_BLOCK data[2];
  552. LPSTR str[1] = {(LPSTR)Server->Name};
  553. IpxAddrCpy (&data[0], &mainNode->SN_Server);
  554. IpxAddrCpy (&data[1], Server);
  555. RouterLogWarningDataA (RouterEventLogHdl,
  556. ROUTERLOG_IPXSAP_SERVER_DUPLICATE_ADDRESSES,
  557. 1, str,
  558. 24, (LPBYTE)data);
  559. }
  560. }
  561. // Collect all servers when routing
  562. if (Routing) {
  563. theNode = CreateNode (Server, InterfaceIndex, Protocol,
  564. AdvertisingNode, HashList);
  565. if (theNode!=NULL) {
  566. if (AcquireAllLocks ()) {
  567. if ((intfLink!=NULL)
  568. || ((intfLink=FindIntfLink (InterfaceIndex))!=NULL)) {
  569. if (theNode->SN_Protocol==IPX_PROTOCOL_STATIC)
  570. ServerTable.ST_StaticServerCnt += 1;
  571. InsertTailList (intfLink,
  572. &theNode->N_Links[SDB_INTF_LIST_LINK]);
  573. if ((Server->HopCount<mainNode->SN_HopCount)
  574. || IsDisabledNode (mainNode))
  575. // Replaces the best node
  576. ChangeMainNode (mainNode, theNode, NULL);
  577. else if (serverLink!=NULL) {
  578. // Going before the serverLink
  579. InsertTailList (serverLink, &theNode->SN_ServerLink);
  580. }
  581. else {
  582. // Going to the end of list (circular list:
  583. // the end is right before the beginning)
  584. InsertTailList (&mainNode->SN_ServerLink,
  585. &theNode->SN_ServerLink);
  586. }
  587. }
  588. else {
  589. HeapFree (ServerTable.ST_Heap, 0, theNode);
  590. status = ERROR_GEN_FAILURE;
  591. }
  592. ReleaseAllLocks ();
  593. }
  594. else {
  595. HeapFree (ServerTable.ST_Heap, 0, theNode);
  596. status = ERROR_GEN_FAILURE;
  597. }
  598. }
  599. else
  600. status = ERROR_NOT_ENOUGH_MEMORY;
  601. }
  602. else if (serverLink!=NULL) {
  603. // If is better than one of ours
  604. if (AcquireAllLocks ()) {
  605. if ((intfLink!=NULL)
  606. || ((intfLink=FindIntfLink (InterfaceIndex))!=NULL)) {
  607. // Replace the worst one (at the end of server list)
  608. theNode = CONTAINING_RECORD (
  609. mainNode->SN_ServerLink.Blink,
  610. SERVER_NODE,
  611. SN_ServerLink);
  612. VALIDATE_SERVER_NODE(theNode);
  613. IpxServerCpy (&theNode->SN_Server, Server);
  614. IpxNodeCpy (theNode->SN_AdvertisingNode, AdvertisingNode);
  615. theNode->SN_InterfaceIndex = InterfaceIndex;
  616. ResetDisabledNode (theNode);
  617. if (theNode->SN_Protocol!=Protocol) {
  618. if (Protocol==IPX_PROTOCOL_STATIC)
  619. ServerTable.ST_StaticServerCnt += 1;
  620. else if (theNode->SN_Protocol==IPX_PROTOCOL_STATIC)
  621. ServerTable.ST_StaticServerCnt -= 1;
  622. theNode->SN_Protocol = Protocol;
  623. }
  624. if (intfLink!=&theNode->N_Links[SDB_INTF_LIST_LINK]) {
  625. RemoveEntryList (&theNode->N_Links[SDB_INTF_LIST_LINK]);
  626. InsertTailList (intfLink,
  627. &theNode->N_Links[SDB_INTF_LIST_LINK]);
  628. }
  629. if (theNode==mainNode) {
  630. if (IsEnumerator (CONTAINING_RECORD (
  631. ServerTable.ST_ChangedSvrsQueue.PL_Head.Flink,
  632. SERVER_NODE,
  633. N_Links[SDB_CHANGE_QUEUE_LINK])))
  634. ExpireLRRequests ((PVOID)UlongToPtr(InterfaceIndex));
  635. // It's already the best, just move it to the
  636. // bottom of change queue
  637. RemoveEntryList (&theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  638. InsertHeadList (&ServerTable.ST_ChangedSvrsQueue.PL_Head,
  639. &theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  640. }
  641. else if ((theNode->SN_HopCount < mainNode->SN_HopCount)
  642. || IsDisabledNode (mainNode))
  643. // It replaces the best one
  644. ChangeMainNode (mainNode, theNode, serverLink);
  645. else if (serverLink!=&theNode->SN_ServerLink) {
  646. // It just gets in the middle
  647. RemoveEntryList (&theNode->SN_ServerLink);
  648. InsertTailList (serverLink, &theNode->SN_ServerLink);
  649. }
  650. }
  651. else
  652. status = ERROR_GEN_FAILURE;
  653. ReleaseAllLocks ();
  654. }
  655. else
  656. status = ERROR_GEN_FAILURE;
  657. }
  658. }
  659. }
  660. // Update position in expiration queue
  661. if ((status==NO_ERROR)
  662. && (theNode!=NULL)
  663. && (Server->HopCount!=IPX_MAX_HOP_COUNT) // theNode could not have
  664. ){ // been deleted or setup for deletion
  665. // Update flags
  666. theNode->N_NodeFlags = (theNode->N_NodeFlags & (~(SDB_DISABLED_NODE_FLAG|SDB_DONT_RESPOND_NODE_FLAG)))
  667. | (Flags & (SDB_DISABLED_NODE_FLAG|SDB_DONT_RESPOND_NODE_FLAG));
  668. if (AcquireServerTableList (&ServerTable.ST_ExpirationQueue, TRUE)) {
  669. if (IsListEntry (&theNode->SN_TimerLink))
  670. RemoveEntryList (&theNode->SN_TimerLink);
  671. if (TimeToLive!=INFINITE) {
  672. ASSERTMSG ("Invalid value of time to live ",
  673. TimeToLive*1000<MAXULONG/2);
  674. theNode->SN_ExpirationTime =
  675. GetTickCount()+TimeToLive*1000;
  676. RoundUpToSec (theNode->SN_ExpirationTime);
  677. // Scan expiration queue from the end (to minimize
  678. // the number of nodes we have to look through)
  679. cur = ServerTable.ST_ExpirationQueue.PL_Head.Blink;
  680. while (cur!=&ServerTable.ST_ExpirationQueue.PL_Head) {
  681. if (IsLater(theNode->SN_ExpirationTime,
  682. CONTAINING_RECORD (
  683. cur,
  684. SERVER_NODE,
  685. SN_TimerLink)->SN_ExpirationTime))
  686. break;
  687. cur = cur->Blink;
  688. }
  689. InsertHeadList (cur, &theNode->SN_TimerLink);
  690. if (cur==&ServerTable.ST_ExpirationQueue.PL_Head) {
  691. // Signal timer if server is in the beginning
  692. // of the list (we need to get a shot
  693. // earlier than we previously requested)
  694. LONGLONG timeout = (LONGLONG)TimeToLive*(1000*(-10000));
  695. BOOL res = SetWaitableTimer (
  696. ServerTable.ST_ExpirationTimer,
  697. (PLARGE_INTEGER)&timeout,
  698. 0, // no period
  699. NULL, NULL, // no completion
  700. FALSE); // no need to resume
  701. ASSERTERRMSG ("Could not set expiraton timer ", res);
  702. }
  703. }
  704. else {
  705. InitializeListEntry (&theNode->SN_TimerLink);
  706. }
  707. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  708. }
  709. else
  710. status = ERROR_GEN_FAILURE;
  711. }
  712. ReleaseServerTableList (&HashList->HL_List);
  713. return status;
  714. }
  715. /*++
  716. *******************************************************************
  717. C r e a t e N o d e
  718. Routine Description:
  719. Allocate and initialize new server entry
  720. Arguments:
  721. Server - server parameters (as it comes from IPX packet)
  722. InterfaceIndex - interface through which knowledge of server was obtained
  723. Protocol - protocol used to obtain server info
  724. AdvertisingNode - node from which this server info was received
  725. HashList - hash list to which this server belongs
  726. Return Value:
  727. Allocated and initialized entry
  728. NULL if allocation failed
  729. *******************************************************************
  730. --*/
  731. PSERVER_NODE
  732. CreateNode (
  733. IN PIPX_SERVER_ENTRY_P Server,
  734. IN ULONG InterfaceIndex,
  735. IN DWORD Protocol,
  736. IN PUCHAR AdvertisingNode,
  737. IN PSDB_HASH_LIST HashList
  738. ) {
  739. PSERVER_NODE theNode;
  740. theNode = (PSERVER_NODE)HeapAlloc (ServerTable.ST_Heap, 0, sizeof (SERVER_NODE));
  741. if (theNode==NULL) {
  742. Trace (DEBUG_FAILURES,
  743. "File: %s, line: %ld. Can't allocate server node (gle:%ld).",
  744. __FILE__, __LINE__, GetLastError ());
  745. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  746. return NULL;
  747. }
  748. theNode->N_NodeFlags = SDB_SERVER_NODE;
  749. theNode->SN_HashList = HashList;
  750. theNode->SN_InterfaceIndex = InterfaceIndex;
  751. theNode->SN_Protocol = Protocol;
  752. theNode->SN_ObjectID = SDB_INVALID_OBJECT_ID;
  753. IpxNodeCpy (theNode->SN_AdvertisingNode, AdvertisingNode);
  754. theNode->SN_Signature = SDB_SERVER_NODE_SIGNATURE;
  755. IpxServerCpy (&theNode->SN_Server, Server);
  756. InitializeListEntry (&theNode->N_Links[SDB_HASH_TABLE_LINK]);
  757. InitializeListEntry (&theNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  758. InitializeListEntry (&theNode->N_Links[SDB_INTF_LIST_LINK]);
  759. InitializeListEntry (&theNode->N_Links[SDB_TYPE_LIST_LINK]);
  760. InitializeListEntry (&theNode->N_Links[SDB_SORTED_LIST_LINK]);
  761. InitializeListEntry (&theNode->SN_ServerLink);
  762. InitializeListEntry (&theNode->SN_TimerLink);
  763. return theNode;
  764. }
  765. /*++
  766. *******************************************************************
  767. C h a n g e M a i n N o d e
  768. Routine Description:
  769. Replace best entry for server (moves new best entry to the
  770. top of the server list, replaces old entry in hash, type,
  771. and sorted lists. Adds new entry to interface list if it
  772. is not already there
  773. All lists used for enumeration should be locked when calling this routine
  774. Arguments:
  775. oldNode - Current best entry
  776. newNode - Node that will become the best
  777. serverLink - Where oldNode has to go in server list:
  778. if newNode not in the list or
  779. serverLink==&oldNode->SN_ServerLink, oldNode
  780. gets pushed down by newNode
  781. if serverLink==NULL, oldNode goes to the end of list
  782. otherwise it goes before serverLink
  783. Return Value:
  784. NO_ERROR - server was added/updated ok
  785. other - reason of failure (windows error code)
  786. *******************************************************************
  787. --*/
  788. VOID
  789. ChangeMainNode (
  790. IN PSERVER_NODE oldNode,
  791. IN PSERVER_NODE newNode,
  792. IN PLIST_ENTRY serverLink
  793. ) {
  794. ASSERTMSG ("Node is already main ", !IsMainNode (newNode));
  795. SetMainNode (newNode);
  796. ASSERTMSG ("Node being reset is not main ", IsMainNode (oldNode));
  797. ResetMainNode (oldNode);
  798. if (oldNode->SN_ObjectID!=SDB_INVALID_OBJECT_ID) {
  799. newNode->SN_ObjectID = oldNode->SN_ObjectID;
  800. oldNode->SN_ObjectID = SDB_INVALID_OBJECT_ID;
  801. }
  802. InsertTailList (&oldNode->N_Links[SDB_HASH_TABLE_LINK],
  803. &newNode->N_Links[SDB_HASH_TABLE_LINK]);
  804. RemoveEntryList (&oldNode->N_Links[SDB_HASH_TABLE_LINK]);
  805. InitializeListEntry (&oldNode->N_Links[SDB_HASH_TABLE_LINK]);
  806. RemoveEntryList (&oldNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  807. InitializeListEntry (&oldNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  808. if (IsEnumerator (CONTAINING_RECORD (
  809. ServerTable.ST_ChangedSvrsQueue.PL_Head.Flink,
  810. SERVER_NODE,
  811. N_Links[SDB_CHANGE_QUEUE_LINK])))
  812. ExpireLRRequests ((PVOID)UlongToPtr(newNode->SN_InterfaceIndex));
  813. InsertHeadList (&ServerTable.ST_ChangedSvrsQueue.PL_Head,
  814. &newNode->N_Links[SDB_CHANGE_QUEUE_LINK]);
  815. InsertTailList (&oldNode->N_Links[SDB_TYPE_LIST_LINK],
  816. &newNode->N_Links[SDB_TYPE_LIST_LINK]);
  817. RemoveEntryList (&oldNode->N_Links[SDB_TYPE_LIST_LINK]);
  818. InitializeListEntry (&oldNode->N_Links[SDB_TYPE_LIST_LINK]);
  819. if (!IsListEntry (&newNode->SN_ServerLink)) {
  820. InsertTailList (&oldNode->SN_ServerLink, &newNode->SN_ServerLink);
  821. }
  822. else if (serverLink==&oldNode->SN_ServerLink) {
  823. RemoveEntryList (&newNode->SN_ServerLink);
  824. InsertTailList (&oldNode->SN_ServerLink, &newNode->SN_ServerLink);
  825. }
  826. else if (serverLink!=NULL) {
  827. RemoveEntryList (&oldNode->SN_ServerLink);
  828. InsertHeadList (serverLink, &oldNode->SN_ServerLink);
  829. }
  830. if (oldNode->SN_HopCount==IPX_MAX_HOP_COUNT) {
  831. DeleteNode (oldNode);
  832. }
  833. serverLink = FindSortedLink (newNode->SN_Server.Type,
  834. newNode->SN_Server.Name);
  835. if (!IsListEntry (&newNode->N_Links[SDB_SORTED_LIST_LINK])) {
  836. InsertTailList (serverLink, &newNode->N_Links[SDB_SORTED_LIST_LINK]);
  837. ServerTable.ST_TMPListCnt += 1;
  838. if (ServerTable.ST_TMPListCnt == SDBMaxUnsortedServers)
  839. UpdateSortedList ();
  840. }
  841. }
  842. /*++
  843. *******************************************************************
  844. A c q u i r e A l l L o c k s
  845. Routine Description:
  846. Acquire locks for all lists that are updated immediately
  847. when server is added/deleted/updated
  848. Arguments:
  849. None
  850. Return Value:
  851. NO_ERROR - server was added/updated ok
  852. other - reason of failure (windows error code)
  853. *******************************************************************
  854. --*/
  855. BOOL
  856. AcquireAllLocks (
  857. void
  858. ) {
  859. if (AcquireServerTableList (&ServerTable.ST_ChangedSvrsQueue, TRUE)) {
  860. if (AcquireServerTableList (&ServerTable.ST_IntfList, TRUE)) {
  861. if (AcquireServerTableList (&ServerTable.ST_TypeList, TRUE)) {
  862. if (AcquireServerTableList (&ServerTable.ST_SortedListTMP, TRUE))
  863. return TRUE;
  864. ReleaseServerTableList (&ServerTable.ST_TypeList);
  865. }
  866. ReleaseServerTableList (&ServerTable.ST_IntfList);
  867. }
  868. ReleaseServerTableList (&ServerTable.ST_ChangedSvrsQueue);
  869. }
  870. return FALSE;
  871. }
  872. /*++
  873. *******************************************************************
  874. R e l e a s e A l l L o c k s
  875. Routine Description:
  876. Release locks for all lists that are updated immediately
  877. when server is added/deleted/updated
  878. Arguments:
  879. None
  880. Return value:
  881. None
  882. *******************************************************************
  883. --*/
  884. VOID
  885. ReleaseAllLocks (
  886. void
  887. ) {
  888. ReleaseServerTableList (&ServerTable.ST_SortedListTMP);
  889. ReleaseServerTableList (&ServerTable.ST_TypeList);
  890. ReleaseServerTableList (&ServerTable.ST_IntfList);
  891. ReleaseServerTableList (&ServerTable.ST_ChangedSvrsQueue);
  892. }
  893. /*++
  894. *******************************************************************
  895. D e l e t e M a i n N o d e
  896. Routine Description:
  897. Delete entry that was best (it still remains in the table for
  898. a while until all interested get a chance to learn this
  899. All lists used for enumeration should be locked when calling this routine
  900. Arguments:
  901. node - entry to delete
  902. Return Value:
  903. None
  904. *******************************************************************
  905. --*/
  906. VOID
  907. DeleteMainNode (
  908. IN PSERVER_NODE node
  909. ) {
  910. RemoveEntryList (&node->N_Links[SDB_HASH_TABLE_LINK]);
  911. InitializeListEntry (&node->N_Links[SDB_HASH_TABLE_LINK]);
  912. RemoveEntryList (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  913. InitializeListEntry (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  914. RemoveEntryList (&node->N_Links[SDB_INTF_LIST_LINK]);
  915. InitializeListEntry (&node->N_Links[SDB_INTF_LIST_LINK]);
  916. RemoveEntryList (&node->N_Links[SDB_TYPE_LIST_LINK]);
  917. InitializeListEntry (&node->N_Links[SDB_TYPE_LIST_LINK]);
  918. ServerTable.ST_ServerCnt -= 1;
  919. if (node->SN_Protocol==IPX_PROTOCOL_STATIC)
  920. ServerTable.ST_StaticServerCnt -= 1;
  921. if (ServerTable.ST_LastEnumerator==NULL) {
  922. ASSERTMSG ("Node being reset is not main ", IsMainNode (node));
  923. ResetMainNode (node);
  924. // We won't try to get access to sorted list because it is
  925. // slow, the entry will be actually removed from it
  926. // and disposed of when the sorted list is updated
  927. if (AcquireServerTableList (&ServerTable.ST_DeletedList, TRUE)) {
  928. InsertTailList (&ServerTable.ST_DeletedList.PL_Head,
  929. &node->SN_ServerLink);
  930. ServerTable.ST_DeletedListCnt += 1;
  931. if (ServerTable.ST_DeletedListCnt==SDBMaxUnsortedServers)
  932. UpdateSortedList ();
  933. ReleaseServerTableList (&ServerTable.ST_DeletedList);
  934. }
  935. // If we fail in locking we just let it hang around
  936. // (at least we won't risk damaging the list)
  937. }
  938. else {
  939. // If there are enumerators in change queue, we can't
  940. // delete the node until they see it
  941. if (IsEnumerator (CONTAINING_RECORD (
  942. ServerTable.ST_ChangedSvrsQueue.PL_Head.Flink,
  943. SERVER_NODE,
  944. N_Links[SDB_CHANGE_QUEUE_LINK])))
  945. ExpireLRRequests ((PVOID)UlongToPtr(node->SN_InterfaceIndex));
  946. InsertHeadList (&ServerTable.ST_ChangedSvrsQueue.PL_Head,
  947. &node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  948. }
  949. }
  950. /*++
  951. *******************************************************************
  952. D e l e t e N o d e
  953. Routine Description:
  954. Delete entry that was not the best
  955. All lists used for enumeration should be locked when calling this routine
  956. Arguments:
  957. node - entry to delete
  958. Return Value:
  959. None
  960. *******************************************************************
  961. --*/
  962. VOID
  963. DeleteNode (
  964. IN PSERVER_NODE node
  965. ) {
  966. RemoveEntryList (&node->N_Links[SDB_INTF_LIST_LINK]);
  967. InitializeListEntry (&node->N_Links[SDB_INTF_LIST_LINK]);
  968. RemoveEntryList (&node->SN_ServerLink);
  969. if (node->SN_Protocol==IPX_PROTOCOL_STATIC)
  970. ServerTable.ST_StaticServerCnt -= 1;
  971. if (AcquireServerTableList (&ServerTable.ST_DeletedList, TRUE)) {
  972. // We won't try to get access to sorted list because it is
  973. // slow, the entry will be actually removed from it
  974. // and disposed of when the sorted list is updated
  975. InsertTailList (&ServerTable.ST_DeletedList.PL_Head,
  976. &node->SN_ServerLink);
  977. ServerTable.ST_DeletedListCnt += 1;
  978. if (ServerTable.ST_DeletedListCnt==SDBMaxUnsortedServers)
  979. UpdateSortedList ();
  980. ReleaseServerTableList (&ServerTable.ST_DeletedList);
  981. }
  982. else {
  983. // If we fail in locking we just let it hang around
  984. // (at least we won't risk damaging the list)
  985. InitializeListEntry (&node->SN_ServerLink);
  986. }
  987. }
  988. /*++
  989. *******************************************************************
  990. D o U p d a t e S o r t e d L i s t
  991. Routine Description:
  992. Deletes entries placed in deleted list and merges temporary and
  993. permanent sorted lists.
  994. This routine may take some time to execute because it may need to scan
  995. the whole sorted list that contains all entries in the table
  996. Arguments:
  997. None
  998. Return Value:
  999. None
  1000. *******************************************************************
  1001. --*/
  1002. VOID
  1003. DoUpdateSortedList (
  1004. void
  1005. ) {
  1006. PLIST_ENTRY cur;
  1007. ULONG curCount;
  1008. LIST_ENTRY tempHead;
  1009. // We first lock the 'slow' list
  1010. if (!AcquireServerTableList (&ServerTable.ST_SortedListPRM, TRUE))
  1011. // Failure to acquire sorted list,
  1012. // tell them to retry in a little while
  1013. return ;
  1014. // The following two list are locked for a short period:
  1015. // we'll just delete what needs to be deleted (no searching)
  1016. // and copy and reset temp sorted list
  1017. if (!AcquireServerTableList (&ServerTable.ST_ExpirationQueue, TRUE)) {
  1018. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  1019. // Failure to acquire expiration queue,
  1020. // tell them to retry in a little while
  1021. return ;
  1022. }
  1023. if (!AcquireServerTableList (&ServerTable.ST_SortedListTMP, TRUE)) {
  1024. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  1025. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  1026. // Failure to acquire sorted list,
  1027. // tell them to retry in a little while
  1028. return ;
  1029. }
  1030. if (!AcquireServerTableList (&ServerTable.ST_DeletedList, TRUE)) {
  1031. ReleaseServerTableList (&ServerTable.ST_SortedListTMP);
  1032. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  1033. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  1034. // Failure to acquire deleted list,
  1035. // tell them to retry in a little while
  1036. return ;
  1037. }
  1038. // Delete what we have to delete
  1039. cur = ServerTable.ST_DeletedList.PL_Head.Flink;
  1040. while (cur != &ServerTable.ST_DeletedList.PL_Head) {
  1041. PSERVER_NODE node = CONTAINING_RECORD (cur,
  1042. SERVER_NODE,
  1043. SN_ServerLink);
  1044. VALIDATE_SERVER_NODE(node);
  1045. cur = cur->Flink;
  1046. RemoveEntryList (&node->SN_ServerLink);
  1047. if (IsListEntry (&node->N_Links[SDB_SORTED_LIST_LINK])) {
  1048. RemoveEntryList (&node->N_Links[SDB_SORTED_LIST_LINK]);
  1049. }
  1050. if (IsListEntry (&node->SN_TimerLink)) {
  1051. RemoveEntryList (&node->SN_TimerLink);
  1052. }
  1053. ASSERTMSG ("Deleted entry is still in hash list ",
  1054. !IsListEntry (&node->N_Links[SDB_HASH_TABLE_LINK]));
  1055. ASSERTMSG ("Deleted entry is still in change queue ",
  1056. !IsListEntry (&node->N_Links[SDB_CHANGE_QUEUE_LINK]));
  1057. ASSERTMSG ("Deleted entry is still in interface list ",
  1058. !IsListEntry (&node->N_Links[SDB_INTF_LIST_LINK]));
  1059. ASSERTMSG ("Deleted entry is still in type list ",
  1060. !IsListEntry (&node->N_Links[SDB_TYPE_LIST_LINK]));
  1061. HeapFree (ServerTable.ST_Heap, 0, node);
  1062. }
  1063. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  1064. ServerTable.ST_DeletedListCnt = 0;
  1065. ReleaseServerTableList (&ServerTable.ST_DeletedList);
  1066. // Now, just copy the head of the temp list,
  1067. // so we won't delay others while processing it
  1068. if (!IsListEmpty (&ServerTable.ST_SortedListTMP.PL_Head)) {
  1069. InsertTailList (&ServerTable.ST_SortedListTMP.PL_Head, &tempHead);
  1070. RemoveEntryList (&ServerTable.ST_SortedListTMP.PL_Head);
  1071. InitializeListHead (&ServerTable.ST_SortedListTMP.PL_Head);
  1072. }
  1073. else
  1074. InitializeListHead (&tempHead);
  1075. ServerTable.ST_TMPListCnt = 0; // We are going to remove all of them,
  1076. ReleaseServerTableList (&ServerTable.ST_SortedListTMP);
  1077. // Now we start the merge
  1078. cur = ServerTable.ST_SortedListPRM.PL_Head.Flink;
  1079. while (!IsListEmpty (&tempHead)) {
  1080. PSERVER_NODE prmNode = NULL;
  1081. PSERVER_NODE tmpNode;
  1082. tmpNode = CONTAINING_RECORD (tempHead.Flink,
  1083. SERVER_NODE,
  1084. N_Links[SDB_SORTED_LIST_LINK]);
  1085. VALIDATE_SERVER_NODE(tmpNode);
  1086. while (cur!=&ServerTable.ST_SortedListPRM.PL_Head) {
  1087. PSERVER_NODE node = CONTAINING_RECORD (cur,
  1088. SERVER_NODE,
  1089. N_Links[SDB_SORTED_LIST_LINK]);
  1090. VALIDATE_NODE(node);
  1091. if (!IsEnumerator (node)) {
  1092. if (tmpNode->SN_Server.Type==node->SN_Server.Type) {
  1093. INT res = IpxNameCmp (tmpNode->SN_Server.Name,
  1094. node->SN_Server.Name);
  1095. if (res==0) {
  1096. cur = cur->Flink;
  1097. prmNode = node;
  1098. break;
  1099. }
  1100. else if (res<0)
  1101. break;
  1102. }
  1103. else if (tmpNode->SN_Server.Type<node->SN_Server.Type)
  1104. break;
  1105. }
  1106. cur = cur->Flink;
  1107. }
  1108. if (AcquireServerTableList (&tmpNode->SN_HashList->HL_List, TRUE)) {
  1109. if (AcquireServerTableList (&ServerTable.ST_SortedListTMP, TRUE)) {
  1110. RemoveEntryList (&tmpNode->N_Links[SDB_SORTED_LIST_LINK]);
  1111. if (IsMainNode (tmpNode)) {
  1112. ASSERTMSG ("Node marked as sorted in temp list ",
  1113. !IsSortedNode (tmpNode));
  1114. SetSortedNode (tmpNode);
  1115. InsertTailList (cur, &tmpNode->N_Links[SDB_SORTED_LIST_LINK]);
  1116. if (prmNode!=NULL) {
  1117. ASSERTMSG ("Node not marked as sorted in sorted list ",
  1118. IsSortedNode (prmNode));
  1119. RemoveEntryList (&prmNode->N_Links[SDB_SORTED_LIST_LINK]);
  1120. InitializeListEntry (&prmNode->N_Links[SDB_SORTED_LIST_LINK]);
  1121. ResetSortedNode (prmNode);
  1122. }
  1123. }
  1124. else {
  1125. InitializeListEntry (&tmpNode->N_Links[SDB_SORTED_LIST_LINK]);
  1126. }
  1127. ReleaseServerTableList (&ServerTable.ST_SortedListTMP);
  1128. }
  1129. else
  1130. Sleep (SAP_ERROR_COOL_OFF_TIME);
  1131. ReleaseServerTableList (&tmpNode->SN_HashList->HL_List);
  1132. }
  1133. else
  1134. Sleep (SAP_ERROR_COOL_OFF_TIME);
  1135. }
  1136. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  1137. }
  1138. VOID APIENTRY
  1139. UpdateSortedListWorker (
  1140. PVOID context
  1141. ) {
  1142. do {
  1143. InterlockedExchange (&ServerTable.ST_UpdatePending, 0);
  1144. DoUpdateSortedList ();
  1145. }
  1146. while (InterlockedDecrement (&ServerTable.ST_UpdatePending)>=0);
  1147. }
  1148. /*++
  1149. *******************************************************************
  1150. U p d a t e S o r t e d L i s t
  1151. Routine Description:
  1152. Schedules work item to update sorted list.
  1153. Should be called whenever UpdateObject is signalled
  1154. Arguments:
  1155. None
  1156. Return Value:
  1157. None
  1158. *******************************************************************
  1159. --*/
  1160. VOID
  1161. UpdateSortedList (
  1162. void
  1163. ) {
  1164. BOOL res;
  1165. LONGLONG timeout=(LONGLONG)SDBSortLatency*(-10000);
  1166. static WORKERFUNCTION worker=&UpdateSortedListWorker;
  1167. res = SetWaitableTimer (ServerTable.ST_UpdateTimer,
  1168. (PLARGE_INTEGER)&timeout,
  1169. 0, // no period
  1170. NULL, NULL, // no completion
  1171. FALSE); // no need to resume
  1172. ASSERTMSG ("Could not set update timer ", res);
  1173. if (InterlockedIncrement (&ServerTable.ST_UpdatePending)==0)
  1174. ScheduleWorkItem (&worker);
  1175. }
  1176. /*++
  1177. *******************************************************************
  1178. P r o c e s s E x p i r a t i o n Q u e u e
  1179. Routine Description:
  1180. Deletes expired servers from the table and set timer object to
  1181. be signalled when next item in expiration queue is due
  1182. Arguments:
  1183. None
  1184. Return Value:
  1185. None
  1186. *******************************************************************
  1187. --*/
  1188. VOID
  1189. ProcessExpirationQueue (
  1190. void
  1191. ) {
  1192. ULONG curTime = GetTickCount ();
  1193. ULONG dueTime = curTime + MAXULONG/2;
  1194. LONGLONG timeout;
  1195. BOOL res;
  1196. if (!AcquireServerTableList (&ServerTable.ST_ExpirationQueue, TRUE))
  1197. return ;
  1198. while (!IsListEmpty (&ServerTable.ST_ExpirationQueue.PL_Head)) {
  1199. PSDB_HASH_LIST HashList;
  1200. PSERVER_NODE node = CONTAINING_RECORD (
  1201. ServerTable.ST_ExpirationQueue.PL_Head.Flink,
  1202. SERVER_NODE,
  1203. SN_TimerLink);
  1204. VALIDATE_SERVER_NODE(node);
  1205. if (IsLater(node->SN_ExpirationTime,curTime)) {
  1206. dueTime = node->SN_ExpirationTime;
  1207. break;
  1208. }
  1209. HashList = node->SN_HashList;
  1210. // Try to get access to hash list but do not wait because
  1211. // we may create a deadlock
  1212. if (!AcquireServerTableList (&HashList->HL_List, FALSE)) {
  1213. // Hash list is locked, we'll have to release the timer queue
  1214. // and reacquire it again after securing the hash list
  1215. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  1216. if (AcquireServerTableList (&HashList->HL_List, TRUE)) {
  1217. if (AcquireServerTableList (&ServerTable.ST_ExpirationQueue, TRUE)) {
  1218. // Make sure entry is still there
  1219. if (ServerTable.ST_ExpirationQueue.PL_Head.Flink
  1220. !=&node->SN_TimerLink) {
  1221. // Gone already, go to the next one
  1222. ReleaseServerTableList (&HashList->HL_List);
  1223. continue;
  1224. }
  1225. }
  1226. else {
  1227. // Failure to regain expiration queue,
  1228. // tell them to retry in a little while
  1229. ReleaseServerTableList (&HashList->HL_List);
  1230. return ;
  1231. }
  1232. }
  1233. else
  1234. // Failure to acquire hash list,
  1235. // tell them to retry in a little while
  1236. return ;
  1237. }
  1238. // At this point we have hash list and expiration queue locks
  1239. // we can proceed with deletion
  1240. RemoveEntryList (&node->SN_TimerLink);
  1241. InitializeListEntry (&node->SN_TimerLink);
  1242. if (node->SN_HopCount!=IPX_MAX_HOP_COUNT) {
  1243. // It might have been already prepeared for deletion
  1244. if (AcquireAllLocks ()) { // Need to have all locks before changing
  1245. // node info
  1246. node->SN_HopCount = IPX_MAX_HOP_COUNT;
  1247. if (IsMainNode (node)) {
  1248. if (IsListEmpty (&node->SN_ServerLink))
  1249. DeleteMainNode (node);
  1250. else
  1251. ChangeMainNode (
  1252. node,
  1253. CONTAINING_RECORD (
  1254. node->SN_ServerLink.Flink,
  1255. SERVER_NODE,
  1256. SN_ServerLink),
  1257. NULL);
  1258. }
  1259. else
  1260. DeleteNode (node);
  1261. ReleaseAllLocks ();
  1262. }
  1263. }
  1264. ReleaseServerTableList (&HashList->HL_List);
  1265. }
  1266. ReleaseServerTableList (&ServerTable.ST_ExpirationQueue);
  1267. timeout = (LONGLONG)(dueTime-curTime)*(-10000);
  1268. res = SetWaitableTimer (ServerTable.ST_ExpirationTimer,
  1269. (PLARGE_INTEGER)&timeout,
  1270. 0, // no period
  1271. NULL, NULL, // no completion
  1272. FALSE); // no need to resume
  1273. ASSERTMSG ("Could not set expiration timer ", res);
  1274. }
  1275. /*++
  1276. *******************************************************************
  1277. Q u e r y S e r v e r
  1278. Routine Description:
  1279. Checks if server with given type and name exists in the table
  1280. Returns TRUE if it does and fills out requested server info
  1281. with data of the best entry for the server
  1282. Arguments:
  1283. Type - server type
  1284. Name - server name
  1285. Server - buffer in which to put server info
  1286. InterfaceIndex - buffer in which to put server interface index
  1287. Protocol - buffer in which to put server protocol
  1288. ObjectID - buffer in which to put server object id (number that uniquely
  1289. identifies server (the whole set of entries, not just the best
  1290. one) in the table; it is valid for very long but FINITE period
  1291. of time)
  1292. Return Value:
  1293. TRUE - server was found
  1294. FALSE - server was not found or operation failed (call GetLastError()
  1295. to find out the reason for failure if any)
  1296. *******************************************************************
  1297. --*/
  1298. BOOL
  1299. QueryServer (
  1300. IN USHORT Type,
  1301. IN PUCHAR Name,
  1302. OUT PIPX_SERVER_ENTRY_P Server OPTIONAL,
  1303. OUT PULONG InterfaceIndex OPTIONAL,
  1304. OUT PULONG Protocol OPTIONAL,
  1305. OUT PULONG ObjectID OPTIONAL
  1306. ) {
  1307. PSDB_HASH_LIST HashList;
  1308. PLIST_ENTRY cur;
  1309. PSERVER_NODE theNode = NULL;
  1310. INT res;
  1311. if (Name[0]==0) {
  1312. Trace (DEBUG_SERVERDB, "Illigal server name in QueryServer.");
  1313. SetLastError (ERROR_INVALID_PARAMETER);
  1314. return FALSE;
  1315. }
  1316. HashList = &ServerTable.ST_HashLists[HashFunction (Name)];
  1317. if (!AcquireServerTableList (&HashList->HL_List, TRUE)) {
  1318. SetLastError (ERROR_GEN_FAILURE);
  1319. return FALSE;
  1320. }
  1321. cur = HashList->HL_List.PL_Head.Flink;
  1322. while (cur!=&HashList->HL_List.PL_Head) {
  1323. PSERVER_NODE node = CONTAINING_RECORD (cur,
  1324. SERVER_NODE,
  1325. N_Links[SDB_HASH_TABLE_LINK]);
  1326. VALIDATE_NODE(node);
  1327. if (!IsEnumerator (node) && !IsDisabledNode (node)
  1328. && (node->SN_Server.HopCount < IPX_MAX_HOP_COUNT)) {
  1329. if (Type == node->SN_Server.Type) {
  1330. res = IpxNameCmp (Name, node->SN_Server.Name);
  1331. if (res==0) {
  1332. theNode = node;
  1333. break;
  1334. }
  1335. else if (res<0)
  1336. break;
  1337. }
  1338. else if (Type<node->SN_Server.Type)
  1339. break;
  1340. }
  1341. cur = cur->Flink;
  1342. }
  1343. if (theNode!=NULL) {
  1344. if (ARGUMENT_PRESENT (Server))
  1345. IpxServerCpy (Server, &theNode->SN_Server);
  1346. if (ARGUMENT_PRESENT (InterfaceIndex))
  1347. *InterfaceIndex = theNode->SN_InterfaceIndex;
  1348. if (ARGUMENT_PRESENT (Protocol))
  1349. *Protocol = theNode->SN_Protocol;
  1350. if (ARGUMENT_PRESENT (ObjectID)) {
  1351. if (theNode->SN_ObjectID==SDB_INVALID_OBJECT_ID)
  1352. theNode->SN_ObjectID = GenerateUniqueID (theNode->SN_HashList);
  1353. *ObjectID = theNode->SN_ObjectID;
  1354. }
  1355. res = TRUE;
  1356. }
  1357. else {
  1358. SetLastError (NO_ERROR);
  1359. res = FALSE;
  1360. }
  1361. ReleaseServerTableList (&HashList->HL_List);
  1362. return res==TRUE;
  1363. }
  1364. /*++
  1365. *******************************************************************
  1366. G e t S e r v e r F r o m I D
  1367. Routine Description:
  1368. Returns info for server with specified ID
  1369. Arguments:
  1370. ObjectID - server object id (number that uniquely
  1371. identifies server in the table, it is valid for very long
  1372. but FINITE amount of time)
  1373. Server - buffer in which to put server info
  1374. InterfaceIndex - buffer in which to put server interface index
  1375. Protocol - buffer in which to put server protocol
  1376. Return Value:
  1377. TRUE - server was found
  1378. FALSE - server was not found or operation failed (call GetLastError()
  1379. to find out the reason for failure if any)
  1380. *******************************************************************
  1381. --*/
  1382. BOOL
  1383. GetServerFromID (
  1384. IN ULONG ObjectID,
  1385. OUT PIPX_SERVER_ENTRY_P Server OPTIONAL,
  1386. OUT PULONG InterfaceIndex OPTIONAL,
  1387. OUT PULONG Protocol OPTIONAL
  1388. ) {
  1389. PSDB_HASH_LIST HashList;
  1390. PLIST_ENTRY cur;
  1391. PSERVER_NODE theNode = NULL;
  1392. INT res;
  1393. HashList = &ServerTable.ST_HashLists[ObjectID%SDB_NAME_HASH_SIZE];
  1394. if (!AcquireServerTableList (&HashList->HL_List, TRUE)) {
  1395. SetLastError (ERROR_GEN_FAILURE);
  1396. return FALSE;
  1397. }
  1398. cur = HashList->HL_List.PL_Head.Flink;
  1399. while (cur!=&HashList->HL_List.PL_Head) {
  1400. PSERVER_NODE node = CONTAINING_RECORD (cur,
  1401. SERVER_NODE,
  1402. N_Links[SDB_HASH_TABLE_LINK]);
  1403. VALIDATE_NODE(node);
  1404. if (!IsEnumerator (node) && !IsDisabledNode (node)
  1405. && (node->SN_HopCount < IPX_MAX_HOP_COUNT)
  1406. && (node->SN_ObjectID == ObjectID)) {
  1407. theNode = node;
  1408. break;
  1409. }
  1410. cur = cur->Flink;
  1411. }
  1412. if (theNode!=NULL) {
  1413. if (ARGUMENT_PRESENT (Server))
  1414. IpxServerCpy (Server, &theNode->SN_Server);
  1415. if (ARGUMENT_PRESENT (InterfaceIndex))
  1416. *InterfaceIndex = theNode->SN_InterfaceIndex;
  1417. if (ARGUMENT_PRESENT (Protocol))
  1418. *Protocol = theNode->SN_Protocol;
  1419. res = TRUE;
  1420. }
  1421. else {
  1422. SetLastError (NO_ERROR);
  1423. res = FALSE;
  1424. }
  1425. ReleaseServerTableList (&HashList->HL_List);
  1426. return res==TRUE;
  1427. }
  1428. /*++
  1429. *******************************************************************
  1430. C r e a t e L i s t E n u m e r a t o r
  1431. Routine Description:
  1432. Creates enumerator node that allows scanning through the server
  1433. table lists
  1434. Arguments:
  1435. ListIdx - index of list through which to scan (currently supported lists
  1436. are: hash lists, interface lists, type lists,
  1437. changed servers queue
  1438. Type - limits enumeration to servers of specific type and
  1439. indentifies a particular type list if index is SDB_TYPE_LIST_IDX
  1440. (use 0xFFFF to return all server and/or to go through all
  1441. type lists)
  1442. Name - limits enumeration to servers with certain name if present
  1443. InterfaceIndex - limits enumeration to servers of specific interface and
  1444. indentifies a particular interface list if index
  1445. is SDB_INTF_LIST_IDX (use INVALID_INTERFACE_INDEX to return all
  1446. server and/or to go through all interface lists)
  1447. Protocol - limits enumeration to servers of certain protocol (0xFFFFFFFF
  1448. - all protocols)
  1449. Flags - identifies additional conditions on entries enumerated:
  1450. SDB_MAIN_NODE_FLAG - only best servers
  1451. SDB_DISABLED_NODE_FLAG - include disabled servers
  1452. Return Value:
  1453. Handle that represents the enumeration node
  1454. NULL if specified list does not exist or operation failed
  1455. (call GetLastError () for the reason of failure if any)
  1456. *******************************************************************
  1457. --*/
  1458. HANDLE
  1459. CreateListEnumerator (
  1460. IN INT ListIdx,
  1461. IN USHORT Type,
  1462. IN PUCHAR Name OPTIONAL,
  1463. IN ULONG InterfaceIndex,
  1464. IN ULONG Protocol,
  1465. IN INT Flags
  1466. ) {
  1467. HANDLE hEnum;
  1468. #define enumNode ((PENUMERATOR_NODE)hEnum)
  1469. hEnum = (HANDLE)GlobalAlloc (GPTR, sizeof (ENUMERATOR_NODE));
  1470. if (hEnum==NULL) {
  1471. Trace (DEBUG_FAILURES,
  1472. "File: %s, line: %ld. Can't allocate enumerator node (gle:%ld).",
  1473. __FILE__, __LINE__, GetLastError ());
  1474. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  1475. return NULL;
  1476. }
  1477. InitializeListEntry (&enumNode->N_Links[ListIdx]);
  1478. enumNode->N_NodeFlags = SDB_ENUMERATION_NODE;
  1479. enumNode->EN_LinkIdx = ListIdx;
  1480. enumNode->EN_InterfaceIndex = InterfaceIndex;
  1481. enumNode->EN_Protocol = Protocol;
  1482. enumNode->EN_Signature = SDB_ENUMERATOR_NODE_SIGNATURE;
  1483. enumNode->EN_Type = Type;
  1484. if (ARGUMENT_PRESENT(Name)) {
  1485. if (Name[0]!=0) {
  1486. enumNode->EN_ListLock = &ServerTable.ST_HashLists[HashFunction(Name)].HL_List;
  1487. IpxNameCpy (enumNode->EN_Name, Name);
  1488. }
  1489. else {
  1490. Trace (DEBUG_SERVERDB, "Illigal server name in CreateListEnumerator.");
  1491. GlobalFree (enumNode);
  1492. SetLastError (ERROR_INVALID_PARAMETER);
  1493. return NULL;
  1494. }
  1495. }
  1496. else
  1497. enumNode->EN_Name[0] = 0;
  1498. enumNode->EN_Flags = Flags;
  1499. switch (ListIdx) {
  1500. case SDB_HASH_TABLE_LINK:
  1501. if (enumNode->EN_Name[0]==0)
  1502. enumNode->EN_ListLock = &ServerTable.ST_HashLists[0].HL_List;
  1503. break;
  1504. case SDB_CHANGE_QUEUE_LINK:
  1505. enumNode->EN_ListLock = &ServerTable.ST_ChangedSvrsQueue;
  1506. break;
  1507. case SDB_INTF_LIST_LINK:
  1508. enumNode->EN_ListLock = &ServerTable.ST_IntfList;
  1509. break;
  1510. case SDB_TYPE_LIST_LINK:
  1511. enumNode->EN_ListLock = &ServerTable.ST_TypeList;
  1512. break;
  1513. default:
  1514. ASSERTMSG ("Invalid list index. ", FALSE);
  1515. GlobalFree (hEnum);
  1516. SetLastError (ERROR_INVALID_PARAMETER);
  1517. return NULL;
  1518. }
  1519. if (!AcquireServerTableList (enumNode->EN_ListLock, TRUE)) {
  1520. GlobalFree (hEnum);
  1521. SetLastError (ERROR_GEN_FAILURE);
  1522. return NULL;
  1523. }
  1524. // All enumeration go in the direction opposite to
  1525. // direction of insertion to exclude the possibility of
  1526. // returning the same server twice (this may happen if
  1527. // server entry gets deleted and another one is inserted in
  1528. // the same place while client processes the result of
  1529. // enumeration callback
  1530. switch (ListIdx) {
  1531. case SDB_HASH_TABLE_LINK:
  1532. enumNode->EN_ListHead = &enumNode->EN_ListLock->PL_Head;
  1533. // Insert in the tail of the list -> we go backwards
  1534. InsertTailList (enumNode->EN_ListHead,
  1535. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1536. break;
  1537. case SDB_CHANGE_QUEUE_LINK:
  1538. enumNode->EN_ListHead = &ServerTable.ST_ChangedSvrsQueue.PL_Head;
  1539. // Insert in the head, because we want client to see only
  1540. // the newly changed servers that will be inserted in the
  1541. // bottom (head) of the list
  1542. InsertHeadList (enumNode->EN_ListHead,
  1543. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1544. // Increment number of enumerating clients (we remove deleted
  1545. // server entries from the change queue once all enumerating clients
  1546. // get a chance to see it)
  1547. if (ServerTable.ST_LastEnumerator==NULL)
  1548. ServerTable.ST_LastEnumerator = hEnum;
  1549. break;
  1550. case SDB_INTF_LIST_LINK:
  1551. if (enumNode->EN_InterfaceIndex==INVALID_INTERFACE_INDEX) {
  1552. if (!IsListEmpty (&ServerTable.ST_IntfList.PL_Head)) {
  1553. PINTF_NODE intfNode = CONTAINING_RECORD (
  1554. ServerTable.ST_IntfList.PL_Head.Flink,
  1555. INTF_NODE,
  1556. IN_Link);
  1557. enumNode->EN_ListHead = &intfNode->IN_Head;
  1558. // Insert in the tail of the list -> we go backwards
  1559. InsertTailList (enumNode->EN_ListHead,
  1560. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1561. break;
  1562. }
  1563. // No interface lists - fall through to error handling
  1564. }
  1565. else {
  1566. enumNode->EN_ListHead = FindIntfLink (InterfaceIndex);
  1567. if (enumNode->EN_ListHead!=NULL) {
  1568. // Insert in the tail of the list -> we go backwards
  1569. InsertTailList (enumNode->EN_ListHead,
  1570. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1571. break;
  1572. }
  1573. // Interface list could not be found -
  1574. // fall through to error handling
  1575. }
  1576. GlobalFree (hEnum);
  1577. SetLastError (NO_ERROR);
  1578. hEnum = NULL;
  1579. break;
  1580. case SDB_TYPE_LIST_LINK:
  1581. if (enumNode->EN_Type==0xFFFF) {
  1582. if (!IsListEmpty (&ServerTable.ST_TypeList.PL_Head)) {
  1583. PTYPE_NODE typeNode = CONTAINING_RECORD (
  1584. ServerTable.ST_TypeList.PL_Head.Flink,
  1585. TYPE_NODE,
  1586. TN_Link);
  1587. enumNode->EN_ListHead = &typeNode->TN_Head;
  1588. // Insert in the tail of the list -> we go backwards
  1589. InsertTailList (enumNode->EN_ListHead,
  1590. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1591. break;
  1592. }
  1593. // No type lists - fall through to error handling
  1594. }
  1595. else {
  1596. enumNode->EN_ListHead = FindTypeLink (Type);
  1597. if (enumNode->EN_ListHead!=NULL) {
  1598. // Insert in the tail of the list -> we go backwards
  1599. InsertTailList (enumNode->EN_ListHead,
  1600. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1601. break;
  1602. }
  1603. // Type list could not be found -
  1604. // fall through to error handling
  1605. }
  1606. GlobalFree (hEnum);
  1607. SetLastError (NO_ERROR);
  1608. hEnum = NULL;
  1609. }
  1610. if (enumNode)
  1611. {
  1612. ReleaseServerTableList (enumNode->EN_ListLock);
  1613. }
  1614. #undef enumNode
  1615. return hEnum;
  1616. }
  1617. /*++
  1618. *******************************************************************
  1619. E n u m e r a t e S e r v e r s
  1620. Routine Description:
  1621. Calls callback routine consequtively for servers in the enumerated
  1622. list until told to stop by the callback or end of list is reached
  1623. Arguments:
  1624. Enumerator - handle obtained from CreateListEnumerator
  1625. CallBackProc - function to call for each server in the list
  1626. CBParam - extra parameter to pass to callback function
  1627. Return Value:
  1628. TRUE - if stopped by the callback
  1629. FALSE - if end of list is reached or operation failed (call GetLastError ()
  1630. to find out the reason of failure)
  1631. *******************************************************************
  1632. --*/
  1633. BOOLEAN
  1634. EnumerateServers (
  1635. IN HANDLE Enumerator,
  1636. IN EnumerateServersCallBack CallBackProc,
  1637. IN LPVOID CBParam
  1638. ) {
  1639. #define enumNode ((PENUMERATOR_NODE)Enumerator)
  1640. BOOL res=FALSE, bNeedHashLock;
  1641. PSERVER_NODE node;
  1642. ULONG releaseTime;
  1643. // The following callbacks need to be invoked with hash table
  1644. // lock held because they modify/delete nodes
  1645. bNeedHashLock = (enumNode->EN_LinkIdx!=SDB_HASH_TABLE_LINK)
  1646. && ((CallBackProc==DeleteAllServersCB)
  1647. || (CallBackProc==DeleteNonLocalServersCB)
  1648. || (CallBackProc==EnableAllServersCB)
  1649. || (CallBackProc==DisableAllServersCB)
  1650. || (CallBackProc==ConvertToStaticCB)
  1651. || (CallBackProc==DeleteAllServersCB));
  1652. VALIDATE_ENUMERATOR_NODE(Enumerator);
  1653. if (!AcquireServerTableList (enumNode->EN_ListLock, TRUE)) {
  1654. SetLastError (ERROR_GEN_FAILURE);
  1655. return FALSE;
  1656. }
  1657. releaseTime = GetTickCount ()+SDB_MAX_LOCK_HOLDING_TIME;
  1658. do { // Loop till told to stop by the callback
  1659. // Don't let client hold the list for too long
  1660. if (IsLater (GetTickCount (),releaseTime)) {
  1661. ReleaseServerTableList (enumNode->EN_ListLock);
  1662. #if DBG
  1663. Trace (DEBUG_SERVERDB,
  1664. "Held enumeration lock (%d list) for %ld extra msec",
  1665. enumNode->EN_LinkIdx, GetTickCount ()-releaseTime);
  1666. #endif
  1667. AcquireServerTableList (enumNode->EN_ListLock, TRUE);
  1668. releaseTime = GetTickCount ()+SDB_MAX_LOCK_HOLDING_TIME;
  1669. }
  1670. // Check if end of the list is reached
  1671. while (enumNode->N_Links[enumNode->EN_LinkIdx].Blink
  1672. ==enumNode->EN_ListHead) {
  1673. // Check if we asked and can go to another list
  1674. switch (enumNode->EN_LinkIdx) {
  1675. case SDB_HASH_TABLE_LINK:
  1676. if ((enumNode->EN_Name[0]==0)
  1677. &&(enumNode->EN_ListHead
  1678. <&ServerTable.ST_HashLists[SDB_NAME_HASH_SIZE-1].HL_List.PL_Head)) {
  1679. RemoveEntryList (
  1680. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1681. ReleaseServerTableList (enumNode->EN_ListLock);
  1682. enumNode->EN_ListLock = &(CONTAINING_RECORD (
  1683. enumNode->EN_ListLock,
  1684. SDB_HASH_LIST,
  1685. HL_List)+1)->HL_List;
  1686. enumNode->EN_ListHead = &enumNode->EN_ListLock->PL_Head;
  1687. if (!AcquireServerTableList (enumNode->EN_ListLock, TRUE)) {
  1688. InitializeListEntry (
  1689. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1690. SetLastError (ERROR_GEN_FAILURE);
  1691. return FALSE;
  1692. }
  1693. releaseTime = GetTickCount ()
  1694. +SDB_MAX_LOCK_HOLDING_TIME;
  1695. InsertTailList (enumNode->EN_ListHead,
  1696. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1697. continue;
  1698. }
  1699. break;
  1700. case SDB_INTF_LIST_LINK:
  1701. if (enumNode->EN_InterfaceIndex
  1702. ==INVALID_INTERFACE_INDEX) {
  1703. PINTF_NODE intfNode = CONTAINING_RECORD (
  1704. enumNode->EN_ListHead,
  1705. INTF_NODE,
  1706. IN_Head);
  1707. if (intfNode->IN_Link.Flink
  1708. !=&ServerTable.ST_IntfList.PL_Head) {
  1709. enumNode->EN_ListHead = &(CONTAINING_RECORD (
  1710. intfNode->IN_Link.Flink,
  1711. INTF_NODE,
  1712. IN_Link)->IN_Head);
  1713. RemoveEntryList (
  1714. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1715. InsertTailList (enumNode->EN_ListHead,
  1716. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1717. continue;
  1718. }
  1719. }
  1720. break;
  1721. case SDB_TYPE_LIST_LINK:
  1722. if (enumNode->EN_Type == 0xFFFF) {
  1723. PTYPE_NODE typeNode = CONTAINING_RECORD (
  1724. enumNode->EN_ListHead,
  1725. TYPE_NODE,
  1726. TN_Head);
  1727. if (typeNode->TN_Link.Flink
  1728. !=&ServerTable.ST_TypeList.PL_Head) {
  1729. enumNode->EN_ListHead = &(CONTAINING_RECORD (
  1730. typeNode->TN_Link.Flink,
  1731. TYPE_NODE,
  1732. TN_Link)->TN_Head);
  1733. RemoveEntryList (
  1734. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1735. InsertTailList (enumNode->EN_ListHead,
  1736. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1737. continue;
  1738. }
  1739. }
  1740. break;
  1741. case SDB_CHANGE_QUEUE_LINK:
  1742. break;
  1743. default:
  1744. ASSERTMSG ("Unsupported list index ", FALSE);
  1745. }
  1746. // No more lists or not asked to check all of them
  1747. ReleaseServerTableList (enumNode->EN_ListLock);
  1748. SetLastError (NO_ERROR);
  1749. return FALSE;
  1750. }
  1751. node = CONTAINING_RECORD (enumNode->N_Links[enumNode->EN_LinkIdx].Blink,
  1752. SERVER_NODE,
  1753. N_Links[enumNode->EN_LinkIdx]);
  1754. VALIDATE_NODE(node);
  1755. RemoveEntryList (&enumNode->N_Links[enumNode->EN_LinkIdx]);
  1756. InsertTailList (&node->N_Links[enumNode->EN_LinkIdx],
  1757. &enumNode->N_Links[enumNode->EN_LinkIdx]);
  1758. if (!IsEnumerator(node)
  1759. && ((enumNode->EN_Flags & SDB_DISABLED_NODE_FLAG) || !IsDisabledNode (node))
  1760. && (!(enumNode->EN_Flags & SDB_MAIN_NODE_FLAG) || IsMainNode (node))
  1761. && ((enumNode->EN_InterfaceIndex==INVALID_INTERFACE_INDEX)
  1762. || (enumNode->EN_InterfaceIndex==node->SN_InterfaceIndex))
  1763. && ((enumNode->EN_Type==0xFFFF)
  1764. || (enumNode->EN_Type==node->SN_Type))
  1765. && ((enumNode->EN_Protocol==0xFFFFFFFF)
  1766. || (enumNode->EN_Protocol==node->SN_Protocol))
  1767. && ((enumNode->EN_Name[0]==0)
  1768. || (IpxNameCmp(enumNode->EN_Name, node->SN_Name)!=0))
  1769. ) {
  1770. PSDB_HASH_LIST HashList;
  1771. if (bNeedHashLock) {
  1772. HashList = node->SN_HashList;
  1773. // Release the non-hash table lock to prevent deadlock
  1774. ReleaseServerTableList (enumNode->EN_ListLock);
  1775. if (!AcquireServerTableList (&HashList->HL_List, TRUE)) {
  1776. SetLastError (ERROR_GEN_FAILURE);
  1777. return FALSE;
  1778. }
  1779. // Make sure the node was not deleted when we were
  1780. // acquiring hash lock
  1781. if (enumNode->N_Links[enumNode->EN_LinkIdx].Flink
  1782. !=&node->N_Links[enumNode->EN_LinkIdx]) {
  1783. // Node is gone, continue with the next one
  1784. ReleaseServerTableList (&HashList->HL_List);
  1785. if (AcquireServerTableList (enumNode->EN_ListLock, TRUE))
  1786. continue;
  1787. else {
  1788. SetLastError (ERROR_GEN_FAILURE);
  1789. return FALSE;
  1790. }
  1791. }
  1792. }
  1793. // Check if we need to go through server list
  1794. if (!(enumNode->EN_Flags & SDB_MAIN_NODE_FLAG)
  1795. && !IsListEmpty (&node->SN_ServerLink)
  1796. && (enumNode->EN_LinkIdx!=SDB_INTF_LIST_LINK)
  1797. // Interface lists contain all entries anyway
  1798. ) {
  1799. PLIST_ENTRY cur;
  1800. BOOL bMainNode;
  1801. cur = node->SN_ServerLink.Blink;
  1802. do {
  1803. PSERVER_NODE node1 = CONTAINING_RECORD (cur,
  1804. SERVER_NODE,
  1805. SN_ServerLink);
  1806. VALIDATE_SERVER_NODE(node1);
  1807. bMainNode = IsMainNode (node1); // It may be deleted in
  1808. // callback
  1809. cur = cur->Blink;
  1810. if (CallBackProc!=NULL) {
  1811. res = (*CallBackProc) (CBParam,
  1812. &node1->SN_Server,
  1813. node1->SN_InterfaceIndex,
  1814. node1->SN_Protocol,
  1815. node1->SN_AdvertisingNode,
  1816. node1->N_NodeFlags
  1817. );
  1818. }
  1819. }
  1820. while (res==FALSE && !bMainNode);
  1821. }
  1822. // Call them with just best entry
  1823. else if (CallBackProc!=NULL) {
  1824. res = (*CallBackProc) (CBParam,
  1825. &node->SN_Server,
  1826. node->SN_InterfaceIndex,
  1827. node->SN_Protocol,
  1828. node->SN_AdvertisingNode,
  1829. node->N_NodeFlags
  1830. );
  1831. }
  1832. if (res==-1) {
  1833. if (bNeedHashLock)
  1834. ReleaseServerTableList (&HashList->HL_List);
  1835. else
  1836. ReleaseServerTableList (enumNode->EN_ListLock);
  1837. SetLastError (ERROR_GEN_FAILURE);
  1838. return FALSE;
  1839. }
  1840. else if (bNeedHashLock) {
  1841. ReleaseServerTableList (&HashList->HL_List);
  1842. if (!AcquireServerTableList (enumNode->EN_ListLock, TRUE)) {
  1843. SetLastError (ERROR_GEN_FAILURE);
  1844. return FALSE;
  1845. }
  1846. }
  1847. }
  1848. // If enumerating through the change queue, this might be
  1849. // the last who needs to know about deleted server entry,
  1850. // so it will have to actually initiate deletion
  1851. if ((Enumerator==ServerTable.ST_LastEnumerator)
  1852. // make sure the node is still there
  1853. && (enumNode->N_Links[SDB_CHANGE_QUEUE_LINK].Flink
  1854. == &node->N_Links[SDB_CHANGE_QUEUE_LINK])) {
  1855. if (IsEnumerator(node))
  1856. ServerTable.ST_LastEnumerator = (HANDLE)node;
  1857. else if (node->SN_HopCount==IPX_MAX_HOP_COUNT) {
  1858. ASSERTMSG ("Node being reset is not main ", IsMainNode (node));
  1859. ResetMainNode (node);
  1860. RemoveEntryList (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  1861. InitializeListEntry (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  1862. ASSERTMSG ("Deleted node in change queue has subnodes ",
  1863. !IsListEntry (&node->SN_ServerLink));
  1864. if (AcquireServerTableList (&ServerTable.ST_DeletedList, TRUE)) {
  1865. InsertTailList (&ServerTable.ST_DeletedList.PL_Head,
  1866. &node->SN_ServerLink);
  1867. ServerTable.ST_DeletedListCnt += 1;
  1868. if (ServerTable.ST_DeletedListCnt==SDBMaxUnsortedServers)
  1869. UpdateSortedList ();
  1870. ReleaseServerTableList (&ServerTable.ST_DeletedList);
  1871. }
  1872. // If we fail in locking we just let it hang around
  1873. // (at least we won't risk damaging the list)
  1874. }
  1875. }
  1876. }
  1877. while (!res);
  1878. ASSERT (res==TRUE);
  1879. ReleaseServerTableList (enumNode->EN_ListLock);
  1880. return TRUE;
  1881. #undef enumNode
  1882. }
  1883. /*++
  1884. *******************************************************************
  1885. G e t O n e C B
  1886. Routine Description:
  1887. Callback proc for EnumerateServers.
  1888. Copies the first entry with which it is called and stops enumeration
  1889. by returning TRUE
  1890. Arguments:
  1891. CBParam - pointer to buffer to which to copy service info
  1892. Server, InterfaceIndex, Protocol, AdvertisingNode - service data
  1893. Flags - ignored
  1894. Return Value:
  1895. TRUE
  1896. *******************************************************************
  1897. --*/
  1898. BOOL
  1899. GetOneCB (
  1900. IN LPVOID CBParam,
  1901. IN OUT PIPX_SERVER_ENTRY_P Server,
  1902. IN ULONG InterfaceIndex,
  1903. IN ULONG Protocol,
  1904. IN PUCHAR AdvertisingNode,
  1905. IN INT Flags
  1906. ) {
  1907. #define Service ((PIPX_SERVICE)CBParam)
  1908. IpxServerCpy (&Service->Server, Server);
  1909. Service->InterfaceIndex = InterfaceIndex;
  1910. Service->Protocol = Protocol;
  1911. return TRUE;
  1912. #undef Service
  1913. }
  1914. /*++
  1915. *******************************************************************
  1916. D e l e t e A l l S e r v e r s C B
  1917. Routine Description:
  1918. Callback proc for EnumerateServers that deletes all server
  1919. entries with which it is called
  1920. Arguments:
  1921. CBParam - enumeration handle that identifies enumeration
  1922. Server - pointer to server data inside server node from which node
  1923. itself is computed
  1924. Return Value:
  1925. FALSE - deletion succeded, continue
  1926. TRUE - failure to lock SDB list, stop enumeration and return FALSE
  1927. to client (error code is set in this routine)
  1928. *******************************************************************
  1929. --*/
  1930. BOOL
  1931. DeleteAllServersCB (
  1932. IN LPVOID CBParam,
  1933. IN PIPX_SERVER_ENTRY_P Server,
  1934. IN ULONG InterfaceIndex,
  1935. IN ULONG Protocol,
  1936. IN PUCHAR AdvertisingNode,
  1937. IN INT Flags
  1938. ) {
  1939. PSERVER_NODE node = CONTAINING_RECORD (Server, SERVER_NODE, SN_Server);
  1940. if (AcquireAllLocks ()) {
  1941. node->SN_HopCount = IPX_MAX_HOP_COUNT;
  1942. if (IsMainNode (node)) {
  1943. if (IsListEmpty (&node->SN_ServerLink))
  1944. DeleteMainNode (node);
  1945. else
  1946. ChangeMainNode (
  1947. node,
  1948. CONTAINING_RECORD (
  1949. node->SN_ServerLink.Flink,
  1950. SERVER_NODE,
  1951. SN_ServerLink),
  1952. NULL);
  1953. }
  1954. else
  1955. DeleteNode (node);
  1956. ReleaseAllLocks ();
  1957. return FALSE;
  1958. }
  1959. else {
  1960. return -1;
  1961. }
  1962. }
  1963. BOOL
  1964. DeleteNonLocalServersCB (
  1965. IN LPVOID CBParam,
  1966. IN PIPX_SERVER_ENTRY_P Server,
  1967. IN ULONG InterfaceIndex,
  1968. IN ULONG Protocol,
  1969. IN PUCHAR AdvertisingNode,
  1970. IN INT Flags
  1971. ) {
  1972. if (InterfaceIndex!=INTERNAL_INTERFACE_INDEX)
  1973. return DeleteAllServersCB (CBParam, Server, InterfaceIndex, Protocol,
  1974. AdvertisingNode, Flags);
  1975. else
  1976. return FALSE;
  1977. }
  1978. /*++
  1979. *******************************************************************
  1980. E n a b l e A l l S e r v e r s C B
  1981. Routine Description:
  1982. Callback proc for EnumerateServers that reenables all server
  1983. entries with which it is called
  1984. Arguments:
  1985. CBParam - enumeration handle that identifies enumeration
  1986. Server - pointer to server data inside server node from which node
  1987. itself is computed
  1988. Return Value:
  1989. FALSE - deletion succeded, continue
  1990. TRUE - failure to lock SDB list, stop enumeration and return FALSE
  1991. to client (error code is set in this routine)
  1992. *******************************************************************
  1993. --*/
  1994. BOOL
  1995. EnableAllServersCB (
  1996. IN LPVOID CBParam,
  1997. IN PIPX_SERVER_ENTRY_P Server,
  1998. IN ULONG InterfaceIndex,
  1999. IN ULONG Protocol,
  2000. IN PUCHAR AdvertisingNode,
  2001. IN INT Flags
  2002. ) {
  2003. PSERVER_NODE node = CONTAINING_RECORD (Server, SERVER_NODE, SN_Server);
  2004. if (AcquireAllLocks ()) {
  2005. if (IsDisabledNode (node)) {
  2006. ResetDisabledNode (node);
  2007. if (!IsMainNode (node)) {
  2008. PSERVER_NODE node1 = node;
  2009. do {
  2010. node1 = CONTAINING_RECORD (
  2011. node1->SN_ServerLink.Blink,
  2012. SERVER_NODE,
  2013. SN_ServerLink);
  2014. }
  2015. while (!IsMainNode (node1)
  2016. && (IsDisabledNode(node1)
  2017. || (node1->SN_HopCount>node->SN_HopCount)));
  2018. if (IsMainNode (node1) && (node1->SN_HopCount>node->SN_HopCount))
  2019. ChangeMainNode (node1, node, NULL);
  2020. else {
  2021. RemoveEntryList (&node->SN_ServerLink);
  2022. InsertHeadList (&node1->SN_ServerLink, &node->SN_ServerLink);
  2023. }
  2024. }
  2025. }
  2026. ReleaseAllLocks ();
  2027. return FALSE;
  2028. }
  2029. else {
  2030. return -1;
  2031. }
  2032. }
  2033. /*++
  2034. *******************************************************************
  2035. D i s a b l e A l l S e r v e r s C B
  2036. Routine Description:
  2037. Callback proc for EnumerateServers that disables all server
  2038. entries with which it is called
  2039. Arguments:
  2040. CBParam - enumeration handle that identifies enumeration
  2041. Server - pointer to server data inside server node from which node
  2042. itself is computed
  2043. Return Value:
  2044. FALSE - deletion succeded, continue
  2045. TRUE - failure to lock SDB list, stop enumeration and return FALSE
  2046. to client (error code is set in this routine)
  2047. *******************************************************************
  2048. --*/
  2049. BOOL
  2050. DisableAllServersCB (
  2051. IN LPVOID CBParam,
  2052. IN PIPX_SERVER_ENTRY_P Server,
  2053. IN ULONG InterfaceIndex,
  2054. IN ULONG Protocol,
  2055. IN PUCHAR AdvertisingNode,
  2056. IN INT Flags
  2057. ) {
  2058. PSERVER_NODE node = CONTAINING_RECORD (Server, SERVER_NODE, SN_Server);
  2059. if (AcquireAllLocks ()) {
  2060. if (!IsDisabledNode (node)) {
  2061. SetDisabledNode (node);
  2062. if (IsMainNode (node)) {
  2063. if (!IsListEmpty (&node->SN_ServerLink)) {
  2064. ChangeMainNode (
  2065. node,
  2066. CONTAINING_RECORD (
  2067. node->SN_ServerLink.Flink,
  2068. SERVER_NODE,
  2069. SN_ServerLink),
  2070. NULL);
  2071. }
  2072. }
  2073. else {
  2074. PSERVER_NODE node1 = node;
  2075. do {
  2076. node1 = CONTAINING_RECORD (
  2077. node1->SN_ServerLink.Blink,
  2078. SERVER_NODE,
  2079. SN_ServerLink);
  2080. }
  2081. while (!IsMainNode (node1)
  2082. && !IsDisabledNode(node1));
  2083. RemoveEntryList (&node->SN_ServerLink);
  2084. InsertTailList (&node1->SN_ServerLink, &node->SN_ServerLink);
  2085. }
  2086. }
  2087. ReleaseAllLocks ();
  2088. }
  2089. else {
  2090. return -1;
  2091. }
  2092. return NO_ERROR;
  2093. }
  2094. /*++
  2095. *******************************************************************
  2096. C o n v e r t T o S t a t i c C B
  2097. Routine Description:
  2098. Callback proc for EnumerateServers that converts all server
  2099. entries with which it is called to static (changes protocol field to
  2100. static)
  2101. Arguments:
  2102. CBParam - enumeration handle that identifies enumeration
  2103. Server - pointer to server data inside server node from which node
  2104. itself is computed
  2105. Return Value:
  2106. FALSE
  2107. *******************************************************************
  2108. --*/
  2109. BOOL
  2110. ConvertToStaticCB (
  2111. IN LPVOID CBParam,
  2112. IN PIPX_SERVER_ENTRY_P Server,
  2113. IN ULONG InterfaceIndex,
  2114. IN ULONG Protocol,
  2115. IN PUCHAR AdvertisingNode,
  2116. IN INT Flags
  2117. ) {
  2118. #define enumNode ((PENUMERATOR_NODE)CBParam)
  2119. PSERVER_NODE node = CONTAINING_RECORD (Server, SERVER_NODE, SN_Server);
  2120. node->SN_Protocol = IPX_PROTOCOL_STATIC;
  2121. IpxNodeCpy (node->SN_AdvertisingNode, IPX_BCAST_NODE);
  2122. #undef enumNode
  2123. return FALSE;
  2124. }
  2125. /*++
  2126. *******************************************************************
  2127. D e l e t e L i s t E n u m e r a t o r
  2128. Routine Description:
  2129. Releases resources associated with list enumerator (this includes
  2130. server entries that are queued to change queue before being deleted)
  2131. Arguments:
  2132. Enumerator - handle obtained from CreateListEnumerator
  2133. Return Value:
  2134. None
  2135. *******************************************************************
  2136. --*/
  2137. void
  2138. DeleteListEnumerator (
  2139. IN HANDLE Enumerator
  2140. ) {
  2141. #define enumNode ((PENUMERATOR_NODE)Enumerator)
  2142. if (!AcquireServerTableList (enumNode->EN_ListLock, TRUE))
  2143. return;
  2144. VALIDATE_ENUMERATOR_NODE(Enumerator);
  2145. if (Enumerator==ServerTable.ST_LastEnumerator) {
  2146. // Release all servers marked for deletion
  2147. PLIST_ENTRY cur = enumNode->N_Links[enumNode->EN_LinkIdx].Blink;
  2148. // Reset to note that there are no enumerators and
  2149. // nodes have to be deleted rigth away.
  2150. ServerTable.ST_LastEnumerator = NULL;
  2151. while (cur!=enumNode->EN_ListHead) {
  2152. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2153. SERVER_NODE,
  2154. N_Links[enumNode->EN_LinkIdx]);
  2155. VALIDATE_NODE(node);
  2156. cur = cur->Blink;
  2157. if (IsEnumerator (node)) {
  2158. ServerTable.ST_LastEnumerator = (HANDLE)node;
  2159. break;
  2160. }
  2161. else if (node->SN_HopCount==IPX_MAX_HOP_COUNT) {
  2162. ASSERTMSG ("Node being reset is not main ", IsMainNode (node));
  2163. ResetMainNode (node);
  2164. RemoveEntryList (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  2165. InitializeListEntry (&node->N_Links[SDB_CHANGE_QUEUE_LINK]);
  2166. ASSERTMSG ("Deleted node in change queue has subnodes ",
  2167. !IsListEntry (&node->SN_ServerLink));
  2168. if (AcquireServerTableList (&ServerTable.ST_DeletedList, TRUE)) {
  2169. InsertTailList (&ServerTable.ST_DeletedList.PL_Head,
  2170. &node->SN_ServerLink);
  2171. ServerTable.ST_DeletedListCnt += 1;
  2172. if (ServerTable.ST_DeletedListCnt==SDBMaxUnsortedServers)
  2173. UpdateSortedList ();
  2174. ReleaseServerTableList (&ServerTable.ST_DeletedList);
  2175. }
  2176. // If we fail in locking we just let it hang around
  2177. // (at least we won't risk damaging the list)
  2178. }
  2179. }
  2180. }
  2181. RemoveEntryList (&enumNode->N_Links[enumNode->EN_LinkIdx]);
  2182. if ((enumNode->EN_LinkIdx==SDB_INTF_LIST_LINK)
  2183. && IsListEmpty (enumNode->EN_ListHead)) {
  2184. PINTF_NODE intfNode = CONTAINING_RECORD (
  2185. enumNode->EN_ListHead,
  2186. INTF_NODE,
  2187. IN_Head);
  2188. RemoveEntryList (&intfNode->IN_Link);
  2189. GlobalFree (intfNode);
  2190. }
  2191. ReleaseServerTableList (enumNode->EN_ListLock);
  2192. GlobalFree (Enumerator);
  2193. #undef enumNode
  2194. }
  2195. /*++
  2196. *******************************************************************
  2197. G e t F i r s t S e r v e r
  2198. Routine Description:
  2199. Find and return first service in the order specified by the ordering method.
  2200. Search is limited only to certain types of services as specified by the
  2201. exclusion flags end corresponding fields in Server parameter.
  2202. Returns ERROR_NO_MORE_ITEMS if there are no services in the
  2203. table that meet specified criteria.
  2204. Arguments:
  2205. OrderingMethod - which ordering to consider in determining what is
  2206. the first server
  2207. ExclusionFlags - flags to limit search to certain servers according
  2208. to specified criteria
  2209. Server - On input: criteria for exclusion flags
  2210. On output: first service entry in the specified order
  2211. Return Value:
  2212. NO_ERROR - server was found that meets specified criteria
  2213. ERROR_NO_MORE_ITEMS - no server exist with specified criteria
  2214. other - operation failed (windows error code)
  2215. *******************************************************************
  2216. --*/
  2217. DWORD
  2218. GetFirstServer (
  2219. IN DWORD OrderingMethod,
  2220. IN DWORD ExclusionFlags,
  2221. IN OUT PIPX_SERVER_ENTRY_P Server,
  2222. IN OUT ULONG *InterfaceIndex,
  2223. IN OUT ULONG *Protocol
  2224. ) {
  2225. DWORD status=NO_ERROR;
  2226. PSDB_HASH_LIST HashList;
  2227. PPROTECTED_LIST list;
  2228. INT link;
  2229. PLIST_ENTRY cur;
  2230. switch (OrderingMethod) {
  2231. case STM_ORDER_BY_TYPE_AND_NAME:
  2232. break;
  2233. case STM_ORDER_BY_INTERFACE_TYPE_NAME:
  2234. if (!(ExclusionFlags & STM_ONLY_THIS_INTERFACE)) {
  2235. if (!AcquireServerTableList (&ServerTable.ST_IntfList, TRUE))
  2236. return ERROR_GEN_FAILURE;
  2237. if (IsListEmpty (&ServerTable.ST_IntfList.PL_Head)) {
  2238. ReleaseServerTableList (&ServerTable.ST_IntfList);
  2239. return ERROR_NO_MORE_ITEMS;
  2240. }
  2241. *InterfaceIndex = CONTAINING_RECORD (
  2242. ServerTable.ST_IntfList.PL_Head.Flink,
  2243. INTF_NODE,
  2244. IN_Link)->IN_InterfaceIndex;
  2245. ReleaseServerTableList (&ServerTable.ST_IntfList);
  2246. }
  2247. break;
  2248. default:
  2249. ASSERTMSG ("Invalid ordering method specified ", FALSE);
  2250. return ERROR_INVALID_PARAMETER;
  2251. }
  2252. if (ExclusionFlags & STM_ONLY_THIS_NAME) {
  2253. HashList = &ServerTable.ST_HashLists[HashFunction (Server->Name)];
  2254. if (!AcquireServerTableList (&HashList->HL_List, TRUE))
  2255. return ERROR_GEN_FAILURE;
  2256. list = &HashList->HL_List;
  2257. link = SDB_HASH_TABLE_LINK;
  2258. }
  2259. else {
  2260. if (ServerTable.ST_UpdatePending==-1)
  2261. DoUpdateSortedList ();
  2262. if (!AcquireServerTableList (&ServerTable.ST_SortedListPRM, TRUE))
  2263. return ERROR_GEN_FAILURE;
  2264. list = &ServerTable.ST_SortedListPRM;
  2265. link = SDB_SORTED_LIST_LINK;
  2266. }
  2267. cur = list->PL_Head.Flink;
  2268. while (TRUE) {
  2269. // We may need to loop through interface lists
  2270. status = DoFindNextNode (cur,
  2271. list,
  2272. link,
  2273. OrderingMethod==STM_ORDER_BY_INTERFACE_TYPE_NAME
  2274. ? ExclusionFlags|STM_ONLY_THIS_INTERFACE
  2275. : ExclusionFlags,
  2276. Server,
  2277. InterfaceIndex,
  2278. Protocol,
  2279. NULL
  2280. );
  2281. // If looping through all interfaces in interface order and
  2282. // no items are available, we may need to check another interface
  2283. if ((status==ERROR_NO_MORE_ITEMS)
  2284. && (OrderingMethod==STM_ORDER_BY_INTERFACE_TYPE_NAME)
  2285. && !(ExclusionFlags&STM_ONLY_THIS_INTERFACE)) {
  2286. if (!AcquireServerTableList (&ServerTable.ST_IntfList, TRUE)) {
  2287. status = ERROR_GEN_FAILURE;
  2288. break;
  2289. }
  2290. // Get next interface in interface list
  2291. cur = ServerTable.ST_IntfList.PL_Head.Flink;
  2292. while (cur!=&ServerTable.ST_IntfList.PL_Head) {
  2293. PINTF_NODE intfNode = CONTAINING_RECORD (cur,
  2294. INTF_NODE,
  2295. IN_Link);
  2296. if (*InterfaceIndex<intfNode->IN_InterfaceIndex) {
  2297. *InterfaceIndex = intfNode->IN_InterfaceIndex;
  2298. break;
  2299. }
  2300. cur = cur->Flink;
  2301. }
  2302. ReleaseServerTableList (&ServerTable.ST_IntfList);
  2303. if (cur!=&ServerTable.ST_IntfList.PL_Head) {
  2304. // Restart the search with another interface index
  2305. cur = list->PL_Head.Flink;
  2306. continue;
  2307. }
  2308. }
  2309. break;
  2310. }
  2311. if (link==SDB_HASH_TABLE_LINK)
  2312. ReleaseServerTableList (&HashList->HL_List);
  2313. else /* if (link==SDB_SORTED_LIST_LINK) */
  2314. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2315. return status;
  2316. }
  2317. /*++
  2318. *******************************************************************
  2319. G e t N e x t S e r v e r
  2320. Routine Description:
  2321. Find and return next service in the order specified by the ordering method.
  2322. Search starts from specified service and is limited only to certain types
  2323. of services as specified by the exclusion flags and corresponding fields
  2324. in Server parameter.
  2325. Arguments:
  2326. OrderingMethod - which ordering to consider in determining what is
  2327. the first server
  2328. ExclusionFlags - flags to limit search to certain servers according
  2329. to fields of Server
  2330. Server - On input server entry from which to compute the next
  2331. On output: first service entry in the specified order
  2332. Return Value:
  2333. NO_ERROR - server was found that meets specified criteria
  2334. ERROR_NO_MORE_ITEMS - no server exist with specified criteria
  2335. other - operation failed (windows error code)
  2336. *******************************************************************
  2337. --*/
  2338. DWORD
  2339. GetNextServer (
  2340. IN DWORD OrderingMethod,
  2341. IN DWORD ExclusionFlags,
  2342. IN OUT PIPX_SERVER_ENTRY_P Server,
  2343. IN OUT ULONG *InterfaceIndex,
  2344. IN OUT ULONG *Protocol
  2345. ) {
  2346. PLIST_ENTRY cur=NULL;
  2347. PSERVER_NODE theNode=NULL;
  2348. DWORD status=NO_ERROR;
  2349. PSDB_HASH_LIST HashList;
  2350. PPROTECTED_LIST list;
  2351. INT link;
  2352. INT res;
  2353. switch (OrderingMethod) {
  2354. case STM_ORDER_BY_TYPE_AND_NAME:
  2355. break;
  2356. case STM_ORDER_BY_INTERFACE_TYPE_NAME:
  2357. break;
  2358. default:
  2359. ASSERTMSG ("Invalid ordering method specified ", FALSE);
  2360. return ERROR_INVALID_PARAMETER;
  2361. }
  2362. if (!AcquireServerTableList (&ServerTable.ST_SortedListPRM, TRUE))
  2363. return ERROR_GEN_FAILURE;
  2364. if (Server->Name[0]!=0) {
  2365. HashList = &ServerTable.ST_HashLists[HashFunction (Server->Name)];
  2366. if (!AcquireServerTableList (&HashList->HL_List, TRUE)) {
  2367. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2368. return ERROR_GEN_FAILURE;
  2369. }
  2370. cur = HashList->HL_List.PL_Head.Flink;
  2371. while (cur!=&HashList->HL_List.PL_Head) {
  2372. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2373. SERVER_NODE,
  2374. N_Links[SDB_HASH_TABLE_LINK]);
  2375. VALIDATE_NODE(node);
  2376. if (!IsEnumerator(node)
  2377. && (!IsDisabledNode (node)
  2378. || ((ExclusionFlags & STM_ONLY_THIS_PROTOCOL)
  2379. && (*Protocol==IPX_PROTOCOL_STATIC)))
  2380. && (node->SN_Server.HopCount<IPX_MAX_HOP_COUNT)) {
  2381. if (Server->Type == node->SN_Server.Type) {
  2382. res = IpxNameCmp (Server->Name, node->SN_Server.Name);
  2383. if ((res==0) && IsSortedNode (node)) {
  2384. theNode = node;
  2385. }
  2386. else if (res<0)
  2387. break;
  2388. }
  2389. else if (Server->Type<node->SN_Server.Type)
  2390. break;
  2391. }
  2392. cur = cur->Flink;
  2393. }
  2394. if (ExclusionFlags&STM_ONLY_THIS_NAME) {
  2395. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2396. if (theNode!=NULL) {
  2397. list = &HashList->HL_List;
  2398. link = SDB_HASH_TABLE_LINK;
  2399. }
  2400. else {
  2401. ReleaseServerTableList (&HashList->HL_List);
  2402. return ERROR_NO_MORE_ITEMS;
  2403. }
  2404. }
  2405. else {
  2406. ReleaseServerTableList (&HashList->HL_List);
  2407. goto DoHardWay;
  2408. }
  2409. }
  2410. else {
  2411. DoHardWay:
  2412. list = &ServerTable.ST_SortedListPRM;
  2413. link = SDB_SORTED_LIST_LINK;
  2414. if (theNode!=NULL)
  2415. cur = theNode->N_Links[SDB_SORTED_LIST_LINK].Flink;
  2416. else {
  2417. cur = ServerTable.ST_SortedListPRM.PL_Head.Flink;
  2418. while (cur!=&ServerTable.ST_SortedListPRM.PL_Head) {
  2419. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2420. SERVER_NODE,
  2421. N_Links[SDB_SORTED_LIST_LINK]);
  2422. VALIDATE_NODE(node);
  2423. if (!IsEnumerator(node)
  2424. && (!IsDisabledNode (node)
  2425. || ((ExclusionFlags & STM_ONLY_THIS_PROTOCOL)
  2426. && (*Protocol==IPX_PROTOCOL_STATIC)))
  2427. && (node->SN_Server.HopCount<IPX_MAX_HOP_COUNT)) {
  2428. if ((Server->Type<node->SN_Server.Type)
  2429. || ((Server->Type == node->SN_Server.Type)
  2430. && (IpxNameCmp (Server->Name,
  2431. node->SN_Server.Name)<0)))
  2432. break;
  2433. }
  2434. cur = cur->Flink;
  2435. }
  2436. }
  2437. }
  2438. while (TRUE) {
  2439. // We may need to loop through interface lists
  2440. status = DoFindNextNode (cur,
  2441. list,
  2442. link,
  2443. OrderingMethod==STM_ORDER_BY_INTERFACE_TYPE_NAME
  2444. ? ExclusionFlags|STM_ONLY_THIS_INTERFACE
  2445. : ExclusionFlags,
  2446. Server,
  2447. InterfaceIndex,
  2448. Protocol,
  2449. NULL
  2450. );
  2451. // If looping through all interfaces in interface order and
  2452. // no items are available, we may need to check another interface
  2453. if ((status==ERROR_NO_MORE_ITEMS)
  2454. && (OrderingMethod==STM_ORDER_BY_INTERFACE_TYPE_NAME)
  2455. && !(ExclusionFlags&STM_ONLY_THIS_INTERFACE)) {
  2456. if (!AcquireServerTableList (&ServerTable.ST_IntfList, TRUE)) {
  2457. status = ERROR_GEN_FAILURE;
  2458. break;
  2459. }
  2460. // Get next interface in interface list
  2461. cur = ServerTable.ST_IntfList.PL_Head.Flink;
  2462. while (cur!=&ServerTable.ST_IntfList.PL_Head) {
  2463. PINTF_NODE intfNode = CONTAINING_RECORD (cur,
  2464. INTF_NODE,
  2465. IN_Link);
  2466. if (*InterfaceIndex<intfNode->IN_InterfaceIndex) {
  2467. *InterfaceIndex = intfNode->IN_InterfaceIndex;
  2468. break;
  2469. }
  2470. cur = cur->Flink;
  2471. }
  2472. ReleaseServerTableList (&ServerTable.ST_IntfList);
  2473. if (cur!=&ServerTable.ST_IntfList.PL_Head) {
  2474. // Restart the search with another interface index
  2475. cur = list->PL_Head.Flink;
  2476. continue;
  2477. }
  2478. }
  2479. break;
  2480. }
  2481. if (link==SDB_HASH_TABLE_LINK)
  2482. ReleaseServerTableList (&HashList->HL_List);
  2483. else /* if (link==SDB_SORTED_LIST_LINK) */
  2484. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2485. return status;
  2486. }
  2487. /*++
  2488. *******************************************************************
  2489. G e t N e x t S e r v e r F r o m I D
  2490. Routine Description:
  2491. Find and return service that follows server with specified ID
  2492. in the type.name order.
  2493. Arguments:
  2494. ObjectID - on input: id of server form which to start the search
  2495. on output: id of returned server
  2496. Type - if not 0xFFFF, search should be limited to only servers
  2497. of specified type
  2498. Server, Protocol, InterfaceIndex - buffer to put returned server info in
  2499. Return Value:
  2500. TRUE - server was found
  2501. FALSE - search failed
  2502. *******************************************************************
  2503. --*/
  2504. BOOL
  2505. GetNextServerFromID (
  2506. IN OUT PULONG ObjectID,
  2507. IN USHORT Type,
  2508. OUT PIPX_SERVER_ENTRY_P Server,
  2509. OUT PULONG InterfaceIndex OPTIONAL,
  2510. OUT PULONG Protocol OPTIONAL
  2511. ) {
  2512. PSDB_HASH_LIST HashList;
  2513. PLIST_ENTRY cur;
  2514. PSERVER_NODE theNode = NULL;
  2515. DWORD status=NO_ERROR;
  2516. HashList = &ServerTable.ST_HashLists[(*ObjectID)%SDB_NAME_HASH_SIZE];
  2517. if (*ObjectID==SDB_INVALID_OBJECT_ID) {
  2518. if (ServerTable.ST_UpdatePending==-1)
  2519. DoUpdateSortedList ();
  2520. }
  2521. if (!AcquireServerTableList (&ServerTable.ST_SortedListPRM, TRUE))
  2522. return ERROR_GEN_FAILURE;
  2523. if (*ObjectID!=SDB_INVALID_OBJECT_ID) {
  2524. if (!AcquireServerTableList (&HashList->HL_List, TRUE)) {
  2525. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2526. SetLastError (ERROR_GEN_FAILURE);
  2527. return FALSE;
  2528. }
  2529. cur = HashList->HL_List.PL_Head.Flink;
  2530. while (cur!=&HashList->HL_List.PL_Head) {
  2531. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2532. SERVER_NODE,
  2533. N_Links[SDB_HASH_TABLE_LINK]);
  2534. VALIDATE_NODE(node);
  2535. if (!IsEnumerator (node) && !IsDisabledNode (node)
  2536. && (node->SN_HopCount < IPX_MAX_HOP_COUNT)
  2537. && (node->SN_ObjectID == *ObjectID)) {
  2538. theNode = node;
  2539. break;
  2540. }
  2541. cur = cur->Flink;
  2542. }
  2543. ReleaseServerTableList (&HashList->HL_List);
  2544. if (theNode==NULL) {
  2545. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2546. SetLastError (NO_ERROR);
  2547. return FALSE;
  2548. }
  2549. else if (!IsSortedNode (theNode)) {
  2550. cur = ServerTable.ST_SortedListPRM.PL_Head.Flink;
  2551. while (cur!=&ServerTable.ST_SortedListPRM.PL_Head) {
  2552. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2553. SERVER_NODE,
  2554. N_Links[SDB_SORTED_LIST_LINK]);
  2555. VALIDATE_NODE(node);
  2556. if (!IsEnumerator(node) && !IsDisabledNode (node)) {
  2557. if ((theNode->SN_Server.Type<node->SN_Server.Type)
  2558. || ((theNode->SN_Server.Type == node->SN_Server.Type)
  2559. && (IpxNameCmp (theNode->SN_Server.Name,
  2560. node->SN_Server.Name)<0)))
  2561. break;
  2562. }
  2563. cur = cur->Flink;
  2564. }
  2565. }
  2566. else
  2567. cur = theNode->N_Links[SDB_SORTED_LIST_LINK].Flink;
  2568. }
  2569. else
  2570. cur = ServerTable.ST_SortedListPRM.PL_Head.Flink;
  2571. Server->Type = Type;
  2572. status = DoFindNextNode (cur,
  2573. &ServerTable.ST_SortedListPRM,
  2574. SDB_SORTED_LIST_LINK,
  2575. Type==0xFFFF ? 0 : STM_ONLY_THIS_TYPE,
  2576. Server,
  2577. InterfaceIndex,
  2578. Protocol,
  2579. ObjectID
  2580. );
  2581. ReleaseServerTableList (&ServerTable.ST_SortedListPRM);
  2582. return status == NO_ERROR;
  2583. }
  2584. /*++
  2585. *******************************************************************
  2586. D o F i n d N e x t N o d e
  2587. Routine Description:
  2588. Scan through SortedListPRM to find the first entry that matches specified
  2589. cirteria. Permanent sorted list must be locked before calling
  2590. this routine
  2591. Arguments:
  2592. cur - pointer to entry in SortedListPRM from which to start the search
  2593. ExclusionFlags - flags to limit search to certain servers according
  2594. to fields of Server
  2595. Server, InterfaceIndex, Protocol - on input: search criteria
  2596. on output: data of found server
  2597. ObjectID - object ID of returned server
  2598. Return Value:
  2599. NO_ERROR - server was found that matches the criteria
  2600. ERROR_NO_MORE_ITEMS - no server exist that matches criteria
  2601. other - operation failed (windows error code)
  2602. *******************************************************************
  2603. --*/
  2604. DWORD
  2605. DoFindNextNode (
  2606. IN PLIST_ENTRY cur,
  2607. IN PPROTECTED_LIST list,
  2608. IN INT link,
  2609. IN DWORD ExclusionFlags,
  2610. IN OUT PIPX_SERVER_ENTRY_P Server,
  2611. IN OUT PULONG InterfaceIndex OPTIONAL,
  2612. IN OUT PULONG Protocol OPTIONAL,
  2613. OUT PULONG ObjectID OPTIONAL
  2614. ) {
  2615. while (cur!=&list->PL_Head) {
  2616. PSDB_HASH_LIST HashList;
  2617. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2618. SERVER_NODE,
  2619. N_Links[link]);
  2620. VALIDATE_NODE(node);
  2621. if (!IsEnumerator(node)
  2622. && (!IsDisabledNode (node)
  2623. || ((ExclusionFlags & STM_ONLY_THIS_PROTOCOL)
  2624. && (*Protocol==IPX_PROTOCOL_STATIC)))
  2625. && (node->SN_Server.HopCount<IPX_MAX_HOP_COUNT)) {
  2626. if (ExclusionFlags & STM_ONLY_THIS_TYPE) {
  2627. if (Server->Type>node->SN_Type)
  2628. goto DoNextNode;
  2629. else if (Server->Type<node->SN_Type)
  2630. break;
  2631. }
  2632. if (ExclusionFlags & STM_ONLY_THIS_NAME) {
  2633. INT res = IpxNameCmp (Server->Name,node->SN_Name);
  2634. if (res>0)
  2635. goto DoNextNode;
  2636. else if (res<0) {
  2637. if (ExclusionFlags & STM_ONLY_THIS_TYPE)
  2638. break;
  2639. else
  2640. goto DoNextNode;
  2641. }
  2642. }
  2643. HashList = node->SN_HashList;
  2644. if (list!=&HashList->HL_List) {
  2645. if (!AcquireServerTableList (&HashList->HL_List, TRUE))
  2646. return ERROR_GEN_FAILURE;
  2647. }
  2648. do {
  2649. if ((ExclusionFlags &
  2650. STM_ONLY_THIS_PROTOCOL|STM_ONLY_THIS_INTERFACE)
  2651. == (STM_ONLY_THIS_PROTOCOL|STM_ONLY_THIS_INTERFACE)) {
  2652. if ((*Protocol==node->SN_Protocol)
  2653. && (*InterfaceIndex==node->SN_InterfaceIndex))
  2654. break;
  2655. }
  2656. else if (ExclusionFlags & STM_ONLY_THIS_PROTOCOL) {
  2657. if (*Protocol==node->SN_Protocol)
  2658. break;
  2659. }
  2660. else if (ExclusionFlags & STM_ONLY_THIS_INTERFACE) {
  2661. if (*InterfaceIndex!=node->SN_InterfaceIndex)
  2662. break;
  2663. }
  2664. else
  2665. break;
  2666. node = CONTAINING_RECORD (node->SN_ServerLink.Flink,
  2667. SERVER_NODE, SN_ServerLink);
  2668. VALIDATE_SERVER_NODE(node);
  2669. if (cur==&node->N_Links[link]) {
  2670. if (list!=&HashList->HL_List)
  2671. ReleaseServerTableList (&HashList->HL_List);
  2672. goto DoNextNode;
  2673. }
  2674. }
  2675. while (1);
  2676. IpxServerCpy (Server, &node->SN_Server);
  2677. if (ARGUMENT_PRESENT (ObjectID)) {
  2678. if (node->SN_ObjectID==SDB_INVALID_OBJECT_ID)
  2679. node->SN_ObjectID = GenerateUniqueID (node->SN_HashList);
  2680. *ObjectID = node->SN_ObjectID;
  2681. }
  2682. if (ARGUMENT_PRESENT (InterfaceIndex))
  2683. *InterfaceIndex = node->SN_InterfaceIndex;
  2684. if (ARGUMENT_PRESENT (Protocol))
  2685. *Protocol = node->SN_Protocol;
  2686. if (list!=&HashList->HL_List)
  2687. ReleaseServerTableList (&HashList->HL_List);
  2688. return NO_ERROR;
  2689. }
  2690. DoNextNode:
  2691. cur = cur->Flink;
  2692. }
  2693. return ERROR_NO_MORE_ITEMS;
  2694. }
  2695. /*++
  2696. *******************************************************************
  2697. F i n d I n t f L i n k
  2698. Routine Description:
  2699. Find interface list given an interface index. Create new interface
  2700. list if one for given index does not exist
  2701. Interface list must be locked when calling this routine
  2702. Arguments:
  2703. InterfaceIndex - index to look for
  2704. Return Value:
  2705. Head of interface list (link at which new entry can be inserted)
  2706. NULL if list could not be found and creation of new list failed
  2707. *******************************************************************
  2708. --*/
  2709. PLIST_ENTRY
  2710. FindIntfLink (
  2711. ULONG InterfaceIndex
  2712. ) {
  2713. PLIST_ENTRY cur;
  2714. PINTF_NODE node;
  2715. cur = ServerTable.ST_IntfList.PL_Head.Flink;
  2716. while (cur!=&ServerTable.ST_IntfList.PL_Head) {
  2717. node = CONTAINING_RECORD (cur, INTF_NODE, IN_Link);
  2718. if (InterfaceIndex==node->IN_InterfaceIndex)
  2719. return &node->IN_Head;
  2720. else if (InterfaceIndex<node->IN_InterfaceIndex)
  2721. break;
  2722. cur = cur->Flink;
  2723. }
  2724. node = (PINTF_NODE)GlobalAlloc (GMEM_FIXED, sizeof (INTF_NODE));
  2725. if (node==NULL) {
  2726. Trace (DEBUG_FAILURES,
  2727. "File: %s, line: %ld. Can't allocate interface list node (gle:%ld).",
  2728. __FILE__, __LINE__, GetLastError ());
  2729. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2730. return NULL;
  2731. }
  2732. node->IN_InterfaceIndex = InterfaceIndex;
  2733. InitializeListHead (&node->IN_Head);
  2734. InsertTailList (cur, &node->IN_Link);
  2735. return &node->IN_Head;
  2736. }
  2737. /*++
  2738. *******************************************************************
  2739. F i n d T y p e L i n k
  2740. Routine Description:
  2741. Find type list given a type value. Create new type
  2742. list if one for given type does not exist
  2743. Type list must be locked when calling this routine
  2744. Arguments:
  2745. Type - type to look for
  2746. Return Value:
  2747. Head of type list (link at which new entry can be inserted)
  2748. NULL if list could not be found and creation of new list failed
  2749. *******************************************************************
  2750. --*/
  2751. PLIST_ENTRY
  2752. FindTypeLink (
  2753. USHORT Type
  2754. ) {
  2755. PLIST_ENTRY cur;
  2756. PTYPE_NODE node;
  2757. cur = ServerTable.ST_TypeList.PL_Head.Flink;
  2758. while (cur!=&ServerTable.ST_TypeList.PL_Head) {
  2759. node = CONTAINING_RECORD (cur, TYPE_NODE, TN_Link);
  2760. if (Type==node->TN_Type)
  2761. return &node->TN_Head;
  2762. else if (Type<node->TN_Type)
  2763. break;
  2764. cur = cur->Flink;
  2765. }
  2766. node = (PTYPE_NODE)GlobalAlloc (GMEM_FIXED, sizeof (TYPE_NODE));
  2767. if (node==NULL) {
  2768. Trace (DEBUG_FAILURES,
  2769. "File: %s, line: %ld. Can't allocate type list node (gle:%ld).",
  2770. __FILE__, __LINE__, GetLastError ());
  2771. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2772. return NULL;
  2773. }
  2774. node->TN_Type = Type;
  2775. InitializeListHead (&node->TN_Head);
  2776. InsertTailList (cur, &node->TN_Link);
  2777. return &node->TN_Head;
  2778. }
  2779. /*++
  2780. *******************************************************************
  2781. F i n d S o r t e d L i n k
  2782. Routine Description:
  2783. Find place for server with given type and name in SortedListTMP
  2784. If there is another node there with the same name and type it
  2785. is removed from the list
  2786. SortedListTMP must be locked when calling this routine
  2787. Arguments:
  2788. Type - type to look for
  2789. Name - name to look for
  2790. Return Value:
  2791. Link in SortedListTMP at which server with given name and type
  2792. should be inserted
  2793. This routine can't fail
  2794. *******************************************************************
  2795. --*/
  2796. PLIST_ENTRY
  2797. FindSortedLink (
  2798. USHORT Type,
  2799. PUCHAR Name
  2800. ) {
  2801. PLIST_ENTRY cur;
  2802. INT res;
  2803. cur = ServerTable.ST_SortedListTMP.PL_Head.Flink;
  2804. while (cur!=&ServerTable.ST_SortedListTMP.PL_Head) {
  2805. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2806. SERVER_NODE,
  2807. N_Links[SDB_SORTED_LIST_LINK]);
  2808. VALIDATE_SERVER_NODE(node);
  2809. if (Type==node->SN_Type) {
  2810. res = IpxNameCmp (Name, node->SN_Name);
  2811. if (res==0) {
  2812. cur = cur->Flink;
  2813. RemoveEntryList (&node->N_Links[SDB_SORTED_LIST_LINK]);
  2814. InitializeListEntry (&node->N_Links[SDB_SORTED_LIST_LINK]);
  2815. ServerTable.ST_TMPListCnt -= 1;
  2816. break;
  2817. }
  2818. else if (res<0)
  2819. break;
  2820. }
  2821. else if (Type<node->SN_Type)
  2822. break;
  2823. cur = cur->Flink;
  2824. }
  2825. return cur;
  2826. }
  2827. /*++
  2828. *******************************************************************
  2829. H a s h F u n c t i o n
  2830. Routine Description:
  2831. Computes hash function for given server name. In addition it normalizes
  2832. length and capitalization of name
  2833. Arguments:
  2834. Name - name to process
  2835. Return Value:
  2836. Hash value
  2837. *******************************************************************
  2838. --*/
  2839. INT
  2840. HashFunction (
  2841. PUCHAR Name
  2842. ) {
  2843. INT i;
  2844. INT res = 0;
  2845. for (i=0; i<47; i++) {
  2846. Name[i] = (UCHAR)toupper(Name[i]);
  2847. if (Name[i]==0)
  2848. break;
  2849. else
  2850. res += Name[i];
  2851. }
  2852. if ((i==47) && (Name[i]!=0)) {
  2853. Trace (DEBUG_SERVERDB, "Correcting server name: %.48s.", Name);
  2854. Name[i] = 0;
  2855. }
  2856. return res % SDB_NAME_HASH_SIZE;
  2857. }
  2858. /*++
  2859. *******************************************************************
  2860. G e n e r a t e U n i q u e I D
  2861. Routine Description:
  2862. Generates "unique" ULONG for server by combining hash bucket number and
  2863. unique ID of entry in hash list.
  2864. The number is kept with entry until there is a danger of collision
  2865. due to number wraparound
  2866. Arguments:
  2867. HashList - hash bucket to generate ID for
  2868. Return Value:
  2869. ULONG ID
  2870. *******************************************************************
  2871. --*/
  2872. ULONG
  2873. GenerateUniqueID (
  2874. PSDB_HASH_LIST HashList
  2875. ) {
  2876. ULONG id = HashList->HL_ObjectID;
  2877. HashList->HL_ObjectID = (HashList->HL_ObjectID+SDB_NAME_HASH_SIZE)&SDB_OBJECT_ID_MASK;
  2878. // Make sure we won't assign invalid id
  2879. if (HashList->HL_ObjectID==SDB_INVALID_OBJECT_ID)
  2880. HashList->HL_ObjectID+=SDB_NAME_HASH_SIZE;
  2881. // Create guard zone by invalidating all ID's that are one zone
  2882. // above the zone we just entered
  2883. if (!IsSameObjectIDZone(id, HashList->HL_ObjectID)) {
  2884. PLIST_ENTRY cur = HashList->HL_List.PL_Head.Flink;
  2885. ULONG oldMask = (HashList->HL_ObjectID & SDB_OBJECT_ID_ZONE_MASK)
  2886. + SDB_OBJECT_ID_ZONE_UNIT;
  2887. while (cur!=&HashList->HL_List.PL_Head) {
  2888. PSERVER_NODE node = CONTAINING_RECORD (cur,
  2889. SERVER_NODE,
  2890. N_Links[SDB_HASH_TABLE_LINK]);
  2891. if (!IsEnumerator(node)) {
  2892. if ((node->SN_ObjectID & SDB_OBJECT_ID_ZONE_MASK)==oldMask)
  2893. node->SN_ObjectID = SDB_INVALID_OBJECT_ID;
  2894. }
  2895. }
  2896. cur = cur->Flink;
  2897. }
  2898. return id;
  2899. }