curl_multi_remove_handle() don't block terminating c-ares requests
[platform/upstream/curl.git] / lib / asyn-thread.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, 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 /***********************************************************************
26  * Only for threaded name resolves builds
27  **********************************************************************/
28 #ifdef CURLRES_THREADED
29
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #endif
33 #ifdef HAVE_NETDB_H
34 #include <netdb.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
38 #endif
39 #ifdef __VMS
40 #include <in.h>
41 #include <inet.h>
42 #endif
43
44 #if defined(USE_THREADS_POSIX)
45 #  ifdef HAVE_PTHREAD_H
46 #    include <pthread.h>
47 #  endif
48 #elif defined(USE_THREADS_WIN32)
49 #  ifdef HAVE_PROCESS_H
50 #    include <process.h>
51 #  endif
52 #endif
53
54 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
55 #undef in_addr_t
56 #define in_addr_t unsigned long
57 #endif
58
59 #ifdef HAVE_GETADDRINFO
60 #  define RESOLVER_ENOMEM  EAI_MEMORY
61 #else
62 #  define RESOLVER_ENOMEM  ENOMEM
63 #endif
64
65 #include "urldata.h"
66 #include "sendf.h"
67 #include "hostip.h"
68 #include "hash.h"
69 #include "share.h"
70 #include "strerror.h"
71 #include "url.h"
72 #include "multiif.h"
73 #include "inet_pton.h"
74 #include "inet_ntop.h"
75 #include "curl_threads.h"
76 #include "connect.h"
77 /* The last 3 #include files should be in this order */
78 #include "curl_printf.h"
79 #include "curl_memory.h"
80 #include "memdebug.h"
81
82 struct resdata {
83   struct curltime start;
84 };
85
86 /*
87  * Curl_resolver_global_init()
88  * Called from curl_global_init() to initialize global resolver environment.
89  * Does nothing here.
90  */
91 int Curl_resolver_global_init(void)
92 {
93   return CURLE_OK;
94 }
95
96 /*
97  * Curl_resolver_global_cleanup()
98  * Called from curl_global_cleanup() to destroy global resolver environment.
99  * Does nothing here.
100  */
101 void Curl_resolver_global_cleanup(void)
102 {
103 }
104
105 /*
106  * Curl_resolver_init()
107  * Called from curl_easy_init() -> Curl_open() to initialize resolver
108  * URL-state specific environment ('resolver' member of the UrlState
109  * structure).
110  */
111 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
112 {
113   (void)easy;
114   *resolver = calloc(1, sizeof(struct resdata));
115   if(!*resolver)
116     return CURLE_OUT_OF_MEMORY;
117   return CURLE_OK;
118 }
119
120 /*
121  * Curl_resolver_cleanup()
122  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
123  * URL-state specific environment ('resolver' member of the UrlState
124  * structure).
125  */
126 void Curl_resolver_cleanup(void *resolver)
127 {
128   free(resolver);
129 }
130
131 /*
132  * Curl_resolver_duphandle()
133  * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
134  * environment ('resolver' member of the UrlState structure).
135  */
136 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
137 {
138   (void)from;
139   return Curl_resolver_init(easy, to);
140 }
141
142 static void destroy_async_data(struct Curl_async *);
143
144 /*
145  * Cancel all possibly still on-going resolves for this connection.
146  */
147 void Curl_resolver_cancel(struct connectdata *conn)
148 {
149   destroy_async_data(&conn->async);
150 }
151
152 /* This function is used to init a threaded resolve */
153 static bool init_resolve_thread(struct connectdata *conn,
154                                 const char *hostname, int port,
155                                 const struct addrinfo *hints);
156
157
158 /* Data for synchronization between resolver thread and its parent */
159 struct thread_sync_data {
160   curl_mutex_t * mtx;
161   int done;
162
163   char *hostname;        /* hostname to resolve, Curl_async.hostname
164                             duplicate */
165   int port;
166   int sock_error;
167   Curl_addrinfo *res;
168 #ifdef HAVE_GETADDRINFO
169   struct addrinfo hints;
170 #endif
171   struct thread_data *td; /* for thread-self cleanup */
172 };
173
174 struct thread_data {
175   curl_thread_t thread_hnd;
176   unsigned int poll_interval;
177   time_t interval_end;
178   struct thread_sync_data tsd;
179 };
180
181 static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
182 {
183   return &(((struct thread_data *)conn->async.os_specific)->tsd);
184 }
185
186 /* Destroy resolver thread synchronization data */
187 static
188 void destroy_thread_sync_data(struct thread_sync_data * tsd)
189 {
190   if(tsd->mtx) {
191     Curl_mutex_destroy(tsd->mtx);
192     free(tsd->mtx);
193   }
194
195   free(tsd->hostname);
196
197   if(tsd->res)
198     Curl_freeaddrinfo(tsd->res);
199
200   memset(tsd, 0, sizeof(*tsd));
201 }
202
203 /* Initialize resolver thread synchronization data */
204 static
205 int init_thread_sync_data(struct thread_data * td,
206                            const char *hostname,
207                            int port,
208                            const struct addrinfo *hints)
209 {
210   struct thread_sync_data *tsd = &td->tsd;
211
212   memset(tsd, 0, sizeof(*tsd));
213
214   tsd->td = td;
215   tsd->port = port;
216   /* Treat the request as done until the thread actually starts so any early
217    * cleanup gets done properly.
218    */
219   tsd->done = 1;
220 #ifdef HAVE_GETADDRINFO
221   DEBUGASSERT(hints);
222   tsd->hints = *hints;
223 #else
224   (void) hints;
225 #endif
226
227   tsd->mtx = malloc(sizeof(curl_mutex_t));
228   if(tsd->mtx == NULL)
229     goto err_exit;
230
231   Curl_mutex_init(tsd->mtx);
232
233   tsd->sock_error = CURL_ASYNC_SUCCESS;
234
235   /* Copying hostname string because original can be destroyed by parent
236    * thread during gethostbyname execution.
237    */
238   tsd->hostname = strdup(hostname);
239   if(!tsd->hostname)
240     goto err_exit;
241
242   return 1;
243
244  err_exit:
245   /* Memory allocation failed */
246   destroy_thread_sync_data(tsd);
247   return 0;
248 }
249
250 static int getaddrinfo_complete(struct connectdata *conn)
251 {
252   struct thread_sync_data *tsd = conn_thread_sync_data(conn);
253   int rc;
254
255   rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
256   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
257      cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
258   */
259   tsd->res = NULL;
260
261   return rc;
262 }
263
264
265 #ifdef HAVE_GETADDRINFO
266
267 /*
268  * getaddrinfo_thread() resolves a name and then exits.
269  *
270  * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
271  * and wait on it.
272  */
273 static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
274 {
275   struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
276   struct thread_data *td = tsd->td;
277   char service[12];
278   int rc;
279
280   snprintf(service, sizeof(service), "%d", tsd->port);
281
282   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
283
284   if(rc != 0) {
285     tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
286     if(tsd->sock_error == 0)
287       tsd->sock_error = RESOLVER_ENOMEM;
288   }
289   else {
290     Curl_addrinfo_set_port(tsd->res, tsd->port);
291   }
292
293   Curl_mutex_acquire(tsd->mtx);
294   if(tsd->done) {
295     /* too late, gotta clean up the mess */
296     Curl_mutex_release(tsd->mtx);
297     destroy_thread_sync_data(tsd);
298     free(td);
299   }
300   else {
301     tsd->done = 1;
302     Curl_mutex_release(tsd->mtx);
303   }
304
305   return 0;
306 }
307
308 #else /* HAVE_GETADDRINFO */
309
310 /*
311  * gethostbyname_thread() resolves a name and then exits.
312  */
313 static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
314 {
315   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
316   struct thread_data *td = tsd->td;
317
318   tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
319
320   if(!tsd->res) {
321     tsd->sock_error = SOCKERRNO;
322     if(tsd->sock_error == 0)
323       tsd->sock_error = RESOLVER_ENOMEM;
324   }
325
326   Curl_mutex_acquire(tsd->mtx);
327   if(tsd->done) {
328     /* too late, gotta clean up the mess */
329     Curl_mutex_release(tsd->mtx);
330     destroy_thread_sync_data(tsd);
331     free(td);
332   }
333   else {
334     tsd->done = 1;
335     Curl_mutex_release(tsd->mtx);
336   }
337
338   return 0;
339 }
340
341 #endif /* HAVE_GETADDRINFO */
342
343 /*
344  * destroy_async_data() cleans up async resolver data and thread handle.
345  */
346 static void destroy_async_data(struct Curl_async *async)
347 {
348   if(async->os_specific) {
349     struct thread_data *td = (struct thread_data*) async->os_specific;
350     int done;
351
352     /*
353      * if the thread is still blocking in the resolve syscall, detach it and
354      * let the thread do the cleanup...
355      */
356     Curl_mutex_acquire(td->tsd.mtx);
357     done = td->tsd.done;
358     td->tsd.done = 1;
359     Curl_mutex_release(td->tsd.mtx);
360
361     if(!done) {
362       Curl_thread_destroy(td->thread_hnd);
363     }
364     else {
365       if(td->thread_hnd != curl_thread_t_null)
366         Curl_thread_join(&td->thread_hnd);
367
368       destroy_thread_sync_data(&td->tsd);
369
370       free(async->os_specific);
371     }
372   }
373   async->os_specific = NULL;
374
375   free(async->hostname);
376   async->hostname = NULL;
377 }
378
379 /*
380  * init_resolve_thread() starts a new thread that performs the actual
381  * resolve. This function returns before the resolve is done.
382  *
383  * Returns FALSE in case of failure, otherwise TRUE.
384  */
385 static bool init_resolve_thread(struct connectdata *conn,
386                                 const char *hostname, int port,
387                                 const struct addrinfo *hints)
388 {
389   struct thread_data *td = calloc(1, sizeof(struct thread_data));
390   int err = ENOMEM;
391
392   conn->async.os_specific = (void *)td;
393   if(!td)
394     goto errno_exit;
395
396   conn->async.port = port;
397   conn->async.done = FALSE;
398   conn->async.status = 0;
399   conn->async.dns = NULL;
400   td->thread_hnd = curl_thread_t_null;
401
402   if(!init_thread_sync_data(td, hostname, port, hints)) {
403     conn->async.os_specific = NULL;
404     free(td);
405     goto errno_exit;
406   }
407
408   free(conn->async.hostname);
409   conn->async.hostname = strdup(hostname);
410   if(!conn->async.hostname)
411     goto err_exit;
412
413   /* The thread will set this to 1 when complete. */
414   td->tsd.done = 0;
415
416 #ifdef HAVE_GETADDRINFO
417   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
418 #else
419   td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
420 #endif
421
422   if(!td->thread_hnd) {
423     /* The thread never started, so mark it as done here for proper cleanup. */
424     td->tsd.done = 1;
425     err = errno;
426     goto err_exit;
427   }
428
429   return TRUE;
430
431  err_exit:
432   destroy_async_data(&conn->async);
433
434  errno_exit:
435   errno = err;
436   return FALSE;
437 }
438
439 /*
440  * resolver_error() calls failf() with the appropriate message after a resolve
441  * error
442  */
443
444 static CURLcode resolver_error(struct connectdata *conn)
445 {
446   const char *host_or_proxy;
447   CURLcode result;
448
449   if(conn->bits.httpproxy) {
450     host_or_proxy = "proxy";
451     result = CURLE_COULDNT_RESOLVE_PROXY;
452   }
453   else {
454     host_or_proxy = "host";
455     result = CURLE_COULDNT_RESOLVE_HOST;
456   }
457
458   failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
459         conn->async.hostname);
460
461   return result;
462 }
463
464 /*
465  * Until we gain a way to signal the resolver threads to stop early, we must
466  * simply wait for them and ignore their results.
467  */
468 void Curl_resolver_kill(struct connectdata *conn)
469 {
470   struct thread_data *td = (struct thread_data*) conn->async.os_specific;
471
472   /* If we're still resolving, we must wait for the threads to fully clean up,
473      unfortunately.  Otherwise, we can simply cancel to clean up any resolver
474      data. */
475   if(td && td->thread_hnd != curl_thread_t_null)
476     (void)Curl_resolver_wait_resolv(conn, NULL);
477   else
478     Curl_resolver_cancel(conn);
479 }
480
481 /*
482  * Curl_resolver_wait_resolv()
483  *
484  * Waits for a resolve to finish. This function should be avoided since using
485  * this risk getting the multi interface to "hang".
486  *
487  * If 'entry' is non-NULL, make it point to the resolved dns entry
488  *
489  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
490  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
491  *
492  * This is the version for resolves-in-a-thread.
493  */
494 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
495                                    struct Curl_dns_entry **entry)
496 {
497   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
498   CURLcode result = CURLE_OK;
499
500   DEBUGASSERT(conn && td);
501   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
502
503   /* wait for the thread to resolve the name */
504   if(Curl_thread_join(&td->thread_hnd)) {
505     if(entry)
506       result = getaddrinfo_complete(conn);
507   }
508   else
509     DEBUGASSERT(0);
510
511   conn->async.done = TRUE;
512
513   if(entry)
514     *entry = conn->async.dns;
515
516   if(!conn->async.dns)
517     /* a name was not resolved, report error */
518     result = resolver_error(conn);
519
520   destroy_async_data(&conn->async);
521
522   if(!conn->async.dns)
523     connclose(conn, "asynch resolve failed");
524
525   return result;
526 }
527
528 /*
529  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
530  * name resolve request has completed. It should also make sure to time-out if
531  * the operation seems to take too long.
532  */
533 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
534                                    struct Curl_dns_entry **entry)
535 {
536   struct Curl_easy *data = conn->data;
537   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
538   int done = 0;
539
540   *entry = NULL;
541
542   if(!td) {
543     DEBUGASSERT(td);
544     return CURLE_COULDNT_RESOLVE_HOST;
545   }
546
547   Curl_mutex_acquire(td->tsd.mtx);
548   done = td->tsd.done;
549   Curl_mutex_release(td->tsd.mtx);
550
551   if(done) {
552     getaddrinfo_complete(conn);
553
554     if(!conn->async.dns) {
555       CURLcode result = resolver_error(conn);
556       destroy_async_data(&conn->async);
557       return result;
558     }
559     destroy_async_data(&conn->async);
560     *entry = conn->async.dns;
561   }
562   else {
563     /* poll for name lookup done with exponential backoff up to 250ms */
564     timediff_t elapsed = Curl_timediff(Curl_now(),
565                                        data->progress.t_startsingle);
566     if(elapsed < 0)
567       elapsed = 0;
568
569     if(td->poll_interval == 0)
570       /* Start at 1ms poll interval */
571       td->poll_interval = 1;
572     else if(elapsed >= td->interval_end)
573       /* Back-off exponentially if last interval expired  */
574       td->poll_interval *= 2;
575
576     if(td->poll_interval > 250)
577       td->poll_interval = 250;
578
579     td->interval_end = elapsed + td->poll_interval;
580     Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
581   }
582
583   return CURLE_OK;
584 }
585
586 int Curl_resolver_getsock(struct connectdata *conn,
587                           curl_socket_t *socks,
588                           int numsocks)
589 {
590   time_t milli;
591   timediff_t ms;
592   struct Curl_easy *data = conn->data;
593   struct resdata *reslv = (struct resdata *)data->state.resolver;
594   (void)socks;
595   (void)numsocks;
596   ms = Curl_timediff(Curl_now(), reslv->start);
597   if(ms < 3)
598     milli = 0;
599   else if(ms <= 50)
600     milli = ms/3;
601   else if(ms <= 250)
602     milli = 50;
603   else
604     milli = 200;
605   Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
606   return 0;
607 }
608
609 #ifndef HAVE_GETADDRINFO
610 /*
611  * Curl_getaddrinfo() - for platforms without getaddrinfo
612  */
613 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
614                                          const char *hostname,
615                                          int port,
616                                          int *waitp)
617 {
618   struct in_addr in;
619   struct Curl_easy *data = conn->data;
620   struct resdata *reslv = (struct resdata *)data->state.resolver;
621
622   *waitp = 0; /* default to synchronous response */
623
624   if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
625     /* This is a dotted IP address 123.123.123.123-style */
626     return Curl_ip2addr(AF_INET, &in, hostname, port);
627
628   reslv->start = Curl_now();
629
630   /* fire up a new resolver thread! */
631   if(init_resolve_thread(conn, hostname, port, NULL)) {
632     *waitp = 1; /* expect asynchronous response */
633     return NULL;
634   }
635
636   failf(conn->data, "getaddrinfo() thread failed\n");
637
638   return NULL;
639 }
640
641 #else /* !HAVE_GETADDRINFO */
642
643 /*
644  * Curl_resolver_getaddrinfo() - for getaddrinfo
645  */
646 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
647                                          const char *hostname,
648                                          int port,
649                                          int *waitp)
650 {
651   struct addrinfo hints;
652   char sbuf[12];
653   int pf = PF_INET;
654   struct Curl_easy *data = conn->data;
655   struct resdata *reslv = (struct resdata *)data->state.resolver;
656
657   *waitp = 0; /* default to synchronous response */
658
659 #ifndef USE_RESOLVE_ON_IPS
660   {
661     struct in_addr in;
662     /* First check if this is an IPv4 address string */
663     if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
664       /* This is a dotted IP address 123.123.123.123-style */
665       return Curl_ip2addr(AF_INET, &in, hostname, port);
666   }
667 #ifdef CURLRES_IPV6
668   {
669     struct in6_addr in6;
670     /* check if this is an IPv6 address string */
671     if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
672       /* This is an IPv6 address literal */
673       return Curl_ip2addr(AF_INET6, &in6, hostname, port);
674   }
675 #endif /* CURLRES_IPV6 */
676 #endif /* !USE_RESOLVE_ON_IPS */
677
678 #ifdef CURLRES_IPV6
679   /*
680    * Check if a limited name resolve has been requested.
681    */
682   switch(conn->ip_version) {
683   case CURL_IPRESOLVE_V4:
684     pf = PF_INET;
685     break;
686   case CURL_IPRESOLVE_V6:
687     pf = PF_INET6;
688     break;
689   default:
690     pf = PF_UNSPEC;
691     break;
692   }
693
694   if((pf != PF_INET) && !Curl_ipv6works())
695     /* The stack seems to be a non-IPv6 one */
696     pf = PF_INET;
697 #endif /* CURLRES_IPV6 */
698
699   memset(&hints, 0, sizeof(hints));
700   hints.ai_family = pf;
701   hints.ai_socktype = conn->socktype;
702
703   snprintf(sbuf, sizeof(sbuf), "%d", port);
704
705   reslv->start = Curl_now();
706   /* fire up a new resolver thread! */
707   if(init_resolve_thread(conn, hostname, port, &hints)) {
708     *waitp = 1; /* expect asynchronous response */
709     return NULL;
710   }
711
712   failf(data, "getaddrinfo() thread failed to start\n");
713   return NULL;
714
715 }
716
717 #endif /* !HAVE_GETADDRINFO */
718
719 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
720                               char *servers)
721 {
722   (void)data;
723   (void)servers;
724   return CURLE_NOT_BUILT_IN;
725
726 }
727
728 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
729                                 const char *interf)
730 {
731   (void)data;
732   (void)interf;
733   return CURLE_NOT_BUILT_IN;
734 }
735
736 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
737                                 const char *local_ip4)
738 {
739   (void)data;
740   (void)local_ip4;
741   return CURLE_NOT_BUILT_IN;
742 }
743
744 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
745                                 const char *local_ip6)
746 {
747   (void)data;
748   (void)local_ip6;
749   return CURLE_NOT_BUILT_IN;
750 }
751
752 #endif /* CURLRES_THREADED */