asyn-ares.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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 https://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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifdef HAVE_LIMITS_H
26 #include <limits.h>
27 #endif
28 #ifdef HAVE_NETINET_IN_H
29 #include <netinet/in.h>
30 #endif
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34 #ifdef HAVE_ARPA_INET_H
35 #include <arpa/inet.h>
36 #endif
37 #ifdef __VMS
38 #include <in.h>
39 #include <inet.h>
40 #endif
41 
42 #ifdef HAVE_PROCESS_H
43 #include <process.h>
44 #endif
45 
46 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
47 #undef in_addr_t
48 #define in_addr_t unsigned long
49 #endif
50 
51 /***********************************************************************
52  * Only for ares-enabled builds
53  * And only for functions that fulfill the asynch resolver backend API
54  * as defined in asyn.h, nothing else belongs in this file!
55  **********************************************************************/
56 
57 #ifdef CURLRES_ARES
58 
59 #include "urldata.h"
60 #include "sendf.h"
61 #include "hostip.h"
62 #include "hash.h"
63 #include "share.h"
64 #include "strerror.h"
65 #include "url.h"
66 #include "multiif.h"
67 #include "inet_pton.h"
68 #include "connect.h"
69 #include "select.h"
70 #include "progress.h"
71 
72 # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
73  (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
74 # define CARES_STATICLIB
75 # endif
76 # include <ares.h>
77 # include <ares_version.h> /* really old c-ares didn't include this by
78  itself */
79 
80 #if ARES_VERSION >= 0x010500
81 /* c-ares 1.5.0 or later, the callback proto is modified */
82 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
83 #endif
84 
85 /* The last 3 #include files should be in this order */
86 #include "curl_printf.h"
87 #include "curl_memory.h"
88 #include "memdebug.h"
89 
90 struct ResolverResults {
91  int num_pending; /* number of ares_gethostbyname() requests */
92  Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
93  int last_status;
94 };
95 
96 /*
97  * Curl_resolver_global_init() - the generic low-level asynchronous name
98  * resolve API. Called from curl_global_init() to initialize global resolver
99  * environment. Initializes ares library.
100  */
102 {
103 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
104  if(ares_library_init(ARES_LIB_INIT_ALL)) {
105  return CURLE_FAILED_INIT;
106  }
107 #endif
108  return CURLE_OK;
109 }
110 
111 /*
112  * Curl_resolver_global_cleanup()
113  *
114  * Called from curl_global_cleanup() to destroy global resolver environment.
115  * Deinitializes ares library.
116  */
118 {
119 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
120  ares_library_cleanup();
121 #endif
122 }
123 
124 /*
125  * Curl_resolver_init()
126  *
127  * Called from curl_easy_init() -> Curl_open() to initialize resolver
128  * URL-state specific environment ('resolver' member of the UrlState
129  * structure). Fills the passed pointer by the initialized ares_channel.
130  */
131 CURLcode Curl_resolver_init(void **resolver)
132 {
133  int status = ares_init((ares_channel*)resolver);
134  if(status != ARES_SUCCESS) {
135  if(status == ARES_ENOMEM)
136  return CURLE_OUT_OF_MEMORY;
137  else
138  return CURLE_FAILED_INIT;
139  }
140  return CURLE_OK;
141  /* make sure that all other returns from this function should destroy the
142  ares channel before returning error! */
143 }
144 
145 /*
146  * Curl_resolver_cleanup()
147  *
148  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
149  * URL-state specific environment ('resolver' member of the UrlState
150  * structure). Destroys the ares channel.
151  */
152 void Curl_resolver_cleanup(void *resolver)
153 {
154  ares_destroy((ares_channel)resolver);
155 }
156 
157 /*
158  * Curl_resolver_duphandle()
159  *
160  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
161  * environment ('resolver' member of the UrlState structure). Duplicates the
162  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
163  */
164 int Curl_resolver_duphandle(void **to, void *from)
165 {
166  /* Clone the ares channel for the new handle */
167  if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from))
168  return CURLE_FAILED_INIT;
169  return CURLE_OK;
170 }
171 
172 static void destroy_async_data(struct Curl_async *async);
173 
174 /*
175  * Cancel all possibly still on-going resolves for this connection.
176  */
177 void Curl_resolver_cancel(struct connectdata *conn)
178 {
179  if(conn->data && conn->data->state.resolver)
180  ares_cancel((ares_channel)conn->data->state.resolver);
181  destroy_async_data(&conn->async);
182 }
183 
184 /*
185  * destroy_async_data() cleans up async resolver data.
186  */
187 static void destroy_async_data(struct Curl_async *async)
188 {
189  free(async->hostname);
190 
191  if(async->os_specific) {
192  struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
193  if(res) {
194  if(res->temp_ai) {
195  Curl_freeaddrinfo(res->temp_ai);
196  res->temp_ai = NULL;
197  }
198  free(res);
199  }
200  async->os_specific = NULL;
201  }
202 
203  async->hostname = NULL;
204 }
205 
206 /*
207  * Curl_resolver_getsock() is called when someone from the outside world
208  * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
209  * with ares. The caller must make sure that this function is only called when
210  * we have a working ares channel.
211  *
212  * Returns: sockets-in-use-bitmap
213  */
214 
215 int Curl_resolver_getsock(struct connectdata *conn,
216  curl_socket_t *socks,
217  int numsocks)
218 
219 {
220  struct timeval maxtime;
221  struct timeval timebuf;
222  struct timeval *timeout;
223  long milli;
224  int max = ares_getsock((ares_channel)conn->data->state.resolver,
225  (ares_socket_t *)socks, numsocks);
226 
227  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
228  maxtime.tv_usec = 0;
229 
230  timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
231  &timebuf);
232  milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
233  if(milli == 0)
234  milli += 10;
235  Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME);
236 
237  return max;
238 }
239 
240 /*
241  * waitperform()
242  *
243  * 1) Ask ares what sockets it currently plays with, then
244  * 2) wait for the timeout period to check for action on ares' sockets.
245  * 3) tell ares to act on all the sockets marked as "with action"
246  *
247  * return number of sockets it worked on
248  */
249 
250 static int waitperform(struct connectdata *conn, int timeout_ms)
251 {
252  struct Curl_easy *data = conn->data;
253  int nfds;
254  int bitmask;
255  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
256  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
257  int i;
258  int num = 0;
259 
260  bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
261  ARES_GETSOCK_MAXNUM);
262 
263  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
264  pfd[i].events = 0;
265  pfd[i].revents = 0;
266  if(ARES_GETSOCK_READABLE(bitmask, i)) {
267  pfd[i].fd = socks[i];
268  pfd[i].events |= POLLRDNORM|POLLIN;
269  }
270  if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
271  pfd[i].fd = socks[i];
272  pfd[i].events |= POLLWRNORM|POLLOUT;
273  }
274  if(pfd[i].events != 0)
275  num++;
276  else
277  break;
278  }
279 
280  if(num)
281  nfds = Curl_poll(pfd, num, timeout_ms);
282  else
283  nfds = 0;
284 
285  if(!nfds)
286  /* Call ares_process() unconditonally here, even if we simply timed out
287  above, as otherwise the ares name resolve won't timeout! */
288  ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
289  ARES_SOCKET_BAD);
290  else {
291  /* move through the descriptors and ask for processing on them */
292  for(i = 0; i < num; i++)
293  ares_process_fd((ares_channel)data->state.resolver,
294  pfd[i].revents & (POLLRDNORM|POLLIN)?
295  pfd[i].fd:ARES_SOCKET_BAD,
296  pfd[i].revents & (POLLWRNORM|POLLOUT)?
297  pfd[i].fd:ARES_SOCKET_BAD);
298  }
299  return nfds;
300 }
301 
302 /*
303  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
304  * name resolve request has completed. It should also make sure to time-out if
305  * the operation seems to take too long.
306  *
307  * Returns normal CURLcode errors.
308  */
310  struct Curl_dns_entry **dns)
311 {
312  struct Curl_easy *data = conn->data;
313  struct ResolverResults *res = (struct ResolverResults *)
314  conn->async.os_specific;
316 
317  *dns = NULL;
318 
319  waitperform(conn, 0);
320 
321  if(res && !res->num_pending) {
322  (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
323  /* temp_ai ownership is moved to the connection, so we need not free-up
324  them */
325  res->temp_ai = NULL;
326  if(!conn->async.dns) {
327  failf(data, "Could not resolve: %s (%s)",
328  conn->async.hostname, ares_strerror(conn->async.status));
331  }
332  else
333  *dns = conn->async.dns;
334 
335  destroy_async_data(&conn->async);
336  }
337 
338  return result;
339 }
340 
341 /*
342  * Curl_resolver_wait_resolv()
343  *
344  * waits for a resolve to finish. This function should be avoided since using
345  * this risk getting the multi interface to "hang".
346  *
347  * If 'entry' is non-NULL, make it point to the resolved dns entry
348  *
349  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
350  * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
351  */
353  struct Curl_dns_entry **entry)
354 {
356  struct Curl_easy *data = conn->data;
357  long timeout;
358  struct curltime now = Curl_tvnow();
359  struct Curl_dns_entry *temp_entry;
360 
361  if(entry)
362  *entry = NULL; /* clear on entry */
363 
364  timeout = Curl_timeleft(data, &now, TRUE);
365  if(timeout < 0) {
366  /* already expired! */
367  connclose(conn, "Timed out before name resolve started");
369  }
370  if(!timeout)
371  timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
372 
373  /* Wait for the name resolve query to complete. */
374  while(!result) {
375  struct timeval *tvp, tv, store;
376  int itimeout;
377  int timeout_ms;
378 
379  itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
380 
381  store.tv_sec = itimeout/1000;
382  store.tv_usec = (itimeout%1000)*1000;
383 
384  tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
385 
386  /* use the timeout period ares returned to us above if less than one
387  second is left, otherwise just use 1000ms to make sure the progress
388  callback gets called frequent enough */
389  if(!tvp->tv_sec)
390  timeout_ms = (int)(tvp->tv_usec/1000);
391  else
392  timeout_ms = 1000;
393 
394  waitperform(conn, timeout_ms);
395  result = Curl_resolver_is_resolved(conn, &temp_entry);
396 
397  if(result || conn->async.done)
398  break;
399 
400  if(Curl_pgrsUpdate(conn))
401  result = CURLE_ABORTED_BY_CALLBACK;
402  else {
403  struct curltime now2 = Curl_tvnow();
404  time_t timediff = Curl_tvdiff(now2, now); /* spent time */
405  if(timediff <= 0)
406  timeout -= 1; /* always deduct at least 1 */
407  else if(timediff > timeout)
408  timeout = -1;
409  else
410  timeout -= (long)timediff;
411  now = now2; /* for next loop */
412  }
413  if(timeout < 0)
414  result = CURLE_OPERATION_TIMEDOUT;
415  }
416  if(result)
417  /* failure, so we cancel the ares operation */
418  ares_cancel((ares_channel)data->state.resolver);
419 
420  /* Operation complete, if the lookup was successful we now have the entry
421  in the cache. */
422  if(entry)
423  *entry = conn->async.dns;
424 
425  if(result)
426  /* close the connection, since we can't return failure here without
427  cleaning up this connection properly.
428  TODO: remove this action from here, it is not a name resolver decision.
429  */
430  connclose(conn, "c-ares resolve failed");
431 
432  return result;
433 }
434 
435 /* Connects results to the list */
436 static void compound_results(struct ResolverResults *res,
437  Curl_addrinfo *ai)
438 {
439  Curl_addrinfo *ai_tail;
440  if(!ai)
441  return;
442  ai_tail = ai;
443 
444  while(ai_tail->ai_next)
445  ai_tail = ai_tail->ai_next;
446 
447  /* Add the new results to the list of old results. */
448  ai_tail->ai_next = res->temp_ai;
449  res->temp_ai = ai;
450 }
451 
452 /*
453  * ares_query_completed_cb() is the callback that ares will call when
454  * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
455  * when using ares, is completed either successfully or with failure.
456  */
457 static void query_completed_cb(void *arg, /* (struct connectdata *) */
458  int status,
459 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
460  int timeouts,
461 #endif
462  struct hostent *hostent)
463 {
464  struct connectdata *conn = (struct connectdata *)arg;
465  struct ResolverResults *res;
466 
467 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
468  (void)timeouts; /* ignored */
469 #endif
470 
471  if(ARES_EDESTRUCTION == status)
472  /* when this ares handle is getting destroyed, the 'arg' pointer may not
473  be valid so only defer it when we know the 'status' says its fine! */
474  return;
475 
476  res = (struct ResolverResults *)conn->async.os_specific;
477  res->num_pending--;
478 
479  if(CURL_ASYNC_SUCCESS == status) {
480  Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
481  if(ai) {
482  compound_results(res, ai);
483  }
484  }
485  /* A successful result overwrites any previous error */
486  if(res->last_status != ARES_SUCCESS)
487  res->last_status = status;
488 }
489 
490 /*
491  * Curl_resolver_getaddrinfo() - when using ares
492  *
493  * Returns name information about the given hostname and port number. If
494  * successful, the 'hostent' is returned and the forth argument will point to
495  * memory we need to free after use. That memory *MUST* be freed with
496  * Curl_freeaddrinfo(), nothing else.
497  */
499  const char *hostname,
500  int port,
501  int *waitp)
502 {
503  char *bufp;
504  struct Curl_easy *data = conn->data;
505  struct in_addr in;
506  int family = PF_INET;
507 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
508  struct in6_addr in6;
509 #endif /* CURLRES_IPV6 */
510 
511  *waitp = 0; /* default to synchronous response */
512 
513  /* First check if this is an IPv4 address string */
514  if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
515  /* This is a dotted IP address 123.123.123.123-style */
516  return Curl_ip2addr(AF_INET, &in, hostname, port);
517  }
518 
519 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
520  /* Otherwise, check if this is an IPv6 address string */
521  if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
522  /* This must be an IPv6 address literal. */
523  return Curl_ip2addr(AF_INET6, &in6, hostname, port);
524 
525  switch(conn->ip_version) {
526  default:
527 #if ARES_VERSION >= 0x010601
528  family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
529  c-ares versions this just falls through and defaults
530  to PF_INET */
531  break;
532 #endif
533  case CURL_IPRESOLVE_V4:
534  family = PF_INET;
535  break;
536  case CURL_IPRESOLVE_V6:
537  family = PF_INET6;
538  break;
539  }
540 #endif /* CURLRES_IPV6 */
541 
542  bufp = strdup(hostname);
543  if(bufp) {
544  struct ResolverResults *res = NULL;
545  free(conn->async.hostname);
546  conn->async.hostname = bufp;
547  conn->async.port = port;
548  conn->async.done = FALSE; /* not done */
549  conn->async.status = 0; /* clear */
550  conn->async.dns = NULL; /* clear */
551  res = calloc(sizeof(struct ResolverResults), 1);
552  if(!res) {
553  free(conn->async.hostname);
554  conn->async.hostname = NULL;
555  return NULL;
556  }
557  conn->async.os_specific = res;
558 
559  /* initial status - failed */
560  res->last_status = ARES_ENOTFOUND;
561 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
562  if(family == PF_UNSPEC) {
563  if(Curl_ipv6works()) {
564  res->num_pending = 2;
565 
566  /* areschannel is already setup in the Curl_open() function */
567  ares_gethostbyname((ares_channel)data->state.resolver, hostname,
568  PF_INET, query_completed_cb, conn);
569  ares_gethostbyname((ares_channel)data->state.resolver, hostname,
570  PF_INET6, query_completed_cb, conn);
571  }
572  else {
573  res->num_pending = 1;
574 
575  /* areschannel is already setup in the Curl_open() function */
576  ares_gethostbyname((ares_channel)data->state.resolver, hostname,
577  PF_INET, query_completed_cb, conn);
578  }
579  }
580  else
581 #endif /* CURLRES_IPV6 */
582  {
583  res->num_pending = 1;
584 
585  /* areschannel is already setup in the Curl_open() function */
586  ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
587  query_completed_cb, conn);
588  }
589 
590  *waitp = 1; /* expect asynchronous response */
591  }
592  return NULL; /* no struct yet */
593 }
594 
596  char *servers)
597 {
598  CURLcode result = CURLE_NOT_BUILT_IN;
599  int ares_result;
600 
601  /* If server is NULL or empty, this would purge all DNS servers
602  * from ares library, which will cause any and all queries to fail.
603  * So, just return OK if none are configured and don't actually make
604  * any changes to c-ares. This lets c-ares use it's defaults, which
605  * it gets from the OS (for instance from /etc/resolv.conf on Linux).
606  */
607  if(!(servers && servers[0]))
608  return CURLE_OK;
609 
610 #if (ARES_VERSION >= 0x010704)
611  ares_result = ares_set_servers_csv(data->state.resolver, servers);
612  switch(ares_result) {
613  case ARES_SUCCESS:
614  result = CURLE_OK;
615  break;
616  case ARES_ENOMEM:
617  result = CURLE_OUT_OF_MEMORY;
618  break;
619  case ARES_ENOTINITIALIZED:
620  case ARES_ENODATA:
621  case ARES_EBADSTR:
622  default:
624  break;
625  }
626 #else /* too old c-ares version! */
627  (void)data;
628  (void)(ares_result);
629 #endif
630  return result;
631 }
632 
634  const char *interf)
635 {
636 #if (ARES_VERSION >= 0x010704)
637  if(!interf)
638  interf = "";
639 
640  ares_set_local_dev((ares_channel)data->state.resolver, interf);
641 
642  return CURLE_OK;
643 #else /* c-ares version too old! */
644  (void)data;
645  (void)interf;
646  return CURLE_NOT_BUILT_IN;
647 #endif
648 }
649 
651  const char *local_ip4)
652 {
653 #if (ARES_VERSION >= 0x010704)
654  struct in_addr a4;
655 
656  if((!local_ip4) || (local_ip4[0] == 0)) {
657  a4.s_addr = 0; /* disabled: do not bind to a specific address */
658  }
659  else {
660  if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
662  }
663  }
664 
665  ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
666 
667  return CURLE_OK;
668 #else /* c-ares version too old! */
669  (void)data;
670  (void)local_ip4;
671  return CURLE_NOT_BUILT_IN;
672 #endif
673 }
674 
676  const char *local_ip6)
677 {
678 #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
679  unsigned char a6[INET6_ADDRSTRLEN];
680 
681  if((!local_ip6) || (local_ip6[0] == 0)) {
682  /* disabled: do not bind to a specific address */
683  memset(a6, 0, sizeof(a6));
684  }
685  else {
686  if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
688  }
689  }
690 
691  ares_set_local_ip6((ares_channel)data->state.resolver, a6);
692 
693  return CURLE_OK;
694 #else /* c-ares version too old! */
695  (void)data;
696  (void)local_ip6;
697  return CURLE_NOT_BUILT_IN;
698 #endif
699 }
700 #endif /* CURLRES_ARES */
#define free(ptr)
Definition: curl_memory.h:130
#define CURL_IPRESOLVE_V6
Definition: curl.h:1856
struct ConnectBits bits
Definition: urldata.h:893
#define connclose(x, y)
Definition: connect.h:141
CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4)
Definition: hostsyn.c:87
int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock, int numsocks)
#define failf
Definition: sendf.h:48
#define CURL_IPRESOLVE_V4
Definition: curl.h:1855
#define strdup(ptr)
Definition: curl_memory.h:122
Definition: hostip.h:66
uv_timer_t timeout
Definition: multi-uv.c:42
CURLcode
Definition: curl.h:454
#define POLLWRNORM
Definition: select.h:63
CURLcode Curl_resolver_init(void **resolver)
struct curltime now
Definition: unit1399.c:83
Curl_addrinfo * Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
void Curl_freeaddrinfo(Curl_addrinfo *cahead)
Definition: curl_addrinfo.c:78
#define POLLOUT
Definition: select.h:44
static int res
short events
Definition: select.h:52
UNITTEST_START int result
Definition: unit1304.c:49
unsigned int i
Definition: unit1303.c:79
void Curl_resolver_cancel(struct connectdata *conn)
static srvr_sockaddr_union_t from
Definition: tftpd.c:197
#define CURL_ASYNC_SUCCESS
Definition: hostip.h:49
Curl_addrinfo * Curl_resolver_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp)
int Curl_pgrsUpdate(struct connectdata *conn)
Definition: progress.c:350
CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, Curl_addrinfo *ai)
#define FALSE
time_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect)
Definition: connect.c:182
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6)
Definition: hostsyn.c:99
bool proxy
Definition: urldata.h:382
CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers)
Definition: hostsyn.c:62
Definition: select.h:49
#define Curl_tvnow()
Definition: timeval.h:57
void Curl_resolver_cleanup(void *resolver)
Definition: curl.h:455
#define Curl_resolver_global_init()
Definition: asyn.h:155
int Curl_inet_pton(int af, const char *src, void *dst)
Definition: inet_pton.c:66
static unsigned short port
Definition: sockfilt.c:137
struct Curl_addrinfo * ai_next
Definition: curl_addrinfo.h:59
struct UrlState state
Definition: urldata.h:1769
#define Curl_ipv6works()
Definition: hostip.h:98
long ip_version
Definition: urldata.h:907
#define POLLIN
Definition: select.h:42
CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns)
#define Curl_tvdiff(x, y)
Definition: timeval.h:58
int Curl_resolver_duphandle(void **to, void *from)
void * resolver
Definition: urldata.h:1294
long port
Definition: urldata.h:841
#define Curl_resolver_global_cleanup()
Definition: asyn.h:156
int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
Definition: select.c:391
Curl_addrinfo * Curl_he2ai(const struct hostent *he, int port)
CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **dnsentry)
void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
Definition: multi.c:2930
#define TRUE
#define CURL_TIMEOUT_RESOLVE
Definition: hostip.h:46
double max(double a, double b)
int curl_socket_t
Definition: curl.h:130
Definition: debug.c:29
CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf)
Definition: hostsyn.c:75
#define calloc(nbelem, size)
Definition: curl_memory.h:126
#define POLLRDNORM
Definition: select.h:59
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:08