hostares.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
  58. #undef in_addr_t
  59. #define in_addr_t unsigned long
  60. #endif
  61. #include "urldata.h"
  62. #include "sendf.h"
  63. #include "hostip.h"
  64. #include "hash.h"
  65. #include "share.h"
  66. #include "strerror.h"
  67. #include "url.h"
  68. #include "multiif.h"
  69. #include "inet_pton.h"
  70. #include "connect.h"
  71. #include "select.h"
  72. #define _MPRINTF_REPLACE /* use our functions only */
  73. #include <curl/mprintf.h>
  74. #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
  75. #include "inet_ntoa_r.h"
  76. #endif
  77. #include "memory.h"
  78. /* The last #include file should be: */
  79. #include "memdebug.h"
  80. /***********************************************************************
  81. * Only for ares-enabled builds
  82. **********************************************************************/
  83. #ifdef CURLRES_ARES
  84. /*
  85. * Curl_resolv_fdset() is called when someone from the outside world (using
  86. * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
  87. * ares. The caller must make sure that this function is only called when we
  88. * have a working ares channel.
  89. *
  90. * Returns: CURLE_OK always!
  91. */
  92. int Curl_resolv_getsock(struct connectdata *conn,
  93. curl_socket_t *socks,
  94. int numsocks)
  95. {
  96. struct timeval maxtime;
  97. struct timeval timebuf;
  98. struct timeval *timeout;
  99. int max = ares_getsock(conn->data->state.areschannel,
  100. (int *)socks, numsocks);
  101. maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
  102. maxtime.tv_usec = 0;
  103. timeout = ares_timeout(conn->data->state.areschannel, &maxtime, &timebuf);
  104. Curl_expire(conn->data,
  105. (timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
  106. return max;
  107. }
  108. /*
  109. * ares_waitperform()
  110. *
  111. * 1) Ask ares what sockets it currently plays with, then
  112. * 2) wait for the timeout period to check for action on ares' sockets.
  113. * 3) tell ares to act on all the sockets marked as "with action"
  114. *
  115. * return number of sockets it worked on
  116. */
  117. static int ares_waitperform(struct connectdata *conn, int timeout_ms)
  118. {
  119. struct SessionHandle *data = conn->data;
  120. int nfds;
  121. int bitmask;
  122. int socks[ARES_GETSOCK_MAXNUM];
  123. struct pollfd pfd[ARES_GETSOCK_MAXNUM];
  124. int i;
  125. int num = 0;
  126. bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM);
  127. for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
  128. pfd[i].events = 0;
  129. pfd[i].revents = 0;
  130. if(ARES_GETSOCK_READABLE(bitmask, i)) {
  131. pfd[i].fd = socks[i];
  132. pfd[i].events |= POLLRDNORM|POLLIN;
  133. }
  134. if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
  135. pfd[i].fd = socks[i];
  136. pfd[i].events |= POLLWRNORM|POLLOUT;
  137. }
  138. if(pfd[i].events != 0)
  139. num++;
  140. else
  141. break;
  142. }
  143. if(num)
  144. nfds = Curl_poll(pfd, num, timeout_ms);
  145. else
  146. nfds = 0;
  147. if(!nfds)
  148. /* Call ares_process() unconditonally here, even if we simply timed out
  149. above, as otherwise the ares name resolve won't timeout! */
  150. ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
  151. else {
  152. /* move through the descriptors and ask for processing on them */
  153. for(i=0; i < num; i++)
  154. ares_process_fd(data->state.areschannel,
  155. pfd[i].revents & (POLLRDNORM|POLLIN)?
  156. pfd[i].fd:ARES_SOCKET_BAD,
  157. pfd[i].revents & (POLLWRNORM|POLLOUT)?
  158. pfd[i].fd:ARES_SOCKET_BAD);
  159. }
  160. return nfds;
  161. }
  162. /*
  163. * Curl_is_resolved() is called repeatedly to check if a previous name resolve
  164. * request has completed. It should also make sure to time-out if the
  165. * operation seems to take too long.
  166. *
  167. * Returns normal CURLcode errors.
  168. */
  169. CURLcode Curl_is_resolved(struct connectdata *conn,
  170. struct Curl_dns_entry **dns)
  171. {
  172. struct SessionHandle *data = conn->data;
  173. *dns = NULL;
  174. ares_waitperform(conn, 0);
  175. if(conn->async.done) {
  176. /* we're done, kill the ares handle */
  177. if(!conn->async.dns) {
  178. failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
  179. ares_strerror(conn->async.status));
  180. return CURLE_COULDNT_RESOLVE_HOST;
  181. }
  182. *dns = conn->async.dns;
  183. }
  184. return CURLE_OK;
  185. }
  186. /*
  187. * Curl_wait_for_resolv() waits for a resolve to finish. This function should
  188. * be avoided since using this risk getting the multi interface to "hang".
  189. *
  190. * If 'entry' is non-NULL, make it point to the resolved dns entry
  191. *
  192. * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
  193. * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
  194. */
  195. CURLcode Curl_wait_for_resolv(struct connectdata *conn,
  196. struct Curl_dns_entry **entry)
  197. {
  198. CURLcode rc=CURLE_OK;
  199. struct SessionHandle *data = conn->data;
  200. long timeout;
  201. struct timeval now = Curl_tvnow();
  202. /* now, see if there's a connect timeout or a regular timeout to
  203. use instead of the default one */
  204. if(conn->data->set.connecttimeout)
  205. timeout = conn->data->set.connecttimeout;
  206. else if(conn->data->set.timeout)
  207. timeout = conn->data->set.timeout;
  208. else
  209. timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
  210. /* Wait for the name resolve query to complete. */
  211. while(1) {
  212. struct timeval *tvp, tv, store;
  213. long timediff;
  214. int itimeout;
  215. itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
  216. store.tv_sec = itimeout/1000;
  217. store.tv_usec = (itimeout%1000)*1000;
  218. tvp = ares_timeout(data->state.areschannel, &store, &tv);
  219. /* use the timeout period ares returned to us above */
  220. ares_waitperform(conn, (int)(tvp->tv_sec * 1000 + tvp->tv_usec/1000));
  221. if(conn->async.done)
  222. break;
  223. timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
  224. timeout -= timediff?timediff:1; /* always deduct at least 1 */
  225. if(timeout < 0) {
  226. /* our timeout, so we cancel the ares operation */
  227. ares_cancel(data->state.areschannel);
  228. break;
  229. }
  230. }
  231. /* Operation complete, if the lookup was successful we now have the entry
  232. in the cache. */
  233. if(entry)
  234. *entry = conn->async.dns;
  235. if(!conn->async.dns) {
  236. /* a name was not resolved */
  237. if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
  238. failf(data, "Resolving host timed out: %s", conn->host.dispname);
  239. rc = CURLE_COULDNT_RESOLVE_HOST;
  240. }
  241. else if(conn->async.done) {
  242. failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
  243. ares_strerror(conn->async.status));
  244. rc = CURLE_COULDNT_RESOLVE_HOST;
  245. }
  246. else
  247. rc = CURLE_OPERATION_TIMEDOUT;
  248. /* close the connection, since we can't return failure here without
  249. cleaning up this connection properly */
  250. conn->bits.close = TRUE;
  251. }
  252. return rc;
  253. }
  254. #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
  255. /*
  256. * Curl_ip2addr6() takes an ipv6 internet address as input parameter
  257. * together with a pointer to the string version of the address, and it
  258. * returns a Curl_addrinfo chain filled in correctly with information for this
  259. * address/host.
  260. *
  261. * The input parameters ARE NOT checked for validity but they are expected
  262. * to have been checked already when this is called.
  263. */
  264. Curl_addrinfo *Curl_ip2addr6(struct in6_addr *in,
  265. const char *hostname, int port)
  266. {
  267. Curl_addrinfo *ai;
  268. #if defined(VMS) && defined(__INITIAL_POINTER_SIZE) && \
  269. (__INITIAL_POINTER_SIZE == 64)
  270. #pragma pointer_size save
  271. #pragma pointer_size short
  272. #pragma message disable PTRMISMATCH
  273. #endif
  274. struct hostent *h;
  275. struct in6_addr *addrentry;
  276. struct namebuf6 {
  277. struct hostent hostentry;
  278. char *h_addr_list[2];
  279. struct in6_addr addrentry;
  280. char hostname[1];
  281. };
  282. struct namebuf6 *buf = malloc(sizeof (struct namebuf6) + strlen(hostname));
  283. if(!buf)
  284. return NULL;
  285. h = &buf->hostentry;
  286. h->h_addr_list = &buf->h_addr_list[0];
  287. addrentry = &buf->addrentry;
  288. memcpy(addrentry, in, sizeof (*in));
  289. h->h_addr_list[0] = (char*)addrentry;
  290. h->h_addr_list[1] = NULL; /* terminate list of entries */
  291. h->h_name = &buf->hostname[0];
  292. h->h_aliases = NULL;
  293. h->h_addrtype = AF_INET6;
  294. /* Now store the dotted version of the address */
  295. strcpy (h->h_name, hostname);
  296. #if defined(VMS) && defined(__INITIAL_POINTER_SIZE) && \
  297. (__INITIAL_POINTER_SIZE == 64)
  298. #pragma pointer_size restore
  299. #pragma message enable PTRMISMATCH
  300. #endif
  301. ai = Curl_he2ai(h, port);
  302. free(buf);
  303. return ai;
  304. }
  305. #endif /* CURLRES_IPV6 */
  306. /*
  307. * Curl_getaddrinfo() - when using ares
  308. *
  309. * Returns name information about the given hostname and port number. If
  310. * successful, the 'hostent' is returned and the forth argument will point to
  311. * memory we need to free after use. That memory *MUST* be freed with
  312. * Curl_freeaddrinfo(), nothing else.
  313. */
  314. Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
  315. const char *hostname,
  316. int port,
  317. int *waitp)
  318. {
  319. char *bufp;
  320. struct SessionHandle *data = conn->data;
  321. in_addr_t in = inet_addr(hostname);
  322. int family = PF_INET;
  323. #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
  324. struct in6_addr in6;
  325. #endif /* CURLRES_IPV6 */
  326. *waitp = FALSE;
  327. if(in != CURL_INADDR_NONE) {
  328. /* This is a dotted IP address 123.123.123.123-style */
  329. return Curl_ip2addr(in, hostname, port);
  330. }
  331. #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
  332. if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) {
  333. /* This must be an IPv6 address literal. */
  334. return Curl_ip2addr6(&in6, hostname, port);
  335. }
  336. switch(data->set.ip_version) {
  337. case CURL_IPRESOLVE_V4:
  338. family = PF_INET;
  339. break;
  340. default: /* by default we try ipv6, as PF_UNSPEC isn't supported by (c-)ares */
  341. case CURL_IPRESOLVE_V6:
  342. family = PF_INET6;
  343. break;
  344. }
  345. #endif /* CURLRES_IPV6 */
  346. bufp = strdup(hostname);
  347. if(bufp) {
  348. Curl_safefree(conn->async.hostname);
  349. conn->async.hostname = bufp;
  350. conn->async.port = port;
  351. conn->async.done = FALSE; /* not done */
  352. conn->async.status = 0; /* clear */
  353. conn->async.dns = NULL; /* clear */
  354. /* areschannel is already setup in the Curl_open() function */
  355. ares_gethostbyname(data->state.areschannel, hostname, family,
  356. (ares_host_callback)Curl_addrinfo4_callback, conn);
  357. *waitp = TRUE; /* please wait for the response */
  358. }
  359. return NULL; /* no struct yet */
  360. }
  361. #endif /* CURLRES_ARES */