hostares.c 12 KB

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