hostip.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2008, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. ***************************************************************************/
  23. #include "setup.h"
  24. #include <string.h>
  25. #ifdef NEED_MALLOC_H
  26. #include <malloc.h>
  27. #endif
  28. #ifdef HAVE_SYS_SOCKET_H
  29. #include <sys/socket.h>
  30. #endif
  31. #ifdef HAVE_NETINET_IN_H
  32. #include <netinet/in.h>
  33. #endif
  34. #ifdef HAVE_NETDB_H
  35. #include <netdb.h>
  36. #endif
  37. #ifdef HAVE_ARPA_INET_H
  38. #include <arpa/inet.h>
  39. #endif
  40. #ifdef HAVE_STDLIB_H
  41. #include <stdlib.h> /* required for free() prototypes */
  42. #endif
  43. #ifdef HAVE_UNISTD_H
  44. #include <unistd.h> /* for the close() proto */
  45. #endif
  46. #ifdef VMS
  47. #include <in.h>
  48. #include <inet.h>
  49. #include <stdlib.h>
  50. #endif
  51. #ifdef HAVE_SETJMP_H
  52. #include <setjmp.h>
  53. #endif
  54. #ifdef HAVE_PROCESS_H
  55. #include <process.h>
  56. #endif
  57. #include "urldata.h"
  58. #include "sendf.h"
  59. #include "hostip.h"
  60. #include "hash.h"
  61. #include "share.h"
  62. #include "strerror.h"
  63. #include "url.h"
  64. #include "inet_ntop.h"
  65. #define _MPRINTF_REPLACE /* use our functions only */
  66. #include <curl/mprintf.h>
  67. #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
  68. #include "inet_ntoa_r.h"
  69. #endif
  70. #include "memory.h"
  71. /* The last #include file should be: */
  72. #include "memdebug.h"
  73. /*
  74. * hostip.c explained
  75. * ==================
  76. *
  77. * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
  78. * source file are these:
  79. *
  80. * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
  81. * that. The host may not be able to resolve IPv6, but we don't really have to
  82. * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
  83. * defined.
  84. *
  85. * CURLRES_ARES - is defined if libcurl is built to use c-ares for
  86. * asynchronous name resolves. This can be Windows or *nix.
  87. *
  88. * CURLRES_THREADED - is defined if libcurl is built to run under (native)
  89. * Windows, and then the name resolve will be done in a new thread, and the
  90. * supported API will be the same as for ares-builds.
  91. *
  92. * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
  93. * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
  94. * defined.
  95. *
  96. * The host*.c sources files are split up like this:
  97. *
  98. * hostip.c - method-independent resolver functions and utility functions
  99. * hostasyn.c - functions for asynchronous name resolves
  100. * hostsyn.c - functions for synchronous name resolves
  101. * hostares.c - functions for ares-using name resolves
  102. * hostthre.c - functions for threaded name resolves
  103. * hostip4.c - ipv4-specific functions
  104. * hostip6.c - ipv6-specific functions
  105. *
  106. * The hostip.h is the united header file for all this. It defines the
  107. * CURLRES_* defines based on the config*.h and setup.h defines.
  108. */
  109. /* These two symbols are for the global DNS cache */
  110. static struct curl_hash hostname_cache;
  111. static int host_cache_initialized;
  112. static void freednsentry(void *freethis);
  113. /*
  114. * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
  115. * Global DNS cache is general badness. Do not use. This will be removed in
  116. * a future version. Use the share interface instead!
  117. *
  118. * Returns a struct curl_hash pointer on success, NULL on failure.
  119. */
  120. struct curl_hash *Curl_global_host_cache_init(void)
  121. {
  122. int rc = 0;
  123. if(!host_cache_initialized) {
  124. rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
  125. Curl_str_key_compare, freednsentry);
  126. if(!rc)
  127. host_cache_initialized = 1;
  128. }
  129. return rc?NULL:&hostname_cache;
  130. }
  131. /*
  132. * Destroy and cleanup the global DNS cache
  133. */
  134. void Curl_global_host_cache_dtor(void)
  135. {
  136. if(host_cache_initialized) {
  137. Curl_hash_clean(&hostname_cache);
  138. host_cache_initialized = 0;
  139. }
  140. }
  141. /*
  142. * Return # of adresses in a Curl_addrinfo struct
  143. */
  144. int Curl_num_addresses(const Curl_addrinfo *addr)
  145. {
  146. int i;
  147. for (i = 0; addr; addr = addr->ai_next, i++)
  148. ; /* empty loop */
  149. return i;
  150. }
  151. /*
  152. * Curl_printable_address() returns a printable version of the 1st address
  153. * given in the 'ip' argument. The result will be stored in the buf that is
  154. * bufsize bytes big.
  155. *
  156. * If the conversion fails, it returns NULL.
  157. */
  158. const char *Curl_printable_address(const Curl_addrinfo *ip,
  159. char *buf, size_t bufsize)
  160. {
  161. const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
  162. int af = ip->ai_family;
  163. #ifdef CURLRES_IPV6
  164. const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
  165. #else
  166. const void *ip6 = NULL;
  167. #endif
  168. return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
  169. }
  170. /*
  171. * Return a hostcache id string for the providing host + port, to be used by
  172. * the DNS caching.
  173. */
  174. static char *
  175. create_hostcache_id(const char *server, int port)
  176. {
  177. /* create and return the new allocated entry */
  178. return aprintf("%s:%d", server, port);
  179. }
  180. struct hostcache_prune_data {
  181. long cache_timeout;
  182. time_t now;
  183. };
  184. /*
  185. * This function is set as a callback to be called for every entry in the DNS
  186. * cache when we want to prune old unused entries.
  187. *
  188. * Returning non-zero means remove the entry, return 0 to keep it in the
  189. * cache.
  190. */
  191. static int
  192. hostcache_timestamp_remove(void *datap, void *hc)
  193. {
  194. struct hostcache_prune_data *data =
  195. (struct hostcache_prune_data *) datap;
  196. struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
  197. if((data->now - c->timestamp < data->cache_timeout) ||
  198. c->inuse) {
  199. /* please don't remove */
  200. return 0;
  201. }
  202. /* fine, remove */
  203. return 1;
  204. }
  205. /*
  206. * Prune the DNS cache. This assumes that a lock has already been taken.
  207. */
  208. static void
  209. hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
  210. {
  211. struct hostcache_prune_data user;
  212. user.cache_timeout = cache_timeout;
  213. user.now = now;
  214. Curl_hash_clean_with_criterium(hostcache,
  215. (void *) &user,
  216. hostcache_timestamp_remove);
  217. }
  218. /*
  219. * Library-wide function for pruning the DNS cache. This function takes and
  220. * returns the appropriate locks.
  221. */
  222. void Curl_hostcache_prune(struct SessionHandle *data)
  223. {
  224. time_t now;
  225. if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
  226. /* cache forever means never prune, and NULL hostcache means
  227. we can't do it */
  228. return;
  229. if(data->share)
  230. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  231. time(&now);
  232. /* Remove outdated and unused entries from the hostcache */
  233. hostcache_prune(data->dns.hostcache,
  234. data->set.dns_cache_timeout,
  235. now);
  236. if(data->share)
  237. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  238. }
  239. /*
  240. * Check if the entry should be pruned. Assumes a locked cache.
  241. */
  242. static int
  243. remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
  244. {
  245. struct hostcache_prune_data user;
  246. if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
  247. /* cache forever means never prune, and NULL hostcache means
  248. we can't do it */
  249. return 0;
  250. time(&user.now);
  251. user.cache_timeout = data->set.dns_cache_timeout;
  252. if( !hostcache_timestamp_remove(&user,dns) )
  253. return 0;
  254. Curl_hash_clean_with_criterium(data->dns.hostcache,
  255. (void *) &user,
  256. hostcache_timestamp_remove);
  257. return 1;
  258. }
  259. #ifdef HAVE_SIGSETJMP
  260. /* Beware this is a global and unique instance. This is used to store the
  261. return address that we can jump back to from inside a signal handler. This
  262. is not thread-safe stuff. */
  263. sigjmp_buf curl_jmpenv;
  264. #endif
  265. /*
  266. * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
  267. *
  268. * When calling Curl_resolv() has resulted in a response with a returned
  269. * address, we call this function to store the information in the dns
  270. * cache etc
  271. *
  272. * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
  273. */
  274. struct Curl_dns_entry *
  275. Curl_cache_addr(struct SessionHandle *data,
  276. Curl_addrinfo *addr,
  277. const char *hostname,
  278. int port)
  279. {
  280. char *entry_id;
  281. size_t entry_len;
  282. struct Curl_dns_entry *dns;
  283. struct Curl_dns_entry *dns2;
  284. time_t now;
  285. /* Create an entry id, based upon the hostname and port */
  286. entry_id = create_hostcache_id(hostname, port);
  287. /* If we can't create the entry id, fail */
  288. if(!entry_id)
  289. return NULL;
  290. entry_len = strlen(entry_id);
  291. /* Create a new cache entry */
  292. dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
  293. if(!dns) {
  294. free(entry_id);
  295. return NULL;
  296. }
  297. dns->inuse = 0; /* init to not used */
  298. dns->addr = addr; /* this is the address(es) */
  299. /* Store the resolved data in our DNS cache. This function may return a
  300. pointer to an existing struct already present in the hash, and it may
  301. return the same argument we pass in. Make no assumptions. */
  302. dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
  303. (void *)dns);
  304. if(!dns2) {
  305. /* Major badness, run away. */
  306. free(dns);
  307. free(entry_id);
  308. return NULL;
  309. }
  310. time(&now);
  311. dns = dns2;
  312. dns->timestamp = now; /* used now */
  313. dns->inuse++; /* mark entry as in-use */
  314. /* free the allocated entry_id again */
  315. free(entry_id);
  316. return dns;
  317. }
  318. /*
  319. * Curl_resolv() is the main name resolve function within libcurl. It resolves
  320. * a name and returns a pointer to the entry in the 'entry' argument (if one
  321. * is provided). This function might return immediately if we're using asynch
  322. * resolves. See the return codes.
  323. *
  324. * The cache entry we return will get its 'inuse' counter increased when this
  325. * function is used. You MUST call Curl_resolv_unlock() later (when you're
  326. * done using this struct) to decrease the counter again.
  327. *
  328. * Return codes:
  329. *
  330. * CURLRESOLV_ERROR (-1) = error, no pointer
  331. * CURLRESOLV_RESOLVED (0) = OK, pointer provided
  332. * CURLRESOLV_PENDING (1) = waiting for response, no pointer
  333. */
  334. int Curl_resolv(struct connectdata *conn,
  335. const char *hostname,
  336. int port,
  337. struct Curl_dns_entry **entry)
  338. {
  339. char *entry_id = NULL;
  340. struct Curl_dns_entry *dns = NULL;
  341. size_t entry_len;
  342. struct SessionHandle *data = conn->data;
  343. CURLcode result;
  344. int rc = CURLRESOLV_ERROR; /* default to failure */
  345. *entry = NULL;
  346. #ifdef HAVE_SIGSETJMP
  347. /* this allows us to time-out from the name resolver, as the timeout
  348. will generate a signal and we will siglongjmp() from that here */
  349. if(!data->set.no_signal) {
  350. if(sigsetjmp(curl_jmpenv, 1)) {
  351. /* this is coming from a siglongjmp() */
  352. failf(data, "name lookup timed out");
  353. return rc;
  354. }
  355. }
  356. #endif
  357. /* Create an entry id, based upon the hostname and port */
  358. entry_id = create_hostcache_id(hostname, port);
  359. /* If we can't create the entry id, fail */
  360. if(!entry_id)
  361. return rc;
  362. entry_len = strlen(entry_id);
  363. if(data->share)
  364. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  365. /* See if its already in our dns cache */
  366. dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
  367. /* See whether the returned entry is stale. Done before we release lock */
  368. if( remove_entry_if_stale(data, dns) )
  369. dns = NULL; /* the memory deallocation is being handled by the hash */
  370. if(dns) {
  371. dns->inuse++; /* we use it! */
  372. rc = CURLRESOLV_RESOLVED;
  373. }
  374. if(data->share)
  375. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  376. /* free the allocated entry_id again */
  377. free(entry_id);
  378. if(!dns) {
  379. /* The entry was not in the cache. Resolve it to IP address */
  380. Curl_addrinfo *addr;
  381. int respwait;
  382. /* Check what IP specifics the app has requested and if we can provide it.
  383. * If not, bail out. */
  384. if(!Curl_ipvalid(data))
  385. return CURLRESOLV_ERROR;
  386. /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
  387. non-zero value indicating that we need to wait for the response to the
  388. resolve call */
  389. addr = Curl_getaddrinfo(conn, hostname, port, &respwait);
  390. if(!addr) {
  391. if(respwait) {
  392. /* the response to our resolve call will come asynchronously at
  393. a later time, good or bad */
  394. /* First, check that we haven't received the info by now */
  395. result = Curl_is_resolved(conn, &dns);
  396. if(result) /* error detected */
  397. return CURLRESOLV_ERROR;
  398. if(dns)
  399. rc = CURLRESOLV_RESOLVED; /* pointer provided */
  400. else
  401. rc = CURLRESOLV_PENDING; /* no info yet */
  402. }
  403. }
  404. else {
  405. if(data->share)
  406. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  407. /* we got a response, store it in the cache */
  408. dns = Curl_cache_addr(data, addr, hostname, port);
  409. if(data->share)
  410. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  411. if(!dns)
  412. /* returned failure, bail out nicely */
  413. Curl_freeaddrinfo(addr);
  414. else
  415. rc = CURLRESOLV_RESOLVED;
  416. }
  417. }
  418. *entry = dns;
  419. return rc;
  420. }
  421. /*
  422. * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
  423. * made, the struct may be destroyed due to pruning. It is important that only
  424. * one unlock is made for each Curl_resolv() call.
  425. */
  426. void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
  427. {
  428. DEBUGASSERT(dns && (dns->inuse>0));
  429. if(data->share)
  430. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  431. dns->inuse--;
  432. if(data->share)
  433. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  434. }
  435. /*
  436. * File-internal: free a cache dns entry.
  437. */
  438. static void freednsentry(void *freethis)
  439. {
  440. struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
  441. Curl_freeaddrinfo(p->addr);
  442. free(p);
  443. }
  444. /*
  445. * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
  446. */
  447. struct curl_hash *Curl_mk_dnscache(void)
  448. {
  449. return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
  450. }
  451. #ifdef CURLRES_ADDRINFO_COPY
  452. /* align on even 64bit boundaries */
  453. #define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
  454. /*
  455. * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
  456. * returns a pointer to the malloc()ed copy. You need to call free() on the
  457. * returned buffer when you're done with it.
  458. */
  459. Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
  460. {
  461. const struct hostent *orig = org;
  462. return Curl_he2ai(orig, port);
  463. }
  464. #endif /* CURLRES_ADDRINFO_COPY */
  465. /***********************************************************************
  466. * Only for plain-ipv4 and c-ares builds (NOTE: c-ares builds can be IPv6
  467. * enabled)
  468. **********************************************************************/
  469. #if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
  470. /*
  471. * This is a function for freeing name information in a protocol independent
  472. * way.
  473. */
  474. void Curl_freeaddrinfo(Curl_addrinfo *ai)
  475. {
  476. Curl_addrinfo *next;
  477. /* walk over the list and free all entries */
  478. while(ai) {
  479. next = ai->ai_next;
  480. if(ai->ai_canonname)
  481. free(ai->ai_canonname);
  482. free(ai);
  483. ai = next;
  484. }
  485. }
  486. struct namebuf {
  487. struct hostent hostentry;
  488. char *h_addr_list[2];
  489. struct in_addr addrentry;
  490. char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
  491. };
  492. /*
  493. * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
  494. * together with a pointer to the string version of the address, and it
  495. * returns a Curl_addrinfo chain filled in correctly with information for this
  496. * address/host.
  497. *
  498. * The input parameters ARE NOT checked for validity but they are expected
  499. * to have been checked already when this is called.
  500. */
  501. Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
  502. {
  503. Curl_addrinfo *ai;
  504. #if defined(VMS) && \
  505. defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
  506. #pragma pointer_size save
  507. #pragma pointer_size short
  508. #pragma message disable PTRMISMATCH
  509. #endif
  510. struct hostent *h;
  511. struct in_addr *addrentry;
  512. struct namebuf buffer;
  513. struct namebuf *buf = &buffer;
  514. h = &buf->hostentry;
  515. h->h_addr_list = &buf->h_addr_list[0];
  516. addrentry = &buf->addrentry;
  517. #ifdef _CRAYC
  518. /* On UNICOS, s_addr is a bit field and for some reason assigning to it
  519. * doesn't work. There must be a better fix than this ugly hack.
  520. */
  521. memcpy(addrentry, &num, SIZEOF_in_addr);
  522. #else
  523. addrentry->s_addr = num;
  524. #endif
  525. h->h_addr_list[0] = (char*)addrentry;
  526. h->h_addr_list[1] = NULL;
  527. h->h_addrtype = AF_INET;
  528. h->h_length = sizeof(*addrentry);
  529. h->h_name = &buf->h_name[0];
  530. h->h_aliases = NULL;
  531. /* Now store the dotted version of the address */
  532. snprintf((char *)h->h_name, 16, "%s", hostname);
  533. #if defined(VMS) && \
  534. defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
  535. #pragma pointer_size restore
  536. #pragma message enable PTRMISMATCH
  537. #endif
  538. ai = Curl_he2ai(h, port);
  539. return ai;
  540. }
  541. /*
  542. * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
  543. * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
  544. * stacks, but for all hosts and environments.
  545. *
  546. * Curl_addrinfo defined in "lib/hostip.h"
  547. *
  548. * struct Curl_addrinfo {
  549. * int ai_flags;
  550. * int ai_family;
  551. * int ai_socktype;
  552. * int ai_protocol;
  553. * socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo *
  554. * char *ai_canonname;
  555. * struct sockaddr *ai_addr;
  556. * struct Curl_addrinfo *ai_next;
  557. * };
  558. *
  559. * hostent defined in <netdb.h>
  560. *
  561. * struct hostent {
  562. * char *h_name;
  563. * char **h_aliases;
  564. * int h_addrtype;
  565. * int h_length;
  566. * char **h_addr_list;
  567. * };
  568. *
  569. * for backward compatibility:
  570. *
  571. * #define h_addr h_addr_list[0]
  572. */
  573. Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
  574. {
  575. Curl_addrinfo *ai;
  576. Curl_addrinfo *prevai = NULL;
  577. Curl_addrinfo *firstai = NULL;
  578. struct sockaddr_in *addr;
  579. #ifdef CURLRES_IPV6
  580. struct sockaddr_in6 *addr6;
  581. #endif /* CURLRES_IPV6 */
  582. int i;
  583. struct in_addr *curr;
  584. if(!he)
  585. /* no input == no output! */
  586. return NULL;
  587. for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) {
  588. int ss_size;
  589. #ifdef CURLRES_IPV6
  590. if (he->h_addrtype == AF_INET6)
  591. ss_size = sizeof (struct sockaddr_in6);
  592. else
  593. #endif /* CURLRES_IPV6 */
  594. ss_size = sizeof (struct sockaddr_in);
  595. ai = calloc(1, sizeof(Curl_addrinfo) + ss_size);
  596. if(!ai)
  597. break;
  598. if(!firstai)
  599. /* store the pointer we want to return from this function */
  600. firstai = ai;
  601. if(prevai)
  602. /* make the previous entry point to this */
  603. prevai->ai_next = ai;
  604. ai->ai_family = he->h_addrtype;
  605. /* we return all names as STREAM, so when using this address for TFTP
  606. the type must be ignored and conn->socktype be used instead! */
  607. ai->ai_socktype = SOCK_STREAM;
  608. ai->ai_addrlen = ss_size;
  609. /* make the ai_addr point to the address immediately following this struct
  610. and use that area to store the address */
  611. ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo));
  612. /* need to free this eventually */
  613. ai->ai_canonname = strdup(he->h_name);
  614. /* leave the rest of the struct filled with zero */
  615. switch (ai->ai_family) {
  616. case AF_INET:
  617. addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */
  618. memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr));
  619. addr->sin_family = (unsigned short)(he->h_addrtype);
  620. addr->sin_port = htons((unsigned short)port);
  621. break;
  622. #ifdef CURLRES_IPV6
  623. case AF_INET6:
  624. addr6 = (struct sockaddr_in6 *)ai->ai_addr; /* storage area for this info */
  625. memcpy((char *)&(addr6->sin6_addr), curr, sizeof(struct in6_addr));
  626. addr6->sin6_family = (unsigned short)(he->h_addrtype);
  627. addr6->sin6_port = htons((unsigned short)port);
  628. break;
  629. #endif /* CURLRES_IPV6 */
  630. }
  631. prevai = ai;
  632. }
  633. return firstai;
  634. }
  635. #endif /* CURLRES_IPV4 || CURLRES_ARES */