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.

1206 lines
28 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. String.cxx
  5. Abstract:
  6. Methods of construction of various kinds of DUALSTRINGARRAYs.
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 04-01-95 Bits 'n pieces
  11. MarioGO 01-??-96 STRINGARRAYs replaced by DUALSTRINGARRAYs
  12. --*/
  13. #include <or.hxx>
  14. #include <mach.hxx>
  15. static CONST WCHAR aCallbackSecurity[] = L"Security=Identification Dynamic True";
  16. static CONST DWORD dwCallbackSecurityLength = sizeof(aCallbackSecurity)/sizeof(WCHAR);
  17. HRESULT dsaAllocateAndCopy(DUALSTRINGARRAY** ppdsaDest, DUALSTRINGARRAY* pdsaSrc)
  18. {
  19. ASSERT(ppdsaDest);
  20. ASSERT(pdsaSrc);
  21. ASSERT(dsaValid(pdsaSrc));
  22. *ppdsaDest = NULL;
  23. DWORD dwDSASize = sizeof(USHORT) +
  24. sizeof(USHORT) +
  25. (pdsaSrc->wNumEntries * sizeof(WCHAR));
  26. *ppdsaDest = (DUALSTRINGARRAY*)MIDL_user_allocate(dwDSASize);
  27. if (*ppdsaDest)
  28. {
  29. // copy in the string bindings
  30. memcpy(*ppdsaDest, pdsaSrc, dwDSASize);
  31. ASSERT(dsaValid(*ppdsaDest));
  32. return S_OK;
  33. }
  34. return E_OUTOFMEMORY;
  35. }
  36. RPC_BINDING_HANDLE
  37. GetBinding(
  38. IN PWSTR pCompressedBinding
  39. )
  40. {
  41. ASSERT(pCompressedBinding);
  42. PWSTR pwstrStringBinding;
  43. PWSTR pwstrProtseq = GetProtseq(*pCompressedBinding);
  44. PWSTR pwstrT;
  45. RPC_STATUS Status;
  46. RPC_BINDING_HANDLE bhReturn;
  47. BOOL fLocal = FALSE;
  48. if (!pwstrProtseq)
  49. {
  50. return(0);
  51. }
  52. size_t size = OrStringLen(pwstrProtseq) + OrStringLen(pCompressedBinding);
  53. if (*pCompressedBinding == ID_LPC)
  54. {
  55. fLocal = TRUE;
  56. size += dwCallbackSecurityLength + 1; // +1 for ','
  57. }
  58. pwstrStringBinding = (PWSTR) alloca(size * sizeof(USHORT));
  59. if (!pwstrStringBinding)
  60. {
  61. return(0);
  62. }
  63. OrStringCopy(pwstrStringBinding, pwstrProtseq);
  64. pwstrT = OrStringSearch(pwstrStringBinding, 0);
  65. *pwstrT = L':';
  66. pwstrT++;
  67. *pwstrT = 0;
  68. OrStringCopy(pwstrT, pCompressedBinding + 1);
  69. if (fLocal)
  70. {
  71. // We assume we have an endpoint.
  72. pwstrT = OrStringSearch(pwstrT, 0);
  73. pwstrT--;
  74. if (*pwstrT != L']')
  75. {
  76. KdPrintEx((DPFLTR_DCOMSS_ID,
  77. DPFLTR_WARNING_LEVEL,
  78. "OR: Local string binding missing endpoint %S\n",
  79. pwstrStringBinding));
  80. ASSERT(0);
  81. return(0);
  82. }
  83. *pwstrT = L',';
  84. pwstrT++;
  85. OrStringCopy(pwstrT, aCallbackSecurity);
  86. pwstrT = OrStringSearch(pwstrT, 0);
  87. *pwstrT = L']';
  88. *(pwstrT + 1) = 0;
  89. }
  90. Status =
  91. RpcBindingFromStringBinding( pwstrStringBinding,
  92. &bhReturn);
  93. if (Status != RPC_S_OK)
  94. {
  95. KdPrintEx((DPFLTR_DCOMSS_ID,
  96. DPFLTR_WARNING_LEVEL,
  97. "OR: Unable to create binding for %S = %d\n",
  98. pwstrStringBinding,
  99. Status));
  100. bhReturn = NULL;
  101. }
  102. return(bhReturn);
  103. }
  104. RPC_BINDING_HANDLE
  105. GetBindingToOr(
  106. IN PWSTR pwstrCompressedBinding
  107. )
  108. /*++
  109. Routine Description:
  110. Gets an RPC binding to a remote object resolver given
  111. a compressed string binding to the remote object resolver.
  112. Arguments:
  113. pwstrCompressedBinding - a compressed string binding without an endpoint.
  114. Return Value:
  115. 0 - failed to allocate memory or RpcBindingFromStringBinding failed.
  116. non-NULL - completed okay
  117. --*/
  118. {
  119. PWSTR protseq, endpoint;
  120. PWSTR strbinding;
  121. size_t len;
  122. RPC_BINDING_HANDLE bh = 0;
  123. ASSERT(pwstrCompressedBinding);
  124. ASSERT(*pwstrCompressedBinding != 0);
  125. protseq = GetProtseq(*pwstrCompressedBinding);
  126. endpoint = GetEndpoint(*pwstrCompressedBinding);
  127. if (0 == protseq || 0 == endpoint)
  128. {
  129. ASSERT(0);
  130. return(0);
  131. }
  132. len = 4; // ':' '[' ']' and '\0'
  133. len += OrStringLen(protseq);
  134. len += OrStringLen(endpoint);
  135. len += OrStringLen(&pwstrCompressedBinding[1]);
  136. strbinding = new USHORT[len];
  137. if (strbinding)
  138. {
  139. PWSTR pwstrT;
  140. OrStringCopy(strbinding, protseq); // protseq
  141. pwstrT = OrStringSearch(strbinding, 0); // :
  142. *pwstrT = L':';
  143. pwstrT++;
  144. *pwstrT = 0;
  145. OrStringCat(strbinding, &pwstrCompressedBinding[1]); // network address
  146. pwstrT = OrStringSearch(strbinding, 0); // [
  147. *pwstrT = L'[';
  148. pwstrT++;
  149. *pwstrT = 0;
  150. OrStringCat(strbinding, endpoint); // endpoint
  151. pwstrT = OrStringSearch(strbinding, 0); // ]
  152. *pwstrT = L']';
  153. pwstrT++;
  154. *pwstrT = 0;
  155. RPC_STATUS status = RpcBindingFromStringBinding(strbinding, &bh);
  156. ASSERT(bh == 0 || status == RPC_S_OK);
  157. delete strbinding;
  158. }
  159. if (bh == 0)
  160. {
  161. KdPrintEx((DPFLTR_DCOMSS_ID,
  162. DPFLTR_INFO_LEVEL,
  163. "OR: Unable to bind to %S\n",
  164. pwstrCompressedBinding + 1));
  165. }
  166. return(bh);
  167. }
  168. DUALSTRINGARRAY *
  169. GetStringBinding(
  170. IN PWSTR pwstrCompressed,
  171. IN PWSTR pwstrSecurityBindings
  172. )
  173. /*++
  174. Routine Description:
  175. Converts the compressed string binding into an expanded
  176. string binding. An enpoint maybe optionally specified.
  177. Arguments:
  178. pwstrCompressed - a compressed string binding
  179. pwstrSecurityBindings - optional security bindings
  180. too be tacked onto the end of the expanded string binding.
  181. Terminated by two nulls.
  182. Return Value:
  183. NULL - out of memory
  184. non-NULL - a string binding. Allocated with MIDL_user_allocate.
  185. --*/
  186. {
  187. DUALSTRINGARRAY *pT;
  188. PWSTR protseq;
  189. USHORT seccount;
  190. PWSTR t = pwstrSecurityBindings;
  191. if (t && *t)
  192. {
  193. seccount = 0;
  194. do
  195. {
  196. seccount++;
  197. t++;
  198. if (*t == 0)
  199. {
  200. seccount++;
  201. t++;
  202. }
  203. }
  204. while (*t);
  205. seccount++; // final NULL
  206. }
  207. else
  208. {
  209. // Two nulls only.
  210. seccount = 2;
  211. }
  212. protseq = GetProtseq(*pwstrCompressed);
  213. if (!protseq)
  214. return NULL; // not out of memory -- means bindings contained bogus tower id
  215. size_t l = OrStringLen(pwstrCompressed) + OrStringLen(protseq) + seccount + 1 + 1;
  216. pT =(DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY) + l * sizeof(WCHAR));
  217. if (!pT)
  218. {
  219. return(0);
  220. }
  221. pT->wNumEntries = (USHORT) l;
  222. OrStringCopy(pT->aStringArray, protseq);
  223. OrStringCat(pT->aStringArray, L":");
  224. OrStringCat(pT->aStringArray, pwstrCompressed + 1);
  225. if (pwstrSecurityBindings)
  226. {
  227. PWSTR t = pT->aStringArray;
  228. t = OrStringSearch(t, 0);
  229. t++;
  230. *t = 0; // Second NULL on string bindings.
  231. t++;
  232. OrMemoryCopy(t, pwstrSecurityBindings, seccount*sizeof(WCHAR));
  233. }
  234. else
  235. {
  236. // Add three NULLs, total of four.
  237. PWSTR t = pT->aStringArray;
  238. t = OrStringSearch(t, 0);
  239. t[1] = 0;
  240. t[2] = 0;
  241. t[3] = 0;
  242. }
  243. pT->wSecurityOffset = pT->wNumEntries - seccount;
  244. ASSERT(dsaValid(pT));
  245. return(pT);
  246. }
  247. ORSTATUS
  248. ConvertToRemote(
  249. IN DUALSTRINGARRAY *pdsaLocal,
  250. OUT DUALSTRINGARRAY **ppdsaRemote
  251. )
  252. /* ++
  253. Parameters:
  254. pdsaLocal - An array of string bindings with compressed protseqs.
  255. ppdsaRemote - Will contain only those string bindings in pdsaLocal
  256. which are not "IsLocal()".
  257. Note: *ppdsaRemote maybe used as a flag, don't set it to non-NULL
  258. until it is valid.
  259. -- */
  260. {
  261. USHORT iTotalSize;
  262. USHORT iSize;
  263. USHORT *p1, *p2;
  264. DUALSTRINGARRAY *pdsaT;
  265. // Size remote array
  266. // Final null terminator
  267. iSize = 1;
  268. p1 = pdsaLocal->aStringArray;
  269. while (*p1)
  270. {
  271. if (! IsLocal(*p1) )
  272. {
  273. iSize += (USHORT) OrStringLen(p1) + 1;
  274. }
  275. p1 = OrStringSearch(p1, 0) + 1;
  276. }
  277. if (iSize == 1)
  278. {
  279. iSize = 2; // No non-local strings, need two terminators.
  280. }
  281. iTotalSize = iSize + (pdsaLocal->wNumEntries - pdsaLocal->wSecurityOffset);
  282. pdsaT = new(iTotalSize * sizeof(WCHAR)) DUALSTRINGARRAY;
  283. if (!pdsaT)
  284. {
  285. return(OR_NOMEM);
  286. }
  287. pdsaT->wNumEntries = iTotalSize;
  288. pdsaT->wSecurityOffset = iSize;
  289. p2 = pdsaT->aStringArray;
  290. // Copy security bindings
  291. OrMemoryCopy(p2 + iSize,
  292. pdsaLocal->aStringArray + pdsaLocal->wSecurityOffset,
  293. (iTotalSize - iSize) * sizeof(WCHAR));
  294. if (iSize == 2)
  295. {
  296. // No non-local strings, fill in terminators and return.
  297. *p2 = 0;
  298. *(p2 + 1) = 0;
  299. *ppdsaRemote = pdsaT;
  300. ASSERT(dsaValid(pdsaT));
  301. return(OR_OK);
  302. }
  303. p1 = pdsaLocal->aStringArray;
  304. while (*p1)
  305. {
  306. if ( ! IsLocal(*p1) )
  307. {
  308. OrStringCopy(p2, p1);
  309. p2 = OrStringSearch(p2, 0) + 1;
  310. }
  311. p1 = OrStringSearch(p1, 0) + 1;
  312. }
  313. *p2 = 0; // Second terminator.
  314. *ppdsaRemote = pdsaT;
  315. ASSERT(dsaValid(pdsaT));
  316. return(OR_OK);
  317. }
  318. DUALSTRINGARRAY *
  319. CompressStringArrayAndAddIPAddrs(
  320. IN DUALSTRINGARRAY *pdsaExpanded
  321. )
  322. /*++
  323. Routine Description:
  324. Converts a stringarray of regular string bindings into a
  325. compressed (protseq's replaced with WORD id's) array of
  326. string bindings.
  327. Arguments:
  328. pdsaExpanded - the string array to compress.
  329. Security information is copied.
  330. Return Value:
  331. 0 - failed to allocate memory.
  332. non-0 - compressed string array.
  333. --*/
  334. {
  335. size_t i, size;
  336. USHORT *p1, *p2, *p3;
  337. PWSTR pwstr;
  338. DUALSTRINGARRAY *pdsaCompressed;
  339. CIPAddrs* pIPAddrs = gpMachineName->GetIPAddrs();
  340. ULONG cIPAddrs = 0;
  341. // Possible for gpMachineName->GetIPAddrs to return NULL.
  342. if (pIPAddrs)
  343. {
  344. ASSERT(pIPAddrs->_pIPAddresses);
  345. cIPAddrs = pIPAddrs->_pIPAddresses->Count;
  346. }
  347. // Compute size of result.
  348. p1 = pdsaExpanded->aStringArray;
  349. size = pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset;
  350. if (*p1 == 0)
  351. {
  352. size += 2; // two null terminators ONLY.
  353. }
  354. else
  355. {
  356. size += 1; // last null terminator
  357. }
  358. while (*p1)
  359. {
  360. size_t sizeT = OrStringLen(p1);
  361. p2 = OrStringSearch(p1, L':'); // ':' is not valid in protseq.
  362. if (p2)
  363. {
  364. // proseq len (p2 - p1) become 1 for Id.
  365. size_t newLen = (sizeT + 1 - (size_t)(p2 - p1));
  366. size += newLen;
  367. *p2 = 0; // subst NULL just for the compare
  368. if ((lstrcmpW(L"ncacn_ip_tcp", p1) == 0) ||
  369. (lstrcmpW(L"ncadg_ip_udp", p1) == 0) ||
  370. (lstrcmpW(L"ncacn_http", p1) == 0))
  371. {
  372. if (pIPAddrs)
  373. {
  374. size += pIPAddrs->_pIPAddresses->StringBufferSpace;
  375. }
  376. }
  377. *p2 = L':'; // put the colon back in
  378. p1 = OrStringSearch(p2, 0) + 1;
  379. }
  380. else
  381. {
  382. // Prefix bug: if we got here, this would mean we found a binding
  383. // that did not have a colon, and we would then have passed a NULL
  384. // p2 to OrStringSearch. This code is so old I doubt that this
  385. // case ever has been or will be hit, but better to do the right thing.
  386. ASSERT(0 && "Malformed binding");
  387. if (pIPAddrs)
  388. pIPAddrs->DecRefCount();
  389. return NULL;
  390. }
  391. }
  392. pdsaCompressed = new(size * sizeof(WCHAR)) DUALSTRINGARRAY;
  393. if (0 == pdsaCompressed)
  394. {
  395. if (pIPAddrs)
  396. pIPAddrs->DecRefCount();
  397. return(0);
  398. }
  399. p3 = pdsaCompressed->aStringArray;
  400. *p3 = 0;
  401. p1 = pdsaExpanded->aStringArray;
  402. if (*p1 == 0)
  403. {
  404. // Loop won't be entered, point p3 to second null terminator
  405. p3++;
  406. }
  407. while (*p1)
  408. {
  409. p2 = OrStringSearch(p1, L':');
  410. if (p2)
  411. {
  412. USHORT TowerId;
  413. *p2 = 0;
  414. *p3 = TowerId = GetProtseqId(p1);
  415. *p2 = L':';
  416. if (*p3 != 0)
  417. {
  418. p3++;
  419. p1 = p2 + 1; // Just after ':'
  420. OrStringCopy(p3, p1);
  421. // Move p3 to start of next string if any.
  422. p3 = OrStringSearch(p3, 0) + 1;
  423. //
  424. // add in IP addresses for TCP/IP and UDP/IP
  425. //
  426. if ((TowerId == ID_TCP) || (TowerId == ID_UDP) || (ID_DCOMHTTP == TowerId))
  427. {
  428. ULONG i;
  429. p2 = OrStringSearch(p1, L'[');
  430. if (p2)
  431. {
  432. for (i=0; i<cIPAddrs; i++)
  433. {
  434. // do not include the loopback address in server bindings
  435. if (lstrcmpW(L"127.0.0.1", pIPAddrs->_pIPAddresses->NetworkAddresses[i]) != 0)
  436. {
  437. *p3 = TowerId;
  438. p3++;
  439. // copy in IP address
  440. OrStringCopy(p3, pIPAddrs->_pIPAddresses->NetworkAddresses[i]);
  441. p3 = OrStringSearch(p3, 0);
  442. // copy in rest of string binding
  443. OrStringCopy(p3, p2);
  444. // Move p3 to start of next string if any.
  445. p3 = OrStringSearch(p3, 0) + 1;
  446. }
  447. }
  448. }
  449. }
  450. }
  451. }
  452. // Move p1 to start of next string if any.
  453. p1 = OrStringSearch(p1, 0) + 1;
  454. }
  455. // Second terminator, p3 already points to it.
  456. *p3 = 0;
  457. pdsaCompressed->wSecurityOffset = (USHORT) (p3 + 1 - pdsaCompressed->aStringArray );
  458. pdsaCompressed->wNumEntries = pdsaCompressed->wSecurityOffset +
  459. (pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset);
  460. // Copy security bindings
  461. OrMemoryCopy(p3 + 1,
  462. pdsaExpanded->aStringArray + pdsaExpanded->wSecurityOffset,
  463. (pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset) * sizeof(WCHAR));
  464. ASSERT(dsaValid(pdsaCompressed));
  465. if (pIPAddrs)
  466. pIPAddrs->DecRefCount();
  467. return(pdsaCompressed);
  468. }
  469. USHORT
  470. FindMatchingProtseq(
  471. IN USHORT cClientProtseqs,
  472. IN USHORT aClientProtseqs[],
  473. IN PWSTR pwstrServerBindings
  474. )
  475. /*++
  476. Routine Description:
  477. Finds the first protseq id in aClientProtseqs which appears in any of
  478. the server bindings.
  479. Arguments:
  480. cClientProtseqs - the number of entries in aClientProtseqs.
  481. aClientProtseqs - Protseq tower id's support by the client.
  482. pwstrServerBindings - compressed array of bindings supported by the server
  483. terminated by two NULLs.
  484. Return Value:
  485. 0 - no match found.
  486. non-0 - the matching protseq id.
  487. --*/
  488. // Called by server oxid's and processes when checking for lazy use protseq.
  489. {
  490. ULONG i;
  491. if (0 == cClientProtseqs)
  492. {
  493. return(0);
  494. }
  495. while (*pwstrServerBindings)
  496. {
  497. for (i = 0; i < cClientProtseqs; i++)
  498. {
  499. if (aClientProtseqs[i] == *pwstrServerBindings)
  500. {
  501. return(aClientProtseqs[i]);
  502. }
  503. }
  504. pwstrServerBindings = OrStringSearch(pwstrServerBindings, 0) + 1;
  505. }
  506. return(0);
  507. }
  508. PWSTR
  509. FindMatchingProtseq(
  510. IN USHORT protseq,
  511. IN PWSTR pwstrCompressedBindings
  512. )
  513. /*++
  514. Routine Description:
  515. Searches a compressed string array for an entry which
  516. matches a particular protseq.
  517. Arguments:
  518. protseq - The protseq to search for.
  519. pwstrCompressedBindings - The bindings to search.
  520. Return Value:
  521. 0 - not found
  522. non-0 - a pointer into the pwstrCompressedBindings
  523. --*/
  524. {
  525. ASSERT(pwstrCompressedBindings);
  526. while (*pwstrCompressedBindings)
  527. {
  528. if (*pwstrCompressedBindings == protseq)
  529. {
  530. return(pwstrCompressedBindings);
  531. }
  532. pwstrCompressedBindings = OrStringSearch(pwstrCompressedBindings, 0) + 1;
  533. }
  534. return(0);
  535. }
  536. PWSTR
  537. FindMatchingProtseq(
  538. IN PWSTR pMachineName,
  539. IN USHORT protseq,
  540. IN PWSTR pwstrCompressedBindings
  541. )
  542. /*++
  543. Routine Description:
  544. Searches a compressed string array for an entry which
  545. matches a particular protseq and machine
  546. Arguments:
  547. protseq - The protseq to search for.
  548. pMachine - the machine name to search for.
  549. pwstrCompressedBindings - The bindings to search.
  550. Return Value:
  551. 0 - not found
  552. non-0 - a pointer into the pwstrCompressedBindings
  553. --*/
  554. {
  555. ASSERT(pwstrCompressedBindings);
  556. while (*pwstrCompressedBindings)
  557. {
  558. if (*pwstrCompressedBindings == protseq)
  559. {
  560. PWSTR pwstrMachineNameTemp = pMachineName;
  561. WCHAR* pwstrT = pwstrCompressedBindings + 1;
  562. BOOL fSkip = FALSE;
  563. while (*pwstrT && *pwstrMachineNameTemp && ((*pwstrT != L'[') || fSkip))
  564. {
  565. fSkip = (*pwstrT == L'\\') && !fSkip;
  566. if (towupper(*pwstrMachineNameTemp) != towupper(*pwstrT))
  567. {
  568. break;
  569. }
  570. pwstrT++;
  571. pwstrMachineNameTemp++;
  572. }
  573. if (!*pwstrMachineNameTemp && (!*pwstrT || (*pwstrT == L'[')))
  574. {
  575. return pwstrCompressedBindings;
  576. }
  577. }
  578. pwstrCompressedBindings = OrStringSearch(pwstrCompressedBindings, 0) + 1;
  579. }
  580. return(0);
  581. }
  582. WCHAR *
  583. ExtractMachineName(WCHAR *pSB)
  584. {
  585. pSB++;
  586. WCHAR* pwstrT = pSB;
  587. BOOL fSkip = FALSE;
  588. while (*pwstrT && ((*pwstrT != L'[') || fSkip))
  589. {
  590. fSkip = (*pwstrT == L'\\') && !fSkip;
  591. pwstrT++;
  592. }
  593. ULONG len = (ULONG)(pwstrT - pSB);
  594. if (len)
  595. {
  596. WCHAR* pMachineName;
  597. pMachineName = new WCHAR[len + 1];
  598. if (pMachineName)
  599. {
  600. memcpy(pMachineName, pSB, (UINT)((pwstrT - pSB) * sizeof(WCHAR)));
  601. pMachineName[len] = 0;
  602. return pMachineName;
  603. }
  604. }
  605. return NULL;
  606. }
  607. RPC_BINDING_HANDLE
  608. TestBindingGetHandle(
  609. IN PWSTR pwstrCompressedBinding
  610. )
  611. /*++
  612. Routine Description:
  613. Tests that an OR can be found on the machine identified by the
  614. compressed binding.
  615. Arguments:
  616. pwstrCompressedBiding - A compressed stringing binding to the
  617. server in question. May include an endpoint to something
  618. other then the endpoint mapper.
  619. Return Value:
  620. None
  621. --*/
  622. {
  623. PWSTR pwstrT;
  624. PWSTR pwstrCopy = (PWSTR)alloca( (OrStringLen(pwstrCompressedBinding) + 1)
  625. * sizeof(WCHAR) );
  626. if (pwstrCopy == 0)
  627. {
  628. return(FALSE);
  629. }
  630. OrStringCopy(pwstrCopy, pwstrCompressedBinding);
  631. // We need to wack the endpoint out of the string binding.
  632. // Go read the runtime's string parsing stuff if you're not
  633. // sure what this is doing. Note: on Win9x this needs to
  634. // be DBCS enabled...
  635. #ifndef NTENV
  636. #message "Error: string.cxx(): this won't work"
  637. #endif
  638. pwstrT = pwstrCopy;
  639. while (*pwstrT && *pwstrT != L'[')
  640. pwstrT++;
  641. if (*pwstrT)
  642. {
  643. ASSERT(*pwstrT == L'[');
  644. *pwstrT = 0;
  645. // Endpoint gone.
  646. }
  647. return GetBindingToOr(pwstrCopy);
  648. }
  649. //////////////////////////////////////////////////////////////////////////////
  650. //
  651. // CDualStringArray methods
  652. //
  653. DWORD CDualStringArray::AddRef()
  654. {
  655. ASSERT(_cRef != 0);
  656. DWORD cRef = InterlockedIncrement(&_cRef);
  657. return cRef;
  658. }
  659. DWORD CDualStringArray::Release()
  660. {
  661. ASSERT(_cRef > 0);
  662. DWORD cRef = InterlockedDecrement(&_cRef);
  663. if (cRef == 0)
  664. {
  665. delete this;
  666. }
  667. return cRef;
  668. }
  669. CDualStringArray::~CDualStringArray()
  670. {
  671. ASSERT(_cRef == 0);
  672. // free the dual string array
  673. MIDL_user_free( _pdsa );
  674. }
  675. //
  676. //////////////////////////////////////////////////////////////////////////////
  677. RPC_STATUS CParallelPing::Ping()
  678. /*++
  679. Routine Description:
  680. Calls ServerAlive2 on all supplied bindings asyncronously. First binding
  681. that completles succesfully is chosen. Remaining calls are cancelled.
  682. Arguments:
  683. None;
  684. Return Value:
  685. RPC_S_OK
  686. RPC_S_CALL_FAILED
  687. --*/
  688. {
  689. ULONG cHandlesMax = 0;
  690. const ULONG cBlockSize = 10;
  691. _cCalls = 0;
  692. _cReceived = 0;
  693. _arAsyncCallInfo = NULL;
  694. //
  695. // First ping that succeeds sets _ndxWinner to it's index + 1
  696. //
  697. _ndxWinner = 0;
  698. //
  699. // send off all the calls
  700. //
  701. RPC_STATUS sc;
  702. ULONG i;
  703. for (i=0; _ndxWinner == 0; i++)
  704. {
  705. //
  706. // allocate/resize arrays to hold call state
  707. //
  708. if (i >= cHandlesMax)
  709. {
  710. REALLOC(MIDL_user_allocate, MIDL_user_free,
  711. PRPC_ASYNC_STATE,
  712. _arAsyncCallInfo, cHandlesMax, cHandlesMax+cBlockSize, sc)
  713. if (FAILED(sc))
  714. {
  715. break;
  716. }
  717. memset(_arAsyncCallInfo+cHandlesMax, 0, (sizeof(PRPC_ASYNC_STATE) * cBlockSize));
  718. cHandlesMax += cBlockSize;
  719. }
  720. if (i >= _cProtseqMax)
  721. {
  722. REALLOC(MIDL_user_allocate, MIDL_user_free,
  723. PROTSEQINFO, _pProtseqInfo,
  724. _cProtseqMax, _cProtseqMax+cBlockSize, sc)
  725. if (FAILED(sc))
  726. {
  727. break;
  728. }
  729. _cProtseqMax += cBlockSize;
  730. }
  731. if (i == _cHandles)
  732. {
  733. // get more handles
  734. if (!NextCall(_pProtseqInfo+i))
  735. {
  736. // no more, so we're done
  737. break;
  738. }
  739. _cHandles++;
  740. //
  741. // turn off serialization
  742. //
  743. sc = RpcBindingSetOption(_pProtseqInfo[i].hRpc, RPC_C_OPT_BINDING_NONCAUSAL, TRUE);
  744. if (sc != RPC_S_OK)
  745. {
  746. break;
  747. }
  748. //
  749. // Initialize the COM version, to the minimum (so if the call
  750. // fails with RPC_S_PROCNUM_OUT_OF_RANGE, we know the right
  751. // answer.
  752. //
  753. _pProtseqInfo[i].comVersion.MajorVersion = 5;
  754. _pProtseqInfo[i].comVersion.MinorVersion = 1;
  755. }
  756. if (_pProtseqInfo[i].hRpc == NULL)
  757. {
  758. continue;
  759. }
  760. _arAsyncCallInfo[i] = (PRPC_ASYNC_STATE) MIDL_user_allocate(sizeof(RPC_ASYNC_STATE));
  761. if (_arAsyncCallInfo[i] == NULL)
  762. {
  763. sc = RPC_S_OUT_OF_MEMORY;
  764. break;
  765. }
  766. //
  767. // set up async information
  768. //
  769. sc = RpcAsyncInitializeHandle(_arAsyncCallInfo[i],
  770. sizeof(RPC_ASYNC_STATE));
  771. //
  772. // If this succeeds we pass the ownership of _arAsyncCallInfo[i] to the callback
  773. //
  774. if (sc != RPC_S_OK)
  775. {
  776. MIDL_user_free(_arAsyncCallInfo[i]);
  777. _arAsyncCallInfo[i] = NULL;
  778. break;
  779. }
  780. _arAsyncCallInfo[i]->NotificationType = RpcNotificationTypeApc;
  781. _arAsyncCallInfo[i]->u.APC.NotificationRoutine = ServerAliveAPC;
  782. _arAsyncCallInfo[i]->u.APC.hThread = 0;
  783. _arAsyncCallInfo[i]->UserInfo = (void *)this;
  784. _cCalls++;
  785. //
  786. // begin the call
  787. //
  788. RPC_STATUS ret = ServerAlive2( _arAsyncCallInfo[i],
  789. _pProtseqInfo[i].hRpc,
  790. &(_pProtseqInfo[i].comVersion),
  791. &_tmpOrBindings,
  792. &_tmpReserved );
  793. if (ret != RPC_S_OK)
  794. {
  795. ServerAliveWork(_arAsyncCallInfo[i], ret);
  796. }
  797. else
  798. {
  799. //
  800. // stagger the calls
  801. //
  802. SleepEx(PARALLEL_PING_STAGGER_TIME, TRUE);
  803. }
  804. }
  805. //
  806. // wait for successful ping or for all calls to
  807. // return
  808. //
  809. while ( (_ndxWinner == 0) && ((_cCalls - _cReceived) > 0) )
  810. {
  811. SleepEx(INFINITE, TRUE);
  812. }
  813. //
  814. // Cancel the calls left outstanding if there are any
  815. //
  816. if ((_cCalls - _cReceived) > 0)
  817. {
  818. for (i = 0; i<_cHandles; i++)
  819. {
  820. if (_arAsyncCallInfo[i] != NULL)
  821. {
  822. // we purposely ignore the return code here. Even if it failed
  823. // there wouldn't be much we could do.
  824. RPC_STATUS retDontCare = RpcAsyncCancelCall(_arAsyncCallInfo[i], TRUE);
  825. if (retDontCare != RPC_S_OK)
  826. {
  827. KdPrintEx((DPFLTR_DCOMSS_ID,
  828. DPFLTR_WARNING_LEVEL,
  829. "OR: RpcAsyncCancelCall failed - this is non-fatal; ret=%d\n",
  830. retDontCare));
  831. }
  832. }
  833. }
  834. //
  835. // wait for cancelled calls to return
  836. //
  837. while ( (_cCalls - _cReceived) > 0)
  838. {
  839. SleepEx(INFINITE, TRUE);
  840. }
  841. }
  842. // Free call infos
  843. if (_arAsyncCallInfo)
  844. {
  845. #if DBG
  846. for (i=0; i < cHandlesMax; ++i)
  847. {
  848. ASSERT(_arAsyncCallInfo[i] == NULL);
  849. }
  850. #endif
  851. MIDL_user_free(_arAsyncCallInfo);
  852. }
  853. //
  854. // return results
  855. //
  856. _arAsyncCallInfo = NULL;
  857. if (_ndxWinner != 0)
  858. {
  859. _pWinner = _pProtseqInfo + _ndxWinner - 1;
  860. return RPC_S_OK;
  861. }
  862. else
  863. {
  864. _pWinner = NULL;
  865. //
  866. // give precedence to failure which occured while attempting
  867. // to make calls.
  868. //
  869. if (sc != RPC_S_OK)
  870. {
  871. return sc;
  872. }
  873. else
  874. {
  875. ASSERT(_sc != RPC_S_OK);
  876. return _sc;
  877. }
  878. }
  879. }
  880. void ServerAliveAPC( IN PRPC_ASYNC_STATE pAsyncState,
  881. IN void *Context,
  882. IN RPC_ASYNC_EVENT Flags)
  883. {
  884. CParallelPing *pParallelPing = (CParallelPing *)pAsyncState->UserInfo;
  885. pParallelPing->ServerAliveWork(pAsyncState, RPC_S_OK);
  886. }
  887. void CParallelPing::ServerAliveWork( PRPC_ASYNC_STATE pAsyncState, RPC_STATUS scBegin)
  888. {
  889. RPC_STATUS tmpStatus;
  890. _tmpOrBindings = NULL;
  891. if (scBegin == RPC_S_OK)
  892. {
  893. _sc = RpcAsyncCompleteCall(pAsyncState, &tmpStatus);
  894. }
  895. else
  896. {
  897. _sc = scBegin;
  898. }
  899. // If there are no saved bindings, save these.
  900. if (_pdsaOrBindings == NULL && dsaValid(_tmpOrBindings))
  901. {
  902. _pdsaOrBindings = _tmpOrBindings;
  903. _tmpOrBindings = NULL;
  904. }
  905. else
  906. {
  907. MIDL_user_free( _tmpOrBindings );
  908. _tmpOrBindings = NULL;
  909. }
  910. _cReceived++;
  911. ULONG uMyIndex = 0;
  912. for (uMyIndex=0; uMyIndex < _cHandles; ++uMyIndex)
  913. {
  914. if (_arAsyncCallInfo[uMyIndex] == pAsyncState)
  915. {
  916. MIDL_user_free(pAsyncState);
  917. _arAsyncCallInfo[uMyIndex] = NULL;
  918. break;
  919. }
  920. }
  921. if (uMyIndex == _cHandles)
  922. {
  923. ASSERT(uMyIndex < _cHandles);
  924. return;
  925. }
  926. //
  927. // First protocol to succeed is the winner
  928. //
  929. if (_ndxWinner == 0)
  930. {
  931. if ((_sc == RPC_S_OK) || (_sc == RPC_S_PROCNUM_OUT_OF_RANGE))
  932. {
  933. _ndxWinner = uMyIndex + 1;
  934. _sc = RPC_S_OK;
  935. }
  936. }
  937. }