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.

570 lines
18 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation
  4. //
  5. // File: rpselect.c
  6. //
  7. // Contents: Routines to select and walk down a PKT Entry's svc list.
  8. //
  9. // Classes:
  10. //
  11. // Functions: ReplFindFirstProvider - find first appropriate provider
  12. // ReplFindNextProvider - walk the list of providers.
  13. //
  14. // ReplFindRemoteService - Helper function to find a remote
  15. // (ie, not local) service.
  16. //
  17. // History: 31 Aug 92 MilanS created.
  18. //
  19. //-----------------------------------------------------------------------------
  20. #include "dfsprocs.h"
  21. #include "rpselect.h"
  22. #include "mupwml.h"
  23. #define Dbg (DEBUG_TRACE_DNR)
  24. NTSTATUS ReplFindRemoteService(
  25. IN PDFS_PKT_ENTRY pPktEntry,
  26. IN PREPL_SELECT_CONTEXT pSelectContext,
  27. OUT ULONG *piSvc);
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text( PAGE, ReplFindFirstProvider )
  30. #pragma alloc_text( PAGE, ReplFindNextProvider )
  31. #pragma alloc_text( PAGE, ReplLookupProvider )
  32. #pragma alloc_text( PAGE, ReplFindRemoteService )
  33. #endif // ALLOC_PRAGMA
  34. //+----------------------------------------------------------------------------
  35. //
  36. // Function: ReplFindFirstProvider
  37. //
  38. // Synopsis: Supports the abstraction that a PKT Entry's service list is an
  39. // ORDERED list, with a distinguished "first" element. This
  40. // function returns that first element.
  41. //
  42. // Arguments: [pPktEntry] - Contains the Service List.
  43. // [pidPrincipal] - Look for a service with this machine id
  44. // [pustrPrincipal] - Look for a service with this principal name
  45. // [ppService] - Will be set to point to the Service Structure
  46. // [pSelectContext] - An opaque structure that will get initialized
  47. // properly for future calls to
  48. // ReplFindNextProvider().
  49. // [pLastEntry] - TRUE if last entry, FALSE otherwise
  50. //
  51. // Notes: Assumes PktEntry is locked.
  52. //
  53. // Returns: [STATUS_SUCCESS] -- If provider found.
  54. //
  55. // [STATUS_NO_MORE_ENTRIES] -- If no provider found.
  56. //
  57. // [STATUS_OBJECT_NAME_NOT_FOUND] if prin. name spec'd but no
  58. // service has that name.
  59. //
  60. // [STATUS_OBJECT_TYPE_MISMATCH] if prin. name spec'd and matched
  61. // with service, but service can't be used because of
  62. // type or provider incompatibility.
  63. //
  64. //-----------------------------------------------------------------------------
  65. NTSTATUS
  66. ReplFindFirstProvider(
  67. IN PDFS_PKT_ENTRY pPktEntry,
  68. IN GUID *pidPrincipal,
  69. IN PUNICODE_STRING pustrPrincipal,
  70. OUT PDFS_SERVICE *ppService,
  71. OUT PREPL_SELECT_CONTEXT pSelectContext,
  72. OUT BOOLEAN *pLastEntry
  73. ) {
  74. NTSTATUS Status;
  75. PDFS_SERVICE psvcFirst = NULL;
  76. ULONG iSvc;
  77. ASSERT(pPktEntry != NULL);
  78. DfsDbgTrace(+1, Dbg, "ReplFindFirstProvider Entered.\n", 0);
  79. *pLastEntry = FALSE;
  80. //
  81. // See if the user wants a service with a specific machine id
  82. //
  83. ASSERT( pidPrincipal == NULL );
  84. //
  85. // See if the user wants us to pick a particular server
  86. //
  87. ASSERT( pustrPrincipal == NULL );
  88. // Initialize the SelectContext
  89. if ((pSelectContext->Flags & REPL_UNINITIALIZED) == 0) {
  90. pSelectContext->Flags = REPL_UNINITIALIZED;
  91. pSelectContext->iFirstSvcIndex = 0;
  92. }
  93. //
  94. // Check to see if Entry has a local service that will do.
  95. //
  96. if (pPktEntry->LocalService != NULL) {
  97. ASSERT(pPktEntry->LocalService->pProvider != NULL);
  98. DfsDbgTrace(0, Dbg, "Selecting Local Svc\n", 0);
  99. psvcFirst = pPktEntry->LocalService;
  100. pSelectContext->Flags = REPL_SVC_IS_LOCAL;
  101. //
  102. // pSelectContext->iSvcIndex and iFirstSvcIndex are meaningless
  103. // because of REPL_SVC_IS_LOCAL flag above. Leave them at unknown
  104. // values.
  105. //
  106. }
  107. if (psvcFirst == NULL) {
  108. // No local service, or local service not sufficient, lets find a
  109. // remote service.
  110. Status = ReplFindRemoteService(
  111. pPktEntry,
  112. pSelectContext,
  113. &iSvc);
  114. if (NT_SUCCESS(Status)) {
  115. pSelectContext->Flags = REPL_SVC_IS_REMOTE;
  116. pSelectContext->iFirstSvcIndex = pSelectContext->iSvcIndex = iSvc;
  117. psvcFirst = &pPktEntry->Info.ServiceList[iSvc];
  118. }
  119. }
  120. if (psvcFirst != NULL) {
  121. DfsDbgTrace(-1, Dbg, "ReplFindFirstProvider: Found service %8lx\n",
  122. psvcFirst);
  123. ASSERT(psvcFirst->pProvider != NULL);
  124. *ppService = psvcFirst;
  125. Status = ReplFindRemoteService(
  126. pPktEntry,
  127. pSelectContext,
  128. &iSvc);
  129. if (!NT_SUCCESS(Status)) {
  130. *pLastEntry = TRUE;
  131. }
  132. return(STATUS_SUCCESS);
  133. } else {
  134. //
  135. // An appropriate provider or referral was not found.
  136. //
  137. DfsDbgTrace(-1, Dbg,
  138. "ReplFindFirstProvider: no service or provider found, "
  139. "pPktEntry = %x\n", pPktEntry);
  140. *ppService = NULL;
  141. RtlZeroMemory(pSelectContext, sizeof(REPL_SELECT_CONTEXT));
  142. pSelectContext->Flags = REPL_NO_MORE_ENTRIES;
  143. Status = STATUS_NO_MORE_ENTRIES;
  144. MUP_TRACE_HIGH(ERROR, ReplFindFirstProvider_Error_NotFound,
  145. LOGSTATUS(Status));
  146. return(STATUS_NO_MORE_ENTRIES);
  147. }
  148. }
  149. //+----------------------------------------------------------------------------
  150. //
  151. // Function: ReplFindNextProvider
  152. //
  153. // Synopsis: Supports the abstraction that a PktEntry's service list is an
  154. // ORDERED list. Based on the SELECT_TOKEN (which the caller is
  155. // required to have initialized by a call to ReplFindFirstProvider)
  156. // this call returns the next provider in the ordered sequence.
  157. //
  158. // Arguments: [pPktEntry] - Contains the service list to operate on
  159. // [ppService] - The next service.
  160. // [pSelectContext] - The context
  161. // [pLastEntry] - TRUE if last entry, FALSE otherwise
  162. //
  163. // Notes: Caller is required to have called ReplFindFirstProvider() before
  164. // calling this.
  165. //
  166. // Returns: [STATUS_SUCCESS] -- *ppService is the lucky winner.
  167. //
  168. // [STATUS_NO_MORE_ENTRIES] -- End of ordered sequence.
  169. //
  170. //-----------------------------------------------------------------------------
  171. NTSTATUS
  172. ReplFindNextProvider(
  173. IN PDFS_PKT_ENTRY pPktEntry,
  174. OUT PDFS_SERVICE *ppService,
  175. IN OUT PREPL_SELECT_CONTEXT pSelectContext,
  176. OUT BOOLEAN *pLastEntry
  177. ) {
  178. NTSTATUS Status;
  179. PDFS_SERVICE psvcNext = NULL; // The one we will return
  180. ULONG iSvc; // index into ServiceList
  181. DfsDbgTrace( 0, Dbg, "ReplFindNextProvider Entered.\n", 0);
  182. *pLastEntry = FALSE;
  183. //
  184. // First, check to see if we have previously determined that the list
  185. // is exhausted.
  186. //
  187. if (pSelectContext->Flags & REPL_NO_MORE_ENTRIES ||
  188. pSelectContext->Flags & REPL_PRINCIPAL_SPECD) {
  189. if (pSelectContext->Flags & REPL_PRINCIPAL_SPECD) {
  190. DfsDbgTrace(0, Dbg,
  191. "ReplFindNextProvider called for open with principal", 0);
  192. }
  193. *pLastEntry = TRUE;
  194. return(STATUS_NO_MORE_ENTRIES);
  195. }
  196. //
  197. // This routine will never return the local service; if the local service
  198. // were an appropriate choice, it would be returned by ReplFindFirstProvider
  199. // So here, we simply find the next appropriate remote service, and adjust
  200. // pSelectContext accordingly.
  201. //
  202. Status = ReplFindRemoteService(
  203. pPktEntry,
  204. pSelectContext,
  205. &iSvc);
  206. if (!NT_SUCCESS(Status)) {
  207. DfsDbgTrace( 0, Dbg, "ReplFindNextProvider: No more services.\n", 0);
  208. pSelectContext->Flags = REPL_NO_MORE_ENTRIES;
  209. *ppService = NULL;
  210. *pLastEntry = TRUE;
  211. return(STATUS_NO_MORE_ENTRIES);
  212. }
  213. // Service and provider found. Update pSelectContext and return.
  214. ASSERT(iSvc <= pPktEntry->Info.ServiceCount);
  215. psvcNext = &pPktEntry->Info.ServiceList[iSvc];
  216. DfsDbgTrace( 0, Dbg, "ReplFindNextProvider: Found svc %8lx\n", psvcNext);
  217. if (pSelectContext->Flags & REPL_SVC_IS_LOCAL) {
  218. pSelectContext->iFirstSvcIndex = iSvc;
  219. }
  220. pSelectContext->Flags = REPL_SVC_IS_REMOTE;
  221. pSelectContext->iSvcIndex = iSvc; // Record Svc for next time
  222. ASSERT(psvcNext->pProvider != NULL);
  223. *ppService = psvcNext;
  224. Status = ReplFindRemoteService(
  225. pPktEntry,
  226. pSelectContext,
  227. &iSvc);
  228. if (!NT_SUCCESS(Status)) {
  229. *pLastEntry = TRUE;
  230. }
  231. return(STATUS_SUCCESS);
  232. }
  233. //+-------------------------------------------------------------------
  234. //
  235. // Function: ReplLookupProvider, local
  236. // (formerly DnrLookupProvider)
  237. //
  238. // Synopsis: This routine looks up a provider given a provider ID.
  239. //
  240. // Arguments: [ProviderID] -- The ID of the provider to be looked up
  241. //
  242. // Returns: [PPROVIDER_DEF] -- the provider found, or NULL
  243. //
  244. //--------------------------------------------------------------------
  245. PPROVIDER_DEF
  246. ReplLookupProvider(
  247. ULONG ProviderId
  248. ) {
  249. NTSTATUS Status;
  250. PPROVIDER_DEF pProv;
  251. HANDLE hProvider = NULL;
  252. OBJECT_ATTRIBUTES objectAttributes;
  253. IO_STATUS_BLOCK ioStatusBlock;
  254. OBJECT_HANDLE_INFORMATION handleInformation;
  255. PFILE_OBJECT fileObject;
  256. int i;
  257. DfsDbgTrace(+1, Dbg, "ReplLookupProvider Entered: id = %x\n", ULongToPtr(ProviderId) );
  258. for (pProv = DfsData.pProvider, i=0; i<DfsData.cProvider; pProv++, i++) {
  259. if (ProviderId == pProv->eProviderId) {
  260. if (pProv->FileObject == NULL) {
  261. DfsDbgTrace(0, Dbg, "Provider device not been referenced yet\n", 0);
  262. //
  263. // We haven't opened a handle to the provider yet - so
  264. // lets try to.
  265. //
  266. if (pProv->DeviceName.Buffer) {
  267. //
  268. // Get a handle to the provider.
  269. //
  270. DfsDbgTrace(0, Dbg, "About to open %wZ\n", &pProv->DeviceName);
  271. InitializeObjectAttributes(
  272. &objectAttributes,
  273. &pProv->DeviceName,
  274. OBJ_CASE_INSENSITIVE, // Attributes
  275. 0, // Root Directory
  276. NULL // Security
  277. );
  278. Status = ZwOpenFile(
  279. &hProvider,
  280. FILE_TRAVERSE,
  281. &objectAttributes,
  282. &ioStatusBlock,
  283. FILE_SHARE_READ | FILE_SHARE_WRITE,
  284. FILE_DIRECTORY_FILE
  285. );
  286. if ( NT_SUCCESS( Status ) ) {
  287. Status = ioStatusBlock.Status;
  288. }
  289. DfsDbgTrace(0, Dbg, "Open returned %08lx\n", ULongToPtr(Status) );
  290. if ( NT_SUCCESS( Status ) ) {
  291. //
  292. // Increment ref count on objects
  293. //
  294. //
  295. // 426184, need to check return code for errors.
  296. //
  297. Status = ObReferenceObjectByHandle(
  298. hProvider,
  299. 0,
  300. NULL,
  301. KernelMode,
  302. (PVOID *)&fileObject,
  303. &handleInformation );
  304. ZwClose(hProvider);
  305. }
  306. if ( NT_SUCCESS( Status ) ) {
  307. //
  308. // We have to do this because the pProv structure is in paged
  309. // pool, and ObReferenceObjectByHandle requires the fileObject
  310. // argument in NonPaged memory. So, we pass in a stack variable
  311. // to ObReferenceObjectByHandle, then copy it to pProv->FileObject
  312. //
  313. pProv->FileObject = fileObject;
  314. ASSERT( NT_SUCCESS( Status ) );
  315. pProv->DeviceObject = IoGetRelatedDeviceObject(
  316. pProv->FileObject
  317. );
  318. Status = ObReferenceObjectByPointer(
  319. pProv->DeviceObject,
  320. 0,
  321. NULL,
  322. KernelMode
  323. );
  324. ASSERT( pProv->DeviceObject->StackSize < 6 ); // see dsinit.c
  325. DfsDbgTrace(-1, Dbg, "ReplLookupProvider Exited: "
  326. "Provider Def @ %08lx\n", pProv);
  327. return pProv;
  328. } else {
  329. return NULL;
  330. }
  331. }
  332. } else {
  333. DfsDbgTrace(-1, Dbg, "ReplLookupProvider Exited: "
  334. "Provider Def @ %08lx\n", pProv);
  335. return pProv;
  336. } // If pProv->FileObject == NULL
  337. } // If ProviderId == pProv->eProviderId
  338. } // For all provider defs
  339. DfsDbgTrace(-1, Dbg, "ReplLookupProvider Exited: Failed!", 0);
  340. return NULL;
  341. }
  342. //+----------------------------------------------------------------------------
  343. //
  344. // Function: ReplFindRemoteService
  345. //
  346. // Synopsis: This routine is a worker used by both ReplFindFirstProvider
  347. // and ReplFindNextProvider to find a !remote! service. It
  348. // completely ignores the local service, if any.
  349. //
  350. // For now, it will simply scan the list sequentially. Later,
  351. // this routine can be modified to call a separate
  352. // component that will compute the transport cost, given the set
  353. // of network addresses in the service list.
  354. //
  355. // Arguments: [pPktEntry] -- The entry for for which a remote provider is
  356. // to be selected.
  357. //
  358. // [pSelectContext] -- The status of replica selection so far.
  359. //
  360. // [piSvc] -- On successful return, the index in the service list
  361. // of the selected service.
  362. //
  363. // Returns: [STATUS_SUCCESS] -- ServiceList[*piSvc] is the lucky winner.
  364. //
  365. // [STATUS_NO_MORE_ENTRIES] -- Either service list is empty, or
  366. // none of the services in the service list will do.
  367. //
  368. //-----------------------------------------------------------------------------
  369. NTSTATUS ReplFindRemoteService(
  370. IN PDFS_PKT_ENTRY pPktEntry,
  371. IN PREPL_SELECT_CONTEXT pSelectContext,
  372. OUT ULONG *piSvc)
  373. {
  374. ULONG iSvc;
  375. BOOLEAN bFound = FALSE;
  376. DfsDbgTrace(+1, Dbg, "ReplFindRemoteService: Entered\n", 0);
  377. if ( pPktEntry->Info.ServiceCount == 0 ) {
  378. DfsDbgTrace(0, Dbg, "ReplFindRemoteService: No svcs in pkt entry\n", 0);
  379. DfsDbgTrace(-1, Dbg, "ReplFindRemoteService: returning %08lx\n",
  380. ULongToPtr(STATUS_NO_MORE_ENTRIES) );
  381. return(STATUS_NO_MORE_ENTRIES);
  382. }
  383. if (pSelectContext->Flags & REPL_SVC_IS_LOCAL ||
  384. pSelectContext->Flags & REPL_UNINITIALIZED) {
  385. //
  386. // We haven't looked at a remote service yet. Start from the active
  387. // service or the first service in the svc list.
  388. //
  389. PDFS_SERVICE pSvc;
  390. if (pPktEntry->ActiveService) {
  391. DfsDbgTrace(0, Dbg, "Starting search at active svc\n", 0);
  392. pSvc = pPktEntry->ActiveService;
  393. } else {
  394. DfsDbgTrace(0, Dbg, "Starting search at first svc\n", 0);
  395. pSvc = &pPktEntry->Info.ServiceList[ 0 ];
  396. }
  397. iSvc = (ULONG)(pSvc - &pPktEntry->Info.ServiceList[0]);
  398. if (pSvc->pProvider == NULL) {
  399. pSvc->pProvider = ReplLookupProvider(pSvc->ProviderId);
  400. }
  401. if ( pSvc->pProvider != NULL ) {
  402. bFound = TRUE;
  403. } else {
  404. iSvc = (iSvc + 1) % pPktEntry->Info.ServiceCount;
  405. }
  406. } else {
  407. //
  408. // We have already looked at some remote services, lets continue where
  409. // we left off.
  410. //
  411. ASSERT(pPktEntry->Info.ServiceCount != 0);
  412. iSvc = (pSelectContext->iSvcIndex + 1) % pPktEntry->Info.ServiceCount;
  413. DfsDbgTrace(0, Dbg, "Continuing search at svc # %d\n", ULongToPtr(iSvc) );
  414. }
  415. //
  416. // We know where to begin looking and where to stop.
  417. //
  418. while ( (iSvc != pSelectContext->iFirstSvcIndex) && !bFound) {
  419. register PDFS_SERVICE pSvc = &pPktEntry->Info.ServiceList[iSvc];
  420. if (pSvc->pProvider == NULL) {
  421. pSvc->pProvider = ReplLookupProvider(pSvc->ProviderId);
  422. }
  423. if ( pSvc->pProvider != NULL ) {
  424. DfsDbgTrace(0, Dbg, "Found svc # %d\n", ULongToPtr(iSvc) );
  425. bFound = TRUE;
  426. } else {
  427. DfsDbgTrace(0, Dbg, "No provider for svc # %d\n", ULongToPtr(iSvc) );
  428. iSvc = (iSvc + 1) % pPktEntry->Info.ServiceCount;
  429. }
  430. }
  431. if (bFound) {
  432. *piSvc = iSvc;
  433. DfsDbgTrace(-1, Dbg, "ReplFindRemoteService: returning svc %08lx\n",
  434. &pPktEntry->Info.ServiceList[iSvc]);
  435. return(STATUS_SUCCESS);
  436. } else {
  437. DfsDbgTrace(-1, Dbg, "ReplFindRemoteService: Exited-> %08lx\n",
  438. ULongToPtr(STATUS_NO_MORE_ENTRIES) );
  439. return(STATUS_NO_MORE_ENTRIES);
  440. }
  441. }