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.

613 lines
14 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. loader.cxx
  5. Abstract:
  6. Configuration and loading of RPC transports
  7. Revision History:
  8. MarioGo 03-18-96 Cloned from parts of old common.c
  9. MarioGo 10-31-96 Async RPC
  10. --*/
  11. #include <precomp.hxx>
  12. #include <loader.hxx>
  13. #include <trans.hxx>
  14. #include <cotrans.hxx>
  15. #include <dgtrans.hxx>
  16. // Globals - see loader.hxx
  17. DWORD gdwComputerNameLength = 0;
  18. RPC_CHAR gpstrComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  19. UINT gPostSize = CO_MIN_RECV;
  20. #ifdef _INTERNAL_RPC_BUILD_
  21. RPCLT_PDU_FILTER_FUNC gpfnFilter = NULL;
  22. #endif
  23. //
  24. // Used to convert numbers to hex strings
  25. //
  26. const RPC_CHAR HexDigits[] =
  27. {
  28. RPC_CONST_CHAR('0'),
  29. RPC_CONST_CHAR('1'),
  30. RPC_CONST_CHAR('2'),
  31. RPC_CONST_CHAR('3'),
  32. RPC_CONST_CHAR('4'),
  33. RPC_CONST_CHAR('5'),
  34. RPC_CONST_CHAR('6'),
  35. RPC_CONST_CHAR('7'),
  36. RPC_CONST_CHAR('8'),
  37. RPC_CONST_CHAR('9'),
  38. RPC_CONST_CHAR('A'),
  39. RPC_CONST_CHAR('B'),
  40. RPC_CONST_CHAR('C'),
  41. RPC_CONST_CHAR('D'),
  42. RPC_CONST_CHAR('E'),
  43. RPC_CONST_CHAR('F')
  44. };
  45. // WARNING: The order of these protocols must be consistent with the
  46. // definition of PROTOCOL_ID.
  47. const
  48. TRANSPORT_TABLE_ENTRY TransportTable[] = {
  49. {
  50. 0,
  51. 0,
  52. 0
  53. },
  54. // TCP/IP
  55. {
  56. TCP_TOWER_ID,
  57. IP_ADDRESS_ID,
  58. (RPC_TRANSPORT_INTERFACE)&TCP_TransportInterface
  59. },
  60. #ifdef SPX_ON
  61. // SPX
  62. {
  63. SPX_TOWER_ID,
  64. IPX_ADDRESS_ID,
  65. (RPC_TRANSPORT_INTERFACE)&SPX_TransportInterface
  66. },
  67. #else
  68. {
  69. 0,
  70. 0,
  71. NULL
  72. },
  73. #endif
  74. // Named pipes
  75. {
  76. NMP_TOWER_ID,
  77. UNC_ADDRESS_ID,
  78. (RPC_TRANSPORT_INTERFACE)&NMP_TransportInterface
  79. },
  80. #ifdef NETBIOS_ON
  81. // Netbeui
  82. {
  83. NB_TOWER_ID,
  84. NBF_ADDRESS_ID,
  85. (RPC_TRANSPORT_INTERFACE)&NBF_TransportInterface
  86. },
  87. // Netbios over TCP/IP
  88. {
  89. NB_TOWER_ID,
  90. IP_ADDRESS_ID,
  91. (RPC_TRANSPORT_INTERFACE)&NBT_TransportInterface
  92. },
  93. // Netbios over IPX
  94. {
  95. NB_TOWER_ID,
  96. IPX_ADDRESS_ID,
  97. (RPC_TRANSPORT_INTERFACE)&NBI_TransportInterface
  98. },
  99. #else
  100. // Netbeui
  101. {
  102. 0,
  103. 0,
  104. NULL
  105. },
  106. // Netbios over TCP/IP
  107. {
  108. 0,
  109. 0,
  110. NULL
  111. },
  112. // Netbios over IPX
  113. {
  114. 0,
  115. 0,
  116. NULL
  117. },
  118. #endif
  119. #ifdef APPLETALK_ON
  120. // Appletalk Datastream protocol
  121. {
  122. DSP_TOWER_ID,
  123. NBP_ADDRESS_ID,
  124. (RPC_TRANSPORT_INTERFACE)&DSP_TransportInterface
  125. },
  126. #else
  127. // Appletalk Datastream protocol
  128. {
  129. 0,
  130. 0,
  131. NULL
  132. },
  133. #endif
  134. // Banyan Vines SSP
  135. {
  136. 0,
  137. 0,
  138. NULL
  139. },
  140. // Hyper-Text Tranfer Protocol (HTTP)
  141. {
  142. HTTP_TOWER_ID,
  143. HTTP_ADDRESS_ID,
  144. (RPC_TRANSPORT_INTERFACE)&HTTP_TransportInterface
  145. },
  146. // UDP/IP
  147. {
  148. UDP_TOWER_ID,
  149. IP_ADDRESS_ID,
  150. (RPC_TRANSPORT_INTERFACE)&UDP_TransportInterface
  151. },
  152. #ifdef IPX_ON
  153. // IPX
  154. {
  155. IPX_TOWER_ID,
  156. IPX_ADDRESS_ID,
  157. (RPC_TRANSPORT_INTERFACE)&IPX_TransportInterface
  158. },
  159. #else
  160. // IPX
  161. {
  162. 0,
  163. 0,
  164. 0
  165. },
  166. #endif
  167. // CDP/UDP/IP
  168. {
  169. CDP_TOWER_ID,
  170. IP_ADDRESS_ID,
  171. (RPC_TRANSPORT_INTERFACE)&CDP_TransportInterface
  172. },
  173. #ifdef NCADG_MQ_ON
  174. // MSMQ (Falcon/RPC)
  175. {
  176. MQ_TOWER_ID,
  177. MQ_ADDRESS_ID,
  178. (RPC_TRANSPORT_INTERFACE)&MQ_TransportInterface
  179. },
  180. #else
  181. // MSMQ (Falcon/RPC)
  182. {
  183. 0,
  184. 0,
  185. NULL
  186. },
  187. #endif
  188. // TCP over IPv6
  189. {
  190. TCP_TOWER_ID,
  191. IP_ADDRESS_ID,
  192. (RPC_TRANSPORT_INTERFACE)&TCP_TransportInterface
  193. },
  194. // HTTP2 - same as HTTP in terms of contents.
  195. {
  196. HTTP_TOWER_ID,
  197. HTTP_ADDRESS_ID,
  198. (RPC_TRANSPORT_INTERFACE)&HTTP_TransportInterface
  199. }
  200. };
  201. const DWORD cTransportTable = sizeof(TransportTable)/sizeof(TRANSPORT_TABLE_ENTRY);
  202. inline
  203. BOOL CompareProtseqs(
  204. IN const CHAR *p1,
  205. IN const RPC_CHAR *p2)
  206. // Note: protseqs use only ANSI characters so this is ok.
  207. {
  208. while(*p1)
  209. {
  210. if (*p1 != *p2)
  211. {
  212. return FALSE;
  213. }
  214. p1++;
  215. p2++;
  216. }
  217. return(*p2 == 0);
  218. }
  219. PROTOCOL_ID
  220. MapProtseq(
  221. IN const RPC_CHAR *RpcProtocolSequence
  222. )
  223. {
  224. PROTOCOL_ID index;
  225. for(index = 1; index < cTransportTable; index++)
  226. {
  227. if (TransportTable[index].pInfo != NULL)
  228. {
  229. if (RpcpStringCompare(RpcProtocolSequence,
  230. TransportTable[index].pInfo->ProtocolSequence) == 0)
  231. {
  232. return(index);
  233. }
  234. }
  235. }
  236. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  237. DPFLTR_WARNING_LEVEL,
  238. RPCTRANS "Called with unknown protseq %S\n",
  239. RpcProtocolSequence));
  240. ASSERT(0);
  241. return(0);
  242. }
  243. PROTOCOL_ID
  244. MapProtseq(
  245. IN const CHAR *RpcProtocolSequence
  246. )
  247. {
  248. PROTOCOL_ID index;
  249. for(index = 1; index < cTransportTable; index++)
  250. {
  251. if (TransportTable[index].pInfo != NULL)
  252. {
  253. if (CompareProtseqs(RpcProtocolSequence,
  254. TransportTable[index].pInfo->ProtocolSequence))
  255. {
  256. return(index);
  257. }
  258. }
  259. }
  260. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  261. DPFLTR_WARNING_LEVEL,
  262. RPCTRANS "Called with unknown protseq %S\n",
  263. RpcProtocolSequence));
  264. ASSERT(0);
  265. return(0);
  266. }
  267. // NB: must be called before RpcCompletionPort is zeroed out, because it is used for comparison
  268. void FreeCompletionPortHashTable(void)
  269. {
  270. DWORD i;
  271. HANDLE hCurrentHandle;
  272. // walk through the table, not closing if there is next entry, and it is the same as this
  273. for (i = 0; i < gNumberOfProcessors * 2; i ++)
  274. {
  275. hCurrentHandle = RpcCompletionPorts[i];
  276. if (hCurrentHandle && (hCurrentHandle != RpcCompletionPort))
  277. {
  278. CloseHandle(hCurrentHandle);
  279. }
  280. }
  281. }
  282. HANDLE GetCompletionPortHandleForThread(void)
  283. {
  284. DWORD i;
  285. DWORD nMinLoad = (DWORD) -1;
  286. int nMinLoadIndex = -1;
  287. for (i = 0; i < gNumberOfProcessors * 2; i ++)
  288. {
  289. if ((DWORD)CompletionPortHandleLoads[i] < nMinLoad)
  290. {
  291. nMinLoadIndex = i;
  292. nMinLoad = CompletionPortHandleLoads[i];
  293. }
  294. }
  295. ASSERT (nMinLoadIndex >= 0);
  296. InterlockedIncrement(&CompletionPortHandleLoads[nMinLoadIndex]);
  297. ASSERT(RpcCompletionPorts[nMinLoadIndex] != 0);
  298. return RpcCompletionPorts[nMinLoadIndex];
  299. }
  300. void ReleaseCompletionPortHandleForThread(HANDLE h)
  301. {
  302. DWORD i;
  303. for (i = 0; i < gNumberOfProcessors * 2; i ++)
  304. {
  305. if (h == RpcCompletionPorts[i])
  306. {
  307. InterlockedDecrement((long *)&CompletionPortHandleLoads[i]);
  308. ASSERT(CompletionPortHandleLoads[i] >= 0);
  309. return;
  310. }
  311. }
  312. ASSERT(0);
  313. }
  314. RPC_TRANSPORT_INTERFACE
  315. TransportLoad (
  316. IN const RPC_CHAR * RpcProtocolSequence
  317. )
  318. {
  319. static fLoaded = FALSE;
  320. RPC_STATUS RpcStatus;
  321. PROTOCOL_ID index;
  322. RPC_STATUS status;
  323. RPC_TRANSPORT_INTERFACE pInfo;
  324. if (fLoaded == FALSE)
  325. {
  326. RpcStatus = InitTransportProtocols();
  327. if (RpcStatus != RPC_S_OK)
  328. return NULL;
  329. //
  330. // Query the computer name - used by most protocols.
  331. //
  332. gdwComputerNameLength = sizeof(gpstrComputerName)/sizeof(RPC_CHAR);
  333. if (!GetComputerName((RPC_SCHAR *)gpstrComputerName, &gdwComputerNameLength))
  334. {
  335. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  336. DPFLTR_WARNING_LEVEL,
  337. "RPCTRANS: GetComputerNameW failed: %d\n",
  338. GetLastError()));
  339. return(0);
  340. }
  341. gdwComputerNameLength++; // Include the null in the count.
  342. // Create initial IO completion port. This saves us from a race
  343. // assigning the global io completion port.
  344. ASSERT(RpcCompletionPort == 0);
  345. RpcCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
  346. 0,
  347. 0,
  348. 0); // PERF REVIEW
  349. if (RpcCompletionPort == 0)
  350. {
  351. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  352. DPFLTR_WARNING_LEVEL, RPCTRANS "Failed to create initial completion port: %d\n",
  353. GetLastError()));
  354. return(0);
  355. }
  356. InactiveRpcCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
  357. 0,
  358. 0,
  359. MAXULONG); // PERF REVIEW
  360. if (InactiveRpcCompletionPort == 0)
  361. {
  362. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  363. DPFLTR_WARNING_LEVEL, RPCTRANS "Failed to create initial completion port: %d\n",
  364. GetLastError()));
  365. CloseHandle(RpcCompletionPort);
  366. return(0);
  367. }
  368. HANDLE hCurrentCompletionPortHandle;
  369. DWORD i;
  370. BOOL fSuccess = TRUE;
  371. HANDLE hSourceProcessHandle = GetCurrentProcess();
  372. RpcCompletionPorts = new HANDLE[gNumberOfProcessors * 2];
  373. CompletionPortHandleLoads = new long[gNumberOfProcessors * 2];
  374. if ((RpcCompletionPorts == NULL) || (CompletionPortHandleLoads == NULL))
  375. {
  376. CloseHandle(RpcCompletionPort);
  377. RpcCompletionPort = 0;
  378. return 0;
  379. }
  380. for (i = 0; i < gNumberOfProcessors * 2; i ++)
  381. {
  382. RpcCompletionPorts[i] = 0;
  383. CompletionPortHandleLoads[i] = 0;
  384. }
  385. RpcCompletionPorts[0] = RpcCompletionPort;
  386. for (i = 1; i < gNumberOfProcessors * 2; i ++)
  387. {
  388. fSuccess = DuplicateHandle(hSourceProcessHandle, RpcCompletionPort,
  389. hSourceProcessHandle, &hCurrentCompletionPortHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
  390. if (!fSuccess)
  391. break;
  392. ASSERT(hCurrentCompletionPortHandle != 0);
  393. RpcCompletionPorts[i] = hCurrentCompletionPortHandle;
  394. }
  395. if (!fSuccess)
  396. {
  397. FreeCompletionPortHashTable();
  398. CloseHandle(RpcCompletionPort);
  399. RpcCompletionPort = 0;
  400. return 0;
  401. }
  402. //
  403. // Initalize locks, use Rtl* so we don't need to catch exception.
  404. //
  405. NTSTATUS NtStatus;
  406. NtStatus = RtlInitializeCriticalSectionAndSpinCount(&AddressListLock, PREALLOCATE_EVENT_MASK);
  407. if (!NT_SUCCESS(NtStatus))
  408. {
  409. FreeCompletionPortHashTable();
  410. CloseHandle(RpcCompletionPort);
  411. RpcCompletionPort = 0;
  412. return 0;
  413. }
  414. if (fPagedBCacheMode)
  415. {
  416. // allocate minimum post size. This guarantees that buffer
  417. // will always be at the end.
  418. gPostSize = sizeof(CONN_RPC_HEADER);
  419. }
  420. fLoaded = TRUE;
  421. }
  422. index = MapProtseq(RpcProtocolSequence);
  423. if (!index)
  424. {
  425. return(0);
  426. }
  427. pInfo = 0;
  428. switch (index)
  429. {
  430. case NMP:
  431. pInfo = (RPC_TRANSPORT_INTERFACE) NMP_TransportLoad();
  432. break;
  433. #ifdef NETBIOS_ON
  434. case NBF:
  435. case NBT:
  436. case NBI:
  437. pInfo = (RPC_TRANSPORT_INTERFACE) NB_TransportLoad(index);
  438. break;
  439. #endif
  440. case TCP:
  441. #ifdef SPX_ON
  442. case SPX:
  443. #endif
  444. #ifdef APPLETALK_ON
  445. case DSP:
  446. #endif
  447. case HTTP:
  448. pInfo = (RPC_TRANSPORT_INTERFACE) WS_TransportLoad(index);
  449. break;
  450. #ifdef NCADG_MQ_ON
  451. case MSMQ:
  452. #endif
  453. case CDP:
  454. case UDP:
  455. #ifdef IPX_ON
  456. case IPX:
  457. #endif
  458. pInfo = (RPC_TRANSPORT_INTERFACE) DG_TransportLoad(index);
  459. break;
  460. }
  461. if (pInfo == 0)
  462. {
  463. #ifdef UNICODE
  464. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  465. DPFLTR_WARNING_LEVEL,
  466. RPCTRANS "Load of %S failed\n",
  467. RpcProtocolSequence));
  468. #else
  469. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  470. DPFLTR_WARNING_LEVEL,
  471. RPCTRANS "Load of %s failed\n",
  472. RpcProtocolSequence));
  473. #endif
  474. return(0);
  475. }
  476. ASSERT(pInfo == TransportTable[index].pInfo);
  477. return(pInfo);
  478. }
  479. void
  480. UnjoinCompletionPort (
  481. void
  482. )
  483. {
  484. DWORD NumberOfBytes;
  485. ULONG_PTR CompletionKey;
  486. LPOVERLAPPED Overlapped;
  487. BOOL b;
  488. // The kernel today doesn't have the functionality to
  489. // unjoin a thread from a completion port. Therefore
  490. // we fake unjoining by joining another completion port which has
  491. // unlimited concurrency called the inactive completion port.
  492. // Thus threads unjoined from the main completion port will not
  493. // affect its concurrency. One undesirable effect is that each
  494. // time a thread joined to the inactive completion port blocks,
  495. // it will try to wake up another thread, and there won't be any
  496. // there, which is a waste of CPU. Ideally, we should have had
  497. // a capability to set KTHREAD::Queue to NULL, but we don't
  498. b = GetQueuedCompletionStatus(InactiveRpcCompletionPort,
  499. &NumberOfBytes,
  500. &CompletionKey,
  501. &Overlapped,
  502. 0
  503. );
  504. // this operation should either timeout or fail - it should never
  505. // succeed. If it does, this means somebody has erroneously posted
  506. // an IO on the inactive completion port
  507. ASSERT(b == FALSE);
  508. }
  509. #ifdef _INTERNAL_RPC_BUILD_
  510. void
  511. I_RpcltDebugSetPDUFilter (
  512. IN RPCLT_PDU_FILTER_FUNC pfnFilter
  513. )
  514. {
  515. gpfnFilter = pfnFilter;
  516. }
  517. #endif