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.

1160 lines
30 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. caddrlst.cxx
  5. Abstract:
  6. Contains CAddressList class definition
  7. Contents:
  8. CAddressList::FreeList
  9. CAddressList::SetList
  10. CAddressList::SetList
  11. CAddressList::SetList
  12. CAddressList::GetNextAddress
  13. CAddressList::InvalidateAddress
  14. CAddressList::ResolveHost
  15. CFsm_ResolveHost::RunSM
  16. (CAddressList::IPAddressToAddressList)
  17. (CAddressList::HostentToAddressList)
  18. (CAddressList::AddrInfoToAddressList)
  19. Author:
  20. Richard L Firth (rfirth) 19-Apr-1997
  21. Environment:
  22. Win32 user-mode DLL
  23. Revision History:
  24. 19-Apr-1997 rfirth
  25. Created
  26. 28-Jan-1998 rfirth
  27. No longer randomly index address list. NT5 and Win98 are modified to
  28. return the address list in decreasing order of desirability by RTT/
  29. route
  30. --*/
  31. #include <wininetp.h>
  32. #include <perfdiag.hxx>
  33. #include <autodial.h>
  34. //#define TEST_CODE
  35. //
  36. // methods
  37. //
  38. VOID
  39. CAddressList::FreeList(
  40. VOID
  41. )
  42. /*++
  43. Routine Description:
  44. Free address list
  45. Arguments:
  46. None.
  47. Return Value:
  48. None.
  49. --*/
  50. {
  51. if (m_Addresses != NULL) {
  52. m_Addresses = (LPRESOLVED_ADDRESS)FREE_MEMORY((HLOCAL)m_Addresses);
  53. INET_ASSERT(m_Addresses == NULL);
  54. m_AddressCount = 0;
  55. m_BadAddressCount = 0;
  56. m_CurrentAddress = 0;
  57. }
  58. }
  59. DWORD
  60. CAddressList::SetList(
  61. IN DWORD dwIpAddress
  62. )
  63. /*++
  64. Routine Description:
  65. Sets the list contents from the IP address
  66. Arguments:
  67. dwIpAddress - IP address from which to create list contents
  68. Return Value:
  69. DWORD
  70. Success - ERROR_SUCCESS
  71. Failure - ERROR_NOT_ENOUGH_MEMORY
  72. --*/
  73. {
  74. Acquire();
  75. FreeList();
  76. DWORD error = IPAddressToAddressList(dwIpAddress);
  77. Release();
  78. return error;
  79. }
  80. DWORD
  81. CAddressList::SetList(
  82. IN LPHOSTENT lpHostent
  83. )
  84. /*++
  85. Routine Description:
  86. Sets the list contents from the hostent
  87. Arguments:
  88. lpHostent - pointer to hostent containing resolved addresses to add
  89. Return Value:
  90. DWORD
  91. Success - ERROR_SUCCESS
  92. Failure - ERROR_NOT_ENOUGH_MEMORY
  93. --*/
  94. {
  95. Acquire();
  96. FreeList();
  97. DWORD error = HostentToAddressList(lpHostent);
  98. Release();
  99. return error;
  100. }
  101. DWORD
  102. CAddressList::SetList(
  103. IN struct addrinfo FAR *lpAddrInfo
  104. )
  105. /*++
  106. Routine Description:
  107. Sets the list contents from the addrinfo. Basically just a wrapper
  108. around AddrInfoToAddressList() that also grabs the critical section.
  109. Arguments:
  110. lpAddrInfo - Pointer to addrinfo containing resolved addresses to add.
  111. Return Value:
  112. DWORD
  113. Success - ERROR_SUCCESS
  114. Failure - ERROR_NOT_ENOUGH_MEMORY
  115. --*/
  116. {
  117. Acquire();
  118. FreeList();
  119. DWORD error = AddrInfoToAddressList(lpAddrInfo);
  120. Release();
  121. return error;
  122. }
  123. BOOL
  124. CAddressList::GetNextAddress(
  125. OUT LPDWORD lpdwResolutionId,
  126. IN OUT LPDWORD lpdwIndex,
  127. IN INTERNET_PORT nPort,
  128. OUT LPCSADDR_INFO lpAddressInfo
  129. )
  130. /*++
  131. Routine Description:
  132. Get next address to use when connecting. If we already have a preferred
  133. address, use that. We make a copy of the address to use in the caller's
  134. data space
  135. Arguments:
  136. lpdwResolutionId - used to determine whether the address list has been
  137. resolved between calls
  138. lpdwIndex - IN: current index tried; -1 if we want to try default
  139. OUT: index of address address returned if successful
  140. nPort - which port we want to connect to
  141. lpAddressInfo - pointer to returned address if successful
  142. Return Value:
  143. BOOL
  144. TRUE - lpResolvedAddress contains resolved address to use
  145. FALSE - need to (re-)resolve name
  146. --*/
  147. {
  148. DEBUG_ENTER((DBG_SOCKETS,
  149. Bool,
  150. "CAddressList::GetNextAddress",
  151. "%#x [%d], %#x [%d], %d, %#x",
  152. lpdwResolutionId,
  153. *lpdwResolutionId,
  154. lpdwIndex,
  155. *lpdwIndex,
  156. nPort,
  157. lpAddressInfo
  158. ));
  159. PERF_ENTER(GetNextAddress);
  160. BOOL bOk = TRUE;
  161. //
  162. // if we tried all the addresses and failed already, re-resolve the name
  163. //
  164. Acquire();
  165. if (m_BadAddressCount < m_AddressCount) {
  166. if (*lpdwIndex != (DWORD)-1) {
  167. INET_ASSERT(m_BadAddressCount < m_AddressCount);
  168. INT i = 0;
  169. m_CurrentAddress = *lpdwIndex;
  170. INET_ASSERT((m_CurrentAddress >= 0)
  171. && (m_CurrentAddress < m_AddressCount));
  172. if ((m_CurrentAddress < 0) || (m_CurrentAddress >= m_AddressCount)) {
  173. m_CurrentAddress = 0;
  174. }
  175. do {
  176. NextAddress();
  177. if (++i == m_AddressCount) {
  178. bOk = FALSE;
  179. break;
  180. }
  181. } while (!IsCurrentAddressValid());
  182. }
  183. //
  184. // check to make sure this address hasn't expired
  185. //
  186. //if (!CheckHostentCacheTtl()) {
  187. // bOk = FALSE;
  188. //}
  189. } else {
  190. DEBUG_PRINT(SOCKETS,
  191. INFO,
  192. ("exhausted %d addresses\n",
  193. m_BadAddressCount
  194. ));
  195. bOk = FALSE;
  196. }
  197. if (bOk) {
  198. DWORD dwLocalLength = LocalSockaddrLength();
  199. LPBYTE lpRemoteAddr = (LPBYTE)(lpAddressInfo + 1) + dwLocalLength;
  200. memcpy(lpAddressInfo + 1, LocalSockaddr(), dwLocalLength);
  201. memcpy(lpRemoteAddr, RemoteSockaddr(), RemoteSockaddrLength());
  202. lpAddressInfo->LocalAddr.lpSockaddr = (LPSOCKADDR)(lpAddressInfo + 1);
  203. lpAddressInfo->LocalAddr.iSockaddrLength = dwLocalLength;
  204. lpAddressInfo->RemoteAddr.lpSockaddr = (LPSOCKADDR)lpRemoteAddr;
  205. lpAddressInfo->RemoteAddr.iSockaddrLength = RemoteSockaddrLength();
  206. lpAddressInfo->iSocketType = SocketType();
  207. lpAddressInfo->iProtocol = Protocol();
  208. //
  209. // The port number field is in the same location in both a
  210. // sockaddr_in and a sockaddr_in6, so it is safe to cast the
  211. // sockaddr to sockaddr_in here - this works for IPv4 or IPv6.
  212. //
  213. INET_ASSERT(offsetof(SOCKADDR_IN, sin_port) ==
  214. offsetof(SOCKADDR_IN6, sin6_port));
  215. ((LPSOCKADDR_IN)lpAddressInfo->RemoteAddr.lpSockaddr)->sin_port =
  216. _I_htons((unsigned short)nPort);
  217. *lpdwIndex = m_CurrentAddress;
  218. DEBUG_PRINT(SOCKETS,
  219. INFO,
  220. ("current address = %d.%d.%d.%d\n",
  221. ((LPBYTE)RemoteSockaddr())[4] & 0xff,
  222. ((LPBYTE)RemoteSockaddr())[5] & 0xff,
  223. ((LPBYTE)RemoteSockaddr())[6] & 0xff,
  224. ((LPBYTE)RemoteSockaddr())[7] & 0xff
  225. ));
  226. //dprintf("returning address %d.%d.%d.%d, index %d:%d\n",
  227. // ((LPBYTE)RemoteSockaddr())[4] & 0xff,
  228. // ((LPBYTE)RemoteSockaddr())[5] & 0xff,
  229. // ((LPBYTE)RemoteSockaddr())[6] & 0xff,
  230. // ((LPBYTE)RemoteSockaddr())[7] & 0xff,
  231. // m_ResolutionId,
  232. // m_CurrentAddress
  233. // );
  234. }
  235. *lpdwResolutionId = m_ResolutionId;
  236. DEBUG_PRINT(SOCKETS,
  237. INFO,
  238. ("ResolutionId = %d, Index = %d\n",
  239. m_ResolutionId,
  240. m_CurrentAddress
  241. ));
  242. Release();
  243. PERF_LEAVE(GetNextAddress);
  244. DEBUG_LEAVE(bOk);
  245. return bOk;
  246. }
  247. VOID
  248. CAddressList::InvalidateAddress(
  249. IN DWORD dwResolutionId,
  250. IN DWORD dwAddressIndex
  251. )
  252. /*++
  253. Routine Description:
  254. We failed to create a connection. Invalidate the address so other requests
  255. will try another address
  256. Arguments:
  257. dwResolutionId - used to ensure coherency of address list
  258. dwAddressIndex - which address to invalidate
  259. Return Value:
  260. None.
  261. --*/
  262. {
  263. DEBUG_ENTER((DBG_SOCKETS,
  264. None,
  265. "CAddressList::InvalidateAddress",
  266. "%d, %d",
  267. dwResolutionId,
  268. dwAddressIndex
  269. ));
  270. //dprintf("invalidating %d.%d.%d.%d, index %d:%d\n",
  271. // ((LPBYTE)RemoteSockaddr())[4] & 0xff,
  272. // ((LPBYTE)RemoteSockaddr())[5] & 0xff,
  273. // ((LPBYTE)RemoteSockaddr())[6] & 0xff,
  274. // ((LPBYTE)RemoteSockaddr())[7] & 0xff,
  275. // dwResolutionId,
  276. // dwAddressIndex
  277. // );
  278. Acquire();
  279. //
  280. // only do this if the list is the same age as when the caller last tried
  281. // an address
  282. //
  283. if (dwResolutionId == m_ResolutionId) {
  284. INET_ASSERT(((INT)dwAddressIndex >= 0)
  285. && ((INT)dwAddressIndex < m_AddressCount));
  286. if (dwAddressIndex < (DWORD)m_AddressCount) {
  287. m_Addresses[dwAddressIndex].IsValid = FALSE;
  288. DEBUG_PRINT(SOCKETS,
  289. INFO,
  290. ("invalidated address %d.%d.%d.%d\n",
  291. ((LPBYTE)RemoteSockaddr())[4] & 0xff,
  292. ((LPBYTE)RemoteSockaddr())[5] & 0xff,
  293. ((LPBYTE)RemoteSockaddr())[6] & 0xff,
  294. ((LPBYTE)RemoteSockaddr())[7] & 0xff
  295. ));
  296. INET_ASSERT(m_BadAddressCount <= m_AddressCount);
  297. if (m_BadAddressCount < m_AddressCount) {
  298. ++m_BadAddressCount;
  299. if (m_BadAddressCount < m_AddressCount) {
  300. for (int i = 0;
  301. !IsCurrentAddressValid() && (i < m_AddressCount);
  302. ++i) {
  303. NextAddress();
  304. }
  305. }
  306. }
  307. }
  308. }
  309. Release();
  310. DEBUG_LEAVE(0);
  311. }
  312. DWORD
  313. CAddressList::ResolveHost(
  314. IN LPSTR lpszHostName,
  315. IN OUT LPDWORD lpdwResolutionId,
  316. IN DWORD dwFlags
  317. )
  318. /*++
  319. Routine Description:
  320. Resolves host name (or (IP-)address)
  321. BUGBUG: Ideally, we don't want to keep hold of worker threads if we are in
  322. the blocking gethostbyname() call. But correctly handling this is
  323. difficult, so we always block the thread while we are resolving.
  324. For this reason, an async request being run on an app thread should
  325. have switched to a worker thread before calling this function.
  326. Arguments:
  327. lpszHostName - host name (or IP-address) to resolve
  328. lpdwResolutionId - used to determine whether entry changed
  329. dwFlags - controlling request:
  330. SF_INDICATE - if set, make indications via callback
  331. SF_FORCE - if set, force (re-)resolve
  332. Return Value:
  333. DWORD
  334. Success - ERROR_SUCCESS
  335. Name successfully resolved
  336. Failure - ERROR_INTERNET_NAME_NOT_RESOLVED
  337. Couldn't resolve the name
  338. ERROR_NOT_ENOUGH_MEMORY
  339. Couldn't allocate memory for the FSM
  340. --*/
  341. {
  342. DEBUG_ENTER((DBG_SOCKETS,
  343. Dword,
  344. "CAddressList::ResolveHost",
  345. "%q, %d, %#x",
  346. lpszHostName,
  347. *lpdwResolutionId,
  348. dwFlags
  349. ));
  350. DWORD error;
  351. if (IsOffline()) {
  352. error = ERROR_INTERNET_OFFLINE;
  353. goto quit;
  354. }
  355. error = DoFsm(new CFsm_ResolveHost(lpszHostName,
  356. lpdwResolutionId,
  357. dwFlags,
  358. this
  359. ));
  360. quit:
  361. DEBUG_LEAVE(error);
  362. return error;
  363. }
  364. DWORD
  365. CFsm_ResolveHost::RunSM(
  366. IN CFsm * Fsm
  367. )
  368. {
  369. DEBUG_ENTER((DBG_SESSION,
  370. Dword,
  371. "CFsm_ResolveHost::RunSM",
  372. "%#x",
  373. Fsm
  374. ));
  375. CAddressList * pAddressList = (CAddressList *)Fsm->GetContext();
  376. CFsm_ResolveHost * stateMachine = (CFsm_ResolveHost *)Fsm;
  377. DWORD error;
  378. switch (Fsm->GetState()) {
  379. case FSM_STATE_INIT:
  380. case FSM_STATE_CONTINUE:
  381. error = pAddressList->ResolveHost_Fsm(stateMachine);
  382. break;
  383. case FSM_STATE_ERROR:
  384. error = Fsm->GetError();
  385. Fsm->SetDone();
  386. break;
  387. default:
  388. error = ERROR_INTERNET_INTERNAL_ERROR;
  389. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  390. INET_ASSERT(FALSE);
  391. break;
  392. }
  393. DEBUG_LEAVE(error);
  394. return error;
  395. }
  396. DWORD
  397. CAddressList::ResolveHost_Fsm(
  398. IN CFsm_ResolveHost * Fsm
  399. )
  400. {
  401. DEBUG_ENTER((DBG_SOCKETS,
  402. Dword,
  403. "CAddressList::ResolveHost_Fsm",
  404. "%#x(%q, %#x [%d], %#x)",
  405. Fsm,
  406. Fsm->m_lpszHostName,
  407. Fsm->m_lpdwResolutionId,
  408. *Fsm->m_lpdwResolutionId,
  409. Fsm->m_dwFlags
  410. ));
  411. PERF_ENTER(ResolveHost);
  412. //
  413. // restore variables from FSM object
  414. //
  415. CFsm_ResolveHost & fsm = *Fsm;
  416. LPSTR lpszHostName = fsm.m_lpszHostName;
  417. LPDWORD lpdwResolutionId = fsm.m_lpdwResolutionId;
  418. DWORD dwFlags = fsm.m_dwFlags;
  419. LPINTERNET_THREAD_INFO lpThreadInfo = fsm.GetThreadInfo();
  420. INTERNET_HANDLE_OBJECT * pHandle = fsm.GetMappedHandleObject();
  421. DWORD error = ERROR_SUCCESS;
  422. //
  423. // BUGBUG - RLF 04/23/97
  424. //
  425. // This is sub-optimal. We want to block worker FSMs and free up the worker
  426. // thread. Sync client threads can wait. However, since a clash is not very
  427. // likely, we'll block all threads for now and come up with a better
  428. // solution later (XTLock).
  429. //
  430. // Don't have time to implement the proper solution now
  431. //
  432. Acquire();
  433. //
  434. // if the resolution id is different then the name has already been resolved
  435. //
  436. if (*lpdwResolutionId != m_ResolutionId) {
  437. goto done;
  438. }
  439. //
  440. // if we're an app thread making an async request then go async now rather
  441. // than risk blocking the app thread. This will be the typical scenario for
  442. // IE, and we care about little else
  443. //
  444. // BUGBUG - RLF 05/20/97
  445. //
  446. // We should really lock & test the cache first, but let's do that after
  447. // Beta2 (its perf work)
  448. //
  449. if (!lpThreadInfo->IsAsyncWorkerThread
  450. && pHandle->IsAsyncHandle()
  451. && (fsm.GetAppContext() != INTERNET_NO_CALLBACK)) {
  452. DEBUG_PRINT(SOCKETS,
  453. INFO,
  454. ("async request on app thread - jumping to hyper-drive\n"
  455. ));
  456. error = Fsm->QueueWorkItem();
  457. goto done;
  458. }
  459. //
  460. // throw out current list (if any)
  461. //
  462. FreeList();
  463. //
  464. // let the app know we are resolving the name
  465. //
  466. if (dwFlags & SF_INDICATE) {
  467. InternetIndicateStatusString(INTERNET_STATUS_RESOLVING_NAME,
  468. lpszHostName
  469. );
  470. }
  471. //dprintf("resolving %q\n", lpszHostName);
  472. //
  473. // Figure out if we're being asked to resolve a name or an address literal.
  474. // If getaddrinfo with the AI_NUMERICHOST flag succeeds then we were
  475. // given a string representation of an IPv6 or IPv4 address. Otherwise
  476. // we expect getaddrinfo to return EAI_NONAME.
  477. //
  478. ADDRINFO Hints;
  479. LPADDRINFO lpAddrInfo;
  480. memset(&Hints, 0, sizeof(struct addrinfo));
  481. Hints.ai_flags = AI_NUMERICHOST; // Only check for address literals.
  482. Hints.ai_family = PF_UNSPEC; // Accept any protocol family.
  483. Hints.ai_socktype = SOCK_STREAM; // Constrain results to stream socket.
  484. Hints.ai_protocol = IPPROTO_TCP; // Constrain results to TCP.
  485. error = _I_getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo);
  486. if (error != EAI_NONAME) {
  487. if (error != 0) {
  488. if (error == EAI_MEMORY)
  489. error = ERROR_NOT_ENOUGH_MEMORY;
  490. else
  491. error = ERROR_INTERNET_NAME_NOT_RESOLVED;
  492. goto quit;
  493. }
  494. //
  495. // An IP address (either v4 or v6) was passed in.
  496. // Simply convert to address list representation and quit.
  497. //
  498. // NOTE: Previous versions of this code had a function here to
  499. // make sure the string didn't contain additional info that would
  500. // invalidate the string. For example, "111.111.111.111 .msn.com"
  501. // would allow the navigation to succeed, but the cookies for
  502. // .msn.com would be retrievable, violating cross-domain security.
  503. // We no longer need this check because getaddrinfo is far pickier
  504. // than inetaddr was - getaddrinfo with the AI_NUMERICHOST flag set
  505. // will only accept a string that parses *exactly* as an IP address
  506. // literal. No extra data is allowed.
  507. //
  508. error = SetList(lpAddrInfo);
  509. _I_freeaddrinfo(lpAddrInfo);
  510. goto quit;
  511. }
  512. //
  513. // 255.255.255.255 (or 65535.65535 or 16777215.255) would never work anyway
  514. //
  515. INET_ASSERT(lstrcmp(lpszHostName, "255.255.255.255"));
  516. //
  517. // now try to find the name or address in the cache. If it's not in the
  518. // cache then resolve it
  519. //
  520. DWORD ttl;
  521. LPRESOLVER_CACHE_ENTRY lpResolverCacheEntry;
  522. if (!(dwFlags & SF_FORCE)
  523. && (lpResolverCacheEntry=QueryResolverCache(lpszHostName, NULL, &lpAddrInfo, &ttl))) {
  524. error = SetList(lpAddrInfo);
  525. ReleaseResolverCacheEntry(lpResolverCacheEntry);
  526. ++m_ResolutionId;
  527. } else
  528. {
  529. if (dwFlags & SF_FORCE) {
  530. //ThrowOutResolverCacheEntry(lpszHostName);
  531. }
  532. //
  533. // If we call winsock getaddrinfo() then we don't get to find out the
  534. // time-to-live as returned by DNS, so we have to use the default value
  535. // (LIVE_DEFAULT)
  536. //
  537. Hints.ai_flags = AI_CANONNAME;
  538. LPSTR lpszUTF8HostName = NULL;
  539. LPSTR lpszTempHostName;
  540. if (GlobalUseUTF8ServerForNameRes)
  541. {
  542. DWORD dwUTF8StrLen;
  543. if (lpszUTF8HostName = ConvertMBCSToUTF8(lpszHostName,
  544. lstrlen(lpszHostName),
  545. GetACP(),
  546. &dwUTF8StrLen,
  547. FALSE))
  548. {
  549. lpszTempHostName = lpszHostName;
  550. lpszHostName = lpszUTF8HostName;
  551. }
  552. }
  553. error = _I_getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo);
  554. DEBUG_PRINT(SOCKETS,
  555. INFO,
  556. ("%q %sresolved\n",
  557. lpszHostName,
  558. error ? "NOT " : ""
  559. ));
  560. if (lpszUTF8HostName)
  561. {
  562. delete [] lpszUTF8HostName;
  563. lpszHostName = lpszTempHostName;
  564. }
  565. if (error == 0) {
  566. error = SetList(lpAddrInfo);
  567. AddResolverCacheEntry(lpszHostName, lpAddrInfo, LIVE_DEFAULT);
  568. ++m_ResolutionId;
  569. } else {
  570. if (error == EAI_MEMORY)
  571. error = ERROR_NOT_ENOUGH_MEMORY;
  572. else
  573. error = ERROR_INTERNET_NAME_NOT_RESOLVED;
  574. }
  575. }
  576. quit:
  577. if ((error == ERROR_SUCCESS) && (dwFlags & SF_INDICATE)) {
  578. //
  579. // inform the app that we have resolved the name
  580. //
  581. InternetIndicateStatusAddress(INTERNET_STATUS_NAME_RESOLVED,
  582. RemoteSockaddr(),
  583. RemoteSockaddrLength()
  584. );
  585. }
  586. *lpdwResolutionId = m_ResolutionId;
  587. done:
  588. Release();
  589. if (error != ERROR_IO_PENDING) {
  590. fsm.SetDone();
  591. //PERF_LEAVE(ResolveHost);
  592. }
  593. PERF_LEAVE(ResolveHost);
  594. DEBUG_LEAVE(error);
  595. return error;
  596. }
  597. //
  598. // private methods
  599. //
  600. PRIVATE
  601. DWORD
  602. CAddressList::IPAddressToAddressList(
  603. IN DWORD ipAddr
  604. )
  605. /*++
  606. Routine Description:
  607. Converts an IP-address to a RESOLVED_ADDRESS
  608. Arguments:
  609. ipAddr - IP address to convert
  610. Return Value:
  611. DWORD
  612. Success - ERROR_SUCCESS
  613. Failure - ERROR_NOT_ENOUGH_MEMORY
  614. --*/
  615. {
  616. LPRESOLVED_ADDRESS address = (LPRESOLVED_ADDRESS)ALLOCATE_MEMORY(
  617. LMEM_FIXED,
  618. sizeof(RESOLVED_ADDRESS)
  619. //
  620. // 1 local and 1 remote
  621. // socket address
  622. //
  623. + 2 * sizeof(SOCKADDR)
  624. );
  625. if (address == NULL) {
  626. return ERROR_NOT_ENOUGH_MEMORY;
  627. }
  628. LPBYTE lpVariable;
  629. LPSOCKADDR_IN lpSin;
  630. lpVariable = (LPBYTE)address + (sizeof(RESOLVED_ADDRESS));
  631. //
  632. // For this IP address, build a CSADDR_INFO structure:
  633. // create a local SOCKADDR containing only the address family (AF_INET),
  634. // everything else is zeroed; create a remote SOCKADDR containing the
  635. // address family (AF_INET), zero port value and the IP address
  636. // presented in the arguments
  637. //
  638. address->AddrInfo.LocalAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  639. address->AddrInfo.LocalAddr.iSockaddrLength = sizeof(SOCKADDR);
  640. lpSin = (LPSOCKADDR_IN)lpVariable;
  641. lpVariable += sizeof(*lpSin);
  642. lpSin->sin_family = AF_INET;
  643. lpSin->sin_port = 0;
  644. *(LPDWORD)&lpSin->sin_addr = INADDR_ANY;
  645. memset(lpSin->sin_zero, 0, sizeof(lpSin->sin_zero));
  646. address->AddrInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  647. address->AddrInfo.RemoteAddr.iSockaddrLength = sizeof(SOCKADDR);
  648. lpSin = (LPSOCKADDR_IN)lpVariable;
  649. lpVariable += sizeof(*lpSin);
  650. lpSin->sin_family = AF_INET;
  651. lpSin->sin_port = 0;
  652. *(LPDWORD)&lpSin->sin_addr = ipAddr;
  653. memset(lpSin->sin_zero, 0, sizeof(lpSin->sin_zero));
  654. address->AddrInfo.iSocketType = SOCK_STREAM;
  655. address->AddrInfo.iProtocol = IPPROTO_TCP;
  656. address->IsValid = TRUE;
  657. //
  658. // update the object
  659. //
  660. INET_ASSERT(m_AddressCount == 0);
  661. INET_ASSERT(m_Addresses == NULL);
  662. m_AddressCount = 1;
  663. m_BadAddressCount = 0;
  664. m_Addresses = address;
  665. m_CurrentAddress = 0; // only one to choose from
  666. return ERROR_SUCCESS;
  667. }
  668. PRIVATE
  669. DWORD
  670. CAddressList::HostentToAddressList(
  671. IN LPHOSTENT lpHostent
  672. )
  673. /*++
  674. Routine Description:
  675. Converts a HOSTENT structure to an array of RESOLVED_ADDRESSs
  676. Arguments:
  677. lpHostent - pointer to HOSTENT to convert
  678. Return Value:
  679. DWORD
  680. Success - ERROR_SUCCESS
  681. Failure - ERROR_NOT_ENOUGH_MEMORY
  682. --*/
  683. {
  684. INET_ASSERT(lpHostent != NULL);
  685. LPBYTE * addressList = (LPBYTE *)lpHostent->h_addr_list;
  686. INET_ASSERT(addressList[0]);
  687. //
  688. // first off, figure out how many addresses there are in the hostent
  689. //
  690. int nAddrs;
  691. if (fDontUseDNSLoadBalancing) {
  692. nAddrs = 1;
  693. } else {
  694. for (nAddrs = 0; addressList[nAddrs] != NULL; ++nAddrs) {
  695. /* NOTHING */
  696. }
  697. #ifdef TEST_CODE
  698. nAddrs = 4;
  699. #endif
  700. }
  701. LPRESOLVED_ADDRESS addresses = (LPRESOLVED_ADDRESS)ALLOCATE_MEMORY(
  702. LMEM_FIXED,
  703. nAddrs * (sizeof(RESOLVED_ADDRESS)
  704. //
  705. // need 1 local and 1 remote socket
  706. // address for each
  707. //
  708. + 2 * sizeof(SOCKADDR))
  709. );
  710. if (addresses == NULL) {
  711. return ERROR_NOT_ENOUGH_MEMORY;
  712. }
  713. //
  714. // for each IP address in the hostent, build a RESOLVED_ADDRESS structure:
  715. // create a local SOCKADDR containing only the address family (AF_INET),
  716. // everything else is zeroed; create a remote SOCKADDR containing the
  717. // address family (AF_INET), zero port value, and the IP address from
  718. // the hostent presented in the arguments
  719. //
  720. LPBYTE lpVariable = (LPBYTE)addresses + (nAddrs * sizeof(RESOLVED_ADDRESS));
  721. LPSOCKADDR_IN lpSin;
  722. for (int i = 0; i < nAddrs; ++i) {
  723. addresses[i].AddrInfo.LocalAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  724. addresses[i].AddrInfo.LocalAddr.iSockaddrLength = sizeof(SOCKADDR);
  725. lpSin = (LPSOCKADDR_IN)lpVariable;
  726. lpVariable += sizeof(*lpSin);
  727. lpSin->sin_family = AF_INET;
  728. lpSin->sin_port = 0;
  729. *(LPDWORD)&lpSin->sin_addr = INADDR_ANY;
  730. memset(lpSin->sin_zero, 0, sizeof(lpSin->sin_zero));
  731. addresses[i].AddrInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  732. addresses[i].AddrInfo.RemoteAddr.iSockaddrLength = sizeof(SOCKADDR);
  733. lpSin = (LPSOCKADDR_IN)lpVariable;
  734. lpVariable += sizeof(*lpSin);
  735. lpSin->sin_family = AF_INET;
  736. lpSin->sin_port = 0;
  737. #ifdef TEST_CODE
  738. //if (i) {
  739. *(LPDWORD)&lpSin->sin_addr = 0x04030201;
  740. //*(LPDWORD)&lpSin->sin_addr = 0x1cfe379d;
  741. //}
  742. #else
  743. *(LPDWORD)&lpSin->sin_addr = *(LPDWORD)addressList[i];
  744. #endif
  745. memset(lpSin->sin_zero, 0, sizeof(lpSin->sin_zero));
  746. addresses[i].AddrInfo.iSocketType = SOCK_STREAM;
  747. addresses[i].AddrInfo.iProtocol = IPPROTO_TCP;
  748. addresses[i].IsValid = TRUE;
  749. }
  750. #ifdef TEST_CODE
  751. *((LPDWORD)&((LPSOCKADDR_IN)addresses[3].AddrInfo.RemoteAddr.lpSockaddr)->sin_addr) = *(LPDWORD)addressList[0];
  752. //((LPSOCKADDR_IN)addresses[7].AddrInfo.RemoteAddr.lpSockaddr)->sin_addr = ((LPSOCKADDR_IN)addresses[0].AddrInfo.RemoteAddr.lpSockaddr)->sin_addr;
  753. //*((LPDWORD)&((LPSOCKADDR_IN)addresses[0].AddrInfo.RemoteAddr.lpSockaddr)->sin_addr) = 0x04030201;
  754. #endif
  755. //
  756. // update the object
  757. //
  758. INET_ASSERT(m_AddressCount == 0);
  759. INET_ASSERT(m_Addresses == NULL);
  760. m_AddressCount = nAddrs;
  761. m_BadAddressCount = 0;
  762. m_Addresses = addresses;
  763. m_CurrentAddress = 0;
  764. return ERROR_SUCCESS;
  765. }
  766. PRIVATE
  767. DWORD
  768. CAddressList::AddrInfoToAddressList(
  769. IN struct addrinfo FAR *lpAddrInfo
  770. )
  771. /*++
  772. Routine Description:
  773. Converts an addrinfo structure(s) to an array of RESOLVED_ADDRESSes.
  774. Arguments:
  775. lpAddrInfo - pointer to AddrInfo chain to convert.
  776. Return Value:
  777. DWORD
  778. Success - ERROR_SUCCESS
  779. Failure - ERROR_NOT_ENOUGH_MEMORY
  780. --*/
  781. {
  782. INET_ASSERT(lpAddrInfo != NULL);
  783. struct addrinfo *lpCurrentInfo = lpAddrInfo;
  784. //
  785. // First off, figure out how many addrinfo structs are on the chain.
  786. // And how much memory we'll need to hold them as RESOLVED_ADDRESSes.
  787. // Note we also need space to hold the actual local and remote sockaddrs,
  788. // the RESOLVED_ADDRESS struct only contains the pointers to them.
  789. //
  790. int SpaceNeeded = 0;
  791. int nAddrs = 0;
  792. for (; lpCurrentInfo != NULL; lpCurrentInfo = lpCurrentInfo->ai_next) {
  793. if ((lpCurrentInfo->ai_family != PF_INET) &&
  794. (lpCurrentInfo->ai_family != PF_INET6)) {
  795. //
  796. // Ignore any non-internet addrsses.
  797. // We won't get any with the current getaddrinfo,
  798. // but maybe someday.
  799. //
  800. continue;
  801. }
  802. SpaceNeeded += sizeof(RESOLVED_ADDRESS) +
  803. 2 * lpCurrentInfo->ai_addrlen;
  804. nAddrs++;
  805. if (fDontUseDNSLoadBalancing)
  806. break; // Leave after one.
  807. }
  808. //
  809. // Allocate enough memory to hold these as RESOLVED_ADDRESSes.
  810. //
  811. LPRESOLVED_ADDRESS addresses = (LPRESOLVED_ADDRESS)
  812. ALLOCATE_MEMORY(LMEM_FIXED, SpaceNeeded);
  813. if (addresses == NULL) {
  814. return ERROR_NOT_ENOUGH_MEMORY;
  815. }
  816. //
  817. // For each IP address in the chain, build a RESOLVED_ADDRESS structure:
  818. // create a local SOCKADDR containing only the address family,
  819. // everything else is zeroed; create a remote SOCKADDR containing all
  820. // the values from the addrinfo structure.
  821. //
  822. LPBYTE lpVariable = (LPBYTE)addresses + (nAddrs * sizeof(RESOLVED_ADDRESS));
  823. lpCurrentInfo = lpAddrInfo;
  824. for (int i = 0; i < nAddrs; lpCurrentInfo = lpCurrentInfo->ai_next) {
  825. if ((lpCurrentInfo->ai_family != PF_INET) &&
  826. (lpCurrentInfo->ai_family != PF_INET6)) {
  827. //
  828. // Ignore any non-internet addrsses.
  829. // We won't get any with the current getaddrinfo,
  830. // but maybe someday.
  831. //
  832. continue;
  833. }
  834. addresses[i].AddrInfo.LocalAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  835. addresses[i].AddrInfo.LocalAddr.iSockaddrLength =
  836. lpCurrentInfo->ai_addrlen;
  837. memset(lpVariable, 0, lpCurrentInfo->ai_addrlen);
  838. addresses[i].AddrInfo.LocalAddr.lpSockaddr->sa_family =
  839. (unsigned short)lpCurrentInfo->ai_family;
  840. lpVariable += lpCurrentInfo->ai_addrlen;
  841. addresses[i].AddrInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR)lpVariable;
  842. addresses[i].AddrInfo.RemoteAddr.iSockaddrLength =
  843. lpCurrentInfo->ai_addrlen;
  844. memcpy(lpVariable, lpCurrentInfo->ai_addr, lpCurrentInfo->ai_addrlen);
  845. lpVariable += lpCurrentInfo->ai_addrlen;
  846. addresses[i].AddrInfo.iSocketType = lpCurrentInfo->ai_socktype;
  847. addresses[i].AddrInfo.iProtocol = lpCurrentInfo->ai_protocol;
  848. addresses[i].IsValid = TRUE;
  849. i++;
  850. }
  851. //
  852. // update the object
  853. //
  854. INET_ASSERT(m_AddressCount == 0);
  855. INET_ASSERT(m_Addresses == NULL);
  856. m_AddressCount = nAddrs;
  857. m_BadAddressCount = 0;
  858. m_Addresses = addresses;
  859. m_CurrentAddress = 0;
  860. return ERROR_SUCCESS;
  861. }