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.

3376 lines
94 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. binding.cxx
  5. Abstract:
  6. The implementation of the DCE binding class is contained in this
  7. file.
  8. Author:
  9. Michael Montague (mikemon) 04-Nov-1991
  10. Revision History:
  11. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  12. --*/
  13. #include <precomp.hxx>
  14. #include <epmap.h>
  15. #include <hndlsvr.hxx>
  16. #include <sdict2.hxx>
  17. #include <dispatch.h>
  18. #include <osfpcket.hxx>
  19. #include <bitset.hxx>
  20. #include <ProtBind.hxx>
  21. #include <osfclnt.hxx>
  22. #include <osfsvr.hxx>
  23. #include <rpctrans.hxx>
  24. UUID MgmtIf = { 0xafa8bd80,0x7d8a,0x11c9,
  25. {0xbe,0xf4,0x08,0x00,0x2b,0x10,0x29,0x89} };
  26. UUID NullUuid = { 0L, 0, 0, {0,0,0,0,0,0,0,0} };
  27. int
  28. IsMgmtIfUuid(
  29. UUID PAPI * IfId
  30. )
  31. {
  32. if (RpcpMemoryCompare(IfId, &MgmtIf, sizeof(UUID)) == 0)
  33. {
  34. return 1;
  35. }
  36. return 0;
  37. }
  38. RPC_CHAR *
  39. DuplicateString (
  40. IN RPC_CHAR PAPI * String
  41. )
  42. /*++
  43. Routine Description:
  44. When this routine is called, it will duplicate the string into a fresh
  45. string and return it.
  46. Arguments, either:
  47. String - Supplies the string to be duplicated.
  48. Ansi String - Supplies the string to be duplicated.
  49. Return Value:
  50. The duplicated string is returned. If insufficient memory is available
  51. to allocate a fresh string, zero will be returned.
  52. --*/
  53. {
  54. RPC_CHAR * FreshString, * FreshStringScan;
  55. RPC_CHAR PAPI * StringScan;
  56. unsigned int Length;
  57. ASSERT(String);
  58. Length = 1;
  59. StringScan = String;
  60. while (*StringScan++ != 0)
  61. Length += 1;
  62. FreshString = new RPC_CHAR[Length];
  63. if (FreshString == 0)
  64. return(0);
  65. for (FreshStringScan = FreshString, StringScan = String;
  66. *StringScan != 0; FreshStringScan++, StringScan++)
  67. {
  68. *FreshStringScan = *StringScan;
  69. }
  70. *FreshStringScan = *StringScan;
  71. return(FreshString);
  72. }
  73. DCE_BINDING::DCE_BINDING (
  74. IN RPC_CHAR PAPI * ObjectUuid OPTIONAL,
  75. IN RPC_CHAR PAPI * RpcProtocolSequence OPTIONAL,
  76. IN RPC_CHAR PAPI * NetworkAddress OPTIONAL,
  77. IN RPC_CHAR PAPI * Endpoint OPTIONAL,
  78. IN RPC_CHAR PAPI * Options OPTIONAL,
  79. OUT RPC_STATUS PAPI * Status
  80. )
  81. /*++
  82. Routine Description:
  83. The constructor creates a DCE_BINDING object based on the pieces of
  84. the string binding specified.
  85. Arguments:
  86. ObjectUuid - Optionally supplies the object uuid component of the
  87. binding.
  88. RpcProtocolSequence - Optionally supplies the rpc protocol sequence
  89. component of the binding.
  90. NetworkAddress - Optionally supplies the network address component
  91. of the binding.
  92. Endpoint - Optionally supplies the endpoint component of the binding.
  93. Options - Optionally supplies the network options component of the
  94. binding.
  95. Status - Returns the status of the operation. This argument will
  96. be set to one of the following values.
  97. RPC_S_OK - The operation completed successfully.
  98. RPC_S_INVALID_STRING_UUID - The specified object uuid does
  99. not contain the valid string representation of a uuid.
  100. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to
  101. complete the operation.
  102. --*/
  103. {
  104. ALLOCATE_THIS(DCE_BINDING);
  105. *Status = RPC_S_OK;
  106. if ( ARGUMENT_PRESENT(ObjectUuid)
  107. && (ObjectUuid[0] != 0))
  108. {
  109. if (this->ObjectUuid.ConvertFromString(ObjectUuid))
  110. {
  111. *Status = RPC_S_INVALID_STRING_UUID;
  112. this->ObjectUuid.SetToNullUuid();
  113. }
  114. }
  115. else
  116. this->ObjectUuid.SetToNullUuid();
  117. if (ARGUMENT_PRESENT(RpcProtocolSequence))
  118. {
  119. this->RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
  120. if (this->RpcProtocolSequence == 0)
  121. *Status = RPC_S_OUT_OF_MEMORY;
  122. }
  123. else
  124. this->RpcProtocolSequence = 0;
  125. if (ARGUMENT_PRESENT(NetworkAddress))
  126. {
  127. this->NetworkAddress = DuplicateString(NetworkAddress);
  128. if (this->NetworkAddress == 0)
  129. *Status = RPC_S_OUT_OF_MEMORY;
  130. }
  131. else
  132. this->NetworkAddress = 0;
  133. if (ARGUMENT_PRESENT(Endpoint))
  134. {
  135. this->Endpoint = DuplicateString(Endpoint);
  136. if (this->Endpoint == 0)
  137. *Status = RPC_S_OUT_OF_MEMORY;
  138. }
  139. else
  140. this->Endpoint = 0;
  141. if (ARGUMENT_PRESENT(Options))
  142. {
  143. this->Options = DuplicateString(Options);
  144. if (this->Options == 0)
  145. *Status = RPC_S_OUT_OF_MEMORY;
  146. }
  147. else
  148. {
  149. this->Options = 0;
  150. }
  151. }
  152. /*static*/ RPC_CHAR PAPI *
  153. StringCharSearchWithEscape (
  154. IN RPC_CHAR PAPI * String,
  155. IN unsigned int Character
  156. )
  157. /*++
  158. Routine Description:
  159. This routine is the same as the library routine, strchr, except that
  160. the backslash character ('\') is treated as an escape character.
  161. Arguments:
  162. String - Supplies the string in which to search for the character.
  163. Character - Supplies the character to search for in the string.
  164. Return Value:
  165. A pointer to the first occurance of Character in String is returned.
  166. If Character does not exist in String, then 0 is returned.
  167. --*/
  168. {
  169. #ifdef DBCS_ENABLED
  170. ASSERT(IsDBCSLeadByte((RPC_CHAR)Character) == FALSE);
  171. ASSERT(IsDBCSLeadByte(RPC_CONST_CHAR('\\')) == FALSE);
  172. while(*String != (RPC_CHAR)Character)
  173. {
  174. if (*String == 0)
  175. return(0);
  176. if (*String == RPC_CONST_CHAR('\\'))
  177. {
  178. String = (RPC_CHAR *)CharNext((LPCSTR)String);
  179. }
  180. String = (RPC_CHAR *)CharNext((LPCSTR)String);
  181. }
  182. return(String);
  183. #else
  184. while (*String != (RPC_CHAR) Character)
  185. {
  186. if (*String == RPC_CONST_CHAR('\\'))
  187. String++;
  188. if (*String == 0)
  189. return(0);
  190. String++;
  191. }
  192. return(String);
  193. #endif
  194. }
  195. /*static*/ void
  196. StringCopyWithEscape (
  197. OUT RPC_CHAR PAPI * Destination,
  198. IN RPC_CHAR PAPI * Source
  199. )
  200. /*++
  201. Routine Description:
  202. This routine is the same as the library routine, strcpy, except that
  203. the backslash character ('\') is treated as an escape character. When
  204. a character is escaped, the backslash character is not copied to the
  205. Destination.
  206. Arguments:
  207. Destination - Returns a duplicate of the string specified in Source,
  208. but with out escaped characters escaped.
  209. Source - Specifies the string to be copied.
  210. Return Value:
  211. None.
  212. --*/
  213. {
  214. BOOL fLastQuote = FALSE;
  215. #ifdef DBCS_ENABLED
  216. ASSERT(IsDBCSLeadByte('\\') == FALSE);
  217. #endif
  218. while ((*Destination = *Source) != 0)
  219. {
  220. #ifdef DBCS_ENABLED
  221. if (IsDBCSLeadByte(*Source))
  222. {
  223. // Copy the whole DBCS character; don't look for
  224. // escapes within the character.
  225. Destination++;
  226. Source++;
  227. *Destination = *Source;
  228. if (*Source == 0)
  229. {
  230. ASSERT(0); // Bad string, NULL following a lead byte.
  231. return;
  232. }
  233. Destination++;
  234. Source++;
  235. }
  236. else
  237. #endif
  238. {
  239. if ( *Source != RPC_CONST_CHAR('\\')
  240. || fLastQuote == TRUE)
  241. {
  242. Destination++;
  243. fLastQuote = FALSE;
  244. }
  245. else
  246. {
  247. fLastQuote = TRUE;
  248. }
  249. Source++;
  250. }
  251. }
  252. }
  253. /*static*/ RPC_STATUS
  254. ParseAndCopyEndpointField (
  255. OUT RPC_CHAR ** Endpoint,
  256. IN RPC_CHAR PAPI * String
  257. )
  258. /*++
  259. Routine Description:
  260. This routine parses and then copies the endpoint field in String. A
  261. copy of the field is made into a newly allocated string and returned
  262. in Endpoint. String is assumed to contain only the endpoint field;
  263. the terminating ',' or ']' are not included.
  264. Arguments:
  265. Endpoint - Returns a copy of the endpoint field in a newly allocated
  266. string.
  267. String - Supplies the endpoint field to be parsed and copied.
  268. Return Value:
  269. RPC_S_OK - The operation completed successfully.
  270. RPC_S_OUT_OF_MEMORY - There is no memory available to make a copy
  271. of the string.
  272. RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint field is syntactically
  273. incorrect. This error code will be returned if the endpoint field
  274. does not match the following pattern.
  275. [ <Endpoint> | "endpoint=" <Endpoint> ]
  276. --*/
  277. {
  278. // Search will be used to scan along the string to find the end of
  279. // the endpoint field and the '='.
  280. RPC_CHAR PAPI * Search;
  281. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('='));
  282. if (Search == 0)
  283. {
  284. // This means that we have the <Endpoint> pattern, so we just
  285. // copy the endpoint field.
  286. Search = StringCharSearchWithEscape(String,0);
  287. *Endpoint = new RPC_CHAR[size_t(Search - String + 1)];
  288. if (*Endpoint == 0)
  289. return(RPC_S_OUT_OF_MEMORY);
  290. StringCopyWithEscape(*Endpoint,String);
  291. return(RPC_S_OK);
  292. }
  293. // Otherwise, we have the "endpoint=" pattern. First we need to check
  294. // that the string before the '=' is in fact "endpoint".
  295. *Search = 0;
  296. if ( RpcpStringCompare(String, RPC_CONST_STRING("endpoint")) != 0 )
  297. {
  298. *Search = RPC_CONST_CHAR('=');
  299. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  300. }
  301. *Search = RPC_CONST_CHAR('=');
  302. String = Search + 1;
  303. // Now we just need to allocate a new string and copy the endpoint into
  304. // it.
  305. Search = StringCharSearchWithEscape(String,0);
  306. *Endpoint = new RPC_CHAR[size_t(Search - String + 1)];
  307. if (*Endpoint == 0)
  308. return(RPC_S_OUT_OF_MEMORY);
  309. StringCopyWithEscape(*Endpoint,String);
  310. return(RPC_S_OK);
  311. }
  312. RPC_CHAR *
  313. AllocateEmptyString (
  314. void
  315. )
  316. /*++
  317. Routine Description:
  318. This routine allocates and returns an empty string ("").
  319. Return Value:
  320. A newly allocated empty string will be returned.
  321. --*/
  322. {
  323. RPC_CHAR * String;
  324. String = new RPC_CHAR[1];
  325. if (String != 0)
  326. *String = 0;
  327. return(String);
  328. }
  329. DCE_BINDING::DCE_BINDING (
  330. IN RPC_CHAR PAPI * StringBinding,
  331. OUT RPC_STATUS PAPI * Status
  332. )
  333. /*++
  334. Routine Description:
  335. This constructor creates a DCE_BINDING object from a string binding,
  336. which requires that the string binding be parsed into seperate
  337. strings and validated.
  338. Arguments:
  339. StringBinding - Supplies the string being to be parsed.
  340. Status - Returns the status of the operation. This parameter will
  341. take on the following values:
  342. RPC_S_OK - The operation completed successfully.
  343. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to
  344. allocate space for the fields of the string binding.
  345. RPC_S_INVALID_STRING_BINDING - The string binding is
  346. syntactically invalid.
  347. RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint specified in
  348. the string binding is syntactically incorrect.
  349. RPC_S_INVALID_STRING_UUID - The specified object uuid does not
  350. contain the valid string representation of a uuid.
  351. --*/
  352. {
  353. // String will point to the beginning of the field we are trying to
  354. // parse.
  355. RPC_CHAR PAPI * String;
  356. // Search will be used to scan along the string to find the end of
  357. // the field we are trying to parse.
  358. RPC_CHAR PAPI * Search;
  359. // This will contain the string representation of the object uuid.
  360. RPC_CHAR PAPI * ObjectUuidString;
  361. ALLOCATE_THIS(DCE_BINDING);
  362. // A string binding consists of an optional object uuid, an RPC protocol
  363. // sequence, a network address, an optional endpoint, and zero or more
  364. // option fields.
  365. //
  366. // [ <Object UUID> "@" ] <RPC Protocol Sequence> ":" <Network Address>
  367. // [ "[" ( <Endpoint> | "endpoint=" <Endpoint> | ) [","]
  368. // [ "," <Option Name> "=" <Option Value>
  369. // ( <Option Name> "=" <Option Value> )* ] "]" ]
  370. //
  371. // If an object UUID is specified, then it will be followed by '@'.
  372. // Likewise, if an endpoint and/or option(s) are specified, they will
  373. // be in square brackets. Finally, one or more options are specified,
  374. // then ',' must seperate the optional endpoint from the options. The
  375. // backslash character '\' is treated as an escape character in all
  376. // string binding fields.
  377. // To begin with, we need to set all of the string pointers to zero.
  378. // This is necessary so that when we do memory cleanup for error
  379. // recovery, we know which pointers we allocated a string for.
  380. ObjectUuidString = 0;
  381. RpcProtocolSequence = 0;
  382. NetworkAddress = 0;
  383. Endpoint = 0;
  384. Options = 0;
  385. String = StringBinding;
  386. // To begin with, we need to parse off the object UUID from the string
  387. // if it exists.
  388. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('@'));
  389. if (Search == 0)
  390. {
  391. // The string binding does not contain an object UUID.
  392. ObjectUuid.SetToNullUuid();
  393. }
  394. else
  395. {
  396. // There is an object UUID in the string.
  397. // We need to add one for the terminating zero in the
  398. // string.
  399. ObjectUuidString = (RPC_CHAR PAPI *) RpcpFarAllocate(
  400. sizeof(RPC_CHAR)*size_t(Search - String + 1));
  401. if (ObjectUuidString == 0)
  402. {
  403. *Status = RPC_S_OUT_OF_MEMORY;
  404. goto FreeMemoryAndReturn;
  405. }
  406. // Now copy the string.
  407. *Search = 0;
  408. StringCopyWithEscape(ObjectUuidString,String);
  409. *Search = RPC_CONST_CHAR('@');
  410. // Finally, update String so that we are ready to parse the next
  411. // field.
  412. String = Search + 1;
  413. // Now convert the string representation of the object uuid
  414. // into an actual uuid.
  415. if (ObjectUuid.ConvertFromString(ObjectUuidString))
  416. {
  417. *Status = RPC_S_INVALID_STRING_UUID;
  418. goto FreeMemoryAndReturn;
  419. }
  420. RpcpFarFree(ObjectUuidString);
  421. ObjectUuidString = 0;
  422. }
  423. // The RPC protocol sequence field comes next; it is terminated by
  424. // ':'. Both the RPC protocol sequence field and the ':' are required.
  425. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(':'));
  426. if (Search == 0)
  427. {
  428. // This is an error, because the RPC protocol sequence field is
  429. // required. We may need to free the string we allocated for
  430. // the object UUID field.
  431. *Status = RPC_S_INVALID_STRING_BINDING;
  432. goto FreeMemoryAndReturn;
  433. }
  434. else
  435. {
  436. // The same comments which applied to copying the object UUID
  437. // apply here as well.
  438. RpcProtocolSequence = new RPC_CHAR[size_t(Search - String + 1)];
  439. if (RpcProtocolSequence == 0)
  440. {
  441. *Status = RPC_S_OUT_OF_MEMORY;
  442. goto FreeMemoryAndReturn;
  443. }
  444. *Search = 0;
  445. StringCopyWithEscape(RpcProtocolSequence,String);
  446. *Search = RPC_CONST_CHAR(':');
  447. // Finally, update String so that we are ready to parse the next
  448. // field.
  449. String = Search + 1;
  450. }
  451. // Next comes the network address field which is required. It is
  452. // terminated by zero or '['.
  453. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('['));
  454. if (Search == 0)
  455. {
  456. // This means that the network address is the last field, so we
  457. // just copy it, and set the remaining fields to be empty strings.
  458. Search = StringCharSearchWithEscape(String,0);
  459. NetworkAddress = new RPC_CHAR[size_t(Search - String + 1)];
  460. if (NetworkAddress == 0)
  461. {
  462. *Status = RPC_S_OUT_OF_MEMORY;
  463. goto FreeMemoryAndReturn;
  464. }
  465. StringCopyWithEscape(NetworkAddress,String);
  466. Endpoint = AllocateEmptyString();
  467. if (Endpoint == 0)
  468. {
  469. *Status = RPC_S_OUT_OF_MEMORY;
  470. goto FreeMemoryAndReturn;
  471. }
  472. Options = 0;
  473. *Status = RPC_S_OK;
  474. return;
  475. }
  476. // Otherwise, if we reach here, there is an endpoint and/or options
  477. // left to parse. But before we parse them, lets copy the network
  478. // address field.
  479. NetworkAddress = new RPC_CHAR [size_t(Search - String + 1)];
  480. if (NetworkAddress == 0)
  481. {
  482. *Status = RPC_S_OUT_OF_MEMORY;
  483. goto FreeMemoryAndReturn;
  484. }
  485. *Search = 0;
  486. StringCopyWithEscape(NetworkAddress,String);
  487. *Search = RPC_CONST_CHAR('[');
  488. String = Search + 1;
  489. // Now we are ready to parse off the endpoint and/or options.
  490. // To begin with, we check to see if there is a comma.
  491. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(','));
  492. if (Search == 0)
  493. {
  494. // There is only one token in the string binding. See
  495. // if its an endpoint, if not, it must be an option.
  496. // Before we copy the endpoint field, we need to check
  497. // for the closing square bracket.
  498. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(']'));
  499. if (Search == 0)
  500. {
  501. // This is an error; the string binding is invalid. We need to
  502. // clean everything up, and return an error.
  503. *Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  504. goto FreeMemoryAndReturn;
  505. }
  506. *Search = 0;
  507. *Status = ParseAndCopyEndpointField(&Endpoint,String);
  508. *Search = RPC_CONST_CHAR(']');
  509. // If the parse succeeded, allocate an empty option.
  510. if (*Status == RPC_S_OK)
  511. {
  512. Options = 0;
  513. }
  514. // If the endpoint parse failed with RPC_S_INVALID_ENDPOINT_FORMAT,
  515. // the token must be an option.
  516. else if (*Status == RPC_S_INVALID_ENDPOINT_FORMAT)
  517. {
  518. Endpoint = AllocateEmptyString();
  519. if (Endpoint == 0)
  520. {
  521. *Status = RPC_S_OUT_OF_MEMORY;
  522. goto FreeMemoryAndReturn;
  523. }
  524. Options = new RPC_CHAR [size_t(Search - String + 1)];
  525. if (Options == 0)
  526. {
  527. *Status = RPC_S_OUT_OF_MEMORY;
  528. goto FreeMemoryAndReturn;
  529. }
  530. *Search = 0;
  531. StringCopyWithEscape(Options,String);
  532. *Search = RPC_CONST_CHAR(']');
  533. }
  534. // Something bad must have happened, clean up.
  535. else
  536. goto FreeMemoryAndReturn;
  537. *Status = RPC_S_OK;
  538. return;
  539. }
  540. // When we reach here, we know that there are options. We have
  541. // to see if there is an endpoint. If there is, copy it and then
  542. // copy the options. If there isn't, allocate a null endpoint and
  543. // copy the options.
  544. *Search = 0;
  545. *Status = ParseAndCopyEndpointField(&Endpoint,String);
  546. *Search = RPC_CONST_CHAR(',');
  547. // If there was an endpoint, skip that part of the string.
  548. // Otherwise treat it as an option.
  549. if (*Status == RPC_S_OK)
  550. String = Search + 1;
  551. else if (*Status != RPC_S_INVALID_ENDPOINT_FORMAT)
  552. goto FreeMemoryAndReturn;
  553. // There was no endpoint, so allocate an empty string.
  554. else
  555. {
  556. Endpoint = AllocateEmptyString();
  557. if (Endpoint == 0)
  558. {
  559. *Status = RPC_S_OUT_OF_MEMORY;
  560. goto FreeMemoryAndReturn;
  561. }
  562. }
  563. // Even if the caller did not specify the NetworkOptions argument,
  564. // we still want to validate the rest of the string binding.
  565. Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(']'));
  566. if (Search == 0)
  567. {
  568. // This is an error; the string binding is invalid. We need
  569. // to clean everything up, and return an error.
  570. *Status = RPC_S_INVALID_STRING_BINDING;
  571. goto FreeMemoryAndReturn;
  572. }
  573. // Go ahead and copy the network options field if we reach here.
  574. Options = new RPC_CHAR [size_t(Search - String + 1)];
  575. if (Options == 0)
  576. {
  577. *Status = RPC_S_OUT_OF_MEMORY;
  578. goto FreeMemoryAndReturn;
  579. }
  580. *Search = 0;
  581. StringCopyWithEscape(Options,String);
  582. *Search = RPC_CONST_CHAR(']');
  583. // Everything worked out fine; we just fall through the memory
  584. // cleanup code and return.
  585. *Status = RPC_S_OK;
  586. // If an error occured up above, we will have set status to the
  587. // appropriate error code, and jumped here. We may also arrive
  588. // here if an error did not occur, hence the check for an error status
  589. // before we clean up the memory.
  590. FreeMemoryAndReturn:
  591. if (*Status != RPC_S_OK)
  592. {
  593. if (ObjectUuidString != 0)
  594. RpcpFarFree(ObjectUuidString);
  595. delete RpcProtocolSequence;
  596. delete NetworkAddress;
  597. delete Endpoint;
  598. delete Options;
  599. ObjectUuidString = 0;
  600. RpcProtocolSequence = 0;
  601. NetworkAddress = 0;
  602. Endpoint = 0;
  603. Options = 0;
  604. }
  605. }
  606. DCE_BINDING::~DCE_BINDING (
  607. )
  608. /*++
  609. Routine Description:
  610. We cleaning things up here when a DCE_BINDING is getting deleted.
  611. This consists of freeing the strings pointed to by the fields of
  612. the class.
  613. --*/
  614. {
  615. delete RpcProtocolSequence;
  616. delete NetworkAddress;
  617. delete Endpoint;
  618. delete Options;
  619. }
  620. /*static*/ int
  621. StringLengthWithEscape (
  622. IN RPC_CHAR PAPI * String
  623. )
  624. /*++
  625. Routine Description:
  626. This routine is the same as the library routine, strlen, except that
  627. for that following characters, '@', ':', '\', '[', and ',', are
  628. counted as two characters (to save space for a \) rather than one.
  629. Arguments:
  630. String - Supplies a string whose length will be determined.
  631. Return Value:
  632. The length of the string will be returned including enough space to
  633. escape certain characters.
  634. --*/
  635. {
  636. // We use length to keep track of how long the string is so far.
  637. int Length;
  638. Length = 0;
  639. while (*String != 0)
  640. {
  641. #ifdef DBCS_ENABLED
  642. if (IsDBCSLeadByte(*String))
  643. {
  644. String += 2;
  645. Length += 2;
  646. }
  647. else
  648. #endif
  649. {
  650. if ( (*String == RPC_CONST_CHAR('@'))
  651. || (*String == RPC_CONST_CHAR(':'))
  652. || (*String == RPC_CONST_CHAR('\\'))
  653. || (*String == RPC_CONST_CHAR('['))
  654. || (*String == RPC_CONST_CHAR(']'))
  655. || (*String == RPC_CONST_CHAR(',')))
  656. Length += 2;
  657. else
  658. Length += 1;
  659. String += 1;
  660. }
  661. }
  662. return(Length);
  663. }
  664. /*static*/ RPC_CHAR PAPI *
  665. StringCopyEscapeCharacters (
  666. OUT RPC_CHAR PAPI * Destination,
  667. IN RPC_CHAR PAPI * Source
  668. )
  669. /*++
  670. Routine Description:
  671. Source is copied into destination. When coping into destination, the
  672. following characters are escaped by prefixing them with a '\': '@',
  673. ':', '\', '[', ']', and ','.
  674. Arguments:
  675. Destination - Returns a copy of Source.
  676. Source - Supplies a string to be copied into destination.
  677. Return Value:
  678. A pointer to the terminating zero in Destination is returned.
  679. --*/
  680. {
  681. while ((*Destination = *Source) != 0)
  682. {
  683. #ifdef DBCS_ENABLED
  684. if (IsDBCSLeadByte(*Source))
  685. {
  686. Destination++;
  687. Source++;
  688. *Destination = *Source;
  689. }
  690. else
  691. #endif
  692. {
  693. if ( (*Source == RPC_CONST_CHAR('@'))
  694. || (*Source == RPC_CONST_CHAR(':'))
  695. || (*Source == RPC_CONST_CHAR('\\'))
  696. || (*Source == RPC_CONST_CHAR('['))
  697. || (*Source == RPC_CONST_CHAR(']'))
  698. || (*Source == RPC_CONST_CHAR(',')))
  699. {
  700. *Destination++ = RPC_CONST_CHAR('\\');
  701. *Destination = *Source;
  702. }
  703. }
  704. Destination++;
  705. Source++;
  706. }
  707. *Destination = 0;
  708. return(Destination);
  709. }
  710. RPC_CHAR PAPI *
  711. DCE_BINDING::StringBindingCompose (
  712. IN RPC_UUID PAPI * Uuid OPTIONAL,
  713. IN BOOL fStatic
  714. )
  715. /*++
  716. Routine Description:
  717. This method creates a string binding from a DCE_BINDING by combining
  718. the components of a string binding.
  719. Arguments:
  720. Uuid - Optionally supplies a uuid to use in composing the string
  721. binding rather than the object uuid contained in the DCE_BINDING.
  722. Return Value:
  723. String Binding - A newly allocated and created (from the components)
  724. is returned.
  725. 0 - Insufficient memory is available to allocate the string binding.
  726. --*/
  727. {
  728. // We will use the following automatic variable to calculate the
  729. // required length of the string.
  730. int Length;
  731. // Copy is used to copy the fields of the string binding into the
  732. // string binding.
  733. RPC_CHAR PAPI * Copy;
  734. // StringBinding will contain the string binding we are supposed
  735. // to be creating here.
  736. RPC_CHAR PAPI * StringBinding;
  737. // This routine is written as follows. First we need to calculate
  738. // the amount of space required to hold the string binding. This
  739. // is not quite straight forward as it seems: we need to escape
  740. // '@', ':', '\', '[', ']', and ',' characters in the string binding
  741. // we create. After allocating the string, we copy each piece in,
  742. // escaping characters as necessary.
  743. // Go through and figure out how much space each field of the string
  744. // binding will take up.
  745. if (!ARGUMENT_PRESENT(Uuid))
  746. Uuid = &ObjectUuid;
  747. if (Uuid->IsNullUuid() == 0)
  748. {
  749. // The extra plus one is to save space for the '@' which seperates
  750. // the object UUID field from the RPC protocol sequence field. The
  751. // length of the string representation of a uuid is always 36
  752. // characters.
  753. Length = 36 + 1;
  754. }
  755. else
  756. {
  757. Length = 0;
  758. }
  759. if (RpcProtocolSequence != 0)
  760. {
  761. Length += StringLengthWithEscape(RpcProtocolSequence);
  762. }
  763. // We need to save space for the ':' seperating the RPC protocol
  764. // sequence field from the network address field.
  765. Length += 1;
  766. if (NetworkAddress != 0)
  767. Length += StringLengthWithEscape(NetworkAddress);
  768. if ( (Endpoint != 0)
  769. && (Endpoint[0] != 0))
  770. {
  771. // The plus two is to save space for the '[' and ']' surrounding
  772. // the endpoint and options fields.
  773. Length += StringLengthWithEscape(Endpoint) + 2;
  774. if ( (Options != 0)
  775. && (Options[0] != 0))
  776. {
  777. // The extra plus one is for the ',' which goes before the
  778. // options field.
  779. Length += StringLengthWithEscape(Options) + 1;
  780. }
  781. }
  782. else
  783. {
  784. if ( (Options != 0)
  785. && (Options[0] != 0))
  786. {
  787. // We need to add three to the length to save space for the
  788. // '[' and ']' which will go around the options, and the ','
  789. // which goes before the options.
  790. Length += StringLengthWithEscape(Options) + 3;
  791. }
  792. }
  793. // Finally, include space for the terminating zero in the string.
  794. Length += 1;
  795. // Now we allocate space for the string binding and copy all of the
  796. // pieces into it.
  797. StringBinding = (RPC_CHAR PAPI *)
  798. RpcpFarAllocate(Length * sizeof(RPC_CHAR));
  799. if (StringBinding == 0)
  800. return(0);
  801. if (Uuid->IsNullUuid() == 0)
  802. {
  803. Copy = Uuid->ConvertToString(StringBinding);
  804. *Copy++ = RPC_CONST_CHAR('@');
  805. }
  806. else
  807. {
  808. Copy = StringBinding;
  809. }
  810. if (RpcProtocolSequence != 0)
  811. {
  812. Copy = StringCopyEscapeCharacters(Copy, RpcProtocolSequence);
  813. }
  814. *Copy++ = RPC_CONST_CHAR(':');
  815. if (NetworkAddress != 0)
  816. {
  817. Copy = StringCopyEscapeCharacters(Copy, NetworkAddress);
  818. }
  819. if ( (fStatic == 0)
  820. && (Endpoint != 0)
  821. && (Endpoint[0] != 0))
  822. {
  823. *Copy++ = RPC_CONST_CHAR('[');
  824. Copy = StringCopyEscapeCharacters(Copy, Endpoint);
  825. if ( (Options != 0)
  826. && (Options[0] != 0))
  827. {
  828. *Copy++ = RPC_CONST_CHAR(',');
  829. Copy = StringCopyEscapeCharacters(Copy, Options);
  830. }
  831. *Copy++ = RPC_CONST_CHAR(']');
  832. }
  833. else
  834. {
  835. if ( (Options != 0)
  836. && (Options[0] != 0))
  837. {
  838. *Copy++ = RPC_CONST_CHAR('[');
  839. *Copy++ = RPC_CONST_CHAR(',');
  840. Copy = StringCopyEscapeCharacters(Copy, Options);
  841. *Copy++ = RPC_CONST_CHAR(']');
  842. }
  843. }
  844. // And do not forget to terminate the string.
  845. *Copy = 0;
  846. return(StringBinding);
  847. }
  848. RPC_CHAR PAPI *
  849. DCE_BINDING::ObjectUuidCompose (
  850. OUT RPC_STATUS PAPI * Status
  851. )
  852. /*++
  853. Routine Description:
  854. This method returns a string representation of the object UUID
  855. component of the DCE_BINDING. The string representation is
  856. suitable for using as the object UUID component of a string binding.
  857. Arguments:
  858. Status - Returns the status of the operation if there is insufficient
  859. memory to allocate for the string to be returned.
  860. Return Value:
  861. The string representation of the object UUID is returned in a freshly
  862. allocated string.
  863. --*/
  864. {
  865. RPC_CHAR PAPI * String;
  866. if (ObjectUuid.IsNullUuid() != 0)
  867. return(AllocateEmptyStringPAPI());
  868. // The string representation of a uuid is always 36 characters long
  869. // (and the extra character is for the terminating zero).
  870. String = (RPC_CHAR PAPI *) RpcpFarAllocate(37 * sizeof(RPC_CHAR));
  871. if (String == 0)
  872. *Status = RPC_S_OUT_OF_MEMORY;
  873. else
  874. {
  875. ObjectUuid.ConvertToString(String);
  876. String[36] = 0;
  877. }
  878. return(String);
  879. }
  880. RPC_CHAR PAPI *
  881. DCE_BINDING::RpcProtocolSequenceCompose (
  882. OUT RPC_STATUS PAPI * Status
  883. )
  884. /*++
  885. Routine Description:
  886. This method returns a string representation of the RPC protocol sequence
  887. component of the DCE_BINDING. The string representation is
  888. suitable for using as the RPC protocol sequence component of a
  889. string binding.
  890. Arguments:
  891. Status - Returns the status of the operation if there is insufficient
  892. memory to allocate for the string to be returned.
  893. Return Value:
  894. The string representation of the RPC protocol sequence is returned
  895. in a freshly allocated string.
  896. --*/
  897. {
  898. RPC_CHAR PAPI * String;
  899. if (RpcProtocolSequence == 0)
  900. return(AllocateEmptyStringPAPI());
  901. String = DuplicateStringPAPI(RpcProtocolSequence);
  902. if (String == 0)
  903. *Status = RPC_S_OUT_OF_MEMORY;
  904. return(String);
  905. }
  906. RPC_CHAR PAPI *
  907. DCE_BINDING::NetworkAddressCompose (
  908. OUT RPC_STATUS PAPI * Status
  909. )
  910. /*++
  911. Routine Description:
  912. This method returns a string representation of the network address
  913. component of the DCE_BINDING. The string representation is
  914. suitable for using as the network address component of a string binding.
  915. Arguments:
  916. Status - Returns the status of the operation if there is insufficient
  917. memory to allocate for the string to be returned.
  918. Return Value:
  919. The string representation of the network address is returned in a freshly
  920. allocated string.
  921. --*/
  922. {
  923. RPC_CHAR PAPI * String;
  924. if (NetworkAddress == 0)
  925. return(AllocateEmptyStringPAPI());
  926. String = DuplicateStringPAPI(NetworkAddress);
  927. if (String == 0)
  928. *Status = RPC_S_OUT_OF_MEMORY;
  929. return(String);
  930. }
  931. RPC_CHAR PAPI *
  932. DCE_BINDING::EndpointCompose (
  933. OUT RPC_STATUS PAPI * Status
  934. )
  935. /*++
  936. Routine Description:
  937. This method returns a string representation of the endpoint
  938. component of the DCE_BINDING. The string representation is
  939. suitable for using as the endpoint component of a string binding.
  940. Arguments:
  941. Status - Returns the status of the operation if there is insufficient
  942. memory to allocate for the string to be returned.
  943. Return Value:
  944. The string representation of the endpoint is returned in a freshly
  945. allocated string.
  946. --*/
  947. {
  948. RPC_CHAR PAPI * String;
  949. if (Endpoint == 0)
  950. return(AllocateEmptyStringPAPI());
  951. String = DuplicateStringPAPI(Endpoint);
  952. if (String == 0)
  953. *Status = RPC_S_OUT_OF_MEMORY;
  954. return(String);
  955. }
  956. RPC_CHAR PAPI *
  957. DCE_BINDING::OptionsCompose (
  958. OUT RPC_STATUS PAPI * Status
  959. )
  960. /*++
  961. Routine Description:
  962. This method returns a string representation of the options
  963. component of the DCE_BINDING. The string representation is
  964. suitable for using as the options component of a string binding.
  965. Arguments:
  966. Status - Returns the status of the operation if there is insufficient
  967. memory to allocate for the string to be returned.
  968. Return Value:
  969. The string representation of the options is returned in a freshly
  970. allocated string.
  971. --*/
  972. {
  973. RPC_CHAR PAPI * String;
  974. if (Options == 0)
  975. return(AllocateEmptyStringPAPI());
  976. String = DuplicateStringPAPI(Options);
  977. if (String == 0)
  978. *Status = RPC_S_OUT_OF_MEMORY;
  979. return(String);
  980. }
  981. BINDING_HANDLE *
  982. DCE_BINDING::CreateBindingHandle (
  983. OUT RPC_STATUS *Status
  984. )
  985. /*++
  986. Routine Description:
  987. We will create a binding handle specific to the rpc protocol sequence
  988. specified by the DCE_BINDING object. The object uuid will be
  989. passed on to the created binding handle. Ownership of this
  990. passes to this routine. If an error occurs, it will be deleted.
  991. Arguments:
  992. The created binding handle will be returned, or zero if an error
  993. occured.
  994. Return Value:
  995. RPC_S_OK - We had no trouble allocating the binding handle.
  996. RPC_S_OUT_OF_MEMORY - Insufficient memory was available to
  997. complete the operation.
  998. RPC_S_INVALID_RPC_PROTSEQ - The rpc protocol sequence is
  999. syntactically invalid.
  1000. RPC_S_PROTSEQ_NOT_SUPPORTED - The requested rpc protocol sequence
  1001. is not supported.
  1002. --*/
  1003. {
  1004. TRANS_INFO *ClientTransInfo ;
  1005. BINDING_HANDLE *BindingHandle ;
  1006. if ( RpcpMemoryCompare(
  1007. RpcProtocolSequence,
  1008. RPC_CONST_STRING("ncalrpc"),
  1009. 8 * sizeof(RPC_CHAR)) == 0 )
  1010. {
  1011. BindingHandle = LrpcCreateBindingHandle();
  1012. if (BindingHandle == 0)
  1013. {
  1014. delete this;
  1015. *Status = RPC_S_OUT_OF_MEMORY;
  1016. return 0;
  1017. }
  1018. }
  1019. else if ( RpcpMemoryCompare(
  1020. RpcProtocolSequence,
  1021. RPC_CONST_STRING("ncadg_"),
  1022. 6*sizeof(RPC_CHAR)) == 0)
  1023. {
  1024. BindingHandle = DgCreateBindingHandle();
  1025. if (BindingHandle == 0)
  1026. {
  1027. delete this;
  1028. *Status = RPC_S_OUT_OF_MEMORY;
  1029. return 0;
  1030. }
  1031. *Status = OsfMapRpcProtocolSequence(0,
  1032. RpcProtocolSequence,
  1033. &ClientTransInfo);
  1034. if (*Status != RPC_S_OK)
  1035. {
  1036. delete BindingHandle;
  1037. delete this;
  1038. return 0;
  1039. }
  1040. }
  1041. else if ( RpcpMemoryCompare(
  1042. RPC_CONST_STRING("ncacn_"),
  1043. RpcProtocolSequence,
  1044. 6 * sizeof(RPC_CHAR)) == 0 )
  1045. {
  1046. BindingHandle = OsfCreateBindingHandle();
  1047. if (BindingHandle == 0)
  1048. {
  1049. delete this;
  1050. *Status = RPC_S_OUT_OF_MEMORY;
  1051. return 0;
  1052. }
  1053. *Status = OsfMapRpcProtocolSequence(0,
  1054. RpcProtocolSequence,
  1055. &ClientTransInfo) ;
  1056. if (*Status != RPC_S_OK)
  1057. {
  1058. delete BindingHandle;
  1059. delete this;
  1060. return 0;
  1061. }
  1062. }
  1063. else
  1064. {
  1065. delete this;
  1066. *Status = RPC_S_INVALID_RPC_PROTSEQ;
  1067. return 0;
  1068. }
  1069. BindingHandle->SetObjectUuid(&ObjectUuid);
  1070. *Status = BindingHandle->PrepareBindingHandle(ClientTransInfo, this);
  1071. if (*Status != RPC_S_OK)
  1072. {
  1073. delete BindingHandle;
  1074. delete this;
  1075. return 0;
  1076. }
  1077. *Status = RPC_S_OK;
  1078. return BindingHandle;
  1079. }
  1080. void
  1081. DCE_BINDING::AddEndpoint(
  1082. IN RPC_CHAR *Endpoint
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. This routine can be used to update the endpoint stored in the DCE_BINDING.
  1087. If the DCE_BINDING already has an endpoint it is deleted.
  1088. Arguments:
  1089. Endpoint - The new endpoint to store in this DCE_BINDING. Ownership
  1090. passes to this DCE_BINDING.
  1091. Return Value:
  1092. n/a
  1093. --*/
  1094. {
  1095. if (this->Endpoint)
  1096. delete this->Endpoint;
  1097. this->Endpoint = Endpoint;
  1098. }
  1099. RPC_STATUS
  1100. DCE_BINDING::ResolveEndpointIfNecessary (
  1101. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  1102. IN RPC_UUID * ObjectUuid,
  1103. IN OUT void PAPI * PAPI * EpLookupHandle,
  1104. IN BOOL UseEpMapperEp,
  1105. IN unsigned ConnTimeout,
  1106. IN ULONG CallTimeout,
  1107. IN CLIENT_AUTH_INFO *AuthInfo OPTIONAL
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. This routine will determine the endpoint if it is not specified.
  1112. The arguments specifies interface information necessary to resolve
  1113. the endpoint, as well as the object uuid.
  1114. Arguments:
  1115. RpcInterfaceInformation - Supplies the interface information necessary
  1116. to resolve the endpoint.
  1117. ObjectUuid - Supplies the object uuid in the binding.
  1118. EpLookupHandle - Supplies the current value of the endpoint mapper
  1119. lookup handle for a binding, and returns the new value.
  1120. ConnTimeout - the connection timeout
  1121. CallTimeout - the call timeout
  1122. AuthInfo - optional authentication info to be used when resolving the endpoint
  1123. Return Value:
  1124. RPC_S_OK - The endpoint is fully resolved.
  1125. RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
  1126. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
  1127. the endpoint.
  1128. EPT_S_NOT_REGISTERED - There are no more endpoints to be found
  1129. for the specified combination of interface, network address,
  1130. and lookup handle.
  1131. EPT_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
  1132. unable to bind to the EpMapper.
  1133. --*/
  1134. {
  1135. unsigned int Index;
  1136. RPC_STATUS RpcStatus;
  1137. UNICODE_STRING UnicodeString;
  1138. if ( (Endpoint == 0)
  1139. || (Endpoint[0] == 0) )
  1140. {
  1141. // This binding does not have an endpoint, so we must perform
  1142. // binding resolution to obtain an endpoint. First we look
  1143. // in the interface information to see if an endpoint corresponding
  1144. // to the rpc protocol sequence for this binding is there.
  1145. for (Index = 0;
  1146. Index < RpcInterfaceInformation->RpcProtseqEndpointCount;
  1147. Index++)
  1148. {
  1149. RpcStatus = AnsiToUnicodeString(
  1150. RpcInterfaceInformation->RpcProtseqEndpoint[
  1151. Index].RpcProtocolSequence, &UnicodeString);
  1152. if (RpcStatus != RPC_S_OK)
  1153. return(RpcStatus);
  1154. if ( RpcpStringCompare(RpcProtocolSequence,
  1155. UnicodeString.Buffer) == 0 )
  1156. {
  1157. RtlFreeUnicodeString(&UnicodeString);
  1158. if (Endpoint != 0)
  1159. {
  1160. delete Endpoint;
  1161. Endpoint = 0;
  1162. }
  1163. RpcStatus = AnsiToUnicodeString(
  1164. RpcInterfaceInformation->RpcProtseqEndpoint[
  1165. Index].Endpoint, &UnicodeString);
  1166. if (RpcStatus != RPC_S_OK)
  1167. return(RpcStatus);
  1168. Endpoint = DuplicateString(UnicodeString.Buffer);
  1169. RtlFreeUnicodeString(&UnicodeString);
  1170. if (Endpoint == 0)
  1171. return(RPC_S_OUT_OF_MEMORY);
  1172. return(RPC_S_OK);
  1173. }
  1174. RtlFreeUnicodeString(&UnicodeString);
  1175. }
  1176. //The endpoint has not been supplied so resolve the endpoint.
  1177. //CLH 2/17/94 If datagram and forward is required (that is
  1178. //RpcEpResolveBinding has not been called), then simply put
  1179. //the endpoint mapper's endpoint into this binding handles endpoint.
  1180. //The endpoint mapper on the destination node will resolve the
  1181. //endpoint and its runtime will forward the pkt.
  1182. if (Endpoint != 0)
  1183. {
  1184. delete Endpoint;
  1185. Endpoint = 0;
  1186. }
  1187. //
  1188. // We cannot allow management interfaces to be resolved if they dont contain
  1189. // an object uuid.
  1190. //
  1191. if ( (IsMgmtIfUuid ((UUID PAPI * )
  1192. &RpcInterfaceInformation->InterfaceId.SyntaxGUID))
  1193. &&( (ObjectUuid == 0) ||
  1194. (RpcpMemoryCompare(ObjectUuid, &NullUuid, sizeof(UUID)) == 0) ) )
  1195. {
  1196. return(RPC_S_BINDING_INCOMPLETE);
  1197. }
  1198. if ( (RpcpMemoryCompare(RpcProtocolSequence,
  1199. RPC_CONST_STRING("ncadg_"), 6*sizeof(RPC_CHAR)) == 0)
  1200. && (UseEpMapperEp != 0) )
  1201. {
  1202. RpcStatus = EpGetEpmapperEndpoint(
  1203. ((RPC_CHAR * PAPI *) &Endpoint),
  1204. RpcProtocolSequence);
  1205. return((RpcStatus == RPC_S_OK) ?
  1206. RPC_P_EPMAPPER_EP : RpcStatus);
  1207. }
  1208. else
  1209. {
  1210. // Otherwise, we need to contact the endpoint mapper to
  1211. // resolve the endpoint.
  1212. return (EpResolveEndpoint((UUID PAPI *) ObjectUuid,
  1213. &RpcInterfaceInformation->InterfaceId,
  1214. &RpcInterfaceInformation->TransferSyntax,
  1215. RpcProtocolSequence,
  1216. NetworkAddress,
  1217. Options,
  1218. EpLookupHandle,
  1219. ConnTimeout,
  1220. CallTimeout,
  1221. AuthInfo,
  1222. (RPC_CHAR * PAPI *) &Endpoint));
  1223. }
  1224. }
  1225. return(RPC_S_OK);
  1226. }
  1227. DCE_BINDING::Compare (
  1228. IN DCE_BINDING * DceBinding,
  1229. OUT BOOL *fOnlyEndpointDiffers
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. This method compares two DCE_BINDING objects for equality.
  1234. Arguments:
  1235. DceBinding - Supplies a DCE_BINDING object to compare with this.
  1236. fOnlyEndpointDiffers - this output variable will be set to TRUE
  1237. if the result is non-zero and only the endpoint is different.
  1238. It will be set to FALSE if the result is non-zero, and there
  1239. is more than the endpoint different. If this function returns
  1240. 0, the fOnlyEndpointDiffers argument is undefined.
  1241. Return Value:
  1242. Zero will be returned if the specified DCE_BINDING object is the
  1243. same as this. Otherwise, non-zero will be returned.
  1244. --*/
  1245. {
  1246. int Result;
  1247. Result = CompareWithoutSecurityOptions(DceBinding,
  1248. fOnlyEndpointDiffers);
  1249. if (Result != 0)
  1250. return Result;
  1251. if (Options != 0)
  1252. {
  1253. if (DceBinding->Options != 0)
  1254. {
  1255. Result = RpcpStringCompare(DceBinding->Options, Options);
  1256. }
  1257. else
  1258. Result = 1;
  1259. }
  1260. else
  1261. {
  1262. if (DceBinding->Options != 0)
  1263. Result = 1;
  1264. // else - Result has already been set from above
  1265. // Result = 0;
  1266. }
  1267. if (Result)
  1268. {
  1269. // if we didn't bail out after CompareWithoutSecurityOptions,
  1270. // everything but the security options must have been the same
  1271. // If Result is non-zero, only the security optinos have been
  1272. // different. This means that it is not only the endpoint that
  1273. // is different.
  1274. *fOnlyEndpointDiffers = FALSE;
  1275. }
  1276. return(Result);
  1277. }
  1278. DCE_BINDING::CompareWithoutSecurityOptions (
  1279. IN DCE_BINDING * DceBinding,
  1280. OUT BOOL *fOnlyEndpointDiffers
  1281. )
  1282. /*++
  1283. Routine Description:
  1284. This method compares two DCE_BINDING objects for equality without
  1285. comparing the security options.
  1286. Arguments:
  1287. DceBinding - Supplies a DCE_BINDING object to compare with this.
  1288. fOnlyEndpointDiffers - this output variable will be set to TRUE
  1289. if the result is non-zero and only the endpoint is different.
  1290. It will be set to FALSE if the result is non-zero, and there
  1291. is more than the endpoint different. If this function returns
  1292. 0, the fOnlyEndpointDiffers argument is undefined.
  1293. Return Value:
  1294. Zero will be returned if the specified DCE_BINDING object is the
  1295. same as this. Otherwise, non-zero will be returned.
  1296. --*/
  1297. {
  1298. int Result;
  1299. *fOnlyEndpointDiffers = FALSE;
  1300. Result = RpcpMemoryCompare(&(DceBinding->ObjectUuid), &ObjectUuid, sizeof(UUID));
  1301. if (Result != 0)
  1302. return(Result);
  1303. if (RpcProtocolSequence != 0)
  1304. {
  1305. if (DceBinding->RpcProtocolSequence != 0)
  1306. {
  1307. Result = RpcpStringCompare(DceBinding->RpcProtocolSequence,
  1308. RpcProtocolSequence);
  1309. if (Result != 0)
  1310. return(Result);
  1311. }
  1312. else
  1313. return(1);
  1314. }
  1315. else
  1316. {
  1317. if (DceBinding->RpcProtocolSequence != 0)
  1318. return(1);
  1319. }
  1320. if (NetworkAddress != 0)
  1321. {
  1322. if (DceBinding->NetworkAddress != 0)
  1323. {
  1324. Result = RpcpStringCompare(DceBinding->NetworkAddress,
  1325. NetworkAddress);
  1326. if (Result != 0)
  1327. return(Result);
  1328. }
  1329. else
  1330. return(1);
  1331. }
  1332. else
  1333. {
  1334. if (DceBinding->NetworkAddress != 0)
  1335. return(1);
  1336. }
  1337. *fOnlyEndpointDiffers = TRUE;
  1338. if (Endpoint != 0)
  1339. {
  1340. if (DceBinding->Endpoint != 0)
  1341. {
  1342. Result = RpcpStringCompare(DceBinding->Endpoint, Endpoint);
  1343. if (Result != 0)
  1344. return(Result);
  1345. }
  1346. else
  1347. return(1);
  1348. }
  1349. else
  1350. {
  1351. if (DceBinding->Endpoint != 0)
  1352. return(1);
  1353. }
  1354. return(0);
  1355. }
  1356. DCE_BINDING *
  1357. DCE_BINDING::DuplicateDceBinding (
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. We duplicate this DCE binding in this method.
  1362. Return Value:
  1363. A duplicate DCE_BINDING to this DCE_BINDING will be returned, if
  1364. everthing works correctly. Otherwise, zero will be returned
  1365. indicating an out of memory error.
  1366. --*/
  1367. {
  1368. DCE_BINDING * DceBinding;
  1369. RPC_STATUS Status = RPC_S_OK;
  1370. RPC_CHAR ObjectUuidString[37];
  1371. ObjectUuid.ConvertToString(ObjectUuidString);
  1372. ObjectUuidString[36] = 0;
  1373. DceBinding = new DCE_BINDING(ObjectUuidString,RpcProtocolSequence,
  1374. NetworkAddress,Endpoint,Options,&Status);
  1375. if (Status != RPC_S_OK)
  1376. {
  1377. ASSERT(Status == RPC_S_OUT_OF_MEMORY);
  1378. delete DceBinding;
  1379. return(0);
  1380. }
  1381. return(DceBinding);
  1382. }
  1383. void
  1384. DCE_BINDING::MakePartiallyBound (
  1385. )
  1386. /*++
  1387. Routine Description:
  1388. We need to make the binding into a partially bound one by setting the
  1389. endpoint to zero. This is really easy to do.
  1390. --*/
  1391. {
  1392. if (Endpoint != 0)
  1393. {
  1394. delete Endpoint;
  1395. Endpoint = 0;
  1396. }
  1397. }
  1398. BOOL
  1399. DCE_BINDING::MaybeMakePartiallyBound (
  1400. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  1401. IN RPC_UUID * MyObjectUuid
  1402. )
  1403. /*++
  1404. Function Name:MaybeMakePartiallyBound
  1405. Parameters:
  1406. Description:
  1407. If the interface can uniquely identify an RPC server on a machine, the
  1408. binding is made partially bound. Otherwise, it is not.
  1409. Returns:
  1410. --*/
  1411. /*++
  1412. Routine Description:
  1413. --*/
  1414. {
  1415. if ((IsMgmtIfUuid ((UUID PAPI * )
  1416. &RpcInterfaceInformation->InterfaceId.SyntaxGUID))
  1417. &&((MyObjectUuid == 0) ||
  1418. (RpcpMemoryCompare(MyObjectUuid, &NullUuid, sizeof(UUID)) == 0)))
  1419. {
  1420. return FALSE;
  1421. }
  1422. MakePartiallyBound();
  1423. return TRUE;
  1424. }
  1425. RPC_STATUS
  1426. IsRpcProtocolSequenceSupported (
  1427. IN RPC_CHAR PAPI * RpcProtocolSequence
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine determines if the specified rpc protocol sequence is
  1432. supported. It will optionally return the parts of the rpc protocol
  1433. sequence (rpc protocol specifier, and address + interface specifiers).
  1434. Arguments:
  1435. RpcProtocolSequence - Supplies an rpc protocol sequence to check.
  1436. RpcProtocolPart - Optionally returns the rpc protocol part of the
  1437. rpc protocol sequence.
  1438. AddressAndInterfacePart - Optionally returns the address and interface
  1439. parts of the rpc protocol sequence.
  1440. Return Value:
  1441. RPC_S_OK - The specified rpc protocol sequence is supported.
  1442. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to check
  1443. the rpc protocol sequence.
  1444. RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence is not
  1445. supported (but it appears to be valid).
  1446. RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
  1447. syntactically invalid.
  1448. --*/
  1449. {
  1450. RPC_STATUS Status;
  1451. TRANS_INFO *ClientTransInfo ;
  1452. size_t ProtSeqLength;
  1453. ProtSeqLength = RpcpStringLength(RpcProtocolSequence);
  1454. if ( (ProtSeqLength >= 7)
  1455. &&
  1456. (RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("ncalrpc"),
  1457. 8 * sizeof(RPC_CHAR)) == 0) )
  1458. {
  1459. return(RPC_S_OK);
  1460. }
  1461. else if ( (ProtSeqLength >= 6)
  1462. && ((RpcpMemoryCompare(RPC_CONST_STRING("ncacn_"),
  1463. RpcProtocolSequence, 6 * sizeof(RPC_CHAR)) == 0 )
  1464. || ( RpcpMemoryCompare(RPC_CONST_STRING("ncadg_"), RpcProtocolSequence,
  1465. 6 * sizeof(RPC_CHAR)) == 0 )) )
  1466. {
  1467. RPC_PROTSEQ_VECTOR *ProtseqVector;
  1468. unsigned int i;
  1469. Status = RpcNetworkInqProtseqs(&ProtseqVector);
  1470. if (Status != RPC_S_OK)
  1471. {
  1472. return Status;
  1473. }
  1474. Status = RPC_S_PROTSEQ_NOT_SUPPORTED;
  1475. for (i = 0; i < ProtseqVector->Count; i++)
  1476. {
  1477. if (RpcpStringCompare(RpcProtocolSequence, ProtseqVector->Protseq[i]) == 0)
  1478. {
  1479. Status = RPC_S_OK;
  1480. break;
  1481. }
  1482. }
  1483. RpcProtseqVectorFree(&ProtseqVector);
  1484. return(Status);
  1485. }
  1486. else if ( (ProtSeqLength >= 6)
  1487. &&
  1488. (RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("mswmsg"),
  1489. 7 * sizeof(RPC_CHAR)) == 0) )
  1490. {
  1491. return(RPC_S_PROTSEQ_NOT_SUPPORTED);
  1492. }
  1493. return(RPC_S_INVALID_RPC_PROTSEQ);
  1494. }
  1495. LOADABLE_TRANSPORT::LOADABLE_TRANSPORT (
  1496. IN RPC_TRANSPORT_INTERFACE pTransportInterface,
  1497. IN RPC_CHAR * DllName,
  1498. IN RPC_CHAR PAPI * ProtocolSequence,
  1499. IN DLL *LoadableTransportDll,
  1500. IN FuncGetHandleForThread GetHandleForThread,
  1501. IN FuncReleaseHandleForThread ReleaseHandleForThread,
  1502. OUT RPC_STATUS *Status,
  1503. OUT TRANS_INFO * PAPI *TransInfo
  1504. ) : nThreadsAtCompletionPort(0),
  1505. ThreadsDoingLongWait(0)
  1506. /*++
  1507. Routine Description:
  1508. To construct the object, all we have got to do is to copy the
  1509. arguments into the object.
  1510. Arguments:
  1511. DllName - Supplies the name of the dll from which this transport
  1512. interface was loaded.
  1513. --*/
  1514. {
  1515. RpcpStringCopy(this->DllName, DllName) ;
  1516. LoadedDll = LoadableTransportDll;
  1517. *TransInfo = new TRANS_INFO(pTransportInterface,
  1518. ProtocolSequence,
  1519. this) ;
  1520. if (*TransInfo == 0)
  1521. {
  1522. *Status = RPC_S_OUT_OF_MEMORY;
  1523. return ;
  1524. }
  1525. if (ProtseqDict.Insert(*TransInfo) == -1)
  1526. {
  1527. *Status = RPC_S_OUT_OF_MEMORY;
  1528. return ;
  1529. }
  1530. ThreadsStarted = 0;
  1531. nActivityValue = 0;
  1532. nOptimalNumberOfThreads = gNumberOfProcessors + 1;
  1533. ProcessCallsFunc = pTransportInterface->ProcessCalls;
  1534. this->GetHandleForThread = GetHandleForThread;
  1535. this->ReleaseHandleForThread = ReleaseHandleForThread;
  1536. #ifndef NO_PLUG_AND_PLAY
  1537. PnpListen = pTransportInterface->PnpListen;
  1538. #endif
  1539. *Status = RPC_S_OK;
  1540. NumThreads = 0;
  1541. }
  1542. TRANS_INFO *
  1543. LOADABLE_TRANSPORT::MapProtocol (
  1544. IN RPC_CHAR * DllName,
  1545. IN RPC_CHAR PAPI * ProtocolSequence
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This method is used to search the dictionary. It compares a
  1550. LOADABLE_TRANSPORT with a transport interface to see if
  1551. they match.
  1552. Arguments:
  1553. DllName - Supplies the name of the dll from which this loadable
  1554. transport interface was loaded.
  1555. Return Value:
  1556. --*/
  1557. {
  1558. TRANS_INFO *Protseq ;
  1559. TRANSPORT_LOAD TransportLoad;
  1560. RPC_TRANSPORT_INTERFACE pTransport;
  1561. DictionaryCursor cursor;
  1562. if (RpcpStringCompare(DllName, this->DllName) != 0)
  1563. {
  1564. return 0;
  1565. }
  1566. ProtseqDict.Reset(cursor) ;
  1567. while ((Protseq = ProtseqDict.Next(cursor)) != 0)
  1568. {
  1569. if (Protseq->MatchProtseq(ProtocolSequence))
  1570. {
  1571. return Protseq ;
  1572. }
  1573. }
  1574. if (GetTransportEntryPoints(LoadedDll, &TransportLoad,
  1575. &GetHandleForThread,
  1576. &ReleaseHandleForThread) == 0)
  1577. return 0;
  1578. pTransport = (*TransportLoad) (ProtocolSequence);
  1579. if (pTransport == 0)
  1580. {
  1581. return 0 ;
  1582. }
  1583. Protseq = new TRANS_INFO(
  1584. pTransport,
  1585. ProtocolSequence,
  1586. this) ;
  1587. if (Protseq == 0)
  1588. {
  1589. return 0;
  1590. }
  1591. if (ProtseqDict.Insert(Protseq) == -1)
  1592. {
  1593. delete Protseq ;
  1594. return 0;
  1595. }
  1596. return Protseq ;
  1597. }
  1598. TRANS_INFO *
  1599. LOADABLE_TRANSPORT::MatchId (
  1600. IN unsigned short Id
  1601. )
  1602. {
  1603. TRANS_INFO *Protseq ;
  1604. DictionaryCursor cursor;
  1605. ProtseqDict.Reset(cursor) ;
  1606. while ((Protseq = ProtseqDict.Next(cursor)) != 0)
  1607. {
  1608. if (Protseq->MatchId(Id))
  1609. {
  1610. return Protseq ;
  1611. }
  1612. }
  1613. return 0;
  1614. }
  1615. LOADABLE_TRANSPORT_DICT * LoadedLoadableTransports;
  1616. BOOL GetTransportEntryPoints(IN DLL *LoadableTransportDll, OUT TRANSPORT_LOAD *TransportLoad,
  1617. OUT FuncGetHandleForThread *GetHandleForThread,
  1618. OUT FuncReleaseHandleForThread *ReleaseHandleForThread
  1619. )
  1620. /*++
  1621. Function Name:GetTransportEntryPoints
  1622. Parameters: IN LoadableTransportDll - the DLL on which to obtain the entry points
  1623. OUT TRANSPORT_LOAD *TransportLoad - the TransportLoad function for this DLL. 0 iff the
  1624. function fails
  1625. OUT FuncGetHandleForThread *GetHandleForThread - the GetHandleForThread function for this DLL
  1626. OUT FuncReleaseHandleForThread *ReleaseHandleForThread - the ReleaseHandleForThread
  1627. function for this DLL
  1628. Description: Gets the entry points from this transport DLL
  1629. Returns: TRUE if successful, FALSE otherwise
  1630. --*/
  1631. {
  1632. *TransportLoad = (TRANSPORT_LOAD) LoadableTransportDll->GetEntryPoint("TransportLoad");
  1633. *GetHandleForThread =
  1634. (FuncGetHandleForThread) LoadableTransportDll->GetEntryPoint("GetCompletionPortHandleForThread");
  1635. *ReleaseHandleForThread =
  1636. (FuncReleaseHandleForThread) LoadableTransportDll->GetEntryPoint("ReleaseCompletionPortHandleForThread");
  1637. if ((*TransportLoad == 0)
  1638. || (*GetHandleForThread == 0)
  1639. || (*ReleaseHandleForThread == 0)
  1640. )
  1641. {
  1642. *TransportLoad = 0;
  1643. return FALSE;
  1644. }
  1645. return TRUE;
  1646. }
  1647. RPC_STATUS
  1648. LoadableTransportInfo (
  1649. IN RPC_CHAR * DllName,
  1650. IN RPC_CHAR PAPI * RpcProtocolSequence,
  1651. OUT TRANS_INFO * PAPI *pTransInfo
  1652. )
  1653. /*++
  1654. Routine Description:
  1655. We need to return the client information for the loadable transport
  1656. specified by the argument, DllName. This may mean that we need
  1657. to load the transport support dll.
  1658. Argument:
  1659. DllName - Supplies the name of the dll which we need to try and
  1660. load to get the appropriate loadable transport interface.
  1661. RpcProtocolSequence - Supplies the protocol sequence for which
  1662. we are trying to find the appropriate loadable transport
  1663. interface.
  1664. Status - Returns the specific error code for failure to find/load
  1665. a loadable transport.
  1666. Return Value:
  1667. 0 - If the specified transport interface can not be loaded for any
  1668. reason: does not exist, out of memory, version mismatch, etc.
  1669. Otherwise, a pointer to the client information for the requested
  1670. transport interface (loadable transport support) will be returned.
  1671. --*/
  1672. {
  1673. RPC_TRANSPORT_INTERFACE pTransportInterface;
  1674. LOADABLE_TRANSPORT * LoadableTransport;
  1675. TRANSPORT_LOAD TransportLoad;
  1676. FuncGetHandleForThread GetHandleForThread;
  1677. FuncReleaseHandleForThread ReleaseHandleForThread;
  1678. DLL * LoadableTransportDll;
  1679. RPC_STATUS Status = RPC_S_OK;
  1680. DictionaryCursor cursor;
  1681. ASSERT(Status == 0);
  1682. // we can support only up to 4 loadable transports (though today we
  1683. // use only 1 and we don't allow third parties to write their own).
  1684. // This allows us to avoid taking a mutex when browsing the
  1685. // LoadedLoadableTransports dictionary, as we never remove
  1686. // transport from it
  1687. ASSERT(LoadedLoadableTransports->Size() <= INITIALDICTSLOTS);
  1688. //
  1689. // To begin with, check to see if the transport is already loaded.
  1690. // If so, all we have got to do is to return a pointer to it.
  1691. //
  1692. RequestGlobalMutex();
  1693. LoadedLoadableTransports->Reset(cursor);
  1694. while ((LoadableTransport
  1695. = LoadedLoadableTransports->Next(cursor)) != 0)
  1696. {
  1697. *pTransInfo = LoadableTransport->MapProtocol (
  1698. DllName,
  1699. RpcProtocolSequence) ;
  1700. if (*pTransInfo != 0)
  1701. {
  1702. ClearGlobalMutex();
  1703. return RPC_S_OK;
  1704. }
  1705. }
  1706. //
  1707. // If we reach here, that means that we need to try and load the
  1708. // specified loadable transport DLL.
  1709. //
  1710. LoadableTransportDll = new DLL(DllName, &Status);
  1711. if (LoadableTransportDll == 0)
  1712. {
  1713. Status = RPC_S_OUT_OF_MEMORY;
  1714. }
  1715. if (Status != RPC_S_OK)
  1716. {
  1717. ClearGlobalMutex();
  1718. delete LoadableTransportDll;
  1719. VALIDATE(Status)
  1720. {
  1721. RPC_S_OUT_OF_MEMORY,
  1722. RPC_S_INVALID_ARG
  1723. } END_VALIDATE;
  1724. if ( Status != RPC_S_OUT_OF_MEMORY )
  1725. {
  1726. ASSERT( Status == RPC_S_INVALID_ARG );
  1727. Status = RPC_S_PROTSEQ_NOT_SUPPORTED;
  1728. }
  1729. return Status;
  1730. }
  1731. if (GetTransportEntryPoints(LoadableTransportDll, &TransportLoad, &GetHandleForThread,
  1732. &ReleaseHandleForThread) == 0)
  1733. {
  1734. ClearGlobalMutex();
  1735. delete LoadableTransportDll;
  1736. return RPC_S_PROTSEQ_NOT_SUPPORTED;
  1737. }
  1738. pTransportInterface = (*TransportLoad)(RpcProtocolSequence);
  1739. if ( pTransportInterface == 0 )
  1740. {
  1741. ClearGlobalMutex();
  1742. delete LoadableTransportDll;
  1743. return RPC_S_PROTSEQ_NOT_SUPPORTED;
  1744. }
  1745. if ( pTransportInterface->TransInterfaceVersion
  1746. > RPC_TRANSPORT_INTERFACE_VERSION )
  1747. {
  1748. ClearGlobalMutex();
  1749. delete LoadableTransportDll;
  1750. return RPC_S_PROTSEQ_NOT_SUPPORTED;
  1751. }
  1752. //
  1753. // When we reach here, we have successfully loaded and initialized
  1754. // the loadable transport DLL. Now we need to create the client
  1755. // loadable transport and stick it in the dictionary.
  1756. //
  1757. LoadableTransport = new LOADABLE_TRANSPORT(
  1758. pTransportInterface,
  1759. DllName,
  1760. RpcProtocolSequence,
  1761. LoadableTransportDll,
  1762. GetHandleForThread,
  1763. ReleaseHandleForThread,
  1764. &Status,
  1765. pTransInfo);
  1766. if ( LoadableTransport == 0 )
  1767. {
  1768. ClearGlobalMutex();
  1769. delete LoadableTransportDll;
  1770. return RPC_S_OUT_OF_MEMORY;
  1771. }
  1772. if ( Status != RPC_S_OK
  1773. || LoadedLoadableTransports->Insert(LoadableTransport) == -1 )
  1774. {
  1775. ClearGlobalMutex();
  1776. delete LoadableTransportDll;
  1777. delete LoadableTransport;
  1778. return RPC_S_OUT_OF_MEMORY;
  1779. }
  1780. ClearGlobalMutex();
  1781. return RPC_S_OK;
  1782. }
  1783. TRANS_INFO PAPI *
  1784. GetLoadedClientTransportInfoFromId(
  1785. IN unsigned short Id
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. We need to return the client information for the loadable transport
  1790. specified by the argument, TransportId. We look into the DICT and see
  1791. if the transport is loaded- it it isnt, tough- we will return an error.
  1792. -this is because we need Protseq and dllname to load a transport and
  1793. all we have is a transport ID.
  1794. Argument:
  1795. Id - Transport Id. This is actually the opcode used to encode endpoint
  1796. in a DCE tower. For a listing see DCE spec Chapter 11&12.
  1797. Status - Returns the error/success code.
  1798. Return Value:
  1799. 0 - If the specified transport interface can not be loaded for any
  1800. reason: does not exist, out of memory.
  1801. Otherwise, a pointer to the client information for the requested
  1802. transport interface (loadable transport support) will be returned.
  1803. --*/
  1804. {
  1805. TRANS_INFO PAPI *TransInfo ;
  1806. LOADABLE_TRANSPORT * LoadableTransport;
  1807. DictionaryCursor cursor;
  1808. // To begin with, check to see if the transport is already loaded.
  1809. // If so, all we have got to do is to return a pointer to it.
  1810. RequestGlobalMutex();
  1811. LoadedLoadableTransports->Reset(cursor);
  1812. while ((LoadableTransport
  1813. = LoadedLoadableTransports->Next(cursor)) != 0)
  1814. {
  1815. TransInfo = LoadableTransport->MatchId(Id);
  1816. if (TransInfo != 0)
  1817. {
  1818. ClearGlobalMutex();
  1819. return(TransInfo);
  1820. }
  1821. }
  1822. // If we reached here, that means that we are in trouble
  1823. // We assumed that all relevant loadable transports will be
  1824. // loaded for us.... but we are wrong!
  1825. ClearGlobalMutex();
  1826. return(0);
  1827. }
  1828. int
  1829. InitializeLoadableTransportClient (
  1830. )
  1831. /*++
  1832. Routine Description:
  1833. This routine will be called at DLL load time. We do all necessary
  1834. initializations here for this file.
  1835. Return Value:
  1836. Zero will be returned if initialization completes successfully;
  1837. otherwise, non-zero will be returned.
  1838. --*/
  1839. {
  1840. LoadedLoadableTransports = new LOADABLE_TRANSPORT_DICT;
  1841. if (LoadedLoadableTransports == 0)
  1842. return(1);
  1843. return(0);
  1844. }
  1845. inline
  1846. BOOL
  1847. ProcessIOEventsWrapper(
  1848. IN LOADABLE_TRANSPORT PAPI *Transport
  1849. )
  1850. /*++
  1851. Function Name:ProcessIOEventsWrapper
  1852. Parameters:
  1853. Description:
  1854. Returns:
  1855. TRUE - thread should exit.
  1856. --*/
  1857. {
  1858. Transport->ProcessIOEvents();
  1859. return(TRUE);
  1860. }
  1861. RPC_STATUS
  1862. LOADABLE_TRANSPORT::StartServerIfNecessary (
  1863. )
  1864. /*++
  1865. Function Name:StartServerIfNecessary
  1866. Parameters:
  1867. Description:
  1868. Returns:
  1869. --*/
  1870. {
  1871. int i;
  1872. RPC_STATUS Status ;
  1873. int MinimumThreads = GlobalRpcServer->MinimumCallThreads ;
  1874. if ( ThreadsStarted != 0
  1875. || InterlockedIncrement(&ThreadsStarted) != 1)
  1876. {
  1877. return RPC_S_OK ;
  1878. }
  1879. Status = InitializeServerSideCellHeapIfNecessary();
  1880. if (Status != RPC_S_OK)
  1881. {
  1882. ThreadsStarted = 0;
  1883. return Status;
  1884. }
  1885. for (i = 0; i < MinimumThreads; i++)
  1886. {
  1887. InterlockedIncrement(&NumThreads);
  1888. Status = GlobalRpcServer->CreateThread (
  1889. (THREAD_PROC) &ProcessIOEventsWrapper, this) ;
  1890. if (Status != RPC_S_OK)
  1891. {
  1892. NumThreads = 0;
  1893. ThreadsStarted = 0;
  1894. return Status ;
  1895. }
  1896. }
  1897. return RPC_S_OK;
  1898. }
  1899. RPC_STATUS
  1900. LOADABLE_TRANSPORT::CreateThread (void)
  1901. /*++
  1902. Function Name:CreateThread
  1903. Parameters:
  1904. Description:
  1905. Returns:
  1906. --*/
  1907. {
  1908. RPC_STATUS Status;
  1909. if (NumThreads < 1)
  1910. {
  1911. Status = GlobalRpcServer->CreateThread (
  1912. (THREAD_PROC) &ProcessIOEventsWrapper, this) ;
  1913. if (Status != RPC_S_OK)
  1914. {
  1915. return Status;
  1916. }
  1917. InterlockedIncrement(&NumThreads);
  1918. }
  1919. return RPC_S_OK;
  1920. }
  1921. inline
  1922. RPC_STATUS
  1923. LOADABLE_TRANSPORT::ProcessCalls (
  1924. IN INT Timeout,
  1925. OUT RPC_TRANSPORT_EVENT *pEvent,
  1926. OUT RPC_STATUS *pEventStatus,
  1927. OUT PVOID *ppEventContext,
  1928. OUT UINT *pBufferLength,
  1929. OUT BUFFER *pBuffer,
  1930. OUT PVOID *ppSourceContext)
  1931. /*++
  1932. Function Name:ProcessCalls
  1933. Parameters:
  1934. Description:
  1935. Returns:
  1936. --*/
  1937. {
  1938. return (*ProcessCallsFunc) (
  1939. Timeout,
  1940. pEvent,
  1941. pEventStatus,
  1942. ppEventContext,
  1943. pBufferLength,
  1944. pBuffer,
  1945. ppSourceContext) ;
  1946. }
  1947. const ULONG MAX_THREAD_TIMEOUT = 660*1000; // 11 minutes
  1948. void ProcessNewAddressEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  1949. IN RPC_TRANSPORT_EVENT Event,
  1950. IN RPC_STATUS EventStatus,
  1951. IN PVOID pEventContext,
  1952. IN UINT BufferLength,
  1953. IN BUFFER Buffer,
  1954. IN PVOID pSourceContext)
  1955. {
  1956. LISTEN_FOR_PNP_NOTIFICATIONS PnpFunc;
  1957. RpcpPurgeEEInfo();
  1958. GlobalRpcServer->CreateOrUpdateAddresses();
  1959. #ifndef NO_PLUG_AND_PLAY
  1960. PnpFunc = pLoadableTransport->PnpListen;
  1961. (*PnpFunc)();
  1962. #endif
  1963. }
  1964. void ProcessConnectionServerReceivedEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  1965. IN RPC_TRANSPORT_EVENT Event,
  1966. IN RPC_STATUS EventStatus, // operation status
  1967. IN PVOID pEventContext, // trans conenction
  1968. IN UINT BufferLength, // buffer length
  1969. IN BUFFER Buffer, // buffer
  1970. IN PVOID pSourceContext)
  1971. {
  1972. OSF_SCONNECTION *SConnection = InqTransSConnection(pEventContext);
  1973. ASSERT(SConnection->InvalidHandle(OSF_SCONNECTION_TYPE) == 0);
  1974. RpcpPurgeEEInfo();
  1975. SConnection->ProcessReceiveComplete(EventStatus,
  1976. Buffer,
  1977. BufferLength);
  1978. }
  1979. void ProcessConnectionServerSendEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  1980. IN RPC_TRANSPORT_EVENT Event,
  1981. IN RPC_STATUS EventStatus,
  1982. IN PVOID pEventContext,
  1983. IN UINT BufferLength,
  1984. IN BUFFER Buffer,
  1985. IN PVOID pSourceContext // send context
  1986. )
  1987. {
  1988. OSF_SCALL *SCall = InqTransSCall(pSourceContext);
  1989. ASSERT(SCall->InvalidHandle(OSF_SCALL_TYPE) == 0);
  1990. ASSERT(EventStatus != RPC_S_OK
  1991. || ((rpcconn_common *) Buffer)->frag_length == BufferLength);
  1992. RpcpPurgeEEInfo();
  1993. SCall->ProcessSendComplete(EventStatus, Buffer);
  1994. }
  1995. void ProcessConnectionClientSendEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  1996. IN RPC_TRANSPORT_EVENT Event,
  1997. IN RPC_STATUS EventStatus, // Operation status
  1998. IN PVOID pEventContext,
  1999. IN UINT BufferLength,
  2000. IN BUFFER Buffer, // Buffer
  2001. IN PVOID pSourceContext // send context
  2002. )
  2003. {
  2004. REFERENCED_OBJECT *pObj;
  2005. pObj = (REFERENCED_OBJECT *) *((PVOID *)
  2006. ((char *) pSourceContext - sizeof(void *)));
  2007. ASSERT(pObj->InvalidHandle(OSF_CCALL_TYPE | OSF_CCONNECTION_TYPE) == 0);
  2008. RpcpPurgeEEInfo();
  2009. pObj->ProcessSendComplete(EventStatus, Buffer);
  2010. }
  2011. void ProcessConnectionClientReceiveEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  2012. IN RPC_TRANSPORT_EVENT Event,
  2013. IN RPC_STATUS EventStatus, // operation status
  2014. IN PVOID pEventContext, // trans connection
  2015. IN UINT BufferLength, // buffer length
  2016. IN BUFFER Buffer, // buffer
  2017. IN PVOID pSourceContext)
  2018. {
  2019. OSF_CCONNECTION *CConnection = InqTransCConnection(pEventContext);
  2020. ASSERT(CConnection->InvalidHandle(OSF_CCONNECTION_TYPE) == 0);
  2021. ASSERT(CConnection->IsExclusive() == FALSE);
  2022. RpcpPurgeEEInfo();
  2023. CConnection->ProcessReceiveComplete(
  2024. EventStatus,
  2025. Buffer,
  2026. BufferLength);
  2027. CConnection->RemoveReference();
  2028. }
  2029. void ProcessDatagramServerReceiveEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  2030. IN RPC_TRANSPORT_EVENT Event,
  2031. IN RPC_STATUS EventStatus,
  2032. IN PVOID pEventContext,
  2033. IN UINT BufferLength,
  2034. IN BUFFER Buffer,
  2035. IN PVOID pSourceContext)
  2036. {
  2037. ProcessDgServerPacket( EventStatus,
  2038. pEventContext,
  2039. Buffer,
  2040. BufferLength,
  2041. (DatagramTransportPair *)pSourceContext );
  2042. }
  2043. void ProcessDatagramClientReceiveEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  2044. IN RPC_TRANSPORT_EVENT Event,
  2045. IN RPC_STATUS EventStatus,
  2046. IN PVOID pEventContext,
  2047. IN UINT BufferLength,
  2048. IN BUFFER Buffer,
  2049. IN PVOID pSourceContext)
  2050. {
  2051. ProcessDgClientPacket( EventStatus,
  2052. pEventContext,
  2053. Buffer,
  2054. BufferLength,
  2055. (DatagramTransportPair *)pSourceContext );
  2056. }
  2057. void ProcessRuntimePostedEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  2058. IN RPC_TRANSPORT_EVENT Event,
  2059. IN RPC_STATUS EventStatus,
  2060. IN PVOID pEventContext,
  2061. IN UINT BufferLength,
  2062. IN BUFFER Buffer,
  2063. IN PVOID pSourceContext)
  2064. {
  2065. BOOL IsServer;
  2066. BOOL SendToRuntime;
  2067. RPC_STATUS RpcStatus;
  2068. RpcpPurgeEEInfo();
  2069. switch (BufferLength)
  2070. {
  2071. case CO_EVENT_BIND_TO_SERVER:
  2072. extern void OsfBindToServer( PVOID Context );
  2073. OsfBindToServer( pEventContext );
  2074. break;
  2075. case DG_EVENT_CALLBACK_COMPLETE:
  2076. class DG_SCONNECTION;
  2077. extern void ConvCallCompletedWrapper( PVOID Connection );
  2078. ConvCallCompletedWrapper(pEventContext);
  2079. break;
  2080. case CO_EVENT_TICKLE_THREAD:
  2081. #if defined (RPC_GC_AUDIT)
  2082. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Thread %X: Tickled\n",
  2083. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  2084. #endif
  2085. // no-op
  2086. break;
  2087. case IN_PROXY_IIS_DIRECT_RECV:
  2088. HTTP2IISDirectReceive(pEventContext);
  2089. break;
  2090. case HTTP2_DIRECT_RECEIVE:
  2091. // For now we will not inject corruption prior to HTTP2DirectReceive.
  2092. // We will need to query ((HTTP2EndpointReceiver *)pEventContext)->IsServer
  2093. // to tell which kind of buffer this really is before injecting corruption.
  2094. EventStatus = HTTP2DirectReceive(pEventContext,
  2095. (BYTE **)&Buffer,
  2096. (ULONG *)&BufferLength,
  2097. &pEventContext,
  2098. &IsServer
  2099. );
  2100. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2101. {
  2102. if (IsServer == FALSE)
  2103. {
  2104. ProcessConnectionClientReceiveEvent(pLoadableTransport,
  2105. Event,
  2106. EventStatus,
  2107. pEventContext,
  2108. BufferLength,
  2109. Buffer,
  2110. pSourceContext);
  2111. }
  2112. else
  2113. {
  2114. ProcessConnectionServerReceivedEvent(pLoadableTransport,
  2115. Event,
  2116. EventStatus,
  2117. pEventContext,
  2118. BufferLength,
  2119. Buffer,
  2120. pSourceContext);
  2121. }
  2122. }
  2123. break;
  2124. case HTTP2_WINHTTP_DIRECT_RECV:
  2125. EventStatus = HTTP2WinHttpDirectReceive(pEventContext,
  2126. (BYTE **)&Buffer,
  2127. (ULONG *)&BufferLength,
  2128. &pEventContext
  2129. );
  2130. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2131. {
  2132. ProcessConnectionClientReceiveEvent(pLoadableTransport,
  2133. Event,
  2134. EventStatus,
  2135. pEventContext,
  2136. BufferLength,
  2137. Buffer,
  2138. pSourceContext);
  2139. }
  2140. break;
  2141. case HTTP2_WINHTTP_DIRECT_SEND:
  2142. EventStatus = HTTP2WinHttpDirectSend(pEventContext,
  2143. (BYTE **)&Buffer,
  2144. &pSourceContext
  2145. );
  2146. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2147. {
  2148. ProcessConnectionClientSendEvent(pLoadableTransport,
  2149. Event,
  2150. EventStatus,
  2151. pEventContext,
  2152. BufferLength,
  2153. Buffer,
  2154. pSourceContext);
  2155. }
  2156. break;
  2157. case PLUG_CHANNEL_DIRECT_SEND:
  2158. RpcStatus = HTTP2PlugChannelDirectSend(pEventContext);
  2159. ASSERT(RpcStatus == RPC_S_OK);
  2160. break;
  2161. case CHANNEL_DATA_ORIGINATOR_DIRECT_SEND:
  2162. EventStatus = HTTP2ChannelDataOriginatorDirectSend(pEventContext,
  2163. &IsServer,
  2164. &pSourceContext,
  2165. &Buffer,
  2166. &BufferLength
  2167. );
  2168. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2169. {
  2170. if (IsServer == FALSE)
  2171. {
  2172. ProcessConnectionClientSendEvent(pLoadableTransport,
  2173. Event,
  2174. EventStatus,
  2175. pEventContext,
  2176. BufferLength,
  2177. Buffer,
  2178. pSourceContext);
  2179. }
  2180. else
  2181. {
  2182. ProcessConnectionServerSendEvent(pLoadableTransport,
  2183. Event,
  2184. EventStatus,
  2185. pEventContext,
  2186. BufferLength,
  2187. Buffer,
  2188. pSourceContext);
  2189. }
  2190. }
  2191. break;
  2192. case HTTP2_FLOW_CONTROL_DIRECT_SEND:
  2193. EventStatus = HTTP2FlowControlChannelDirectSend(pEventContext,
  2194. &IsServer,
  2195. &SendToRuntime,
  2196. &pSourceContext,
  2197. &Buffer,
  2198. &BufferLength
  2199. );
  2200. if ((EventStatus != RPC_P_PACKET_CONSUMED) && (SendToRuntime != FALSE))
  2201. {
  2202. if (IsServer == FALSE)
  2203. {
  2204. ProcessConnectionClientSendEvent(pLoadableTransport,
  2205. Event,
  2206. EventStatus,
  2207. pEventContext,
  2208. BufferLength,
  2209. Buffer,
  2210. pSourceContext);
  2211. }
  2212. else
  2213. {
  2214. ProcessConnectionServerSendEvent(pLoadableTransport,
  2215. Event,
  2216. EventStatus,
  2217. pEventContext,
  2218. BufferLength,
  2219. Buffer,
  2220. pSourceContext);
  2221. }
  2222. }
  2223. break;
  2224. case HTTP2_RESCHEDULE_TIMER:
  2225. HTTP2TimerReschedule(pEventContext);
  2226. break;
  2227. case HTTP2_ABORT_CONNECTION:
  2228. HTTP2AbortConnection(pEventContext);
  2229. break;
  2230. case HTTP2_RECYCLE_CHANNEL:
  2231. HTTP2RecycleChannel(pEventContext);
  2232. break;
  2233. default:
  2234. ASSERT( 0 );
  2235. }
  2236. }
  2237. void ProcessInvalidIOEvent(LOADABLE_TRANSPORT *pLoadableTransport,
  2238. IN RPC_TRANSPORT_EVENT Event,
  2239. IN RPC_STATUS EventStatus,
  2240. IN PVOID pEventContext,
  2241. IN UINT BufferLength,
  2242. IN BUFFER Buffer,
  2243. IN PVOID pSourceContext)
  2244. {
  2245. ASSERT(0);
  2246. }
  2247. void ProcessComplexTSend(LOADABLE_TRANSPORT *pLoadableTransport,
  2248. IN RPC_TRANSPORT_EVENT Event,
  2249. IN RPC_STATUS EventStatus, // status of the operation
  2250. IN PVOID pEventContext,
  2251. IN UINT BufferLength,
  2252. IN BUFFER Buffer,
  2253. IN PVOID pSourceContext // send context
  2254. )
  2255. {
  2256. EventStatus = HTTP2ProcessComplexTSend(pSourceContext,
  2257. EventStatus,
  2258. &Buffer
  2259. );
  2260. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2261. {
  2262. if ((Event & TYPE_MASK) == CLIENT)
  2263. {
  2264. ProcessConnectionClientSendEvent(pLoadableTransport,
  2265. Event,
  2266. EventStatus,
  2267. pEventContext,
  2268. BufferLength,
  2269. Buffer,
  2270. pSourceContext
  2271. );
  2272. }
  2273. else
  2274. {
  2275. ProcessConnectionServerSendEvent(pLoadableTransport,
  2276. Event,
  2277. EventStatus,
  2278. pEventContext,
  2279. BufferLength,
  2280. Buffer,
  2281. pSourceContext
  2282. );
  2283. }
  2284. }
  2285. }
  2286. void ProcessComplexTReceive(LOADABLE_TRANSPORT *pLoadableTransport,
  2287. IN RPC_TRANSPORT_EVENT Event,
  2288. IN RPC_STATUS EventStatus, // status of the operation
  2289. IN PVOID pEventContext, // connection
  2290. IN UINT BufferLength,
  2291. IN BUFFER Buffer,
  2292. IN PVOID pSourceContext // bytes received
  2293. )
  2294. {
  2295. ULONG Bytes = PtrToUlong(pSourceContext);
  2296. EventStatus = HTTP2ProcessComplexTReceive(&pEventContext,
  2297. EventStatus,
  2298. Bytes,
  2299. &Buffer,
  2300. &BufferLength
  2301. );
  2302. if ((EventStatus != RPC_P_PACKET_CONSUMED)
  2303. && (EventStatus != RPC_P_PARTIAL_RECEIVE))
  2304. {
  2305. if ((Event & TYPE_MASK) == CLIENT)
  2306. {
  2307. ProcessConnectionClientReceiveEvent(pLoadableTransport,
  2308. Event,
  2309. EventStatus,
  2310. pEventContext,
  2311. BufferLength,
  2312. Buffer,
  2313. pSourceContext);
  2314. }
  2315. else
  2316. {
  2317. ProcessConnectionServerReceivedEvent(pLoadableTransport,
  2318. Event,
  2319. EventStatus,
  2320. pEventContext,
  2321. BufferLength,
  2322. Buffer,
  2323. pSourceContext);
  2324. }
  2325. }
  2326. }
  2327. // note that this array must have correspondence to the constants in rpctrans.hxx
  2328. ProcessIOEventFunc *IOEventDispatchTable[LastRuntimeConstant + 1] =
  2329. {
  2330. // 0 is CONNECTION | CLIENT | SEND
  2331. ProcessConnectionClientSendEvent,
  2332. // 1 is DATAGRAM | CLIENT | SEND
  2333. ProcessInvalidIOEvent,
  2334. // 2 is invalid
  2335. ProcessInvalidIOEvent,
  2336. // 3 is invalid
  2337. ProcessInvalidIOEvent,
  2338. // 4 is CONNECTION | SERVER | SEND
  2339. ProcessConnectionServerSendEvent,
  2340. // 5 is DATAGRAM | SERVER | SEND
  2341. ProcessInvalidIOEvent,
  2342. // 6 is invalid
  2343. ProcessInvalidIOEvent,
  2344. // 7 is invalid
  2345. ProcessInvalidIOEvent,
  2346. // 8 is CONNECTION | CLIENT | RECEIVE
  2347. ProcessConnectionClientReceiveEvent,
  2348. // 9 is DATAGRAM | CLIENT | RECEIVE
  2349. ProcessDatagramClientReceiveEvent,
  2350. // 10 is invalid
  2351. ProcessInvalidIOEvent,
  2352. // 11 is invalid
  2353. ProcessInvalidIOEvent,
  2354. // 12 is CONNECTION | SERVER | RECEIVE
  2355. ProcessConnectionServerReceivedEvent,
  2356. // 13 is DATAGRAM | SERVER | RECEIVE
  2357. ProcessDatagramServerReceiveEvent,
  2358. // 14 is invalid
  2359. ProcessInvalidIOEvent,
  2360. // 15 is invalid
  2361. ProcessInvalidIOEvent,
  2362. // 16 is COMPLEX_T | CONNECTION | SEND | CLIENT
  2363. ProcessComplexTSend,
  2364. // 17 is RuntimePosted
  2365. ProcessRuntimePostedEvent,
  2366. // 18 is NewAddress
  2367. ProcessNewAddressEvent,
  2368. // 19 is invalid
  2369. ProcessInvalidIOEvent,
  2370. // 20 is COMPLEX_T | CONNECTION | SEND | SERVER
  2371. ProcessComplexTSend,
  2372. // 21 is invalid
  2373. ProcessInvalidIOEvent,
  2374. // 22 is invalid
  2375. ProcessInvalidIOEvent,
  2376. // 23 is invalid
  2377. ProcessInvalidIOEvent,
  2378. // 24 is COMPLEX_T | CONNECTION | RECEIVE | CLIENT
  2379. ProcessComplexTReceive,
  2380. // 25 is invalid
  2381. ProcessInvalidIOEvent,
  2382. // 26 is invalid
  2383. ProcessInvalidIOEvent,
  2384. // 27 is invalid
  2385. ProcessInvalidIOEvent,
  2386. // 28 is COMPLEX_T | CONNECTION | RECEIVE | SERVER
  2387. ProcessComplexTReceive
  2388. };
  2389. const ULONG UndefinedLocalThreadTimeout = 0;
  2390. void LOADABLE_TRANSPORT::ProcessIOEvents (
  2391. )
  2392. /*++
  2393. Function Name:ProcessIOEvents
  2394. Parameters:
  2395. Description:
  2396. Returns:
  2397. TRUE - the thread should not be cached
  2398. FALSE - the thread should be cached
  2399. --*/
  2400. {
  2401. RPC_STATUS Status ;
  2402. RPC_TRANSPORT_EVENT Event ;
  2403. RPC_STATUS EventStatus ;
  2404. PVOID EventContext ;
  2405. BUFFER Buffer ;
  2406. UINT BufferLength ;
  2407. PVOID pSourceContext = 0;
  2408. int Timeout = gThreadTimeout;
  2409. unsigned int nLocalActivityValue = 0;
  2410. int nOldActivityValue = nActivityValue;
  2411. HANDLE hCompletionPortHandleForThread = GetHandleForThread();
  2412. THREAD *CurrentThread;
  2413. DebugThreadInfo *ThreadDebugCell;
  2414. BOOL fThreadIsDoingLongWait = FALSE;
  2415. ULONG LocalNumThreads;
  2416. ULONG LocalThreadsDoingLongWait;
  2417. long LocalMaxThreadTimeout;
  2418. #if defined (RPC_GC_AUDIT)
  2419. long Temp;
  2420. #endif
  2421. long ThreadActivationDelay;
  2422. if (IocThreadStarted == 0)
  2423. {
  2424. IocThreadStarted = 1;
  2425. }
  2426. nThreadsAtCompletionPort.Increment();
  2427. if ((gProrateStart > 0) && ((DWORD)nThreadsAtCompletionPort.GetInteger() > gProrateStart))
  2428. {
  2429. ThreadActivationDelay = nThreadsAtCompletionPort.GetInteger() - gProrateStart;
  2430. if (ThreadActivationDelay > 0)
  2431. {
  2432. ThreadActivationDelay *= gProrateFactor;
  2433. if ((DWORD)ThreadActivationDelay > gProrateMax)
  2434. ThreadActivationDelay = gProrateMax;
  2435. Sleep(ThreadActivationDelay);
  2436. }
  2437. }
  2438. CurrentThread = RpcpGetThreadPointer();
  2439. ASSERT(CurrentThread);
  2440. ThreadDebugCell = CurrentThread->DebugCell;
  2441. if (ThreadDebugCell)
  2442. {
  2443. ThreadDebugCell->Status = dtsIdle;
  2444. ThreadDebugCell->LastUpdateTime = NtGetTickCount();
  2445. ThreadDebugCell->Endpoint.CellID = 0;
  2446. ThreadDebugCell->Endpoint.SectionID = 0;
  2447. }
  2448. while (1)
  2449. {
  2450. EventContext = hCompletionPortHandleForThread;
  2451. Status = ProcessCalls (Timeout,
  2452. &Event,
  2453. &EventStatus,
  2454. &EventContext,
  2455. &BufferLength,
  2456. &Buffer,
  2457. &pSourceContext);
  2458. if (Status == RPC_S_OK)
  2459. {
  2460. InterlockedDecrement(&NumThreads);
  2461. if (fThreadIsDoingLongWait)
  2462. {
  2463. fThreadIsDoingLongWait = FALSE;
  2464. #if defined (RPC_GC_AUDIT)
  2465. Temp = ThreadsDoingLongWait.Decrement();
  2466. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Thread %X: is coming back from long wait %d\n",
  2467. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), Temp);
  2468. #else
  2469. ThreadsDoingLongWait.Decrement();
  2470. #endif
  2471. }
  2472. Timeout = gThreadTimeout;
  2473. if (ThreadDebugCell)
  2474. {
  2475. ThreadDebugCell->Status = dtsProcessing;
  2476. ThreadDebugCell->LastUpdateTime = NtGetTickCount();
  2477. }
  2478. // capture the current activity state
  2479. nOldActivityValue = nActivityValue;
  2480. // indicate to the next thread that there's activity
  2481. nLocalActivityValue ++;
  2482. if ((nLocalActivityValue & 0xFF) == 0)
  2483. nActivityValue ++;
  2484. // make sure that the io event is within the bounds of the dispatch table
  2485. ASSERT(Event < sizeof(IOEventDispatchTable) / sizeof(IOEventDispatchTable[0]));
  2486. (*IOEventDispatchTable[Event])(this,
  2487. Event,
  2488. EventStatus,
  2489. EventContext,
  2490. BufferLength,
  2491. Buffer,
  2492. pSourceContext);
  2493. InterlockedIncrement(&NumThreads);
  2494. if (ThreadDebugCell)
  2495. {
  2496. ThreadDebugCell->Status = dtsIdle;
  2497. ThreadDebugCell->LastUpdateTime = NtGetTickCount();
  2498. }
  2499. }
  2500. else
  2501. {
  2502. BOOL fKeepThread = FALSE;
  2503. // N.B. If a thread times out waiting for an Irp, we should
  2504. // let it go, unless any one of the following conditions
  2505. // exist:
  2506. // - it is the last listening thread on the port
  2507. // - there is an Irp pending on it
  2508. // - the port is busy, and we are at or below the optimal
  2509. // number of threads for this number of processors
  2510. // N.B. The NumThreads and ThreadsDoingLongWait are not
  2511. // changed atomically with respect to each other. This
  2512. // opens a race condition, but the race is benign, if the
  2513. // simple rule below is kept.
  2514. // Whenever we change both NumThreads and
  2515. // ThreadsDoingLongWait, we must do so in a way that errs
  2516. // to less threads doing short wait, rather than more
  2517. // threads doing short wait. Thus we may scare somebody
  2518. // into not doing a long wait, but that's better rather
  2519. // than letting somebody do a long wait, and toasting the
  2520. // garbage collection. For overview of the garbage
  2521. // collection mechanism, see the header in GC.cxx
  2522. ASSERT(Status == RPC_P_TIMEOUT);
  2523. LocalNumThreads = InterlockedDecrement(&NumThreads);
  2524. PerformGarbageCollection();
  2525. if (!fThreadIsDoingLongWait)
  2526. {
  2527. // we will be conservative, and we will presume we will be
  2528. // doing a long wait. If we're not, we'll decrement it later
  2529. fThreadIsDoingLongWait = TRUE;
  2530. LocalThreadsDoingLongWait = ThreadsDoingLongWait.Increment();
  2531. }
  2532. else
  2533. {
  2534. // we were already doing a long wait - just grab the current
  2535. // value
  2536. LocalThreadsDoingLongWait = ThreadsDoingLongWait.GetInteger();
  2537. }
  2538. // if there are no threads on short wait, and either one-time garbage
  2539. // collection was requested (GarbageCollectionRequested), or items
  2540. // with periodic garbage collection are requested
  2541. // (PeriodicGarbageCollectItems > 0), we can't go on a long wait
  2542. if ((LocalNumThreads <= LocalThreadsDoingLongWait)
  2543. && (GarbageCollectionRequested || (PeriodicGarbageCollectItems > 0)))
  2544. {
  2545. #if defined (RPC_GC_AUDIT)
  2546. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Thread %X: garbage collection requested - doing short wait %d, %d, %d, %d\n",
  2547. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), LocalNumThreads,
  2548. LocalThreadsDoingLongWait, GarbageCollectionRequested, PeriodicGarbageCollectItems);
  2549. #endif
  2550. // if garbage collection was requested, and there are
  2551. // no threads doing a short wait, we can't do a long
  2552. // wait - indicate to the code below that gThreadTimeout
  2553. // is the maximum allowed thread timeout and decrement
  2554. // the number of threads doing a long wait (we incremented
  2555. // it above - this decrement restores it)
  2556. ASSERT (fThreadIsDoingLongWait);
  2557. ThreadsDoingLongWait.Decrement();
  2558. fThreadIsDoingLongWait = FALSE;
  2559. LocalMaxThreadTimeout = gThreadTimeout;
  2560. }
  2561. else
  2562. {
  2563. // signal the code below that there is no restriction on
  2564. // the timeout applied, and it is free to choose its
  2565. // timeout
  2566. LocalMaxThreadTimeout = UndefinedLocalThreadTimeout;
  2567. }
  2568. if (LocalNumThreads == 0)
  2569. {
  2570. fKeepThread = TRUE;
  2571. if (LocalMaxThreadTimeout == UndefinedLocalThreadTimeout)
  2572. {
  2573. #if defined (RPC_GC_AUDIT)
  2574. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Thread %X: Max thread timeout\n",
  2575. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  2576. #endif
  2577. ASSERT(fThreadIsDoingLongWait);
  2578. Timeout = INFINITE;
  2579. }
  2580. else
  2581. {
  2582. ASSERT(fThreadIsDoingLongWait == FALSE);
  2583. Timeout = LocalMaxThreadTimeout;
  2584. }
  2585. }
  2586. #ifdef RPC_OLD_IO_PROTECTION
  2587. else if (ThreadSelf()->InqProtectCount() > 1)
  2588. #else
  2589. // the simplest form of timing out threads introduces the following problem
  2590. // On an MP box, if we have N processors executing N threads, we need to keep
  2591. // an extra thread to listen for new requests. However, periodically, it will
  2592. // timeout, die, and then get recreated by one of the executing threads which
  2593. // picks a new call. This wastes cycles. If, on the other hand, on an MP box
  2594. // we keep N+1 threads around, we hurt scalability in the ASP case.
  2595. // We solve this problem by introducing the concept of a busy port. A port is
  2596. // busy if it has served within one timeout period approximately 2048 or more
  2597. // calls. If a port falls into the busy category, we don't let go the N+1th
  2598. // thread on an MP box. If the port has activity, but not enough to get into
  2599. // the busy category, we timeout the extra thread. 2048 is an arbitrary number
  2600. // where we switch trading memory for speed. nOptimalNumberOfThreads is
  2601. // the number of processors + 1 for this implementation.
  2602. // since nLocalActivityValue is updated once per 256 requests (to avoid sloshing)
  2603. // having a difference of 8 is approximately 2048 requests. There is wide
  2604. // margin of error, as it is possible for threads to be anywhere in the 256
  2605. // range and still count as nothing, but that's ok.
  2606. else if ((nThreadsAtCompletionPort.GetInteger() <= nOptimalNumberOfThreads)
  2607. && ((nOldActivityValue + 8) < nActivityValue))
  2608. #endif
  2609. {
  2610. fKeepThread = TRUE;
  2611. Timeout *= 2;
  2612. if (LocalMaxThreadTimeout == UndefinedLocalThreadTimeout)
  2613. LocalMaxThreadTimeout = MAX_THREAD_TIMEOUT;
  2614. // if by doubling we have exceeded the max timeout,
  2615. // drop back to it
  2616. if (Timeout > LocalMaxThreadTimeout)
  2617. {
  2618. Timeout = LocalMaxThreadTimeout;
  2619. }
  2620. // else
  2621. // {
  2622. // We could have checked whether Timeout still falls into
  2623. // the short wait category after doubling, but we know
  2624. // that short wait is gThreadTimeout, and after doubling
  2625. // it will be bigger. Therefore, we don't need to do this
  2626. // check
  2627. // }
  2628. if ((ULONG)Timeout > gThreadTimeout)
  2629. {
  2630. if (!fThreadIsDoingLongWait)
  2631. {
  2632. #if defined (RPC_GC_AUDIT)
  2633. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Thread %X: Doing long wait: %d\n",
  2634. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), Timeout);
  2635. #endif
  2636. fThreadIsDoingLongWait = TRUE;
  2637. ThreadsDoingLongWait.Increment();
  2638. }
  2639. }
  2640. }
  2641. else
  2642. {
  2643. ASSERT(fKeepThread == FALSE);
  2644. }
  2645. nOldActivityValue = nActivityValue;
  2646. if (fKeepThread)
  2647. {
  2648. InterlockedIncrement(&NumThreads);
  2649. if (ThreadDebugCell)
  2650. {
  2651. RelocateCellIfPossible((void **) &ThreadDebugCell, &CurrentThread->DebugCellTag);
  2652. CurrentThread->DebugCell = ThreadDebugCell;
  2653. }
  2654. }
  2655. else
  2656. {
  2657. if (fThreadIsDoingLongWait)
  2658. {
  2659. ThreadsDoingLongWait.Decrement();
  2660. }
  2661. else
  2662. {
  2663. // the only way this thread can be here is if
  2664. // all other threads are on long wait
  2665. ASSERT(LocalNumThreads <= LocalThreadsDoingLongWait);
  2666. // in this case, make a best effort to tickle one
  2667. // of the threads on a long wait. We ignore the result.
  2668. // This is ok, because it will only delay the gc until
  2669. // on of the long wait threads comes back.
  2670. TickleIocThread();
  2671. }
  2672. break;
  2673. }
  2674. }
  2675. }
  2676. nThreadsAtCompletionPort.Decrement();
  2677. if (ThreadDebugCell)
  2678. {
  2679. ThreadDebugCell->Status = dtsAllocated;
  2680. ThreadDebugCell->LastUpdateTime = NtGetTickCount();
  2681. }
  2682. ReleaseHandleForThread(hCompletionPortHandleForThread);
  2683. }