Windows NT 4.0 source code leak
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.

558 lines
17 KiB

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