]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
CURLOPT_QUICK_EXIT: don't wait for DNS thread on exit
authorAlexandre Ferrieux <alexandre.ferrieux@orange.com>
Tue, 12 Jul 2022 21:40:05 +0000 (23:40 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 17 Nov 2022 23:17:27 +0000 (00:17 +0100)
Fixes #2975
Closes #9147

.github/scripts/spellcheck.words
docs/libcurl/curl_easy_setopt.3
docs/libcurl/opts/CURLOPT_QUICK_EXIT.3 [new file with mode: 0644]
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/asyn-thread.c
lib/easyoptions.c
lib/setopt.c
lib/url.c
lib/urldata.h
src/tool_operate.c

index d8836d1376d4075ebb2be48c6c5cbafa8bd9bb11..73b65d46f600eaa13dc18b218ab104e2c3879a6f 100644 (file)
@@ -755,6 +755,7 @@ Tomtom
 toolchain
 toolchains
 toolset
+toplevel
 TPF
 TrackMemory
 Tru
index da7752767b479c2e5f526d055b0233dbc85f67b3..9295d84aa3e8ebeecd223ff83f7e8b6b08d00552 100644 (file)
@@ -699,6 +699,8 @@ Share object to use. See \fICURLOPT_SHARE(3)\fP
 Mode for creating new remote files. See \fICURLOPT_NEW_FILE_PERMS(3)\fP
 .IP CURLOPT_NEW_DIRECTORY_PERMS
 Mode for creating new remote directories. See \fICURLOPT_NEW_DIRECTORY_PERMS(3)\fP
+.IP CURLOPT_QUICK_EXIT
+To be set by toplevel tools like "curl" to skip lengthy cleanups when they are about to call exit() anyway. See \fICURLOPT_QUICK_EXIT(3)\fP
 .SH TELNET OPTIONS
 .IP CURLOPT_TELNETOPTIONS
 TELNET options. See \fICURLOPT_TELNETOPTIONS(3)\fP
diff --git a/docs/libcurl/opts/CURLOPT_QUICK_EXIT.3 b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.3
new file mode 100644 (file)
index 0000000..5f800bb
--- /dev/null
@@ -0,0 +1,59 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" *
+.\" * This software is licensed as described in the file COPYING, which
+.\" * you should have received as part of this distribution. The terms
+.\" * are also available at https://curl.se/docs/copyright.html.
+.\" *
+.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+.\" * copies of the Software, and permit persons to whom the Software is
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" * SPDX-License-Identifier: curl
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_QUICK_EXIT 3 "30 Sep 2022" "libcurl 7.87.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_QUICK_EXIT \- allow to exit quickly
+.SH SYNOPSIS
+.nf
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_QUICK_EXIT,
+                          long value);
+.SH DESCRIPTION
+Pass a long as a parameter, 1L meaning that when recovering from a timeout,
+libcurl should skip lengthy cleanups that are intended to avoid all kinds of
+leaks (threads etc.), as the caller program is about to call exit() anyway.
+This allows for a swift termination after a DNS timeout for example, by
+canceling and/or forgetting about a resolver thread, at the expense of a
+possible (though short-lived) leak of associated resources.
+.SH DEFAULT
+0
+.SH PROTOCOLS
+All
+.SH EXAMPLE
+.nf
+CURL *curl = curl_easy_init();
+if(curl) {
+  CURLcode ret;
+  curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
+  ret = curl_easy_perform(curl);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.87.0
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_RESOLVE "(3), "
index 59c66b4e35392a3ff86287dc1f19c94dc7629c36..5ee245d361ef8576ffe91e4618b34b0482a03a38 100644 (file)
@@ -687,6 +687,7 @@ CURLOPT_MAIL_AUTH               7.25.0
 CURLOPT_MAIL_FROM               7.20.0
 CURLOPT_MAIL_RCPT               7.20.0
 CURLOPT_MAIL_RCPT_ALLLOWFAILS   7.69.0
+CURLOPT_QUICK_EXIT              7.87.0
 CURLOPT_MAX_RECV_SPEED_LARGE    7.15.5
 CURLOPT_MAX_SEND_SPEED_LARGE    7.15.5
 CURLOPT_MAXAGE_CONN             7.65.0
index 6b8b10bd1ae0b2a8a2aaa18064bd3cbd15856418..efbba31f80e5dac94dd8169e3e080a1cc58fbefc 100644 (file)
@@ -2201,6 +2201,9 @@ typedef enum {
   /* CA cache timeout */
   CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321),
 
+  /* Can leak things, gonna exit() soon */
+  CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 283629e8453bf0d136d62b48ecc42cfc8d9eeb44..3524ada584fbb48447f5d36d6f11e3e410d610af 100644 (file)
@@ -534,7 +534,8 @@ void Curl_resolver_kill(struct Curl_easy *data)
   /* If we're still resolving, we must wait for the threads to fully clean up,
      unfortunately.  Otherwise, we can simply cancel to clean up any resolver
      data. */
-  if(td && td->thread_hnd != curl_thread_t_null)
+  if(td && td->thread_hnd != curl_thread_t_null
+     && (data->set.quick_exit != 1L))
     (void)thread_wait_resolv(data, NULL, FALSE);
   else
     Curl_resolver_cancel(data);
index 594150178addca71782cda6fcf5d1e7f6bd9d97b..03b814e5aaf5744b3bdd1469f9d5235ce42558a1 100644 (file)
@@ -242,6 +242,7 @@ struct curl_easyoption Curl_easyopts[] = {
    CURLOT_STRING, 0},
   {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0},
   {"PUT", CURLOPT_PUT, CURLOT_LONG, 0},
+  {"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0},
   {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0},
   {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0},
   {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0},
@@ -369,6 +370,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return ((CURLOPT_LASTENTRY%10000) != (321 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (322 + 1));
 }
 #endif
index 51335b8cd7a781d1045651700126dbd0c92e4b33..d53131a0ec610e8407df6106702c2a373fd45bc6 100644 (file)
@@ -3116,6 +3116,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   }
 #endif
+  case CURLOPT_QUICK_EXIT:
+    data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
+    break;
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_UNKNOWN_OPTION;
index a9d89cc2c1543af4f2965288498672d49d2b88e2..f2ad31742c8cd2f8614a0c019399e2fc5fe6f83a 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -655,6 +655,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
 #endif
     ;
   Curl_http2_init_userset(set);
+  set->quick_exit = 0L;
   return result;
 }
 
