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.

950 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996.
  5. //
  6. // File: mach.cxx
  7. //
  8. // Contents:
  9. // Machine naming helper objects
  10. //
  11. // History:
  12. //--------------------------------------------------------------------------
  13. #include "act.hxx"
  14. #include <mach.hxx>
  15. #include <misc.hxx>
  16. // Singleton instance:
  17. CMachineName gMachineName;
  18. // Defn of global ptr external parties use:
  19. CMachineName * gpMachineName = &gMachineName;
  20. CIPAddrs::CIPAddrs() :
  21. _lRefs(1), // constructed with non-zero refcount!
  22. _pIPAddresses(NULL)
  23. {
  24. }
  25. CIPAddrs::~CIPAddrs()
  26. {
  27. ASSERT(_lRefs == 0);
  28. if (_pIPAddresses)
  29. {
  30. PrivMemFree(_pIPAddresses);
  31. }
  32. }
  33. void CIPAddrs::IncRefCount()
  34. {
  35. InterlockedIncrement(&_lRefs);
  36. }
  37. void CIPAddrs::DecRefCount()
  38. {
  39. LONG lRefs = InterlockedDecrement(&_lRefs);
  40. if (lRefs == 0)
  41. {
  42. delete this;
  43. }
  44. }
  45. const DWORD MAX_IPV4_STRING_BUF = ((INET_ADDRSTRLEN+1) * sizeof(WCHAR));
  46. const DWORD MAX_IPV6_STRING_BUF = ((INET6_ADDRSTRLEN+1) * sizeof(WCHAR));
  47. CMachineName::CMachineName()
  48. {
  49. _pIPAddresses = NULL;
  50. _pwszNetBiosName = NULL;
  51. _pwszDNSName = NULL;
  52. _bIPV4AddrsChanged = TRUE;
  53. _bIPV6AddrsChanged = TRUE;
  54. _bInitialized = FALSE;
  55. InitAQD(&_aqdIPV4, AF_INET);
  56. InitAQD(&_aqdIPV6, AF_INET6);
  57. ZeroMemory(&_csMachineNameLock, sizeof(CRITICAL_SECTION));
  58. }
  59. void
  60. CMachineName::InitAQD(
  61. ADDRESS_QUERY_DATA* paqd,
  62. int addrfamily)
  63. {
  64. ASSERT(paqd);
  65. ZeroMemory(paqd, sizeof(ADDRESS_QUERY_DATA));
  66. paqd->dwSig = ADDRQUERYDATA_SIG;
  67. paqd->socket = INVALID_SOCKET;
  68. paqd->addrfamily = addrfamily;
  69. if (addrfamily == AF_INET)
  70. {
  71. paqd->pfnIsGlobalAddress = CMachineName::IsIPV4AddressGlobal;
  72. paqd->dwMaxAddrStringBufSize = MAX_IPV4_STRING_BUF;
  73. }
  74. else if (addrfamily == AF_INET6)
  75. {
  76. paqd->pfnIsGlobalAddress = CMachineName::IsIPV6AddressGlobal;
  77. paqd->dwMaxAddrStringBufSize = MAX_IPV6_STRING_BUF;
  78. }
  79. else
  80. {
  81. ASSERT(0);
  82. }
  83. }
  84. CMachineName::~CMachineName()
  85. {
  86. // CODEWORK: This object does not cleanup its resources. This
  87. // could be fixed, but is pointless at the present time since the
  88. // object lives for the life of the RPCSS svchost, which lives for
  89. // the life of the machine boot.
  90. }
  91. BOOL CMachineName::Initialize()
  92. {
  93. NTSTATUS status;
  94. // Initialize lock
  95. status = RtlInitializeCriticalSection(&_csMachineNameLock);
  96. _bInitialized = NT_SUCCESS(status);
  97. return _bInitialized;
  98. }
  99. void
  100. CMachineName::IPAddrsChanged(int addrfamily)
  101. {
  102. ASSERT(_bInitialized);
  103. switch (addrfamily)
  104. {
  105. case AF_INET:
  106. // IPV4 addresses changed
  107. _bIPV4AddrsChanged = TRUE;
  108. break;
  109. case AF_INET6:
  110. // IPV6 addresses changed
  111. ASSERT(gAddrRefreshMgr.IsIPV6Installed() == TRUE);
  112. _bIPV6AddrsChanged = TRUE;
  113. break;
  114. default:
  115. ASSERT(0 && "Address change signalled on unknown addr family");
  116. return;
  117. }
  118. return;
  119. }
  120. BOOL
  121. CMachineName::Compare( IN WCHAR * pwszName )
  122. {
  123. CIPAddrs* pIPAddrs = NULL;
  124. ASSERT(_bInitialized);
  125. if (!pwszName)
  126. return FALSE;
  127. // Okay to check hard-coded names first (they never change)
  128. if (CompareHardCodedLocalHostNames(pwszName))
  129. return TRUE;
  130. // Get netbios name if we haven't done so already:
  131. if (!_pwszNetBiosName)
  132. {
  133. SetNetBIOSName();
  134. }
  135. if (_pwszNetBiosName && !lstrcmpiW(pwszName, _pwszNetBiosName))
  136. return TRUE;
  137. // Don't go any farther unless we're actually using TCP
  138. if (!gAddrRefreshMgr.ListenedOnTCP())
  139. return FALSE;
  140. // Get DNS name if we haven't done so already.
  141. if (! _pwszDNSName)
  142. {
  143. SetDNSName();
  144. }
  145. if (_pwszDNSName && !lstrcmpiW(pwszName, _pwszDNSName))
  146. return TRUE;
  147. // review: there are other names we could be checking for here, see docs
  148. // on GetComputerNameEx. Need to be wary of cluster names though.
  149. pIPAddrs = GetIPAddrs();
  150. if (pIPAddrs)
  151. {
  152. NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
  153. for ( DWORD n = 0; n < pNetworkAddrVector->Count; n++ )
  154. {
  155. if (!lstrcmpiW(pwszName, pNetworkAddrVector->NetworkAddresses[n]))
  156. {
  157. pIPAddrs->DecRefCount();
  158. return TRUE;
  159. }
  160. }
  161. pIPAddrs->DecRefCount();
  162. }
  163. // We do this last because a side-effect of calling GetIPAddrs is that it will
  164. // populate the list of IPV4 & IPV6 localhost names, if any.
  165. if (CompareDynamicLocalHostNames(pwszName))
  166. return TRUE;
  167. return FALSE;
  168. }
  169. //
  170. // CMachineName::GetIPAddrs()
  171. //
  172. // Returns a pointer to a refcounted CIPAddrs for this
  173. // machine. If we don't yet have a non-localhost ip,
  174. // then we keep trying to get one.
  175. //
  176. CIPAddrs*
  177. CMachineName::GetIPAddrs()
  178. {
  179. ASSERT(_bInitialized);
  180. CMutexLock lock(&_csMachineNameLock);
  181. // should we call gAddrRefreshMgr.ListenedOnTCP() here
  182. // and simply return an empty vector if so?
  183. // If anything changed, or if we don't have any
  184. // addresses at all, go query for the current stuff
  185. if (_bIPV4AddrsChanged ||
  186. _bIPV6AddrsChanged ||
  187. !_pIPAddresses)
  188. {
  189. // Release old addresses, if any
  190. if (_pIPAddresses)
  191. {
  192. _pIPAddresses->DecRefCount();
  193. _pIPAddresses = NULL;
  194. }
  195. _pIPAddresses = QueryAddresses();
  196. if (!_pIPAddresses)
  197. return NULL;
  198. }
  199. ASSERT(_pIPAddresses);
  200. _pIPAddresses->IncRefCount();
  201. return _pIPAddresses;
  202. }
  203. WCHAR*
  204. CMachineName::NetBiosName()
  205. {
  206. ASSERT(_bInitialized);
  207. if (!_pwszNetBiosName)
  208. {
  209. SetNetBIOSName();
  210. }
  211. return _pwszNetBiosName;
  212. }
  213. WCHAR*
  214. CMachineName::DNSName()
  215. {
  216. ASSERT(_bInitialized);
  217. if (!_pwszDNSName)
  218. {
  219. SetDNSName();
  220. }
  221. return _pwszDNSName;
  222. }
  223. CIPAddrs*
  224. CMachineName::QueryAddresses()
  225. {
  226. // Assumes we hold _csMachineNameLock
  227. // If necessary free old ipv4 addresses and requery
  228. if (_bIPV4AddrsChanged)
  229. {
  230. _bIPV4AddrsChanged = FALSE;
  231. BOOL fRet = QueryAddressesSpecific(&_aqdIPV4);
  232. if (!fRet)
  233. {
  234. // If something went wrong, just keep going. The only thing
  235. // we could do here is refuse to supply bindings. If we keep
  236. // going though, the worst thing that could occur (IMHO) is
  237. // that the bindings might only contain a DNS name. Better
  238. // to degrade gracefully than refuse service altogether.
  239. }
  240. }
  241. // If necessary free old ipv6 addresses and requery
  242. if (_bIPV6AddrsChanged && gAddrRefreshMgr.IsIPV6Installed())
  243. {
  244. _bIPV6AddrsChanged = FALSE;
  245. BOOL fRet = QueryAddressesSpecific(&_aqdIPV6);
  246. if (!fRet)
  247. {
  248. // If something went wrong, just keep going. The only thing
  249. // we could do here is refuse to supply bindings. If we keep
  250. // going though, the worst thing that could occur (IMHO) is
  251. // that the bindings might only contain a DNS name. Better
  252. // to degrade gracefully than refuse service altogether.
  253. }
  254. }
  255. // We now have the current IPV4 + IPV6 addresses, now
  256. // just merge them.
  257. CIPAddrs* pIPAddrs = MergeAddresses();
  258. if (!pIPAddrs)
  259. return NULL;
  260. return pIPAddrs;
  261. }
  262. CIPAddrs*
  263. CMachineName::MergeAddresses()
  264. {
  265. DWORD dwCurrentAddress = 0;
  266. DWORD dwTotalAddresses = 0;
  267. CIPAddrs* pIPAddrs = NULL;
  268. NetworkAddressVector* pVector = NULL;
  269. DWORD dwTotalVectorStorageNeeded = 0;
  270. // Assumes we hold _csMachineNameLock
  271. // Allocate new wrapper object
  272. pIPAddrs = new CIPAddrs();
  273. if (!pIPAddrs)
  274. return NULL;
  275. // Figure out how many addresses we have
  276. if (_aqdIPV4.pAddresses)
  277. {
  278. dwTotalAddresses += _aqdIPV4.pAddresses->Count;
  279. }
  280. if (_aqdIPV6.pAddresses)
  281. {
  282. dwTotalAddresses += _aqdIPV6.pAddresses->Count;
  283. }
  284. //
  285. // Handle case with zero addresses
  286. //
  287. if (dwTotalAddresses == 0)
  288. {
  289. // Allocate an empty vector
  290. pVector = (NetworkAddressVector*)PrivMemAlloc(sizeof(NetworkAddressVector));
  291. if (pVector)
  292. {
  293. pVector->Count = 0;
  294. pVector->StringBufferSpace = 0;
  295. pVector->NetworkAddresses = NULL;
  296. pIPAddrs->_pIPAddresses = pVector;
  297. }
  298. else
  299. {
  300. pIPAddrs->DecRefCount();
  301. pIPAddrs = NULL;
  302. }
  303. return pIPAddrs;
  304. }
  305. //
  306. // Calculate total memory needed for combined vector and
  307. // allocate it
  308. //
  309. dwTotalVectorStorageNeeded = sizeof(NetworkAddressVector);
  310. dwTotalVectorStorageNeeded += (sizeof(WCHAR*) * dwTotalAddresses);
  311. if (_aqdIPV4.pAddresses)
  312. {
  313. dwTotalVectorStorageNeeded += _aqdIPV4.pAddresses->StringBufferSpace;
  314. }
  315. if (_aqdIPV6.pAddresses)
  316. {
  317. dwTotalVectorStorageNeeded += _aqdIPV6.pAddresses->StringBufferSpace;
  318. }
  319. pVector = (NetworkAddressVector*)PrivMemAlloc(dwTotalVectorStorageNeeded);
  320. if (!pVector)
  321. {
  322. pIPAddrs->DecRefCount();
  323. pIPAddrs = NULL;
  324. return NULL;
  325. }
  326. //
  327. // Init struct and set it up for copying
  328. //
  329. ZeroMemory(pVector, dwTotalVectorStorageNeeded);
  330. pVector->Count = dwTotalAddresses;
  331. if (_aqdIPV4.pAddresses)
  332. {
  333. pVector->StringBufferSpace = _aqdIPV4.pAddresses->StringBufferSpace;
  334. }
  335. if (_aqdIPV6.pAddresses)
  336. {
  337. pVector->StringBufferSpace += _aqdIPV6.pAddresses->StringBufferSpace;
  338. }
  339. pVector->NetworkAddresses = (WCHAR**)&pVector[1];
  340. //
  341. // Copy addresses into the vector
  342. //
  343. dwCurrentAddress = 0;
  344. WCHAR* pszCurrentAddress = (WCHAR*)(&pVector->NetworkAddresses[dwTotalAddresses]);
  345. if (_aqdIPV4.pAddresses)
  346. {
  347. CopySrcVectorToTargetVector (pVector,
  348. _aqdIPV4.pAddresses,
  349. &dwCurrentAddress,
  350. &pszCurrentAddress);
  351. ASSERT(dwCurrentAddress == _aqdIPV4.pAddresses->Count);
  352. }
  353. if (_aqdIPV6.pAddresses)
  354. {
  355. CopySrcVectorToTargetVector(pVector,
  356. _aqdIPV6.pAddresses,
  357. &dwCurrentAddress,
  358. &pszCurrentAddress);
  359. }
  360. ASSERT(dwCurrentAddress == dwTotalAddresses);
  361. ValidateVector(pVector);
  362. //
  363. // Success
  364. //
  365. pIPAddrs->_pIPAddresses = pVector;
  366. return pIPAddrs;
  367. }
  368. void
  369. CMachineName::CopySrcVectorToTargetVector (
  370. NetworkAddressVector* pTargetVector, // The vector to copy into
  371. NetworkAddressVector* pSourceVector, // The vector to copy from
  372. DWORD * pdwCurrentAddress, // On input, the index in the vector to start copying into.
  373. WCHAR** ppszCurrentAddress) // On input, the buffer position to start copying into.
  374. {
  375. // Do nothing in case of an empty source vector
  376. if (pSourceVector->Count == 0)
  377. return;
  378. // Copy down the [in,out] parameters for shorthand purposes.
  379. DWORD dwCurrent = *pdwCurrentAddress;
  380. WCHAR *pszCurrent = *ppszCurrentAddress;
  381. for (DWORD i = 0; i < pSourceVector->Count; i++)
  382. {
  383. // Lay the source network address into the buffer at wszCurrent.
  384. lstrcpy(pszCurrent, pSourceVector->NetworkAddresses[i]);
  385. // Now set the pointer in pTargetVector to point to wszCurrent...
  386. pTargetVector->NetworkAddresses[dwCurrent] = pszCurrent;
  387. //
  388. // ...and advance wszCurrent to the next free spot in the buffer.
  389. pszCurrent += (lstrlen(pszCurrent) + 1);
  390. dwCurrent++;
  391. }
  392. // Update the [in,out] params.
  393. *pdwCurrentAddress = dwCurrent;
  394. *ppszCurrentAddress = pszCurrent;
  395. return;
  396. }
  397. BOOL
  398. CMachineName::IsIPV4AddressGlobal(LPSOCKADDR psockaddr)
  399. {
  400. ASSERT(psockaddr);
  401. // undone? what do we need to check here? do we even see localhost
  402. // addresses from a socket query? (not usually)
  403. //in6_addr* pin6addr = &(((sockaddr_in6*)psockaddr)->sin6_addr);
  404. return TRUE;
  405. }
  406. BOOL
  407. CMachineName::IsIPV6AddressGlobal(LPSOCKADDR psockaddr)
  408. {
  409. ASSERT(psockaddr);
  410. in6_addr* pin6addr = &(((sockaddr_in6*)psockaddr)->sin6_addr);
  411. // This macro just checks for ::1%1
  412. if (IN6_IS_ADDR_LOOPBACK(pin6addr))
  413. {
  414. return FALSE;
  415. }
  416. // Unfortunately, the IN6_IS_ADDR_LOOPBACK macro doesn't cover all
  417. // cases. Specifically, it doesn't work for fe80::1. Here we
  418. // have a hard-coded check for this:
  419. if ((pin6addr->s6_words[0] == 0x80fe) &&
  420. (pin6addr->s6_words[1] == 0x0) &&
  421. (pin6addr->s6_words[2] == 0x0) &&
  422. (pin6addr->s6_words[3] == 0x0) &&
  423. (pin6addr->s6_words[4] == 0x0) &&
  424. (pin6addr->s6_words[5] == 0x0) &&
  425. (pin6addr->s6_words[6] == 0x0) &&
  426. (pin6addr->s6_words[7] == 0x0100))
  427. {
  428. return FALSE;
  429. }
  430. // No link-local addresses
  431. if (IN6_IS_ADDR_LINKLOCAL(pin6addr))
  432. {
  433. return FALSE;
  434. }
  435. // No site local addresses.
  436. if (IN6_IS_ADDR_SITELOCAL(pin6addr))
  437. {
  438. return FALSE;
  439. }
  440. // At this point, we have concluded that the IPV6 address in question is
  441. // a "global" scope address, and hence is okay to put in the bindings.
  442. return TRUE;
  443. }
  444. void
  445. CMachineName::SetNetBIOSName()
  446. {
  447. CMutexLock lock(&_csMachineNameLock);
  448. if (!_pwszNetBiosName)
  449. {
  450. SetComputerNameHelper(ComputerNamePhysicalNetBIOS, &_pwszNetBiosName);
  451. }
  452. }
  453. void
  454. CMachineName::SetDNSName()
  455. {
  456. CMutexLock lock(&_csMachineNameLock);
  457. if (!_pwszDNSName)
  458. {
  459. SetComputerNameHelper(ComputerNamePhysicalDnsFullyQualified, &_pwszDNSName);
  460. }
  461. }
  462. void
  463. CMachineName::SetComputerNameHelper(
  464. COMPUTER_NAME_FORMAT format,
  465. WCHAR** ppwszName
  466. )
  467. {
  468. BOOL fRet = FALSE;
  469. DWORD dwSize = 0;
  470. ASSERT(ppwszName);
  471. *ppwszName = NULL;
  472. // Get needed buffer size
  473. fRet = GetComputerNameEx(format, NULL, &dwSize);
  474. if (!fRet)
  475. {
  476. // Be resilient if failures occur, sometimes network
  477. // apis can be flaky during machine boot (for instance)
  478. if (GetLastError() == ERROR_MORE_DATA)
  479. {
  480. ASSERT(dwSize > 0);
  481. if (dwSize == 0)
  482. return;
  483. WCHAR* pwszName = new WCHAR[dwSize];
  484. if (!pwszName)
  485. return;
  486. // Get name for real
  487. fRet = GetComputerNameEx(format, pwszName, &dwSize);
  488. if (fRet)
  489. {
  490. // success
  491. *ppwszName = pwszName;
  492. }
  493. else
  494. {
  495. // still failed? hmm
  496. ASSERT(0 && "Unexpected failure from GetComputerNameEx");
  497. delete [] pwszName;
  498. }
  499. }
  500. }
  501. return;
  502. }
  503. BOOL
  504. CMachineName::CompareHardCodedLocalHostNames(WCHAR* pwszName)
  505. {
  506. ASSERT(pwszName);
  507. // Some localhost aliases don't show up in socket queries.
  508. if (!lstrcmpi(L"localhost", pwszName))
  509. return TRUE;
  510. if (!lstrcmpi(L"127.0.0.1", pwszName))
  511. return TRUE;
  512. return FALSE;
  513. }
  514. BOOL
  515. CMachineName::CompareDynamicLocalHostNames(WCHAR* pwszName)
  516. {
  517. DWORD i;
  518. ASSERT(pwszName);
  519. CMutexLock lock(&_csMachineNameLock);
  520. if (_aqdIPV4.pLocalOnlyAddresses)
  521. {
  522. for (i = 0; i < _aqdIPV4.pLocalOnlyAddresses->Count; i++)
  523. {
  524. if (!lstrcmpi(_aqdIPV4.pLocalOnlyAddresses->NetworkAddresses[i],
  525. pwszName))
  526. {
  527. return TRUE;
  528. }
  529. }
  530. }
  531. if (_aqdIPV6.pLocalOnlyAddresses)
  532. {
  533. for (i = 0; i < _aqdIPV6.pLocalOnlyAddresses->Count; i++)
  534. {
  535. if (!lstrcmpi(_aqdIPV6.pLocalOnlyAddresses->NetworkAddresses[i],
  536. pwszName))
  537. {
  538. return TRUE;
  539. }
  540. }
  541. }
  542. return FALSE;
  543. }
  544. BOOL
  545. CMachineName::QueryAddressesSpecific(ADDRESS_QUERY_DATA* paqd)
  546. /*++
  547. Routine Description:
  548. Retrieves a SOCKET_ADDRESS_LIST containing addresses supported by this
  549. machine for the specified address family (ipv4 or ipv6) and stores
  550. it in either _pIPV4Addrs or _pIPV6Addrs.
  551. Arguments:
  552. paqd - structure containing data with which to query addresses on
  553. Return Value:
  554. TRUE -- valid results are stored in paqd
  555. FALSE -- error occurred. One or both of paqd->pAddresses and
  556. paqd->pLocalAddresses may be NULL.
  557. --*/
  558. {
  559. int ret;
  560. BOOL fReturn = TRUE;
  561. DWORD dwBytesReturned;
  562. DWORD i;
  563. SOCKET* pSocket = NULL;
  564. SOCKET_ADDRESS_LIST** ppSocketAddrList = NULL;
  565. DWORD* pdwSocketAddrBufferSize = NULL;
  566. ASSERT(paqd->dwSig == ADDRQUERYDATA_SIG);
  567. // Allocate socket if we haven't already
  568. if (paqd->socket == INVALID_SOCKET)
  569. {
  570. paqd->socket = WSASocket(paqd->addrfamily,
  571. SOCK_STREAM,
  572. IPPROTO_TCP,
  573. NULL,
  574. 0,
  575. 0
  576. );
  577. if (paqd->socket == INVALID_SOCKET)
  578. return NULL;
  579. // else we got a socket for this addrfamily, which we keep forever.
  580. }
  581. while (TRUE)
  582. {
  583. ret = WSAIoctl(paqd->socket,
  584. SIO_ADDRESS_LIST_QUERY,
  585. NULL,
  586. 0,
  587. (BYTE*)paqd->pSockAddrList,
  588. paqd->dwSockAddrListBufferSize,
  589. &dwBytesReturned,
  590. NULL,
  591. NULL);
  592. paqd->dwTotalTimesQueried++;
  593. if (ret == 0)
  594. {
  595. // Success
  596. break;
  597. }
  598. else
  599. {
  600. // Failed. If need bigger buffer, allocate it
  601. // and try again. Otherwise fail.
  602. if (WSAGetLastError() == WSAEFAULT)
  603. {
  604. ASSERT(dwBytesReturned > paqd->dwSockAddrListBufferSize);
  605. if (paqd->pSockAddrList)
  606. {
  607. ASSERT(paqd->dwSockAddrListBufferSize > 0);
  608. PrivMemFree(paqd->pSockAddrList);
  609. paqd->pSockAddrList = NULL;
  610. paqd->dwSockAddrListBufferSize = 0;
  611. }
  612. else
  613. {
  614. ASSERT(paqd->dwSockAddrListBufferSize == 0);
  615. }
  616. paqd->pSockAddrList = (SOCKET_ADDRESS_LIST*)PrivMemAlloc(dwBytesReturned);
  617. if (!(paqd->pSockAddrList))
  618. {
  619. fReturn = FALSE;
  620. break;
  621. }
  622. paqd->dwSockAddrListBufferSize = dwBytesReturned;
  623. }
  624. else
  625. {
  626. // some other error
  627. fReturn = FALSE;
  628. break;
  629. }
  630. }
  631. }
  632. if (fReturn)
  633. {
  634. // Build local-only vector
  635. if (!BuildVector(paqd, FALSE))
  636. fReturn = FALSE;
  637. // Build non-local-only vector
  638. if (!BuildVector(paqd, TRUE))
  639. fReturn = FALSE;
  640. }
  641. else
  642. {
  643. // if we failed above before calling BuildVector, then we need to
  644. // free and NULL pAddresses & pLocalAddresses so that downstream
  645. // code doesn't assume that they are pointing to valid contents.
  646. PrivMemFree(paqd->pAddresses);
  647. paqd->pAddresses = NULL;
  648. paqd->dwAddrVectorSize = 0;
  649. PrivMemFree(paqd->pLocalOnlyAddresses);
  650. paqd->pLocalOnlyAddresses = NULL;
  651. paqd->dwLocalAddrVectorSize = 0;
  652. }
  653. return fReturn;
  654. }
  655. BOOL
  656. CMachineName::BuildVector(ADDRESS_QUERY_DATA* paqd, BOOL fLocalOnly)
  657. {
  658. int i = 0;
  659. DWORD* pdwVectorSize = NULL;
  660. NetworkAddressVector** ppVector = NULL;
  661. DWORD dwTotalAddrs = 0;
  662. BOOL fIsGlobalAddress;
  663. ASSERT(paqd->dwSig == ADDRQUERYDATA_SIG);
  664. //
  665. // Sum up how many addresses of the non-local or local-only type there
  666. // are, so we know how much memory to allocate.
  667. //
  668. for (i = 0; i < paqd->pSockAddrList->iAddressCount; i++)
  669. {
  670. fIsGlobalAddress = (!paqd->pfnIsGlobalAddress ||
  671. paqd->pfnIsGlobalAddress(paqd->pSockAddrList->Address[i].lpSockaddr));
  672. if ((fIsGlobalAddress && !fLocalOnly) || (!fIsGlobalAddress && fLocalOnly))
  673. {
  674. dwTotalAddrs++;
  675. }
  676. }
  677. if (fLocalOnly)
  678. {
  679. pdwVectorSize = &paqd->dwLocalAddrVectorSize;
  680. ppVector = &paqd->pLocalOnlyAddresses;
  681. }
  682. else
  683. {
  684. pdwVectorSize = &paqd->dwAddrVectorSize;
  685. ppVector = &paqd->pAddresses;
  686. }
  687. //
  688. // Build a vector of the specified addresses
  689. //
  690. DWORD dwBufSizeNeeded;
  691. //
  692. // Figure out how much space we need. See comment below (right above call
  693. // to WSAAddressToString) regarding string buffer space required per address.
  694. //
  695. dwBufSizeNeeded = sizeof(NetworkAddressVector) +
  696. (dwTotalAddrs * sizeof(WCHAR*)) +
  697. (dwTotalAddrs * paqd->dwMaxAddrStringBufSize);
  698. // Figure out if we can use the old vector buffer, or allocate a new one
  699. if (*pdwVectorSize < dwBufSizeNeeded)
  700. {
  701. ASSERT((*pdwVectorSize > 0) ? (*ppVector != NULL) : (*ppVector == NULL));
  702. PrivMemFree(*ppVector);
  703. *pdwVectorSize = 0;
  704. *ppVector = (NetworkAddressVector*)PrivMemAlloc(dwBufSizeNeeded);
  705. if (!(*ppVector))
  706. return FALSE;
  707. *pdwVectorSize = dwBufSizeNeeded;
  708. }
  709. // Zero the buffer
  710. ASSERT(*ppVector);
  711. ZeroMemory(*ppVector, *pdwVectorSize);
  712. // Fill in the vector
  713. if (dwTotalAddrs > 0)
  714. {
  715. NetworkAddressVector* pVector = *ppVector;
  716. pVector->Count = dwTotalAddrs;
  717. pVector->StringBufferSpace = (dwTotalAddrs * paqd->dwMaxAddrStringBufSize);
  718. pVector->NetworkAddresses = (WCHAR**)&pVector[1];
  719. DWORD dwCurrentVectorAddress = 0;
  720. WCHAR* pszNextAddress = (WCHAR*)&pVector->NetworkAddresses[dwTotalAddrs];
  721. for (i = 0;
  722. (i < paqd->pSockAddrList->iAddressCount) && (dwCurrentVectorAddress < dwTotalAddrs);
  723. i++)
  724. {
  725. BOOL fUseCurrentAddress;
  726. // Re-calculate if the current address in the sockaddrlist is going to
  727. // be put into the vector.
  728. fIsGlobalAddress = (!(paqd->pfnIsGlobalAddress) ||
  729. paqd->pfnIsGlobalAddress(paqd->pSockAddrList->Address[i].lpSockaddr));
  730. fUseCurrentAddress = (fIsGlobalAddress && !fLocalOnly) || (!fIsGlobalAddress && fLocalOnly);
  731. if (fUseCurrentAddress)
  732. {
  733. int ret;
  734. DWORD dwAddrBufLen;
  735. dwAddrBufLen = paqd->dwMaxAddrStringBufSize;
  736. // Note that we are being slightly sloppy here. In theory we could be
  737. // callling WSAAddressToString with a zero-size output buffer, and WSATS
  738. // would come back with an error and the exact required size of the buffer;
  739. // We could then do this across all addresses going into the vector. However,
  740. // there are some network stack bugs that don't let this work for every
  741. // address type (ie, ipv6). Hence, we play it safe and allocate a "maximum"
  742. // buffer space for every address.
  743. ret = WSAAddressToString(paqd->pSockAddrList->Address[i].lpSockaddr,
  744. paqd->pSockAddrList->Address[i].iSockaddrLength,
  745. NULL,
  746. pszNextAddress,
  747. &dwAddrBufLen);
  748. if (ret != 0)
  749. {
  750. // An error occurred. We don't expect "insufficient buffer" here, and other
  751. // errors are not something we can recover from. Cleanup and return NULL.
  752. PrivMemFree(*ppVector);
  753. *ppVector = NULL;
  754. *pdwVectorSize = 0;
  755. return FALSE;
  756. }
  757. else
  758. {
  759. ASSERT(dwAddrBufLen <= paqd->dwMaxAddrStringBufSize);
  760. ASSERT((((DWORD)lstrlenW(pszNextAddress) + 1) * sizeof(WCHAR)) <= paqd->dwMaxAddrStringBufSize);
  761. // Write in address of just copied string
  762. pVector->NetworkAddresses[dwCurrentVectorAddress] = pszNextAddress;
  763. // Advance pointers to next free spot in the buffer
  764. dwCurrentVectorAddress++;
  765. pszNextAddress += (lstrlen(pszNextAddress) + 1);
  766. }
  767. }
  768. // else skip this address
  769. }
  770. ASSERT(dwCurrentVectorAddress == dwTotalAddrs);
  771. }
  772. else
  773. {
  774. // Zero addresses and the vector is already "empty" (it was
  775. // zeroed out above). So nothing to do.
  776. }
  777. ValidateVector(*ppVector);
  778. return TRUE;
  779. }
  780. void
  781. CMachineName::ValidateVector(NetworkAddressVector* pVector)
  782. {
  783. #ifdef DBG
  784. ASSERT(pVector);
  785. if (pVector->Count > 0)
  786. {
  787. ASSERT(pVector->StringBufferSpace > 0);
  788. ASSERT(pVector->NetworkAddresses != NULL);
  789. DWORD i;
  790. DWORD cchTotalStringSpace = 0;
  791. for (i = 0; i < pVector->Count; i++)
  792. {
  793. BYTE* pStart = (BYTE*)&pVector->NetworkAddresses[pVector->Count];
  794. BYTE* pEnd = pStart + pVector->StringBufferSpace;
  795. ASSERT((BYTE*)pVector->NetworkAddresses[i] >= pStart);
  796. ASSERT((BYTE*)pVector->NetworkAddresses[i] < pEnd);
  797. cchTotalStringSpace += (lstrlenW(pVector->NetworkAddresses[i]) + 1);
  798. }
  799. ASSERT((cchTotalStringSpace * sizeof(WCHAR)) <= pVector->StringBufferSpace);
  800. }
  801. else
  802. {
  803. ASSERT(pVector->StringBufferSpace == 0);
  804. ASSERT(pVector->NetworkAddresses == NULL);
  805. }
  806. #endif
  807. }