Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1198 lines
27 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. int 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 DBG
  94. if (Status != RPC_S_OK)
  95. {
  96. KdPrintEx((DPFLTR_DCOMSS_ID,
  97. DPFLTR_WARNING_LEVEL,
  98. "OR: Unable to create binding for %S = %d\n",
  99. pwstrStringBinding,
  100. Status));
  101. }
  102. #endif
  103. return(bhReturn);
  104. }
  105. RPC_BINDING_HANDLE
  106. GetBindingToOr(
  107. IN PWSTR pwstrCompressedBinding
  108. )
  109. /*++
  110. Routine Description:
  111. Gets an RPC binding to a remote object resolver given
  112. a compressed string binding to the remote object resolver.
  113. Arguments:
  114. pwstrCompressedBinding - a compressed string binding without an endpoint.
  115. Return Value:
  116. 0 - failed to allocate memory or RpcBindingFromStringBinding failed.
  117. non-NULL - completed okay
  118. --*/
  119. {
  120. PWSTR protseq, endpoint;
  121. PWSTR strbinding;
  122. size_t len;
  123. RPC_BINDING_HANDLE bh = 0;
  124. ASSERT(pwstrCompressedBinding);
  125. ASSERT(*pwstrCompressedBinding != 0);
  126. protseq = GetProtseq(*pwstrCompressedBinding);
  127. endpoint = GetEndpoint(*pwstrCompressedBinding);
  128. if (0 == protseq || 0 == endpoint)
  129. {
  130. ASSERT(0);
  131. return(0);
  132. }
  133. len = 4; // ':' '[' ']' and '\0'
  134. len += OrStringLen(protseq);
  135. len += OrStringLen(endpoint);
  136. len += OrStringLen(&pwstrCompressedBinding[1]);
  137. strbinding = new USHORT[len];
  138. if (strbinding)
  139. {
  140. PWSTR pwstrT;
  141. OrStringCopy(strbinding, protseq); // protseq
  142. pwstrT = OrStringSearch(strbinding, 0); // :
  143. *pwstrT = L':';
  144. pwstrT++;
  145. *pwstrT = 0;
  146. OrStringCat(strbinding, &pwstrCompressedBinding[1]); // network address
  147. pwstrT = OrStringSearch(strbinding, 0); // [
  148. *pwstrT = L'[';
  149. pwstrT++;
  150. *pwstrT = 0;
  151. OrStringCat(strbinding, endpoint); // endpoint
  152. pwstrT = OrStringSearch(strbinding, 0); // ]
  153. *pwstrT = L']';
  154. pwstrT++;
  155. *pwstrT = 0;
  156. RPC_STATUS status = RpcBindingFromStringBinding(strbinding, &bh);
  157. ASSERT(bh == 0 || status == RPC_S_OK);
  158. delete strbinding;
  159. }
  160. if (bh == 0)
  161. {
  162. KdPrintEx((DPFLTR_DCOMSS_ID,
  163. DPFLTR_INFO_LEVEL,
  164. "OR: Unable to bind to %S\n",
  165. pwstrCompressedBinding + 1));
  166. }
  167. return(bh);
  168. }
  169. DUALSTRINGARRAY *
  170. GetStringBinding(
  171. IN PWSTR pwstrCompressed,
  172. IN PWSTR pwstrSecurityBindings
  173. )
  174. /*++
  175. Routine Description:
  176. Converts the compressed string binding into an expanded
  177. string binding. An enpoint maybe optionally specified.
  178. Arguments:
  179. pwstrCompressed - a compressed string binding
  180. pwstrSecurityBindings - optional security bindings
  181. too be tacked onto the end of the expanded string binding.
  182. Terminated by two nulls.
  183. Return Value:
  184. NULL - out of memory
  185. non-NULL - a string binding. Allocated with MIDL_user_allocate.
  186. --*/
  187. {
  188. DUALSTRINGARRAY *pT;
  189. PWSTR protseq;
  190. USHORT seccount;
  191. PWSTR t = pwstrSecurityBindings;
  192. if (t && *t)
  193. {
  194. seccount = 0;
  195. do
  196. {
  197. seccount++;
  198. t++;
  199. if (*t == 0)
  200. {
  201. seccount++;
  202. t++;
  203. }
  204. }
  205. while (*t);
  206. seccount++; // final NULL
  207. }
  208. else
  209. {
  210. // Two nulls only.
  211. seccount = 2;
  212. }
  213. protseq = GetProtseq(*pwstrCompressed);
  214. if (!protseq)
  215. return NULL; // not out of memory -- means bindings contained bogus tower id
  216. int l = OrStringLen(pwstrCompressed) + OrStringLen(protseq) + seccount + 1 + 1;
  217. pT =(DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY) + l * sizeof(WCHAR));
  218. if (!pT)
  219. {
  220. return(0);
  221. }
  222. pT->wNumEntries = (USHORT) l;
  223. OrStringCopy(pT->aStringArray, protseq);
  224. OrStringCat(pT->aStringArray, L":");
  225. OrStringCat(pT->aStringArray, pwstrCompressed + 1);
  226. if (pwstrSecurityBindings)
  227. {
  228. PWSTR t = pT->aStringArray;
  229. t = OrStringSearch(t, 0);
  230. t++;
  231. *t = 0; // Second NULL on string bindings.
  232. t++;
  233. OrMemoryCopy(t, pwstrSecurityBindings, seccount*sizeof(WCHAR));
  234. }
  235. else
  236. {
  237. // Add three NULLs, total of four.
  238. PWSTR t = pT->aStringArray;
  239. t = OrStringSearch(t, 0);
  240. t[1] = 0;
  241. t[2] = 0;
  242. t[3] = 0;
  243. }
  244. pT->wSecurityOffset = pT->wNumEntries - seccount;
  245. ASSERT(dsaValid(pT));
  246. return(pT);
  247. }
  248. ORSTATUS
  249. ConvertToRemote(
  250. IN DUALSTRINGARRAY *pdsaLocal,
  251. OUT DUALSTRINGARRAY **ppdsaRemote
  252. )
  253. /* ++
  254. Parameters:
  255. pdsaLocal - An array of string bindings with compressed protseqs.
  256. ppdsaRemote - Will contain only those string bindings in pdsaLocal
  257. which are not "IsLocal()".
  258. Note: *ppdsaRemote maybe used as a flag, don't set it to non-NULL
  259. until it is valid.
  260. -- */
  261. {
  262. USHORT iTotalSize;
  263. USHORT iSize;
  264. USHORT *p1, *p2;
  265. DUALSTRINGARRAY *pdsaT;
  266. // Size remote array
  267. // Final null terminator
  268. iSize = 1;
  269. p1 = pdsaLocal->aStringArray;
  270. while (*p1)
  271. {
  272. if (! IsLocal(*p1) )
  273. {
  274. iSize += OrStringLen(p1) + 1;
  275. }
  276. p1 = OrStringSearch(p1, 0) + 1;
  277. }
  278. if (iSize == 1)
  279. {
  280. iSize = 2; // No non-local strings, need two terminators.
  281. }
  282. iTotalSize = iSize + (pdsaLocal->wNumEntries - pdsaLocal->wSecurityOffset);
  283. pdsaT = new(iTotalSize * sizeof(WCHAR)) DUALSTRINGARRAY;
  284. if (!pdsaT)
  285. {
  286. return(OR_NOMEM);
  287. }
  288. pdsaT->wNumEntries = iTotalSize;
  289. pdsaT->wSecurityOffset = iSize;
  290. p2 = pdsaT->aStringArray;
  291. // Copy security bindings
  292. OrMemoryCopy(p2 + iSize,
  293. pdsaLocal->aStringArray + pdsaLocal->wSecurityOffset,
  294. (iTotalSize - iSize) * sizeof(WCHAR));
  295. if (iSize == 2)
  296. {
  297. // No non-local strings, fill in terminators and return.
  298. *p2 = 0;
  299. *(p2 + 1) = 0;
  300. *ppdsaRemote = pdsaT;
  301. ASSERT(dsaValid(pdsaT));
  302. return(OR_OK);
  303. }
  304. p1 = pdsaLocal->aStringArray;
  305. while (*p1)
  306. {
  307. if ( ! IsLocal(*p1) )
  308. {
  309. OrStringCopy(p2, p1);
  310. p2 = OrStringSearch(p2, 0) + 1;
  311. }
  312. p1 = OrStringSearch(p1, 0) + 1;
  313. }
  314. *p2 = 0; // Second terminator.
  315. *ppdsaRemote = pdsaT;
  316. ASSERT(dsaValid(pdsaT));
  317. return(OR_OK);
  318. }
  319. DUALSTRINGARRAY *
  320. CompressStringArrayAndAddIPAddrs(
  321. IN DUALSTRINGARRAY *pdsaExpanded
  322. )
  323. /*++
  324. Routine Description:
  325. Converts a stringarray of regular string bindings into a
  326. compressed (protseq's replaced with WORD id's) array of
  327. string bindings.
  328. Arguments:
  329. pdsaExpanded - the string array to compress.
  330. Security information is copied.
  331. Return Value:
  332. 0 - failed to allocate memory.
  333. non-0 - compressed string array.
  334. --*/
  335. {
  336. size_t i, size;
  337. USHORT *p1, *p2, *p3;
  338. PWSTR pwstr;
  339. DUALSTRINGARRAY *pdsaCompressed;
  340. CIPAddrs* pIPAddrs = gpMachineName->GetIPAddrs();
  341. ULONG cIPAddrs = 0;
  342. // Possible for gpMachineName->GetIPAddrs to return NULL.
  343. if (pIPAddrs)
  344. {
  345. ASSERT(pIPAddrs->_pIPAddresses);
  346. cIPAddrs = pIPAddrs->_pIPAddresses->Count;
  347. }
  348. // Compute size of result.
  349. p1 = pdsaExpanded->aStringArray;
  350. size = pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset;
  351. if (*p1 == 0)
  352. {
  353. size += 2; // two null terminators ONLY.
  354. }
  355. else
  356. {
  357. size += 1; // last null terminator
  358. }
  359. while (*p1)
  360. {
  361. size_t sizeT = OrStringLen(p1);
  362. p2 = OrStringSearch(p1, L':'); // ':' is not valid in protseq.
  363. if (p2)
  364. {
  365. // proseq len (p2 - p1) become 1 for Id.
  366. size_t newLen = (sizeT + 1 - (size_t)(p2 - p1));
  367. size += newLen;
  368. *p2 = 0; // subst NULL just for the compare
  369. if ((lstrcmpW(L"ncacn_ip_tcp", p1) == 0) ||
  370. (lstrcmpW(L"ncadg_ip_udp", p1) == 0))
  371. {
  372. WCHAR *p4 = OrStringSearch(p2+1, L'[');
  373. size_t nameLen = (size_t)(p4 - p2 - 1);
  374. newLen = newLen - nameLen + IPMaximumRawName;
  375. size += newLen * cIPAddrs;
  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))
  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. if (_pProtseqInfo[i].hRpc == NULL)
  750. {
  751. continue;
  752. }
  753. _arAsyncCallInfo[i] = (PRPC_ASYNC_STATE) MIDL_user_allocate(sizeof(RPC_ASYNC_STATE));
  754. if (_arAsyncCallInfo[i] == NULL)
  755. {
  756. sc = RPC_S_OUT_OF_MEMORY;
  757. break;
  758. }
  759. //
  760. // set up async information
  761. //
  762. sc = RpcAsyncInitializeHandle(_arAsyncCallInfo[i],
  763. sizeof(RPC_ASYNC_STATE));
  764. //
  765. // If this succeeds we pass the ownership of _arAsyncCallInfo[i] to the callback
  766. //
  767. if (sc != RPC_S_OK)
  768. {
  769. MIDL_user_free(_arAsyncCallInfo[i]);
  770. _arAsyncCallInfo[i] = NULL;
  771. break;
  772. }
  773. _arAsyncCallInfo[i]->NotificationType = RpcNotificationTypeApc;
  774. _arAsyncCallInfo[i]->u.APC.NotificationRoutine = ServerAliveAPC;
  775. _arAsyncCallInfo[i]->u.APC.hThread = 0;
  776. _arAsyncCallInfo[i]->UserInfo = (void *)this;
  777. _cCalls++;
  778. //
  779. // begin the call
  780. //
  781. RPC_STATUS ret = ServerAlive2( _arAsyncCallInfo[i],
  782. _pProtseqInfo[i].hRpc,
  783. &_tmpComVersion,
  784. &_tmpOrBindings,
  785. &_tmpReserved );
  786. if (ret != RPC_S_OK)
  787. {
  788. ServerAliveWork(_arAsyncCallInfo[i], ret);
  789. }
  790. else
  791. {
  792. //
  793. // stagger the calls
  794. //
  795. SleepEx(PARALLEL_PING_STAGGER_TIME, TRUE);
  796. }
  797. }
  798. //
  799. // wait for successful ping or for all calls to
  800. // return
  801. //
  802. while ( (_ndxWinner == 0) && ((_cCalls - _cReceived) > 0) )
  803. {
  804. SleepEx(INFINITE, TRUE);
  805. }
  806. //
  807. // Cancel the calls left outstanding if there are any
  808. //
  809. if ((_cCalls - _cReceived) > 0)
  810. {
  811. for (i = 0; i<_cHandles; i++)
  812. {
  813. if (_arAsyncCallInfo[i] != NULL)
  814. {
  815. // we purposely ignore the return code here. Even if it failed
  816. // there wouldn't be much we could do.
  817. RPC_STATUS retDontCare = RpcAsyncCancelCall(_arAsyncCallInfo[i], TRUE);
  818. if (retDontCare != RPC_S_OK)
  819. {
  820. KdPrintEx((DPFLTR_DCOMSS_ID,
  821. DPFLTR_WARNING_LEVEL,
  822. "OR: RpcAsyncCancelCall failed - this is non-fatal; ret=%d\n",
  823. retDontCare));
  824. }
  825. }
  826. }
  827. //
  828. // wait for cancelled calls to return
  829. //
  830. while ( (_cCalls - _cReceived) > 0)
  831. {
  832. SleepEx(INFINITE, TRUE);
  833. }
  834. }
  835. // Free call infos
  836. if (_arAsyncCallInfo)
  837. {
  838. #if DBG
  839. for (i=0; i < cHandlesMax; ++i)
  840. {
  841. ASSERT(_arAsyncCallInfo[i] == NULL);
  842. }
  843. #endif
  844. MIDL_user_free(_arAsyncCallInfo);
  845. }
  846. //
  847. // return results
  848. //
  849. _arAsyncCallInfo = NULL;
  850. if (_ndxWinner != 0)
  851. {
  852. _pWinner = _pProtseqInfo + _ndxWinner - 1;
  853. return RPC_S_OK;
  854. }
  855. else
  856. {
  857. _pWinner = NULL;
  858. //
  859. // give precedence to failure which occured while attempting
  860. // to make calls.
  861. //
  862. if (sc != RPC_S_OK)
  863. {
  864. return sc;
  865. }
  866. else
  867. {
  868. ASSERT(_sc != RPC_S_OK);
  869. return _sc;
  870. }
  871. }
  872. }
  873. void ServerAliveAPC( IN PRPC_ASYNC_STATE pAsyncState,
  874. IN void *Context,
  875. IN RPC_ASYNC_EVENT Flags)
  876. {
  877. CParallelPing *pParallelPing = (CParallelPing *)pAsyncState->UserInfo;
  878. pParallelPing->ServerAliveWork(pAsyncState, RPC_S_OK);
  879. }
  880. void CParallelPing::ServerAliveWork( PRPC_ASYNC_STATE pAsyncState, RPC_STATUS scBegin)
  881. {
  882. RPC_STATUS tmpStatus;
  883. _tmpOrBindings = NULL;
  884. if (scBegin == RPC_S_OK)
  885. {
  886. _sc = RpcAsyncCompleteCall(pAsyncState, &tmpStatus);
  887. }
  888. else
  889. {
  890. _sc = scBegin;
  891. }
  892. // If there are no saved bindings, save these.
  893. if (_pdsaOrBindings == NULL && dsaValid(_tmpOrBindings))
  894. {
  895. _pdsaOrBindings = _tmpOrBindings;
  896. _tmpOrBindings = NULL;
  897. }
  898. else
  899. {
  900. MIDL_user_free( _tmpOrBindings );
  901. _tmpOrBindings = NULL;
  902. }
  903. _cReceived++;
  904. ULONG uMyIndex = 0;
  905. for (uMyIndex=0; uMyIndex < _cHandles; ++uMyIndex)
  906. {
  907. if (_arAsyncCallInfo[uMyIndex] == pAsyncState)
  908. {
  909. MIDL_user_free(pAsyncState);
  910. _arAsyncCallInfo[uMyIndex] = NULL;
  911. break;
  912. }
  913. }
  914. if (uMyIndex == _cHandles)
  915. {
  916. ASSERT(uMyIndex < _cHandles);
  917. return;
  918. }
  919. //
  920. // First protocol to succeed is the winner
  921. //
  922. if (_ndxWinner == 0)
  923. {
  924. if ((_sc == RPC_S_OK) || (_sc == RPC_S_PROCNUM_OUT_OF_RANGE))
  925. {
  926. _ndxWinner = uMyIndex + 1;
  927. _sc = RPC_S_OK;
  928. }
  929. }
  930. }