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.

471 lines
11 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. CMachineName::CMachineName()
  46. {
  47. _socket = INVALID_SOCKET;
  48. _pAddrQueryBuf = NULL;
  49. _dwAddrQueryBufSize = 0;
  50. _bIPAddrsChanged = FALSE;
  51. _dwcResets = 0;
  52. _wszMachineName[0] = 0;
  53. _bInitialized = FALSE;
  54. _pwszDNSName = 0;
  55. _pIPAddresses = 0;
  56. _pAliases = NULL;
  57. NTSTATUS status;
  58. // Initialize lock
  59. status = RtlInitializeCriticalSection(&_csMachineNameLock);
  60. _bInitialized = NT_SUCCESS(status);
  61. }
  62. DWORD CMachineName::Initialize()
  63. {
  64. NTSTATUS status = NO_ERROR;
  65. ASSERT(gpClientLock->HeldExclusive());
  66. // Get computer name if we haven't done so already:
  67. if (!_wszMachineName[0])
  68. {
  69. SetName();
  70. }
  71. // Get DNS name if we haven't done so already. Note that we
  72. // currently have no way of knowing when the DNS name changes
  73. // (unlike IP address changes), so it is left alone once set.
  74. if (!_pwszDNSName)
  75. {
  76. SetDNSName();
  77. }
  78. return status;
  79. }
  80. BOOL
  81. CMachineName::Compare( IN WCHAR * pwszName )
  82. {
  83. CIPAddrs* pIPAddrs = NULL;
  84. ASSERT(_bInitialized);
  85. if ( lstrcmpiW( pwszName, _wszMachineName ) == 0 )
  86. return TRUE;
  87. if ( lstrcmpiW( pwszName, L"localhost" ) == 0 )
  88. return TRUE;
  89. if ( lstrcmpiW( pwszName, L"127.0.0.1" ) == 0 )
  90. return TRUE;
  91. if (! _pwszDNSName )
  92. SetDNSName();
  93. if ( _pwszDNSName && lstrcmpiW( pwszName, _pwszDNSName ) == 0 )
  94. return TRUE;
  95. pIPAddrs = GetIPAddrs();
  96. if (pIPAddrs)
  97. {
  98. NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
  99. for ( DWORD n = 0; n < pNetworkAddrVector->Count; n++ )
  100. {
  101. if ( lstrcmpiW( pwszName, pNetworkAddrVector->NetworkAddresses[n] ) == 0 )
  102. {
  103. pIPAddrs->DecRefCount();
  104. return TRUE;
  105. }
  106. }
  107. pIPAddrs->DecRefCount();
  108. }
  109. if (_pAliases)
  110. {
  111. for (DWORD n=0; _pAliases[n]; n++)
  112. {
  113. if ( lstrcmpiW( pwszName, _pAliases[n] ) == 0 )
  114. return TRUE;
  115. }
  116. }
  117. return FALSE;
  118. }
  119. //
  120. // CMachineName::GetIPAddrs()
  121. //
  122. // Returns a pointer to a refcounted CIPAddrs for this
  123. // machine. If we don't yet have a non-localhost ip,
  124. // then we keep trying to get one.
  125. //
  126. CIPAddrs* CMachineName::GetIPAddrs()
  127. {
  128. ASSERT(_bInitialized);
  129. CMutexLock lock(&_csMachineNameLock);
  130. // _bIPAddrsChanged will TRUE if we were notified of
  131. // an address change
  132. if (_bIPAddrsChanged || !_pIPAddresses)
  133. {
  134. CIPAddrs* pIPAddrs = NULL;
  135. NetworkAddressVector* pNewAddrVector = NULL;
  136. // Create a new wrapper object
  137. pIPAddrs = new CIPAddrs; // refcount starts as 1
  138. if (!pIPAddrs)
  139. return NULL;
  140. // Build a new IP address vector:
  141. pNewAddrVector = COMMON_IP_BuildAddressVector();
  142. if (!pNewAddrVector)
  143. {
  144. pIPAddrs->DecRefCount();
  145. return NULL;
  146. }
  147. // Store the new vector in the wrapper object:
  148. pIPAddrs->_pIPAddresses = pNewAddrVector;
  149. _dwcResets++; // debug counter
  150. // Clear dirty flag
  151. _bIPAddrsChanged = FALSE;
  152. // Release old copy
  153. if (_pIPAddresses)
  154. _pIPAddresses->DecRefCount();
  155. // Update our cached copy
  156. _pIPAddresses = pIPAddrs;
  157. // Bump refcount and return
  158. _pIPAddresses->IncRefCount();
  159. return _pIPAddresses;
  160. }
  161. else
  162. {
  163. // Don't need to recalculate our ip's. Just refcount the cached object and
  164. // return it.
  165. ASSERT(_pIPAddresses);
  166. _pIPAddresses->IncRefCount();
  167. return _pIPAddresses;
  168. }
  169. }
  170. void
  171. CMachineName::SetName()
  172. {
  173. DWORD Size;
  174. Size = sizeof(_wszMachineName);
  175. (void) GetComputerNameW( _wszMachineName, &Size );
  176. }
  177. void
  178. CMachineName::SetDNSName()
  179. {
  180. char hostname[IPMaximumPrettyName];
  181. HOSTENT * HostEnt = 0;
  182. DWORD Length;
  183. int Status;
  184. if (gethostname(hostname, IPMaximumPrettyName) != 0)
  185. return;
  186. HostEnt = gethostbyname(hostname);
  187. if ( ! HostEnt )
  188. return;
  189. Length = lstrlenA( HostEnt->h_name ) + 1;
  190. _pwszDNSName = (WCHAR *) PrivMemAlloc( Length * sizeof(WCHAR) );
  191. if ( ! _pwszDNSName )
  192. return;
  193. Status = MultiByteToWideChar(
  194. CP_ACP,
  195. 0,
  196. HostEnt->h_name,
  197. Length,
  198. _pwszDNSName,
  199. Length );
  200. if ( ! Status )
  201. {
  202. PrivMemFree( _pwszDNSName );
  203. _pwszDNSName = 0;
  204. }
  205. SetHostAliases(HostEnt);
  206. }
  207. void CMachineName::SetHostAliases(HOSTENT *pHostEnt)
  208. {
  209. if (!pHostEnt->h_aliases)
  210. {
  211. return;
  212. }
  213. //
  214. // sum up the number of bytes needed for allocation
  215. //
  216. ULONG cAliases = 0;
  217. ULONG cbAliases = 0;
  218. while (pHostEnt->h_aliases[cAliases])
  219. {
  220. cbAliases += sizeof(WCHAR) * (lstrlenA(pHostEnt->h_aliases[cAliases]) + 1);
  221. cAliases++;
  222. }
  223. if (cAliases == 0)
  224. {
  225. return;
  226. }
  227. //
  228. // allocate one chunk of memory
  229. //
  230. _pAliases = (WCHAR **) PrivMemAlloc(((cAliases+1) * sizeof(WCHAR*)) + cbAliases);
  231. if (!_pAliases)
  232. {
  233. return;
  234. }
  235. WCHAR *pStrings = (WCHAR *) ( _pAliases + cAliases + 1 );
  236. ULONG i;
  237. //
  238. // copy the strings
  239. //
  240. for (i=0; i<cAliases; i++)
  241. {
  242. MultiByteToWideChar(
  243. CP_ACP,
  244. 0,
  245. pHostEnt->h_aliases[i],
  246. -1,
  247. pStrings,
  248. IPMaximumPrettyName
  249. );
  250. _pAliases[i] = pStrings;
  251. pStrings += (wcslen(pStrings) + 1);
  252. }
  253. // null terminator
  254. _pAliases[cAliases] = NULL;
  255. return;
  256. }
  257. NetworkAddressVector*
  258. CMachineName::COMMON_IP_BuildAddressVector()
  259. /*++
  260. Routine Description:
  261. Builds a vector of IP addresses supported by this machine.
  262. Arguments:
  263. None
  264. Return Value:
  265. non-NULL -- a valid NetworkAddressVector
  266. NULL - error occurred
  267. --*/
  268. {
  269. int ret;
  270. DWORD dwBytesReturned;
  271. int i;
  272. DWORD dwVectMemNeeded = 0;
  273. LPSOCKET_ADDRESS_LIST pSocketAddrList = NULL;
  274. NetworkAddressVector* pVector = NULL;
  275. char* pszIPAddress;
  276. // Allocate socket if we haven't already
  277. if (_socket == INVALID_SOCKET)
  278. {
  279. _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  280. if (_socket == INVALID_SOCKET)
  281. return NULL;
  282. // else we got a socket, which we keep forever.
  283. }
  284. while (TRUE)
  285. {
  286. ret = WSAIoctl(_socket,
  287. SIO_ADDRESS_LIST_QUERY,
  288. NULL,
  289. 0,
  290. _pAddrQueryBuf,
  291. _dwAddrQueryBufSize,
  292. &dwBytesReturned,
  293. NULL,
  294. NULL);
  295. if (ret == 0)
  296. {
  297. // Success, break out and keep going
  298. break;
  299. }
  300. else
  301. {
  302. // Failed. If need bigger buffer, allocate it
  303. // and try again. Otherwise fail.
  304. if (WSAGetLastError() == WSAEFAULT)
  305. {
  306. ASSERT(dwBytesReturned > _dwAddrQueryBufSize);
  307. delete _pAddrQueryBuf;
  308. _dwAddrQueryBufSize = 0;
  309. _pAddrQueryBuf = new BYTE[dwBytesReturned];
  310. if (!_pAddrQueryBuf)
  311. return NULL;
  312. _dwAddrQueryBufSize = dwBytesReturned;
  313. }
  314. else
  315. {
  316. // some other error
  317. return NULL;
  318. }
  319. }
  320. }
  321. // Okay, we now have successfully queried the socket for
  322. // the latest and greatest IP addresses assigned to this
  323. // machine. Now we need to allocate and fill in a
  324. // NetworkAddressVector structure.
  325. pSocketAddrList = (LPSOCKET_ADDRESS_LIST)_pAddrQueryBuf;
  326. // Handle case with no addresses
  327. if (pSocketAddrList->iAddressCount == 0)
  328. {
  329. // Allocate an empty vector
  330. pVector = (NetworkAddressVector*)PrivMemAlloc(sizeof(NetworkAddressVector));
  331. if (pVector)
  332. {
  333. pVector->Count = 0;
  334. pVector->NetworkAddresses = NULL;
  335. }
  336. return pVector;
  337. }
  338. // Calculate how much memory needed
  339. dwVectMemNeeded = sizeof(NetworkAddressVector) +
  340. (pSocketAddrList->iAddressCount * sizeof(WCHAR*));
  341. for (i = 0; i < pSocketAddrList->iAddressCount; i++)
  342. {
  343. pszIPAddress = inet_ntoa(((SOCKADDR_IN*)pSocketAddrList->Address[i].lpSockaddr)->sin_addr);
  344. ASSERT(pszIPAddress);
  345. dwVectMemNeeded += ((lstrlenA(pszIPAddress) + 1) * sizeof(WCHAR));
  346. }
  347. pVector = (NetworkAddressVector*)PrivMemAlloc(dwVectMemNeeded);
  348. if (!pVector)
  349. return NULL;
  350. // Init struct
  351. pVector->Count = pSocketAddrList->iAddressCount;
  352. pVector->NetworkAddresses = (WCHAR**)&pVector[1];
  353. pVector->NetworkAddresses[0] = (WCHAR*)&pVector->NetworkAddresses[pSocketAddrList->iAddressCount];
  354. // Copy in addresses
  355. for (i = 0; i < pSocketAddrList->iAddressCount; i++)
  356. {
  357. pszIPAddress = inet_ntoa(((SOCKADDR_IN*)pSocketAddrList->Address[i].lpSockaddr)->sin_addr);
  358. ASSERT(pszIPAddress);
  359. ret = MultiByteToWideChar(
  360. CP_ACP,
  361. 0,
  362. pszIPAddress,
  363. -1,
  364. pVector->NetworkAddresses[i],
  365. IPMaximumPrettyName
  366. );
  367. if (ret == 0)
  368. {
  369. PrivMemFree(pVector);
  370. return NULL;
  371. }
  372. if (i != (pSocketAddrList->iAddressCount - 1))
  373. {
  374. // Setup for next address, if any
  375. pVector->NetworkAddresses[i+1] = pVector->NetworkAddresses[i];
  376. pVector->NetworkAddresses[i+1] += lstrlenW(pVector->NetworkAddresses[i]) + 1;
  377. }
  378. }
  379. return pVector;
  380. }