Leaked source code of windows server 2003
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.

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