]> rtime.felk.cvut.cz Git - hornmich/skoda-qr-demo.git/blob - QRScanner/mobile/jni/thirdparty/curl/lib/asyn-ares.c
Add MuPDF native source codes
[hornmich/skoda-qr-demo.git] / QRScanner / mobile / jni / thirdparty / curl / lib / asyn-ares.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, 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  ***************************************************************************/
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 #define _MPRINTF_REPLACE /* use our functions only */
73 #include <curl/mprintf.h>
74
75 #  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
76      (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
77 #    define CARES_STATICLIB
78 #  endif
79 #  include <ares.h>
80 #  include <ares_version.h> /* really old c-ares didn't include this by
81                                itself */
82
83 #if ARES_VERSION >= 0x010500
84 /* c-ares 1.5.0 or later, the callback proto is modified */
85 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
86 #endif
87
88 #include "curl_memory.h"
89 /* The last #include file should be: */
90 #include "memdebug.h"
91
92 struct ResolverResults {
93   int num_pending; /* number of ares_gethostbyname() requests */
94   Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
95   int last_status;
96 };
97
98 /*
99  * Curl_resolver_global_init() - the generic low-level asynchronous name
100  * resolve API.  Called from curl_global_init() to initialize global resolver
101  * environment.  Initializes ares library.
102  */
103 int Curl_resolver_global_init(void)
104 {
105 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
106   if(ares_library_init(ARES_LIB_INIT_ALL)) {
107     return CURLE_FAILED_INIT;
108   }
109 #endif
110   return CURLE_OK;
111 }
112
113 /*
114  * Curl_resolver_global_cleanup()
115  *
116  * Called from curl_global_cleanup() to destroy global resolver environment.
117  * Deinitializes ares library.
118  */
119 void Curl_resolver_global_cleanup(void)
120 {
121 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
122   ares_library_cleanup();
123 #endif
124 }
125
126 /*
127  * Curl_resolver_init()
128  *
129  * Called from curl_easy_init() -> Curl_open() to initialize resolver
130  * URL-state specific environment ('resolver' member of the UrlState
131  * structure).  Fills the passed pointer by the initialized ares_channel.
132  */
133 CURLcode Curl_resolver_init(void **resolver)
134 {
135   int status = ares_init((ares_channel*)resolver);
136   if(status != ARES_SUCCESS) {
137     if(status == ARES_ENOMEM)
138       return CURLE_OUT_OF_MEMORY;
139     else
140       return CURLE_FAILED_INIT;
141   }
142   return CURLE_OK;
143   /* make sure that all other returns from this function should destroy the
144      ares channel before returning error! */
145 }
146
147 /*
148  * Curl_resolver_cleanup()
149  *
150  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
151  * URL-state specific environment ('resolver' member of the UrlState
152  * structure).  Destroys the ares channel.
153  */
154 void Curl_resolver_cleanup(void *resolver)
155 {
156   ares_destroy((ares_channel)resolver);
157 }
158
159 /*
160  * Curl_resolver_duphandle()
161  *
162  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
163  * environment ('resolver' member of the UrlState structure).  Duplicates the
164  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
165  */
166 int Curl_resolver_duphandle(void **to, void *from)
167 {
168   /* Clone the ares channel for the new handle */
169   if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from))
170     return CURLE_FAILED_INIT;
171   return CURLE_OK;
172 }
173
174 static void destroy_async_data (struct Curl_async *async);
175
176 /*
177  * Cancel all possibly still on-going resolves for this connection.
178  */
179 void Curl_resolver_cancel(struct connectdata *conn)
180 {
181   if(conn && conn->data && conn->data->state.resolver)
182     ares_cancel((ares_channel)conn->data->state.resolver);
183   destroy_async_data(&conn->async);
184 }
185
186 /*
187  * destroy_async_data() cleans up async resolver data.
188  */
189 static void destroy_async_data (struct Curl_async *async)
190 {
191   if(async->hostname)
192     free(async->hostname);
193
194   if(async->os_specific) {
195     struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
196     if(res) {
197       if(res->temp_ai) {
198         Curl_freeaddrinfo(res->temp_ai);
199         res->temp_ai = NULL;
200       }
201       free(res);
202     }
203     async->os_specific = NULL;
204   }
205
206   async->hostname = NULL;
207 }
208
209 /*
210  * Curl_resolver_getsock() is called when someone from the outside world
211  * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
212  * with ares. The caller must make sure that this function is only called when
213  * we have a working ares channel.
214  *
215  * Returns: sockets-in-use-bitmap
216  */
217
218 int Curl_resolver_getsock(struct connectdata *conn,
219                           curl_socket_t *socks,
220                           int numsocks)
221
222 {
223   struct timeval maxtime;
224   struct timeval timebuf;
225   struct timeval *timeout;
226   long milli;
227   int max = ares_getsock((ares_channel)conn->data->state.resolver,
228                          (ares_socket_t *)socks, numsocks);
229
230   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
231   maxtime.tv_usec = 0;
232
233   timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
234                          &timebuf);
235   milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
236   if(milli == 0)
237     milli += 10;
238   Curl_expire(conn->data, milli);
239
240   return max;
241 }
242
243 /*
244  * waitperform()
245  *
246  * 1) Ask ares what sockets it currently plays with, then
247  * 2) wait for the timeout period to check for action on ares' sockets.
248  * 3) tell ares to act on all the sockets marked as "with action"
249  *
250  * return number of sockets it worked on
251  */
252
253 static int waitperform(struct connectdata *conn, int timeout_ms)
254 {
255   struct SessionHandle *data = conn->data;
256   int nfds;
257   int bitmask;
258   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
259   struct pollfd pfd[ARES_GETSOCK_MAXNUM];
260   int i;
261   int num = 0;
262
263   bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
264                          ARES_GETSOCK_MAXNUM);
265
266   for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
267     pfd[i].events = 0;
268     pfd[i].revents = 0;
269     if(ARES_GETSOCK_READABLE(bitmask, i)) {
270       pfd[i].fd = socks[i];
271       pfd[i].events |= POLLRDNORM|POLLIN;
272     }
273     if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
274       pfd[i].fd = socks[i];
275       pfd[i].events |= POLLWRNORM|POLLOUT;
276     }
277     if(pfd[i].events != 0)
278       num++;
279     else
280       break;
281   }
282
283   if(num)
284     nfds = Curl_poll(pfd, num, timeout_ms);
285   else
286     nfds = 0;
287
288   if(!nfds)
289     /* Call ares_process() unconditonally here, even if we simply timed out
290        above, as otherwise the ares name resolve won't timeout! */
291     ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
292                     ARES_SOCKET_BAD);
293   else {
294     /* move through the descriptors and ask for processing on them */
295     for(i=0; i < num; i++)
296       ares_process_fd((ares_channel)data->state.resolver,
297                       pfd[i].revents & (POLLRDNORM|POLLIN)?
298                       pfd[i].fd:ARES_SOCKET_BAD,
299                       pfd[i].revents & (POLLWRNORM|POLLOUT)?
300                       pfd[i].fd:ARES_SOCKET_BAD);
301   }
302   return nfds;
303 }
304
305 /*
306  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
307  * name resolve request has completed. It should also make sure to time-out if
308  * the operation seems to take too long.
309  *
310  * Returns normal CURLcode errors.
311  */
312 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
313                                    struct Curl_dns_entry **dns)
314 {
315   struct SessionHandle *data = conn->data;
316   struct ResolverResults *res = (struct ResolverResults *)
317     conn->async.os_specific;
318
319   *dns = NULL;
320
321   waitperform(conn, 0);
322
323   if(res && !res->num_pending) {
324     (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
325     /* temp_ai ownership is moved to the connection, so we need not free-up
326        them */
327     res->temp_ai = NULL;
328     destroy_async_data(&conn->async);
329     if(!conn->async.dns) {
330       failf(data, "Could not resolve %s: %s (%s)",
331             conn->bits.proxy?"proxy":"host",
332             conn->host.dispname,
333             ares_strerror(conn->async.status));
334       return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
335         CURLE_COULDNT_RESOLVE_HOST;
336     }
337     *dns = conn->async.dns;
338   }
339
340   return CURLE_OK;
341 }
342
343 /*
344  * Curl_resolver_wait_resolv()
345  *
346  * waits for a resolve to finish. This function should be avoided since using
347  * this risk getting the multi interface to "hang".
348  *
349  * If 'entry' is non-NULL, make it point to the resolved dns entry
350  *
351  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
352  * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
353  */
354 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
355                                    struct Curl_dns_entry **entry)
356 {
357   CURLcode rc=CURLE_OK;
358   struct SessionHandle *data = conn->data;
359   long timeout;
360   struct timeval now = Curl_tvnow();
361   struct Curl_dns_entry *temp_entry;
362
363   timeout = Curl_timeleft(data, &now, TRUE);
364   if(!timeout)
365     timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
366
367   /* Wait for the name resolve query to complete. */
368   for(;;) {
369     struct timeval *tvp, tv, store;
370     long timediff;
371     int itimeout;
372     int timeout_ms;
373
374     itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
375
376     store.tv_sec = itimeout/1000;
377     store.tv_usec = (itimeout%1000)*1000;
378
379     tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
380
381     /* use the timeout period ares returned to us above if less than one
382        second is left, otherwise just use 1000ms to make sure the progress
383        callback gets called frequent enough */
384     if(!tvp->tv_sec)
385       timeout_ms = (int)(tvp->tv_usec/1000);
386     else
387       timeout_ms = 1000;
388
389     waitperform(conn, timeout_ms);
390     Curl_resolver_is_resolved(conn,&temp_entry);
391
392     if(conn->async.done)
393       break;
394
395     if(Curl_pgrsUpdate(conn)) {
396       rc = CURLE_ABORTED_BY_CALLBACK;
397       timeout = -1; /* trigger the cancel below */
398     }
399     else {
400       struct timeval now2 = Curl_tvnow();
401       timediff = Curl_tvdiff(now2, now); /* spent time */
402       timeout -= timediff?timediff:1; /* always deduct at least 1 */
403       now = now2; /* for next loop */
404     }
405     if(timeout < 0) {
406       /* our timeout, so we cancel the ares operation */
407       ares_cancel((ares_channel)data->state.resolver);
408       break;
409     }
410   }
411
412   /* Operation complete, if the lookup was successful we now have the entry
413      in the cache. */
414
415   if(entry)
416     *entry = conn->async.dns;
417
418   if(!conn->async.dns) {
419     /* a name was not resolved */
420     if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
421       if(conn->bits.proxy) {
422         failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
423         rc = CURLE_COULDNT_RESOLVE_PROXY;
424       }
425       else {
426         failf(data, "Resolving host timed out: %s", conn->host.dispname);
427         rc = CURLE_COULDNT_RESOLVE_HOST;
428       }
429     }
430     else if(conn->async.done) {
431       if(conn->bits.proxy) {
432         failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
433               ares_strerror(conn->async.status));
434         rc = CURLE_COULDNT_RESOLVE_PROXY;
435       }
436       else {
437         failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
438               ares_strerror(conn->async.status));
439         rc = CURLE_COULDNT_RESOLVE_HOST;
440       }
441     }
442     else
443       rc = CURLE_OPERATION_TIMEDOUT;
444
445     /* close the connection, since we can't return failure here without
446        cleaning up this connection properly */
447     conn->bits.close = TRUE;
448   }
449
450   return rc;
451 }
452
453 /* Connects results to the list */
454 static void compound_results(struct ResolverResults *res,
455                              Curl_addrinfo *ai)
456 {
457   Curl_addrinfo *ai_tail;
458   if(!ai)
459     return;
460   ai_tail = ai;
461
462   while(ai_tail->ai_next)
463     ai_tail = ai_tail->ai_next;
464
465   /* Add the new results to the list of old results. */
466   ai_tail->ai_next = res->temp_ai;
467   res->temp_ai = ai;
468 }
469
470 /*
471  * ares_query_completed_cb() is the callback that ares will call when
472  * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
473  * when using ares, is completed either successfully or with failure.
474  */
475 static void query_completed_cb(void *arg,  /* (struct connectdata *) */
476                                int status,
477 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
478                                int timeouts,
479 #endif
480                                struct hostent *hostent)
481 {
482   struct connectdata *conn = (struct connectdata *)arg;
483   struct ResolverResults *res;
484
485 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
486   (void)timeouts; /* ignored */
487 #endif
488
489   if(ARES_EDESTRUCTION == status)
490     /* when this ares handle is getting destroyed, the 'arg' pointer may not
491        be valid so only defer it when we know the 'status' says its fine! */
492     return;
493
494   res = (struct ResolverResults *)conn->async.os_specific;
495   res->num_pending--;
496
497   if(CURL_ASYNC_SUCCESS == status) {
498     Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
499     if(ai) {
500       compound_results(res, ai);
501     }
502   }
503   /* A successful result overwrites any previous error */
504   if(res->last_status != ARES_SUCCESS)
505     res->last_status = status;
506 }
507
508 /*
509  * Curl_resolver_getaddrinfo() - when using ares
510  *
511  * Returns name information about the given hostname and port number. If
512  * successful, the 'hostent' is returned and the forth argument will point to
513  * memory we need to free after use. That memory *MUST* be freed with
514  * Curl_freeaddrinfo(), nothing else.
515  */
516 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
517                                          const char *hostname,
518                                          int port,
519                                          int *waitp)
520 {
521   char *bufp;
522   struct SessionHandle *data = conn->data;
523   struct in_addr in;
524   int family = PF_INET;
525 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
526   struct in6_addr in6;
527 #endif /* CURLRES_IPV6 */
528
529   *waitp = 0; /* default to synchronous response */
530
531   /* First check if this is an IPv4 address string */
532   if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
533     /* This is a dotted IP address 123.123.123.123-style */
534     return Curl_ip2addr(AF_INET, &in, hostname, port);
535   }
536
537 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
538   /* Otherwise, check if this is an IPv6 address string */
539   if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
540     /* This must be an IPv6 address literal.  */
541     return Curl_ip2addr(AF_INET6, &in6, hostname, port);
542
543   switch(conn->ip_version) {
544   default:
545 #if ARES_VERSION >= 0x010601
546     family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
547                            c-ares versions this just falls through and defaults
548                            to PF_INET */
549     break;
550 #endif
551   case CURL_IPRESOLVE_V4:
552     family = PF_INET;
553     break;
554   case CURL_IPRESOLVE_V6:
555     family = PF_INET6;
556     break;
557   }
558 #endif /* CURLRES_IPV6 */
559
560   bufp = strdup(hostname);
561   if(bufp) {
562     struct ResolverResults *res = NULL;
563     Curl_safefree(conn->async.hostname);
564     conn->async.hostname = bufp;
565     conn->async.port = port;
566     conn->async.done = FALSE;   /* not done */
567     conn->async.status = 0;     /* clear */
568     conn->async.dns = NULL;     /* clear */
569     res = calloc(sizeof(struct ResolverResults),1);
570     if(!res) {
571       Curl_safefree(conn->async.hostname);
572       conn->async.hostname = NULL;
573       return NULL;
574     }
575     conn->async.os_specific = res;
576
577     /* initial status - failed */
578     res->last_status = ARES_ENOTFOUND;
579 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
580     if(family == PF_UNSPEC) {
581       if(Curl_ipv6works()) {
582         res->num_pending = 2;
583
584         /* areschannel is already setup in the Curl_open() function */
585         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
586                             PF_INET, query_completed_cb, conn);
587         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
588                             PF_INET6, query_completed_cb, conn);
589       }
590       else {
591         res->num_pending = 1;
592
593         /* areschannel is already setup in the Curl_open() function */
594         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
595                             PF_INET, query_completed_cb, conn);
596       }
597     }
598     else
599 #endif /* CURLRES_IPV6 */
600     {
601       res->num_pending = 1;
602
603       /* areschannel is already setup in the Curl_open() function */
604       ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
605                          query_completed_cb, conn);
606     }
607
608     *waitp = 1; /* expect asynchronous response */
609   }
610   return NULL; /* no struct yet */
611 }
612
613 CURLcode Curl_set_dns_servers(struct SessionHandle *data,
614                               char *servers)
615 {
616   CURLcode result = CURLE_NOT_BUILT_IN;
617 #if (ARES_VERSION >= 0x010704)
618   int ares_result = ares_set_servers_csv(data->state.resolver, servers);
619   switch(ares_result) {
620   case ARES_SUCCESS:
621     result = CURLE_OK;
622     break;
623   case ARES_ENOMEM:
624     result = CURLE_OUT_OF_MEMORY;
625     break;
626   case ARES_ENOTINITIALIZED:
627   case ARES_ENODATA:
628   case ARES_EBADSTR:
629   default:
630     result = CURLE_BAD_FUNCTION_ARGUMENT;
631     break;
632   }
633 #else /* too old c-ares version! */
634   (void)data;
635   (void)servers;
636 #endif
637   return result;
638 }
639 #endif /* CURLRES_ARES */