index 638763cf77797f8231e4033103c826a9da163049..c50171e73cb3ac192be4589e005f607abe991899 100644 (file)
@@ -1826,6 +1826,10 @@ struct UserDefined {
 /* Here follows boolean settings that define how to behave during
    this session. They are STATIC, set by libcurl users or at least initially
    and they don't change during operations. */
+  BIT(quick_exit);       /* set 1L when it is okay to leak things (like
+                            threads), as we're about to exit() anyway and
+                            don't want lengthy cleanups to delay termination,
+                            e.g. after a DNS timeout */
   BIT(get_filetime);     /* get the time and get of the remote file */
   BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
   BIT(prefer_ascii);     /* ASCII rather than binary */
index 095c24bacf1c9c3d0ccaee12a70968483f9db070..cd137ec10dc11772df737593d735ae85f2f99a96 100644 (file)
@@ -1237,6 +1237,15 @@ static CURLcode single_transfer(struct GlobalConfig *global,
 
         use_proto = url_proto(per->this_url);
 
+        /* On most modern OSes, exiting works thoroughly,
+           we'll clean everything up via exit(), so don't bother with
+           slow cleanups. Crappy ones might need to skip this.
+           Note: avoid having this setopt added to the --libcurl source
+           output. */
+        result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
+        if(result)
+          break;
+
         if(!config->tcp_nodelay)
           my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);