Ver código fonte

Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2025-06-04 (fdb8a789)
Brad King 4 meses atrás
pai
commit
cebb60188f
100 arquivos alterados com 6772 adições e 4680 exclusões
  1. 5 5
      Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
  2. 39 59
      Utilities/cmcurl/CMake/CurlTests.c
  3. 4 9
      Utilities/cmcurl/CMake/FindBrotli.cmake
  4. 3 7
      Utilities/cmcurl/CMake/FindLDAP.cmake
  5. 3 8
      Utilities/cmcurl/CMake/FindMbedTLS.cmake
  6. 5 12
      Utilities/cmcurl/CMake/FindNGTCP2.cmake
  7. 8 1
      Utilities/cmcurl/CMake/Macros.cmake
  8. 3 5
      Utilities/cmcurl/CMake/OtherTests.cmake
  9. 127 46
      Utilities/cmcurl/CMake/PickyWarnings.cmake
  10. 5 4
      Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
  11. 11 4
      Utilities/cmcurl/CMake/curl-config.cmake.in
  12. 316 0
      Utilities/cmcurl/CMake/unix-cache.cmake
  13. 149 109
      Utilities/cmcurl/CMake/win32-cache.cmake
  14. 265 234
      Utilities/cmcurl/CMakeLists.txt
  15. 116 80
      Utilities/cmcurl/include/curl/curl.h
  16. 3 3
      Utilities/cmcurl/include/curl/curlver.h
  17. 22 12
      Utilities/cmcurl/include/curl/system.h
  18. 348 199
      Utilities/cmcurl/include/curl/typecheck-gcc.h
  19. 2 1
      Utilities/cmcurl/include/curl/websockets.h
  20. 59 36
      Utilities/cmcurl/lib/CMakeLists.txt
  21. 48 32
      Utilities/cmcurl/lib/Makefile.inc
  22. 155 203
      Utilities/cmcurl/lib/altsvc.c
  23. 2 2
      Utilities/cmcurl/lib/altsvc.h
  24. 1 1
      Utilities/cmcurl/lib/amigaos.c
  25. 387 443
      Utilities/cmcurl/lib/asyn-ares.c
  26. 196 0
      Utilities/cmcurl/lib/asyn-base.c
  27. 760 0
      Utilities/cmcurl/lib/asyn-thrdd.c
  28. 0 812
      Utilities/cmcurl/lib/asyn-thread.c
  29. 173 146
      Utilities/cmcurl/lib/asyn.h
  30. 3 1
      Utilities/cmcurl/lib/bufref.c
  31. 27 23
      Utilities/cmcurl/lib/cf-h1-proxy.c
  32. 4 4
      Utilities/cmcurl/lib/cf-h2-proxy.c
  33. 15 15
      Utilities/cmcurl/lib/cf-haproxy.c
  34. 96 82
      Utilities/cmcurl/lib/cf-https-connect.c
  35. 1 4
      Utilities/cmcurl/lib/cf-https-connect.h
  36. 85 103
      Utilities/cmcurl/lib/cf-socket.c
  37. 1 1
      Utilities/cmcurl/lib/cf-socket.h
  38. 82 22
      Utilities/cmcurl/lib/cfilters.c
  39. 24 17
      Utilities/cmcurl/lib/cfilters.h
  40. 250 801
      Utilities/cmcurl/lib/conncache.c
  41. 25 62
      Utilities/cmcurl/lib/conncache.h
  42. 75 71
      Utilities/cmcurl/lib/connect.c
  43. 5 6
      Utilities/cmcurl/lib/connect.h
  44. 27 17
      Utilities/cmcurl/lib/content_encoding.c
  45. 104 179
      Utilities/cmcurl/lib/cookie.c
  46. 581 0
      Utilities/cmcurl/lib/cshutdn.c
  47. 110 0
      Utilities/cmcurl/lib/cshutdn.h
  48. 30 14
      Utilities/cmcurl/lib/curl_addrinfo.c
  49. 22 13
      Utilities/cmcurl/lib/curl_config.h.cmake
  50. 1 0
      Utilities/cmcurl/lib/curl_ctype.h
  51. 12 11
      Utilities/cmcurl/lib/curl_fnmatch.c
  52. 5 5
      Utilities/cmcurl/lib/curl_get_line.c
  53. 1 7
      Utilities/cmcurl/lib/curl_get_line.h
  54. 2 2
      Utilities/cmcurl/lib/curl_gssapi.c
  55. 5 3
      Utilities/cmcurl/lib/curl_krb5.h
  56. 0 14
      Utilities/cmcurl/lib/curl_memory.h
  57. 1 7
      Utilities/cmcurl/lib/curl_memrchr.c
  58. 0 6
      Utilities/cmcurl/lib/curl_memrchr.h
  59. 16 25
      Utilities/cmcurl/lib/curl_ntlm_core.c
  60. 15 9
      Utilities/cmcurl/lib/curl_printf.h
  61. 17 16
      Utilities/cmcurl/lib/curl_range.c
  62. 38 16
      Utilities/cmcurl/lib/curl_rtmp.c
  63. 102 6
      Utilities/cmcurl/lib/curl_sasl.c
  64. 2 0
      Utilities/cmcurl/lib/curl_sasl.h
  65. 78 27
      Utilities/cmcurl/lib/curl_setup.h
  66. 54 82
      Utilities/cmcurl/lib/curl_setup_once.h
  67. 1 5
      Utilities/cmcurl/lib/curl_sha512_256.c
  68. 8 8
      Utilities/cmcurl/lib/curl_sspi.c
  69. 246 1
      Utilities/cmcurl/lib/curl_sspi.h
  70. 20 19
      Utilities/cmcurl/lib/curl_threads.c
  71. 2 2
      Utilities/cmcurl/lib/curl_threads.h
  72. 236 82
      Utilities/cmcurl/lib/curl_trc.c
  73. 23 5
      Utilities/cmcurl/lib/curl_trc.h
  74. 32 40
      Utilities/cmcurl/lib/curlx/base64.c
  75. 8 13
      Utilities/cmcurl/lib/curlx/base64.h
  76. 19 14
      Utilities/cmcurl/lib/curlx/curlx.h
  77. 30 26
      Utilities/cmcurl/lib/curlx/dynbuf.c
  78. 20 33
      Utilities/cmcurl/lib/curlx/dynbuf.h
  79. 9 20
      Utilities/cmcurl/lib/curlx/inet_pton.c
  80. 5 5
      Utilities/cmcurl/lib/curlx/inet_pton.h
  81. 34 27
      Utilities/cmcurl/lib/curlx/multibyte.c
  82. 4 9
      Utilities/cmcurl/lib/curlx/multibyte.h
  83. 1 1
      Utilities/cmcurl/lib/curlx/nonblock.c
  84. 0 0
      Utilities/cmcurl/lib/curlx/nonblock.h
  85. 303 0
      Utilities/cmcurl/lib/curlx/strparse.c
  86. 112 0
      Utilities/cmcurl/lib/curlx/strparse.h
  87. 2 2
      Utilities/cmcurl/lib/curlx/timediff.c
  88. 1 1
      Utilities/cmcurl/lib/curlx/timediff.h
  89. 38 16
      Utilities/cmcurl/lib/curlx/timeval.c
  90. 10 5
      Utilities/cmcurl/lib/curlx/timeval.h
  91. 11 89
      Utilities/cmcurl/lib/curlx/version_win32.c
  92. 2 2
      Utilities/cmcurl/lib/curlx/version_win32.h
  93. 2 29
      Utilities/cmcurl/lib/curlx/warnless.c
  94. 3 5
      Utilities/cmcurl/lib/curlx/warnless.h
  95. 135 0
      Utilities/cmcurl/lib/curlx/winapi.c
  96. 7 10
      Utilities/cmcurl/lib/curlx/winapi.h
  97. 64 42
      Utilities/cmcurl/lib/cw-out.c
  98. 1 1
      Utilities/cmcurl/lib/cw-out.h
  99. 242 0
      Utilities/cmcurl/lib/cw-pause.c
  100. 10 24
      Utilities/cmcurl/lib/cw-pause.h

+ 5 - 5
Utilities/cmcurl/CMake/CurlSymbolHiding.cmake

@@ -29,7 +29,7 @@ if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
   # e.g. curl_easy_perform_ev() or curl_dbg_*(),
   # so disable symbol hiding for debug builds and for memory tracking.
   set(CURL_HIDDEN_SYMBOLS OFF)
-elseif(DOS OR AMIGA)
+elseif(DOS OR AMIGA OR MINGW32CE)
   set(CURL_HIDDEN_SYMBOLS OFF)
 endif()
 
@@ -42,18 +42,18 @@ if(CURL_HIDDEN_SYMBOLS)
     set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
     set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
     set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
-  elseif(CMAKE_COMPILER_IS_GNUCC)
-    if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+  elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+    if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.4)
       # Note: This is considered buggy prior to 4.0 but the autotools do not care, so let us ignore that fact
       set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
       set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
       set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
     endif()
-  elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
+  elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
     set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
     set(CURL_EXTERN_SYMBOL "__global")
     set(CURL_CFLAG_SYMBOLS_HIDE "-xldscope=hidden")
-  elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)  # Requires 9.1.045
+  elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.0)  # Requires 9.1.045
     set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
     set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
     set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")

+ 39 - 59
Utilities/cmcurl/CMake/CurlTests.c

@@ -30,14 +30,14 @@
 /* */
 #if defined(sun) || defined(__sun__) || \
     defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-# if defined(__SVR4) || defined(__srv4__)
-#  define PLATFORM_SOLARIS
-# else
-#  define PLATFORM_SUNOS4
-# endif
+#  if defined(__SVR4) || defined(__srv4__)
+#    define PLATFORM_SOLARIS
+#  else
+#    define PLATFORM_SUNOS4
+#  endif
 #endif
 #if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX41)
-# define PLATFORM_AIX_V3
+#  define PLATFORM_AIX_V3
 #endif
 /* */
 #if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3)
@@ -55,72 +55,52 @@ int main(void)
 #endif
 
 /* tests for gethostbyname_r */
-#if defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
-    defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
-    defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
-#   define _REENTRANT
-    /* no idea whether _REENTRANT is always set, just invent a new flag */
-#   define TEST_GETHOSTBYFOO_REENTRANT
-#endif
 #if defined(HAVE_GETHOSTBYNAME_R_3) || \
+    defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
     defined(HAVE_GETHOSTBYNAME_R_5) || \
+    defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
     defined(HAVE_GETHOSTBYNAME_R_6) || \
-    defined(TEST_GETHOSTBYFOO_REENTRANT)
+    defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
 #include <sys/types.h>
 #include <netdb.h>
 int main(void)
 {
   const char *address = "example.com";
-  int length = 0;
-  int type = 0;
   struct hostent h;
   int rc = 0;
-#if defined(HAVE_GETHOSTBYNAME_R_3) || \
-    defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
+#if   defined(HAVE_GETHOSTBYNAME_R_3) || \
+      defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
   struct hostent_data hdata;
 #elif defined(HAVE_GETHOSTBYNAME_R_5) || \
       defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
       defined(HAVE_GETHOSTBYNAME_R_6) || \
       defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
   char buffer[8192];
-  int h_errnop;
   struct hostent *hp;
+  int h_errnop;
 #endif
 
 #if   defined(HAVE_GETHOSTBYNAME_R_3) || \
       defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
   rc = gethostbyname_r(address, &h, &hdata);
+  (void)hdata;
 #elif defined(HAVE_GETHOSTBYNAME_R_5) || \
       defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT)
   rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop);
   (void)hp; /* not used for test */
+  (void)h_errnop;
 #elif defined(HAVE_GETHOSTBYNAME_R_6) || \
       defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
   rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop);
+  (void)hp;
+  (void)h_errnop;
 #endif
-
-  (void)length;
-  (void)type;
+  (void)h;
   (void)rc;
   return 0;
 }
 #endif
 
-#ifdef HAVE_IN_ADDR_T
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-int main(void)
-{
-  if((in_addr_t *) 0)
-    return 0;
-  if(sizeof(in_addr_t))
-    return 0;
-  ;
-  return 0;
-}
-#endif
-
 #ifdef HAVE_BOOL_T
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -130,10 +110,7 @@ int main(void)
 #endif
 int main(void)
 {
-  if(sizeof(bool *))
-    return 0;
-  ;
-  return 0;
+  return (int)sizeof(bool *);
 }
 #endif
 
@@ -146,18 +123,20 @@ int main(void) { return 0; }
 #endif
 
 #ifdef HAVE_FILE_OFFSET_BITS
-#undef _FILE_OFFSET_BITS
-#define _FILE_OFFSET_BITS 64
 #include <sys/types.h>
 /* Check that off_t can represent 2**63 - 1 correctly.
    We cannot simply define LARGE_OFF_T to be 9223372036854775807,
    since some C++ compilers masquerading as C compilers
    incorrectly reject 9223372036854775807. */
 #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
-int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
-                     && LARGE_OFF_T % 2147483647 == 1)
-                    ? 1 : -1];
-int main(void) { return 0; }
+static int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 &&
+                           LARGE_OFF_T % 2147483647 == 1)
+                          ? 1 : -1];
+int main(void)
+{
+  (void)off_t_is_large;
+  return 0;
+}
 #endif
 
 #ifdef HAVE_IOCTLSOCKET
@@ -169,7 +148,7 @@ int main(void)
   /* ioctlsocket source code */
   int socket = -1;
   unsigned long flags = ioctlsocket(socket, FIONBIO, &flags);
-  ;
+  (void)flags;
   return 0;
 }
 
@@ -182,7 +161,6 @@ int main(void)
   /* IoctlSocket source code */
   if(0 != IoctlSocket(0, 0, 0))
     return 1;
-  ;
   return 0;
 }
 #endif
@@ -198,7 +176,7 @@ int main(void)
   long flags = 0;
   if(0 != IoctlSocket(0, FIONBIO, &flags))
     return 1;
-  ;
+  (void)flags;
   return 0;
 }
 #endif
@@ -212,7 +190,7 @@ int main(void)
   unsigned long flags = 0;
   if(0 != ioctlsocket(0, FIONBIO, &flags))
     return 1;
-  ;
+  (void)flags;
   return 0;
 }
 #endif
@@ -239,7 +217,7 @@ int main(void)
   int flags = 0;
   if(0 != ioctl(0, FIONBIO, &flags))
     return 1;
-  ;
+  (void)flags;
   return 0;
 }
 #endif
@@ -267,7 +245,7 @@ int main(void)
   struct ifreq ifr;
   if(0 != ioctl(0, SIOCGIFADDR, &ifr))
     return 1;
-  ;
+  (void)ifr;
   return 0;
 }
 #endif
@@ -286,7 +264,6 @@ int main(void)
 {
   if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
     return 1;
-  ;
   return 0;
 }
 #endif
@@ -295,12 +272,13 @@ int main(void)
 #include <string.h>
 #include <errno.h>
 
-void check(char c) {}
+static void check(char c) { (void)c; }
 
 int main(void)
 {
   char buffer[1024];
   /* This will not compile if strerror_r does not return a char* */
+  /* !checksrc! disable ERRNOVAR 1 */
   check(strerror_r(EACCES, buffer, sizeof(buffer))[0]);
   return 0;
 }
@@ -311,12 +289,13 @@ int main(void)
 #include <errno.h>
 
 /* Float, because a pointer cannot be implicitly cast to float */
-void check(float f) {}
+static void check(float f) { (void)f; }
 
 int main(void)
 {
   char buffer[1024];
   /* This will not compile if strerror_r does not return an int */
+  /* !checksrc! disable ERRNOVAR 1 */
   check(strerror_r(EACCES, buffer, sizeof(buffer)));
   return 0;
 }
@@ -335,7 +314,7 @@ int main(void)
 #include <sys/xattr.h> /* header from libc, not from libattr */
 int main(void)
 {
-  fsetxattr(0, 0, 0, 0, 0);
+  fsetxattr(0, "", 0, 0, 0);
   return 0;
 }
 #endif
@@ -344,8 +323,9 @@ int main(void)
 #include <time.h>
 int main(void)
 {
-  struct timespec ts = {0, 0};
-  clock_gettime(CLOCK_MONOTONIC, &ts);
+  struct timespec ts;
+  (void)clock_gettime(CLOCK_MONOTONIC, &ts);
+  (void)ts;
   return 0;
 }
 #endif

+ 4 - 9
Utilities/cmcurl/CMake/FindBrotli.cmake

@@ -39,24 +39,19 @@
 # - `BROTLI_CFLAGS`:         Required compiler flags.
 # - `BROTLI_VERSION`:        Version of brotli.
 
-set(BROTLI_PC_REQUIRES "libbrotlidec")
+set(BROTLI_PC_REQUIRES "libbrotlidec" "libbrotlicommon")  # order is significant: brotlidec then brotlicommon
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED BROTLI_INCLUDE_DIR AND
    NOT DEFINED BROTLICOMMON_LIBRARY AND
    NOT DEFINED BROTLIDEC_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(BROTLI "libbrotlicommon")
-  pkg_check_modules(BROTLIDEC ${BROTLI_PC_REQUIRES})
+  pkg_check_modules(BROTLI ${BROTLI_PC_REQUIRES})
 endif()
 
-if(BROTLI_FOUND AND BROTLIDEC_FOUND)
+if(BROTLI_FOUND)
   set(Brotli_FOUND TRUE)
-  list(APPEND BROTLIDEC_LIBRARIES ${BROTLI_LIBRARIES})  # order is significant: brotlidec then brotlicommon
-  list(REVERSE BROTLIDEC_LIBRARIES)
-  list(REMOVE_DUPLICATES BROTLIDEC_LIBRARIES)
-  list(REVERSE BROTLIDEC_LIBRARIES)
-  set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARIES})
+  set(BROTLI_VERSION "${BROTLI_libbrotlicommon_VERSION}")
   string(REPLACE ";" " " BROTLI_CFLAGS "${BROTLI_CFLAGS}")
   message(STATUS "Found Brotli (via pkg-config): ${BROTLI_INCLUDE_DIRS} (found version \"${BROTLI_VERSION}\")")
 else()

+ 3 - 7
Utilities/cmcurl/CMake/FindLDAP.cmake

@@ -39,7 +39,7 @@
 # - `LDAP_CFLAGS`:        Required compiler flags.
 # - `LDAP_VERSION`:       Version of ldap.
 
-set(LDAP_PC_REQUIRES "ldap")
+set(LDAP_PC_REQUIRES "ldap" "lber")
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LDAP_INCLUDE_DIR AND
@@ -47,14 +47,10 @@ if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LDAP_LBER_LIBRARY)
   find_package(PkgConfig QUIET)
   pkg_check_modules(LDAP ${LDAP_PC_REQUIRES})
-  pkg_check_modules(LDAP_LBER "lber")
 endif()
 
-if(LDAP_FOUND AND LDAP_LBER_FOUND)
-  list(APPEND LDAP_LIBRARIES ${LDAP_LBER_LIBRARIES})
-  list(REVERSE LDAP_LIBRARIES)
-  list(REMOVE_DUPLICATES LDAP_LIBRARIES)
-  list(REVERSE LDAP_LIBRARIES)
+if(LDAP_FOUND)
+  set(LDAP_VERSION "${LDAP_ldap_VERSION}")
   string(REPLACE ";" " " LDAP_CFLAGS "${LDAP_CFLAGS}")
   message(STATUS "Found LDAP (via pkg-config): ${LDAP_INCLUDE_DIRS} (found version \"${LDAP_VERSION}\")")
 else()

+ 3 - 8
Utilities/cmcurl/CMake/FindMbedTLS.cmake

@@ -46,7 +46,7 @@ if(DEFINED MBEDTLS_INCLUDE_DIRS AND NOT DEFINED MBEDTLS_INCLUDE_DIR)
   unset(MBEDTLS_INCLUDE_DIRS)
 endif()
 
-set(MBEDTLS_PC_REQUIRES "mbedtls")
+set(MBEDTLS_PC_REQUIRES "mbedtls" "mbedx509" "mbedcrypto")
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MBEDTLS_INCLUDE_DIR AND
@@ -55,16 +55,11 @@ if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MBEDCRYPTO_LIBRARY)
   find_package(PkgConfig QUIET)
   pkg_check_modules(MBEDTLS ${MBEDTLS_PC_REQUIRES})
-  pkg_check_modules(MBEDX509 "mbedx509")
-  pkg_check_modules(MBEDCRYPTO "mbedcrypto")
 endif()
 
-if(MBEDTLS_FOUND AND MBEDX509_FOUND AND MBEDCRYPTO_FOUND)
+if(MBEDTLS_FOUND)
   set(MbedTLS_FOUND TRUE)
-  list(APPEND MBEDTLS_LIBRARIES ${MBEDX509_LIBRARIES} ${MBEDCRYPTO_LIBRARIES})
-  list(REVERSE MBEDTLS_LIBRARIES)
-  list(REMOVE_DUPLICATES MBEDTLS_LIBRARIES)
-  list(REVERSE MBEDTLS_LIBRARIES)
+  set(MBEDTLS_VERSION "${MBEDTLS_mbedtls_VERSION}")
   string(REPLACE ";" " " MBEDTLS_CFLAGS "${MBEDTLS_CFLAGS}")
   message(STATUS "Found MbedTLS (via pkg-config): ${MBEDTLS_INCLUDE_DIRS} (found version \"${MBEDTLS_VERSION}\")")
 else()

+ 5 - 12
Utilities/cmcurl/CMake/FindNGTCP2.cmake

@@ -30,6 +30,7 @@
 # - BoringSSL:  Use `libngtcp2_crypto_boringssl`. (choose this for AWS-LC)
 # - wolfSSL:    Use `libngtcp2_crypto_wolfssl`.
 # - GnuTLS:     Use `libngtcp2_crypto_gnutls`.
+# - ossl:       Use `libngtcp2_crypto_ossl`.
 #
 # Input variables:
 #
@@ -49,7 +50,7 @@
 if(NGTCP2_FIND_COMPONENTS)
   set(_ngtcp2_crypto_backend "")
   foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
-    if(_component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)")
+    if(_component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS|ossl)")
       if(_ngtcp2_crypto_backend)
         message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
       endif()
@@ -65,7 +66,7 @@ endif()
 
 set(NGTCP2_PC_REQUIRES "libngtcp2")
 if(_ngtcp2_crypto_backend)
-  set(NGTCP2_CRYPTO_PC_REQUIRES "lib${_crypto_library_lower}")
+  list(APPEND NGTCP2_PC_REQUIRES "lib${_crypto_library_lower}")
 endif()
 
 if(CURL_USE_PKGCONFIG AND
@@ -73,18 +74,10 @@ if(CURL_USE_PKGCONFIG AND
    NOT DEFINED NGTCP2_LIBRARY)
   find_package(PkgConfig QUIET)
   pkg_check_modules(NGTCP2 ${NGTCP2_PC_REQUIRES})
-  if(_ngtcp2_crypto_backend)
-    pkg_check_modules("${_crypto_library_upper}" ${NGTCP2_CRYPTO_PC_REQUIRES})
-  else()
-    set("${_crypto_library_upper}_FOUND" TRUE)
-  endif()
 endif()
 
-list(APPEND NGTCP2_PC_REQUIRES ${NGTCP2_CRYPTO_PC_REQUIRES})
-
-if(NGTCP2_FOUND AND "${${_crypto_library_upper}_FOUND}")
-  list(APPEND NGTCP2_LIBRARIES "${${_crypto_library_upper}_LIBRARIES}")
-  list(REMOVE_DUPLICATES NGTCP2_LIBRARIES)
+if(NGTCP2_FOUND)
+  set(NGTCP2_VERSION "${NGTCP2_libngtcp2_VERSION}")
   string(REPLACE ";" " " NGTCP2_CFLAGS "${NGTCP2_CFLAGS}")
   message(STATUS "Found NGTCP2 (via pkg-config): ${NGTCP2_INCLUDE_DIRS} (found version \"${NGTCP2_VERSION}\")")
 else()

+ 8 - 1
Utilities/cmcurl/CMake/Macros.cmake

@@ -52,7 +52,7 @@ macro(curl_internal_test _curl_test)
       ${PROJECT_BINARY_DIR}
       "${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c"
       CMAKE_FLAGS
-        "-DCOMPILE_DEFINITIONS:STRING=-D${_curl_test} ${CURL_TEST_DEFINES} ${_cmake_required_definitions}"
+        "-DCOMPILE_DEFINITIONS:STRING=-D${_curl_test} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS} ${_cmake_required_definitions}"
         "${_curl_test_add_libraries}"
       OUTPUT_VARIABLE CURL_TEST_OUTPUT)
     if(${_curl_test})
@@ -87,3 +87,10 @@ macro(curl_required_libpaths _libpaths_arg)
     list(APPEND CMAKE_REQUIRED_LINK_DIRECTORIES "${_libpaths_arg}")
   endif()
 endmacro()
+
+# Pre-fill variables set by a check_type_size() call.
+macro(curl_prefill_type_size _type _size)
+  set(HAVE_SIZEOF_${_type} TRUE)
+  set(SIZEOF_${_type} ${_size})
+  set(SIZEOF_${_type}_CODE "#define SIZEOF_${_type} ${_size}")
+endmacro()

+ 3 - 5
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -107,11 +107,10 @@ if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
   check_c_source_compiles("${_source_epilogue}
     int main(void)
     {
-    #ifdef h_errno
-      return 0;
-    #else
+    #ifndef h_errno
       #error force compilation error
     #endif
+      return 0;
     }" HAVE_H_ERRNO)
 
   if(NOT HAVE_H_ERRNO)
@@ -127,12 +126,11 @@ if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
         int main(void)
         {
         #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
-          return 0;
         #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
-          return 0;
         #else
           #error force compilation error
         #endif
+          return 0;
         }" HAVE_H_ERRNO_SBS_ISSUE_7)
     endif()
   endif()

+ 127 - 46
Utilities/cmcurl/CMake/PickyWarnings.cmake

@@ -24,28 +24,45 @@
 include(CheckCCompilerFlag)
 
 set(_picky "")
+set(_picky_nocheck "")  # not to pass to feature checks
 
-if(CURL_WERROR AND
-   ((CMAKE_COMPILER_IS_GNUCC AND
-     NOT DOS AND  # Watt-32 headers use the '#include_next' GCC extension
-     NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
-     NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # to avoid check_symbol_exists() conflicting with GCC -pedantic-errors
-   CMAKE_C_COMPILER_ID MATCHES "Clang"))
-  list(APPEND _picky "-pedantic-errors")
+if(CURL_WERROR)
+  if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
+    set(CMAKE_COMPILE_WARNING_AS_ERROR ON)
+  else()
+    if(MSVC)
+      list(APPEND _picky_nocheck "-WX")
+    else()  # llvm/clang and gcc style options
+      list(APPEND _picky_nocheck "-Werror")
+    endif()
+  endif()
+
+  if((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+      NOT DOS AND  # Watt-32 headers use the '#include_next' GCC extension
+      CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0) OR
+     CMAKE_C_COMPILER_ID MATCHES "Clang")
+    list(APPEND _picky_nocheck "-pedantic-errors")
+  endif()
 endif()
 
 if(APPLE AND
-   (CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
-   (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
+   (CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR
+   (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3))
   list(APPEND _picky "-Werror=partial-availability")  # clang 3.6  appleclang 6.3
 endif()
 
-if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
   list(APPEND _picky "-Werror-implicit-function-declaration")  # clang 1.0  gcc 2.95
 endif()
 
+if(MSVC)
+  list(APPEND _picky "-W4")  # Use the highest warning level for Visual Studio.
+elseif(BORLAND)
+  list(APPEND _picky "-w-")  # Disable warnings on Borland to avoid changing 3rd party code.
+endif()
+
 if(PICKY_COMPILER)
-  if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+  if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
 
     # https://clang.llvm.org/docs/DiagnosticsReference.html
     # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
@@ -93,6 +110,7 @@ if(PICKY_COMPILER)
       -Waddress                            # clang  2.7  gcc  4.3
       -Wattributes                         # clang  2.7  gcc  4.1
       -Wcast-align                         # clang  1.0  gcc  4.2
+      -Wcast-qual                          # clang  3.0  gcc  3.4.6
       -Wdeclaration-after-statement        # clang  1.0  gcc  3.4
       -Wdiv-by-zero                        # clang  2.7  gcc  4.1
       -Wempty-body                         # clang  2.7  gcc  4.3
@@ -113,6 +131,7 @@ if(PICKY_COMPILER)
       -Wtype-limits                        # clang  2.7  gcc  4.3
       -Wunreachable-code                   # clang  2.7  gcc  4.1
     # -Wunused-macros                      # clang  2.7  gcc  4.1               # Not practical
+    #   -Wno-error=unused-macros           # clang  2.7  gcc  4.1
       -Wunused-parameter                   # clang  2.7  gcc  4.1
       -Wvla                                # clang  2.8  gcc  4.3
     )
@@ -130,8 +149,8 @@ if(PICKY_COMPILER)
         )
       endif()
       # Enable based on compiler version
-      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
-         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
+      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR
+         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3))
         list(APPEND _picky_enable
           -Wdouble-promotion               # clang  3.6  gcc  4.6  appleclang  6.3
           -Wenum-conversion                # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
@@ -142,29 +161,30 @@ if(PICKY_COMPILER)
           -Wunused-const-variable          # clang  3.4  gcc  6.0  appleclang  5.1
         )
       endif()
-      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR
-         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.3))
+      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9) OR
+         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.3))
         list(APPEND _picky_enable
           -Wcomma                          # clang  3.9            appleclang  8.3
           -Wmissing-variable-declarations  # clang  3.2            appleclang  4.6
         )
       endif()
-      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0) OR
-         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.3))
+      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) OR
+         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.3))
         list(APPEND _picky_enable
           -Wassign-enum                    # clang  7.0            appleclang 10.3
           -Wextra-semi-stmt                # clang  7.0            appleclang 10.3
         )
       endif()
-      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0) OR
-         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.4))
+      if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR
+         (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.4))
         list(APPEND _picky_enable
           -Wimplicit-fallthrough           # clang  4.0  gcc  7.0  appleclang 12.4  # We do silencing for clang 10.0 and above only
+          -Wxor-used-as-pow                # clang 10.0  gcc 13.0
         )
       endif()
     else()  # gcc
       # Enable based on compiler version
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.3)
         list(APPEND _picky_enable
           ${_picky_common_old}
           -Wclobbered                      #             gcc  4.3
@@ -172,26 +192,32 @@ if(PICKY_COMPILER)
           -Wold-style-declaration          #             gcc  4.3
           -Wpragmas                        # clang  3.5  gcc  4.1  appleclang  6.0
           -Wstrict-aliasing=3              #             gcc  4.0
+          -ftree-vrp                       #             gcc  4.3 (required for -Warray-bounds, included in -Wall)
         )
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.5)
         list(APPEND _picky_enable
-          -Wno-pedantic-ms-format          #             gcc  4.5 (MinGW-only)
+          -Wjump-misses-init               #             gcc  4.5
         )
+        if(MINGW)
+          list(APPEND _picky_enable
+            -Wno-pedantic-ms-format        #             gcc  4.5 (MinGW-only)
+          )
+        endif()
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.8)
         list(APPEND _picky_enable
           -Wdouble-promotion               # clang  3.6  gcc  4.6  appleclang  6.3
           -Wformat=2                       # clang  3.0  gcc  4.8
           -Wtrampolines                    #             gcc  4.6
         )
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0)
         list(APPEND _picky_enable
-          -Warray-bounds=2 -ftree-vrp      # clang  3.0  gcc  5.0 (clang default: -Warray-bounds)
+          -Warray-bounds=2                 # clang  3.0  gcc  5.0 (clang default: -Warray-bounds)
         )
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
         list(APPEND _picky_enable
           -Wduplicated-cond                #             gcc  6.0
           -Wnull-dereference               # clang  3.0  gcc  6.0 (clang default)
@@ -201,7 +227,7 @@ if(PICKY_COMPILER)
           -Wunused-const-variable          # clang  3.4  gcc  6.0  appleclang  5.1
         )
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0)
         list(APPEND _picky_enable
           -Walloc-zero                     #             gcc  7.0
           -Wduplicated-branches            #             gcc  7.0
@@ -210,19 +236,42 @@ if(PICKY_COMPILER)
           -Wrestrict                       #             gcc  7.0
         )
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)
         list(APPEND _picky_enable
           -Warith-conversion               #             gcc 10.0
           -Wenum-conversion                # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
         )
       endif()
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)
+        list(APPEND _picky_enable
+          -Warray-compare                  # clang 20.0  gcc 12.0
+          -Wenum-int-mismatch              #             gcc 13.0
+          -Wxor-used-as-pow                # clang 10.0  gcc 13.0
+        )
+      endif()
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0)
+        list(APPEND _picky_enable
+          -Wleading-whitespace=spaces      #             gcc 15.0
+          -Wtrailing-whitespace=any        #             gcc 15.0
+          -Wunterminated-string-initialization  #        gcc 15.0
+        )
+      endif()
     endif()
 
     #
 
+    set(_picky_skipped "")
     foreach(_ccopt IN LISTS _picky_enable)
-      list(APPEND _picky "${_ccopt}")
+      string(REGEX MATCH "-W([a-z0-9-]+)" _ccmatch "${_ccopt}")
+      if(_ccmatch AND CMAKE_C_FLAGS MATCHES "-Wno-${CMAKE_MATCH_1}" AND NOT _ccopt STREQUAL "-Wall" AND NOT _ccopt MATCHES "^-Wno-")
+        string(APPEND _picky_skipped " ${_ccopt}")
+      else()
+        list(APPEND _picky "${_ccopt}")
+      endif()
     endforeach()
+    if(_picky_skipped)
+      message(STATUS "Picky compiler options skipped due to CMAKE_C_FLAGS override:${_picky_skipped}")
+    endif()
 
     foreach(_ccopt IN LISTS _picky_detect)
       # Use a unique variable name 1. for meaningful log output 2. to have a fresh, undefined variable for each detection
@@ -236,22 +285,43 @@ if(PICKY_COMPILER)
       endif()
     endforeach()
 
-    if(CMAKE_COMPILER_IS_GNUCC)
+    if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
       if(CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
         # Avoid false positives
         list(APPEND _picky "-Wno-shadow")
         list(APPEND _picky "-Wno-unreachable-code")
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.2 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.2 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
         # GCC <4.6 do not support #pragma to suppress warnings locally. Disable them globally instead.
         list(APPEND _picky "-Wno-overlength-strings")
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.0 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
         list(APPEND _picky "-Wno-missing-field-initializers")  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
       endif()
-      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.3 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
         list(APPEND _picky "-Wno-type-limits")  # Avoid false positives
       endif()
+      if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.1 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.5)
+        list(APPEND _picky "-Wno-conversion")  # Avoid false positives
+      endif()
+    endif()
+  elseif(MSVC AND MSVC_VERSION LESS_EQUAL 1943)  # Skip for untested/unreleased newer versions
+    list(APPEND _picky "-Wall")
+    list(APPEND _picky "-wd4061")  # enumerator 'A' in switch of enum 'B' is not explicitly handled by a case label
+    list(APPEND _picky "-wd4191")  # 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)(void)'
+    list(APPEND _picky "-wd4255")  # no function prototype given: converting '()' to '(void)' (in winuser.h)
+    list(APPEND _picky "-wd4464")  # relative include path contains '..'
+    list(APPEND _picky "-wd4548")  # expression before comma has no effect; expected expression with side-effect (in FD_SET())
+    list(APPEND _picky "-wd4574")  # 'M' is defined to be '0': did you mean to use '#if M'? (in ws2tcpip.h)
+    list(APPEND _picky "-wd4668")  # 'M' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' (in winbase.h)
+    list(APPEND _picky "-wd4710")  # 'snprintf': function not inlined
+    list(APPEND _picky "-wd4711")  # function 'A' selected for automatic inline expansion
+    list(APPEND _picky "-wd4746")  # volatile access of '<expression>' is subject to /volatile:<iso|ms> setting;
+                                   #   consider using __iso_volatile_load/store intrinsic functions (ARM64)
+    list(APPEND _picky "-wd4774")  # 'snprintf': format string expected in argument 3 is not a string literal
+    list(APPEND _picky "-wd4820")  # 'A': 'N' bytes padding added after data member 'B'
+    if(MSVC_VERSION GREATER_EQUAL 1900)
+      list(APPEND _picky "-wd5045")  # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
     endif()
   endif()
 endif()
@@ -260,20 +330,31 @@ endif()
 if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC)
   list(APPEND _picky "-Wno-language-extension-token")  # Allow __int64
 
-  set(_picky_tmp "")
-  foreach(_ccopt IN LISTS _picky)
-    # Prefix -Wall, otherwise clang-cl interprets it as an MSVC option and translates it to -Weverything
-    if(_ccopt MATCHES "^-W" AND NOT _ccopt STREQUAL "-Wall")
-      list(APPEND _picky_tmp ${_ccopt})
-    else()
-      list(APPEND _picky_tmp "-clang:${_ccopt}")
-    endif()
+  foreach(_wlist IN ITEMS _picky_nocheck _picky)
+    set(_picky_tmp "")
+    foreach(_ccopt IN LISTS "${_wlist}")
+      # Prefix -Wall, otherwise clang-cl interprets it as an MSVC option and translates it to -Weverything
+      if(_ccopt MATCHES "^-W" AND NOT _ccopt STREQUAL "-Wall")
+        list(APPEND _picky_tmp ${_ccopt})
+      else()
+        list(APPEND _picky_tmp "-clang:${_ccopt}")
+      endif()
+    endforeach()
+    set("${_wlist}" ${_picky_tmp})
   endforeach()
-  set(_picky ${_picky_tmp})
 endif()
 
-if(_picky)
-  string(REPLACE ";" " " _picky "${_picky}")
-  string(APPEND CMAKE_C_FLAGS " ${_picky}")
-  message(STATUS "Picky compiler options: ${_picky}")
+if(_picky_nocheck OR _picky)
+  set(_picky_tmp "${_picky_nocheck}" "${_picky}")
+  string(REPLACE ";" " " _picky_tmp "${_picky_tmp}")
+  string(STRIP "${_picky_tmp}" _picky_tmp)
+  message(STATUS "Picky compiler options: ${_picky_tmp}")
+  set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "${_picky_nocheck}" "${_picky}")
+
+  # Apply to all feature checks
+  string(REPLACE ";" " " _picky_tmp "${_picky}")
+  string(APPEND CMAKE_REQUIRED_FLAGS " ${_picky_tmp}")
+
+  unset(_picky)
+  unset(_picky_tmp)
 endif()

+ 5 - 4
Utilities/cmcurl/CMake/cmake_uninstall.cmake.in

@@ -35,10 +35,11 @@ string(REGEX REPLACE "\n" ";" _files "${_files}")
 foreach(_file ${_files})
   message(STATUS "Uninstalling $ENV{DESTDIR}${_file}")
   if(IS_SYMLINK "$ENV{DESTDIR}${_file}" OR EXISTS "$ENV{DESTDIR}${_file}")
-    exec_program(
-      "@CMAKE_COMMAND@" ARGS "-E rm -f \"$ENV{DESTDIR}${_file}\""
-      OUTPUT_VARIABLE rm_out
-      RETURN_VALUE rm_retval
+    execute_process(
+      COMMAND "@CMAKE_COMMAND@" -E rm -f "$ENV{DESTDIR}${_file}"
+      RESULT_VARIABLE rm_retval
+      OUTPUT_QUIET
+      ERROR_QUIET
     )
     if(NOT "${rm_retval}" STREQUAL 0)
       message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${_file}")

+ 11 - 4
Utilities/cmcurl/CMake/curl-config.cmake.in

@@ -25,7 +25,11 @@
 
 include(CMakeFindDependencyMacro)
 if("@USE_OPENSSL@")
-  find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
+  if("@OPENSSL_VERSION_MAJOR@")
+    find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
+  else()
+    find_dependency(OpenSSL)
+  endif()
 endif()
 if("@HAVE_LIBZ@")
   find_dependency(ZLIB "@ZLIB_VERSION_MAJOR@")
@@ -34,13 +38,16 @@ endif()
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 
 # Alias for either shared or static library
-if(NOT TARGET @PROJECT_NAME@::libcurl)
-  add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@)
+if(NOT TARGET @PROJECT_NAME@::@LIB_NAME@)
+  if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.11 AND CMAKE_VERSION VERSION_LESS 3.18)
+    set_target_properties(@PROJECT_NAME@::@LIB_SELECTED@ PROPERTIES IMPORTED_GLOBAL TRUE)
+  endif()
+  add_library(@PROJECT_NAME@::@LIB_NAME@ ALIAS @PROJECT_NAME@::@LIB_SELECTED@)
 endif()
 
 # For compatibility with CMake's FindCURL.cmake
 set(CURL_VERSION_STRING "@CURLVERSION@")
-set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
+set(CURL_LIBRARIES @PROJECT_NAME@::@LIB_NAME@)
 set_and_check(CURL_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
 
 set(CURL_SUPPORTED_PROTOCOLS "@CURL_SUPPORTED_PROTOCOLS_LIST@")

+ 316 - 0
Utilities/cmcurl/CMake/unix-cache.cmake

@@ -0,0 +1,316 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <[email protected]>, 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
+#
+###########################################################################
+# Based on CI runs for Cygwin/MSYS2, Linux, macOS, FreeBSD, NetBSD, OpenBSD
+if(NOT UNIX)
+  message(FATAL_ERROR "This file should be included on Unix platforms only")
+endif()
+
+if(APPLE OR
+   CYGWIN)
+  set(HAVE_ACCEPT4 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_ACCEPT4 1)
+endif()
+set(HAVE_ALARM 1)
+if(ANDROID)
+  set(HAVE_ARC4RANDOM 1)
+else()
+  set(HAVE_ARC4RANDOM 0)
+endif()
+set(HAVE_ARPA_INET_H 1)
+set(HAVE_ATOMIC 1)
+set(HAVE_BASENAME 1)
+set(HAVE_BOOL_T 1)
+if(NOT APPLE)
+  set(HAVE_CLOCK_GETTIME_MONOTONIC 1)
+  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    set(HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1)
+  else()
+    set(HAVE_CLOCK_GETTIME_MONOTONIC_RAW 0)
+  endif()
+endif()
+set(HAVE_CLOSESOCKET 0)
+set(HAVE_DECL_FSEEKO 1)
+set(HAVE_DIRENT_H 1)
+if(APPLE OR
+   CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_EVENTFD 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+  set(HAVE_EVENTFD 1)
+endif()
+set(HAVE_FCNTL 1)
+set(HAVE_FCNTL_H 1)
+set(HAVE_FCNTL_O_NONBLOCK 1)
+set(HAVE_FILE_OFFSET_BITS 1)
+set(HAVE_FNMATCH 1)
+set(HAVE_FREEADDRINFO 1)
+set(HAVE_FSEEKO 1)
+if(APPLE)
+  set(HAVE_FSETXATTR 1)
+  set(HAVE_FSETXATTR_5 0)
+  set(HAVE_FSETXATTR_6 1)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_FSETXATTR 0)
+  set(HAVE_FSETXATTR_5 0)
+  set(HAVE_FSETXATTR_6 0)
+elseif(CYGWIN OR
+       CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+  set(HAVE_FSETXATTR 1)
+  set(HAVE_FSETXATTR_5 1)
+  set(HAVE_FSETXATTR_6 0)
+endif()
+set(HAVE_FTRUNCATE 1)
+set(HAVE_GETADDRINFO 1)
+if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_GETADDRINFO_THREADSAFE 0)
+elseif(CYGWIN OR
+       CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+  set(HAVE_GETADDRINFO_THREADSAFE 1)
+endif()
+set(HAVE_GETEUID 1)
+if(APPLE OR
+   CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
+   CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_GETHOSTBYNAME_R 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+  set(HAVE_GETHOSTBYNAME_R 1)
+endif()
+set(HAVE_GETHOSTBYNAME_R_3 0)
+set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
+set(HAVE_GETHOSTBYNAME_R_5 0)
+set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_GETHOSTBYNAME_R_6 1)
+  set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 1)
+else()
+  set(HAVE_GETHOSTBYNAME_R_6 0)
+  set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
+endif()
+set(HAVE_GETHOSTNAME 1)
+if(NOT ANDROID OR ANDROID_PLATFORM_LEVEL GREATER_EQUAL 24)
+  set(HAVE_GETIFADDRS 1)
+else()
+  set(HAVE_GETIFADDRS 0)
+endif()
+if(APPLE OR
+   CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+   CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+   CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_GETPASS_R 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+  set(HAVE_GETPASS_R 1)
+endif()
+set(HAVE_GETPEERNAME 1)
+set(HAVE_GETPPID 1)
+set(HAVE_GETPWUID 1)
+set(HAVE_GETPWUID_R 1)
+set(HAVE_GETRLIMIT 1)
+set(HAVE_GETSOCKNAME 1)
+set(HAVE_GETTIMEOFDAY 1)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_GLIBC_STRERROR_R 1)
+else()
+  set(HAVE_GLIBC_STRERROR_R 0)
+endif()
+set(HAVE_GMTIME_R 1)
+set(HAVE_IFADDRS_H 1)
+set(HAVE_IF_NAMETOINDEX 1)
+set(HAVE_INET_NTOP 1)
+set(HAVE_INET_PTON 1)
+set(HAVE_IOCTLSOCKET 0)
+set(HAVE_IOCTLSOCKET_CAMEL 0)
+set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
+set(HAVE_IOCTLSOCKET_FIONBIO 0)
+set(HAVE_IOCTL_FIONBIO 1)
+set(HAVE_IOCTL_SIOCGIFADDR 1)
+if(CYGWIN)
+  set(HAVE_IO_H 1)
+else()
+  set(HAVE_IO_H 0)
+endif()
+set(HAVE_LIBGEN_H 1)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_LINUX_TCP_H 1)
+else()
+  set(HAVE_LINUX_TCP_H 0)
+endif()
+set(HAVE_LOCALE_H 1)
+set(HAVE_LONGLONG 1)
+if(APPLE)
+  set(HAVE_MACH_ABSOLUTE_TIME 1)
+endif()
+if(APPLE OR
+   CYGWIN)
+  set(HAVE_MEMRCHR 0)
+else()
+  set(HAVE_MEMRCHR 1)
+endif()
+set(HAVE_MSG_NOSIGNAL 1)
+set(HAVE_NETDB_H 1)
+if(ANDROID)
+  set(HAVE_NETINET_IN6_H 1)
+else()
+  set(HAVE_NETINET_IN6_H 0)
+endif()
+set(HAVE_NETINET_IN_H 1)
+set(HAVE_NETINET_TCP_H 1)
+set(HAVE_NETINET_UDP_H 1)
+set(HAVE_NET_IF_H 1)
+set(HAVE_OPENDIR 1)
+set(HAVE_PIPE 1)
+if(APPLE OR
+   CYGWIN)
+  set(HAVE_PIPE2 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_PIPE2 1)
+endif()
+set(HAVE_POLL 1)
+set(HAVE_POLL_H 1)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_POSIX_STRERROR_R 0)
+else()
+  set(HAVE_POSIX_STRERROR_R 1)
+endif()
+set(HAVE_PWD_H 1)
+set(HAVE_REALPATH 1)
+set(HAVE_RECV 1)
+set(HAVE_SA_FAMILY_T 1)
+set(HAVE_SCHED_YIELD 1)
+set(HAVE_SELECT 1)
+set(HAVE_SEND 1)
+if(APPLE OR
+   CYGWIN)
+  set(HAVE_SENDMMSG 0)
+else()
+  set(HAVE_SENDMMSG 1)
+endif()
+set(HAVE_SENDMSG 1)
+set(HAVE_SETLOCALE 1)
+if(CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_SETMODE 0)
+else()
+  set(HAVE_SETMODE 1)
+endif()
+set(HAVE_SETRLIMIT 1)
+set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
+set(HAVE_SIGACTION 1)
+set(HAVE_SIGINTERRUPT 1)
+set(HAVE_SIGNAL 1)
+set(HAVE_SIGSETJMP 1)
+set(HAVE_SNPRINTF 1)
+set(HAVE_SOCKADDR_IN6_SIN6_ADDR 1)
+set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1)
+set(HAVE_SOCKET 1)
+set(HAVE_SOCKETPAIR 1)
+set(HAVE_STDATOMIC_H 1)
+set(HAVE_STDBOOL_H 1)
+set(HAVE_STDDEF_H 1)
+set(HAVE_STDINT_H 1)
+set(HAVE_STRCASECMP 1)
+set(HAVE_STRCMPI 0)
+set(HAVE_STRDUP 1)
+set(HAVE_STRERROR_R 1)
+set(HAVE_STRICMP 0)
+set(HAVE_STRINGS_H 1)
+if(_CURL_OLD_LINUX)
+  set(HAVE_STROPTS_H 1)
+else()
+  set(HAVE_STROPTS_H 0)  # glibc 2.30 or newer. https://sourceware.org/legacy-ml/libc-alpha/2019-08/msg00029.html
+endif()
+set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+set(HAVE_STRUCT_TIMEVAL 1)
+if(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
+  set(HAVE_SUSECONDS_T 1)
+endif()
+if(APPLE OR
+   CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_SYS_EVENTFD_H 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+  set(HAVE_SYS_EVENTFD_H 1)
+endif()
+if(CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_SYS_FILIO_H 0)
+else()
+  set(HAVE_SYS_FILIO_H 1)
+endif()
+set(HAVE_SYS_IOCTL_H 1)
+set(HAVE_SYS_PARAM_H 1)
+set(HAVE_SYS_POLL_H 1)
+set(HAVE_SYS_RESOURCE_H 1)
+set(HAVE_SYS_SELECT_H 1)
+set(HAVE_SYS_SOCKET_H 1)
+if(CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_SYS_SOCKIO_H 0)
+else()
+  set(HAVE_SYS_SOCKIO_H 1)
+endif()
+set(HAVE_SYS_STAT_H 1)
+set(HAVE_SYS_TIME_H 1)
+set(HAVE_SYS_TYPES_H 1)
+set(HAVE_SYS_UN_H 1)
+if(CYGWIN)
+  set(HAVE_SYS_UTIME_H 1)
+else()
+  set(HAVE_SYS_UTIME_H 0)
+endif()
+set(HAVE_TERMIOS_H 1)
+if(CYGWIN OR
+   CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(HAVE_TERMIO_H 1)
+else()
+  set(HAVE_TERMIO_H 0)
+endif()
+set(HAVE_TIME_T_UNSIGNED 0)
+set(HAVE_UNISTD_H 1)
+set(HAVE_UTIME 1)
+set(HAVE_UTIMES 1)
+set(HAVE_UTIME_H 1)
+set(HAVE_WRITABLE_ARGV 1)
+if(CYGWIN)
+  set(HAVE__SETMODE 1)
+endif()
+set(STDC_HEADERS 1)
+set(USE_UNIX_SOCKETS 1)

+ 149 - 109
Utilities/cmcurl/CMake/win32-cache.cmake

@@ -25,55 +25,36 @@ if(NOT WIN32)
   message(FATAL_ERROR "This file should be included on Windows platform only")
 endif()
 
-set(HAVE_LOCALE_H 1)
-
 if(MINGW)
-  set(HAVE_SNPRINTF 1)
-  set(HAVE_UNISTD_H 1)
+  set(HAVE_BASENAME 1)
+  set(HAVE_BOOL_T 1)  # = HAVE_STDBOOL_H
+  set(HAVE_DIRENT_H 1)
+  set(HAVE_FTRUNCATE 1)
+  set(HAVE_GETTIMEOFDAY 1)
   set(HAVE_LIBGEN_H 1)
+  set(HAVE_OPENDIR 1)
+  set(HAVE_SNPRINTF 1)
+  set(HAVE_STDBOOL_H 1)
   set(HAVE_STDDEF_H 1)  # detected by CMake internally in check_type_size()
   set(HAVE_STDINT_H 1)  # detected by CMake internally in check_type_size()
-  set(HAVE_STDBOOL_H 1)
-  set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
-  set(HAVE_STRTOLL 1)
-  set(HAVE_BASENAME 1)
-  set(HAVE_FTRUNCATE 1)
+  set(HAVE_STRINGS_H 1)  # wrapper to string.h
   set(HAVE_SYS_PARAM_H 1)
   set(HAVE_SYS_TIME_H 1)
-  set(HAVE_GETTIMEOFDAY 1)
-  set(HAVE_STRINGS_H 1)  # wrapper to string.h
+  set(HAVE_UNISTD_H 1)
   set(HAVE_UTIME_H 1)  # wrapper to sys/utime.h
-  set(HAVE_DIRENT_H 1)
-  set(HAVE_OPENDIR 1)
-  if(MINGW64_VERSION)
-    if(NOT MINGW64_VERSION VERSION_LESS 4.0)
-      set(HAVE_STRTOK_R 1)
-    else()
-      set(HAVE_STRTOK_R 0)
-    endif()
-  endif()
-  if((CMAKE_COMPILER_IS_GNUCC              AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) OR
-     (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6))
-    set(HAVE_STDATOMIC_H 1)
-    set(HAVE_ATOMIC 1)
-  else()
-    set(HAVE_STDATOMIC_H 0)
-    set(HAVE_ATOMIC 0)
-  endif()
 else()
-  set(HAVE_LIBGEN_H 0)
+  set(HAVE_DIRENT_H 0)
   set(HAVE_FTRUNCATE 0)
-  set(HAVE_SYS_PARAM_H 0)
-  set(HAVE_SYS_TIME_H 0)
   set(HAVE_GETTIMEOFDAY 0)
+  set(HAVE_LIBGEN_H 0)
+  set(HAVE_OPENDIR 0)
   set(HAVE_STRINGS_H 0)
+  set(HAVE_SYS_PARAM_H 0)
+  set(HAVE_SYS_TIME_H 0)
   set(HAVE_UTIME_H 0)
-  set(HAVE_DIRENT_H 0)
-  set(HAVE_OPENDIR 0)
   if(MSVC)
     set(HAVE_UNISTD_H 0)
     set(HAVE_STDDEF_H 1)  # detected by CMake internally in check_type_size()
-    set(HAVE_STDATOMIC_H 0)
     if(MSVC_VERSION GREATER_EQUAL 1600)
       set(HAVE_STDINT_H 1)  # detected by CMake internally in check_type_size()
     else()
@@ -81,10 +62,8 @@ else()
     endif()
     if(MSVC_VERSION GREATER_EQUAL 1800)
       set(HAVE_STDBOOL_H 1)
-      set(HAVE_STRTOLL 1)
     else()
       set(HAVE_STDBOOL_H 0)
-      set(HAVE_STRTOLL 0)
     endif()
     set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
     if(MSVC_VERSION GREATER_EQUAL 1900)
@@ -93,58 +72,99 @@ else()
       set(HAVE_SNPRINTF 0)
     endif()
     set(HAVE_BASENAME 0)
-    set(HAVE_STRTOK_R 0)
-    set(HAVE_FILE_OFFSET_BITS 0)
-    set(HAVE_ATOMIC 0)
   endif()
 endif()
 
-# Available in Windows XP and newer
-set(HAVE_GETADDRINFO 1)
-set(HAVE_FREEADDRINFO 1)
+if((CMAKE_C_COMPILER_ID STREQUAL "GNU"   AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.9) OR
+   (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6))
+  # MinGW or clang-cl
+  set(HAVE_STDATOMIC_H 1)
+  set(HAVE_ATOMIC 1)
+else()
+  set(HAVE_STDATOMIC_H 0)
+  set(HAVE_ATOMIC 0)
+endif()
 
-set(HAVE_SOCKETPAIR 0)
-set(HAVE_SENDMSG 0)
-set(HAVE_SENDMMSG 0)
+set(HAVE_ACCEPT4 0)
 set(HAVE_ALARM 0)
+set(HAVE_ARC4RANDOM 0)
+set(HAVE_ARPA_INET_H 0)
+set(HAVE_CLOSESOCKET 1)
+set(HAVE_EVENTFD 0)
 set(HAVE_FCNTL 0)
+set(HAVE_FCNTL_H 1)
+set(HAVE_FCNTL_O_NONBLOCK 0)
+set(HAVE_FNMATCH 0)
+set(HAVE_FREEADDRINFO 1)  # Available in Windows XP and newer
+set(HAVE_FSETXATTR 0)
+set(HAVE_GETADDRINFO 1)  # Available in Windows XP and newer
+set(HAVE_GETEUID 0)
+set(HAVE_GETHOSTBYNAME_R 0)
+set(HAVE_GETHOSTBYNAME_R_3 0)
+set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
+set(HAVE_GETHOSTBYNAME_R_5 0)
+set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
+set(HAVE_GETHOSTBYNAME_R_6 0)
+set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
+set(HAVE_GETHOSTNAME 1)
+set(HAVE_GETIFADDRS 0)
+set(HAVE_GETPASS_R 0)
+set(HAVE_GETPEERNAME 1)
 set(HAVE_GETPPID 0)
-set(HAVE_UTIMES 0)
+set(HAVE_GETPWUID 0)
 set(HAVE_GETPWUID_R 0)
-set(HAVE_STRERROR_R 0)
-set(HAVE_SIGINTERRUPT 0)
-set(HAVE_PIPE 0)
-set(HAVE_EVENTFD 0)
-set(HAVE_IF_NAMETOINDEX 0)
 set(HAVE_GETRLIMIT 0)
-set(HAVE_SETRLIMIT 0)
-set(HAVE_FSETXATTR 0)
-set(HAVE_SETLOCALE 1)
-set(HAVE_SETMODE 1)
-set(HAVE__SETMODE 1)
-set(HAVE_GETPEERNAME 1)
 set(HAVE_GETSOCKNAME 1)
-set(HAVE_GETHOSTNAME 1)
-
-set(HAVE_RECV 1)
-set(HAVE_SEND 1)
-set(HAVE_STROPTS_H 0)
-set(HAVE_ARC4RANDOM 0)
-set(HAVE_FNMATCH 0)
-set(HAVE_ARPA_INET_H 0)
-set(HAVE_FCNTL_H 1)
+set(HAVE_GLIBC_STRERROR_R 0)
+set(HAVE_GMTIME_R 0)
 set(HAVE_IFADDRS_H 0)
+set(HAVE_IF_NAMETOINDEX 0)
+set(HAVE_INET_NTOP 0)
+set(HAVE_INET_PTON 0)
+set(HAVE_IOCTLSOCKET 1)
+set(HAVE_IOCTLSOCKET_CAMEL 0)
+set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
+set(HAVE_IOCTLSOCKET_FIONBIO 1)
+set(HAVE_IOCTL_FIONBIO 0)
+set(HAVE_IOCTL_SIOCGIFADDR 0)
 set(HAVE_IO_H 1)
+set(HAVE_LINUX_TCP_H 0)
+set(HAVE_LOCALE_H 1)
+set(HAVE_MEMRCHR 0)
+set(HAVE_MSG_NOSIGNAL 0)
 set(HAVE_NETDB_H 0)
-set(HAVE_NETINET_IN_H 0)
 set(HAVE_NETINET_IN6_H 0)
+set(HAVE_NETINET_IN_H 0)
 set(HAVE_NETINET_TCP_H 0)
 set(HAVE_NETINET_UDP_H 0)
 set(HAVE_NET_IF_H 0)
-set(HAVE_IOCTL_SIOCGIFADDR 0)
-set(HAVE_POLL_H 0)
+set(HAVE_PIPE 0)
+set(HAVE_PIPE2 0)
 set(HAVE_POLL 0)
+set(HAVE_POLL_H 0)
+set(HAVE_POSIX_STRERROR_R 0)
 set(HAVE_PWD_H 0)
+set(HAVE_RECV 1)
+set(HAVE_SELECT 1)
+set(HAVE_SEND 1)
+set(HAVE_SENDMMSG 0)
+set(HAVE_SENDMSG 0)
+set(HAVE_SETLOCALE 1)
+set(HAVE_SETMODE 1)
+set(HAVE_SETRLIMIT 0)
+set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
+set(HAVE_SIGACTION 0)
+set(HAVE_SIGINTERRUPT 0)
+set(HAVE_SIGNAL 1)
+set(HAVE_SIGSETJMP 0)
+set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1)
+set(HAVE_SOCKET 1)
+set(HAVE_SOCKETPAIR 0)
+set(HAVE_STRDUP 1)
+set(HAVE_STRERROR_R 0)
+set(HAVE_STROPTS_H 0)
+set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+set(HAVE_STRUCT_TIMEVAL 1)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
 set(HAVE_SYS_IOCTL_H 0)
@@ -159,47 +179,67 @@ set(HAVE_SYS_UN_H 0)
 set(HAVE_SYS_UTIME_H 1)
 set(HAVE_TERMIOS_H 0)
 set(HAVE_TERMIO_H 0)
-set(HAVE_LINUX_TCP_H 0)
-
-set(HAVE_SOCKET 1)
-set(HAVE_SELECT 1)
-set(HAVE_STRDUP 1)
-set(HAVE_MEMRCHR 0)
-set(HAVE_CLOSESOCKET 1)
-set(HAVE_SIGSETJMP 0)
-set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1)
-set(HAVE_GETPASS_R 0)
-set(HAVE_GETPWUID 0)
-set(HAVE_GETEUID 0)
-set(HAVE_UTIME 1)
-set(HAVE_GMTIME_R 0)
-set(HAVE_GETHOSTBYNAME_R 0)
-set(HAVE_SIGNAL 1)
-set(HAVE_SIGACTION 0)
-set(HAVE_GLIBC_STRERROR_R 0)
-set(HAVE_GETIFADDRS 0)
-set(HAVE_FCNTL_O_NONBLOCK 0)
-set(HAVE_IOCTLSOCKET 1)
-set(HAVE_IOCTLSOCKET_CAMEL 0)
-set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
-set(HAVE_IOCTLSOCKET_FIONBIO 1)
-set(HAVE_IOCTL_FIONBIO 0)
-set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
-set(HAVE_POSIX_STRERROR_R 0)
-set(HAVE_MSG_NOSIGNAL 0)
-set(HAVE_STRUCT_TIMEVAL 1)
-set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
 set(HAVE_TIME_T_UNSIGNED 0)
-
-set(HAVE_GETHOSTBYNAME_R_3 0)
-set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
-set(HAVE_GETHOSTBYNAME_R_5 0)
-set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
-set(HAVE_GETHOSTBYNAME_R_6 0)
-set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
-
-set(HAVE_IN_ADDR_T 0)
+set(HAVE_UTIME 1)
+set(HAVE_UTIMES 0)
+set(HAVE__SETMODE 1)
 set(STDC_HEADERS 1)
 
-set(HAVE_SIZEOF_SUSECONDS_T 0)
+# Types and sizes
+
 set(HAVE_SIZEOF_SA_FAMILY_T 0)
+set(HAVE_SIZEOF_SUSECONDS_T 0)
+
+if(MINGW OR MSVC)
+  curl_prefill_type_size("INT" 4)
+  curl_prefill_type_size("LONG" 4)
+  curl_prefill_type_size("LONG_LONG" 8)
+  curl_prefill_type_size("__INT64" 8)
+  curl_prefill_type_size("CURL_OFF_T" 8)
+  # CURL_SOCKET_T, SIZE_T: 8 for _WIN64, 4 otherwise
+  # TIME_T: 8 for _WIN64 or UCRT or MSVC and not Windows CE, 4 otherwise
+  #   Also 4 for non-UCRT 32-bit when _USE_32BIT_TIME_T is set.
+  #   mingw-w64 sets _USE_32BIT_TIME_T unless __MINGW_USE_VC2005_COMPAT is explicit defined.
+  if(MSVC)
+    set(HAVE_SIZEOF_SSIZE_T 0)
+    set(HAVE_FILE_OFFSET_BITS 0)
+    curl_prefill_type_size("OFF_T" 4)
+    curl_prefill_type_size("ADDRESS_FAMILY" 2)
+  else()
+    # SSIZE_T: 8 for _WIN64, 4 otherwise
+    if(MINGW64_VERSION)
+      if(MINGW64_VERSION VERSION_GREATER_EQUAL 3.0)
+        set(HAVE_FILE_OFFSET_BITS 1)
+        curl_prefill_type_size("OFF_T" 8)
+      endif()
+      if(MINGW64_VERSION VERSION_GREATER_EQUAL 2.0)
+        curl_prefill_type_size("ADDRESS_FAMILY" 2)
+      else()
+        set(HAVE_SIZEOF_ADDRESS_FAMILY 0)
+      endif()
+    endif()
+  endif()
+endif()
+
+# Windows CE exceptions
+
+if(WINCE)
+  set(HAVE_FREEADDRINFO 0)
+  set(HAVE_GETADDRINFO 0)
+  set(HAVE_LOCALE_H 0)
+  set(HAVE_SETLOCALE 0)
+  set(HAVE_SETMODE 0)
+  set(HAVE_SIGNAL 0)
+  set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 0)
+  curl_prefill_type_size("CURL_SOCKET_T" 4)
+  curl_prefill_type_size("TIME_T" 4)
+  curl_prefill_type_size("SIZE_T" 4)
+  if(MINGW32CE)
+    set(HAVE_STRTOK_R 0)
+    set(HAVE__SETMODE 0)
+    set(HAVE_FILE_OFFSET_BITS 0)
+    set(HAVE_SIZEOF_ADDRESS_FAMILY 0)
+    curl_prefill_type_size("SSIZE_T" 4)
+    curl_prefill_type_size("OFF_T" 4)
+  endif()
+endif()

Diferenças do arquivo suprimidas por serem muito extensas
+ 265 - 234
Utilities/cmcurl/CMakeLists.txt


+ 116 - 80
Utilities/cmcurl/include/curl/curl.h

@@ -42,7 +42,7 @@
   !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
 #define CURL_DEPRECATED(version, message)                       \
   __attribute__((deprecated("since " # version ". " message)))
-#if defined(__IAR_SYSTEMS_ICC__)
+#ifdef __IAR_SYSTEMS_ICC__
 #define CURL_IGNORE_DEPRECATION(statements) \
       _Pragma("diag_suppress=Pe1444") \
       statements \
@@ -97,19 +97,11 @@
 #include <sys/select.h>
 #endif
 
-#if !defined(_WIN32) && !defined(_WIN32_WCE)
+#ifndef _WIN32
 #include <sys/socket.h>
-#endif
-
-#if !defined(_WIN32)
 #include <sys/time.h>
 #endif
 
-/* Compatibility for non-Clang compilers */
-#ifndef __has_declspec_attribute
-#  define __has_declspec_attribute(x) 0
-#endif
-
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -121,11 +113,17 @@ typedef void CURLSH;
  * libcurl external API function linkage decorations.
  */
 
+#ifdef __has_declspec_attribute
+#define CURL_HAS_DECLSPEC_ATTRIBUTE(x) __has_declspec_attribute(x)
+#else
+#define CURL_HAS_DECLSPEC_ATTRIBUTE(x) 0
+#endif
+
 #ifdef CURL_STATICLIB
 #  define CURL_EXTERN
 #elif defined(_WIN32) || \
-     (__has_declspec_attribute(dllexport) && \
-      __has_declspec_attribute(dllimport))
+     (CURL_HAS_DECLSPEC_ATTRIBUTE(dllexport) && \
+      CURL_HAS_DECLSPEC_ATTRIBUTE(dllimport))
 #  if defined(BUILDING_LIBCURL)
 #    define CURL_EXTERN  __declspec(dllexport)
 #  else
@@ -177,6 +175,16 @@ typedef enum {
 #define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
 #define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT
 
+/* bits for the CURLOPT_FOLLOWLOCATION option */
+#define CURLFOLLOW_ALL       1L /* generic follow redirects */
+
+/* Do not use the custom method in the follow-up request if the HTTP code
+   instructs so (301, 302, 303). */
+#define CURLFOLLOW_OBEYCODE  2L
+
+/* Only use the custom method in the first request, always reset in the next */
+#define CURLFOLLOW_FIRSTONLY 3L
+
 struct curl_httppost {
   struct curl_httppost *next;       /* next entry in the list */
   char *name;                       /* pointer to allocated name */
@@ -637,7 +645,20 @@ typedef enum {
   CURLE_UNRECOVERABLE_POLL,      /* 99 - poll/select returned fatal error */
   CURLE_TOO_LARGE,               /* 100 - a value/data met its maximum */
   CURLE_ECH_REQUIRED,            /* 101 - ECH tried but failed */
-  CURL_LAST /* never use! */
+  CURL_LAST, /* never use! */
+
+  CURLE_RESERVED115 = 115,       /* 115-126 - used in tests */
+  CURLE_RESERVED116 = 116,
+  CURLE_RESERVED117 = 117,
+  CURLE_RESERVED118 = 118,
+  CURLE_RESERVED119 = 119,
+  CURLE_RESERVED120 = 120,
+  CURLE_RESERVED121 = 121,
+  CURLE_RESERVED122 = 122,
+  CURLE_RESERVED123 = 123,
+  CURLE_RESERVED124 = 124,
+  CURLE_RESERVED125 = 125,
+  CURLE_RESERVED126 = 126
 } CURLcode;
 
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
@@ -906,12 +927,13 @@ typedef int
 
 
 /* parameter for the CURLOPT_USE_SSL option */
+#define CURLUSESSL_NONE    0L /* do not attempt to use SSL */
+#define CURLUSESSL_TRY     1L /* try using SSL, proceed anyway otherwise */
+#define CURLUSESSL_CONTROL 2L /* SSL for the control connection or fail */
+#define CURLUSESSL_ALL     3L /* SSL for all communication or fail */
+
 typedef enum {
-  CURLUSESSL_NONE,    /* do not attempt to use SSL */
-  CURLUSESSL_TRY,     /* try using SSL, proceed anyway otherwise */
-  CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
-  CURLUSESSL_ALL,     /* SSL for all communication or fail */
-  CURLUSESSL_LAST     /* not an option, never use */
+  CURLUSESSL_LAST = 4 /* not an option, never use */
 } curl_usessl;
 
 /* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
@@ -1015,6 +1037,12 @@ typedef enum {
 #define CURLALTSVC_H2           (1<<4)
 #define CURLALTSVC_H3           (1<<5)
 
+/* bitmask values for CURLOPT_UPLOAD_FLAGS */
+#define CURLULFLAG_ANSWERED (1L<<0)
+#define CURLULFLAG_DELETED  (1L<<1)
+#define CURLULFLAG_DRAFT    (1L<<2)
+#define CURLULFLAG_FLAGGED  (1L<<3)
+#define CURLULFLAG_SEEN     (1L<<4)
 
 struct curl_hstsentry {
   char *name;
@@ -2228,6 +2256,11 @@ typedef enum {
   /* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
   CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),
 
+  CURLOPT(CURLOPT_UPLOAD_FLAGS, CURLOPTTYPE_LONG, 327),
+
+  /* set TLS supported signature algorithms */
+  CURLOPT(CURLOPT_SSL_SIGNATURE_ALGORITHMS, CURLOPTTYPE_STRINGPOINT, 328),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -2276,26 +2309,25 @@ typedef enum {
   /* Convenient "aliases" */
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 
-  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
-enum {
-  CURL_HTTP_VERSION_NONE, /* setting this means we do not care, and that we
-                             would like the library to choose the best
-                             possible for us! */
-  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
-  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
-  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
-  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
-  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
-                                           Upgrade */
-  CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if
-                               needed. For HTTPS only. For HTTP, this option
-                               makes libcurl return error. */
-  CURL_HTTP_VERSION_3ONLY = 31, /* Use HTTP/3 without fallback. For HTTPS
-                                   only. For HTTP, this makes libcurl
-                                   return error. */
-
-  CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
-};
+/* These constants are for use with the CURLOPT_HTTP_VERSION option. */
+#define CURL_HTTP_VERSION_NONE  0L /* setting this means we do not care, and
+                                      that we would like the library to choose
+                                      the best possible for us! */
+#define CURL_HTTP_VERSION_1_0   1L /* please use HTTP 1.0 in the request */
+#define CURL_HTTP_VERSION_1_1   2L /* please use HTTP 1.1 in the request */
+#define CURL_HTTP_VERSION_2_0   3L /* please use HTTP 2 in the request */
+#define CURL_HTTP_VERSION_2TLS  4L /* use version 2 for HTTPS, version 1.1 for
+                                      HTTP */
+#define CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE 5L /* please use HTTP 2 without
+                                                  HTTP/1.1 Upgrade */
+#define CURL_HTTP_VERSION_3     30L /* Use HTTP/3, fallback to HTTP/2 or
+                                       HTTP/1 if needed. For HTTPS only. For
+                                       HTTP, this option makes libcurl
+                                       return error. */
+#define CURL_HTTP_VERSION_3ONLY 31L /* Use HTTP/3 without fallback. For
+                                       HTTPS only. For HTTP, this makes
+                                       libcurl return error. */
+#define CURL_HTTP_VERSION_LAST  32L /* *ILLEGAL* http version */
 
 /* Convenience definition simple because the name of the version is HTTP/2 and
    not 2.0. The 2_0 version of the enum name was set while the version was
@@ -2305,32 +2337,33 @@ enum {
 /*
  * Public API enums for RTSP requests
  */
-enum {
-    CURL_RTSPREQ_NONE, /* first in list */
-    CURL_RTSPREQ_OPTIONS,
-    CURL_RTSPREQ_DESCRIBE,
-    CURL_RTSPREQ_ANNOUNCE,
-    CURL_RTSPREQ_SETUP,
-    CURL_RTSPREQ_PLAY,
-    CURL_RTSPREQ_PAUSE,
-    CURL_RTSPREQ_TEARDOWN,
-    CURL_RTSPREQ_GET_PARAMETER,
-    CURL_RTSPREQ_SET_PARAMETER,
-    CURL_RTSPREQ_RECORD,
-    CURL_RTSPREQ_RECEIVE,
-    CURL_RTSPREQ_LAST /* last in list */
-};
+
+#define CURL_RTSPREQ_NONE          0L
+#define CURL_RTSPREQ_OPTIONS       1L
+#define CURL_RTSPREQ_DESCRIBE      2L
+#define CURL_RTSPREQ_ANNOUNCE      3L
+#define CURL_RTSPREQ_SETUP         4L
+#define CURL_RTSPREQ_PLAY          5L
+#define CURL_RTSPREQ_PAUSE         6L
+#define CURL_RTSPREQ_TEARDOWN      7L
+#define CURL_RTSPREQ_GET_PARAMETER 8L
+#define CURL_RTSPREQ_SET_PARAMETER 9L
+#define CURL_RTSPREQ_RECORD        10L
+#define CURL_RTSPREQ_RECEIVE       11L
+#define CURL_RTSPREQ_LAST          12L /* not used */
 
   /* These enums are for use with the CURLOPT_NETRC option. */
+#define CURL_NETRC_IGNORED  0L /* The .netrc will never be read.
+                                  This is the default. */
+#define CURL_NETRC_OPTIONAL 1L /* A user:password in the URL will be preferred
+                                  to one in the .netrc. */
+#define CURL_NETRC_REQUIRED 2L /* A user:password in the URL will be ignored.
+                                  Unless one is set programmatically, the
+                                  .netrc will be queried. */
 enum CURL_NETRC_OPTION {
-  CURL_NETRC_IGNORED,     /* The .netrc will never be read.
-                           * This is the default. */
-  CURL_NETRC_OPTIONAL,    /* A user:password in the URL will be preferred
-                           * to one in the .netrc. */
-  CURL_NETRC_REQUIRED,    /* A user:password in the URL will be ignored.
-                           * Unless one is set programmatically, the .netrc
-                           * will be queried. */
-  CURL_NETRC_LAST
+  /* we set a single member here, just to make sure we still provide the enum,
+     but the values to use are defined above with L suffixes */
+  CURL_NETRC_LAST = 3
 };
 
 #define CURL_SSLVERSION_DEFAULT 0
@@ -2354,10 +2387,13 @@ enum CURL_NETRC_OPTION {
   /* never use, keep last */
 #define CURL_SSLVERSION_MAX_LAST    (CURL_SSLVERSION_LAST    << 16)
 
+#define CURL_TLSAUTH_NONE 0L
+#define CURL_TLSAUTH_SRP  1L
+
 enum CURL_TLSAUTH {
-  CURL_TLSAUTH_NONE,
-  CURL_TLSAUTH_SRP,
-  CURL_TLSAUTH_LAST /* never use, keep last */
+  /* we set a single member here, just to make sure we still provide the enum,
+     but the values to use are defined above with L suffixes */
+  CURL_TLSAUTH_LAST = 2
 };
 
 /* symbols to use with CURLOPT_POSTREDIR.
@@ -2372,14 +2408,16 @@ enum CURL_TLSAUTH {
 #define CURL_REDIR_POST_ALL \
     (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
 
-typedef enum {
-  CURL_TIMECOND_NONE,
-
-  CURL_TIMECOND_IFMODSINCE,
-  CURL_TIMECOND_IFUNMODSINCE,
-  CURL_TIMECOND_LASTMOD,
+#define CURL_TIMECOND_NONE         0L
+#define CURL_TIMECOND_IFMODSINCE   1L
+#define CURL_TIMECOND_IFUNMODSINCE 2L
+#define CURL_TIMECOND_LASTMOD      3L
 
-  CURL_TIMECOND_LAST
+typedef enum {
+  /* we set a single member here, just to make sure we still provide
+     the enum typedef, but the values to use are defined above with L
+     suffixes */
+  CURL_TIMECOND_LAST = 4
 } curl_TimeCond;
 
 /* Special size_t value signaling a null-terminated string. */
@@ -2775,17 +2813,17 @@ struct curl_slist {
  * *before* curl_global_init().
  *
  * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The
- * backend can also be specified via the name parameter (passing -1 as id).
- * If both id and name are specified, the name will be ignored. If neither id
- * nor name are specified, the function will fail with
- * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the
- * NULL-terminated list of available backends.
+ * backend can also be specified via the name parameter (passing -1 as id). If
+ * both id and name are specified, the name will be ignored. If neither id nor
+ * name are specified, the function will fail with CURLSSLSET_UNKNOWN_BACKEND
+ * and set the "avail" pointer to the NULL-terminated list of available
+ * backends.
  *
  * Upon success, the function returns CURLSSLSET_OK.
  *
  * If the specified SSL backend is not available, the function returns
- * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated
- * list of available SSL backends.
+ * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a
+ * NULL-terminated list of available SSL backends.
  *
  * The SSL backend can be set only once. If it has already been set, a
  * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE.
@@ -3288,9 +3326,7 @@ CURL_EXTERN CURLcode curl_easy_ssls_export(CURL *handle,
 #include "options.h"
 #include "header.h"
 #include "websockets.h"
-#ifndef CURL_SKIP_INCLUDE_MPRINTF
 #include "mprintf.h"
-#endif
 
 /* the typechecker does not work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \

+ 3 - 3
Utilities/cmcurl/include/curl/curlver.h

@@ -32,12 +32,12 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "8.12.1"
+#define LIBCURL_VERSION "8.14.1"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 12
+#define LIBCURL_VERSION_MINOR 14
 #define LIBCURL_VERSION_PATCH 1
 
 /* This is the numeric version of the libcurl version number, meant for easier
@@ -59,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x080c01
+#define LIBCURL_VERSION_NUM 0x080e01
 
 /*
  * This is the date and time when the full source package was created. The

+ 22 - 12
Utilities/cmcurl/include/curl/system.h

@@ -36,13 +36,10 @@
  * curl_off_t
  * ----------
  *
- * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit
+ * For any given platform/compiler curl_off_t MUST be typedef'ed to a 64-bit
  * wide signed integral data type. The width of this data type must remain
  * constant and independent of any possible large file support settings.
  *
- * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
- * wide signed integral data type if there is no 64-bit type.
- *
  * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
  * only be violated if off_t is the only 64-bit data type available and the
  * size of off_t is independent of large file support settings. Keep your
@@ -52,7 +49,7 @@
  *
  */
 
-#if defined(__DJGPP__)
+#ifdef __DJGPP__
 #  define CURL_TYPEOF_CURL_OFF_T     long long
 #  define CURL_FORMAT_CURL_OFF_T     "lld"
 #  define CURL_FORMAT_CURL_OFF_TU    "llu"
@@ -137,13 +134,22 @@
 #    define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 #  endif
 
-#elif defined(_WIN32_WCE)
-#  define CURL_TYPEOF_CURL_OFF_T     __int64
-#  define CURL_FORMAT_CURL_OFF_T     "I64d"
-#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
-#  define CURL_SUFFIX_CURL_OFF_T     i64
-#  define CURL_SUFFIX_CURL_OFF_TU    ui64
-#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+#elif defined(UNDER_CE)
+#  if defined(__MINGW32CE__)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#    define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  endif
 
 #elif defined(__MINGW32__)
 #  include <inttypes.h>
@@ -330,6 +336,8 @@
 #    define CURL_FORMAT_CURL_OFF_TU    "llu"
 #    define CURL_SUFFIX_CURL_OFF_T     LL
 #    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_POPCOUNT64(x)         __builtin_popcountll(x)
+#    define CURL_CTZ64(x)              __builtin_ctzll(x)
 #  elif defined(__LP64__) || \
         defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \
         defined(__e2k__) || \
@@ -340,6 +348,8 @@
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"
 #    define CURL_SUFFIX_CURL_OFF_T     L
 #    define CURL_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_POPCOUNT64(x)         __builtin_popcountl(x)
+#    define CURL_CTZ64(x)              __builtin_ctzl(x)
 #  endif
 #  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
 #  define CURL_PULL_SYS_TYPES_H      1

+ 348 - 199
Utilities/cmcurl/include/curl/typecheck-gcc.h

@@ -40,115 +40,157 @@
  * To add an option that uses the same type as an existing option, you will
  * just need to extend the appropriate _curl_*_option macro
  */
+
 #define curl_easy_setopt(handle, option, value)                         \
   __extension__({                                                       \
-      CURLoption _curl_opt = (option);                                  \
-      if(__builtin_constant_p(_curl_opt)) {                             \
+      if(__builtin_constant_p(option)) {                                \
         CURL_IGNORE_DEPRECATION(                                        \
-          if(curlcheck_long_option(_curl_opt))                          \
+          if(curlcheck_long_option(option))                             \
             if(!curlcheck_long(value))                                  \
               _curl_easy_setopt_err_long();                             \
-          if(curlcheck_off_t_option(_curl_opt))                         \
+          if(curlcheck_off_t_option(option))                            \
             if(!curlcheck_off_t(value))                                 \
               _curl_easy_setopt_err_curl_off_t();                       \
-          if(curlcheck_string_option(_curl_opt))                        \
+          if(curlcheck_string_option(option))                           \
             if(!curlcheck_string(value))                                \
               _curl_easy_setopt_err_string();                           \
-          if(curlcheck_write_cb_option(_curl_opt))                      \
+          if((option) == CURLOPT_PRIVATE) { }                           \
+          if(curlcheck_write_cb_option(option))                         \
             if(!curlcheck_write_cb(value))                              \
               _curl_easy_setopt_err_write_callback();                   \
-          if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION)            \
+          if(curlcheck_curl_option(option))                             \
+            if(!curlcheck_curl(value))                                  \
+              _curl_easy_setopt_err_curl();                             \
+          if((option) == CURLOPT_RESOLVER_START_FUNCTION)               \
             if(!curlcheck_resolver_start_callback(value))               \
               _curl_easy_setopt_err_resolver_start_callback();          \
-          if((_curl_opt) == CURLOPT_READFUNCTION)                       \
+          if((option) == CURLOPT_READFUNCTION)                          \
             if(!curlcheck_read_cb(value))                               \
               _curl_easy_setopt_err_read_cb();                          \
-          if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                      \
+          if((option) == CURLOPT_IOCTLFUNCTION)                         \
             if(!curlcheck_ioctl_cb(value))                              \
               _curl_easy_setopt_err_ioctl_cb();                         \
-          if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                    \
+          if((option) == CURLOPT_SOCKOPTFUNCTION)                       \
             if(!curlcheck_sockopt_cb(value))                            \
               _curl_easy_setopt_err_sockopt_cb();                       \
-          if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                 \
+          if((option) == CURLOPT_OPENSOCKETFUNCTION)                    \
             if(!curlcheck_opensocket_cb(value))                         \
               _curl_easy_setopt_err_opensocket_cb();                    \
-          if((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                   \
+          if((option) == CURLOPT_PROGRESSFUNCTION)                      \
             if(!curlcheck_progress_cb(value))                           \
               _curl_easy_setopt_err_progress_cb();                      \
-          if((_curl_opt) == CURLOPT_DEBUGFUNCTION)                      \
+          if((option) == CURLOPT_XFERINFOFUNCTION)                      \
+            if(!curlcheck_xferinfo_cb(value))                           \
+              _curl_easy_setopt_err_xferinfo_cb();                      \
+          if((option) == CURLOPT_DEBUGFUNCTION)                         \
             if(!curlcheck_debug_cb(value))                              \
               _curl_easy_setopt_err_debug_cb();                         \
-          if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                   \
+          if((option) == CURLOPT_SSL_CTX_FUNCTION)                      \
             if(!curlcheck_ssl_ctx_cb(value))                            \
               _curl_easy_setopt_err_ssl_ctx_cb();                       \
-          if(curlcheck_conv_cb_option(_curl_opt))                       \
+          if(curlcheck_conv_cb_option(option))                          \
             if(!curlcheck_conv_cb(value))                               \
               _curl_easy_setopt_err_conv_cb();                          \
-          if((_curl_opt) == CURLOPT_SEEKFUNCTION)                       \
+          if((option) == CURLOPT_SEEKFUNCTION)                          \
             if(!curlcheck_seek_cb(value))                               \
               _curl_easy_setopt_err_seek_cb();                          \
-          if(curlcheck_cb_data_option(_curl_opt))                       \
+          if((option) == CURLOPT_CHUNK_BGN_FUNCTION)                    \
+            if(!curlcheck_chunk_bgn_cb(value))                          \
+              _curl_easy_setopt_err_chunk_bgn_cb();                     \
+          if((option) == CURLOPT_CHUNK_END_FUNCTION)                    \
+            if(!curlcheck_chunk_end_cb(value))                          \
+              _curl_easy_setopt_err_chunk_end_cb();                     \
+          if((option) == CURLOPT_CLOSESOCKETFUNCTION)                   \
+            if(!curlcheck_close_socket_cb(value))                       \
+              _curl_easy_setopt_err_close_socket_cb();                  \
+          if((option) == CURLOPT_FNMATCH_FUNCTION)                      \
+            if(!curlcheck_fnmatch_cb(value))                            \
+              _curl_easy_setopt_err_fnmatch_cb();                       \
+          if((option) == CURLOPT_HSTSREADFUNCTION)                      \
+            if(!curlcheck_hstsread_cb(value))                           \
+              _curl_easy_setopt_err_hstsread_cb();                      \
+          if((option) == CURLOPT_HSTSWRITEFUNCTION)                     \
+            if(!curlcheck_hstswrite_cb(value))                          \
+              _curl_easy_setopt_err_hstswrite_cb();                     \
+          if((option) == CURLOPT_SSH_HOSTKEYFUNCTION)                   \
+            if(!curlcheck_ssh_hostkey_cb(value))                        \
+              _curl_easy_setopt_err_ssh_hostkey_cb();                   \
+          if((option) == CURLOPT_SSH_KEYFUNCTION)                       \
+            if(!curlcheck_ssh_key_cb(value))                            \
+              _curl_easy_setopt_err_ssh_key_cb();                       \
+          if((option) == CURLOPT_INTERLEAVEFUNCTION)                    \
+            if(!curlcheck_interleave_cb(value))                         \
+              _curl_easy_setopt_err_interleave_cb();                    \
+          if((option) == CURLOPT_PREREQFUNCTION)                        \
+            if(!curlcheck_prereq_cb(value))                             \
+              _curl_easy_setopt_err_prereq_cb();                        \
+          if((option) == CURLOPT_TRAILERFUNCTION)                       \
+            if(!curlcheck_trailer_cb(value))                            \
+              _curl_easy_setopt_err_trailer_cb();                       \
+          if(curlcheck_cb_data_option(option))                          \
             if(!curlcheck_cb_data(value))                               \
               _curl_easy_setopt_err_cb_data();                          \
-          if((_curl_opt) == CURLOPT_ERRORBUFFER)                        \
+          if((option) == CURLOPT_ERRORBUFFER)                           \
             if(!curlcheck_error_buffer(value))                          \
               _curl_easy_setopt_err_error_buffer();                     \
-          if((_curl_opt) == CURLOPT_STDERR)                             \
+          if((option) == CURLOPT_CURLU)                                 \
+            if(!curlcheck_ptr((value), CURLU))                          \
+              _curl_easy_setopt_err_curlu();                    \
+          if((option) == CURLOPT_STDERR)                                \
             if(!curlcheck_FILE(value))                                  \
               _curl_easy_setopt_err_FILE();                             \
-          if(curlcheck_postfields_option(_curl_opt))                    \
+          if(curlcheck_postfields_option(option))                       \
             if(!curlcheck_postfields(value))                            \
               _curl_easy_setopt_err_postfields();                       \
-          if((_curl_opt) == CURLOPT_HTTPPOST)                           \
+          if((option) == CURLOPT_HTTPPOST)                              \
             if(!curlcheck_arr((value), struct curl_httppost))           \
               _curl_easy_setopt_err_curl_httpost();                     \
-          if((_curl_opt) == CURLOPT_MIMEPOST)                           \
+          if((option) == CURLOPT_MIMEPOST)                              \
             if(!curlcheck_ptr((value), curl_mime))                      \
               _curl_easy_setopt_err_curl_mimepost();                    \
-          if(curlcheck_slist_option(_curl_opt))                         \
+          if(curlcheck_slist_option(option))                            \
             if(!curlcheck_arr((value), struct curl_slist))              \
               _curl_easy_setopt_err_curl_slist();                       \
-          if((_curl_opt) == CURLOPT_SHARE)                              \
+          if((option) == CURLOPT_SHARE)                                 \
             if(!curlcheck_ptr((value), CURLSH))                         \
               _curl_easy_setopt_err_CURLSH();                           \
-        )                                                               \
-      }                                                                 \
-      curl_easy_setopt(handle, _curl_opt, value);                       \
+          )                                                             \
+          }                                                             \
+      curl_easy_setopt(handle, option, value);                          \
     })
 
 /* wraps curl_easy_getinfo() with typechecking */
 #define curl_easy_getinfo(handle, info, arg)                            \
   __extension__({                                                       \
-      CURLINFO _curl_info = (info);                                     \
-      if(__builtin_constant_p(_curl_info)) {                            \
+      if(__builtin_constant_p(info)) {                                  \
         CURL_IGNORE_DEPRECATION(                                        \
-          if(curlcheck_string_info(_curl_info))                         \
+          if(curlcheck_string_info(info))                               \
             if(!curlcheck_arr((arg), char *))                           \
               _curl_easy_getinfo_err_string();                          \
-          if(curlcheck_long_info(_curl_info))                           \
+          if(curlcheck_long_info(info))                                 \
             if(!curlcheck_arr((arg), long))                             \
               _curl_easy_getinfo_err_long();                            \
-          if(curlcheck_double_info(_curl_info))                         \
+          if(curlcheck_double_info(info))                               \
             if(!curlcheck_arr((arg), double))                           \
               _curl_easy_getinfo_err_double();                          \
-          if(curlcheck_slist_info(_curl_info))                          \
+          if(curlcheck_slist_info(info))                                \
             if(!curlcheck_arr((arg), struct curl_slist *))              \
               _curl_easy_getinfo_err_curl_slist();                      \
-          if(curlcheck_tlssessioninfo_info(_curl_info))                 \
+          if(curlcheck_tlssessioninfo_info(info))                       \
             if(!curlcheck_arr((arg), struct curl_tlssessioninfo *))     \
-              _curl_easy_getinfo_err_curl_tlssesssioninfo();            \
-          if(curlcheck_certinfo_info(_curl_info))                       \
+              _curl_easy_getinfo_err_curl_tlssessioninfo();            \
+          if(curlcheck_certinfo_info(info))                             \
             if(!curlcheck_arr((arg), struct curl_certinfo *))           \
               _curl_easy_getinfo_err_curl_certinfo();                   \
-          if(curlcheck_socket_info(_curl_info))                         \
+          if(curlcheck_socket_info(info))                               \
             if(!curlcheck_arr((arg), curl_socket_t))                    \
               _curl_easy_getinfo_err_curl_socket();                     \
-          if(curlcheck_off_t_info(_curl_info))                          \
+          if(curlcheck_off_t_info(info))                                \
             if(!curlcheck_arr((arg), curl_off_t))                       \
               _curl_easy_getinfo_err_curl_off_t();                      \
-        )                                                               \
-      }                                                                 \
-      curl_easy_getinfo(handle, _curl_info, arg);                       \
+          )                                                             \
+          }                                                             \
+      curl_easy_getinfo(handle, info, arg);                             \
     })
 
 /*
@@ -157,7 +199,6 @@
 #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
 #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
 
-
 /* the actual warnings, triggered by calling the _curl_easy_setopt_err*
  * functions */
 
@@ -168,187 +209,212 @@
   id(void) { __asm__(""); }
 
 CURLWARNING(_curl_easy_setopt_err_long,
-  "curl_easy_setopt expects a long argument for this option")
+            "curl_easy_setopt expects a long argument")
 CURLWARNING(_curl_easy_setopt_err_curl_off_t,
-  "curl_easy_setopt expects a curl_off_t argument for this option")
+            "curl_easy_setopt expects a curl_off_t argument")
 CURLWARNING(_curl_easy_setopt_err_string,
-              "curl_easy_setopt expects a "
-              "string ('char *' or char[]) argument for this option"
-  )
+            "curl_easy_setopt expects a "
+            "string ('char *' or char[]) argument")
 CURLWARNING(_curl_easy_setopt_err_write_callback,
-  "curl_easy_setopt expects a curl_write_callback argument for this option")
+            "curl_easy_setopt expects a curl_write_callback argument")
 CURLWARNING(_curl_easy_setopt_err_resolver_start_callback,
-              "curl_easy_setopt expects a "
-              "curl_resolver_start_callback argument for this option"
-  )
+            "curl_easy_setopt expects a "
+            "curl_resolver_start_callback argument")
 CURLWARNING(_curl_easy_setopt_err_read_cb,
-  "curl_easy_setopt expects a curl_read_callback argument for this option")
+            "curl_easy_setopt expects a curl_read_callback argument")
 CURLWARNING(_curl_easy_setopt_err_ioctl_cb,
-  "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+            "curl_easy_setopt expects a curl_ioctl_callback argument")
 CURLWARNING(_curl_easy_setopt_err_sockopt_cb,
-  "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+            "curl_easy_setopt expects a curl_sockopt_callback argument")
 CURLWARNING(_curl_easy_setopt_err_opensocket_cb,
-              "curl_easy_setopt expects a "
-              "curl_opensocket_callback argument for this option"
-  )
+            "curl_easy_setopt expects a "
+            "curl_opensocket_callback argument")
 CURLWARNING(_curl_easy_setopt_err_progress_cb,
-  "curl_easy_setopt expects a curl_progress_callback argument for this option")
+            "curl_easy_setopt expects a curl_progress_callback argument")
+CURLWARNING(_curl_easy_setopt_err_xferinfo_cb,
+            "curl_easy_setopt expects a curl_xferinfo_callback argument")
 CURLWARNING(_curl_easy_setopt_err_debug_cb,
-  "curl_easy_setopt expects a curl_debug_callback argument for this option")
+            "curl_easy_setopt expects a curl_debug_callback argument")
 CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb,
-  "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+            "curl_easy_setopt expects a curl_ssl_ctx_callback argument")
 CURLWARNING(_curl_easy_setopt_err_conv_cb,
-  "curl_easy_setopt expects a curl_conv_callback argument for this option")
+            "curl_easy_setopt expects a curl_conv_callback argument")
 CURLWARNING(_curl_easy_setopt_err_seek_cb,
-  "curl_easy_setopt expects a curl_seek_callback argument for this option")
+            "curl_easy_setopt expects a curl_seek_callback argument")
 CURLWARNING(_curl_easy_setopt_err_cb_data,
-              "curl_easy_setopt expects a "
-              "private data pointer as argument for this option")
+            "curl_easy_setopt expects a "
+            "private data pointer as argument")
+CURLWARNING(_curl_easy_setopt_err_chunk_bgn_cb,
+            "curl_easy_setopt expects a curl_chunk_bgn_callback argument")
+CURLWARNING(_curl_easy_setopt_err_chunk_end_cb,
+            "curl_easy_setopt expects a curl_chunk_end_callback argument")
+CURLWARNING(_curl_easy_setopt_err_close_socket_cb,
+            "curl_easy_setopt expects a curl_closesocket_callback argument")
+CURLWARNING(_curl_easy_setopt_err_fnmatch_cb,
+            "curl_easy_setopt expects a curl_fnmatch_callback argument")
+CURLWARNING(_curl_easy_setopt_err_hstsread_cb,
+            "curl_easy_setopt expects a curl_hstsread_callback argument")
+CURLWARNING(_curl_easy_setopt_err_hstswrite_cb,
+            "curl_easy_setopt expects a curl_hstswrite_callback argument")
+CURLWARNING(_curl_easy_setopt_err_ssh_key_cb,
+            "curl_easy_setopt expects a curl_sshkeycallback argument")
+CURLWARNING(_curl_easy_setopt_err_ssh_hostkey_cb,
+            "curl_easy_setopt expects a curl_sshhostkeycallback argument")
+CURLWARNING(_curl_easy_setopt_err_interleave_cb,
+            "curl_easy_setopt expects a curl_interleave_callback argument")
+CURLWARNING(_curl_easy_setopt_err_prereq_cb,
+            "curl_easy_setopt expects a curl_prereq_callback argument")
+CURLWARNING(_curl_easy_setopt_err_trailer_cb,
+            "curl_easy_setopt expects a curl_trailerfunc_ok argument")
 CURLWARNING(_curl_easy_setopt_err_error_buffer,
-              "curl_easy_setopt expects a "
-              "char buffer of CURL_ERROR_SIZE as argument for this option")
+            "curl_easy_setopt expects a "
+            "char buffer of CURL_ERROR_SIZE as argument")
+CURLWARNING(_curl_easy_setopt_err_curlu,
+            "curl_easy_setopt expects a 'CURLU *' argument")
+CURLWARNING(_curl_easy_setopt_err_curl,
+            "curl_easy_setopt expects a 'CURL *' argument")
 CURLWARNING(_curl_easy_setopt_err_FILE,
-  "curl_easy_setopt expects a 'FILE *' argument for this option")
+            "curl_easy_setopt expects a 'FILE *' argument")
 CURLWARNING(_curl_easy_setopt_err_postfields,
-  "curl_easy_setopt expects a 'void *' or 'char *' argument for this option")
+            "curl_easy_setopt expects a 'void *' or 'char *' argument")
 CURLWARNING(_curl_easy_setopt_err_curl_httpost,
-              "curl_easy_setopt expects a 'struct curl_httppost *' "
-              "argument for this option")
+            "curl_easy_setopt expects a 'struct curl_httppost *' "
+            "argument")
 CURLWARNING(_curl_easy_setopt_err_curl_mimepost,
-              "curl_easy_setopt expects a 'curl_mime *' "
-              "argument for this option")
+            "curl_easy_setopt expects a 'curl_mime *' "
+            "argument")
 CURLWARNING(_curl_easy_setopt_err_curl_slist,
-  "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
+            "curl_easy_setopt expects a 'struct curl_slist *' argument")
 CURLWARNING(_curl_easy_setopt_err_CURLSH,
-  "curl_easy_setopt expects a CURLSH* argument for this option")
-
+            "curl_easy_setopt expects a CURLSH* argument")
 CURLWARNING(_curl_easy_getinfo_err_string,
-  "curl_easy_getinfo expects a pointer to 'char *' for this info")
+            "curl_easy_getinfo expects a pointer to 'char *'")
 CURLWARNING(_curl_easy_getinfo_err_long,
-  "curl_easy_getinfo expects a pointer to long for this info")
+            "curl_easy_getinfo expects a pointer to long")
 CURLWARNING(_curl_easy_getinfo_err_double,
-  "curl_easy_getinfo expects a pointer to double for this info")
+            "curl_easy_getinfo expects a pointer to double")
 CURLWARNING(_curl_easy_getinfo_err_curl_slist,
-  "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info")
-CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
-              "curl_easy_getinfo expects a pointer to "
-              "'struct curl_tlssessioninfo *' for this info")
+            "curl_easy_getinfo expects a pointer to 'struct curl_slist *'")
+CURLWARNING(_curl_easy_getinfo_err_curl_tlssessioninfo,
+            "curl_easy_getinfo expects a pointer to "
+            "'struct curl_tlssessioninfo *'")
 CURLWARNING(_curl_easy_getinfo_err_curl_certinfo,
-              "curl_easy_getinfo expects a pointer to "
-              "'struct curl_certinfo *' for this info")
+            "curl_easy_getinfo expects a pointer to "
+            "'struct curl_certinfo *'")
 CURLWARNING(_curl_easy_getinfo_err_curl_socket,
-  "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
+            "curl_easy_getinfo expects a pointer to curl_socket_t")
 CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
-  "curl_easy_getinfo expects a pointer to curl_off_t for this info")
+            "curl_easy_getinfo expects a pointer to curl_off_t")
 
 /* groups of curl_easy_setops options that take the same type of argument */
 
-/* To add a new option to one of the groups, just add
- *   (option) == CURLOPT_SOMETHING
- * to the or-expression. If the option takes a long or curl_off_t, you do not
- * have to do anything
- */
-
 /* evaluates to true if option takes a long argument */
 #define curlcheck_long_option(option)                   \
   (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
 
-#define curlcheck_off_t_option(option)          \
+#define curlcheck_off_t_option(option)                                  \
   (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB))
 
+/* option takes a CURL * argument */
+#define curlcheck_curl_option(option)                                 \
+  ((option) == CURLOPT_STREAM_DEPENDS ||                              \
+   (option) == CURLOPT_STREAM_DEPENDS_E ||                            \
+   0)
+
 /* evaluates to true if option takes a char* argument */
-#define curlcheck_string_option(option)                                       \
-  ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET ||                                \
-   (option) == CURLOPT_ACCEPT_ENCODING ||                                     \
-   (option) == CURLOPT_ALTSVC ||                                              \
-   (option) == CURLOPT_CAINFO ||                                              \
-   (option) == CURLOPT_CAPATH ||                                              \
-   (option) == CURLOPT_COOKIE ||                                              \
-   (option) == CURLOPT_COOKIEFILE ||                                          \
-   (option) == CURLOPT_COOKIEJAR ||                                           \
-   (option) == CURLOPT_COOKIELIST ||                                          \
-   (option) == CURLOPT_CRLFILE ||                                             \
-   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
-   (option) == CURLOPT_DEFAULT_PROTOCOL ||                                    \
-   (option) == CURLOPT_DNS_INTERFACE ||                                       \
-   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                       \
-   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                       \
-   (option) == CURLOPT_DNS_SERVERS ||                                         \
-   (option) == CURLOPT_DOH_URL ||                                             \
-   (option) == CURLOPT_ECH        ||                                          \
-   (option) == CURLOPT_EGDSOCKET ||                                           \
-   (option) == CURLOPT_FTP_ACCOUNT ||                                         \
-   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
-   (option) == CURLOPT_FTPPORT ||                                             \
-   (option) == CURLOPT_HSTS ||                                                \
-   (option) == CURLOPT_HAPROXY_CLIENT_IP ||                                   \
-   (option) == CURLOPT_INTERFACE ||                                           \
-   (option) == CURLOPT_ISSUERCERT ||                                          \
-   (option) == CURLOPT_KEYPASSWD ||                                           \
-   (option) == CURLOPT_KRBLEVEL ||                                            \
-   (option) == CURLOPT_LOGIN_OPTIONS ||                                       \
-   (option) == CURLOPT_MAIL_AUTH ||                                           \
-   (option) == CURLOPT_MAIL_FROM ||                                           \
-   (option) == CURLOPT_NETRC_FILE ||                                          \
-   (option) == CURLOPT_NOPROXY ||                                             \
-   (option) == CURLOPT_PASSWORD ||                                            \
-   (option) == CURLOPT_PINNEDPUBLICKEY ||                                     \
-   (option) == CURLOPT_PRE_PROXY ||                                           \
-   (option) == CURLOPT_PROTOCOLS_STR ||                                       \
-   (option) == CURLOPT_PROXY ||                                               \
-   (option) == CURLOPT_PROXY_CAINFO ||                                        \
-   (option) == CURLOPT_PROXY_CAPATH ||                                        \
-   (option) == CURLOPT_PROXY_CRLFILE ||                                       \
-   (option) == CURLOPT_PROXY_ISSUERCERT ||                                    \
-   (option) == CURLOPT_PROXY_KEYPASSWD ||                                     \
-   (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                               \
-   (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
-   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                               \
-   (option) == CURLOPT_PROXY_SSLCERT ||                                       \
-   (option) == CURLOPT_PROXY_SSLCERTTYPE ||                                   \
-   (option) == CURLOPT_PROXY_SSLKEY ||                                        \
-   (option) == CURLOPT_PROXY_SSLKEYTYPE ||                                    \
-   (option) == CURLOPT_PROXY_TLS13_CIPHERS ||                                 \
-   (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD ||                              \
-   (option) == CURLOPT_PROXY_TLSAUTH_TYPE ||                                  \
-   (option) == CURLOPT_PROXY_TLSAUTH_USERNAME ||                              \
-   (option) == CURLOPT_PROXYPASSWORD ||                                       \
-   (option) == CURLOPT_PROXYUSERNAME ||                                       \
-   (option) == CURLOPT_PROXYUSERPWD ||                                        \
-   (option) == CURLOPT_RANDOM_FILE ||                                         \
-   (option) == CURLOPT_RANGE ||                                               \
-   (option) == CURLOPT_REDIR_PROTOCOLS_STR ||                                 \
-   (option) == CURLOPT_REFERER ||                                             \
-   (option) == CURLOPT_REQUEST_TARGET ||                                      \
-   (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
-   (option) == CURLOPT_RTSP_STREAM_URI ||                                     \
-   (option) == CURLOPT_RTSP_TRANSPORT ||                                      \
-   (option) == CURLOPT_SASL_AUTHZID ||                                        \
-   (option) == CURLOPT_SERVICE_NAME ||                                        \
-   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
-   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
-   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 ||                          \
-   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
-   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
-   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
-   (option) == CURLOPT_SSLCERT ||                                             \
-   (option) == CURLOPT_SSLCERTTYPE ||                                         \
-   (option) == CURLOPT_SSLENGINE ||                                           \
-   (option) == CURLOPT_SSLKEY ||                                              \
-   (option) == CURLOPT_SSLKEYTYPE ||                                          \
-   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
-   (option) == CURLOPT_TLS13_CIPHERS ||                                       \
-   (option) == CURLOPT_TLSAUTH_PASSWORD ||                                    \
-   (option) == CURLOPT_TLSAUTH_TYPE ||                                        \
-   (option) == CURLOPT_TLSAUTH_USERNAME ||                                    \
-   (option) == CURLOPT_UNIX_SOCKET_PATH ||                                    \
-   (option) == CURLOPT_URL ||                                                 \
-   (option) == CURLOPT_USERAGENT ||                                           \
-   (option) == CURLOPT_USERNAME ||                                            \
-   (option) == CURLOPT_AWS_SIGV4 ||                                           \
-   (option) == CURLOPT_USERPWD ||                                             \
-   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
-   (option) == CURLOPT_SSL_EC_CURVES ||                                       \
+#define curlcheck_string_option(option)                                 \
+  ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET ||                          \
+   (option) == CURLOPT_ACCEPT_ENCODING ||                               \
+   (option) == CURLOPT_ALTSVC ||                                        \
+   (option) == CURLOPT_CAINFO ||                                        \
+   (option) == CURLOPT_CAPATH ||                                        \
+   (option) == CURLOPT_COOKIE ||                                        \
+   (option) == CURLOPT_COOKIEFILE ||                                    \
+   (option) == CURLOPT_COOKIEJAR ||                                     \
+   (option) == CURLOPT_COOKIELIST ||                                    \
+   (option) == CURLOPT_CRLFILE ||                                       \
+   (option) == CURLOPT_CUSTOMREQUEST ||                                 \
+   (option) == CURLOPT_DEFAULT_PROTOCOL ||                              \
+   (option) == CURLOPT_DNS_INTERFACE ||                                 \
+   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                 \
+   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                 \
+   (option) == CURLOPT_DNS_SERVERS ||                                   \
+   (option) == CURLOPT_DOH_URL ||                                       \
+   (option) == CURLOPT_ECH ||                                           \
+   (option) == CURLOPT_EGDSOCKET ||                                     \
+   (option) == CURLOPT_FTP_ACCOUNT ||                                   \
+   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                       \
+   (option) == CURLOPT_FTPPORT ||                                       \
+   (option) == CURLOPT_HAPROXY_CLIENT_IP ||                             \
+   (option) == CURLOPT_HSTS ||                                          \
+   (option) == CURLOPT_INTERFACE ||                                     \
+   (option) == CURLOPT_ISSUERCERT ||                                    \
+   (option) == CURLOPT_KEYPASSWD ||                                     \
+   (option) == CURLOPT_KRBLEVEL ||                                      \
+   (option) == CURLOPT_LOGIN_OPTIONS ||                                 \
+   (option) == CURLOPT_MAIL_AUTH ||                                     \
+   (option) == CURLOPT_MAIL_FROM ||                                     \
+   (option) == CURLOPT_NETRC_FILE ||                                    \
+   (option) == CURLOPT_NOPROXY ||                                       \
+   (option) == CURLOPT_PASSWORD ||                                      \
+   (option) == CURLOPT_PINNEDPUBLICKEY ||                               \
+   (option) == CURLOPT_PRE_PROXY ||                                     \
+   (option) == CURLOPT_PROTOCOLS_STR ||                                 \
+   (option) == CURLOPT_PROXY ||                                         \
+   (option) == CURLOPT_PROXY_CAINFO ||                                  \
+   (option) == CURLOPT_PROXY_CAPATH ||                                  \
+   (option) == CURLOPT_PROXY_CRLFILE ||                                 \
+   (option) == CURLOPT_PROXY_ISSUERCERT ||                              \
+   (option) == CURLOPT_PROXY_KEYPASSWD ||                               \
+   (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                         \
+   (option) == CURLOPT_PROXY_SERVICE_NAME ||                            \
+   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                         \
+   (option) == CURLOPT_PROXY_SSLCERT ||                                 \
+   (option) == CURLOPT_PROXY_SSLCERTTYPE ||                             \
+   (option) == CURLOPT_PROXY_SSLKEY ||                                  \
+   (option) == CURLOPT_PROXY_SSLKEYTYPE ||                              \
+   (option) == CURLOPT_PROXY_TLS13_CIPHERS ||                           \
+   (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD ||                        \
+   (option) == CURLOPT_PROXY_TLSAUTH_TYPE ||                            \
+   (option) == CURLOPT_PROXY_TLSAUTH_USERNAME ||                        \
+   (option) == CURLOPT_PROXYPASSWORD ||                                 \
+   (option) == CURLOPT_PROXYUSERNAME ||                                 \
+   (option) == CURLOPT_PROXYUSERPWD ||                                  \
+   (option) == CURLOPT_RANDOM_FILE ||                                   \
+   (option) == CURLOPT_RANGE ||                                         \
+   (option) == CURLOPT_REDIR_PROTOCOLS_STR ||                           \
+   (option) == CURLOPT_REFERER ||                                       \
+   (option) == CURLOPT_REQUEST_TARGET ||                                \
+   (option) == CURLOPT_RTSP_SESSION_ID ||                               \
+   (option) == CURLOPT_RTSP_STREAM_URI ||                               \
+   (option) == CURLOPT_RTSP_TRANSPORT ||                                \
+   (option) == CURLOPT_SASL_AUTHZID ||                                  \
+   (option) == CURLOPT_SERVICE_NAME ||                                  \
+   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                         \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                       \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 ||                    \
+   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                \
+   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                           \
+   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                            \
+   (option) == CURLOPT_SSLCERT ||                                       \
+   (option) == CURLOPT_SSLCERTTYPE ||                                   \
+   (option) == CURLOPT_SSLENGINE ||                                     \
+   (option) == CURLOPT_SSLKEY ||                                        \
+   (option) == CURLOPT_SSLKEYTYPE ||                                    \
+   (option) == CURLOPT_SSL_CIPHER_LIST ||                               \
+   (option) == CURLOPT_SSL_EC_CURVES ||                                 \
+   (option) == CURLOPT_SSL_SIGNATURE_ALGORITHMS ||                      \
+   (option) == CURLOPT_TLS13_CIPHERS ||                                 \
+   (option) == CURLOPT_TLSAUTH_PASSWORD ||                              \
+   (option) == CURLOPT_TLSAUTH_TYPE ||                                  \
+   (option) == CURLOPT_TLSAUTH_USERNAME ||                              \
+   (option) == CURLOPT_UNIX_SOCKET_PATH ||                              \
+   (option) == CURLOPT_URL ||                                           \
+   (option) == CURLOPT_USERAGENT ||                                     \
+   (option) == CURLOPT_USERNAME ||                                      \
+   (option) == CURLOPT_AWS_SIGV4 ||                                     \
+   (option) == CURLOPT_USERPWD ||                                       \
+   (option) == CURLOPT_XOAUTH2_BEARER ||                                \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
@@ -375,7 +441,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_IOCTLDATA ||                                           \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
    (option) == CURLOPT_PREREQDATA ||                                          \
-   (option) == CURLOPT_PROGRESSDATA ||                                        \
+   (option) == CURLOPT_XFERINFODATA ||                                        \
    (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
    (option) == CURLOPT_SOCKOPTDATA ||                                         \
@@ -479,22 +545,36 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    curlcheck_arr((expr), signed char) ||                                \
    curlcheck_arr((expr), unsigned char))
 
+/* evaluates to true if expr is a CURL * */
+#define curlcheck_curl(expr)                                          \
+  (curlcheck_NULL(expr) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), CURL *))
+
+
 /* evaluates to true if expr is a long (no matter the signedness)
  * XXX: for now, int is also accepted (and therefore short and char, which
  * are promoted to int when passed to a variadic function) */
-#define curlcheck_long(expr)                                                  \
-  (__builtin_types_compatible_p(__typeof__(expr), long) ||                    \
-   __builtin_types_compatible_p(__typeof__(expr), signed long) ||             \
-   __builtin_types_compatible_p(__typeof__(expr), unsigned long) ||           \
-   __builtin_types_compatible_p(__typeof__(expr), int) ||                     \
-   __builtin_types_compatible_p(__typeof__(expr), signed int) ||              \
-   __builtin_types_compatible_p(__typeof__(expr), unsigned int) ||            \
-   __builtin_types_compatible_p(__typeof__(expr), short) ||                   \
-   __builtin_types_compatible_p(__typeof__(expr), signed short) ||            \
-   __builtin_types_compatible_p(__typeof__(expr), unsigned short) ||          \
-   __builtin_types_compatible_p(__typeof__(expr), char) ||                    \
-   __builtin_types_compatible_p(__typeof__(expr), signed char) ||             \
-   __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+#define curlcheck_long(expr)                                            \
+  (                                                                     \
+  ((sizeof(long) != sizeof(int)) &&                                     \
+   (__builtin_types_compatible_p(__typeof__(expr), long) ||             \
+    __builtin_types_compatible_p(__typeof__(expr), signed long) ||      \
+    __builtin_types_compatible_p(__typeof__(expr), unsigned long)))     \
+  ||                                                                    \
+  ((sizeof(long) == sizeof(int)) &&                                     \
+  (__builtin_types_compatible_p(__typeof__(expr), long) ||              \
+   __builtin_types_compatible_p(__typeof__(expr), signed long) ||       \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned long) ||     \
+   __builtin_types_compatible_p(__typeof__(expr), int) ||               \
+   __builtin_types_compatible_p(__typeof__(expr), signed int) ||        \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned int) ||      \
+   __builtin_types_compatible_p(__typeof__(expr), short) ||             \
+   __builtin_types_compatible_p(__typeof__(expr), signed short) ||      \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned short) ||    \
+   __builtin_types_compatible_p(__typeof__(expr), char) ||              \
+   __builtin_types_compatible_p(__typeof__(expr), signed char) ||       \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned char)))      \
+                                                                  )
 
 /* evaluates to true if expr is of type curl_off_t */
 #define curlcheck_off_t(expr)                                   \
@@ -629,6 +709,11 @@ typedef int (*_curl_progress_callback1)(void *,
 typedef int (*_curl_progress_callback2)(const void *,
     double, double, double, double);
 
+/* evaluates to true if expr is of type curl_xferinfo_callback */
+#define curlcheck_xferinfo_cb(expr)                                     \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_xferinfo_callback))
+
 /* evaluates to true if expr is of type curl_debug_callback or "similar" */
 #define curlcheck_debug_cb(expr)                                        \
   (curlcheck_NULL(expr) ||                                              \
@@ -714,5 +799,69 @@ typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
 typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
 typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
 
+/* evaluates to true if expr is of type curl_chunk_bgn_callback */
+#define curlcheck_chunk_bgn_cb(expr)                                    \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_chunk_bgn_callback) ||          \
+   curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback1) ||        \
+   curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback2))
+typedef long (*_curl_chunk_bgn_callback1)(struct curl_fileinfo *,
+                                          void *, int);
+typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int);
+
+/* evaluates to true if expr is of type curl_chunk_end_callback */
+#define curlcheck_chunk_end_cb(expr)                                    \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_chunk_end_callback))
+
+/* evaluates to true if expr is of type curl_closesocket_callback */
+#define curlcheck_close_socket_cb(expr)                                 \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_closesocket_callback))
+
+/* evaluates to true if expr is of type curl_fnmatch_callback */
+#define curlcheck_fnmatch_cb(expr)                                      \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_fnmatch_callback))
+
+/* evaluates to true if expr is of type curl_hstsread_callback */
+#define curlcheck_hstsread_cb(expr)                                     \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_hstsread_callback))
+
+/* evaluates to true if expr is of type curl_hstswrite_callback */
+#define curlcheck_hstswrite_cb(expr)                                    \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_hstswrite_callback))
+
+/* evaluates to true if expr is of type curl_sshhostkeycallback */
+#define curlcheck_ssh_hostkey_cb(expr)                                  \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_sshhostkeycallback))
+
+/* evaluates to true if expr is of type curl_sshkeycallback */
+#define curlcheck_ssh_key_cb(expr)                                  \
+  (curlcheck_NULL(expr) ||                                          \
+   curlcheck_cb_compatible((expr), curl_sshkeycallback))
+
+/* evaluates to true if expr is of type curl_interleave_callback */
+#define curlcheck_interleave_cb(expr)                                   \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), _curl_interleave_callback1) ||       \
+   curlcheck_cb_compatible((expr), _curl_interleave_callback2))
+typedef size_t (*_curl_interleave_callback1)(void *p, size_t s,
+                                             size_t n, void *u);
+typedef size_t (*_curl_interleave_callback2)(char *p, size_t s,
+                                             size_t n, void *u);
+
+/* evaluates to true if expr is of type curl_prereq_callback */
+#define curlcheck_prereq_cb(expr)                                    \
+  (curlcheck_NULL(expr) ||                                           \
+   curlcheck_cb_compatible((expr), curl_prereq_callback))
+
+/* evaluates to true if expr is of type curl_trailer_callback */
+#define curlcheck_trailer_cb(expr)                                    \
+  (curlcheck_NULL(expr) ||                                            \
+   curlcheck_cb_compatible((expr), curl_trailer_callback))
 
 #endif /* CURLINC_TYPECHECK_GCC_H */

+ 2 - 1
Utilities/cmcurl/include/curl/websockets.h

@@ -73,7 +73,8 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
                                   unsigned int flags);
 
 /* bits for the CURLOPT_WS_OPTIONS bitmask: */
-#define CURLWS_RAW_MODE (1<<0)
+#define CURLWS_RAW_MODE   (1<<0)
+#define CURLWS_NOAUTOPONG (1<<1)
 
 CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl);
 

+ 59 - 36
Utilities/cmcurl/lib/CMakeLists.txt

@@ -21,9 +21,11 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-set(LIB_NAME "libcurl")
-set(LIBCURL_OUTPUT_NAME "libcurl" CACHE STRING "Basename of the curl library")
-add_definitions("-DBUILDING_LIBCURL")
+
+set(LIBCURL_OUTPUT_NAME "${LIB_NAME}" CACHE STRING "Basename of the curl library")
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "BUILDING_LIBCURL")
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${CURL_DEBUG_MACROS}")
 
 configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
@@ -31,17 +33,14 @@ configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h"
 curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
-# DllMain is added later for DLL builds only.
-list(REMOVE_ITEM CSOURCES "dllmain.c")
-
 list(APPEND HHEADERS "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
 # The rest of the build
 
-include_directories(
-  "${PROJECT_BINARY_DIR}/lib"  # for "curl_config.h"
-  "${PROJECT_SOURCE_DIR}/lib"  # for "curl_setup.h"
+set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
+  "${PROJECT_BINARY_DIR}/lib"        # for "curl_config.h"
 )
+
 if(USE_ARES)
   include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
 endif()
@@ -92,7 +91,7 @@ if(CURL_BUILD_TESTING)
     EXCLUDE_FROM_ALL
     ${HHEADERS} ${CSOURCES}
   )
-  target_compile_definitions(curlu PUBLIC "UNITTESTS" "CURL_STATICLIB")
+  target_compile_definitions(curlu PUBLIC "CURL_STATICLIB" "UNITTESTS")
   target_link_libraries(curlu PRIVATE ${CURL_LIBS})
   # There is plenty of parallelism when building the testdeps target.
   # Override the curlu batch size with the maximum to optimize performance.
@@ -100,26 +99,35 @@ if(CURL_BUILD_TESTING)
 endif()
 
 if(ENABLE_CURLDEBUG)
-  # We must compile these sources separately to avoid memdebug.h redefinitions
-  # applying to them.
-  set_source_files_properties("memdebug.c" "curl_multibyte.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+  # We must compile this source separately to avoid memdebug.h redefinitions
+  # applying to it.
+  set_source_files_properties("memdebug.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 endif()
 
 ## Library definition
 
 if(NOT DEFINED IMPORT_LIB_SUFFIX)
-  set(IMPORT_LIB_SUFFIX "")
+  # Suffix implib name with "_imp" by default, to avoid conflicting with
+  # the generated static "libcurl.lib" (typically with MSVC).
+  if(WIN32 AND BUILD_SHARED_LIBS AND
+     CMAKE_IMPORT_LIBRARY_SUFFIX STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
+    set(IMPORT_LIB_SUFFIX "_imp")
+  else()
+    set(IMPORT_LIB_SUFFIX "")
+  endif()
 endif()
 if(NOT DEFINED STATIC_LIB_SUFFIX)
   set(STATIC_LIB_SUFFIX "")
 endif()
 
-# Add "_imp" as a suffix before the extension to avoid conflicting with
-# the statically linked "libcurl.lib" (typically with MSVC)
-if(WIN32 AND
-   NOT IMPORT_LIB_SUFFIX AND
-   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
-  set(IMPORT_LIB_SUFFIX "_imp")
+# Detect implib static lib filename collision
+if(WIN32 AND BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS AND
+   "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" STREQUAL
+   "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+  message(FATAL_ERROR "Library suffix is the same ('${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}') "
+    "for the import and static '${LIBCURL_OUTPUT_NAME}' library. "
+    "Set IMPORT_LIB_SUFFIX and/or STATIC_LIB_SUFFIX to different values, "
+    "or disable building either the shared or static library to avoid the filename collision.")
 endif()
 
 # Whether to do a single compilation pass for libcurl sources and reuse these
@@ -136,9 +144,9 @@ if(NOT DEFINED SHARE_LIB_OBJECT)
   endif()
 endif()
 
-if(SHARE_LIB_OBJECT)
+if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
   set(LIB_OBJECT "libcurl_object")
-  add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+  add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})  # Requires CMake 3.12
   if(WIN32)
     # Define CURL_STATICLIB always, to disable __declspec(dllexport) for
     # exported libcurl symbols. We handle exports via libcurl.def instead.
@@ -154,7 +162,13 @@ if(SHARE_LIB_OBJECT)
     set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    if(CMAKE_CONFIGURATION_TYPES)
+      set_target_properties(${LIB_OBJECT} PROPERTIES
+        INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+        INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    else()
+      set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    endif()
   endif()
 
   target_include_directories(${LIB_OBJECT} INTERFACE
@@ -179,13 +193,20 @@ if(BUILD_STATIC_LIBS)
   set_target_properties(${LIB_STATIC} PROPERTIES
     PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
     SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
-    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"
+    INTERFACE_LINK_DIRECTORIES "${CURL_LIBDIRS}")
   if(CURL_HIDES_PRIVATE_SYMBOLS)
     set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
     set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    if(CMAKE_CONFIGURATION_TYPES)
+      set_target_properties(${LIB_OBJECT} PROPERTIES
+        INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+        INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    else()
+      set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    endif()
   endif()
 
   target_include_directories(${LIB_STATIC} INTERFACE
@@ -197,15 +218,8 @@ if(BUILD_SHARED_LIBS)
   list(APPEND libcurl_export ${LIB_SHARED})
   add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
   add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
-  if(WIN32 OR CYGWIN)
-    if(CYGWIN)
-      # For Cygwin always compile dllmain.c as a separate unit since it
-      # includes windows.h, which should not be included in other units.
-      set_source_files_properties("dllmain.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-    endif()
-    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
-  endif()
   if(WIN32)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "libcurl.rc")
     if(CURL_HIDES_PRIVATE_SYMBOLS)
       set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${PROJECT_SOURCE_DIR}/lib/libcurl.def")
@@ -222,7 +236,13 @@ if(BUILD_SHARED_LIBS)
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    if(CMAKE_CONFIGURATION_TYPES)
+      set_target_properties(${LIB_OBJECT} PROPERTIES
+        INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+        INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    else()
+      set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
+    endif()
   endif()
 
   target_include_directories(${LIB_SHARED} INTERFACE
@@ -294,8 +314,11 @@ if(BUILD_SHARED_LIBS)
     set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers")
     check_c_source_compiles("int main(void) { return 0; }" HAVE_VERSIONED_SYMBOLS)
     if(HAVE_VERSIONED_SYMBOLS)
-      # Superseded by LINK_OPTIONS in CMake 3.13 and later.
-      set_target_properties(${LIB_SHARED} PROPERTIES LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}")
+      if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
+        set_target_properties(${LIB_SHARED} PROPERTIES LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}")
+      else()
+        set_target_properties(${LIB_SHARED} PROPERTIES LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}")
+      endif()
     else()
       message(WARNING "Versioned symbols requested, but not supported by the toolchain.")
     endif()

+ 48 - 32
Utilities/cmcurl/lib/Makefile.inc

@@ -22,6 +22,33 @@
 #
 ###########################################################################
 
+LIB_CURLX_CFILES = \
+  curlx/base64.c   \
+  curlx/dynbuf.c   \
+  curlx/inet_pton.c \
+  curlx/multibyte.c \
+  curlx/nonblock.c \
+  curlx/strparse.c \
+  curlx/timediff.c \
+  curlx/timeval.c  \
+  curlx/version_win32.c \
+  curlx/warnless.c \
+  curlx/winapi.c
+
+LIB_CURLX_HFILES = \
+  curlx/base64.h   \
+  curlx/curlx.h    \
+  curlx/dynbuf.h   \
+  curlx/inet_pton.h \
+  curlx/multibyte.h \
+  curlx/nonblock.h \
+  curlx/strparse.h \
+  curlx/timediff.h \
+  curlx/timeval.h  \
+  curlx/version_win32.h \
+  curlx/warnless.h \
+  curlx/winapi.h
+
 LIB_VAUTH_CFILES =      \
   vauth/cleartext.c     \
   vauth/cram.c          \
@@ -39,7 +66,6 @@ LIB_VAUTH_CFILES =      \
 
 LIB_VAUTH_HFILES =      \
   vauth/digest.h        \
-  vauth/ntlm.h          \
   vauth/vauth.h
 
 LIB_VTLS_CFILES =           \
@@ -112,8 +138,8 @@ LIB_CFILES =         \
   altsvc.c           \
   amigaos.c          \
   asyn-ares.c        \
-  asyn-thread.c      \
-  base64.c           \
+  asyn-base.c        \
+  asyn-thrdd.c       \
   bufq.c             \
   bufref.c           \
   cf-h1-proxy.c      \
@@ -126,6 +152,7 @@ LIB_CFILES =         \
   connect.c          \
   content_encoding.c \
   cookie.c           \
+  cshutdn.c          \
   curl_addrinfo.c    \
   curl_des.c         \
   curl_endian.c      \
@@ -134,7 +161,6 @@ LIB_CFILES =         \
   curl_gethostname.c \
   curl_gssapi.c      \
   curl_memrchr.c     \
-  curl_multibyte.c   \
   curl_ntlm_core.c   \
   curl_range.c       \
   curl_rtmp.c        \
@@ -144,15 +170,15 @@ LIB_CFILES =         \
   curl_threads.c     \
   curl_trc.c         \
   cw-out.c           \
+  cw-pause.c         \
   dict.c             \
-  dllmain.c          \
   doh.c              \
-  dynbuf.c           \
   dynhds.c           \
   easy.c             \
   easygetopt.c       \
   easyoptions.c      \
   escape.c           \
+  fake_addrinfo.c    \
   file.c             \
   fileinfo.c         \
   fopen.c            \
@@ -165,11 +191,9 @@ LIB_CFILES =         \
   hash.c             \
   headers.c          \
   hmac.c             \
-  hostasyn.c         \
   hostip.c           \
   hostip4.c          \
   hostip6.c          \
-  hostsyn.c          \
   hsts.c             \
   http.c             \
   http1.c            \
@@ -185,7 +209,6 @@ LIB_CFILES =         \
   if2ip.c            \
   imap.c             \
   inet_ntop.c        \
-  inet_pton.c        \
   krb5.c             \
   ldap.c             \
   llist.c            \
@@ -197,8 +220,8 @@ LIB_CFILES =         \
   mprintf.c          \
   mqtt.c             \
   multi.c            \
+  multi_ev.c         \
   netrc.c            \
-  nonblock.c         \
   noproxy.c          \
   openldap.c         \
   parsedate.c        \
@@ -226,21 +249,19 @@ LIB_CFILES =         \
   splay.c            \
   strcase.c          \
   strdup.c           \
+  strequal.c         \
   strerror.c         \
-  strparse.c         \
-  strtok.c           \
-  strtoofft.c        \
   system_win32.c     \
   telnet.c           \
   tftp.c             \
-  timediff.c         \
-  timeval.c          \
   transfer.c         \
+  uint-bset.c        \
+  uint-hash.c        \
+  uint-spbset.c      \
+  uint-table.c       \
   url.c              \
   urlapi.c           \
   version.c          \
-  version_win32.c    \
-  warnless.c         \
   ws.c
 
 LIB_HFILES =         \
@@ -257,11 +278,11 @@ LIB_HFILES =         \
   cf-socket.h        \
   cfilters.h         \
   conncache.h        \
+  cshutdn.h          \
   connect.h          \
   content_encoding.h \
   cookie.h           \
   curl_addrinfo.h    \
-  curl_base64.h      \
   curl_ctype.h       \
   curl_des.h         \
   curl_endian.h      \
@@ -276,7 +297,6 @@ LIB_HFILES =         \
   curl_md5.h         \
   curl_memory.h      \
   curl_memrchr.h     \
-  curl_multibyte.h   \
   curl_ntlm_core.h   \
   curl_printf.h      \
   curl_range.h       \
@@ -289,16 +309,16 @@ LIB_HFILES =         \
   curl_sspi.h        \
   curl_threads.h     \
   curl_trc.h         \
-  curlx.h            \
   cw-out.h           \
+  cw-pause.h         \
   dict.h             \
   doh.h              \
-  dynbuf.h           \
   dynhds.h           \
   easy_lock.h        \
   easyif.h           \
   easyoptions.h      \
   escape.h           \
+  fake_addrinfo.h    \
   file.h             \
   fileinfo.h         \
   fopen.h            \
@@ -326,16 +346,15 @@ LIB_HFILES =         \
   if2ip.h            \
   imap.h             \
   inet_ntop.h        \
-  inet_pton.h        \
   llist.h            \
   macos.h            \
   memdebug.h         \
   mime.h             \
   mqtt.h             \
   multihandle.h      \
+  multi_ev.h         \
   multiif.h          \
   netrc.h            \
-  nonblock.h         \
   noproxy.h          \
   parsedate.h        \
   pingpong.h         \
@@ -365,25 +384,22 @@ LIB_HFILES =         \
   strcase.h          \
   strdup.h           \
   strerror.h         \
-  strparse.h         \
-  strtok.h           \
-  strtoofft.h        \
   system_win32.h     \
   telnet.h           \
   tftp.h             \
-  timediff.h         \
-  timeval.h          \
   transfer.h         \
+  uint-bset.h        \
+  uint-hash.h        \
+  uint-spbset.h      \
+  uint-table.h       \
   url.h              \
   urlapi-int.h       \
   urldata.h          \
-  version_win32.h    \
-  warnless.h         \
   ws.h
 
 LIB_RCFILES = libcurl.rc
 
 CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
-  $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES)
+  $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) $(LIB_CURLX_CFILES)
 HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
-  $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES)
+  $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) $(LIB_CURLX_HFILES)

+ 155 - 203
Utilities/cmcurl/lib/altsvc.c

@@ -35,12 +35,12 @@
 #include "strcase.h"
 #include "parsedate.h"
 #include "sendf.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 #include "fopen.h"
 #include "rename.h"
 #include "strdup.h"
-#include "inet_pton.h"
-#include "strparse.h"
+#include "curlx/inet_pton.h"
+#include "curlx/strparse.h"
 #include "connect.h"
 
 /* The last 3 #include files should be in this order */
@@ -138,18 +138,20 @@ static struct altsvc *altsvc_create(struct Curl_str *srchost,
                                     size_t srcport,
                                     size_t dstport)
 {
-  enum alpnid dstalpnid = Curl_alpn2alpnid(dstalpn->str, dstalpn->len);
-  enum alpnid srcalpnid = Curl_alpn2alpnid(srcalpn->str, srcalpn->len);
+  enum alpnid dstalpnid =
+    Curl_alpn2alpnid(curlx_str(dstalpn), curlx_strlen(dstalpn));
+  enum alpnid srcalpnid =
+    Curl_alpn2alpnid(curlx_str(srcalpn), curlx_strlen(srcalpn));
   if(!srcalpnid || !dstalpnid)
     return NULL;
-  return altsvc_createid(srchost->str, srchost->len,
-                         dsthost->str, dsthost->len,
+  return altsvc_createid(curlx_str(srchost), curlx_strlen(srchost),
+                         curlx_str(dsthost), curlx_strlen(dsthost),
                          srcalpnid, dstalpnid,
                          srcport, dstport);
 }
 
 /* only returns SERIOUS errors */
-static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
 {
   /* Example line:
      h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
@@ -159,42 +161,42 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
   struct Curl_str srcalpn;
   struct Curl_str dstalpn;
   struct Curl_str date;
-  size_t srcport;
-  size_t dstport;
-  size_t persist;
-  size_t prio;
-
-  if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_word(&line, &srchost, MAX_ALTSVC_HOSTLEN) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_number(&line, &srcport, 65535) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_word(&line, &dstalpn, MAX_ALTSVC_ALPNLEN) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_word(&line, &dsthost, MAX_ALTSVC_HOSTLEN) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_number(&line, &dstport, 65535) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_quotedword(&line, &date, MAX_ALTSVC_DATELEN) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_number(&line, &persist, 1) ||
-     Curl_str_singlespace(&line) ||
-     Curl_str_number(&line, &prio, 0) ||
-     Curl_str_newline(&line))
+  curl_off_t srcport;
+  curl_off_t dstport;
+  curl_off_t persist;
+  curl_off_t prio;
+
+  if(curlx_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_word(&line, &srchost, MAX_ALTSVC_HOSTLEN) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_number(&line, &srcport, 65535) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_word(&line, &dstalpn, MAX_ALTSVC_ALPNLEN) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_word(&line, &dsthost, MAX_ALTSVC_HOSTLEN) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_number(&line, &dstport, 65535) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_quotedword(&line, &date, MAX_ALTSVC_DATELEN) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_number(&line, &persist, 1) ||
+     curlx_str_singlespace(&line) ||
+     curlx_str_number(&line, &prio, 0) ||
+     curlx_str_newline(&line))
     ;
   else {
     struct altsvc *as;
     char dbuf[MAX_ALTSVC_DATELEN + 1];
     time_t expires;
 
-    /* The date parser works on a null terminated string. The maximum length
-       is upheld by Curl_str_quotedword(). */
-    memcpy(dbuf, date.str, date.len);
-    dbuf[date.len] = 0;
+    /* The date parser works on a null-terminated string. The maximum length
+       is upheld by curlx_str_quotedword(). */
+    memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
+    dbuf[curlx_strlen(&date)] = 0;
     expires = Curl_getdate_capped(dbuf);
-    as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport,
-                       dstport);
+    as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
+                       (size_t)srcport, (size_t)dstport);
     if(as) {
       as->expires = expires;
       as->prio = 0; /* not supported to just set zero */
@@ -229,18 +231,14 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
   fp = fopen(file, FOPEN_READTEXT);
   if(fp) {
     struct dynbuf buf;
-    Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
+    curlx_dyn_init(&buf, MAX_ALTSVC_LINE);
     while(Curl_get_line(&buf, fp)) {
-      char *lineptr = Curl_dyn_ptr(&buf);
-      while(*lineptr && ISBLANK(*lineptr))
-        lineptr++;
-      if(*lineptr == '#')
-        /* skip commented lines */
-        continue;
-
-      altsvc_add(asi, lineptr);
+      const char *lineptr = curlx_dyn_ptr(&buf);
+      curlx_str_passblanks(&lineptr);
+      if(curlx_str_single(&lineptr, '#'))
+        altsvc_add(asi, lineptr);
     }
-    Curl_dyn_free(&buf); /* free the line buffer */
+    curlx_dyn_free(&buf); /* free the line buffer */
     fclose(fp);
   }
   return result;
@@ -263,11 +261,11 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
 #ifdef USE_IPV6
   else {
     char ipv6_unused[16];
-    if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
+    if(1 == curlx_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
       dst6_pre = "[";
       dst6_post = "]";
     }
-    if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
+    if(1 == curlx_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
       src6_pre = "[";
       src6_post = "]";
     }
@@ -405,26 +403,6 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
   return result;
 }
 
-static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
-{
-  size_t len;
-  const char *protop;
-  const char *p = *ptr;
-  while(*p && ISBLANK(*p))
-    p++;
-  protop = p;
-  while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
-    p++;
-  len = p - protop;
-  *ptr = p;
-
-  if(!len || (len >= buflen))
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-  memcpy(alpnbuf, protop, len);
-  alpnbuf[len] = 0;
-  return CURLE_OK;
-}
-
 /* hostcompare() returns true if 'host' matches 'check'. The first host
  * argument may have a trailing dot present that will be ignored.
  */
@@ -460,15 +438,16 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
   }
 }
 
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
 /* to play well with debug builds, we can *set* a fixed time this will
    return */
 static time_t altsvc_debugtime(void *unused)
 {
-  char *timestr = getenv("CURL_TIME");
+  const char *timestr = getenv("CURL_TIME");
   (void)unused;
   if(timestr) {
-    long val = strtol(timestr, NULL, 10);
+    curl_off_t val;
+    curlx_str_number(&timestr, &val, TIME_T_MAX);
     return (time_t)val;
   }
   return time(NULL);
@@ -494,153 +473,124 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                            unsigned short srcport)
 {
   const char *p = value;
-  char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
   struct altsvc *as;
   unsigned short dstport = srcport; /* the same by default */
-  CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
   size_t entries = 0;
-  size_t alpnlen = strlen(alpnbuf);
-  size_t srchostlen = strlen(srchost);
+  struct Curl_str alpn;
+  const char *sp;
+  time_t maxage = 24 * 3600; /* default is 24 hours */
+  bool persist = FALSE;
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
 #endif
-  if(result) {
-    infof(data, "Excessive alt-svc header, ignoring.");
-    return CURLE_OK;
-  }
 
   DEBUGASSERT(asi);
 
-  /* "clear" is a magic keyword */
-  if(strcasecompare(alpnbuf, "clear")) {
-    /* Flush cached alternatives for this source origin */
-    altsvc_flush(asi, srcalpnid, srchost, srcport);
-    return CURLE_OK;
+  /* initial check for "clear" */
+  if(!curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') &&
+     !curlx_str_single(&p, ';')) {
+    curlx_str_trimblanks(&alpn);
+    /* "clear" is a magic keyword */
+    if(curlx_str_casecompare(&alpn, "clear")) {
+      /* Flush cached alternatives for this source origin */
+      altsvc_flush(asi, srcalpnid, srchost, srcport);
+      return CURLE_OK;
+    }
+  }
+
+  p = value;
+
+  if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
+    return CURLE_OK; /* strange line */
+
+  curlx_str_trimblanks(&alpn);
+
+  /* Handle the optional 'ma' and 'persist' flags once first, as they need to
+     be known for each alternative service. Unknown flags are skipped. */
+  sp = strchr(p, ';');
+  if(sp) {
+    sp++; /* pass the semicolon */
+    for(;;) {
+      struct Curl_str name;
+      struct Curl_str val;
+      const char *vp;
+      curl_off_t num;
+      bool quoted;
+      /* allow some extra whitespaces around name and value */
+      if(curlx_str_until(&sp, &name, 20, '=') ||
+         curlx_str_single(&sp, '=') ||
+         curlx_str_until(&sp, &val, 80, ';'))
+        break;
+      curlx_str_trimblanks(&name);
+      curlx_str_trimblanks(&val);
+      /* the value might be quoted */
+      vp = curlx_str(&val);
+      quoted = (*vp == '\"');
+      if(quoted)
+        vp++;
+      if(!curlx_str_number(&vp, &num, TIME_T_MAX)) {
+        if(curlx_str_casecompare(&name, "ma"))
+          maxage = (time_t)num;
+        else if(curlx_str_casecompare(&name, "persist") && (num == 1))
+          persist = TRUE;
+      }
+      if(quoted && curlx_str_single(&sp, '\"'))
+        break;
+      if(curlx_str_single(&sp, ';'))
+        break;
+    }
   }
 
   do {
-    if(*p == '=') {
-      /* [protocol]="[host][:port]" */
-      enum alpnid dstalpnid = Curl_alpn2alpnid(alpnbuf, alpnlen);
-      p++;
-      if(*p == '\"') {
-        const char *dsthost = "";
-        size_t dstlen = 0; /* destination hostname length */
-        const char *value_ptr;
-        char option[32];
-        unsigned long num;
-        char *end_ptr;
-        bool quoted = FALSE;
-        time_t maxage = 24 * 3600; /* default is 24 hours */
-        bool persist = FALSE;
-        bool valid = TRUE;
-        p++;
-        if(*p != ':') {
+    if(!curlx_str_single(&p, '=')) {
+      /* [protocol]="[host][:port], [protocol]="[host][:port]" */
+      enum alpnid dstalpnid =
+        Curl_alpn2alpnid(curlx_str(&alpn), curlx_strlen(&alpn));
+      if(!curlx_str_single(&p, '\"')) {
+        struct Curl_str dsthost;
+        curl_off_t port = 0;
+        if(curlx_str_single(&p, ':')) {
           /* hostname starts here */
-          const char *hostp = p;
-          if(*p == '[') {
-            /* pass all valid IPv6 letters - does not handle zone id */
-            dstlen = strspn(++p, "0123456789abcdefABCDEF:.");
-            if(p[dstlen] != ']')
-              /* invalid host syntax, bail out */
+          if(curlx_str_single(&p, '[')) {
+            if(curlx_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
+              infof(data, "Bad alt-svc hostname, ignoring.");
               break;
-            /* we store the IPv6 numerical address *with* brackets */
-            dstlen += 2;
-            p = &p[dstlen-1];
+            }
           }
           else {
-            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
-              p++;
-            dstlen = p - hostp;
-          }
-          if(!dstlen || (dstlen >= MAX_ALTSVC_HOSTLEN)) {
-            infof(data, "Excessive alt-svc hostname, ignoring.");
-            valid = FALSE;
-          }
-          else {
-            dsthost = hostp;
+            /* IPv6 host name */
+            if(curlx_str_until(&p, &dsthost, MAX_IPADR_LEN, ']') ||
+               curlx_str_single(&p, ']')) {
+              infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
+              break;
+            }
           }
+          if(curlx_str_single(&p, ':'))
+            break;
         }
-        else {
+        else
           /* no destination name, use source host */
-          dsthost = srchost;
-          dstlen = strlen(srchost);
-        }
-        if(*p == ':') {
-          unsigned long port = 0;
-          p++;
-          if(ISDIGIT(*p))
-            /* a port number */
-            port = strtoul(p, &end_ptr, 10);
-          else
-            end_ptr = (char *)p; /* not left uninitialized */
-          if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
-            infof(data, "Unknown alt-svc port number, ignoring.");
-            valid = FALSE;
-          }
-          else {
-            dstport = curlx_ultous(port);
-            p = end_ptr;
-          }
-        }
-        if(*p++ != '\"')
+          curlx_str_assign(&dsthost, srchost, strlen(srchost));
+
+        if(curlx_str_number(&p, &port, 0xffff)) {
+          infof(data, "Unknown alt-svc port number, ignoring.");
           break;
-        /* Handle the optional 'ma' and 'persist' flags. Unknown flags
-           are skipped. */
-        for(;;) {
-          while(ISBLANK(*p))
-            p++;
-          if(*p != ';')
-            break;
-          p++; /* pass the semicolon */
-          if(!*p || ISNEWLINE(*p))
-            break;
-          result = getalnum(&p, option, sizeof(option));
-          if(result) {
-            /* skip option if name is too long */
-            option[0] = '\0';
-          }
-          while(*p && ISBLANK(*p))
-            p++;
-          if(*p != '=')
-            return CURLE_OK;
-          p++;
-          while(*p && ISBLANK(*p))
-            p++;
-          if(!*p)
-            return CURLE_OK;
-          if(*p == '\"') {
-            /* quoted value */
-            p++;
-            quoted = TRUE;
-          }
-          value_ptr = p;
-          if(quoted) {
-            while(*p && *p != '\"')
-              p++;
-            if(!*p++)
-              return CURLE_OK;
-          }
-          else {
-            while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
-              p++;
-          }
-          num = strtoul(value_ptr, &end_ptr, 10);
-          if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
-            if(strcasecompare("ma", option))
-              maxage = (time_t)num;
-            else if(strcasecompare("persist", option) && (num == 1))
-              persist = TRUE;
-          }
         }
-        if(dstalpnid && valid) {
+
+        dstport = (unsigned short)port;
+
+        if(curlx_str_single(&p, '\"'))
+          break;
+
+        if(dstalpnid) {
           if(!entries++)
             /* Flush cached alternatives for this source origin, if any - when
                this is the first entry of the line. */
             altsvc_flush(asi, srcalpnid, srchost, srcport);
 
-          as = altsvc_createid(srchost, srchostlen,
-                               dsthost, dstlen,
+          as = altsvc_createid(srchost, strlen(srchost),
+                               curlx_str(&dsthost),
+                               curlx_strlen(&dsthost),
                                srcalpnid, dstalpnid,
                                srcport, dstport);
           if(as) {
@@ -653,26 +603,28 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
               as->expires = maxage + secs;
             as->persist = persist;
             Curl_llist_append(&asi->list, as, &as->node);
-            infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
-                  Curl_alpnid2str(dstalpnid));
+            infof(data, "Added alt-svc: %.*s:%d over %s",
+                  (int)curlx_strlen(&dsthost), curlx_str(&dsthost),
+                  dstport, Curl_alpnid2str(dstalpnid));
           }
         }
       }
       else
         break;
+
       /* after the double quote there can be a comma if there is another
          string or a semicolon if no more */
-      if(*p == ',') {
-        /* comma means another alternative is presented */
-        p++;
-        result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
-        if(result)
-          break;
-      }
+      if(curlx_str_single(&p, ','))
+        break;
+
+      /* comma means another alternative is present */
+      if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
+        break;
+      curlx_str_trimblanks(&alpn);
     }
     else
       break;
-  } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
+  } while(1);
 
   return CURLE_OK;
 }

+ 2 - 2
Utilities/cmcurl/lib/altsvc.h

@@ -39,9 +39,9 @@ struct altsvc {
   struct althost src;
   struct althost dst;
   time_t expires;
-  bool persist;
-  unsigned int prio;
   struct Curl_llist_node node;
+  unsigned int prio;
+  BIT(persist);
 };
 
 struct altsvcinfo {

+ 1 - 1
Utilities/cmcurl/lib/amigaos.c

@@ -184,7 +184,7 @@ int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
 {
   int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0);
   /* Ensure Ctrl-C signal is actioned */
-  if((r == -1) && (SOCKERRNO == EINTR))
+  if((r == -1) && (SOCKERRNO == SOCKEINTR))
     raise(SIGINT);
   return r;
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 387 - 443
Utilities/cmcurl/lib/asyn-ares.c


+ 196 - 0
Utilities/cmcurl/lib/asyn-base.c

@@ -0,0 +1,196 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef USE_ARES
+#include <ares.h>
+#include <ares_version.h> /* really old c-ares did not include this by
+                             itself */
+#endif
+
+#include "urldata.h"
+#include "asyn.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "multiif.h"
+#include "select.h"
+#include "share.h"
+#include "url.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
+
+#ifdef USE_ARES
+
+#if ARES_VERSION < 0x010600
+#error "requires c-ares 1.6.0 or newer"
+#endif
+
+/*
+ * Curl_ares_getsock() is called when the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we are talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_ares_getsock(struct Curl_easy *data,
+                      ares_channel channel,
+                      curl_socket_t *socks)
+{
+  struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
+  struct timeval timebuf;
+  int max = ares_getsock(channel,
+                         (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
+  struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
+  timediff_t milli = curlx_tvtoms(timeout);
+  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+  return max;
+}
+
+/*
+ * Curl_ares_perform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on, or -1 on error
+ */
+int Curl_ares_perform(ares_channel channel,
+                      timediff_t timeout_ms)
+{
+  int nfds;
+  int bitmask;
+  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+  int i;
+  int num = 0;
+
+  if(!channel)
+    return 0;
+
+  bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
+
+  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
+    pfd[i].events = 0;
+    pfd[i].revents = 0;
+    if(ARES_GETSOCK_READABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLRDNORM|POLLIN;
+    }
+    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLWRNORM|POLLOUT;
+    }
+    if(pfd[i].events)
+      num++;
+    else
+      break;
+  }
+
+  if(num) {
+    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
+    if(nfds < 0)
+      return -1;
+  }
+  else
+    nfds = 0;
+
+  if(!nfds)
+    /* Call ares_process() unconditionally here, even if we simply timed out
+       above, as otherwise the ares name resolve will not timeout! */
+    ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+  else {
+    /* move through the descriptors and ask for processing on them */
+    for(i = 0; i < num; i++)
+      ares_process_fd(channel,
+                      (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD,
+                      (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD);
+  }
+  return nfds;
+}
+
+#endif
+
+#endif /* CURLRES_ASYNCH */
+
+#ifdef USE_CURL_ASYNC
+
+#include "doh.h"
+
+void Curl_async_shutdown(struct Curl_easy *data)
+{
+#ifdef CURLRES_ARES
+  Curl_async_ares_shutdown(data);
+#endif
+#ifdef CURLRES_THREADED
+  Curl_async_thrdd_shutdown(data);
+#endif
+#ifndef CURL_DISABLE_DOH
+  Curl_doh_cleanup(data);
+#endif
+  Curl_safefree(data->state.async.hostname);
+}
+
+void Curl_async_destroy(struct Curl_easy *data)
+{
+#ifdef CURLRES_ARES
+  Curl_async_ares_destroy(data);
+#endif
+#ifdef CURLRES_THREADED
+  Curl_async_thrdd_destroy(data);
+#endif
+#ifndef CURL_DISABLE_DOH
+  Curl_doh_cleanup(data);
+#endif
+  Curl_safefree(data->state.async.hostname);
+}
+
+#endif /* USE_CURL_ASYNC */

+ 760 - 0
Utilities/cmcurl/lib/asyn-thrdd.c

@@ -0,0 +1,760 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "socketpair.h"
+
+/***********************************************************************
+ * Only for threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+#  include <pthread.h>
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#  define RESOLVER_ENOMEM  EAI_MEMORY  /* = WSA_NOT_ENOUGH_MEMORY on Windows */
+#else
+#  define RESOLVER_ENOMEM  SOCKENOMEM
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_ntop.h"
+#include "curl_threads.h"
+#include "strdup.h"
+
+#ifdef USE_ARES
+#include <ares.h>
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES  /* the combo */
+#endif
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/*
+ * Curl_async_global_init()
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Does nothing here.
+ */
+int Curl_async_global_init(void)
+{
+#if defined(USE_ARES) && defined(CARES_HAVE_ARES_LIBRARY_INIT)
+  if(ares_library_init(ARES_LIB_INIT_ALL)) {
+    return CURLE_FAILED_INIT;
+  }
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * Curl_async_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Does nothing here.
+ */
+void Curl_async_global_cleanup(void)
+{
+#if defined(USE_ARES) && defined(CARES_HAVE_ARES_LIBRARY_INIT)
+  ares_library_cleanup();
+#endif
+}
+
+static void async_thrdd_destroy(struct Curl_easy *);
+
+CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl)
+{
+  (void)data;
+  *impl = NULL;
+  return CURLE_OK;
+}
+
+/* Destroy context of threaded resolver */
+static void addr_ctx_destroy(struct async_thrdd_addr_ctx *addr_ctx)
+{
+  if(addr_ctx) {
+    DEBUGASSERT(!addr_ctx->ref_count);
+    Curl_mutex_destroy(&addr_ctx->mutx);
+    free(addr_ctx->hostname);
+    if(addr_ctx->res)
+      Curl_freeaddrinfo(addr_ctx->res);
+#ifndef CURL_DISABLE_SOCKETPAIR
+  /*
+   * close one end of the socket pair (may be done in resolver thread);
+   * the other end (for reading) is always closed in the parent thread.
+   */
+#ifndef USE_EVENTFD
+  if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
+    wakeup_close(addr_ctx->sock_pair[1]);
+  }
+#endif
+#endif
+    free(addr_ctx);
+  }
+}
+
+/* Initialize context for threaded resolver */
+static struct async_thrdd_addr_ctx *
+addr_ctx_create(const char *hostname, int port,
+                const struct addrinfo *hints)
+{
+  struct async_thrdd_addr_ctx *addr_ctx = calloc(1, sizeof(*addr_ctx));
+  if(!addr_ctx)
+    return NULL;
+
+  addr_ctx->thread_hnd = curl_thread_t_null;
+  addr_ctx->port = port;
+#ifndef CURL_DISABLE_SOCKETPAIR
+  addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
+  addr_ctx->sock_pair[1] = CURL_SOCKET_BAD;
+#endif
+  addr_ctx->ref_count = 0;
+
+#ifdef HAVE_GETADDRINFO
+  DEBUGASSERT(hints);
+  addr_ctx->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  Curl_mutex_init(&addr_ctx->mutx);
+
+#ifndef CURL_DISABLE_SOCKETPAIR
+  /* create socket pair or pipe */
+  if(wakeup_create(addr_ctx->sock_pair, FALSE) < 0) {
+    addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
+    addr_ctx->sock_pair[1] = CURL_SOCKET_BAD;
+    goto err_exit;
+  }
+#endif
+  addr_ctx->sock_error = CURL_ASYNC_SUCCESS;
+
+  /* Copying hostname string because original can be destroyed by parent
+   * thread during gethostbyname execution.
+   */
+  addr_ctx->hostname = strdup(hostname);
+  if(!addr_ctx->hostname)
+    goto err_exit;
+
+  addr_ctx->ref_count = 1;
+  return addr_ctx;
+
+err_exit:
+#ifndef CURL_DISABLE_SOCKETPAIR
+  if(addr_ctx->sock_pair[0] != CURL_SOCKET_BAD) {
+    wakeup_close(addr_ctx->sock_pair[0]);
+    addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
+  }
+#endif
+  addr_ctx_destroy(addr_ctx);
+  return NULL;
+}
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with USE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
+DWORD
+#else
+unsigned int
+#endif
+CURL_STDCALL getaddrinfo_thread(void *arg)
+{
+  struct async_thrdd_addr_ctx *addr_ctx = arg;
+  char service[12];
+  int rc;
+  bool all_gone;
+
+  msnprintf(service, sizeof(service), "%d", addr_ctx->port);
+
+  rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service,
+                           &addr_ctx->hints, &addr_ctx->res);
+
+  if(rc) {
+    addr_ctx->sock_error = SOCKERRNO ? SOCKERRNO : rc;
+    if(addr_ctx->sock_error == 0)
+      addr_ctx->sock_error = RESOLVER_ENOMEM;
+  }
+  else {
+    Curl_addrinfo_set_port(addr_ctx->res, addr_ctx->port);
+  }
+
+  Curl_mutex_acquire(&addr_ctx->mutx);
+  if(addr_ctx->ref_count > 1) {
+    /* Someone still waiting on our results. */
+#ifndef CURL_DISABLE_SOCKETPAIR
+    if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
+#ifdef USE_EVENTFD
+      const uint64_t buf[1] = { 1 };
+#else
+      const char buf[1] = { 1 };
+#endif
+      /* DNS has been resolved, signal client task */
+      if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) {
+        /* update sock_erro to errno */
+        addr_ctx->sock_error = SOCKERRNO;
+      }
+    }
+#endif
+  }
+  /* thread gives up its reference to the shared data now. */
+  --addr_ctx->ref_count;
+  all_gone = !addr_ctx->ref_count;
+  Curl_mutex_release(&addr_ctx->mutx);
+  if(all_gone)
+    addr_ctx_destroy(addr_ctx);
+
+  return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
+DWORD
+#else
+unsigned int
+#endif
+CURL_STDCALL gethostbyname_thread(void *arg)
+{
+  struct async_thrdd_addr_ctx *addr_ctx = arg;
+  bool all_gone;
+
+  addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port);
+
+  if(!addr_ctx->res) {
+    addr_ctx->sock_error = SOCKERRNO;
+    if(addr_ctx->sock_error == 0)
+      addr_ctx->sock_error = RESOLVER_ENOMEM;
+  }
+
+  Curl_mutex_acquire(&addr_ctx->mutx);
+  /* thread gives up its reference to the shared data now. */
+  --addr_ctx->ref_count;
+  all_gone = !addr_ctx->ref_count;;
+  Curl_mutex_release(&addr_ctx->mutx);
+  if(all_gone)
+    addr_ctx_destroy(addr_ctx);
+
+  return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * async_thrdd_destroy() cleans up async resolver data and thread handle.
+ */
+static void async_thrdd_destroy(struct Curl_easy *data)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  struct async_thrdd_addr_ctx *addr = thrdd->addr;
+#ifdef USE_HTTPSRR_ARES
+  if(thrdd->rr.channel) {
+    ares_destroy(thrdd->rr.channel);
+    thrdd->rr.channel = NULL;
+  }
+  Curl_httpsrr_cleanup(&thrdd->rr.hinfo);
+#endif
+
+  if(addr) {
+#ifndef CURL_DISABLE_SOCKETPAIR
+    curl_socket_t sock_rd = addr->sock_pair[0];
+#endif
+    bool done;
+
+    /* Release our reference to the data shared with the thread. */
+    Curl_mutex_acquire(&addr->mutx);
+    --addr->ref_count;
+    CURL_TRC_DNS(data, "resolve, destroy async data, shared ref=%d",
+                 addr->ref_count);
+    done = !addr->ref_count;
+    /* we give up our reference to `addr`, so NULL our pointer.
+     * coverity analyses this as being a potential unsynched write,
+     * assuming two calls to this function could be invoked concurrently.
+     * Which they never are, as the transfer's side runs single-threaded. */
+    thrdd->addr = NULL;
+    if(!done) {
+      /* thread is still running. Detach the thread while mutexed, it will
+       * trigger the cleanup when it releases its reference. */
+      Curl_thread_destroy(&addr->thread_hnd);
+    }
+    Curl_mutex_release(&addr->mutx);
+
+    if(done) {
+      /* thread has released its reference, join it and
+       * release the memory we shared with it. */
+      if(addr->thread_hnd != curl_thread_t_null)
+        Curl_thread_join(&addr->thread_hnd);
+      addr_ctx_destroy(addr);
+    }
+#ifndef CURL_DISABLE_SOCKETPAIR
+    /*
+     * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
+     * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
+     */
+    Curl_multi_will_close(data, sock_rd);
+    wakeup_close(sock_rd);
+#endif
+  }
+}
+
+#ifdef USE_HTTPSRR_ARES
+
+static void async_thrdd_rr_done(void *user_data, ares_status_t status,
+                                size_t timeouts,
+                                const ares_dns_record_t *dnsrec)
+{
+  struct Curl_easy *data = user_data;
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+
+  (void)timeouts;
+  thrdd->rr.done = TRUE;
+  if((ARES_SUCCESS != status) || !dnsrec)
+    return;
+  thrdd->rr.result = Curl_httpsrr_from_ares(data, dnsrec, &thrdd->rr.hinfo);
+}
+
+static CURLcode async_rr_start(struct Curl_easy *data)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  int status;
+
+  DEBUGASSERT(!thrdd->rr.channel);
+  status = ares_init_options(&thrdd->rr.channel, NULL, 0);
+  if(status != ARES_SUCCESS) {
+    thrdd->rr.channel = NULL;
+    return CURLE_FAILED_INIT;
+  }
+
+  memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo));
+  thrdd->rr.hinfo.port = -1;
+  ares_query_dnsrec(thrdd->rr.channel,
+                    data->conn->host.name, ARES_CLASS_IN,
+                    ARES_REC_TYPE_HTTPS,
+                    async_thrdd_rr_done, data, NULL);
+  return CURLE_OK;
+}
+#endif
+
+/*
+ * async_thrdd_init() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool async_thrdd_init(struct Curl_easy *data,
+                             const char *hostname, int port, int ip_version,
+                             const struct addrinfo *hints)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  struct async_thrdd_addr_ctx *addr_ctx;
+
+  /* !checksrc! disable ERRNOVAR 1 */
+  int err = ENOMEM;
+
+  if(thrdd->addr
+#ifdef USE_HTTPSRR_ARES
+     || thrdd->rr.channel
+#endif
+     ) {
+    CURL_TRC_DNS(data, "starting new resolve, with previous not cleaned up");
+    async_thrdd_destroy(data);
+    DEBUGASSERT(!thrdd->addr);
+#ifdef USE_HTTPSRR_ARES
+    DEBUGASSERT(!thrdd->rr.channel);
+#endif
+  }
+
+  data->state.async.dns = NULL;
+  data->state.async.done = FALSE;
+  data->state.async.port = port;
+  data->state.async.ip_version = ip_version;
+  data->state.async.hostname = strdup(hostname);
+  if(!data->state.async.hostname)
+    goto err_exit;
+
+  addr_ctx = addr_ctx_create(hostname, port, hints);
+  if(!addr_ctx)
+    goto err_exit;
+  thrdd->addr = addr_ctx;
+
+  Curl_mutex_acquire(&addr_ctx->mutx);
+  DEBUGASSERT(addr_ctx->ref_count == 1);
+  /* passing addr_ctx to the thread adds a reference */
+  addr_ctx->start = curlx_now();
+  ++addr_ctx->ref_count;
+#ifdef HAVE_GETADDRINFO
+  addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx);
+#else
+  addr_ctx->thread_hnd = Curl_thread_create(gethostbyname_thread, addr_ctx);
+#endif
+  if(addr_ctx->thread_hnd == curl_thread_t_null) {
+    /* The thread never started, remove its reference that never happened. */
+    --addr_ctx->ref_count;
+    err = errno;
+    Curl_mutex_release(&addr_ctx->mutx);
+    goto err_exit;
+  }
+  Curl_mutex_release(&addr_ctx->mutx);
+
+#ifdef USE_HTTPSRR_ARES
+  if(async_rr_start(data))
+    infof(data, "Failed HTTPS RR operation");
+#endif
+  CURL_TRC_DNS(data, "resolve thread started for of %s:%d", hostname, port);
+  return TRUE;
+
+err_exit:
+  CURL_TRC_DNS(data, "resolve thread failed init: %d", err);
+  async_thrdd_destroy(data);
+  CURL_SETERRNO(err);
+  return FALSE;
+}
+
+/*
+ * 'entry' may be NULL and then no data is returned
+ */
+static CURLcode asyn_thrdd_await(struct Curl_easy *data,
+                                 struct async_thrdd_addr_ctx *addr_ctx,
+                                 struct Curl_dns_entry **entry)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null);
+
+  CURL_TRC_DNS(data, "resolve, wait for thread to finish");
+  /* wait for the thread to resolve the name */
+  if(Curl_thread_join(&addr_ctx->thread_hnd)) {
+    if(entry)
+      result = Curl_async_is_resolved(data, entry);
+  }
+  else
+    DEBUGASSERT(0);
+
+  data->state.async.done = TRUE;
+  if(entry)
+    *entry = data->state.async.dns;
+
+  async_thrdd_destroy(data);
+  return result;
+}
+
+
+/*
+ * Until we gain a way to signal the resolver threads to stop early, we must
+ * simply wait for them and ignore their results.
+ */
+void Curl_async_thrdd_shutdown(struct Curl_easy *data)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+
+  /* If we are 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(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null) &&
+     !data->set.quick_exit)
+    (void)asyn_thrdd_await(data, thrdd->addr, NULL);
+  else
+    async_thrdd_destroy(data);
+}
+
+void Curl_async_thrdd_destroy(struct Curl_easy *data)
+{
+  Curl_async_thrdd_shutdown(data);
+}
+
+/*
+ * Curl_async_await()
+ *
+ * Waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_async_await(struct Curl_easy *data,
+                          struct Curl_dns_entry **entry)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  if(thrdd->addr)
+    return asyn_thrdd_await(data, thrdd->addr, entry);
+  return CURLE_FAILED_INIT;
+}
+
+/*
+ * Curl_async_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ */
+CURLcode Curl_async_is_resolved(struct Curl_easy *data,
+                                struct Curl_dns_entry **dns)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  bool done = FALSE;
+
+  DEBUGASSERT(dns);
+  *dns = NULL;
+
+  if(data->state.async.done) {
+    *dns = data->state.async.dns;
+    CURL_TRC_DNS(data, "threaded: is_resolved(), already done, dns=%sfound",
+                 *dns ? "" : "not ");
+    return CURLE_OK;
+  }
+
+#ifdef USE_HTTPSRR_ARES
+  /* best effort, ignore errors */
+  if(thrdd->rr.channel)
+    (void)Curl_ares_perform(thrdd->rr.channel, 0);
+#endif
+
+  DEBUGASSERT(thrdd->addr);
+  if(!thrdd->addr)
+    return CURLE_FAILED_INIT;
+
+  Curl_mutex_acquire(&thrdd->addr->mutx);
+  done = (thrdd->addr->ref_count == 1);
+  Curl_mutex_release(&thrdd->addr->mutx);
+
+  if(done) {
+    CURLcode result = CURLE_OK;
+
+    data->state.async.done = TRUE;
+    Curl_resolv_unlink(data, &data->state.async.dns);
+
+    if(thrdd->addr->res) {
+      data->state.async.dns =
+        Curl_dnscache_mk_entry(data, thrdd->addr->res,
+                               data->state.async.hostname, 0,
+                               data->state.async.port, FALSE);
+      thrdd->addr->res = NULL;
+      if(!data->state.async.dns)
+        result = CURLE_OUT_OF_MEMORY;
+
+#ifdef USE_HTTPSRR_ARES
+      if(thrdd->rr.channel) {
+        result = thrdd->rr.result;
+        if(!result) {
+          struct Curl_https_rrinfo *lhrr;
+          lhrr = Curl_httpsrr_dup_move(&thrdd->rr.hinfo);
+          if(!lhrr)
+            result = CURLE_OUT_OF_MEMORY;
+          else
+            data->state.async.dns->hinfo = lhrr;
+        }
+      }
+#endif
+      if(!result && data->state.async.dns)
+        result = Curl_dnscache_add(data, data->state.async.dns);
+    }
+
+    if(!result && !data->state.async.dns)
+      result = Curl_resolver_error(data);
+    if(result)
+      Curl_resolv_unlink(data, &data->state.async.dns);
+    *dns = data->state.async.dns;
+    CURL_TRC_DNS(data, "is_resolved() result=%d, dns=%sfound",
+                 result, *dns ? "" : "not ");
+    async_thrdd_destroy(data);
+    return result;
+  }
+  else {
+    /* poll for name lookup done with exponential backoff up to 250ms */
+    /* should be fine even if this converts to 32-bit */
+    timediff_t elapsed = curlx_timediff(curlx_now(),
+                                       data->progress.t_startsingle);
+    if(elapsed < 0)
+      elapsed = 0;
+
+    if(thrdd->addr->poll_interval == 0)
+      /* Start at 1ms poll interval */
+      thrdd->addr->poll_interval = 1;
+    else if(elapsed >= thrdd->addr->interval_end)
+      /* Back-off exponentially if last interval expired  */
+      thrdd->addr->poll_interval *= 2;
+
+    if(thrdd->addr->poll_interval > 250)
+      thrdd->addr->poll_interval = 250;
+
+    thrdd->addr->interval_end = elapsed + thrdd->addr->poll_interval;
+    Curl_expire(data, thrdd->addr->poll_interval, EXPIRE_ASYNC_NAME);
+    return CURLE_OK;
+  }
+}
+
+int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
+  int ret_val = 0;
+#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
+  int socketi = 0;
+#else
+  (void)socks;
+#endif
+
+#ifdef USE_HTTPSRR_ARES
+  if(thrdd->rr.channel) {
+    ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks);
+    for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
+      if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
+         !ARES_GETSOCK_WRITABLE(ret_val, socketi))
+        break;
+  }
+#endif
+  if(!thrdd->addr)
+    return ret_val;
+
+#ifndef CURL_DISABLE_SOCKETPAIR
+  if(thrdd->addr) {
+    /* return read fd to client for polling the DNS resolution status */
+    socks[socketi] = thrdd->addr->sock_pair[0];
+    ret_val |= GETSOCK_READSOCK(socketi);
+  }
+  else
+#endif
+  {
+    timediff_t milli;
+    timediff_t ms = curlx_timediff(curlx_now(), thrdd->addr->start);
+    if(ms < 3)
+      milli = 0;
+    else if(ms <= 50)
+      milli = ms/3;
+    else if(ms <= 250)
+      milli = 50;
+    else
+      milli = 200;
+    Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+  }
+
+  return ret_val;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_async_getaddrinfo() - for platforms without getaddrinfo
+ */
+struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
+                                             const char *hostname,
+                                             int port,
+                                             int ip_version,
+                                             int *waitp)
+{
+  (void)ip_version;
+  *waitp = 0; /* default to synchronous response */
+
+  /* fire up a new resolver thread! */
+  if(async_thrdd_init(data, hostname, port, ip_version, NULL)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  failf(data, "getaddrinfo() thread failed");
+
+  return NULL;
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_async_getaddrinfo() - for getaddrinfo
+ */
+struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
+                                             const char *hostname,
+                                             int port,
+                                             int ip_version,
+                                             int *waitp)
+{
+  struct addrinfo hints;
+  int pf = PF_INET;
+  *waitp = 0; /* default to synchronous response */
+
+  CURL_TRC_DNS(data, "init threaded resolve of %s:%d", hostname, port);
+#ifdef CURLRES_IPV6
+  if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
+    /* The stack seems to be IPv6-enabled */
+    if(ip_version == CURL_IPRESOLVE_V6)
+      pf = PF_INET6;
+    else
+      pf = PF_UNSPEC;
+  }
+#else
+  (void)ip_version;
+#endif /* CURLRES_IPV6 */
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+    SOCK_STREAM : SOCK_DGRAM;
+
+  /* fire up a new resolver thread! */
+  if(async_thrdd_init(data, hostname, port, ip_version, &hints)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  failf(data, "getaddrinfo() thread failed to start");
+  return NULL;
+
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+#endif /* CURLRES_THREADED */

+ 0 - 812
Utilities/cmcurl/lib/asyn-thread.c

@@ -1,812 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, 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
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-#include "socketpair.h"
-
-/***********************************************************************
- * Only for threaded name resolves builds
- **********************************************************************/
-#ifdef CURLRES_THREADED
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef __VMS
-#include <in.h>
-#include <inet.h>
-#endif
-
-#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
-#  include <pthread.h>
-#endif
-
-#ifdef HAVE_GETADDRINFO
-#  define RESOLVER_ENOMEM  EAI_MEMORY
-#else
-#  define RESOLVER_ENOMEM  ENOMEM
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "url.h"
-#include "multiif.h"
-#include "inet_ntop.h"
-#include "curl_threads.h"
-#include "connect.h"
-#include "strdup.h"
-
-#ifdef USE_ARES
-#include <ares.h>
-#ifdef USE_HTTPSRR
-#define USE_HTTPSRR_ARES 1 /* the combo */
-#endif
-#endif
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-struct resdata {
-  struct curltime start;
-};
-
-/*
- * Curl_resolver_global_init()
- * Called from curl_global_init() to initialize global resolver environment.
- * Does nothing here.
- */
-int Curl_resolver_global_init(void)
-{
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_global_cleanup()
- * Called from curl_global_cleanup() to destroy global resolver environment.
- * Does nothing here.
- */
-void Curl_resolver_global_cleanup(void)
-{
-}
-
-/*
- * Curl_resolver_init()
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).
- */
-CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
-{
-  (void)easy;
-  *resolver = calloc(1, sizeof(struct resdata));
-  if(!*resolver)
-    return CURLE_OUT_OF_MEMORY;
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_cleanup()
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).
- */
-void Curl_resolver_cleanup(void *resolver)
-{
-  free(resolver);
-}
-
-/*
- * Curl_resolver_duphandle()
- * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
- * environment ('resolver' member of the UrlState structure).
- */
-CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
-{
-  (void)from;
-  return Curl_resolver_init(easy, to);
-}
-
-static void destroy_async_data(struct Curl_easy *);
-
-/*
- * Cancel all possibly still on-going resolves for this connection.
- */
-void Curl_resolver_cancel(struct Curl_easy *data)
-{
-  destroy_async_data(data);
-}
-
-/* This function is used to init a threaded resolve */
-static bool init_resolve_thread(struct Curl_easy *data,
-                                const char *hostname, int port,
-                                const struct addrinfo *hints);
-
-
-static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
-{
-  return &(data->state.async.tdata->tsd);
-}
-
-/* Destroy resolver thread synchronization data */
-static
-void destroy_thread_sync_data(struct thread_sync_data *tsd)
-{
-  if(tsd->mtx) {
-    Curl_mutex_destroy(tsd->mtx);
-    free(tsd->mtx);
-  }
-
-  free(tsd->hostname);
-
-  if(tsd->res)
-    Curl_freeaddrinfo(tsd->res);
-
-#ifndef CURL_DISABLE_SOCKETPAIR
-  /*
-   * close one end of the socket pair (may be done in resolver thread);
-   * the other end (for reading) is always closed in the parent thread.
-   */
-#ifndef USE_EVENTFD
-  if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-    wakeup_close(tsd->sock_pair[1]);
-  }
-#endif
-#endif
-  memset(tsd, 0, sizeof(*tsd));
-}
-
-/* Initialize resolver thread synchronization data */
-static
-int init_thread_sync_data(struct thread_data *td,
-                           const char *hostname,
-                           int port,
-                           const struct addrinfo *hints)
-{
-  struct thread_sync_data *tsd = &td->tsd;
-
-  memset(tsd, 0, sizeof(*tsd));
-
-  tsd->td = td;
-  tsd->port = port;
-  /* Treat the request as done until the thread actually starts so any early
-   * cleanup gets done properly.
-   */
-  tsd->done = TRUE;
-#ifdef HAVE_GETADDRINFO
-  DEBUGASSERT(hints);
-  tsd->hints = *hints;
-#else
-  (void) hints;
-#endif
-
-  tsd->mtx = malloc(sizeof(curl_mutex_t));
-  if(!tsd->mtx)
-    goto err_exit;
-
-  Curl_mutex_init(tsd->mtx);
-
-#ifndef CURL_DISABLE_SOCKETPAIR
-  /* create socket pair or pipe */
-  if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
-    tsd->sock_pair[0] = CURL_SOCKET_BAD;
-    tsd->sock_pair[1] = CURL_SOCKET_BAD;
-    goto err_exit;
-  }
-#endif
-  tsd->sock_error = CURL_ASYNC_SUCCESS;
-
-  /* Copying hostname string because original can be destroyed by parent
-   * thread during gethostbyname execution.
-   */
-  tsd->hostname = strdup(hostname);
-  if(!tsd->hostname)
-    goto err_exit;
-
-  return 1;
-
-err_exit:
-#ifndef CURL_DISABLE_SOCKETPAIR
-  if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
-    wakeup_close(tsd->sock_pair[0]);
-    tsd->sock_pair[0] = CURL_SOCKET_BAD;
-  }
-#endif
-  destroy_thread_sync_data(tsd);
-  return 0;
-}
-
-static CURLcode getaddrinfo_complete(struct Curl_easy *data)
-{
-  struct thread_sync_data *tsd = conn_thread_sync_data(data);
-  CURLcode result;
-
-  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
-  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
-     cache. Set our copy to NULL so destroy_thread_sync_data does not free it.
-  */
-  tsd->res = NULL;
-
-  return result;
-}
-
-
-#ifdef HAVE_GETADDRINFO
-
-/*
- * getaddrinfo_thread() resolves a name and then exits.
- *
- * For builds without ARES, but with USE_IPV6, create a resolver thread
- * and wait on it.
- */
-static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
-DWORD
-#else
-unsigned int
-#endif
-CURL_STDCALL getaddrinfo_thread(void *arg)
-{
-  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
-  struct thread_data *td = tsd->td;
-  char service[12];
-  int rc;
-
-  msnprintf(service, sizeof(service), "%d", tsd->port);
-
-  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
-
-  if(rc) {
-    tsd->sock_error = SOCKERRNO ? SOCKERRNO : rc;
-    if(tsd->sock_error == 0)
-      tsd->sock_error = RESOLVER_ENOMEM;
-  }
-  else {
-    Curl_addrinfo_set_port(tsd->res, tsd->port);
-  }
-
-  Curl_mutex_acquire(tsd->mtx);
-  if(tsd->done) {
-    /* too late, gotta clean up the mess */
-    Curl_mutex_release(tsd->mtx);
-    destroy_thread_sync_data(tsd);
-    free(td);
-  }
-  else {
-#ifndef CURL_DISABLE_SOCKETPAIR
-    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-#ifdef USE_EVENTFD
-      const uint64_t buf[1] = { 1 };
-#else
-      const char buf[1] = { 1 };
-#endif
-      /* DNS has been resolved, signal client task */
-      if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
-        /* update sock_erro to errno */
-        tsd->sock_error = SOCKERRNO;
-      }
-    }
-#endif
-    tsd->done = TRUE;
-    Curl_mutex_release(tsd->mtx);
-  }
-
-  return 0;
-}
-
-#else /* HAVE_GETADDRINFO */
-
-/*
- * gethostbyname_thread() resolves a name and then exits.
- */
-static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
-DWORD
-#else
-unsigned int
-#endif
-CURL_STDCALL gethostbyname_thread(void *arg)
-{
-  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
-  struct thread_data *td = tsd->td;
-
-  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
-
-  if(!tsd->res) {
-    tsd->sock_error = SOCKERRNO;
-    if(tsd->sock_error == 0)
-      tsd->sock_error = RESOLVER_ENOMEM;
-  }
-
-  Curl_mutex_acquire(tsd->mtx);
-  if(tsd->done) {
-    /* too late, gotta clean up the mess */
-    Curl_mutex_release(tsd->mtx);
-    destroy_thread_sync_data(tsd);
-    free(td);
-  }
-  else {
-    tsd->done = TRUE;
-    Curl_mutex_release(tsd->mtx);
-  }
-
-  return 0;
-}
-
-#endif /* HAVE_GETADDRINFO */
-
-/*
- * destroy_async_data() cleans up async resolver data and thread handle.
- */
-static void destroy_async_data(struct Curl_easy *data)
-{
-  struct Curl_async *async;
-  DEBUGASSERT(data);
-  async = &data->state.async;
-  DEBUGASSERT(async);
-  if(async->tdata) {
-    struct thread_data *td = async->tdata;
-    bool done;
-#ifndef CURL_DISABLE_SOCKETPAIR
-    curl_socket_t sock_rd = td->tsd.sock_pair[0];
-#endif
-
-#ifdef USE_HTTPSRR_ARES
-    if(data->state.async.tdata->channel)
-      ares_destroy(data->state.async.tdata->channel);
-#endif
-    /*
-     * if the thread is still blocking in the resolve syscall, detach it and
-     * let the thread do the cleanup...
-     */
-    Curl_mutex_acquire(td->tsd.mtx);
-    done = td->tsd.done;
-    td->tsd.done = TRUE;
-    Curl_mutex_release(td->tsd.mtx);
-
-    if(!done) {
-      Curl_thread_destroy(td->thread_hnd);
-    }
-    else {
-      if(td->thread_hnd != curl_thread_t_null)
-        Curl_thread_join(&td->thread_hnd);
-
-      destroy_thread_sync_data(&td->tsd);
-
-      free(async->tdata);
-    }
-#ifndef CURL_DISABLE_SOCKETPAIR
-    /*
-     * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
-     * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
-     */
-    Curl_multi_closed(data, sock_rd);
-    wakeup_close(sock_rd);
-#endif
-  }
-  async->tdata = NULL;
-
-  free(async->hostname);
-  async->hostname = NULL;
-}
-
-#ifdef USE_HTTPSRR_ARES
-static CURLcode resolve_httpsrr(struct Curl_easy *data,
-                                struct Curl_async *asp)
-{
-  int status = ares_init_options(&asp->tdata->channel, NULL, 0);
-  if(status != ARES_SUCCESS)
-    return CURLE_FAILED_INIT;
-
-  memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
-  ares_query_dnsrec(asp->tdata->channel,
-                    asp->hostname, ARES_CLASS_IN,
-                    ARES_REC_TYPE_HTTPS,
-                    Curl_dnsrec_done_cb, data, NULL);
-
-  return CURLE_OK;
-}
-#endif
-
-/*
- * init_resolve_thread() starts a new thread that performs the actual
- * resolve. This function returns before the resolve is done.
- *
- * Returns FALSE in case of failure, otherwise TRUE.
- */
-static bool init_resolve_thread(struct Curl_easy *data,
-                                const char *hostname, int port,
-                                const struct addrinfo *hints)
-{
-  struct thread_data *td = calloc(1, sizeof(struct thread_data));
-  int err = ENOMEM;
-  struct Curl_async *asp = &data->state.async;
-
-  data->state.async.tdata = td;
-  if(!td)
-    goto errno_exit;
-
-  asp->port = port;
-  asp->done = FALSE;
-  asp->status = 0;
-  asp->dns = NULL;
-  td->thread_hnd = curl_thread_t_null;
-
-  if(!init_thread_sync_data(td, hostname, port, hints)) {
-    asp->tdata = NULL;
-    free(td);
-    goto errno_exit;
-  }
-
-  free(asp->hostname);
-  asp->hostname = strdup(hostname);
-  if(!asp->hostname)
-    goto err_exit;
-
-  /* The thread will set this TRUE when complete. */
-  td->tsd.done = FALSE;
-
-#ifdef HAVE_GETADDRINFO
-  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
-#else
-  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
-#endif
-
-  if(td->thread_hnd == curl_thread_t_null) {
-    /* The thread never started, so mark it as done here for proper cleanup. */
-    td->tsd.done = TRUE;
-    err = errno;
-    goto err_exit;
-  }
-#ifdef USE_HTTPSRR_ARES
-  if(resolve_httpsrr(data, asp))
-    infof(data, "Failed HTTPS RR operation");
-#endif
-  return TRUE;
-
-err_exit:
-  destroy_async_data(data);
-
-errno_exit:
-  errno = err;
-  return FALSE;
-}
-
-/*
- * 'entry' may be NULL and then no data is returned
- */
-static CURLcode thread_wait_resolv(struct Curl_easy *data,
-                                   struct Curl_dns_entry **entry,
-                                   bool report)
-{
-  struct thread_data *td;
-  CURLcode result = CURLE_OK;
-
-  DEBUGASSERT(data);
-  td = data->state.async.tdata;
-  DEBUGASSERT(td);
-  DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
-
-  /* wait for the thread to resolve the name */
-  if(Curl_thread_join(&td->thread_hnd)) {
-    if(entry)
-      result = getaddrinfo_complete(data);
-  }
-  else
-    DEBUGASSERT(0);
-
-  data->state.async.done = TRUE;
-
-  if(entry)
-    *entry = data->state.async.dns;
-
-  if(!data->state.async.dns && report)
-    /* a name was not resolved, report error */
-    result = Curl_resolver_error(data);
-
-  destroy_async_data(data);
-
-  if(!data->state.async.dns && report)
-    connclose(data->conn, "asynch resolve failed");
-
-  return result;
-}
-
-
-/*
- * Until we gain a way to signal the resolver threads to stop early, we must
- * simply wait for them and ignore their results.
- */
-void Curl_resolver_kill(struct Curl_easy *data)
-{
-  struct thread_data *td = data->state.async.tdata;
-
-  /* If we are 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
-     && (data->set.quick_exit != 1L))
-    (void)thread_wait_resolv(data, NULL, FALSE);
-  else
-    Curl_resolver_cancel(data);
-}
-
-/*
- * Curl_resolver_wait_resolv()
- *
- * Waits for a resolve to finish. This function should be avoided since using
- * this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
- *
- * This is the version for resolves-in-a-thread.
- */
-CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
-                                   struct Curl_dns_entry **entry)
-{
-  return thread_wait_resolv(data, entry, TRUE);
-}
-
-/*
- * Curl_resolver_is_resolved() is called repeatedly to check if a previous
- * name resolve request has completed. It should also make sure to time-out if
- * the operation seems to take too long.
- */
-CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
-                                   struct Curl_dns_entry **entry)
-{
-  struct thread_data *td = data->state.async.tdata;
-  bool done = FALSE;
-
-  DEBUGASSERT(entry);
-  *entry = NULL;
-
-  if(!td) {
-    DEBUGASSERT(td);
-    return CURLE_COULDNT_RESOLVE_HOST;
-  }
-#ifdef USE_HTTPSRR_ARES
-  if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
-    return CURLE_UNRECOVERABLE_POLL;
-#endif
-
-  Curl_mutex_acquire(td->tsd.mtx);
-  done = td->tsd.done;
-  Curl_mutex_release(td->tsd.mtx);
-
-  if(done) {
-    getaddrinfo_complete(data);
-
-    if(!data->state.async.dns) {
-      CURLcode result = Curl_resolver_error(data);
-      destroy_async_data(data);
-      return result;
-    }
-#ifdef USE_HTTPSRR_ARES
-    {
-      struct Curl_https_rrinfo *lhrr =
-        Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
-      if(!lhrr) {
-        destroy_async_data(data);
-        return CURLE_OUT_OF_MEMORY;
-      }
-      data->state.async.dns->hinfo = lhrr;
-    }
-#endif
-    destroy_async_data(data);
-    *entry = data->state.async.dns;
-  }
-  else {
-    /* poll for name lookup done with exponential backoff up to 250ms */
-    /* should be fine even if this converts to 32-bit */
-    timediff_t elapsed = Curl_timediff(Curl_now(),
-                                       data->progress.t_startsingle);
-    if(elapsed < 0)
-      elapsed = 0;
-
-    if(td->poll_interval == 0)
-      /* Start at 1ms poll interval */
-      td->poll_interval = 1;
-    else if(elapsed >= td->interval_end)
-      /* Back-off exponentially if last interval expired  */
-      td->poll_interval *= 2;
-
-    if(td->poll_interval > 250)
-      td->poll_interval = 250;
-
-    td->interval_end = elapsed + td->poll_interval;
-    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
-  }
-
-  return CURLE_OK;
-}
-
-int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
-{
-  int ret_val = 0;
-  timediff_t milli;
-  timediff_t ms;
-  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-#ifndef CURL_DISABLE_SOCKETPAIR
-  struct thread_data *td = data->state.async.tdata;
-#endif
-#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
-  int socketi = 0;
-#else
-  (void)socks;
-#endif
-
-#ifdef USE_HTTPSRR_ARES
-  if(data->state.async.tdata && data->state.async.tdata->channel) {
-    ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
-    for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
-      if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
-         !ARES_GETSOCK_WRITABLE(ret_val, socketi))
-        break;
-  }
-#endif
-#ifndef CURL_DISABLE_SOCKETPAIR
-  if(td) {
-    /* return read fd to client for polling the DNS resolution status */
-    socks[socketi] = td->tsd.sock_pair[0];
-    ret_val |= GETSOCK_READSOCK(socketi);
-  }
-  else {
-#endif
-    ms = Curl_timediff(Curl_now(), reslv->start);
-    if(ms < 3)
-      milli = 0;
-    else if(ms <= 50)
-      milli = ms/3;
-    else if(ms <= 250)
-      milli = 50;
-    else
-      milli = 200;
-    Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-#ifndef CURL_DISABLE_SOCKETPAIR
-  }
-#endif
-
-
-  return ret_val;
-}
-
-#ifndef HAVE_GETADDRINFO
-/*
- * Curl_getaddrinfo() - for platforms without getaddrinfo
- */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
-                                                const char *hostname,
-                                                int port,
-                                                int *waitp)
-{
-  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
-  *waitp = 0; /* default to synchronous response */
-
-  reslv->start = Curl_now();
-
-  /* fire up a new resolver thread! */
-  if(init_resolve_thread(data, hostname, port, NULL)) {
-    *waitp = 1; /* expect asynchronous response */
-    return NULL;
-  }
-
-  failf(data, "getaddrinfo() thread failed");
-
-  return NULL;
-}
-
-#else /* !HAVE_GETADDRINFO */
-
-/*
- * Curl_resolver_getaddrinfo() - for getaddrinfo
- */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
-                                                const char *hostname,
-                                                int port,
-                                                int *waitp)
-{
-  struct addrinfo hints;
-  int pf = PF_INET;
-  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
-  *waitp = 0; /* default to synchronous response */
-
-#ifdef CURLRES_IPV6
-  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
-    /* The stack seems to be IPv6-enabled */
-    if(data->conn->ip_version == CURL_IPRESOLVE_V6)
-      pf = PF_INET6;
-    else
-      pf = PF_UNSPEC;
-  }
-#endif /* CURLRES_IPV6 */
-
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
-    SOCK_STREAM : SOCK_DGRAM;
-
-  reslv->start = Curl_now();
-  /* fire up a new resolver thread! */
-  if(init_resolve_thread(data, hostname, port, &hints)) {
-    *waitp = 1; /* expect asynchronous response */
-    return NULL;
-  }
-
-  failf(data, "getaddrinfo() thread failed to start");
-  return NULL;
-
-}
-
-#endif /* !HAVE_GETADDRINFO */
-
-CURLcode Curl_set_dns_servers(struct Curl_easy *data,
-                              char *servers)
-{
-  (void)data;
-  (void)servers;
-  return CURLE_NOT_BUILT_IN;
-
-}
-
-CURLcode Curl_set_dns_interface(struct Curl_easy *data,
-                                const char *interf)
-{
-  (void)data;
-  (void)interf;
-  return CURLE_NOT_BUILT_IN;
-}
-
-CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
-                                const char *local_ip4)
-{
-  (void)data;
-  (void)local_ip4;
-  return CURLE_NOT_BUILT_IN;
-}
-
-CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
-                                const char *local_ip6)
-{
-  (void)data;
-  (void)local_ip6;
-  return CURLE_NOT_BUILT_IN;
-}
-
-#endif /* CURLRES_THREADED */

+ 173 - 146
Utilities/cmcurl/lib/asyn.h

@@ -25,77 +25,23 @@
  ***************************************************************************/
 
 #include "curl_setup.h"
-#include "curl_addrinfo.h"
-#include "httpsrr.h"
 
-struct addrinfo;
-struct hostent;
 struct Curl_easy;
-struct connectdata;
 struct Curl_dns_entry;
 
-#ifdef CURLRES_THREADED
-#include "curl_threads.h"
-
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
-  curl_mutex_t *mtx;
-  char *hostname;        /* hostname to resolve, Curl_async.hostname
-                            duplicate */
-#ifndef CURL_DISABLE_SOCKETPAIR
-  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
-#endif
-  struct Curl_addrinfo *res;
-#ifdef HAVE_GETADDRINFO
-  struct addrinfo hints;
-#endif
-  struct thread_data *td; /* for thread-self cleanup */
-  int port;
-  int sock_error;
-  bool done;
-};
-
-struct thread_data {
-  curl_thread_t thread_hnd;
-  unsigned int poll_interval;
-  timediff_t interval_end;
-  struct thread_sync_data tsd;
-#if defined(USE_HTTPSRR) && defined(USE_ARES)
-  struct Curl_https_rrinfo hinfo;
-  ares_channel channel;
-#endif
-};
-
-#elif defined(CURLRES_ARES) /* CURLRES_THREADED */
-
-struct thread_data {
-  int num_pending; /* number of outstanding c-ares requests */
-  struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
-                                    parts */
-  int last_status;
-#ifndef HAVE_CARES_GETADDRINFO
-  struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
-#endif
-#ifdef USE_HTTPSRR
-  struct Curl_https_rrinfo hinfo;
-#endif
-  char hostname[1];
-};
+#ifdef CURLRES_ASYNCH
 
-#endif /* CURLRES_ARES */
+#include "curl_addrinfo.h"
+#include "httpsrr.h"
 
-#ifdef USE_ARES
-#include <ares.h>
+struct addrinfo;
+struct hostent;
+struct connectdata;
 
-/* for HTTPS RR purposes as well */
-int Curl_ares_getsock(struct Curl_easy *data,
-                      ares_channel channel,
-                      curl_socket_t *socks);
-int Curl_ares_perform(ares_channel channel,
-                      timediff_t timeout_ms);
+#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
+#error cannot have both CURLRES_ARES and CURLRES_THREADED defined
 #endif
 
-
 /*
  * This header defines all functions in the internal asynch resolver interface.
  * All asynch resolvers need to provide these functions.
@@ -104,85 +50,38 @@ int Curl_ares_perform(ares_channel channel,
  */
 
 /*
- * Curl_resolver_global_init()
+ * Curl_async_global_init()
  *
  * Called from curl_global_init() to initialize global resolver environment.
  * Returning anything else than CURLE_OK fails curl_global_init().
  */
-int Curl_resolver_global_init(void);
+int Curl_async_global_init(void);
 
 /*
- * Curl_resolver_global_cleanup()
+ * Curl_async_global_cleanup()
  * Called from curl_global_cleanup() to destroy global resolver environment.
  */
-void Curl_resolver_global_cleanup(void);
-
-/*
- * Curl_resolver_init()
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure). Should fill the passed pointer by the initialized handler.
- * Returning anything else than CURLE_OK fails curl_easy_init() with the
- * correspondent code.
- */
-CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);
-
-/*
- * Curl_resolver_cleanup()
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure). Should destroy the handler and free all resources connected to
- * it.
- */
-void Curl_resolver_cleanup(void *resolver);
-
-/*
- * Curl_resolver_duphandle()
- * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure). Should
- * duplicate the 'from' handle and pass the resulting handle to the 'to'
- * pointer. Returning anything else than CURLE_OK causes failed
- * curl_easy_duphandle() call.
- */
-CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
-                                 void *from);
+void Curl_async_global_cleanup(void);
 
 /*
- * Curl_resolver_cancel().
- *
- * It is called from inside other functions to cancel currently performing
- * resolver request. Should also free any temporary resources allocated to
- * perform a request. This never waits for resolver threads to complete.
- *
- * It is safe to call this when conn is in any state.
- */
-void Curl_resolver_cancel(struct Curl_easy *data);
-
-/*
- * Curl_resolver_kill().
- *
- * This acts like Curl_resolver_cancel() except it will block until any threads
- * associated with the resolver are complete. This never blocks for resolvers
- * that do not use threads. This is intended to be the "last chance" function
- * that cleans up an in-progress resolver completely (before its owner is about
- * to die).
- *
- * It is safe to call this when conn is in any state.
+ * Curl_async_get_impl()
+ * Get the resolver implementation instance (c-ares channel) or NULL
+ * for passing to application callback.
  */
-void Curl_resolver_kill(struct Curl_easy *data);
+CURLcode Curl_async_get_impl(struct Curl_easy *easy, void **impl);
 
-/* Curl_resolver_getsock()
+/* Curl_async_getsock()
  *
- * This function is called from the multi_getsock() function.  'sock' is a
+ * This function is called from the Curl_multi_getsock() function.  'sock' is a
  * pointer to an array to hold the file descriptors, with 'numsock' being the
  * size of that array (in number of entries). This function is supposed to
  * return bitmask indicating what file descriptors (referring to array indexes
  * in the 'sock' array) to wait for, read/write.
  */
-int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock);
+int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *sock);
 
 /*
- * Curl_resolver_is_resolved()
+ * Curl_async_is_resolved()
  *
  * Called repeatedly to check if a previous name resolve request has
  * completed. It should also make sure to time-out if the operation seems to
@@ -190,25 +89,25 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock);
  *
  * Returns normal CURLcode errors.
  */
-CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
-                                   struct Curl_dns_entry **dns);
+CURLcode Curl_async_is_resolved(struct Curl_easy *data,
+                                struct Curl_dns_entry **dns);
 
 /*
- * Curl_resolver_wait_resolv()
+ * Curl_async_await()
  *
  * Waits for a resolve to finish. This function should be avoided since using
  * this risk getting the multi interface to "hang".
  *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
+ * On return 'entry' is assigned the resolved dns (CURLE_OK or NULL otherwise.
  *
  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  */
-CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
-                                   struct Curl_dns_entry **dnsentry);
+CURLcode Curl_async_await(struct Curl_easy *data,
+                          struct Curl_dns_entry **dnsentry);
 
 /*
- * Curl_resolver_getaddrinfo() - when using this resolver
+ * Curl_async_getaddrinfo() - when using this resolver
  *
  * Returns name information about the given hostname and port number. If
  * successful, the 'hostent' is returned and the fourth argument will point to
@@ -218,29 +117,157 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
  * Each resolver backend must of course make sure to return data in the
  * correct format to comply with this.
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
-                                                const char *hostname,
-                                                int port,
-                                                int *waitp);
+struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
+                                             const char *hostname,
+                                             int port,
+                                             int ip_version,
+                                             int *waitp);
+
+#ifdef USE_ARES
+/* common functions for c-ares and threaded resolver with HTTPSRR */
+#include <ares.h>
+
+int Curl_ares_getsock(struct Curl_easy *data,
+                      ares_channel channel,
+                      curl_socket_t *socks);
+int Curl_ares_perform(ares_channel channel,
+                      timediff_t timeout_ms);
+#endif
+
+#ifdef CURLRES_ARES
+/* async resolving implementation using c-ares alone */
+struct async_ares_ctx {
+  ares_channel channel;
+  int num_pending; /* number of outstanding c-ares requests */
+  struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
+                                    parts */
+  int last_status;
+  CURLcode result; /* CURLE_OK or error handling response */
+#ifndef HAVE_CARES_GETADDRINFO
+  struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
+#endif
+#ifdef USE_HTTPSRR
+  struct Curl_https_rrinfo hinfo;
+#endif
+};
+
+void Curl_async_ares_shutdown(struct Curl_easy *data);
+void Curl_async_ares_destroy(struct Curl_easy *data);
+
+/* Set the DNS server to use by ares, from `data` settings. */
+CURLcode Curl_async_ares_set_dns_servers(struct Curl_easy *data);
+
+/* Set the DNS interfacer to use by ares, from `data` settings. */
+CURLcode Curl_async_ares_set_dns_interface(struct Curl_easy *data);
+
+/* Set the local ipv4 address to use by ares, from `data` settings. */
+CURLcode Curl_async_ares_set_dns_local_ip4(struct Curl_easy *data);
+
+/* Set the local ipv6 address to use by ares, from `data` settings. */
+CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data);
+
+#endif /* CURLRES_ARES */
+
+#ifdef CURLRES_THREADED
+/* async resolving implementation using POSIX threads */
+#include "curl_threads.h"
+
+/* Context for threaded address resolver */
+struct async_thrdd_addr_ctx {
+  curl_thread_t thread_hnd;
+  char *hostname;        /* hostname to resolve, Curl_async.hostname
+                            duplicate */
+  curl_mutex_t mutx;
+#ifndef CURL_DISABLE_SOCKETPAIR
+  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
+#endif
+  struct Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+  struct curltime start;
+  timediff_t interval_end;
+  unsigned int poll_interval;
+  int port;
+  int sock_error;
+  int ref_count;
+};
+
+/* Context for threaded resolver */
+struct async_thrdd_ctx {
+  /* `addr` is a pointer since this memory is shared with a started
+   * thread. Since threads cannot be killed, we use reference counting
+   * so that we can "release" our pointer to this memory while the
+   * thread is still running. */
+  struct async_thrdd_addr_ctx *addr;
+#if defined(USE_HTTPSRR) && defined(USE_ARES)
+  struct {
+    ares_channel channel;
+    struct Curl_https_rrinfo hinfo;
+    CURLcode result;
+    BIT(done);
+  } rr;
+#endif
+};
+
+void Curl_async_thrdd_shutdown(struct Curl_easy *data);
+void Curl_async_thrdd_destroy(struct Curl_easy *data);
+
+#endif /* CURLRES_THREADED */
+
+#ifndef CURL_DISABLE_DOH
+struct doh_probes;
+#endif
+
+#else /* CURLRES_ASYNCH */
 
-#ifndef CURLRES_ASYNCH
 /* convert these functions if an asynch resolver is not used */
-#define Curl_resolver_cancel(x) Curl_nop_stmt
-#define Curl_resolver_kill(x) Curl_nop_stmt
-#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
-#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
-#define Curl_resolver_duphandle(x,y,z) CURLE_OK
-#define Curl_resolver_init(x,y) CURLE_OK
-#define Curl_resolver_global_init() CURLE_OK
-#define Curl_resolver_global_cleanup() Curl_nop_stmt
-#define Curl_resolver_cleanup(x) Curl_nop_stmt
+#define Curl_async_get_impl(x,y)    (*(y) = NULL, CURLE_OK)
+#define Curl_async_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_async_await(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_async_global_init() CURLE_OK
+#define Curl_async_global_cleanup() Curl_nop_stmt
+
+#endif /* !CURLRES_ASYNCH */
+
+#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
+#define USE_CURL_ASYNC
 #endif
 
-#ifdef CURLRES_ASYNCH
-#define Curl_resolver_asynch() 1
-#else
-#define Curl_resolver_asynch() 0
+#ifdef USE_CURL_ASYNC
+struct Curl_async {
+#ifdef CURLRES_ARES /*  */
+  struct async_ares_ctx ares;
+#elif defined(CURLRES_THREADED)
+  struct async_thrdd_ctx thrdd;
 #endif
+#ifndef CURL_DISABLE_DOH
+  struct doh_probes *doh; /* DoH specific data for this request */
+#endif
+  struct Curl_dns_entry *dns; /* result of resolving on success */
+  char *hostname; /* copy of the params resolv started with */
+  int port;
+  int ip_version;
+  BIT(done);
+};
+
+/*
+ * Curl_async_shutdown().
+ *
+ * This shuts down all ongoing operations.
+ */
+void Curl_async_shutdown(struct Curl_easy *data);
+
+/*
+ * Curl_async_destroy().
+ *
+ * This frees the resources of any async resolve.
+ */
+void Curl_async_destroy(struct Curl_easy *data);
+#else /* !USE_CURL_ASYNC */
+#define Curl_async_shutdown(x) Curl_nop_stmt
+#define Curl_async_destroy(x) Curl_nop_stmt
+#endif /* USE_CURL_ASYNC */
 
 
 /********** end of generic resolver interface functions *****************/

+ 3 - 1
Utilities/cmcurl/lib/bufref.c

@@ -30,7 +30,9 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#ifdef DEBUGBUILD
 #define SIGNATURE 0x5c48e9b2    /* Random pattern. */
+#endif
 
 /*
  * Init a bufref struct.
@@ -59,7 +61,7 @@ void Curl_bufref_free(struct bufref *br)
   DEBUGASSERT(br->ptr || !br->len);
 
   if(br->ptr && br->dtor)
-    br->dtor((void *) br->ptr);
+    br->dtor(CURL_UNCONST(br->ptr));
 
   br->dtor = NULL;
   br->ptr = NULL;

+ 27 - 23
Utilities/cmcurl/lib/cf-h1-proxy.c

@@ -28,7 +28,7 @@
 
 #include <curl/curl.h>
 #include "urldata.h"
-#include "dynbuf.h"
+#include "curlx/dynbuf.h"
 #include "sendf.h"
 #include "http.h"
 #include "http1.h"
@@ -40,10 +40,11 @@
 #include "cf-h1-proxy.h"
 #include "connect.h"
 #include "curl_trc.h"
-#include "curlx.h"
+#include "strcase.h"
 #include "vtls/vtls.h"
 #include "transfer.h"
 #include "multiif.h"
+#include "curlx/strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -96,8 +97,8 @@ static CURLcode tunnel_reinit(struct Curl_cfilter *cf,
   (void)data;
   (void)cf;
   DEBUGASSERT(ts);
-  Curl_dyn_reset(&ts->rcvbuf);
-  Curl_dyn_reset(&ts->request_data);
+  curlx_dyn_reset(&ts->rcvbuf);
+  curlx_dyn_reset(&ts->request_data);
   ts->tunnel_state = H1_TUNNEL_INIT;
   ts->keepon = KEEPON_CONNECT;
   ts->cl = 0;
@@ -122,8 +123,8 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
 
   infof(data, "allocate connect buffer");
 
-  Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
-  Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
+  curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
+  curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
   Curl_httpchunk_init(data, &ts->ch, TRUE);
 
   *pts =  ts;
@@ -149,7 +150,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
     CURL_TRC_CF(data, cf, "new tunnel state 'connect'");
     ts->tunnel_state = H1_TUNNEL_CONNECT;
     ts->keepon = KEEPON_CONNECT;
-    Curl_dyn_reset(&ts->rcvbuf);
+    curlx_dyn_reset(&ts->rcvbuf);
     break;
 
   case H1_TUNNEL_RECEIVE:
@@ -172,8 +173,8 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
     if(new_state == H1_TUNNEL_FAILED)
       CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
     ts->tunnel_state = new_state;
-    Curl_dyn_reset(&ts->rcvbuf);
-    Curl_dyn_reset(&ts->request_data);
+    curlx_dyn_reset(&ts->rcvbuf);
+    curlx_dyn_reset(&ts->request_data);
     /* restore the protocol pointer */
     data->info.httpcode = 0; /* clear it as it might've been used for the
                                 proxy */
@@ -192,8 +193,8 @@ static void tunnel_free(struct Curl_cfilter *cf,
     struct h1_tunnel_state *ts = cf->ctx;
     if(ts) {
       h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
-      Curl_dyn_free(&ts->rcvbuf);
-      Curl_dyn_free(&ts->request_data);
+      curlx_dyn_free(&ts->rcvbuf);
+      curlx_dyn_free(&ts->request_data);
       Curl_httpchunk_free(data, &ts->ch);
       free(ts);
       cf->ctx = NULL;
@@ -225,7 +226,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
 
   infof(data, "Establish HTTP proxy tunnel to %s", req->authority);
 
-  Curl_dyn_reset(&ts->request_data);
+  curlx_dyn_reset(&ts->request_data);
   ts->nsent = 0;
   ts->headerlines = 0;
   http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1;
@@ -247,8 +248,8 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
                              struct h1_tunnel_state *ts,
                              bool *done)
 {
-  char *buf = Curl_dyn_ptr(&ts->request_data);
-  size_t request_len = Curl_dyn_len(&ts->request_data);
+  char *buf = curlx_dyn_ptr(&ts->request_data);
+  size_t request_len = curlx_dyn_len(&ts->request_data);
   size_t blen = request_len;
   CURLcode result = CURLE_OK;
   ssize_t nwritten;
@@ -314,8 +315,11 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
             k->httpcode);
     }
     else {
-      (void)curlx_strtoofft(header + strlen("Content-Length:"),
-                            NULL, 10, &ts->cl);
+      const char *p = header + strlen("Content-Length:");
+      if(curlx_str_numblanks(&p, &ts->cl)) {
+        failf(data, "Unsupported Content-Length value");
+        return CURLE_WEIRD_SERVER_REPLY;
+      }
     }
   }
   else if(Curl_compareheader(header,
@@ -440,7 +444,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
       continue;
     }
 
-    if(Curl_dyn_addn(&ts->rcvbuf, &byte, 1)) {
+    if(curlx_dyn_addn(&ts->rcvbuf, &byte, 1)) {
       failf(data, "CONNECT response too large");
       return CURLE_RECV_ERROR;
     }
@@ -450,8 +454,8 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
       continue;
 
     ts->headerlines++;
-    linep = Curl_dyn_ptr(&ts->rcvbuf);
-    line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
+    linep = curlx_dyn_ptr(&ts->rcvbuf);
+    line_len = curlx_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
 
     /* output debug if that is requested */
     Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len);
@@ -508,7 +512,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
     if(result)
       return result;
 
-    Curl_dyn_reset(&ts->rcvbuf);
+    curlx_dyn_reset(&ts->rcvbuf);
   } /* while there is buffer left and loop is requested */
 
   if(error)
@@ -597,7 +601,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
           infof(data, "Connect me again please");
           Curl_conn_cf_close(cf, data);
           connkeep(conn, "HTTP proxy CONNECT");
-          result = Curl_conn_cf_connect(cf->next, data, FALSE, &done);
+          result = Curl_conn_cf_connect(cf->next, data, &done);
           goto out;
         }
         else {
@@ -637,7 +641,7 @@ out:
 
 static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
-                                    bool blocking, bool *done)
+                                    bool *done)
 {
   CURLcode result;
   struct h1_tunnel_state *ts = cf->ctx;
@@ -648,7 +652,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
   }
 
   CURL_TRC_CF(data, cf, "connect");
-  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  result = cf->next->cft->do_connect(cf->next, data, done);
   if(result || !*done)
     return result;
 

+ 4 - 4
Utilities/cmcurl/lib/cf-h2-proxy.c

@@ -32,7 +32,7 @@
 #include "connect.h"
 #include "curl_trc.h"
 #include "bufq.h"
-#include "dynbuf.h"
+#include "curlx/dynbuf.h"
 #include "dynhds.h"
 #include "http1.h"
 #include "http2.h"
@@ -619,7 +619,7 @@ static int proxy_h2_fr_print(const nghttp2_frame *frame,
                        frame->hd.flags & NGHTTP2_FLAG_ACK);
     case NGHTTP2_GOAWAY: {
       char scratch[128];
-      size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+      size_t s_len = CURL_ARRAYSIZE(scratch);
       size_t len = (frame->goaway.opaque_data_len < s_len) ?
         frame->goaway.opaque_data_len : s_len-1;
       if(len)
@@ -1090,7 +1090,7 @@ out:
 
 static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
-                                    bool blocking, bool *done)
+                                    bool *done)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
@@ -1105,7 +1105,7 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
 
   /* Connect the lower filters first */
   if(!cf->next->connected) {
-    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    result = Curl_conn_cf_connect(cf->next, data, done);
     if(result || !*done)
       return result;
   }

+ 15 - 15
Utilities/cmcurl/lib/cf-haproxy.c

@@ -54,13 +54,13 @@ static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
 {
   DEBUGASSERT(ctx);
   ctx->state = HAPROXY_INIT;
-  Curl_dyn_reset(&ctx->data_out);
+  curlx_dyn_reset(&ctx->data_out);
 }
 
 static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
 {
   if(ctx) {
-    Curl_dyn_free(&ctx->data_out);
+    curlx_dyn_free(&ctx->data_out);
     free(ctx);
   }
 }
@@ -79,7 +79,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
 #ifdef USE_UNIX_SOCKETS
   if(cf->conn->unix_domain_socket)
     /* the buffer is large enough to hold this! */
-    result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
+    result = curlx_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
   else {
 #endif /* USE_UNIX_SOCKETS */
   result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad);
@@ -92,10 +92,10 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
   else
     client_ip = ipquad.local_ip;
 
-  result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
-                         is_ipv6 ? "TCP6" : "TCP4",
-                         client_ip, ipquad.remote_ip,
-                         ipquad.local_port, ipquad.remote_port);
+  result = curlx_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
+                          is_ipv6 ? "TCP6" : "TCP4",
+                          client_ip, ipquad.remote_ip,
+                          ipquad.local_port, ipquad.remote_port);
 
 #ifdef USE_UNIX_SOCKETS
   }
@@ -105,7 +105,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
 
 static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
-                                   bool blocking, bool *done)
+                                   bool *done)
 {
   struct cf_haproxy_ctx *ctx = cf->ctx;
   CURLcode result;
@@ -117,7 +117,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
-  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  result = cf->next->cft->do_connect(cf->next, data, done);
   if(result || !*done)
     return result;
 
@@ -129,11 +129,11 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
     ctx->state = HAPROXY_SEND;
     FALLTHROUGH();
   case HAPROXY_SEND:
-    len = Curl_dyn_len(&ctx->data_out);
+    len = curlx_dyn_len(&ctx->data_out);
     if(len > 0) {
       ssize_t nwritten;
       nwritten = Curl_conn_cf_send(cf->next, data,
-                                   Curl_dyn_ptr(&ctx->data_out), len, FALSE,
+                                   curlx_dyn_ptr(&ctx->data_out), len, FALSE,
                                    &result);
       if(nwritten < 0) {
         if(result != CURLE_AGAIN)
@@ -141,8 +141,8 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
         result = CURLE_OK;
         nwritten = 0;
       }
-      Curl_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
-      if(Curl_dyn_len(&ctx->data_out) > 0) {
+      curlx_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
+      if(curlx_dyn_len(&ctx->data_out) > 0) {
         result = CURLE_OK;
         goto out;
       }
@@ -150,7 +150,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
     ctx->state = HAPROXY_DONE;
     FALLTHROUGH();
   default:
-    Curl_dyn_free(&ctx->data_out);
+    curlx_dyn_free(&ctx->data_out);
     break;
   }
 
@@ -222,7 +222,7 @@ static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
     goto out;
   }
   ctx->state = HAPROXY_INIT;
-  Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY);
+  curlx_dyn_init(&ctx->data_out, DYN_HAXPROXY);
 
   result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
   if(result)

+ 96 - 82
Utilities/cmcurl/lib/cf-https-connect.c

@@ -113,7 +113,6 @@ static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
 
 struct cf_hc_ctx {
   cf_hc_state state;
-  const struct Curl_dns_entry *remotehost;
   struct curltime started;  /* when connect started */
   CURLcode result;          /* overall result */
   struct cf_hc_baller ballers[2];
@@ -147,11 +146,10 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
                               struct Curl_easy *data,
                               int transport)
 {
-  struct cf_hc_ctx *ctx = cf->ctx;
   struct Curl_cfilter *save = cf->next;
 
   cf->next = NULL;
-  b->started = Curl_now();
+  b->started = curlx_now();
   switch(b->alpn_id) {
   case ALPN_h3:
     transport = TRNSPRT_QUIC;
@@ -161,8 +159,8 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
   }
 
   if(!b->result)
-    b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
-                                           transport, CURL_CF_SSL_ENABLE);
+    b->result = Curl_cf_setup_insert_after(cf, data, transport,
+                                           CURL_CF_SSL_ENABLE);
   b->cf = cf->next;
   cf->next = save;
 }
@@ -175,7 +173,7 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
   struct Curl_cfilter *save = cf->next;
 
   cf->next = b->cf;
-  b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
+  b->result = Curl_conn_cf_connect(cf->next, data, done);
   b->cf = cf->next; /* it might mutate */
   cf->next = save;
   return b->result;
@@ -192,7 +190,7 @@ static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
     ctx->state = CF_HC_INIT;
     ctx->result = CURLE_OK;
     ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
-    ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
+    ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
   }
 }
 
@@ -213,11 +211,12 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
   reply_ms = cf_hc_baller_reply_ms(winner, data);
   if(reply_ms >= 0)
     CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
-                winner->name, (int)Curl_timediff(Curl_now(), winner->started),
-                reply_ms);
+                winner->name, (int)curlx_timediff(curlx_now(),
+                                                  winner->started), reply_ms);
   else
     CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
-                winner->name, (int)Curl_timediff(Curl_now(), winner->started));
+                winner->name, (int)curlx_timediff(curlx_now(),
+                                                  winner->started));
 
   cf->next = winner->cf;
   winner->cf = NULL;
@@ -263,11 +262,11 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
       break;
   }
   if(i == idx) {
-    CURL_TRC_CF(data, cf, "all previous ballers have failed, time to start "
-                "baller %zu [%s]", idx, ctx->ballers[idx].name);
+    CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
+                ctx->ballers[idx].name);
     return TRUE;
   }
-  elapsed_ms = Curl_timediff(now, ctx->started);
+  elapsed_ms = curlx_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
     CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting %s",
                 ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
@@ -291,21 +290,20 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
 
 static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              bool blocking, bool *done)
+                              bool *done)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct curltime now;
   CURLcode result = CURLE_OK;
   size_t i, failed_ballers;
 
-  (void)blocking;
   if(cf->connected) {
     *done = TRUE;
     return CURLE_OK;
   }
 
   *done = FALSE;
-  now = Curl_now();
+  now = curlx_now();
   switch(ctx->state) {
   case CF_HC_INIT:
     DEBUGASSERT(!cf->next);
@@ -316,7 +314,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
     if(ctx->baller_count > 1) {
       Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
-      CURL_TRC_CF(data, cf, "set expire for starting next baller in %ums",
+      CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
                   ctx->soft_eyeballs_timeout_ms);
     }
     ctx->state = CF_HC_CONNECT;
@@ -352,7 +350,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
 
     if(failed_ballers == ctx->baller_count) {
       /* all have failed. we give up */
-      CURL_TRC_CF(data, cf, "connect, all failed");
+      CURL_TRC_CF(data, cf, "connect, all attempts failed");
       for(i = 0; i < ctx->baller_count; i++) {
         if(ctx->ballers[i].result) {
           result = ctx->ballers[i].result;
@@ -451,7 +449,6 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
   if(cf->connected)
     return cf->next->cft->has_data_pending(cf->next, data);
 
-  CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
   for(i = 0; i < ctx->baller_count; i++)
     if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
       return TRUE;
@@ -471,7 +468,7 @@ static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
     struct Curl_cfilter *cfb = ctx->ballers[i].cf;
     memset(&t, 0, sizeof(t));
     if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0)
         tmax = t;
     }
   }
@@ -577,7 +574,6 @@ struct Curl_cftype Curl_cft_http_connect = {
 
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
-                             const struct Curl_dns_entry *remotehost,
                              enum alpnid *alpnids, size_t alpn_count)
 {
   struct Curl_cfilter *cf = NULL;
@@ -599,7 +595,6 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  ctx->remotehost = remotehost;
   for(i = 0; i < alpn_count; ++i)
     cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
   for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
@@ -607,8 +602,6 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
   ctx->baller_count = alpn_count;
 
   result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
-  CURL_TRC_CF(data, cf, "created with %zu ALPNs -> %d",
-              ctx->baller_count, result);
   if(result)
     goto out;
   ctx = NULL;
@@ -623,14 +616,13 @@ out:
 static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
-                                    const struct Curl_dns_entry *remotehost,
                                     enum alpnid *alpn_ids, size_t alpn_count)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, remotehost, alpn_ids, alpn_count);
+  result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -638,88 +630,110 @@ out:
   return result;
 }
 
+static bool cf_https_alpns_contain(enum alpnid id,
+                                   enum alpnid *list, size_t len)
+{
+  size_t i;
+  for(i = 0; i < len; ++i) {
+    if(id == list[i])
+      return TRUE;
+  }
+  return FALSE;
+}
+
 CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              struct connectdata *conn,
-                             int sockindex,
-                             const struct Curl_dns_entry *remotehost)
+                             int sockindex)
 {
   enum alpnid alpn_ids[2];
   size_t alpn_count = 0;
   CURLcode result = CURLE_OK;
+  struct Curl_cfilter cf_fake, *cf = NULL;
 
   (void)sockindex;
-  (void)remotehost;
+  /* we want to log for the filter before we create it, fake it. */
+  memset(&cf_fake, 0, sizeof(cf_fake));
+  cf_fake.cft = &Curl_cft_http_connect;
+  cf = &cf_fake;
 
   if(conn->bits.tls_enable_alpn) {
-    switch(data->state.httpwant) {
-    case CURL_HTTP_VERSION_NONE:
-      /* No preferences by transfer setup. Choose best defaults */
 #ifdef USE_HTTPSRR
-      if(conn->dns_entry && conn->dns_entry->hinfo &&
-         !conn->dns_entry->hinfo->no_def_alpn) {
-        size_t i, j;
-        for(i = 0; i < CURL_ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
-                   alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
-          bool present = FALSE;
-          enum alpnid alpn = conn->dns_entry->hinfo->alpns[i];
-          for(j = 0; j < alpn_count; ++j) {
-            if(alpn == alpn_ids[j]) {
-              present = TRUE;
-              break;
-            }
+    /* Is there an HTTPSRR use its ALPNs here.
+     * We are here after having selected a connection to a host+port and
+     * can no longer change that. Any HTTPSRR advice for other hosts and ports
+     * we need to ignore. */
+    struct Curl_dns_entry *dns = data->state.dns[sockindex];
+    struct Curl_https_rrinfo *rr = dns ? dns->hinfo : NULL;
+    if(rr && !rr->no_def_alpn &&  /* ALPNs are defaults */
+       (!rr->target ||      /* for same host */
+        !rr->target[0] ||
+        (rr->target[0] == '.' &&
+         !rr->target[1])) &&
+       (rr->port < 0 ||    /* for same port */
+        rr->port == conn->remote_port)) {
+      size_t i;
+      for(i = 0; i < CURL_ARRAYSIZE(rr->alpns) &&
+                 alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
+        enum alpnid alpn = rr->alpns[i];
+        if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
+          continue;
+        switch(alpn) {
+        case ALPN_h3:
+          if(Curl_conn_may_http3(data, conn))
+            break;  /* not possible */
+          if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
+            CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
+            alpn_ids[alpn_count++] = alpn;
+          }
+          break;
+        case ALPN_h2:
+          if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
+            CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
+            alpn_ids[alpn_count++] = alpn;
           }
-          if(!present) {
-            switch(alpn) {
-            case ALPN_h3:
-              if(Curl_conn_may_http3(data, conn))
-                break;  /* not possible */
-              FALLTHROUGH();
-            case ALPN_h2:
-            case ALPN_h1:
-              alpn_ids[alpn_count++] = alpn;
-              break;
-            default: /* ignore */
-              break;
-            }
+          break;
+        case ALPN_h1:
+          if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
+            CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
+            alpn_ids[alpn_count++] = alpn;
           }
+          break;
+        default: /* ignore */
+          break;
         }
       }
+    }
 #endif
-      if(!alpn_count)
-        alpn_ids[alpn_count++] = ALPN_h2;
-      break;
-    case CURL_HTTP_VERSION_3ONLY:
+
+    if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+       (data->state.http_neg.wanted & CURL_HTTP_V3x) &&
+       !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
       result = Curl_conn_may_http3(data, conn);
-      if(result) /* cannot do it */
-        goto out;
-      alpn_ids[alpn_count++] = ALPN_h3;
-      break;
-    case CURL_HTTP_VERSION_3:
-      /* We assume that silently not even trying H3 is ok here */
-      if(Curl_conn_may_http3(data, conn) == CURLE_OK)
+      if(!result) {
+        CURL_TRC_CF(data, cf, "adding wanted h3");
         alpn_ids[alpn_count++] = ALPN_h3;
+      }
+      else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
+        goto out; /* only h3 allowed, not possible, error out */
+    }
+    if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+       (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
+       !cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
+      CURL_TRC_CF(data, cf, "adding wanted h2");
       alpn_ids[alpn_count++] = ALPN_h2;
-      break;
-    case CURL_HTTP_VERSION_2_0:
-    case CURL_HTTP_VERSION_2TLS:
-    case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
-      alpn_ids[alpn_count++] = ALPN_h2;
-      break;
-    case CURL_HTTP_VERSION_1_0:
-    case CURL_HTTP_VERSION_1_1:
+    }
+    else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+            (data->state.http_neg.wanted & CURL_HTTP_V1x) &&
+            !cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
+      CURL_TRC_CF(data, cf, "adding wanted h1");
       alpn_ids[alpn_count++] = ALPN_h1;
-      break;
-    default:
-      alpn_ids[alpn_count++] = ALPN_h2;
-      break;
     }
   }
 
   /* If we identified ALPNs to use, install our filter. Otherwise,
    * install nothing, so our call will use a default connect setup. */
   if(alpn_count) {
-    result = cf_http_connect_add(data, conn, sockindex, remotehost,
-                                 alpn_ids, alpn_count);
+    result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count);
   }
 
 out:

+ 1 - 4
Utilities/cmcurl/lib/cf-https-connect.h

@@ -38,20 +38,17 @@ extern struct Curl_cftype Curl_cft_http_connect;
 CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
                                   struct connectdata *conn,
                                   int sockindex,
-                                  const struct Curl_dns_entry *remotehost,
                                   bool try_h3, bool try_h21);
 
 CURLcode
 Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at,
                                   struct Curl_easy *data,
-                                  const struct Curl_dns_entry *remotehost,
                                   bool try_h3, bool try_h21);
 
 
 CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              struct connectdata *conn,
-                             int sockindex,
-                             const struct Curl_dns_entry *remotehost);
+                             int sockindex);
 
 
 #endif /* !defined(CURL_DISABLE_HTTP) */

+ 85 - 103
Utilities/cmcurl/lib/cf-socket.c

@@ -74,15 +74,17 @@
 #include "multiif.h"
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
 #include "inet_ntop.h"
-#include "inet_pton.h"
+#include "curlx/inet_pton.h"
 #include "progress.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 #include "conncache.h"
 #include "multihandle.h"
 #include "rand.h"
 #include "share.h"
 #include "strdup.h"
-#include "version_win32.h"
+#include "system_win32.h"
+#include "curlx/version_win32.h"
+#include "curlx/strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -113,8 +115,8 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
   int level = IPPROTO_TCP;
   char buffer[STRERROR_LEN];
 
-  if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
-                sizeof(onoff)) < 0)
+  if(setsockopt(sockfd, level, TCP_NODELAY,
+                (void *)&onoff, sizeof(onoff)) < 0)
     infof(data, "Could not set TCP_NODELAY: %s",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
 #else
@@ -133,8 +135,8 @@ static void nosigpipe(struct Curl_easy *data,
 {
   int onoff = 1;
   (void)data;
-  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
-                sizeof(onoff)) < 0) {
+  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
+                (void *)&onoff, sizeof(onoff)) < 0) {
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
     char buffer[STRERROR_LEN];
     infof(data, "Could not set SO_NOSIGPIPE: %s",
@@ -181,7 +183,7 @@ tcpkeepalive(struct Curl_easy *data,
 
   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
-        (void *)&optval, sizeof(optval)) < 0) {
+                (void *)&optval, sizeof(optval)) < 0) {
     infof(data, "Failed to set SO_KEEPALIVE on fd "
           "%" FMT_SOCKET_T ": errno %d",
           sockfd, SOCKERRNO);
@@ -234,7 +236,7 @@ tcpkeepalive(struct Curl_easy *data,
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
-          (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPIDLE on fd "
             "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
@@ -244,7 +246,7 @@ tcpkeepalive(struct Curl_easy *data,
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
-      (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE on fd "
             "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
@@ -254,7 +256,7 @@ tcpkeepalive(struct Curl_easy *data,
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
-      (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
             "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
@@ -264,7 +266,7 @@ tcpkeepalive(struct Curl_easy *data,
     optval = curlx_sltosi(data->set.tcp_keepintvl);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
-          (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPINTVL on fd "
             "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
@@ -285,7 +287,7 @@ tcpkeepalive(struct Curl_easy *data,
              curlx_sltosi(data->set.tcp_keepintvl);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
-          (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
             "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
     }
@@ -293,7 +295,7 @@ tcpkeepalive(struct Curl_easy *data,
 #ifdef TCP_KEEPCNT
     optval = curlx_sltosi(data->set.tcp_keepcnt);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
-                (void *)&optval, sizeof(optval)) < 0) {
+                  (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPCNT on fd "
             "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
     }
@@ -420,7 +422,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
 
   if(use_callback && conn && conn->fclosesocket) {
     int rc;
-    Curl_multi_closed(data, sock);
+    Curl_multi_will_close(data, sock);
     Curl_set_in_callback(data, TRUE);
     rc = conn->fclosesocket(conn->closesocket_client, sock);
     Curl_set_in_callback(data, FALSE);
@@ -429,7 +431,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
 
   if(conn)
     /* tell the multi-socket code about this */
-    Curl_multi_closed(data, sock);
+    Curl_multi_will_close(data, sock);
 
   sclose(sock);
 
@@ -460,9 +462,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
    Windows. Following function trying to detect OS version and skips
    SO_SNDBUF adjustment for Windows Vista and above.
 */
-#define DETECT_OS_NONE 0
-#define DETECT_OS_PREVISTA 1
-#define DETECT_OS_VISTA_OR_LATER 2
 
 void Curl_sndbuf_init(curl_socket_t sockfd)
 {
@@ -470,17 +469,7 @@ void Curl_sndbuf_init(curl_socket_t sockfd)
   int curval = 0;
   int curlen = sizeof(curval);
 
-  static int detectOsState = DETECT_OS_NONE;
-
-  if(detectOsState == DETECT_OS_NONE) {
-    if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
-                                    VERSION_GREATER_THAN_EQUAL))
-      detectOsState = DETECT_OS_VISTA_OR_LATER;
-    else
-      detectOsState = DETECT_OS_PREVISTA;
-  }
-
-  if(detectOsState == DETECT_OS_VISTA_OR_LATER)
+  if(Curl_isVistaOrGreater)
     return;
 
   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
@@ -685,21 +674,14 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
        * of the connection. The resolve functions should really be changed
        * to take a type parameter instead.
        */
-      unsigned char ipver = conn->ip_version;
-      int rc;
-
-      if(af == AF_INET)
-        conn->ip_version = CURL_IPRESOLVE_V4;
+      int ip_version = (af == AF_INET) ?
+                       CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_WHATEVER;
 #ifdef USE_IPV6
-      else if(af == AF_INET6)
-        conn->ip_version = CURL_IPRESOLVE_V6;
+      if(af == AF_INET6)
+        ip_version = CURL_IPRESOLVE_V6;
 #endif
 
-      rc = Curl_resolv(data, host, 80, FALSE, &h);
-      if(rc == CURLRESOLV_PENDING)
-        (void)Curl_resolver_wait_resolv(data, &h);
-      conn->ip_version = ipver;
-
+      (void)Curl_resolv_blocking(data, host, 80, ip_version, &h);
       if(h) {
         int h_af = h->addr->ai_family;
         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
@@ -732,7 +714,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
         if(scope_ptr)
           *(scope_ptr++) = '\0';
 #endif
-        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
+        if(curlx_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
           si6->sin6_family = AF_INET6;
           si6->sin6_port = htons(port);
 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -741,10 +723,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
                Curl_printable_address. The latter returns only numeric scope
                IDs and the former returns none at all. So the scope ID, if
                present, is known to be numeric */
-            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
-            if(scope_id > UINT_MAX)
+            curl_off_t scope_id;
+            if(curlx_str_number((const char **)CURL_UNCONST(&scope_ptr),
+                               &scope_id, UINT_MAX))
               return CURLE_UNSUPPORTED_PROTOCOL;
-
             si6->sin6_scope_id = (unsigned int)scope_id;
           }
 #endif
@@ -755,7 +737,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
 #endif
       /* IPv4 address */
       if((af == AF_INET) &&
-         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+         (curlx_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
         si4->sin_family = AF_INET;
         si4->sin_port = htons(port);
         sizeof_sa = sizeof(struct sockaddr_in);
@@ -855,7 +837,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
    *    Someone got to verify this on Win-NT 4.0, 2000."
    */
 
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
   Sleep(0);
 #else
   SleepEx(0, FALSE);
@@ -865,7 +847,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
 
   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
     err = SOCKERRNO;
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
   /* Old Windows CE versions do not support SO_ERROR */
   if(WSAENOPROTOOPT == err) {
     SET_SOCKERRNO(0);
@@ -879,7 +861,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
     err = 0;
   }
 #endif
-  if((0 == err) || (EISCONN == err))
+  if((0 == err) || (SOCKEISCONN == err))
     /* we are connected, awesome! */
     rc = TRUE;
   else
@@ -902,10 +884,10 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
                                       const char *ipaddress, int error)
 {
   switch(error) {
-  case EINPROGRESS:
-  case EWOULDBLOCK:
+  case SOCKEINPROGRESS:
+  case SOCKEWOULDBLOCK:
 #if defined(EAGAIN)
-#if (EAGAIN) != (EWOULDBLOCK)
+#if (EAGAIN) != (SOCKEWOULDBLOCK)
     /* On some platforms EAGAIN and EWOULDBLOCK are the
      * same value, and on others they are different, hence
      * the odd #if
@@ -932,15 +914,6 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
   }
 }
 
-/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
- * This happens often on TLS connections where the TLS implementation
- * tries to read the head of a TLS record, determine the length of the
- * full record and then make a subsequent read for that.
- * On large reads, we will not fill the buffer to avoid the double copy. */
-#define NW_RECV_CHUNK_SIZE    (64 * 1024)
-#define NW_RECV_CHUNKS         1
-#define NW_SMALL_READS        (1024)
-
 struct cf_socket_ctx {
   int transport;
   struct Curl_sockaddr_ex addr;      /* address to connect to */
@@ -983,28 +956,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
 
 #ifdef DEBUGBUILD
   {
-    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
+    const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
     if(p) {
-      long l = strtol(p, NULL, 10);
-      if(l >= 0 && l <= 100)
+      curl_off_t l;
+      if(!curlx_str_number(&p, &l, 100))
         ctx->wblock_percent = (int)l;
     }
     p = getenv("CURL_DBG_SOCK_WPARTIAL");
     if(p) {
-      long l = strtol(p, NULL, 10);
-      if(l >= 0 && l <= 100)
+      curl_off_t l;
+      if(!curlx_str_number(&p, &l, 100))
         ctx->wpartial_percent = (int)l;
     }
     p = getenv("CURL_DBG_SOCK_RBLOCK");
     if(p) {
-      long l = strtol(p, NULL, 10);
-      if(l >= 0 && l <= 100)
+      curl_off_t l;
+      if(!curlx_str_number(&p, &l, 100))
         ctx->rblock_percent = (int)l;
     }
     p = getenv("CURL_DBG_SOCK_RMAX");
     if(p) {
-      long l = strtol(p, NULL, 10);
-      if(l >= 0)
+      curl_off_t l;
+      if(!curlx_str_number(&p, &l, CURL_OFF_T_MAX))
         ctx->recv_max = (size_t)l;
     }
   }
@@ -1018,7 +991,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
   struct cf_socket_ctx *ctx = cf->ctx;
 
   if(ctx && CURL_SOCKET_BAD != ctx->sock) {
-    CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
+    CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
     if(ctx->sock == cf->conn->sock[cf->sockindex])
       cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
     socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
@@ -1040,7 +1013,7 @@ static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
   if(cf->connected) {
     struct cf_socket_ctx *ctx = cf->ctx;
 
-    CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
+    CURL_TRC_CF(data, cf, "cf_socket_shutdown, fd=%" FMT_SOCKET_T, ctx->sock);
     /* On TCP, and when the socket looks well and non-blocking mode
      * can be enabled, receive dangling bytes before close to avoid
      * entering RST states unnecessarily. */
@@ -1132,7 +1105,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
 
   (void)data;
   DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
-  ctx->started_at = Curl_now();
+  ctx->started_at = curlx_now();
 #ifdef SOCK_NONBLOCK
   /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
    * because we would not know how socketype is about to be used in the
@@ -1248,7 +1221,7 @@ out:
   }
   else if(isconnected) {
     set_local_ip(cf, data);
-    ctx->connected_at = Curl_now();
+    ctx->connected_at = curlx_now();
     cf->connected = TRUE;
   }
   CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
@@ -1313,7 +1286,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
 
 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
-                               bool blocking, bool *done)
+                               bool *done)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_COULDNT_CONNECT;
@@ -1325,9 +1298,6 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
-  if(blocking)
-    return CURLE_UNSUPPORTED_PROTOCOL;
-
   *done = FALSE; /* a negative world view is best */
   if(ctx->sock == CURL_SOCKET_BAD) {
     int error;
@@ -1370,7 +1340,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
   else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
     if(verifyconnect(ctx->sock, &ctx->error)) {
       /* we are connected with TCP, awesome! */
-      ctx->connected_at = Curl_now();
+      ctx->connected_at = curlx_now();
       set_local_ip(cf, data);
       *done = TRUE;
       cf->connected = TRUE;
@@ -1471,9 +1441,9 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
 {
   ULONG ideal;
   DWORD ideallen;
-  struct curltime n = Curl_now();
+  struct curltime n = curlx_now();
 
-  if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
+  if(curlx_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
     if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
                   &ideal, sizeof(ideal), &ideallen, 0, 0) &&
        ideal != ctx->sndbuf_size &&
@@ -1538,15 +1508,16 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     int sockerr = SOCKERRNO;
 
     if(
-#ifdef WSAEWOULDBLOCK
+#ifdef USE_WINSOCK
       /* This is how Windows does it */
-      (WSAEWOULDBLOCK == sockerr)
+      (SOCKEWOULDBLOCK == sockerr)
 #else
       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
          due to its inability to send off data without blocking. We therefore
          treat both error codes the same here */
-      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
-      (EINPROGRESS == sockerr)
+      (SOCKEWOULDBLOCK == sockerr) ||
+      (EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
+      (SOCKEINPROGRESS == sockerr)
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
@@ -1606,14 +1577,15 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     int sockerr = SOCKERRNO;
 
     if(
-#ifdef WSAEWOULDBLOCK
+#ifdef USE_WINSOCK
       /* This is how Windows does it */
-      (WSAEWOULDBLOCK == sockerr)
+      (SOCKEWOULDBLOCK == sockerr)
 #else
       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
          due to its inability to send off data without blocking. We therefore
          treat both error codes the same here */
-      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
+      (SOCKEWOULDBLOCK == sockerr) ||
+      (EAGAIN == sockerr) || (SOCKEINTR == sockerr)
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
@@ -1632,7 +1604,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
               *err);
   if(nread > 0 && !ctx->got_first_byte) {
-    ctx->first_byte_at = Curl_now();
+    ctx->first_byte_at = curlx_now();
     ctx->got_first_byte = TRUE;
   }
   return nread;
@@ -1743,7 +1715,7 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
     return CURLE_OK;
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->got_first_byte) {
-      timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
+      timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
       *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
     }
     else
@@ -1849,7 +1821,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
   /* QUIC needs a connected socket, nonblocking */
   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
 
-  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,  /* NOLINT */
+  /* error: The 1st argument to 'connect' is -1 but should be >= 0
+     NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions) */
+  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
                (curl_socklen_t)ctx->addr.addrlen);
   if(-1 == rc) {
     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
@@ -1867,8 +1841,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
    * non-blocking socket created by cf_socket_open() to it. Thus, we
    * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
    */
+#ifdef __linux__
   switch(ctx->addr.family) {
-#if defined(__linux__) && defined(IP_MTU_DISCOVER)
+#ifdef IP_MTU_DISCOVER
   case AF_INET: {
     int val = IP_PMTUDISC_DO;
     (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
@@ -1876,7 +1851,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
     break;
   }
 #endif
-#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
+#ifdef IPV6_MTU_DISCOVER
   case AF_INET6: {
     int val = IPV6_PMTUDISC_DO;
     (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
@@ -1886,11 +1861,12 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
 #endif
   }
 
-#if defined(__linux__) && defined(UDP_GRO) &&                                 \
+#if defined(UDP_GRO) &&                                                       \
   (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) &&                        \
   ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
   (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
                    (socklen_t)sizeof(one));
+#endif
 #endif
 
   return CURLE_OK;
@@ -1898,12 +1874,11 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
 
 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
-                               bool blocking, bool *done)
+                               bool *done)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_COULDNT_CONNECT;
 
-  (void)blocking;
   if(cf->connected) {
     *done = TRUE;
     return CURLE_OK;
@@ -2057,7 +2032,7 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
     timeout_ms = data->set.accepttimeout;
 #endif
 
-  now = Curl_now();
+  now = curlx_now();
   /* check if the generic timeout possibly is set shorter */
   other = Curl_timeleft(data, &now, FALSE);
   if(other && (other < timeout_ms))
@@ -2066,7 +2041,7 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
     timeout_ms = other;
   else {
     /* subtract elapsed time */
-    timeout_ms -= Curl_timediff(now, ctx->started_at);
+    timeout_ms -= curlx_timediff(now, ctx->started_at);
     if(!timeout_ms)
       /* avoid returning 0 as that means no timeout! */
       timeout_ms = -1;
@@ -2108,7 +2083,7 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
 
 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
-                                      bool blocking, bool *done)
+                                      bool *done)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
 #ifdef USE_IPV6
@@ -2124,7 +2099,6 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
 
   /* we start accepted, if we ever close, we cannot go on */
   (void)data;
-  (void)blocking;
   if(cf->connected) {
     *done = TRUE;
     return CURLE_OK;
@@ -2163,7 +2137,12 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
 
   if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
     size = sizeof(add);
+#ifdef HAVE_ACCEPT4
+    s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size,
+                         SOCK_NONBLOCK | SOCK_CLOEXEC);
+#else
     s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
+#endif
   }
 
   if(CURL_SOCKET_BAD == s_accepted) {
@@ -2172,7 +2151,9 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
   }
 
   infof(data, "Connection accepted from server");
+#ifndef HAVE_ACCEPT4
   (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
+#endif
   /* Replace any filter on SECONDARY with one listening on this socket */
   ctx->listening = FALSE;
   ctx->accepted = TRUE;
@@ -2183,7 +2164,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
   cf_tcp_set_accepted_remote_ip(cf, data);
   set_local_ip(cf, data);
   ctx->active = TRUE;
-  ctx->connected_at = Curl_now();
+  ctx->connected_at = curlx_now();
   cf->connected = TRUE;
   CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
               ", remote=%s port=%d)",
@@ -2201,6 +2182,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
     if(error)
       return CURLE_ABORTED_BY_CALLBACK;
   }
+  *done = TRUE;
   return CURLE_OK;
 }
 
@@ -2249,7 +2231,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
 
-  ctx->started_at = Curl_now();
+  ctx->started_at = curlx_now();
   conn->sock[sockindex] = ctx->sock;
   set_local_ip(cf, data);
   CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T

+ 1 - 1
Utilities/cmcurl/lib/cf-socket.h

@@ -25,7 +25,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "curlx/nonblock.h" /* for curlx_nonblock() */
 #include "sockaddr.h"
 
 struct Curl_addrinfo;

+ 82 - 22
Utilities/cmcurl/lib/cfilters.c

@@ -28,13 +28,14 @@
 #include "strerror.h"
 #include "cfilters.h"
 #include "connect.h"
-#include "url.h" /* for Curl_safefree() */
+#include "url.h"
 #include "sendf.h"
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
 #include "multiif.h"
 #include "progress.h"
 #include "select.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
+#include "curlx/strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -197,11 +198,11 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
   }
 
   *done = FALSE;
-  now = Curl_now();
+  now = curlx_now();
   if(!Curl_shutdown_started(data, sockindex)) {
-    DEBUGF(infof(data, "shutdown start on%s connection",
-           sockindex ? " secondary" : ""));
-    Curl_shutdown_start(data, sockindex, &now);
+    CURL_TRC_M(data, "shutdown start on%s connection",
+               sockindex ? " secondary" : "");
+    Curl_shutdown_start(data, sockindex, 0, &now);
   }
   else {
     timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
@@ -367,10 +368,10 @@ bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
 
 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              bool blocking, bool *done)
+                              bool *done)
 {
   if(cf)
-    return cf->cft->do_connect(cf, data, blocking, done);
+    return cf->cft->do_connect(cf, data, done);
   return CURLE_FAILED_INIT;
 }
 
@@ -404,6 +405,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
                            bool blocking,
                            bool *done)
 {
+#define CF_CONN_NUM_POLLS_ON_STACK 5
+  struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
+  struct curl_pollfds cpfds;
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
@@ -411,14 +415,17 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
   DEBUGASSERT(data->conn);
 
   cf = data->conn->cfilter[sockindex];
-  DEBUGASSERT(cf);
   if(!cf) {
     *done = FALSE;
     return CURLE_FAILED_INIT;
   }
 
   *done = cf->connected;
-  if(!*done) {
+  if(*done)
+    return CURLE_OK;
+
+  Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
+  while(!*done) {
     if(Curl_conn_needs_flush(data, sockindex)) {
       DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
       result = Curl_conn_flush(data, sockindex);
@@ -426,24 +433,75 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
         return result;
     }
 
-    result = cf->cft->do_connect(cf, data, blocking, done);
+    result = cf->cft->do_connect(cf, data, done);
+    CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
+                blocking, result, *done);
     if(!result && *done) {
       /* Now that the complete filter chain is connected, let all filters
        * persist information at the connection. E.g. cf-socket sets the
        * socket and ip related information. */
       cf_cntrl_update_info(data, data->conn);
       conn_report_connect_stats(data, data->conn);
-      data->conn->keepalive = Curl_now();
+      data->conn->keepalive = curlx_now();
       Curl_verboseconnect(data, data->conn, sockindex);
+      goto out;
     }
     else if(result) {
+      CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
+                  result);
       conn_report_connect_stats(data, data->conn);
+      goto out;
+    }
+
+    if(!blocking)
+      goto out;
+    else {
+      /* check allowed time left */
+      const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+      curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+      struct easy_pollset ps;
+      int rc;
+
+      if(timeout_ms < 0) {
+        /* no need to continue if time already is up */
+        failf(data, "connect timeout");
+        result = CURLE_OPERATION_TIMEDOUT;
+        goto out;
+      }
+
+      CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
+      Curl_pollfds_reset(&cpfds);
+      memset(&ps, 0, sizeof(ps));
+      /* In general, we want to send after connect, wait on that. */
+      if(sockfd != CURL_SOCKET_BAD)
+        Curl_pollset_set_out_only(data, &ps, sockfd);
+      Curl_conn_adjust_pollset(data, data->conn, &ps);
+      result = Curl_pollfds_add_ps(&cpfds, &ps);
+      if(result)
+        goto out;
+
+      rc = Curl_poll(cpfds.pfds, cpfds.n,
+                     CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
+      CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
+                  rc);
+      if(rc < 0) {
+        result = CURLE_COULDNT_CONNECT;
+        goto out;
+      }
+      /* continue iterating */
     }
   }
 
+out:
+  Curl_pollfds_cleanup(&cpfds);
   return result;
 }
 
+bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
+{
+  return (conn->cfilter[sockindex] != NULL);
+}
+
 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
 {
   struct Curl_cfilter *cf;
@@ -496,13 +554,14 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
   return FALSE;
 }
 
-unsigned char Curl_conn_http_version(struct Curl_easy *data)
+unsigned char Curl_conn_http_version(struct Curl_easy *data,
+                                     struct connectdata *conn)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_UNKNOWN_OPTION;
   unsigned char v = 0;
 
-  cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
+  cf = conn->cfilter[FIRSTSOCKET];
   for(; cf; cf = cf->next) {
     if(cf->cft->flags & CF_TYPE_HTTP) {
       int value = 0;
@@ -571,14 +630,15 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
 }
 
 void Curl_conn_adjust_pollset(struct Curl_easy *data,
-                               struct easy_pollset *ps)
+                              struct connectdata *conn,
+                              struct easy_pollset *ps)
 {
   int i;
 
   DEBUGASSERT(data);
-  DEBUGASSERT(data->conn);
+  DEBUGASSERT(conn);
   for(i = 0; i < 2; ++i) {
-    Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
+    Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
   }
 }
 
@@ -880,14 +940,14 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
   DEBUGASSERT(data->conn);
   conn = data->conn;
 #ifdef DEBUGBUILD
-  {
+  if(write_len) {
     /* Allow debug builds to override this logic to force short sends
     */
-    char *p = getenv("CURL_SMALLSENDS");
+    const char *p = getenv("CURL_SMALLSENDS");
     if(p) {
-      size_t altsize = (size_t)strtoul(p, NULL, 10);
-      if(altsize)
-        write_len = CURLMIN(write_len, altsize);
+      curl_off_t altsize;
+      if(!curlx_str_number(&p, &altsize, write_len))
+        write_len = (size_t)altsize;
     }
   }
 #endif

+ 24 - 17
Utilities/cmcurl/lib/cfilters.h

@@ -24,7 +24,7 @@
  *
  ***************************************************************************/
 
-#include "timediff.h"
+#include "curlx/timediff.h"
 
 struct Curl_cfilter;
 struct Curl_easy;
@@ -51,7 +51,7 @@ typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
 
 typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
-                                  bool blocking, bool *done);
+                                  bool *done);
 
 /* Return the hostname and port the connection goes to.
  * This may change with the connection state of filters when tunneling
@@ -65,10 +65,10 @@ typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
  * @param pport  on return, contains the port number
  */
 typedef void     Curl_cft_get_host(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  const char **phost,
-                                  const char **pdisplay_host,
-                                  int *pport);
+                                   struct Curl_easy *data,
+                                   const char **phost,
+                                   const char **pdisplay_host,
+                                   int *pport);
 
 struct easy_pollset;
 
@@ -96,8 +96,8 @@ struct easy_pollset;
  * @param ps     the pollset (inout) for the easy handle
  */
 typedef void     Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
-                                          struct Curl_easy *data,
-                                          struct easy_pollset *ps);
+                                         struct Curl_easy *data,
+                                         struct easy_pollset *ps);
 
 typedef bool     Curl_cft_data_pending(struct Curl_cfilter *cf,
                                        const struct Curl_easy *data);
@@ -245,8 +245,8 @@ void     Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
                               const char **phost, const char **pdisplay_host,
                               int *pport);
 void     Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data,
-                                     struct easy_pollset *ps);
+                                    struct Curl_easy *data,
+                                    struct easy_pollset *ps);
 bool     Curl_cf_def_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data);
 ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -255,8 +255,8 @@ ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
 ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                           char *buf, size_t len, CURLcode *err);
 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                int event, int arg1, void *arg2);
+                           struct Curl_easy *data,
+                           int event, int arg1, void *arg2);
 bool     Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    bool *input_pending);
@@ -324,7 +324,7 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data,
 
 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              bool blocking, bool *done);
+                              bool *done);
 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                           const void *buf, size_t len, bool eos,
@@ -370,6 +370,11 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
 CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
                            bool blocking, bool *done);
 
+/**
+ * Check if a filter chain at `sockindex` for connection `conn` exists.
+ */
+bool Curl_conn_is_setup(struct connectdata *conn, int sockindex);
+
 /**
  * Check if the filter chain at `sockindex` for connection `conn` is
  * completely connected.
@@ -399,7 +404,8 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
  * Return the HTTP version used on the FIRSTSOCKET connection filters
  * or 0 if unknown. Value otherwise is 09, 10, 11, etc.
  */
-unsigned char Curl_conn_http_version(struct Curl_easy *data);
+unsigned char Curl_conn_http_version(struct Curl_easy *data,
+                                     struct connectdata *conn);
 
 /**
  * Close the filter chain at `sockindex` for connection `data->conn`.
@@ -454,7 +460,8 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
  * Adjust pollset from filters installed at transfer's connection.
  */
 void Curl_conn_adjust_pollset(struct Curl_easy *data,
-                               struct easy_pollset *ps);
+                              struct connectdata *conn,
+                              struct easy_pollset *ps);
 
 /**
  * Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
@@ -654,7 +661,7 @@ struct cf_call_data {
     (save) = CF_CTX_CALL_DATA(cf); \
     DEBUGASSERT((save).data == NULL || (save).depth > 0); \
     CF_CTX_CALL_DATA(cf).depth++;  \
-    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
   } while(0)
 
 #define CF_DATA_RESTORE(cf, save) \
@@ -669,7 +676,7 @@ struct cf_call_data {
 #define CF_DATA_SAVE(save, cf, data) \
   do { \
     (save) = CF_CTX_CALL_DATA(cf); \
-    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
   } while(0)
 
 #define CF_DATA_RESTORE(cf, save) \

Diferenças do arquivo suprimidas por serem muito extensas
+ 250 - 801
Utilities/cmcurl/lib/conncache.c


+ 25 - 62
Utilities/cmcurl/lib/conncache.h

@@ -26,7 +26,7 @@
  ***************************************************************************/
 
 #include <curl/curl.h>
-#include "timeval.h"
+#include "curlx/timeval.h"
 
 struct connectdata;
 struct Curl_easy;
@@ -36,16 +36,17 @@ struct Curl_multi;
 struct Curl_share;
 
 /**
- * Callback invoked when disconnecting connections.
- * @param data    transfer last handling the connection, not attached
- * @param conn    the connection to discard
- * @param aborted if the connection is being aborted
- * @return if the connection is being aborted, e.g. should NOT perform
- *         a shutdown and just close.
- **/
-typedef bool Curl_cpool_disconnect_cb(struct Curl_easy *data,
-                                      struct connectdata *conn,
-                                      bool aborted);
+ * Terminate the connection, e.g. close and destroy.
+ * If the connection is in a cpool, remove it.
+ * If a `cshutdn` is available (e.g. data has a multi handle),
+ * pass the connection to that for controlled shutdown.
+ * Otherwise terminate it right away.
+ * Takes ownership of `conn`.
+ * `data` should not be attached to a connection.
+ */
+void Curl_conn_terminate(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         bool aborted);
 
 struct cpool {
    /* the pooled connections, bundled per destination */
@@ -54,22 +55,19 @@ struct cpool {
   curl_off_t next_connection_id;
   curl_off_t next_easy_id;
   struct curltime last_cleanup;
-  struct Curl_llist shutdowns;  /* The connections being shut down */
-  struct Curl_easy *idata; /* internal handle used for discard */
-  struct Curl_multi *multi; /* != NULL iff pool belongs to multi */
-  struct Curl_share *share; /* != NULL iff pool belongs to share */
-  Curl_cpool_disconnect_cb *disconnect_cb;
+  struct Curl_easy *idata; /* internal handle for maintenance */
+  struct Curl_share *share; /* != NULL if pool belongs to share */
   BIT(locked);
+  BIT(initialised);
 };
 
 /* Init the pool, pass multi only if pool is owned by it.
- * returns 1 on error, 0 is fine.
+ * Cannot fail.
  */
-int Curl_cpool_init(struct cpool *cpool,
-                    Curl_cpool_disconnect_cb *disconnect_cb,
-                    struct Curl_multi *multi,
-                    struct Curl_share *share,
-                    size_t size);
+void Curl_cpool_init(struct cpool *cpool,
+                     struct Curl_easy *idata,
+                     struct Curl_share *share,
+                     size_t size);
 
 /* Destroy all connections and free all members */
 void Curl_cpool_destroy(struct cpool *connc);
@@ -78,14 +76,13 @@ void Curl_cpool_destroy(struct cpool *connc);
  * Assigns `data->id`. */
 void Curl_cpool_xfer_init(struct Curl_easy *data);
 
-/**
- * Get the connection with the given id from the transfer's pool.
- */
+/* Get the connection with the given id from `data`'s conn pool. */
 struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
                                         curl_off_t conn_id);
 
-CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
-                             struct connectdata *conn) WARN_UNUSED_RESULT;
+/* Add the connection to the pool. */
+CURLcode Curl_cpool_add(struct Curl_easy *data,
+                        struct connectdata *conn) WARN_UNUSED_RESULT;
 
 /**
  * Return if the pool has reached its configured limits for adding
@@ -110,14 +107,13 @@ typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
  * All callbacks are invoked while the pool's lock is held.
  * @param data        current transfer
  * @param destination match agaonst `conn->destination` in pool
- * @param dest_len    destination length, including terminating NUL
  * @param conn_cb     must be present, called for each connection in the
  *                    bundle until it returns TRUE
  * @return combined result of last conn_db and result_cb or FALSE if no
                       connections were present.
  */
 bool Curl_cpool_find(struct Curl_easy *data,
-                     const char *destination, size_t dest_len,
+                     const char *destination,
                      Curl_cpool_conn_match_cb *conn_cb,
                      Curl_cpool_done_match_cb *done_cb,
                      void *userdata);
@@ -131,17 +127,6 @@ bool Curl_cpool_find(struct Curl_easy *data,
 bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
                               struct connectdata *conn);
 
-/**
- * Remove the connection from the pool and tear it down.
- * If `aborted` is FALSE, the connection will be shut down first
- * before closing and destroying it.
- * If the shutdown is not immediately complete, the connection
- * will be placed into the pool's shutdown queue.
- */
-void Curl_cpool_disconnect(struct Curl_easy *data,
-                           struct connectdata *conn,
-                           bool aborted);
-
 /**
  * This function scans the data's connection pool for half-open/dead
  * connections, closes and removes them.
@@ -178,26 +163,4 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
                           struct connectdata *conn,
                           Curl_cpool_conn_do_cb *cb, void *cbdata);
 
-/**
- * Add sockets and POLLIN/OUT flags for connections handled by the pool.
- */
-CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
-                                struct curl_pollfds *cpfds);
-unsigned int Curl_cpool_add_waitfds(struct cpool *connc,
-                                    struct Curl_waitfds *cwfds);
-
-void Curl_cpool_setfds(struct cpool *cpool,
-                       fd_set *read_fd_set, fd_set *write_fd_set,
-                       int *maxfd);
-
-/**
- * Perform maintenance on connections in the pool. Specifically,
- * progress the shutdown of connections in the queue.
- */
-void Curl_cpool_multi_perform(struct Curl_multi *multi);
-
-void Curl_cpool_multi_socket(struct Curl_multi *multi,
-                             curl_socket_t s, int ev_bitmask);
-
-
 #endif /* HEADER_CURL_CONNCACHE_H */

+ 75 - 71
Utilities/cmcurl/lib/connect.c

@@ -67,14 +67,14 @@
 #include "multiif.h"
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
 #include "inet_ntop.h"
-#include "inet_pton.h"
+#include "curlx/inet_pton.h"
 #include "vtls/vtls.h" /* for vtsl cfilters */
 #include "progress.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 #include "conncache.h"
 #include "multihandle.h"
 #include "share.h"
-#include "version_win32.h"
+#include "curlx/version_win32.h"
 #include "vquic/vquic.h" /* for quic cfilters */
 #include "http_proxy.h"
 #include "socks.h"
@@ -87,7 +87,7 @@
 
 #if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
 
-enum alpnid Curl_alpn2alpnid(char *name, size_t len)
+enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
 {
   if(len == 2) {
     if(strncasecompare(name, "h1", 2))
@@ -112,7 +112,7 @@ enum alpnid Curl_alpn2alpnid(char *name, size_t len)
  * infinite time left). If the value is negative, the timeout time has already
  * elapsed.
  * @param data the transfer to check on
- * @param nowp timestamp to use for calculation, NULL to use Curl_now()
+ * @param nowp timestamp to use for calculation, NULL to use curlx_now()
  * @param duringconnect TRUE iff connect timeout is also taken into account.
  * @unittest: 1303
  */
@@ -133,13 +133,13 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
     return 0; /* no timeout in place or checked, return "no limit" */
 
   if(!nowp) {
-    now = Curl_now();
+    now = curlx_now();
     nowp = &now;
   }
 
   if(data->set.timeout > 0) {
     timeleft_ms = data->set.timeout -
-                  Curl_timediff(*nowp, data->progress.t_startop);
+                  curlx_timediff(*nowp, data->progress.t_startop);
     if(!timeleft_ms)
       timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
     if(!duringconnect)
@@ -150,7 +150,7 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
     timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
       data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
     ctimeleft_ms = ctimeout_ms -
-                   Curl_timediff(*nowp, data->progress.t_startsingle);
+                   curlx_timediff(*nowp, data->progress.t_startsingle);
     if(!ctimeleft_ms)
       ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
     if(!timeleft_ms)
@@ -161,18 +161,24 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
 }
 
 void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
-                         struct curltime *nowp)
+                         int timeout_ms, struct curltime *nowp)
 {
   struct curltime now;
 
   DEBUGASSERT(data->conn);
   if(!nowp) {
-    now = Curl_now();
+    now = curlx_now();
     nowp = &now;
   }
   data->conn->shutdown.start[sockindex] = *nowp;
-  data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
-    data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
+  data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
+    (unsigned int)timeout_ms :
+    ((data->set.shutdowntimeout > 0) ?
+     data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
+  /* Set a timer, unless we operate on the admin handle */
+  if(data->mid && data->conn->shutdown.timeout_ms)
+    Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
+                   EXPIRE_SHUTDOWN);
 }
 
 timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
@@ -185,11 +191,11 @@ timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
     return 0; /* not started or no limits */
 
   if(!nowp) {
-    now = Curl_now();
+    now = curlx_now();
     nowp = &now;
   }
   left_ms = conn->shutdown.timeout_ms -
-            Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
+            curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
   return left_ms ? left_ms : -1;
 }
 
@@ -204,7 +210,7 @@ timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
     if(!conn->shutdown.start[i].tv_sec)
       continue;
     if(!nowp) {
-      now = Curl_now();
+      now = curlx_now();
       nowp = &now;
     }
     ms = Curl_shutdown_timeleft(conn, i, nowp);
@@ -266,8 +272,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
   switch(sa->sa_family) {
     case AF_INET:
       si = (struct sockaddr_in *)(void *) sa;
-      if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
-                        addr, MAX_IPADR_LEN)) {
+      if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
         unsigned short us_port = ntohs(si->sin_port);
         *port = us_port;
         return TRUE;
@@ -276,8 +281,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 #ifdef USE_IPV6
     case AF_INET6:
       si6 = (struct sockaddr_in6 *)(void *) sa;
-      if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
-                        addr, MAX_IPADR_LEN)) {
+      if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
         unsigned short us_port = ntohs(si6->sin6_port);
         *port = us_port;
         return TRUE;
@@ -301,7 +305,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 
   addr[0] = '\0';
   *port = 0;
-  errno = EAFNOSUPPORT;
+  CURL_SETERRNO(SOCKEAFNOSUPPORT);
   return FALSE;
 }
 
@@ -404,7 +408,6 @@ typedef enum {
 struct cf_he_ctx {
   int transport;
   cf_ip_connect_create *cf_create;
-  const struct Curl_dns_entry *remotehost;
   cf_connect_state state;
   struct eyeballer *baller[2];
   struct eyeballer *winner;
@@ -541,7 +544,7 @@ static CURLcode baller_start(struct Curl_cfilter *cf,
   baller->has_started = TRUE;
 
   while(baller->addr) {
-    baller->started = Curl_now();
+    baller->started = curlx_now();
     baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ?
       USETIME(timeoutms) : timeoutms;
     baller_initiate(cf, data, baller);
@@ -593,18 +596,18 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
   *connected = baller->connected;
   if(!baller->result &&  !*connected) {
     /* evaluate again */
-    baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected);
+    baller->result = Curl_conn_cf_connect(baller->cf, data, connected);
 
     if(!baller->result) {
       if(*connected) {
         baller->connected = TRUE;
         baller->is_done = TRUE;
       }
-      else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
+      else if(curlx_timediff(*now, baller->started) >= baller->timeoutms) {
         infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
               "ms, move on!", baller->name, baller->timeoutms);
-#if defined(ETIMEDOUT)
-        baller->error = ETIMEDOUT;
+#ifdef SOCKETIMEDOUT
+        baller->error = SOCKETIMEDOUT;
 #endif
         baller->result = CURLE_OPERATION_TIMEDOUT;
       }
@@ -638,7 +641,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
    * cot ballers in a QUIC appropriate way. */
 evaluate:
   *connected = FALSE; /* a negative world view is best */
-  now = Curl_now();
+  now = curlx_now();
   ongoing = not_started = 0;
   for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) {
     struct eyeballer *baller = ctx->baller[i];
@@ -693,7 +696,7 @@ evaluate:
    * start new ballers or return ok. */
   if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
     failf(data, "Connection timeout after %" FMT_OFF_T " ms",
-          Curl_timediff(now, data->progress.t_startsingle));
+          curlx_timediff(now, data->progress.t_startsingle));
     return CURLE_OPERATION_TIMEDOUT;
   }
 
@@ -709,7 +712,7 @@ evaluate:
       /* We start its primary baller has failed to connect or if
        * its start delay_ms have expired */
       if((baller->primary && baller->primary->is_done) ||
-          Curl_timediff(now, ctx->started) >= baller->delay_ms) {
+          curlx_timediff(now, ctx->started) >= baller->delay_ms) {
         baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE));
         if(baller->is_done) {
           CURL_TRC_CF(data, cf, "%s done", baller->name);
@@ -762,14 +765,11 @@ evaluate:
   failf(data, "Failed to connect to %s port %u after "
         "%" FMT_TIMEDIFF_T " ms: %s",
         hostname, conn->primary.remote_port,
-        Curl_timediff(now, data->progress.t_startsingle),
+        curlx_timediff(now, data->progress.t_startsingle),
         curl_easy_strerror(result));
 
-#ifdef WSAETIMEDOUT
-  if(WSAETIMEDOUT == data->state.os_errno)
-    result = CURLE_OPERATION_TIMEDOUT;
-#elif defined(ETIMEDOUT)
-  if(ETIMEDOUT == data->state.os_errno)
+#ifdef SOCKETIMEDOUT
+  if(SOCKETIMEDOUT == data->state.os_errno)
     result = CURLE_OPERATION_TIMEDOUT;
 #endif
 
@@ -781,8 +781,7 @@ evaluate:
  * There might be more than one IP address to try out.
  */
 static CURLcode start_connect(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const struct Curl_dns_entry *remotehost)
+                              struct Curl_easy *data)
 {
   struct cf_he_ctx *ctx = cf->ctx;
   struct connectdata *conn = cf->conn;
@@ -790,6 +789,10 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
   int ai_family0 = 0, ai_family1 = 0;
   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
   const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
+  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
+
+  if(!dns)
+    return CURLE_FAILED_INIT;
 
   if(timeout_ms < 0) {
     /* a precaution, no need to continue if time already is up */
@@ -797,9 +800,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
     return CURLE_OPERATION_TIMEDOUT;
   }
 
-  ctx->started = Curl_now();
+  ctx->started = curlx_now();
 
-  /* remotehost->addr is the list of addresses from the resolver, each
+  /* dns->addr is the list of addresses from the resolver, each
    * with an address family. The list has at least one entry, possibly
    * many more.
    * We try at most 2 at a time, until we either get a connection or
@@ -811,27 +814,27 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
   if(conn->ip_version == CURL_IPRESOLVE_V6) {
 #ifdef USE_IPV6
     ai_family0 = AF_INET6;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
 #endif
   }
   else if(conn->ip_version == CURL_IPRESOLVE_V4) {
     ai_family0 = AF_INET;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
   }
   else {
     /* no user preference, we try ipv6 always first when available */
 #ifdef USE_IPV6
     ai_family0 = AF_INET6;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
 #endif
     /* next candidate is ipv4 */
     ai_family1 = AF_INET;
-    addr1 = addr_first_match(remotehost->addr, ai_family1);
+    addr1 = addr_first_match(dns->addr, ai_family1);
     /* no ip address families, probably AF_UNIX or something, use the
      * address family given to us */
-    if(!addr1  && !addr0 && remotehost->addr) {
-      ai_family0 = remotehost->addr->ai_family;
-      addr0 = addr_first_match(remotehost->addr, ai_family0);
+    if(!addr1  && !addr0 && dns->addr) {
+      ai_family0 = dns->addr->ai_family;
+      addr0 = addr_first_match(dns->addr, ai_family0);
     }
   }
 
@@ -948,7 +951,7 @@ static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
 
 static CURLcode cf_he_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              bool blocking, bool *done)
+                              bool *done)
 {
   struct cf_he_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
@@ -958,7 +961,6 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
-  (void)blocking;
   DEBUGASSERT(ctx);
   *done = FALSE;
 
@@ -966,7 +968,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
     case SCFST_INIT:
       DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
       DEBUGASSERT(!cf->connected);
-      result = start_connect(cf, data, ctx->remotehost);
+      result = start_connect(cf, data);
       if(result)
         return result;
       ctx->state = SCFST_WAITING;
@@ -1058,7 +1060,7 @@ static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
     memset(&t, 0, sizeof(t));
     if(baller && baller->cf &&
        !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) {
-      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0)
         tmax = t;
     }
   }
@@ -1158,7 +1160,6 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
                          struct Curl_easy *data,
                          struct connectdata *conn,
                          cf_ip_connect_create *cf_create,
-                         const struct Curl_dns_entry *remotehost,
                          int transport)
 {
   struct cf_he_ctx *ctx = NULL;
@@ -1174,14 +1175,13 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
   }
   ctx->transport = transport;
   ctx->cf_create = cf_create;
-  ctx->remotehost = remotehost;
 
   result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx);
 
 out:
   if(result) {
     Curl_safefree(*pcf);
-    Curl_safefree(ctx);
+    free(ctx);
   }
   return result;
 }
@@ -1220,7 +1220,6 @@ static cf_ip_connect_create *get_cf_create(int transport)
 
 static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
                                    struct Curl_easy *data,
-                                   const struct Curl_dns_entry *remotehost,
                                    int transport)
 {
   cf_ip_connect_create *cf_create;
@@ -1235,8 +1234,7 @@ static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
     return CURLE_UNSUPPORTED_PROTOCOL;
   }
   result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
-                                    cf_create, remotehost,
-                                    transport);
+                                    cf_create, transport);
   if(result)
     return result;
 
@@ -1256,17 +1254,17 @@ typedef enum {
 
 struct cf_setup_ctx {
   cf_setup_state state;
-  const struct Curl_dns_entry *remotehost;
   int ssl_mode;
   int transport;
 };
 
 static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
-                                 bool blocking, bool *done)
+                                 bool *done)
 {
   struct cf_setup_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
+  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
 
   if(cf->connected) {
     *done = TRUE;
@@ -1275,14 +1273,17 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
 
   /* connect current sub-chain */
 connect_sub_chain:
+  if(!dns)
+    return CURLE_FAILED_INIT;
+
   if(cf->next && !cf->next->connected) {
-    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    result = Curl_conn_cf_connect(cf->next, data, done);
     if(result || !*done)
       return result;
   }
 
   if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
-    result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport);
+    result = cf_he_insert_after(cf, data, ctx->transport);
     if(result)
       return result;
     ctx->state = CF_SETUP_CNNCT_EYEBALLS;
@@ -1410,7 +1411,6 @@ struct Curl_cftype Curl_cft_setup = {
 
 static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
                                 struct Curl_easy *data,
-                                const struct Curl_dns_entry *remotehost,
                                 int transport,
                                 int ssl_mode)
 {
@@ -1425,7 +1425,6 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
     goto out;
   }
   ctx->state = CF_SETUP_INIT;
-  ctx->remotehost = remotehost;
   ctx->ssl_mode = ssl_mode;
   ctx->transport = transport;
 
@@ -1436,14 +1435,15 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
 
 out:
   *pcf = result ? NULL : cf;
-  free(ctx);
+  if(ctx) {
+    free(ctx);
+  }
   return result;
 }
 
 static CURLcode cf_setup_add(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex,
-                             const struct Curl_dns_entry *remotehost,
                              int transport,
                              int ssl_mode)
 {
@@ -1451,7 +1451,7 @@ static CURLcode cf_setup_add(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  result = cf_setup_create(&cf, data, transport, ssl_mode);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -1476,7 +1476,6 @@ void Curl_debug_set_transport_provider(int transport,
 
 CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                     struct Curl_easy *data,
-                                    const struct Curl_dns_entry *remotehost,
                                     int transport,
                                     int ssl_mode)
 {
@@ -1484,7 +1483,7 @@ CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
   CURLcode result;
 
   DEBUGASSERT(data);
-  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  result = cf_setup_create(&cf, data, transport, ssl_mode);
   if(result)
     goto out;
   Curl_conn_cf_insert_after(cf_at, cf);
@@ -1495,19 +1494,23 @@ out:
 CURLcode Curl_conn_setup(struct Curl_easy *data,
                          struct connectdata *conn,
                          int sockindex,
-                         const struct Curl_dns_entry *remotehost,
+                         struct Curl_dns_entry *dns,
                          int ssl_mode)
 {
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
   DEBUGASSERT(conn->handler);
+  DEBUGASSERT(dns);
+
+  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
+  data->state.dns[sockindex] = dns;
 
 #if !defined(CURL_DISABLE_HTTP)
   if(!conn->cfilter[sockindex] &&
      conn->handler->protocol == CURLPROTO_HTTPS) {
     DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
-    result = Curl_cf_https_setup(data, conn, sockindex, remotehost);
+    result = Curl_cf_https_setup(data, conn, sockindex);
     if(result)
       goto out;
   }
@@ -1515,13 +1518,14 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
 
   /* Still no cfilter set, apply default. */
   if(!conn->cfilter[sockindex]) {
-    result = cf_setup_add(data, conn, sockindex, remotehost,
-                          conn->transport, ssl_mode);
+    result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
     if(result)
       goto out;
   }
 
   DEBUGASSERT(conn->cfilter[sockindex]);
 out:
+  if(result)
+    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
   return result;
 }

+ 5 - 6
Utilities/cmcurl/lib/connect.h

@@ -25,14 +25,14 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "curlx/nonblock.h" /* for curlx_nonblock() */
 #include "sockaddr.h"
-#include "timeval.h"
+#include "curlx/timeval.h"
 
 struct Curl_dns_entry;
 struct ip_quadruple;
 
-enum alpnid Curl_alpn2alpnid(char *name, size_t len);
+enum alpnid Curl_alpn2alpnid(const char *name, size_t len);
 
 /* generic function that returns how much time there is left to run, according
    to the timeouts set */
@@ -45,7 +45,7 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
 #define DEFAULT_SHUTDOWN_TIMEOUT_MS   (2 * 1000)
 
 void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
-                         struct curltime *nowp);
+                         int timeout_ms, struct curltime *nowp);
 
 /* return how much time there is left to shutdown the connection at
  * sockindex. Returns 0 if there is no limit or shutdown has not started. */
@@ -126,7 +126,6 @@ typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
 
 CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                     struct Curl_easy *data,
-                                    const struct Curl_dns_entry *remotehost,
                                     int transport,
                                     int ssl_mode);
 
@@ -138,7 +137,7 @@ CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
 CURLcode Curl_conn_setup(struct Curl_easy *data,
                          struct connectdata *conn,
                          int sockindex,
-                         const struct Curl_dns_entry *remotehost,
+                         struct Curl_dns_entry *dns,
                          int ssl_mode);
 
 extern struct Curl_cftype Curl_cft_happy_eyeballs;

+ 27 - 17
Utilities/cmcurl/lib/content_encoding.c

@@ -65,12 +65,15 @@
 
 /* allow no more than 5 "chained" compression steps */
 #define MAX_ENCODE_STACK 5
+
+#if defined(HAVE_LIBZ) || defined(HAVE_BROTLI) || defined(HAVE_ZSTD)
 #define DECOMPRESS_BUFFER_SIZE 16384 /* buffer size for decompressed data */
+#endif
 
 #ifdef HAVE_LIBZ
 
-#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
-#error "requires zlib 1.2.0.4 or newer"
+#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1252)
+#error "requires zlib 1.2.5.2 or newer"
 #endif
 
 typedef enum {
@@ -163,7 +166,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;         /* zlib state structure */
   uInt nread = z->avail_in;
-  Bytef *orig_in = z->next_in;
+  z_const Bytef *orig_in = z->next_in;
   bool done = FALSE;
   CURLcode result = CURLE_OK;   /* Curl_client_write status */
 
@@ -183,13 +186,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
     z->next_out = (Bytef *) zp->buffer;
     z->avail_out = DECOMPRESS_BUFFER_SIZE;
 
-#ifdef Z_BLOCK
-    /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
     status = inflate(z, Z_BLOCK);
-#else
-    /* fallback for zlib ver. < 1.2.0.5 */
-    status = inflate(z, Z_SYNC_FLUSH);
-#endif
 
     /* Flush output data if some. */
     if(z->avail_out != DECOMPRESS_BUFFER_SIZE) {
@@ -220,9 +217,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
       /* some servers seem to not generate zlib headers, so this is an attempt
          to fix and continue anyway */
       if(zp->zlib_init == ZLIB_INIT) {
-        /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
-        (void) inflateEnd(z);     /* do not care about the return code */
-        if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
+        if(inflateReset2(z, -MAX_WBITS) == Z_OK) {
           z->next_in = orig_in;
           z->avail_in = nread;
           zp->zlib_init = ZLIB_INFLATING;
@@ -278,8 +273,8 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
     return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
 
   /* Set the compressed input when this function is called */
-  z->next_in = (Bytef *) buf;
-  z->avail_in = (uInt) nbytes;
+  z->next_in = (z_const Bytef *)buf;
+  z->avail_in = (uInt)nbytes;
 
   if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
     return process_trailer(data, zp);
@@ -337,8 +332,8 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
 
   if(zp->zlib_init == ZLIB_INIT_GZIP) {
     /* Let zlib handle the gzip decompression entirely */
-    z->next_in = (Bytef *) buf;
-    z->avail_in = (uInt) nbytes;
+    z->next_in = (z_const Bytef *)buf;
+    z->avail_in = (uInt)nbytes;
     /* Now uncompress the data */
     return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
   }
@@ -742,6 +737,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
   Curl_cwriter_phase phase = is_transfer ?
     CURL_CW_TRANSFER_DECODE : CURL_CW_CONTENT_DECODE;
   CURLcode result;
+  bool has_chunked = FALSE;
 
   do {
     const char *name;
@@ -755,7 +751,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
     name = enclist;
 
     for(namelen = 0; *enclist && *enclist != ','; enclist++)
-      if(!ISSPACE(*enclist))
+      if(*enclist > ' ')
         namelen = enclist - name + 1;
 
     if(namelen) {
@@ -770,9 +766,21 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
        * Exception is "chunked" transfer-encoding which always must happen */
       if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
          (!is_transfer && data->set.http_ce_skip)) {
+        bool is_identity = strncasecompare(name, "identity", 8);
         /* not requested, ignore */
         CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
                        (int)namelen, name);
+        if(is_transfer && !data->set.http_te_skip) {
+          if(has_chunked)
+            failf(data, "A Transfer-Encoding (%.*s) was listed after chunked",
+                  (int)namelen, name);
+          else if(is_identity)
+            continue;
+          else
+            failf(data, "Unsolicited Transfer-Encoding (%.*s) found",
+                  (int)namelen, name);
+          return CURLE_BAD_CONTENT_ENCODING;
+        }
         return CURLE_OK;
       }
 
@@ -823,6 +831,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
         Curl_cwriter_free(data, writer);
         return result;
       }
+      if(is_chunked)
+        has_chunked = TRUE;
     }
   } while(*enclist);
 

+ 104 - 179
Utilities/cmcurl/lib/cookie.c

@@ -76,11 +76,9 @@ Example set of cookies:
 #include "urldata.h"
 #include "cookie.h"
 #include "psl.h"
-#include "strtok.h"
 #include "sendf.h"
 #include "slist.h"
 #include "share.h"
-#include "strtoofft.h"
 #include "strcase.h"
 #include "curl_get_line.h"
 #include "curl_memrchr.h"
@@ -89,6 +87,7 @@ Example set of cookies:
 #include "fopen.h"
 #include "strdup.h"
 #include "llist.h"
+#include "curlx/strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -160,12 +159,10 @@ static bool cookie_tailmatch(const char *cookie_domain,
  * matching cookie path and URL path
  * RFC6265 5.1.4 Paths and Path-Match
  */
-static bool pathmatch(const char *cookie_path, const char *request_uri)
+static bool pathmatch(const char *cookie_path, const char *uri_path)
 {
   size_t cookie_path_len;
   size_t uri_path_len;
-  char *uri_path = NULL;
-  char *pos;
   bool ret = FALSE;
 
   /* cookie_path must not have last '/' separator. ex: /sample */
@@ -175,19 +172,9 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
     return TRUE;
   }
 
-  uri_path = strdup(request_uri);
-  if(!uri_path)
-    return FALSE;
-  pos = strchr(uri_path, '?');
-  if(pos)
-    *pos = 0x0;
-
   /* #-fragments are already cut off! */
-  if(0 == strlen(uri_path) || uri_path[0] != '/') {
-    strstore(&uri_path, "/", 1);
-    if(!uri_path)
-      return FALSE;
-  }
+  if(0 == strlen(uri_path) || uri_path[0] != '/')
+    uri_path = "/";
 
   /*
    * here, RFC6265 5.1.4 says
@@ -201,16 +188,12 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
 
   uri_path_len = strlen(uri_path);
 
-  if(uri_path_len < cookie_path_len) {
-    ret = FALSE;
+  if(uri_path_len < cookie_path_len)
     goto pathmatched;
-  }
 
   /* not using checkprefix() because matching should be case-sensitive */
-  if(strncmp(cookie_path, uri_path, cookie_path_len)) {
-    ret = FALSE;
+  if(strncmp(cookie_path, uri_path, cookie_path_len))
     goto pathmatched;
-  }
 
   /* The cookie-path and the uri-path are identical. */
   if(cookie_path_len == uri_path_len) {
@@ -224,10 +207,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
     goto pathmatched;
   }
 
-  ret = FALSE;
-
 pathmatched:
-  free(uri_path);
   return ret;
 }
 
@@ -301,34 +281,27 @@ static size_t cookiehash(const char * const domain)
  */
 static char *sanitize_cookie_path(const char *cookie_path)
 {
-  size_t len;
-  char *new_path = strdup(cookie_path);
-  if(!new_path)
-    return NULL;
+  size_t len = strlen(cookie_path);
 
-  /* some stupid site sends path attribute with '"'. */
-  len = strlen(new_path);
-  if(new_path[0] == '\"') {
-    memmove(new_path, new_path + 1, len);
+  /* some sites send path attribute within '"'. */
+  if(cookie_path[0] == '\"') {
+    cookie_path++;
     len--;
   }
-  if(len && (new_path[len - 1] == '\"')) {
-    new_path[--len] = 0x0;
-  }
+  if(len && (cookie_path[len - 1] == '\"'))
+    len--;
 
   /* RFC6265 5.2.4 The Path Attribute */
-  if(new_path[0] != '/') {
+  if(cookie_path[0] != '/')
     /* Let cookie-path be the default-path. */
-    strstore(&new_path, "/", 1);
-    return new_path;
-  }
+    return strdup("/");
 
+  /* remove trailing slash */
   /* convert /hoge/ to /hoge */
-  if(len && new_path[len - 1] == '/') {
-    new_path[len - 1] = 0x0;
-  }
+  if(len && cookie_path[len - 1] == '/')
+    len--;
 
-  return new_path;
+  return Curl_memdup0(cookie_path, len);
 }
 
 /*
@@ -370,9 +343,12 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
  */
 static void strstore(char **str, const char *newstr, size_t len)
 {
-  DEBUGASSERT(newstr);
   DEBUGASSERT(str);
   free(*str);
+  if(!len) {
+    len++;
+    newstr = "";
+  }
   *str = Curl_memdup0(newstr, len);
 }
 
@@ -458,18 +434,16 @@ static bool bad_domain(const char *domain, size_t len)
   fine. The prime reason for filtering out control bytes is that some HTTP
   servers return 400 for requests that contain such.
 */
-static bool invalid_octets(const char *p)
+static bool invalid_octets(const char *ptr)
 {
+  const unsigned char *p = (const unsigned char *)ptr;
   /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
-  static const char badoctets[] = {
-    "\x01\x02\x03\x04\x05\x06\x07\x08\x0a"
-    "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
-    "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
-  };
-  size_t len;
-  /* scan for all the octets that are *not* in cookie-octet */
-  len = strcspn(p, badoctets);
-  return p[len] != '\0';
+  while(*p) {
+    if(((*p != 9) && (*p < 0x20)) || (*p == 0x7f))
+      return TRUE;
+    p++;
+  }
+  return FALSE;
 }
 
 #define CERR_OK            0
@@ -486,7 +460,9 @@ static bool invalid_octets(const char *p)
 #define CERR_COMMENT       11 /* a commented line */
 #define CERR_RANGE         12 /* expire range problem */
 #define CERR_FIELDS        13 /* incomplete netscape line */
+#ifdef USE_LIBPSL
 #define CERR_PSL           14 /* a public suffix */
+#endif
 #define CERR_LIVE_WINS     15
 
 /* The maximum length we accept a date string for the 'expire' keyword. The
@@ -517,51 +493,29 @@ parse_cookie_header(struct Curl_easy *data,
 
   now = time(NULL);
   do {
-    size_t vlen;
-    size_t nlen;
-
-    while(*ptr && ISBLANK(*ptr))
-      ptr++;
+    struct Curl_str name;
+    struct Curl_str val;
 
     /* we have a <name>=<value> pair or a stand-alone word here */
-    nlen = strcspn(ptr, ";\t\r\n=");
-    if(nlen) {
+    if(!curlx_str_cspn(&ptr, &name, ";\t\r\n=")) {
       bool done = FALSE;
       bool sep = FALSE;
-      const char *namep = ptr;
-      const char *valuep;
-
-      ptr += nlen;
-
-      /* trim trailing spaces and tabs after name */
-      while(nlen && ISBLANK(namep[nlen - 1]))
-        nlen--;
-
-      if(*ptr == '=') {
-        vlen = strcspn(++ptr, ";\r\n");
-        valuep = ptr;
-        sep = TRUE;
-        ptr = &valuep[vlen];
-
-        /* Strip off trailing whitespace from the value */
-        while(vlen && ISBLANK(valuep[vlen-1]))
-          vlen--;
+      curlx_str_trimblanks(&name);
 
-        /* Skip leading whitespace from the value */
-        while(vlen && ISBLANK(*valuep)) {
-          valuep++;
-          vlen--;
-        }
+      if(!curlx_str_single(&ptr, '=')) {
+        sep = TRUE; /* a '=' was used */
+        if(!curlx_str_cspn(&ptr, &val, ";\r\n")) {
+          curlx_str_trimblanks(&val);
 
-        /* Reject cookies with a TAB inside the value */
-        if(memchr(valuep, '\t', vlen)) {
-          infof(data, "cookie contains TAB, dropping");
-          return CERR_TAB;
+          /* Reject cookies with a TAB inside the value */
+          if(memchr(curlx_str(&val), '\t', curlx_strlen(&val))) {
+            infof(data, "cookie contains TAB, dropping");
+            return CERR_TAB;
+          }
         }
       }
       else {
-        valuep = NULL;
-        vlen = 0;
+        curlx_str_init(&val);
       }
 
       /*
@@ -569,10 +523,11 @@ parse_cookie_header(struct Curl_easy *data,
        * combination of name + contents. Chrome and Firefox support 4095 or
        * 4096 bytes combo
        */
-      if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
-         ((nlen + vlen) > MAX_NAME)) {
+      if(curlx_strlen(&name) >= (MAX_NAME-1) ||
+         curlx_strlen(&val) >= (MAX_NAME-1) ||
+         ((curlx_strlen(&name) + curlx_strlen(&val)) > MAX_NAME)) {
         infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
-              nlen, vlen);
+              curlx_strlen(&name), curlx_strlen(&val));
         return CERR_TOO_BIG;
       }
 
@@ -582,12 +537,10 @@ parse_cookie_header(struct Curl_easy *data,
        * "the rest". Prefixes must start with '__' and end with a '-', so
        * only test for names where that can possibly be true.
        */
-      if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
-        if(strncasecompare("__Secure-", namep, 9))
-          co->prefix_secure = TRUE;
-        else if(strncasecompare("__Host-", namep, 7))
-          co->prefix_host = TRUE;
-      }
+      if(!strncmp("__Secure-", curlx_str(&name), 9))
+        co->prefix_secure = TRUE;
+      else if(!strncmp("__Host-", curlx_str(&name), 7))
+        co->prefix_host = TRUE;
 
       /*
        * Use strstore() below to properly deal with received cookie
@@ -601,8 +554,8 @@ parse_cookie_header(struct Curl_easy *data,
           /* Bad name/value pair. */
           return CERR_NO_SEP;
 
-        strstore(&co->name, namep, nlen);
-        strstore(&co->value, valuep, vlen);
+        strstore(&co->name, curlx_str(&name), curlx_strlen(&name));
+        strstore(&co->value, curlx_str(&val), curlx_strlen(&val));
         done = TRUE;
         if(!co->name || !co->value)
           return CERR_NO_NAME_VALUE;
@@ -612,7 +565,7 @@ parse_cookie_header(struct Curl_easy *data,
           return CERR_INVALID_OCTET;
         }
       }
-      else if(!vlen) {
+      else if(!curlx_strlen(&val)) {
         /*
          * this was a "<name>=" with no content, and we must allow
          * 'secure' and 'httponly' specified this weirdly
@@ -623,7 +576,7 @@ parse_cookie_header(struct Curl_easy *data,
          * using a secure protocol, or when the cookie is being set by
          * reading from file
          */
-        if((nlen == 6) && strncasecompare("secure", namep, 6)) {
+        if(curlx_str_casecompare(&name, "secure")) {
           if(secure || !ci->running) {
             co->secure = TRUE;
           }
@@ -631,7 +584,7 @@ parse_cookie_header(struct Curl_easy *data,
             return CERR_BAD_SECURE;
           }
         }
-        else if((nlen == 8) && strncasecompare("httponly", namep, 8))
+        else if(curlx_str_casecompare(&name, "httponly"))
           co->httponly = TRUE;
         else if(sep)
           /* there was a '=' so we are not done parsing this field */
@@ -639,8 +592,8 @@ parse_cookie_header(struct Curl_easy *data,
       }
       if(done)
         ;
-      else if((nlen == 4) && strncasecompare("path", namep, 4)) {
-        strstore(&co->path, valuep, vlen);
+      else if(curlx_str_casecompare(&name, "path")) {
+        strstore(&co->path, curlx_str(&val), curlx_strlen(&val));
         if(!co->path)
           return CERR_OUT_OF_MEMORY;
         free(co->spath); /* if this is set again */
@@ -648,19 +601,16 @@ parse_cookie_header(struct Curl_easy *data,
         if(!co->spath)
           return CERR_OUT_OF_MEMORY;
       }
-      else if((nlen == 6) &&
-              strncasecompare("domain", namep, 6) && vlen) {
+      else if(curlx_str_casecompare(&name, "domain") && curlx_strlen(&val)) {
         bool is_ip;
-
+        const char *v = curlx_str(&val);
         /*
          * Now, we make sure that our host is within the given domain, or
          * the given domain is not valid and thus cannot be set.
          */
 
-        if('.' == valuep[0]) {
-          valuep++; /* ignore preceding dot */
-          vlen--;
-        }
+        if('.' == *v)
+          curlx_str_nudge(&val, 1);
 
 #ifndef USE_LIBPSL
         /*
@@ -668,17 +618,19 @@ parse_cookie_header(struct Curl_easy *data,
          * TLD or otherwise "protected" suffix. To reduce risk, we require a
          * dot OR the exact hostname being "localhost".
          */
-        if(bad_domain(valuep, vlen))
+        if(bad_domain(curlx_str(&val), curlx_strlen(&val)))
           domain = ":";
 #endif
 
-        is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
+        is_ip = Curl_host_is_ipnum(domain ? domain : curlx_str(&val));
 
         if(!domain
-           || (is_ip && !strncmp(valuep, domain, vlen) &&
-               (vlen == strlen(domain)))
-           || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
-          strstore(&co->domain, valuep, vlen);
+           || (is_ip && !strncmp(curlx_str(&val), domain,
+                                 curlx_strlen(&val)) &&
+               (curlx_strlen(&val) == strlen(domain)))
+           || (!is_ip && cookie_tailmatch(curlx_str(&val),
+                                          curlx_strlen(&val), domain))) {
+          strstore(&co->domain, curlx_str(&val), curlx_strlen(&val));
           if(!co->domain)
             return CERR_OUT_OF_MEMORY;
 
@@ -692,14 +644,14 @@ parse_cookie_header(struct Curl_easy *data,
            * not a domain to which the current host belongs. Mark as bad.
            */
           infof(data, "skipped cookie with bad tailmatch domain: %s",
-                valuep);
+                curlx_str(&val));
           return CERR_NO_TAILMATCH;
         }
       }
-      else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+      else if(curlx_str_casecompare(&name, "version")) {
         /* just ignore */
       }
-      else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
+      else if(curlx_str_casecompare(&name, "max-age") && curlx_strlen(&val)) {
         /*
          * Defined in RFC2109:
          *
@@ -709,21 +661,22 @@ parse_cookie_header(struct Curl_easy *data,
          * client should discard the cookie. A value of zero means the
          * cookie should be discarded immediately.
          */
-        CURLofft offt;
-        const char *maxage = valuep;
-        offt = curlx_strtoofft((*maxage == '\"') ?
-                               &maxage[1] : &maxage[0], NULL, 10,
-                               &co->expires);
-        switch(offt) {
-        case CURL_OFFT_FLOW:
+        int rc;
+        const char *maxage = curlx_str(&val);
+        if(*maxage == '\"')
+          maxage++;
+        rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
+
+        switch(rc) {
+        case STRE_OVERFLOW:
           /* overflow, used max value */
           co->expires = CURL_OFF_T_MAX;
           break;
-        case CURL_OFFT_INVAL:
+        default:
           /* negative or otherwise bad, expire */
           co->expires = 1;
           break;
-        case CURL_OFFT_OK:
+        case STRE_OK:
           if(!co->expires)
             /* already expired */
             co->expires = 1;
@@ -736,8 +689,8 @@ parse_cookie_header(struct Curl_easy *data,
         }
         cap_expires(now, co);
       }
-      else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
-        if(!co->expires && (vlen < MAX_DATE_LENGTH)) {
+      else if(curlx_str_casecompare(&name, "expires") && curlx_strlen(&val)) {
+        if(!co->expires && (curlx_strlen(&val) < MAX_DATE_LENGTH)) {
           /*
            * Let max-age have priority.
            *
@@ -745,8 +698,8 @@ parse_cookie_header(struct Curl_easy *data,
            * will be treated as a session cookie
            */
           char dbuf[MAX_DATE_LENGTH + 1];
-          memcpy(dbuf, valuep, vlen);
-          dbuf[vlen] = 0;
+          memcpy(dbuf, curlx_str(&val), curlx_strlen(&val));
+          dbuf[curlx_strlen(&val)] = 0;
           co->expires = Curl_getdate_capped(dbuf);
 
           /*
@@ -766,15 +719,8 @@ parse_cookie_header(struct Curl_easy *data,
        * Else, this is the second (or more) name we do not know about!
        */
     }
-    else {
-      /* this is an "illegal" <what>=<this> pair */
-    }
 
-    while(*ptr && ISBLANK(*ptr))
-      ptr++;
-    if(*ptr == ';')
-      ptr++;
-    else
+    if(curlx_str_single(&ptr, ';'))
       break;
   } while(1);
 
@@ -787,23 +733,11 @@ parse_cookie_header(struct Curl_easy *data,
 
   if(!co->path && path) {
     /*
-     * No path was given in the header line, set the default. Note that the
-     * passed-in path to this function MAY have a '?' and following part that
-     * MUST NOT be stored as part of the path.
+     * No path was given in the header line, set the default.
      */
-    char *queryp = strchr(path, '?');
-
-    /*
-     * queryp is where the interesting part of the path ends, so now we
-     * want to the find the last
-     */
-    char *endslash;
-    if(!queryp)
-      endslash = strrchr(path, '/');
-    else
-      endslash = memrchr(path, '/', (queryp - path));
+    const char *endslash = strrchr(path, '/');
     if(endslash) {
-      size_t pathlen = (endslash-path + 1); /* include end slash */
+      size_t pathlen = (endslash - path + 1); /* include end slash */
       co->path = Curl_memdup0(path, pathlen);
       if(co->path) {
         co->spath = sanitize_cookie_path(co->path);
@@ -916,16 +850,8 @@ parse_netscape(struct Cookie *co,
       }
       break;
     case 4:
-      {
-        char *endp;
-        const char *p;
-        /* make sure curlx_strtoofft won't read past the current field */
-        for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p)
-          ;
-        if(p == ptr || p != &ptr[len] ||
-           curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len])
-          return CERR_RANGE;
-      }
+      if(curlx_str_number(&ptr, &co->expires, CURL_OFF_T_MAX))
+        return CERR_RANGE;
       break;
     case 5:
       co->name = Curl_memdup0(ptr, len);
@@ -1284,21 +1210,20 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
     ci->running = FALSE; /* this is not running, this is init */
     if(fp) {
       struct dynbuf buf;
-      Curl_dyn_init(&buf, MAX_COOKIE_LINE);
+      curlx_dyn_init(&buf, MAX_COOKIE_LINE);
       while(Curl_get_line(&buf, fp)) {
-        char *lineptr = Curl_dyn_ptr(&buf);
+        const char *lineptr = curlx_dyn_ptr(&buf);
         bool headerline = FALSE;
         if(checkprefix("Set-Cookie:", lineptr)) {
           /* This is a cookie line, get it! */
           lineptr += 11;
           headerline = TRUE;
-          while(*lineptr && ISBLANK(*lineptr))
-            lineptr++;
+          curlx_str_passblanks(&lineptr);
         }
 
         Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL, NULL, TRUE);
       }
-      Curl_dyn_free(&buf); /* free the line buffer */
+      curlx_dyn_free(&buf); /* free the line buffer */
 
       /*
        * Remove expired cookies from the hash. We must make sure to run this
@@ -1326,8 +1251,8 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
  */
 static int cookie_sort(const void *p1, const void *p2)
 {
-  struct Cookie *c1 = *(struct Cookie **)p1;
-  struct Cookie *c2 = *(struct Cookie **)p2;
+  const struct Cookie *c1 = *(const struct Cookie * const *)p1;
+  const struct Cookie *c2 = *(const struct Cookie * const *)p2;
   size_t l1, l2;
 
   /* 1 - compare cookie path lengths */
@@ -1362,8 +1287,8 @@ static int cookie_sort(const void *p1, const void *p2)
  */
 static int cookie_sort_ct(const void *p1, const void *p2)
 {
-  struct Cookie *c1 = *(struct Cookie **)p1;
-  struct Cookie *c2 = *(struct Cookie **)p2;
+  const struct Cookie *c1 = *(const struct Cookie * const *)p1;
+  const struct Cookie *c2 = *(const struct Cookie * const *)p2;
 
   return (c2->creationtime > c1->creationtime) ? 1 : -1;
 }

+ 581 - 0
Utilities/cmcurl/lib/cshutdn.c

@@ -0,0 +1,581 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Linus Nielsen Feltzing, <[email protected]>
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "cfilters.h"
+#include "progress.h"
+#include "multiif.h"
+#include "multi_ev.h"
+#include "sendf.h"
+#include "cshutdn.h"
+#include "http_negotiate.h"
+#include "http_ntlm.h"
+#include "sigpipe.h"
+#include "connect.h"
+#include "select.h"
+#include "strcase.h"
+#include "curlx/strparse.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static void cshutdn_run_conn_handler(struct Curl_easy *data,
+                                     struct connectdata *conn)
+{
+  if(!conn->bits.shutdown_handler) {
+
+    /* Cleanup NTLM connection-related data */
+    Curl_http_auth_cleanup_ntlm(conn);
+
+    /* Cleanup NEGOTIATE connection-related data */
+    Curl_http_auth_cleanup_negotiate(conn);
+
+    if(conn->handler && conn->handler->disconnect) {
+      /* Some disconnect handlers do a blocking wait on server responses.
+       * FTP/IMAP/SMTP and SFTP are among them. When using the internal
+       * handle, set an overall short timeout so we do not hang for the
+       * default 120 seconds. */
+      if(data->state.internal) {
+        data->set.timeout = DEFAULT_SHUTDOWN_TIMEOUT_MS;
+        (void)Curl_pgrsTime(data, TIMER_STARTOP);
+      }
+
+      /* This is set if protocol-specific cleanups should be made */
+      DEBUGF(infof(data, "connection #%" FMT_OFF_T
+                   ", shutdown protocol handler (aborted=%d)",
+                   conn->connection_id, conn->bits.aborted));
+      /* There are protocol handlers that block on retrieving
+       * server responses here (FTP). Set a short timeout. */
+      conn->handler->disconnect(data, conn, conn->bits.aborted);
+    }
+
+    conn->bits.shutdown_handler = TRUE;
+  }
+}
+
+static void cshutdn_run_once(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             bool *done)
+{
+  CURLcode r1, r2;
+  bool done1, done2;
+
+  /* We expect to be attached when called */
+  DEBUGASSERT(data->conn == conn);
+
+  cshutdn_run_conn_handler(data, conn);
+
+  if(conn->bits.shutdown_filters) {
+    *done = TRUE;
+    return;
+  }
+
+  if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
+    r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
+  else {
+    r1 = CURLE_OK;
+    done1 = TRUE;
+  }
+
+  if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
+    r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
+  else {
+    r2 = CURLE_OK;
+    done2 = TRUE;
+  }
+
+  /* we are done when any failed or both report success */
+  *done = (r1 || r2 || (done1 && done2));
+  if(*done)
+    conn->bits.shutdown_filters = TRUE;
+}
+
+void Curl_cshutdn_run_once(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      bool *done)
+{
+  DEBUGASSERT(!data->conn);
+  Curl_attach_connection(data, conn);
+  cshutdn_run_once(data, conn, done);
+  CURL_TRC_M(data, "[SHUTDOWN] shutdown, done=%d", *done);
+  Curl_detach_connection(data);
+}
+
+
+void Curl_cshutdn_terminate(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            bool do_shutdown)
+{
+  struct Curl_easy *admin = data;
+  bool done;
+
+  /* there must be a connection to close */
+  DEBUGASSERT(conn);
+  /* it must be removed from the connection pool */
+  DEBUGASSERT(!conn->bits.in_cpool);
+  /* the transfer must be detached from the connection */
+  DEBUGASSERT(data && !data->conn);
+
+  /* If we can obtain an internal admin handle, use that to attach
+   * and terminate the connection. Some protocol will try to mess with
+   * `data` during shutdown and we do not want that with a `data` from
+   * the application. */
+  if(data->multi && data->multi->admin)
+    admin = data->multi->admin;
+
+  Curl_attach_connection(admin, conn);
+
+  cshutdn_run_conn_handler(admin, conn);
+  if(do_shutdown) {
+    /* Make a last attempt to shutdown handlers and filters, if
+     * not done so already. */
+    cshutdn_run_once(admin, conn, &done);
+  }
+  CURL_TRC_M(admin, "[SHUTDOWN] %sclosing connection #%" FMT_OFF_T,
+             conn->bits.shutdown_filters ? "" : "force ",
+             conn->connection_id);
+  Curl_conn_close(admin, SECONDARYSOCKET);
+  Curl_conn_close(admin, FIRSTSOCKET);
+  Curl_detach_connection(admin);
+
+  if(data->multi)
+    Curl_multi_ev_conn_done(data->multi, data, conn);
+  Curl_conn_free(admin, conn);
+
+  if(data->multi) {
+    CURL_TRC_M(data, "[SHUTDOWN] trigger multi connchanged");
+    Curl_multi_connchanged(data->multi);
+  }
+}
+
+static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn,
+                                   struct Curl_easy *data,
+                                   const char *destination)
+{
+  struct Curl_llist_node *e;
+  struct connectdata *conn;
+
+  e = Curl_llist_head(&cshutdn->list);
+  while(e) {
+    conn = Curl_node_elem(e);
+    if(!destination || !strcmp(destination, conn->destination))
+      break;
+    e = Curl_node_next(e);
+  }
+
+  if(e) {
+    SIGPIPE_VARIABLE(pipe_st);
+    conn = Curl_node_elem(e);
+    Curl_node_remove(e);
+    sigpipe_init(&pipe_st);
+    sigpipe_apply(data, &pipe_st);
+    Curl_cshutdn_terminate(data, conn, FALSE);
+    sigpipe_restore(&pipe_st);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
+                               const char *destination)
+{
+  if(data && data->multi) {
+    struct cshutdn *csd = &data->multi->cshutdn;
+    return cshutdn_destroy_oldest(csd, data, destination);
+  }
+  return FALSE;
+}
+
+#define NUM_POLLS_ON_STACK 10
+
+static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
+                               struct Curl_easy *data,
+                               int timeout_ms)
+{
+  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
+  struct curl_pollfds cpfds;
+  CURLcode result;
+
+  Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
+
+  result = Curl_cshutdn_add_pollfds(cshutdn, data, &cpfds);
+  if(result)
+    goto out;
+
+  Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
+
+out:
+  Curl_pollfds_cleanup(&cpfds);
+  return result;
+}
+
+
+static void cshutdn_perform(struct cshutdn *cshutdn,
+                              struct Curl_easy *data)
+{
+  struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
+  struct Curl_llist_node *enext;
+  struct connectdata *conn;
+  struct curltime *nowp = NULL;
+  struct curltime now;
+  timediff_t next_expire_ms = 0, ms;
+  bool done;
+
+  if(!e)
+    return;
+
+  CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections",
+             Curl_llist_count(&cshutdn->list));
+  while(e) {
+    enext = Curl_node_next(e);
+    conn = Curl_node_elem(e);
+    Curl_cshutdn_run_once(data, conn, &done);
+    if(done) {
+      Curl_node_remove(e);
+      Curl_cshutdn_terminate(data, conn, FALSE);
+    }
+    else {
+      /* idata has one timer list, but maybe more than one connection.
+       * Set EXPIRE_SHUTDOWN to the smallest time left for all. */
+      if(!nowp) {
+        now = curlx_now();
+        nowp = &now;
+      }
+      ms = Curl_conn_shutdown_timeleft(conn, nowp);
+      if(ms && ms < next_expire_ms)
+        next_expire_ms = ms;
+    }
+    e = enext;
+  }
+
+  if(next_expire_ms)
+    Curl_expire_ex(data, nowp, next_expire_ms, EXPIRE_SHUTDOWN);
+}
+
+
+static void cshutdn_terminate_all(struct cshutdn *cshutdn,
+                                  struct Curl_easy *data,
+                                  int timeout_ms)
+{
+  struct curltime started = curlx_now();
+  struct Curl_llist_node *e;
+  SIGPIPE_VARIABLE(pipe_st);
+
+  DEBUGASSERT(cshutdn);
+  DEBUGASSERT(data);
+
+  CURL_TRC_M(data, "[SHUTDOWN] shutdown all");
+  sigpipe_init(&pipe_st);
+  sigpipe_apply(data, &pipe_st);
+
+  while(Curl_llist_head(&cshutdn->list)) {
+    timediff_t timespent;
+    int remain_ms;
+
+    cshutdn_perform(cshutdn, data);
+
+    if(!Curl_llist_head(&cshutdn->list)) {
+      CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly");
+      break;
+    }
+
+    /* wait for activity, timeout or "nothing" */
+    timespent = curlx_timediff(curlx_now(), started);
+    if(timespent >= (timediff_t)timeout_ms) {
+      CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s",
+                (timeout_ms > 0) ? "timeout" : "best effort done");
+      break;
+    }
+
+    remain_ms = timeout_ms - (int)timespent;
+    if(cshutdn_wait(cshutdn, data, remain_ms)) {
+      CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, aborted");
+      break;
+    }
+  }
+
+  /* Terminate any remaining. */
+  e = Curl_llist_head(&cshutdn->list);
+  while(e) {
+    struct connectdata *conn = Curl_node_elem(e);
+    Curl_node_remove(e);
+    Curl_cshutdn_terminate(data, conn, FALSE);
+    e = Curl_llist_head(&cshutdn->list);
+  }
+  DEBUGASSERT(!Curl_llist_count(&cshutdn->list));
+
+  sigpipe_restore(&pipe_st);
+}
+
+
+int Curl_cshutdn_init(struct cshutdn *cshutdn,
+                      struct Curl_multi *multi)
+{
+  DEBUGASSERT(multi);
+  cshutdn->multi = multi;
+  Curl_llist_init(&cshutdn->list, NULL);
+  cshutdn->initialised = TRUE;
+  return 0; /* good */
+}
+
+
+void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
+                          struct Curl_easy *data)
+{
+  if(cshutdn->initialised && data) {
+    int timeout_ms = 0;
+    /* Just for testing, run graceful shutdown */
+#ifdef DEBUGBUILD
+    {
+      const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
+      if(p) {
+        curl_off_t l;
+        if(!curlx_str_number(&p, &l, INT_MAX))
+          timeout_ms = (int)l;
+      }
+    }
+#endif
+
+    CURL_TRC_M(data, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
+               Curl_llist_count(&cshutdn->list), timeout_ms);
+    cshutdn_terminate_all(cshutdn, data, timeout_ms);
+  }
+  cshutdn->multi = NULL;
+}
+
+size_t Curl_cshutdn_count(struct Curl_easy *data)
+{
+  if(data && data->multi) {
+    struct cshutdn *csd = &data->multi->cshutdn;
+    return Curl_llist_count(&csd->list);
+  }
+  return 0;
+}
+
+size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+                               const char *destination)
+{
+  if(data && data->multi) {
+    struct cshutdn *csd = &data->multi->cshutdn;
+    size_t n = 0;
+    struct Curl_llist_node *e = Curl_llist_head(&csd->list);
+    while(e) {
+      struct connectdata *conn = Curl_node_elem(e);
+      if(!strcmp(destination, conn->destination))
+        ++n;
+      e = Curl_node_next(e);
+    }
+    return n;
+  }
+  return 0;
+}
+
+
+static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
+                                     struct Curl_easy *data,
+                                     struct connectdata *conn)
+{
+  CURLMcode mresult;
+
+  DEBUGASSERT(cshutdn);
+  DEBUGASSERT(cshutdn->multi->socket_cb);
+
+  Curl_attach_connection(data, conn);
+  mresult = Curl_multi_ev_assess_conn(cshutdn->multi, data, conn);
+  Curl_detach_connection(data);
+  return mresult;
+}
+
+
+void Curl_cshutdn_add(struct cshutdn *cshutdn,
+                        struct connectdata *conn,
+                        size_t conns_in_pool)
+{
+  struct Curl_easy *data = cshutdn->multi->admin;
+  size_t max_total = (cshutdn->multi->max_total_connections > 0) ?
+                     (size_t)cshutdn->multi->max_total_connections : 0;
+
+  /* Add the connection to our shutdown list for non-blocking shutdown
+   * during multi processing. */
+  if(max_total > 0 && (max_total <=
+        (conns_in_pool + Curl_llist_count(&cshutdn->list)))) {
+    CURL_TRC_M(data, "[SHUTDOWN] discarding oldest shutdown connection "
+               "due to connection limit of %zu", max_total);
+    cshutdn_destroy_oldest(cshutdn, data, NULL);
+  }
+
+  if(cshutdn->multi->socket_cb) {
+    if(cshutdn_update_ev(cshutdn, data, conn)) {
+      CURL_TRC_M(data, "[SHUTDOWN] update events failed, discarding #%"
+                 FMT_OFF_T, conn->connection_id);
+      Curl_cshutdn_terminate(data, conn, FALSE);
+      return;
+    }
+  }
+
+  Curl_llist_append(&cshutdn->list, conn, &conn->cshutdn_node);
+  CURL_TRC_M(data, "[SHUTDOWN] added #%" FMT_OFF_T
+             " to shutdowns, now %zu conns in shutdown",
+             conn->connection_id, Curl_llist_count(&cshutdn->list));
+}
+
+
+static void cshutdn_multi_socket(struct cshutdn *cshutdn,
+                                   struct Curl_easy *data,
+                                   curl_socket_t s)
+{
+  struct Curl_llist_node *e;
+  struct connectdata *conn;
+  bool done;
+
+  DEBUGASSERT(cshutdn->multi->socket_cb);
+  e = Curl_llist_head(&cshutdn->list);
+  while(e) {
+    conn = Curl_node_elem(e);
+    if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
+      Curl_cshutdn_run_once(data, conn, &done);
+      if(done || cshutdn_update_ev(cshutdn, data, conn)) {
+        Curl_node_remove(e);
+        Curl_cshutdn_terminate(data, conn, FALSE);
+      }
+      break;
+    }
+    e = Curl_node_next(e);
+  }
+}
+
+
+void Curl_cshutdn_perform(struct cshutdn *cshutdn,
+                          struct Curl_easy *data,
+                          curl_socket_t s)
+{
+  if((s == CURL_SOCKET_TIMEOUT) || (!cshutdn->multi->socket_cb))
+    cshutdn_perform(cshutdn, data);
+  else
+    cshutdn_multi_socket(cshutdn, data, s);
+}
+
+/* return fd_set info about the shutdown connections */
+void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
+                         struct Curl_easy *data,
+                         fd_set *read_fd_set, fd_set *write_fd_set,
+                         int *maxfd)
+{
+  if(Curl_llist_head(&cshutdn->list)) {
+    struct Curl_llist_node *e;
+
+    for(e = Curl_llist_head(&cshutdn->list); e;
+        e = Curl_node_next(e)) {
+      struct easy_pollset ps;
+      unsigned int i;
+      struct connectdata *conn = Curl_node_elem(e);
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(data, conn);
+      Curl_conn_adjust_pollset(data, conn, &ps);
+      Curl_detach_connection(data);
+
+      for(i = 0; i < ps.num; i++) {
+#if defined(__DJGPP__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warith-conversion"
+#endif
+        if(ps.actions[i] & CURL_POLL_IN)
+          FD_SET(ps.sockets[i], read_fd_set);
+        if(ps.actions[i] & CURL_POLL_OUT)
+          FD_SET(ps.sockets[i], write_fd_set);
+#if defined(__DJGPP__)
+#pragma GCC diagnostic pop
+#endif
+        if((ps.actions[i] & (CURL_POLL_OUT | CURL_POLL_IN)) &&
+           ((int)ps.sockets[i] > *maxfd))
+          *maxfd = (int)ps.sockets[i];
+      }
+    }
+  }
+}
+
+/* return information about the shutdown connections */
+unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
+                                      struct Curl_easy *data,
+                                      struct Curl_waitfds *cwfds)
+{
+  unsigned int need = 0;
+
+  if(Curl_llist_head(&cshutdn->list)) {
+    struct Curl_llist_node *e;
+    struct easy_pollset ps;
+    struct connectdata *conn;
+
+    for(e = Curl_llist_head(&cshutdn->list); e;
+        e = Curl_node_next(e)) {
+      conn = Curl_node_elem(e);
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(data, conn);
+      Curl_conn_adjust_pollset(data, conn, &ps);
+      Curl_detach_connection(data);
+
+      need += Curl_waitfds_add_ps(cwfds, &ps);
+    }
+  }
+  return need;
+}
+
+CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
+                                  struct Curl_easy *data,
+                                  struct curl_pollfds *cpfds)
+{
+  CURLcode result = CURLE_OK;
+
+  if(Curl_llist_head(&cshutdn->list)) {
+    struct Curl_llist_node *e;
+    struct easy_pollset ps;
+    struct connectdata *conn;
+
+    for(e = Curl_llist_head(&cshutdn->list); e;
+        e = Curl_node_next(e)) {
+      conn = Curl_node_elem(e);
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(data, conn);
+      Curl_conn_adjust_pollset(data, conn, &ps);
+      Curl_detach_connection(data);
+
+      result = Curl_pollfds_add_ps(cpfds, &ps);
+      if(result) {
+        Curl_pollfds_cleanup(cpfds);
+        goto out;
+      }
+    }
+  }
+out:
+  return result;
+}

+ 110 - 0
Utilities/cmcurl/lib/cshutdn.h

@@ -0,0 +1,110 @@
+#ifndef HEADER_CURL_CSHUTDN_H
+#define HEADER_CURL_CSHUTDN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) Linus Nielsen Feltzing, <[email protected]>
+ *
+ * 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
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+#include "curlx/timeval.h"
+
+struct connectdata;
+struct Curl_easy;
+struct curl_pollfds;
+struct Curl_waitfds;
+struct Curl_multi;
+struct Curl_share;
+
+/* Run the shutdown of the connection once.
+ * Will shortly attach/detach `data` to `conn` while doing so.
+ * `done` will be set TRUE if any error was encountered or if
+ * the connection was shut down completely. */
+void Curl_cshutdn_run_once(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           bool *done);
+
+/* Terminates the connection, e.g. closes and destroys it.
+ * If `run_shutdown` is TRUE, the shutdown will be run once before
+ * terminating it.
+ * Takes ownership of `conn`. */
+void Curl_cshutdn_terminate(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            bool run_shutdown);
+
+/* A `cshutdown` is always owned by a multi handle to maintain
+ * the connections to be shut down. It registers timers and
+ * sockets to monitor via the multi handle. */
+struct cshutdn {
+  struct Curl_llist list;    /* connections being shut down */
+  struct Curl_multi *multi;  /* the multi owning this */
+  BIT(initialised);
+};
+
+/* Init as part of the given multi handle. */
+int Curl_cshutdn_init(struct cshutdn *cshutdn,
+                      struct Curl_multi *multi);
+
+/* Terminate all remaining connections and free resources. */
+void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
+                          struct Curl_easy *data);
+
+/* Number of connections being shut down. */
+size_t Curl_cshutdn_count(struct Curl_easy *data);
+
+/* Number of connections to the destination being shut down. */
+size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+                               const char *destination);
+
+/* Close the oldest connection in shutdown to destination or,
+ * when destination is NULL for any destination.
+ * Return TRUE if a connection has been closed. */
+bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
+                               const char *destination);
+
+/* Add a connection to have it shut down. Will terminate the oldest
+ * connection when total connection limit of multi is being reached. */
+void Curl_cshutdn_add(struct cshutdn *cshutdn,
+                      struct connectdata *conn,
+                      size_t conns_in_pool);
+
+/* Add sockets and POLLIN/OUT flags for connections being shut down. */
+CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
+                                  struct Curl_easy *data,
+                                  struct curl_pollfds *cpfds);
+
+unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
+                                      struct Curl_easy *data,
+                                      struct Curl_waitfds *cwfds);
+
+void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
+                         struct Curl_easy *data,
+                         fd_set *read_fd_set, fd_set *write_fd_set,
+                         int *maxfd);
+
+/* Run shut down connections using socket. If socket is CURL_SOCKET_TIMEOUT,
+ * run maintenance on all connections. */
+void Curl_cshutdn_perform(struct cshutdn *cshutdn,
+                          struct Curl_easy *data,
+                          curl_socket_t s);
+
+#endif /* HEADER_CURL_CSHUTDN_H */

+ 30 - 14
Utilities/cmcurl/lib/curl_addrinfo.c

@@ -50,8 +50,9 @@
 #include <stddef.h>
 
 #include "curl_addrinfo.h"
-#include "inet_pton.h"
-#include "warnless.h"
+#include "fake_addrinfo.h"
+#include "curlx/inet_pton.h"
+#include "curlx/warnless.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -118,7 +119,7 @@ Curl_getaddrinfo_ex(const char *nodename,
 
   *result = NULL; /* assume failure */
 
-  error = getaddrinfo(nodename, servname, hints, &aihead);
+  error = CURL_GETADDRINFO(nodename, servname, hints, &aihead);
   if(error)
     return error;
 
@@ -184,7 +185,7 @@ Curl_getaddrinfo_ex(const char *nodename,
 
   /* destroy the addrinfo list */
   if(aihead)
-    freeaddrinfo(aihead);
+    CURL_FREEADDRINFO(aihead);
 
   /* if we failed, also destroy the Curl_addrinfo list */
   if(error) {
@@ -217,7 +218,7 @@ Curl_getaddrinfo_ex(const char *nodename,
  *
  * This function returns a pointer to the first element of a newly allocated
  * Curl_addrinfo struct linked list filled with the data of a given hostent.
- * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
+ * Curl_addrinfo is meant to work like the addrinfo struct does for an IPv6
  * stack, but usable also for IPv4, all hosts and environments.
  *
  * The memory allocated by this function *MUST* be free'd later on calling
@@ -430,13 +431,13 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
 struct Curl_addrinfo *Curl_str2addr(char *address, int port)
 {
   struct in_addr in;
-  if(Curl_inet_pton(AF_INET, address, &in) > 0)
+  if(curlx_inet_pton(AF_INET, address, &in) > 0)
     /* This is a dotted IP address 123.123.123.123-style */
     return Curl_ip2addr(AF_INET, &in, address, port);
 #ifdef USE_IPV6
   {
     struct in6_addr in6;
-    if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
+    if(curlx_inet_pton(AF_INET6, address, &in6) > 0)
       /* This is a dotted IPv6 address ::1-style */
       return Curl_ip2addr(AF_INET6, &in6, address, port);
   }
@@ -467,7 +468,7 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
   sa_un = (void *) ai->ai_addr;
   sa_un->sun_family = AF_UNIX;
 
-  /* sun_path must be able to store the NUL-terminated path */
+  /* sun_path must be able to store the null-terminated path */
   path_len = strlen(path) + 1;
   if(path_len > sizeof(sa_un->sun_path)) {
     free(ai);
@@ -508,8 +509,16 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis,
                source, line, (void *)freethis);
 #ifdef USE_LWIPSOCK
   lwip_freeaddrinfo(freethis);
+#elif defined(USE_FAKE_GETADDRINFO)
+  {
+    const char *env = getenv("CURL_DNS_SERVER");
+    if(env)
+      r_freeaddrinfo(freethis);
+    else
+      freeaddrinfo(freethis);
+  }
 #else
-  (freeaddrinfo)(freethis);
+  freeaddrinfo(freethis);
 #endif
 }
 #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
@@ -526,15 +535,22 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis,
 
 int
 curl_dbg_getaddrinfo(const char *hostname,
-                    const char *service,
-                    const struct addrinfo *hints,
-                    struct addrinfo **result,
-                    int line, const char *source)
+                     const char *service,
+                     const struct addrinfo *hints,
+                     struct addrinfo **result,
+                     int line, const char *source)
 {
 #ifdef USE_LWIPSOCK
   int res = lwip_getaddrinfo(hostname, service, hints, result);
+#elif defined(USE_FAKE_GETADDRINFO)
+  int res;
+  const char *env = getenv("CURL_DNS_SERVER");
+  if(env)
+    res = r_getaddrinfo(hostname, service, hints, result);
+  else
+    res = getaddrinfo(hostname, service, hints, result);
 #else
-  int res = (getaddrinfo)(hostname, service, hints, result);
+  int res = getaddrinfo(hostname, service, hints, result);
 #endif
   if(0 == res)
     /* success */

+ 22 - 13
Utilities/cmcurl/lib/curl_config.h.cmake

@@ -190,6 +190,9 @@
 /* Define to 1 if you have _Atomic support. */
 #cmakedefine HAVE_ATOMIC 1
 
+/* Define to 1 if you have the `accept4' function. */
+#cmakedefine HAVE_ACCEPT4 1
+
 /* Define to 1 if you have the `fnmatch' function. */
 #cmakedefine HAVE_FNMATCH 1
 
@@ -317,10 +320,10 @@
 /* Define to 1 if you have the <ifaddrs.h> header file. */
 #cmakedefine HAVE_IFADDRS_H 1
 
-/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+/* Define to 1 if you have an IPv6 capable working inet_ntop function. */
 #cmakedefine HAVE_INET_NTOP 1
 
-/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+/* Define to 1 if you have an IPv6 capable working inet_pton function. */
 #cmakedefine HAVE_INET_PTON 1
 
 /* Define to 1 if symbol `sa_family_t' exists */
@@ -422,6 +425,9 @@
 /* Define to 1 if you have the `pipe' function. */
 #cmakedefine HAVE_PIPE 1
 
+/* Define to 1 if you have the `pipe2' function. */
+#cmakedefine HAVE_PIPE2 1
+
 /* Define to 1 if you have the `eventfd' function. */
 #cmakedefine HAVE_EVENTFD 1
 
@@ -464,6 +470,9 @@
 /* Define to 1 if you have the sendmmsg function. */
 #cmakedefine HAVE_SENDMMSG 1
 
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
 /* Define to 1 if you have the 'fsetxattr' function. */
 #cmakedefine HAVE_FSETXATTR 1
 
@@ -542,12 +551,6 @@
 /* Define to 1 if you have the <stropts.h> header file. */
 #cmakedefine HAVE_STROPTS_H 1
 
-/* Define to 1 if you have the strtok_r function. */
-#cmakedefine HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the strtoll function. */
-#cmakedefine HAVE_STRTOLL 1
-
 /* Define to 1 if you have the memrchr function. */
 #cmakedefine HAVE_MEMRCHR 1
 
@@ -709,14 +712,20 @@ ${SIZEOF_TIME_T_CODE}
 /* if wolfSSL is enabled */
 #cmakedefine USE_WOLFSSL 1
 
+/* if wolfSSL has the wolfSSL_get_peer_certificate function. */
+#cmakedefine HAVE_WOLFSSL_GET_PEER_CERTIFICATE 1
+
+/* if wolfSSL has the wolfSSL_UseALPN function. */
+#cmakedefine HAVE_WOLFSSL_USEALPN 1
+
 /* if wolfSSL has the wolfSSL_DES_ecb_encrypt function. */
 #cmakedefine HAVE_WOLFSSL_DES_ECB_ENCRYPT 1
 
 /* if wolfSSL has the wolfSSL_BIO_new function. */
-#cmakedefine HAVE_WOLFSSL_BIO 1
+#cmakedefine HAVE_WOLFSSL_BIO_NEW 1
 
 /* if wolfSSL has the wolfSSL_BIO_set_shutdown function. */
-#cmakedefine HAVE_WOLFSSL_FULL_BIO 1
+#cmakedefine HAVE_WOLFSSL_BIO_SET_SHUTDOWN 1
 
 /* if libssh is in use */
 #cmakedefine USE_LIBSSH 1
@@ -770,6 +779,9 @@ ${SIZEOF_TIME_T_CODE}
 /* to enable openssl + nghttp3 */
 #cmakedefine USE_OPENSSL_QUIC 1
 
+/* to enable openssl + ngtcp2 + nghttp3 */
+#cmakedefine OPENSSL_QUIC_API2 1
+
 /* Define to 1 if you have the quiche_conn_set_qlog_fd function. */
 #cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1
 
@@ -803,9 +815,6 @@ ${SIZEOF_TIME_T_CODE}
 /* Define to empty if `const' does not conform to ANSI C. */
 #cmakedefine const ${const}
 
-/* Type to use in place of in_addr_t when system does not provide it. */
-#cmakedefine in_addr_t ${in_addr_t}
-
 /* Define to `unsigned int' if <sys/types.h> does not define. */
 #cmakedefine size_t ${size_t}
 

+ 1 - 0
Utilities/cmcurl/lib/curl_ctype.h

@@ -37,6 +37,7 @@
 #define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
 #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
 #define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x))
+#define ISODIGIT(x) (((x) >= '0') && ((x) <= '7'))
 #define ISALNUM(x)  (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x))
 #define ISUPPER(x)  (((x) >= 'A') && ((x) <= 'Z'))
 #define ISLOWER(x)  (((x) >= 'a') && ((x) <= 'z'))

+ 12 - 11
Utilities/cmcurl/lib/curl_fnmatch.c

@@ -71,13 +71,13 @@ typedef enum {
 #define SETCHARSET_OK     1
 #define SETCHARSET_FAIL   0
 
-static int parsekeyword(unsigned char **pattern, unsigned char *charset)
+static int parsekeyword(const unsigned char **pattern, unsigned char *charset)
 {
   parsekey_state state = CURLFNM_PKW_INIT;
 #define KEYLEN 10
   char keyword[KEYLEN] = { 0 };
   int i;
-  unsigned char *p = *pattern;
+  const unsigned char *p = *pattern;
   bool found = FALSE;
   for(i = 0; !found; i++) {
     char c = (char)*p++;
@@ -140,9 +140,9 @@ static char_class charclass(unsigned char c)
 }
 
 /* Include a character or a range in set. */
-static void setcharorrange(unsigned char **pp, unsigned char *charset)
+static void setcharorrange(const unsigned char **pp, unsigned char *charset)
 {
-  unsigned char *p = (*pp)++;
+  const unsigned char *p = (*pp)++;
   unsigned char c = *p++;
 
   charset[c] = 1;
@@ -162,7 +162,7 @@ static void setcharorrange(unsigned char **pp, unsigned char *charset)
 }
 
 /* returns 1 (TRUE) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
-static int setcharset(unsigned char **p, unsigned char *charset)
+static int setcharset(const unsigned char **p, unsigned char *charset)
 {
   setcharset_state state = CURLFNM_SCHS_DEFAULT;
   bool something_found = FALSE;
@@ -185,7 +185,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
         (*p)++;
       }
       else if(c == '[') {
-        unsigned char *pp = *p + 1;
+        const unsigned char *pp = *p + 1;
 
         if(*pp++ == ':' && parsekeyword(&pp, charset))
           *p = pp;
@@ -257,12 +257,12 @@ fail:
 static int loop(const unsigned char *pattern, const unsigned char *string,
                 int maxstars)
 {
-  unsigned char *p = (unsigned char *)pattern;
-  unsigned char *s = (unsigned char *)string;
+  const unsigned char *p = (const unsigned char *)pattern;
+  const unsigned char *s = (const unsigned char *)string;
   unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
 
   for(;;) {
-    unsigned char *pp;
+    const unsigned char *pp;
 
     switch(*p) {
     case '*':
@@ -319,7 +319,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
         else if(charset[CURLFNM_PRINT])
           found = ISPRINT(*s);
         else if(charset[CURLFNM_SPACE])
-          found = ISSPACE(*s);
+          found = ISBLANK(*s);
         else if(charset[CURLFNM_UPPER])
           found = ISUPPER(*s);
         else if(charset[CURLFNM_LOWER])
@@ -359,7 +359,8 @@ int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
   if(!pattern || !string) {
     return CURL_FNMATCH_FAIL;
   }
-  return loop((unsigned char *)pattern, (unsigned char *)string, 2);
+  return loop((const unsigned char *)pattern,
+              (const unsigned char *)string, 2);
 }
 #else
 #include <fnmatch.h>

+ 5 - 5
Utilities/cmcurl/lib/curl_get_line.c

@@ -28,9 +28,7 @@
   !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC)
 
 #include "curl_get_line.h"
-#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
-#endif
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -42,7 +40,7 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
 {
   CURLcode result;
   char buffer[128];
-  Curl_dyn_reset(buf);
+  curlx_dyn_reset(buf);
   while(1) {
     char *b = fgets(buffer, sizeof(buffer), input);
 
@@ -52,7 +50,7 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
       if(!rlen)
         break;
 
-      result = Curl_dyn_addn(buf, b, rlen);
+      result = curlx_dyn_addn(buf, b, rlen);
       if(result)
         /* too long line or out of memory */
         return 0; /* error */
@@ -63,13 +61,15 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
 
       else if(feof(input)) {
         /* append a newline */
-        result = Curl_dyn_addn(buf, "\n", 1);
+        result = curlx_dyn_addn(buf, "\n", 1);
         if(result)
           /* too long line or out of memory */
           return 0; /* error */
         return 1; /* all good */
       }
     }
+    else if(curlx_dyn_len(buf))
+      return 1; /* all good */
     else
       break;
   }

+ 1 - 7
Utilities/cmcurl/lib/curl_get_line.h

@@ -24,13 +24,7 @@
  *
  ***************************************************************************/
 
-#include "dynbuf.h"
-
-#ifndef BUILDING_LIBCURL
-/* this renames functions so that the tool code can use the same code
-   without getting symbol collisions */
-#define Curl_get_line(a,b) curlx_get_line(a,b)
-#endif
+#include "curlx/dynbuf.h"
 
 /* Curl_get_line() returns complete lines that end with a newline. */
 int Curl_get_line(struct dynbuf *buf, FILE *input);

+ 2 - 2
Utilities/cmcurl/lib/curl_gssapi.c

@@ -46,10 +46,10 @@
 #endif
 
 gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
-  6, (char *)"\x2b\x06\x01\x05\x05\x02"
+  6, CURL_UNCONST("\x2b\x06\x01\x05\x05\x02")
 };
 gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
-  9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
+  9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")
 };
 
 OM_uint32 Curl_gss_init_sec_context(

+ 5 - 3
Utilities/cmcurl/lib/curl_krb5.h

@@ -39,14 +39,16 @@ struct Curl_sec_client_mech {
 #define AUTH_CONTINUE   1
 #define AUTH_ERROR      2
 
-#ifdef HAVE_GSSAPI
+#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
+void Curl_sec_conn_init(struct connectdata *);
+void Curl_sec_conn_destroy(struct connectdata *);
 int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
                       enum protection_level);
-void Curl_sec_end(struct connectdata *);
 CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
 int Curl_sec_request_prot(struct connectdata *conn, const char *level);
 #else
-#define Curl_sec_end(x)
+#define Curl_sec_conn_init(x)     Curl_nop_stmt
+#define Curl_sec_conn_destroy(x)  Curl_nop_stmt
 #endif
 
 #endif /* HEADER_CURL_KRB5_H */

+ 0 - 14
Utilities/cmcurl/lib/curl_memory.h

@@ -84,20 +84,6 @@
 #undef socketpair
 #endif
 
-#ifndef CURL_NO_GETADDRINFO_OVERRIDE
-#ifdef HAVE_GETADDRINFO
-#if defined(getaddrinfo) && defined(__osf__)
-#undef ogetaddrinfo
-#else
-#undef getaddrinfo
-#endif
-#endif /* HAVE_GETADDRINFO */
-
-#ifdef HAVE_FREEADDRINFO
-#undef freeaddrinfo
-#endif /* HAVE_FREEADDRINFO */
-#endif /* !CURL_NO_GETADDRINFO_OVERRIDE */
-
 /* sclose is probably already defined, redefine it! */
 #undef sclose
 #undef fopen

+ 1 - 7
Utilities/cmcurl/lib/curl_memrchr.c

@@ -33,10 +33,6 @@
 #include "memdebug.h"
 
 #ifndef HAVE_MEMRCHR
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
-  defined(USE_OPENSSL) || \
-  defined(USE_SCHANNEL)
-
 /*
  * Curl_memrchr()
  *
@@ -57,12 +53,10 @@ Curl_memrchr(const void *s, int c, size_t n)
 
     while(p >= q) {
       if(*p == (unsigned char)c)
-        return (void *)p;
+        return CURL_UNCONST(p);
       p--;
     }
   }
   return NULL;
 }
-
-#endif
 #endif /* HAVE_MEMRCHR */

+ 0 - 6
Utilities/cmcurl/lib/curl_memrchr.h

@@ -34,15 +34,9 @@
 #endif
 
 #else /* HAVE_MEMRCHR */
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
-  defined(USE_OPENSSL) || \
-  defined(USE_SCHANNEL)
-
 void *Curl_memrchr(const void *s, int c, size_t n);
-
 #define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
 
-#endif
 #endif /* HAVE_MEMRCHR */
 
 #endif /* HEADER_CURL_MEMRCHR_H */

+ 16 - 25
Utilities/cmcurl/lib/curl_ntlm_core.c

@@ -71,16 +71,7 @@
 #  include <openssl/md5.h>
 #  include <openssl/ssl.h>
 #  include <openssl/rand.h>
-#  if (defined(OPENSSL_VERSION_NUMBER) && \
-       (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL)
-#    define DES_key_schedule des_key_schedule
-#    define DES_cblock des_cblock
-#    define DES_set_odd_parity des_set_odd_parity
-#    define DES_set_key des_set_key
-#    define DES_ecb_encrypt des_ecb_encrypt
-#    define DESKEY(x) x
-#    define DESKEYARG(x) x
-#  elif defined(OPENSSL_IS_AWSLC)
+#  if defined(OPENSSL_IS_AWSLC)
 #    define DES_set_key_unchecked (void)DES_set_key
 #    define DESKEYARG(x) *x
 #    define DESKEY(x) &x
@@ -135,7 +126,7 @@
 #include "curl_ntlm_core.h"
 #include "curl_md5.h"
 #include "curl_hmac.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 #include "curl_endian.h"
 #include "curl_des.h"
 #include "curl_md4.h"
@@ -144,9 +135,6 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
-#define NTLMv2_BLOB_LEN       (44 -16 + ntlm->target_info_len + 4)
-
 #if !defined(CURL_NTLM_NOT_SUPPORTED)
 /*
 * Turns a 56-bit key into being 64-bit wide.
@@ -333,16 +321,16 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
   DES_key_schedule ks;
 
   setup_des_key(keys, DESKEY(ks));
-  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
-                  DESKEY(ks), DES_ENCRYPT);
+  DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+                  (DES_cblock*)results, DESKEY(ks), DES_ENCRYPT);
 
   setup_des_key(keys + 7, DESKEY(ks));
-  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
-                  DESKEY(ks), DES_ENCRYPT);
+  DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+                  (DES_cblock*)(results + 8), DESKEY(ks), DES_ENCRYPT);
 
   setup_des_key(keys + 14, DESKEY(ks));
-  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
-                  DESKEY(ks), DES_ENCRYPT);
+  DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+                  (DES_cblock*)(results + 16), DESKEY(ks), DES_ENCRYPT);
 #elif defined(USE_GNUTLS)
   struct des_ctx des;
   setup_des_key(keys, &des);
@@ -387,12 +375,12 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
     DES_key_schedule ks;
 
     setup_des_key(pw, DESKEY(ks));
-    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
-                    DESKEY(ks), DES_ENCRYPT);
+    DES_ecb_encrypt((DES_cblock *)CURL_UNCONST(magic),
+                    (DES_cblock *)lmbuffer, DESKEY(ks), DES_ENCRYPT);
 
     setup_des_key(pw + 7, DESKEY(ks));
-    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
-                    DESKEY(ks), DES_ENCRYPT);
+    DES_ecb_encrypt((DES_cblock *)CURL_UNCONST(magic),
+                    (DES_cblock *)(lmbuffer + 8), DESKEY(ks), DES_ENCRYPT);
 #elif defined(USE_GNUTLS)
     struct des_ctx des;
     setup_des_key(pw, &des);
@@ -465,6 +453,9 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
 
 #if !defined(USE_WINDOWS_SSPI)
 
+#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
+#define NTLMv2_BLOB_LEN       (44 -16 + ntlm->target_info_len + 4)
+
 /* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
 struct ms_filetime {
   unsigned int dwLowDateTime;
@@ -626,7 +617,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
   /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
   memcpy(ptr + 8, &ntlm->nonce[0], 8);
   result = Curl_hmacit(&Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
-                    NTLMv2_BLOB_LEN + 8, hmac_output);
+                       NTLMv2_BLOB_LEN + 8, hmac_output);
   if(result) {
     free(ptr);
     return result;

+ 15 - 9
Utilities/cmcurl/lib/curl_printf.h

@@ -24,21 +24,25 @@
  *
  ***************************************************************************/
 
-/*
- * This header should be included by ALL code in libcurl that uses any
- * *rintf() functions.
- */
-
-#ifndef CURL_TEMP_PRINTF
-#error "CURL_TEMP_PRINTF must be set before including curl/mprintf.h"
-#endif
-
 #include <curl/mprintf.h>
 
 #define MERR_OK        0
 #define MERR_MEM       1
 #define MERR_TOO_LARGE 2
 
+/* Lower-case digits.  */
+extern const unsigned char Curl_ldigits[];
+
+/* Upper-case digits.  */
+extern const unsigned char Curl_udigits[];
+
+#ifdef BUILDING_LIBCURL
+
+/*
+ * This header should be included by ALL code in libcurl that uses any
+ * *rintf() functions.
+ */
+
 # undef printf
 # undef fprintf
 # undef msnprintf
@@ -55,4 +59,6 @@
 # define mvsnprintf curl_mvsnprintf
 # define aprintf curl_maprintf
 # define vaprintf curl_mvaprintf
+
+#endif /* BUILDING_LIBCURL */
 #endif /* HEADER_CURL_PRINTF_H */

+ 17 - 16
Utilities/cmcurl/lib/curl_range.c

@@ -26,7 +26,7 @@
 #include <curl/curl.h>
 #include "curl_range.h"
 #include "sendf.h"
-#include "strtoofft.h"
+#include "curlx/strparse.h"
 
 /* Only include this function if one or more of FTP, FILE are enabled. */
 #if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
@@ -37,28 +37,29 @@
  */
 CURLcode Curl_range(struct Curl_easy *data)
 {
-  curl_off_t from, to;
-  char *ptr;
-  char *ptr2;
-
   if(data->state.use_range && data->state.range) {
-    CURLofft from_t;
-    CURLofft to_t;
-    from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
-    if(from_t == CURL_OFFT_FLOW)
-      return CURLE_RANGE_ERROR;
-    while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
-      ptr++;
-    to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
-    if(to_t == CURL_OFFT_FLOW)
+    curl_off_t from, to;
+    bool first_num = TRUE;
+    const char *p = data->state.range;
+    if(curlx_str_number(&p, &from, CURL_OFF_T_MAX))
+      first_num = FALSE;
+
+    if(curlx_str_single(&p, '-'))
+      /* no leading dash or after the first number is an error */
       return CURLE_RANGE_ERROR;
-    if((to_t == CURL_OFFT_INVAL) && !from_t) {
+
+    if(curlx_str_number(&p, &to, CURL_OFF_T_MAX)) {
+      /* no second number */
       /* X - */
       data->state.resume_from = from;
       DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
     }
-    else if((from_t == CURL_OFFT_INVAL) && !to_t) {
+    else if(!first_num) {
       /* -Y */
+      if(!to)
+        /* "-0" is just wrong */
+        return CURLE_RANGE_ERROR;
+
       data->req.maxdownload = to;
       data->state.resume_from = -to;
       DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));

+ 38 - 16
Utilities/cmcurl/lib/curl_rtmp.c

@@ -29,10 +29,11 @@
 
 #include "curl_rtmp.h"
 #include "urldata.h"
-#include "nonblock.h" /* for curlx_nonblock */
+#include "url.h"
+#include "curlx/nonblock.h" /* for curlx_nonblock */
 #include "progress.h" /* for Curl_pgrsSetUploadSize */
 #include "transfer.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 #include <curl/curl.h>
 #include <librtmp/rtmp.h>
 
@@ -52,6 +53,10 @@
 
 #define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
 
+/* meta key for storing RTMP* at connection */
+#define CURL_META_RTMP_CONN   "meta:proto:rtmp:conn"
+
+
 static CURLcode rtmp_setup_connection(struct Curl_easy *data,
                                       struct connectdata *conn);
 static CURLcode rtmp_do(struct Curl_easy *data, bool *done);
@@ -217,11 +222,21 @@ const struct Curl_handler Curl_handler_rtmpts = {
   PROTOPT_NONE                          /* flags */
 };
 
+static void rtmp_conn_dtor(void *key, size_t klen, void *entry)
+{
+  RTMP *r = entry;
+  (void)key;
+  (void)klen;
+  RTMP_Close(r);
+  RTMP_Free(r);
+}
+
 static CURLcode rtmp_setup_connection(struct Curl_easy *data,
                                       struct connectdata *conn)
 {
   RTMP *r = RTMP_Alloc();
-  if(!r)
+  if(!r ||
+    Curl_conn_meta_set(conn, CURL_META_RTMP_CONN, r, rtmp_conn_dtor))
     return CURLE_OUT_OF_MEMORY;
 
   RTMP_Init(r);
@@ -230,16 +245,18 @@ static CURLcode rtmp_setup_connection(struct Curl_easy *data,
     RTMP_Free(r);
     return CURLE_URL_MALFORMAT;
   }
-  conn->proto.rtmp = r;
   return CURLE_OK;
 }
 
 static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
 {
   struct connectdata *conn = data->conn;
-  RTMP *r = conn->proto.rtmp;
+  RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
   SET_RCVTIMEO(tv, 10);
 
+  if(!r)
+    return CURLE_FAILED_INIT;
+
   r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
 
   /* We have to know if it is a write before we send the
@@ -272,9 +289,9 @@ static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
 static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
 {
   struct connectdata *conn = data->conn;
-  RTMP *r = conn->proto.rtmp;
+  RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
 
-  if(!RTMP_ConnectStream(r, 0))
+  if(!r || !RTMP_ConnectStream(r, 0))
     return CURLE_FAILED_INIT;
 
   if(data->state.upload) {
@@ -301,14 +318,11 @@ static CURLcode rtmp_disconnect(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 bool dead_connection)
 {
-  RTMP *r = conn->proto.rtmp;
+  RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
   (void)data;
   (void)dead_connection;
-  if(r) {
-    conn->proto.rtmp = NULL;
-    RTMP_Close(r);
-    RTMP_Free(r);
-  }
+  if(r)
+    Curl_conn_meta_remove(conn, CURL_META_RTMP_CONN);
   return CURLE_OK;
 }
 
@@ -316,10 +330,14 @@ static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
   struct connectdata *conn = data->conn;
-  RTMP *r = conn->proto.rtmp;
+  RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
   ssize_t nread;
 
   (void)sockindex; /* unused */
+  if(!r) {
+    *err = CURLE_FAILED_INIT;
+    return -1;
+  }
 
   nread = RTMP_Read(r, buf, curlx_uztosi(len));
   if(nread < 0) {
@@ -338,13 +356,17 @@ static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
                          const void *buf, size_t len, bool eos, CURLcode *err)
 {
   struct connectdata *conn = data->conn;
-  RTMP *r = conn->proto.rtmp;
+  RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
   ssize_t num;
 
   (void)sockindex; /* unused */
   (void)eos; /* unused */
+  if(!r) {
+    *err = CURLE_FAILED_INIT;
+    return -1;
+  }
 
-  num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
+  num = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
   if(num < 0)
     *err = CURLE_SEND_ERROR;
 

+ 102 - 6
Utilities/cmcurl/lib/curl_sasl.c

@@ -42,15 +42,14 @@
 #include <curl/curl.h>
 #include "urldata.h"
 
-#include "curl_base64.h"
+#include "curlx/base64.h"
 #include "curl_md5.h"
 #include "vauth/vauth.h"
 #include "cfilters.h"
 #include "vtls/vtls.h"
 #include "curl_hmac.h"
 #include "curl_sasl.h"
-#include "warnless.h"
-#include "strtok.h"
+#include "curlx/warnless.h"
 #include "sendf.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -284,7 +283,7 @@ static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
     if(!*serverdata || *serverdata == '=')
       Curl_bufref_set(out, NULL, 0, NULL);
     else {
-      result = Curl_base64_decode(serverdata, &msg, &msglen);
+      result = curlx_base64_decode(serverdata, &msg, &msglen);
       if(!result)
         Curl_bufref_set(out, msg, msglen, curl_free);
     }
@@ -307,8 +306,8 @@ static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
       char *base64;
       size_t base64len;
 
-      result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
-                                  Curl_bufref_len(msg), &base64, &base64len);
+      result = curlx_base64_encode((const char *) Curl_bufref_ptr(msg),
+                                   Curl_bufref_len(msg), &base64, &base64len);
       if(!result)
         Curl_bufref_set(msg, base64, base64len, curl_free);
     }
@@ -757,4 +756,101 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 
   return result;
 }
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void sasl_unchosen(struct Curl_easy *data, unsigned short mech,
+                          unsigned short enabledmechs,
+                          bool built_in, bool platform,
+                          const char *param_missing)
+{
+  const char *mname = NULL;
+  size_t i;
+
+  if(!(enabledmechs & mech))
+    return;
+
+  for(i = 0; mechtable[i].name; ++i) {
+    if(mechtable[i].bit == mech) {
+      mname = mechtable[i].name;
+      break;
+    }
+  }
+  if(!mname)  /* should not happen */
+    return;
+  if(!built_in)
+    infof(data, "SASL: %s not builtin", mname);
+  else if(!platform)
+    infof(data, "SASL: %s not supported by the platform/libraries", mname);
+  else {
+    if(param_missing)
+      infof(data, "SASL: %s is missing %s", mname, param_missing);
+    if(!data->state.aptr.user)
+      infof(data, "SASL: %s is missing username", mname);
+  }
+}
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+#ifdef USE_KERBEROS5
+#define CURL_SASL_KERBEROS5   TRUE
+#else
+#define CURL_SASL_KERBEROS5   FALSE
+#endif
+#ifdef USE_GSASL
+#define CURL_SASL_GASL        TRUE
+#else
+#define CURL_SASL_GASL        FALSE
+#endif
+#ifdef CURL_DISABLE_DIGEST_AUTH
+#define CURL_SASL_DIGEST      TRUE
+#else
+#define CURL_SASL_DIGEST      FALSE
+#endif
+#ifndef USE_NTLM
+#define CURL_SASL_NTLM        TRUE
+#else
+#define CURL_SASL_NTLM        FALSE
+#endif
+  /* Failing SASL authentication is a pain. Give a helping hand if
+   * we were unable to select an AUTH mechanism.
+   * `sasl->authmechs` are mechanisms offered by the peer
+   * `sasl->prefmech`  are mechanisms preferred by us */
+  unsigned short enabledmechs = sasl->authmechs & sasl->prefmech;
+
+  if(!sasl->authmechs)
+    infof(data, "SASL: no auth mechanism was offered or recognized");
+  else if(!enabledmechs)
+    infof(data, "SASL: no overlap between offered and configured "
+          "auth mechanisms");
+  else {
+    infof(data, "SASL: no auth mechanism offered could be selected");
+    if((enabledmechs & SASL_MECH_EXTERNAL) && data->conn->passwd[0])
+      infof(data, "SASL: auth EXTERNAL not chosen with password");
+    sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs,
+                  CURL_SASL_KERBEROS5, Curl_auth_is_gssapi_supported(), NULL);
+    sasl_unchosen(data, SASL_MECH_SCRAM_SHA_256, enabledmechs,
+                  CURL_SASL_GASL, FALSE, NULL);
+    sasl_unchosen(data, SASL_MECH_SCRAM_SHA_1, enabledmechs,
+                  CURL_SASL_GASL, FALSE, NULL);
+    sasl_unchosen(data, SASL_MECH_DIGEST_MD5, enabledmechs,
+                  CURL_SASL_DIGEST, Curl_auth_is_digest_supported(), NULL);
+    sasl_unchosen(data, SASL_MECH_CRAM_MD5, enabledmechs,
+                  CURL_SASL_DIGEST, TRUE, NULL);
+    sasl_unchosen(data, SASL_MECH_NTLM, enabledmechs,
+                  CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL);
+    sasl_unchosen(data, SASL_MECH_OAUTHBEARER, enabledmechs,  TRUE, TRUE,
+                  data->set.str[STRING_BEARER] ?
+                  NULL : "CURLOPT_XOAUTH2_BEARER");
+    sasl_unchosen(data, SASL_MECH_XOAUTH2, enabledmechs,  TRUE, TRUE,
+                  data->set.str[STRING_BEARER] ?
+                  NULL : "CURLOPT_XOAUTH2_BEARER");
+  }
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+  (void)sasl;
+  (void)data;
+  return CURLE_LOGIN_DENIED;
+}
+
 #endif /* protocols are enabled that use SASL */

+ 2 - 0
Utilities/cmcurl/lib/curl_sasl.h

@@ -162,4 +162,6 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
                             int code, saslprogress *progress);
 
+CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data);
+
 #endif /* HEADER_CURL_SASL_H */

+ 78 - 27
Utilities/cmcurl/lib/curl_setup.h

@@ -28,9 +28,6 @@
 #define CURL_NO_OLDIES
 #endif
 
-/* Tell "curl/curl.h" not to include "curl/mprintf.h" */
-#define CURL_SKIP_INCLUDE_MPRINTF
-
 /* Set default _WIN32_WINNT */
 #ifdef __MINGW32__
 #include <_mingw.h>
@@ -56,7 +53,7 @@
 #  endif
 #endif
 
-#if defined(__APPLE__)
+#ifdef __APPLE__
 #include <sys/types.h>
 #include <TargetConditionals.h>
 /* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
@@ -78,6 +75,12 @@
 #endif
 #endif
 
+/* Visual Studio 2008 is the minimum Visual Studio version we support.
+   Workarounds for older versions of Visual Studio have been removed. */
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+#error "Ancient versions of Visual Studio are no longer supported due to bugs."
+#endif
+
 #ifdef _MSC_VER
 /* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
 #pragma warning(disable:4127)
@@ -114,6 +117,14 @@
 #  endif
 #endif
 
+/* Avoid bogus format check warnings with mingw32ce gcc 4.4.0 in
+   C99 (-std=gnu99) mode */
+#if defined(__MINGW32CE__) && !defined(CURL_NO_FMT_CHECKS) && \
+  (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && \
+  (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4))
+#define CURL_NO_FMT_CHECKS
+#endif
+
 /* Compatibility */
 #ifdef ENABLE_IPV6
 #define USE_IPV6 1
@@ -165,6 +176,12 @@
 /* system header files in our config files, avoid this at any cost. */
 /* ================================================================ */
 
+#ifdef HAVE_LIBZ
+#  ifndef ZLIB_CONST
+#  define ZLIB_CONST  /* Use z_const. Supported by v1.2.5.2 and upper. */
+#  endif
+#endif
+
 /*
  * AIX 4.3 and newer needs _THREAD_SAFE defined to build
  * proper reentrant code. Others may also need it.
@@ -266,7 +283,7 @@
  * When HTTP is disabled, disable HTTP-only features
  */
 
-#if defined(CURL_DISABLE_HTTP)
+#ifdef CURL_DISABLE_HTTP
 #  define CURL_DISABLE_ALTSVC 1
 #  define CURL_DISABLE_COOKIES 1
 #  define CURL_DISABLE_BASIC_AUTH 1
@@ -439,6 +456,11 @@
 #  define __NO_NET_API
 #endif
 
+/* Whether to use eventfd() */
+#if defined(HAVE_EVENTFD) && defined(HAVE_SYS_EVENTFD_H)
+#define USE_EVENTFD
+#endif
+
 #include <stdio.h>
 #include <assert.h>
 
@@ -452,12 +474,6 @@
 #include <curl/stdcheaders.h>
 #endif
 
-#ifdef _WIN32
-#define Curl_getpid() GetCurrentProcessId()
-#else
-#define Curl_getpid() getpid()
-#endif
-
 /* Default Windows file API selection.  */
 #ifdef _WIN32
 # if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64)
@@ -474,7 +490,9 @@
  */
 
 #ifdef USE_WIN32_LARGE_FILES
+#  ifdef HAVE_IO_H
 #  include <io.h>
+#  endif
 #  include <sys/types.h>
 #  include <sys/stat.h>
 #  undef  lseek
@@ -505,10 +523,12 @@
  */
 
 #if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
+#  ifdef HAVE_IO_H
 #  include <io.h>
+#  endif
 #  include <sys/types.h>
 #  include <sys/stat.h>
-#  ifndef _WIN32_WCE
+#  ifndef UNDER_CE
 #    undef  lseek
 #    define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
 #    define fstat(fdes,stp)            _fstat(fdes, stp)
@@ -683,7 +703,6 @@
 
 #  ifdef __minix
      /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
-     extern char *strtok_r(char *s, const char *delim, char **last);
      extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp);
 #  endif
 
@@ -696,16 +715,6 @@
 /*         CURLRES_* defines to use in the host*.c sources          */
 /* ---------------------------------------------------------------- */
 
-/*
- * MSVC threads support requires a multi-threaded runtime library.
- * _beginthreadex() is not available in single-threaded ones.
- * Single-threaded option was last available in VS2005: _MSC_VER <= 1400
- */
-#if defined(_MSC_VER) && !defined(_MT)  /* available in _MSC_VER <= 1400 */
-#  undef USE_THREADS_POSIX
-#  undef USE_THREADS_WIN32
-#endif
-
 /*
  * Mutually exclusive CURLRES_* definitions.
  */
@@ -779,7 +788,7 @@
 #endif
 
 /* Single point where USE_NTLM definition might be defined */
-#if !defined(CURL_DISABLE_NTLM)
+#ifndef CURL_DISABLE_NTLM
 #  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                   \
   defined(USE_GNUTLS) || defined(USE_SECTRANSP) ||                      \
   defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
@@ -819,7 +828,7 @@
 
 /* noreturn attribute */
 
-#if !defined(CURL_NORETURN)
+#ifndef CURL_NORETURN
 #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
   defined(__IAR_SYSTEMS_ICC__)
 #  define CURL_NORETURN  __attribute__((__noreturn__))
@@ -832,7 +841,7 @@
 
 /* fallthrough attribute */
 
-#if !defined(FALLTHROUGH)
+#ifndef FALLTHROUGH
 #if (defined(__GNUC__) && __GNUC__ >= 7) || \
     (defined(__clang__) && __clang_major__ >= 10)
 #  define FALLTHROUGH()  __attribute__((fallthrough))
@@ -849,6 +858,27 @@
 #include "curl_setup_once.h"
 #endif
 
+#ifdef UNDER_CE
+#define getenv curl_getenv  /* Windows CE does not support getenv() */
+#define raise(s) ((void)(s))
+/* Terrible workarounds to make Windows CE compile */
+#define errno 0
+#define CURL_SETERRNO(x) ((void)(x))
+#define EINTR  4
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EEXIST 17
+#define EISDIR 21
+#define EINVAL 22
+#define ENOSPC 28
+#define strerror(x) "?"
+#undef STDIN_FILENO
+#define STDIN_FILENO 0
+#else
+#define CURL_SETERRNO(x) (errno = (x))
+#endif
+
 /*
  * Definition of our NOP statement Object-like macro
  */
@@ -893,6 +923,17 @@
 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 #endif
 
+/* For MSVC (all versions as of VS2022) */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO  fileno(stdin)
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO  fileno(stdout)
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO  fileno(stderr)
+#endif
+
 /* Since O_BINARY is used in bitmasks, setting it to zero makes it usable in
    source code but yet it does not ruin anything */
 #ifdef O_BINARY
@@ -950,6 +991,16 @@ endings either CRLF or LF so 't' is appropriate.
 
 #define CURL_ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 
+#ifdef CURLDEBUG
+#define CURL_GETADDRINFO(host,serv,hint,res) \
+  curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#define CURL_FREEADDRINFO(data) \
+  curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
+#else
+#define CURL_GETADDRINFO getaddrinfo
+#define CURL_FREEADDRINFO freeaddrinfo
+#endif
+
 /* Some versions of the Android NDK is missing the declaration */
 #if defined(HAVE_GETPWUID_R) && \
   defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
@@ -1012,7 +1063,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #  endif
 #endif
 
-#if defined(CURL_INLINE)
+#ifdef CURL_INLINE
 /* 'CURL_INLINE' defined, use as-is */
 #elif defined(inline)
 #  define CURL_INLINE inline /* 'inline' defined, assumed correct */

+ 54 - 82
Utilities/cmcurl/lib/curl_setup_once.h

@@ -33,7 +33,9 @@
 #include <string.h>
 #include <stdarg.h>
 #include <time.h>
+#ifndef UNDER_CE
 #include <errno.h>
+#endif
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -63,10 +65,20 @@
 #include <unistd.h>
 #endif
 
-#ifdef USE_WOLFSSL
+#if defined(HAVE_STDINT_H) || defined(USE_WOLFSSL)
 #include <stdint.h>
 #endif
 
+/* Macro to strip 'const' without triggering a compiler warning.
+   Use it for APIs that do not or cannot support the const qualifier. */
+#ifdef HAVE_STDINT_H
+#  define CURL_UNCONST(p) ((void *)(uintptr_t)(const void *)(p))
+#elif defined(_WIN32)  /* for VS2008 */
+#  define CURL_UNCONST(p) ((void *)(ULONG_PTR)(const void *)(p))
+#else
+#  define CURL_UNCONST(p) ((void *)(p))  /* Fall back to simple cast */
+#endif
+
 #ifdef USE_SCHANNEL
 /* Must set this before <schannel.h> is included directly or indirectly by
    another Windows header. */
@@ -123,7 +135,7 @@ struct timeval {
 #endif
 
 
-#if defined(__minix)
+#ifdef __minix
 /* Minix does not support recv on TCP sockets */
 #define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
                                    (RECV_TYPE_ARG2)(y), \
@@ -163,15 +175,14 @@ struct timeval {
 #endif /* HAVE_RECV */
 
 
-#if defined(__minix)
+#ifdef __minix
 /* Minix does not support send on TCP sockets */
 #define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
-                                    (SEND_TYPE_ARG2)(y), \
-                                    (SEND_TYPE_ARG3)(z))
-
+                                     (SEND_TYPE_ARG2)CURL_UNCONST(y), \
+                                     (SEND_TYPE_ARG3)(z))
 #elif defined(HAVE_SEND)
 #define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
-                                    (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \
+                              (SEND_QUAL_ARG2 SEND_TYPE_ARG2)CURL_UNCONST(y), \
                                     (SEND_TYPE_ARG3)(z), \
                                     (SEND_TYPE_ARG4)(SEND_4TH_ARG))
 #else /* HAVE_SEND */
@@ -185,7 +196,7 @@ struct timeval {
  * Function-like macro definition used to close a socket.
  */
 
-#if defined(HAVE_CLOSESOCKET)
+#ifdef HAVE_CLOSESOCKET
 #  define sclose(x)  closesocket((x))
 #elif defined(HAVE_CLOSESOCKET_CAMEL)
 #  define sclose(x)  CloseSocket((x))
@@ -200,7 +211,7 @@ struct timeval {
 /*
  * Stack-independent version of fcntl() on sockets:
  */
-#if defined(USE_LWIPSOCK)
+#ifdef USE_LWIPSOCK
 #  define sfcntl  lwip_fcntl
 #else
 #  define sfcntl  fcntl
@@ -284,7 +295,7 @@ typedef unsigned int bit;
  */
 
 #undef DEBUGASSERT
-#if defined(DEBUGBUILD)
+#ifdef DEBUGBUILD
 #define DEBUGASSERT(x) assert(x)
 #else
 #define DEBUGASSERT(x) do { } while(0)
@@ -310,78 +321,39 @@ typedef unsigned int bit;
  */
 
 #ifdef USE_WINSOCK
-#undef  EBADF            /* override definition in errno.h */
-#define EBADF            WSAEBADF
-#undef  EINTR            /* override definition in errno.h */
-#define EINTR            WSAEINTR
-#undef  EINVAL           /* override definition in errno.h */
-#define EINVAL           WSAEINVAL
-#undef  EWOULDBLOCK      /* override definition in errno.h */
-#define EWOULDBLOCK      WSAEWOULDBLOCK
-#undef  EINPROGRESS      /* override definition in errno.h */
-#define EINPROGRESS      WSAEINPROGRESS
-#undef  EALREADY         /* override definition in errno.h */
-#define EALREADY         WSAEALREADY
-#undef  ENOTSOCK         /* override definition in errno.h */
-#define ENOTSOCK         WSAENOTSOCK
-#undef  EDESTADDRREQ     /* override definition in errno.h */
-#define EDESTADDRREQ     WSAEDESTADDRREQ
-#undef  EMSGSIZE         /* override definition in errno.h */
-#define EMSGSIZE         WSAEMSGSIZE
-#undef  EPROTOTYPE       /* override definition in errno.h */
-#define EPROTOTYPE       WSAEPROTOTYPE
-#undef  ENOPROTOOPT      /* override definition in errno.h */
-#define ENOPROTOOPT      WSAENOPROTOOPT
-#undef  EPROTONOSUPPORT  /* override definition in errno.h */
-#define EPROTONOSUPPORT  WSAEPROTONOSUPPORT
-#define ESOCKTNOSUPPORT  WSAESOCKTNOSUPPORT
-#undef  EOPNOTSUPP       /* override definition in errno.h */
-#define EOPNOTSUPP       WSAEOPNOTSUPP
-#define EPFNOSUPPORT     WSAEPFNOSUPPORT
-#undef  EAFNOSUPPORT     /* override definition in errno.h */
-#define EAFNOSUPPORT     WSAEAFNOSUPPORT
-#undef  EADDRINUSE       /* override definition in errno.h */
-#define EADDRINUSE       WSAEADDRINUSE
-#undef  EADDRNOTAVAIL    /* override definition in errno.h */
-#define EADDRNOTAVAIL    WSAEADDRNOTAVAIL
-#undef  ENETDOWN         /* override definition in errno.h */
-#define ENETDOWN         WSAENETDOWN
-#undef  ENETUNREACH      /* override definition in errno.h */
-#define ENETUNREACH      WSAENETUNREACH
-#undef  ENETRESET        /* override definition in errno.h */
-#define ENETRESET        WSAENETRESET
-#undef  ECONNABORTED     /* override definition in errno.h */
-#define ECONNABORTED     WSAECONNABORTED
-#undef  ECONNRESET       /* override definition in errno.h */
-#define ECONNRESET       WSAECONNRESET
-#undef  ENOBUFS          /* override definition in errno.h */
-#define ENOBUFS          WSAENOBUFS
-#undef  EISCONN          /* override definition in errno.h */
-#define EISCONN          WSAEISCONN
-#undef  ENOTCONN         /* override definition in errno.h */
-#define ENOTCONN         WSAENOTCONN
-#define ESHUTDOWN        WSAESHUTDOWN
-#define ETOOMANYREFS     WSAETOOMANYREFS
-#undef  ETIMEDOUT        /* override definition in errno.h */
-#define ETIMEDOUT        WSAETIMEDOUT
-#undef  ECONNREFUSED     /* override definition in errno.h */
-#define ECONNREFUSED     WSAECONNREFUSED
-#undef  ELOOP            /* override definition in errno.h */
-#define ELOOP            WSAELOOP
-#ifndef ENAMETOOLONG     /* possible previous definition in errno.h */
-#define ENAMETOOLONG     WSAENAMETOOLONG
-#endif
-#define EHOSTDOWN        WSAEHOSTDOWN
-#undef  EHOSTUNREACH     /* override definition in errno.h */
-#define EHOSTUNREACH     WSAEHOSTUNREACH
-#ifndef ENOTEMPTY        /* possible previous definition in errno.h */
-#define ENOTEMPTY        WSAENOTEMPTY
+#define SOCKEACCES        WSAEACCES
+#define SOCKEADDRINUSE    WSAEADDRINUSE
+#define SOCKEADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define SOCKEAFNOSUPPORT  WSAEAFNOSUPPORT
+#define SOCKEBADF         WSAEBADF
+#define SOCKECONNREFUSED  WSAECONNREFUSED
+#define SOCKECONNRESET    WSAECONNRESET
+#define SOCKEINPROGRESS   WSAEINPROGRESS
+#define SOCKEINTR         WSAEINTR
+#define SOCKEINVAL        WSAEINVAL
+#define SOCKEISCONN       WSAEISCONN
+#define SOCKEMSGSIZE      WSAEMSGSIZE
+#define SOCKENOMEM        WSA_NOT_ENOUGH_MEMORY
+#define SOCKETIMEDOUT     WSAETIMEDOUT
+#define SOCKEWOULDBLOCK   WSAEWOULDBLOCK
+#else
+#define SOCKEACCES        EACCES
+#define SOCKEADDRINUSE    EADDRINUSE
+#define SOCKEADDRNOTAVAIL EADDRNOTAVAIL
+#define SOCKEAFNOSUPPORT  EAFNOSUPPORT
+#define SOCKEBADF         EBADF
+#define SOCKECONNREFUSED  ECONNREFUSED
+#define SOCKECONNRESET    ECONNRESET
+#define SOCKEINPROGRESS   EINPROGRESS
+#define SOCKEINTR         EINTR
+#define SOCKEINVAL        EINVAL
+#define SOCKEISCONN       EISCONN
+#define SOCKEMSGSIZE      EMSGSIZE
+#define SOCKENOMEM        ENOMEM
+#ifdef ETIMEDOUT
+#define SOCKETIMEDOUT     ETIMEDOUT
 #endif
-#define EPROCLIM         WSAEPROCLIM
-#define EUSERS           WSAEUSERS
-#define EDQUOT           WSAEDQUOT
-#define ESTALE           WSAESTALE
-#define EREMOTE          WSAEREMOTE
+#define SOCKEWOULDBLOCK   EWOULDBLOCK
 #endif
 
 /*
@@ -390,7 +362,7 @@ typedef unsigned int bit;
 
 #ifdef __VMS
 #define argv_item_t  __char_ptr32
-#elif defined(_UNICODE)
+#elif defined(_UNICODE) && !defined(UNDER_CE)
 #define argv_item_t  wchar_t *
 #else
 #define argv_item_t  char *

+ 1 - 5
Utilities/cmcurl/lib/curl_sha512_256.c

@@ -27,7 +27,7 @@
 #if !defined(CURL_DISABLE_DIGEST_AUTH) && !defined(CURL_DISABLE_SHA512_256)
 
 #include "curl_sha512_256.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
 
 /* The recommended order of the TLS backends:
  * * OpenSSL
@@ -82,7 +82,6 @@
 #  include <nettle/sha.h>
 #  if defined(SHA512_256_DIGEST_SIZE)
 #    define USE_GNUTLS_SHA512_256           1
-#    define HAS_SHA512_256_IMPLEMENTATION   1
 #  endif
 #endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */
 
@@ -269,9 +268,6 @@ Curl_sha512_256_finish(unsigned char *digest,
 
 #else /* No system or TLS backend SHA-512/256 implementation available */
 
-/* Use local implementation */
-#define HAS_SHA512_256_IMPLEMENTATION   1
-
 /* ** This implementation of SHA-512/256 hash calculation was originally ** *
  * ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd.          ** *
  * ** The author ported the code to libcurl. The ported code is provided ** *

+ 8 - 8
Utilities/cmcurl/lib/curl_sspi.c

@@ -28,10 +28,10 @@
 
 #include <curl/curl.h>
 #include "curl_sspi.h"
-#include "curl_multibyte.h"
+#include "curlx/multibyte.h"
 #include "system_win32.h"
-#include "version_win32.h"
-#include "warnless.h"
+#include "curlx/version_win32.h"
+#include "curlx/warnless.h"
 
 /* The last #include files should be: */
 #include "curl_memory.h"
@@ -42,7 +42,7 @@ typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
 
 /* See definition of SECURITY_ENTRYPOINT in sspi.h */
 #ifdef UNICODE
-#  ifdef _WIN32_WCE
+#  ifdef UNDER_CE
 #    define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
 #  else
 #    define SECURITYENTRYPOINT "InitSecurityInterfaceW"
@@ -129,7 +129,7 @@ void Curl_sspi_global_cleanup(void)
 /*
  * Curl_create_sspi_identity()
  *
- * This is used to populate a SSPI identity structure based on the supplied
+ * This is used to populate an SSPI identity structure based on the supplied
  * username and password.
  *
  * Parameters:
@@ -154,7 +154,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
   /* Initialize the identity */
   memset(identity, 0, sizeof(*identity));
 
-  useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp);
+  useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp);
   if(!useranddomain.tchar_ptr)
     return CURLE_OUT_OF_MEMORY;
 
@@ -198,7 +198,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
   curlx_unicodefree(useranddomain.tchar_ptr);
 
   /* Setup the identity's password and length */
-  passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp);
+  passwd.tchar_ptr = curlx_convert_UTF8_to_tchar(passwdp);
   if(!passwd.tchar_ptr)
     return CURLE_OUT_OF_MEMORY;
   dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
@@ -221,7 +221,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
 /*
  * Curl_sspi_free_identity()
  *
- * This is used to free the contents of a SSPI identifier structure.
+ * This is used to free the contents of an SSPI identifier structure.
  *
  * Parameters:
  *

+ 246 - 1
Utilities/cmcurl/lib/curl_sspi.h

@@ -45,7 +45,7 @@
 CURLcode Curl_sspi_global_init(void);
 void Curl_sspi_global_cleanup(void);
 
-/* This is used to populate the domain in a SSPI identity structure */
+/* This is used to populate the domain in an SSPI identity structure */
 CURLcode Curl_override_sspi_http_realm(const char *chlg,
                                        SEC_WINNT_AUTH_IDENTITY *identity);
 
@@ -70,6 +70,225 @@ extern PSecurityFunctionTable Curl_pSecFn;
 #define ISC_REQ_USE_HTTP_STYLE                0x01000000
 #endif
 
+#ifdef __MINGW32CE__
+#ifndef ISC_RET_REPLAY_DETECT
+#define ISC_RET_REPLAY_DETECT                 0x00000004
+#endif
+#ifndef ISC_RET_SEQUENCE_DETECT
+#define ISC_RET_SEQUENCE_DETECT               0x00000008
+#endif
+#ifndef ISC_RET_CONFIDENTIALITY
+#define ISC_RET_CONFIDENTIALITY               0x00000010
+#endif
+#ifndef ISC_RET_ALLOCATED_MEMORY
+#define ISC_RET_ALLOCATED_MEMORY              0x00000100
+#endif
+#ifndef ISC_RET_STREAM
+#define ISC_RET_STREAM                        0x00008000
+#endif
+
+#ifndef SEC_E_INSUFFICIENT_MEMORY
+#define SEC_E_INSUFFICIENT_MEMORY             ((HRESULT)0x80090300L)
+#endif
+#ifndef SEC_E_INVALID_HANDLE
+#define SEC_E_INVALID_HANDLE                  ((HRESULT)0x80090301L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_FUNCTION
+#define SEC_E_UNSUPPORTED_FUNCTION            ((HRESULT)0x80090302L)
+#endif
+#ifndef SEC_E_TARGET_UNKNOWN
+#define SEC_E_TARGET_UNKNOWN                  ((HRESULT)0x80090303L)
+#endif
+#ifndef SEC_E_INTERNAL_ERROR
+#define SEC_E_INTERNAL_ERROR                  ((HRESULT)0x80090304L)
+#endif
+#ifndef SEC_E_SECPKG_NOT_FOUND
+#define SEC_E_SECPKG_NOT_FOUND                ((HRESULT)0x80090305L)
+#endif
+#ifndef SEC_E_NOT_OWNER
+#define SEC_E_NOT_OWNER                       ((HRESULT)0x80090306L)
+#endif
+#ifndef SEC_E_CANNOT_INSTALL
+#define SEC_E_CANNOT_INSTALL                  ((HRESULT)0x80090307L)
+#endif
+#ifndef SEC_E_INVALID_TOKEN
+#define SEC_E_INVALID_TOKEN                   ((HRESULT)0x80090308L)
+#endif
+#ifndef SEC_E_CANNOT_PACK
+#define SEC_E_CANNOT_PACK                     ((HRESULT)0x80090309L)
+#endif
+#ifndef SEC_E_QOP_NOT_SUPPORTED
+#define SEC_E_QOP_NOT_SUPPORTED               ((HRESULT)0x8009030AL)
+#endif
+#ifndef SEC_E_NO_IMPERSONATION
+#define SEC_E_NO_IMPERSONATION                ((HRESULT)0x8009030BL)
+#endif
+#ifndef SEC_E_LOGON_DENIED
+#define SEC_E_LOGON_DENIED                    ((HRESULT)0x8009030CL)
+#endif
+#ifndef SEC_E_UNKNOWN_CREDENTIALS
+#define SEC_E_UNKNOWN_CREDENTIALS             ((HRESULT)0x8009030DL)
+#endif
+#ifndef SEC_E_NO_CREDENTIALS
+#define SEC_E_NO_CREDENTIALS                  ((HRESULT)0x8009030EL)
+#endif
+#ifndef SEC_E_MESSAGE_ALTERED
+#define SEC_E_MESSAGE_ALTERED                 ((HRESULT)0x8009030FL)
+#endif
+#ifndef SEC_E_OUT_OF_SEQUENCE
+#define SEC_E_OUT_OF_SEQUENCE                 ((HRESULT)0x80090310L)
+#endif
+#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY
+#define SEC_E_NO_AUTHENTICATING_AUTHORITY     ((HRESULT)0x80090311L)
+#endif
+#ifndef SEC_E_BAD_PKGID
+#define SEC_E_BAD_PKGID                       ((HRESULT)0x80090316L)
+#endif
+#ifndef SEC_E_CONTEXT_EXPIRED
+#define SEC_E_CONTEXT_EXPIRED                 ((HRESULT)0x80090317L)
+#endif
+#ifndef SEC_E_INCOMPLETE_MESSAGE
+#define SEC_E_INCOMPLETE_MESSAGE              ((HRESULT)0x80090318L)
+#endif
+#ifndef SEC_E_INCOMPLETE_CREDENTIALS
+#define SEC_E_INCOMPLETE_CREDENTIALS          ((HRESULT)0x80090320L)
+#endif
+#ifndef SEC_E_BUFFER_TOO_SMALL
+#define SEC_E_BUFFER_TOO_SMALL                ((HRESULT)0x80090321L)
+#endif
+#ifndef SEC_E_WRONG_PRINCIPAL
+#define SEC_E_WRONG_PRINCIPAL                 ((HRESULT)0x80090322L)
+#endif
+#ifndef SEC_E_TIME_SKEW
+#define SEC_E_TIME_SKEW                       ((HRESULT)0x80090324L)
+#endif
+#ifndef SEC_E_UNTRUSTED_ROOT
+#define SEC_E_UNTRUSTED_ROOT                  ((HRESULT)0x80090325L)
+#endif
+#ifndef SEC_E_ILLEGAL_MESSAGE
+#define SEC_E_ILLEGAL_MESSAGE                 ((HRESULT)0x80090326L)
+#endif
+#ifndef SEC_E_CERT_UNKNOWN
+#define SEC_E_CERT_UNKNOWN                    ((HRESULT)0x80090327L)
+#endif
+#ifndef SEC_E_CERT_EXPIRED
+#define SEC_E_CERT_EXPIRED                    ((HRESULT)0x80090328L)
+#endif
+#ifndef SEC_E_ENCRYPT_FAILURE
+#define SEC_E_ENCRYPT_FAILURE                 ((HRESULT)0x80090329L)
+#endif
+#ifndef SEC_E_DECRYPT_FAILURE
+#define SEC_E_DECRYPT_FAILURE                 ((HRESULT)0x80090330L)
+#endif
+#ifndef SEC_E_ALGORITHM_MISMATCH
+#define SEC_E_ALGORITHM_MISMATCH              ((HRESULT)0x80090331L)
+#endif
+#ifndef SEC_E_SECURITY_QOS_FAILED
+#define SEC_E_SECURITY_QOS_FAILED             ((HRESULT)0x80090332L)
+#endif
+#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED
+#define SEC_E_UNFINISHED_CONTEXT_DELETED      ((HRESULT)0x80090333L)
+#endif
+#ifndef SEC_E_NO_TGT_REPLY
+#define SEC_E_NO_TGT_REPLY                    ((HRESULT)0x80090334L)
+#endif
+#ifndef SEC_E_NO_IP_ADDRESSES
+#define SEC_E_NO_IP_ADDRESSES                 ((HRESULT)0x80090335L)
+#endif
+#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE
+#define SEC_E_WRONG_CREDENTIAL_HANDLE         ((HRESULT)0x80090336L)
+#endif
+#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
+#define SEC_E_CRYPTO_SYSTEM_INVALID           ((HRESULT)0x80090337L)
+#endif
+#ifndef SEC_E_MAX_REFERRALS_EXCEEDED
+#define SEC_E_MAX_REFERRALS_EXCEEDED          ((HRESULT)0x80090338L)
+#endif
+#ifndef SEC_E_MUST_BE_KDC
+#define SEC_E_MUST_BE_KDC                     ((HRESULT)0x80090339L)
+#endif
+#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED     ((HRESULT)0x8009033AL)
+#endif
+#ifndef SEC_E_TOO_MANY_PRINCIPALS
+#define SEC_E_TOO_MANY_PRINCIPALS             ((HRESULT)0x8009033BL)
+#endif
+#ifndef SEC_E_NO_PA_DATA
+#define SEC_E_NO_PA_DATA                      ((HRESULT)0x8009033CL)
+#endif
+#ifndef SEC_E_PKINIT_NAME_MISMATCH
+#define SEC_E_PKINIT_NAME_MISMATCH            ((HRESULT)0x8009033DL)
+#endif
+#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED
+#define SEC_E_SMARTCARD_LOGON_REQUIRED        ((HRESULT)0x8009033EL)
+#endif
+#ifndef SEC_E_SHUTDOWN_IN_PROGRESS
+#define SEC_E_SHUTDOWN_IN_PROGRESS            ((HRESULT)0x8009033FL)
+#endif
+#ifndef SEC_E_KDC_INVALID_REQUEST
+#define SEC_E_KDC_INVALID_REQUEST             ((HRESULT)0x80090340L)
+#endif
+#ifndef SEC_E_KDC_UNABLE_TO_REFER
+#define SEC_E_KDC_UNABLE_TO_REFER             ((HRESULT)0x80090341L)
+#endif
+#ifndef SEC_E_KDC_UNKNOWN_ETYPE
+#define SEC_E_KDC_UNKNOWN_ETYPE               ((HRESULT)0x80090342L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_PREAUTH
+#define SEC_E_UNSUPPORTED_PREAUTH             ((HRESULT)0x80090343L)
+#endif
+#ifndef SEC_E_DELEGATION_REQUIRED
+#define SEC_E_DELEGATION_REQUIRED             ((HRESULT)0x80090345L)
+#endif
+#ifndef SEC_E_BAD_BINDINGS
+#define SEC_E_BAD_BINDINGS                    ((HRESULT)0x80090346L)
+#endif
+#ifndef SEC_E_MULTIPLE_ACCOUNTS
+#define SEC_E_MULTIPLE_ACCOUNTS               ((HRESULT)0x80090347L)
+#endif
+#ifndef SEC_E_NO_KERB_KEY
+#define SEC_E_NO_KERB_KEY                     ((HRESULT)0x80090348L)
+#endif
+#ifndef SEC_E_CERT_WRONG_USAGE
+#define SEC_E_CERT_WRONG_USAGE                ((HRESULT)0x80090349L)
+#endif
+#ifndef SEC_E_DOWNGRADE_DETECTED
+#define SEC_E_DOWNGRADE_DETECTED              ((HRESULT)0x80090350L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_REVOKED
+#define SEC_E_SMARTCARD_CERT_REVOKED          ((HRESULT)0x80090351L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED
+#define SEC_E_ISSUING_CA_UNTRUSTED            ((HRESULT)0x80090352L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_C
+#define SEC_E_REVOCATION_OFFLINE_C            ((HRESULT)0x80090353L)
+#endif
+#ifndef SEC_E_PKINIT_CLIENT_FAILURE
+#define SEC_E_PKINIT_CLIENT_FAILURE           ((HRESULT)0x80090354L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_EXPIRED
+#define SEC_E_SMARTCARD_CERT_EXPIRED          ((HRESULT)0x80090355L)
+#endif
+#ifndef SEC_E_NO_S4U_PROT_SUPPORT
+#define SEC_E_NO_S4U_PROT_SUPPORT             ((HRESULT)0x80090356L)
+#endif
+#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE
+#define SEC_E_CROSSREALM_DELEGATION_FAILURE   ((HRESULT)0x80090357L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_KDC
+#define SEC_E_REVOCATION_OFFLINE_KDC          ((HRESULT)0x80090358L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC
+#define SEC_E_ISSUING_CA_UNTRUSTED_KDC        ((HRESULT)0x80090359L)
+#endif
+#ifndef SEC_E_KDC_CERT_EXPIRED
+#define SEC_E_KDC_CERT_EXPIRED                ((HRESULT)0x8009035AL)
+#endif
+#ifndef SEC_E_KDC_CERT_REVOKED
+#define SEC_E_KDC_CERT_REVOKED                ((HRESULT)0x8009035BL)
+#endif
+#endif /* __MINGW32CE__ */
 #ifndef SEC_E_INVALID_PARAMETER
 # define SEC_E_INVALID_PARAMETER              ((HRESULT)0x8009035DL)
 #endif
@@ -80,6 +299,32 @@ extern PSecurityFunctionTable Curl_pSecFn;
 # define SEC_E_POLICY_NLTM_ONLY               ((HRESULT)0x8009035FL)
 #endif
 
+#ifdef __MINGW32CE__
+#ifndef SEC_I_CONTINUE_NEEDED
+#define SEC_I_CONTINUE_NEEDED                 ((HRESULT)0x00090312L)
+#endif
+#ifndef SEC_I_COMPLETE_NEEDED
+#define SEC_I_COMPLETE_NEEDED                 ((HRESULT)0x00090313L)
+#endif
+#ifndef SEC_I_COMPLETE_AND_CONTINUE
+#define SEC_I_COMPLETE_AND_CONTINUE           ((HRESULT)0x00090314L)
+#endif
+#ifndef SEC_I_LOCAL_LOGON
+#define SEC_I_LOCAL_LOGON                     ((HRESULT)0x00090315L)
+#endif
+#ifndef SEC_I_CONTEXT_EXPIRED
+#define SEC_I_CONTEXT_EXPIRED                 ((HRESULT)0x00090317L)
+#endif
+#ifndef SEC_I_INCOMPLETE_CREDENTIALS
+#define SEC_I_INCOMPLETE_CREDENTIALS          ((HRESULT)0x00090320L)
+#endif
+#ifndef SEC_I_RENEGOTIATE
+#define SEC_I_RENEGOTIATE                     ((HRESULT)0x00090321L)
+#endif
+#ifndef SEC_I_NO_LSA_CONTEXT
+#define SEC_I_NO_LSA_CONTEXT                  ((HRESULT)0x00090323L)
+#endif
+#endif /* __MINGW32CE__ */
 #ifndef SEC_I_SIGNATURE_NEEDED
 #define SEC_I_SIGNATURE_NEEDED                ((HRESULT)0x0009035CL)
 #endif

+ 20 - 19
Utilities/cmcurl/lib/curl_threads.c

@@ -35,9 +35,7 @@
 #endif
 
 #include "curl_threads.h"
-#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
-#endif
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -82,11 +80,12 @@ err:
   return curl_thread_t_null;
 }
 
-void Curl_thread_destroy(curl_thread_t hnd)
+void Curl_thread_destroy(curl_thread_t *hnd)
 {
-  if(hnd != curl_thread_t_null) {
-    pthread_detach(*hnd);
-    free(hnd);
+  if(*hnd != curl_thread_t_null) {
+    pthread_detach(**hnd);
+    free(*hnd);
+    *hnd = curl_thread_t_null;
   }
 }
 
@@ -103,7 +102,7 @@ int Curl_thread_join(curl_thread_t *hnd)
 #elif defined(USE_THREADS_WIN32)
 
 curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
                                  DWORD
 #else
                                  unsigned int
@@ -111,35 +110,39 @@ curl_thread_t Curl_thread_create(
                                  (CURL_STDCALL *func) (void *),
                                  void *arg)
 {
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
   typedef HANDLE curl_win_thread_handle_t;
 #else
   typedef uintptr_t curl_win_thread_handle_t;
 #endif
   curl_thread_t t;
   curl_win_thread_handle_t thread_handle;
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
   thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
   thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
 #endif
   t = (curl_thread_t)thread_handle;
   if((t == 0) || (t == LongToHandle(-1L))) {
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
     DWORD gle = GetLastError();
-    errno = ((gle == ERROR_ACCESS_DENIED ||
-              gle == ERROR_NOT_ENOUGH_MEMORY) ?
-             EACCES : EINVAL);
+    /* !checksrc! disable ERRNOVAR 1 */
+    int err = (gle == ERROR_ACCESS_DENIED ||
+               gle == ERROR_NOT_ENOUGH_MEMORY) ?
+               EACCES : EINVAL;
+    CURL_SETERRNO(err);
 #endif
     return curl_thread_t_null;
   }
   return t;
 }
 
-void Curl_thread_destroy(curl_thread_t hnd)
+void Curl_thread_destroy(curl_thread_t *hnd)
 {
-  if(hnd != curl_thread_t_null)
-    CloseHandle(hnd);
+  if(*hnd != curl_thread_t_null) {
+    CloseHandle(*hnd);
+    *hnd = curl_thread_t_null;
+  }
 }
 
 int Curl_thread_join(curl_thread_t *hnd)
@@ -151,9 +154,7 @@ int Curl_thread_join(curl_thread_t *hnd)
   int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
 #endif
 
-  Curl_thread_destroy(*hnd);
-
-  *hnd = curl_thread_t_null;
+  Curl_thread_destroy(hnd);
 
   return ret;
 }

+ 2 - 2
Utilities/cmcurl/lib/curl_threads.h

@@ -53,7 +53,7 @@
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 
 curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
                                  DWORD
 #else
                                  unsigned int
@@ -61,7 +61,7 @@ curl_thread_t Curl_thread_create(
                                  (CURL_STDCALL *func) (void *),
                                  void *arg);
 
-void Curl_thread_destroy(curl_thread_t hnd);
+void Curl_thread_destroy(curl_thread_t *hnd);
 
 int Curl_thread_join(curl_thread_t *hnd);
 

+ 236 - 82
Utilities/cmcurl/lib/curl_trc.c

@@ -30,7 +30,6 @@
 #include "urldata.h"
 #include "easyif.h"
 #include "cfilters.h"
-#include "timeval.h"
 #include "multiif.h"
 #include "strcase.h"
 
@@ -44,7 +43,7 @@
 #include "cf-haproxy.h"
 #include "cf-https-connect.h"
 #include "socks.h"
-#include "strtok.h"
+#include "curlx/strparse.h"
 #include "vtls/vtls.h"
 #include "vquic/vquic.h"
 
@@ -53,19 +52,20 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-void Curl_debug(struct Curl_easy *data, curl_infotype type,
-                char *ptr, size_t size)
+static void trc_write(struct Curl_easy *data, curl_infotype type,
+                      const char *ptr, size_t size)
 {
   if(data->set.verbose) {
-    static const char s_infotype[CURLINFO_END][3] = {
-      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
     if(data->set.fdebug) {
       bool inCallback = Curl_is_in_callback(data);
       Curl_set_in_callback(data, TRUE);
-      (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
+      (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
+                                data->set.debugdata);
       Curl_set_in_callback(data, inCallback);
     }
     else {
+      static const char s_infotype[CURLINFO_END][3] = {
+        "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
       switch(type) {
       case CURLINFO_TEXT:
       case CURLINFO_HEADER_OUT:
@@ -80,6 +80,101 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
   }
 }
 
+/* max length we trace before ending in '...' */
+#define TRC_LINE_MAX 2048
+
+#define CURL_TRC_FMT_IDSC   "[x-%" CURL_FORMAT_CURL_OFF_T "] "
+#define CURL_TRC_FMT_IDSD   "[%" CURL_FORMAT_CURL_OFF_T "-x] "
+#define CURL_TRC_FMT_IDSDC  "[%" CURL_FORMAT_CURL_OFF_T "-%" \
+                            CURL_FORMAT_CURL_OFF_T "] "
+
+static struct curl_trc_feat Curl_trc_feat_ids = {
+  "LIB-IDS",
+  CURL_LOG_LVL_NONE,
+};
+#define CURL_TRC_IDS(data) \
+             (Curl_trc_is_verbose(data) && \
+             Curl_trc_feat_ids.log_level >= CURL_LOG_LVL_INFO)
+
+static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
+{
+  curl_off_t cid = data->conn ?
+                   data->conn->connection_id : data->state.recent_conn_id;
+  if(data->id >= 0) {
+    if(cid >= 0)
+      return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
+    else
+      return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
+  }
+  else if(cid >= 0)
+    return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
+  else {
+    return msnprintf(buf, maxlen, "[x-x] ");
+  }
+}
+
+static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
+{
+  /* make sure we end the trace line in `buf` properly. It needs
+   * to end with a terminating '\0' or '\n\0' */
+  if(len >= (maxlen - (addnl ? 2 : 1))) {
+    len = maxlen - 5;
+    buf[len++] = '.';
+    buf[len++] = '.';
+    buf[len++] = '.';
+    buf[len++] = '\n';
+  }
+  else if(addnl)
+    buf[len++] = '\n';
+  buf[len] = '\0';
+  return len;
+}
+
+void Curl_debug(struct Curl_easy *data, curl_infotype type,
+                const char *ptr, size_t size)
+{
+  if(data->set.verbose) {
+    static const char s_infotype[CURLINFO_END][3] = {
+      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+    char buf[TRC_LINE_MAX];
+    size_t len;
+    if(data->set.fdebug) {
+      bool inCallback = Curl_is_in_callback(data);
+
+      if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
+        len = trc_print_ids(data, buf, TRC_LINE_MAX);
+        len += msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
+                         (int)size, ptr);
+        len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
+        Curl_set_in_callback(data, TRUE);
+        (void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
+        Curl_set_in_callback(data, inCallback);
+      }
+      else {
+        Curl_set_in_callback(data, TRUE);
+        (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
+                                  size, data->set.debugdata);
+        Curl_set_in_callback(data, inCallback);
+      }
+    }
+    else {
+      switch(type) {
+      case CURLINFO_TEXT:
+      case CURLINFO_HEADER_OUT:
+      case CURLINFO_HEADER_IN:
+        if(CURL_TRC_IDS(data)) {
+          len = trc_print_ids(data, buf, TRC_LINE_MAX);
+          fwrite(buf, len, 1, data->set.err);
+        }
+        fwrite(s_infotype[type], 2, 1, data->set.err);
+        fwrite(ptr, size, 1, data->set.err);
+        break;
+      default: /* nada */
+        break;
+      }
+    }
+  }
+}
 
 /* Curl_failf() is for messages stating why we failed.
  * The message SHALL NOT include any LF or CR.
@@ -89,7 +184,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
   DEBUGASSERT(!strchr(fmt, '\n'));
   if(data->set.verbose || data->set.errorbuffer) {
     va_list ap;
-    int len;
+    size_t len;
     char error[CURL_ERROR_SIZE + 2];
     va_start(ap, fmt);
     len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
@@ -100,36 +195,41 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
     }
     error[len++] = '\n';
     error[len] = '\0';
-    Curl_debug(data, CURLINFO_TEXT, error, len);
+    trc_write(data, CURLINFO_TEXT, error, len);
     va_end(ap);
   }
 }
 
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
 
-/* Curl_infof() is for info message along the way */
-#define MAXINFO 2048
 
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
-                      const char * const fmt, va_list ap)  CURL_PRINTF(3, 0);
+static void trc_infof(struct Curl_easy *data,
+                      struct curl_trc_feat *feat,
+                      const char *opt_id, int opt_id_idx,
+                      const char * const fmt, va_list ap)  CURL_PRINTF(5, 0);
 
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
+static void trc_infof(struct Curl_easy *data,
+                      struct curl_trc_feat *feat,
+                      const char *opt_id, int opt_id_idx,
                       const char * const fmt, va_list ap)
 {
-  int len = 0;
-  char buffer[MAXINFO + 5];
+  size_t len = 0;
+  char buf[TRC_LINE_MAX];
+
+  if(CURL_TRC_IDS(data))
+    len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
   if(feat)
-    len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
-  len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
-  if(len >= MAXINFO) { /* too long, shorten with '...' */
-    --len;
-    buffer[len++] = '.';
-    buffer[len++] = '.';
-    buffer[len++] = '.';
+    len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
+  if(opt_id) {
+    if(opt_id_idx > 0)
+      len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
+                       opt_id, opt_id_idx);
+    else
+      len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
   }
-  buffer[len++] = '\n';
-  buffer[len] = '\0';
-  Curl_debug(data, CURLINFO_TEXT, buffer, len);
+  len += mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap);
+  len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE);
+  trc_write(data, CURLINFO_TEXT, buf, len);
 }
 
 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
@@ -138,36 +238,27 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_is_verbose(data)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, data->state.feat, fmt, ap);
+    trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
 
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
                        const char *fmt, ...)
 {
   DEBUGASSERT(cf);
   if(Curl_trc_cf_is_verbose(cf, data)) {
     va_list ap;
-    int len = 0;
-    char buffer[MAXINFO + 2];
-    if(data->state.feat)
-      len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
-                       data->state.feat->name);
-    if(cf->sockindex)
-      len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
-                      cf->cft->name, cf->sockindex);
-    else
-      len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
     va_start(ap, fmt);
-    len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+    trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
     va_end(ap);
-    buffer[len++] = '\n';
-    buffer[len] = '\0';
-    Curl_debug(data, CURLINFO_TEXT, buffer, len);
   }
 }
 
+struct curl_trc_feat Curl_trc_feat_multi = {
+  "MULTI",
+  CURL_LOG_LVL_NONE,
+};
 struct curl_trc_feat Curl_trc_feat_read = {
   "READ",
   CURL_LOG_LVL_NONE,
@@ -176,6 +267,52 @@ struct curl_trc_feat Curl_trc_feat_write = {
   "WRITE",
   CURL_LOG_LVL_NONE,
 };
+struct curl_trc_feat Curl_trc_feat_dns = {
+  "DNS",
+  CURL_LOG_LVL_NONE,
+};
+
+
+static const char * const Curl_trc_mstate_names[]={
+  "INIT",
+  "PENDING",
+  "SETUP",
+  "CONNECT",
+  "RESOLVING",
+  "CONNECTING",
+  "TUNNELING",
+  "PROTOCONNECT",
+  "PROTOCONNECTING",
+  "DO",
+  "DOING",
+  "DOING_MORE",
+  "DID",
+  "PERFORMING",
+  "RATELIMITING",
+  "DONE",
+  "COMPLETED",
+  "MSGSENT",
+};
+
+const char *Curl_trc_mstate_name(int state)
+{
+  if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
+    return Curl_trc_mstate_names[(size_t)state];
+  return "?";
+}
+
+void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
+    const char *sname = (data->id >= 0) ?
+                        Curl_trc_mstate_name(data->mstate) : NULL;
+    va_list ap;
+    va_start(ap, fmt);
+    trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
+    va_end(ap);
+  }
+}
 
 void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
 {
@@ -183,7 +320,7 @@ void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_read, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -194,7 +331,18 @@ void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_write, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
+    va_end(ap);
+  }
+}
+
+void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
+    va_list ap;
+    va_start(ap, fmt);
+    trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -211,7 +359,7 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -229,7 +377,7 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -247,7 +395,7 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -265,7 +413,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
   if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
     va_list ap;
     va_start(ap, fmt);
-    trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
+    trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
     va_end(ap);
   }
 }
@@ -275,6 +423,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
 #define TRC_CT_PROTOCOL    (1<<(0))
 #define TRC_CT_NETWORK     (1<<(1))
 #define TRC_CT_PROXY       (1<<(2))
+#define TRC_CT_INTERNALS   (1<<(3))
 
 struct trc_feat_def {
   struct curl_trc_feat *feat;
@@ -282,13 +431,15 @@ struct trc_feat_def {
 };
 
 static struct trc_feat_def trc_feats[] = {
+  { &Curl_trc_feat_ids,       TRC_CT_INTERNALS },
+  { &Curl_trc_feat_multi,     TRC_CT_NETWORK },
   { &Curl_trc_feat_read,      TRC_CT_NONE },
   { &Curl_trc_feat_write,     TRC_CT_NONE },
+  { &Curl_trc_feat_dns,       TRC_CT_NETWORK },
 #ifndef CURL_DISABLE_FTP
   { &Curl_trc_feat_ftp,       TRC_CT_PROTOCOL },
 #endif
 #ifndef CURL_DISABLE_DOH
-  { &Curl_doh_trc,            TRC_CT_NETWORK },
 #endif
 #ifndef CURL_DISABLE_SMTP
   { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
@@ -341,18 +492,18 @@ static struct trc_cft_def trc_cfts[] = {
 #endif
 };
 
-static void trc_apply_level_by_name(const char * const token, int lvl)
+static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
 {
   size_t i;
 
   for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
-    if(strcasecompare(token, trc_cfts[i].cft->name)) {
+    if(curlx_str_casecompare(token, trc_cfts[i].cft->name)) {
       trc_cfts[i].cft->log_level = lvl;
       break;
     }
   }
   for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
-    if(strcasecompare(token, trc_feats[i].feat->name)) {
+    if(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
       trc_feats[i].feat->log_level = lvl;
       break;
     }
@@ -375,42 +526,36 @@ static void trc_apply_level_by_category(int category, int lvl)
 
 static CURLcode trc_opt(const char *config)
 {
-  char *token, *tok_buf, *tmp;
-  int lvl;
-
-  tmp = strdup(config);
-  if(!tmp)
-    return CURLE_OUT_OF_MEMORY;
-
-  token = Curl_strtok_r(tmp, ", ", &tok_buf);
-  while(token) {
-    switch(*token) {
-      case '-':
-        lvl = CURL_LOG_LVL_NONE;
-        ++token;
-        break;
-      case '+':
-        lvl = CURL_LOG_LVL_INFO;
-        ++token;
-        break;
-      default:
-        lvl = CURL_LOG_LVL_INFO;
-        break;
+  struct Curl_str out;
+  while(!curlx_str_until(&config, &out, 32, ',')) {
+    int lvl = CURL_LOG_LVL_INFO;
+    const char *token = curlx_str(&out);
+
+    if(*token == '-') {
+      lvl = CURL_LOG_LVL_NONE;
+      curlx_str_nudge(&out, 1);
     }
-    if(strcasecompare(token, "all"))
+    else if(*token == '+')
+      curlx_str_nudge(&out, 1);
+
+    if(curlx_str_casecompare(&out, "all"))
       trc_apply_level_by_category(TRC_CT_NONE, lvl);
-    else if(strcasecompare(token, "protocol"))
+    else if(curlx_str_casecompare(&out, "protocol"))
       trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
-    else if(strcasecompare(token, "network"))
+    else if(curlx_str_casecompare(&out, "network"))
       trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
-    else if(strcasecompare(token, "proxy"))
+    else if(curlx_str_casecompare(&out, "proxy"))
       trc_apply_level_by_category(TRC_CT_PROXY, lvl);
+    else if(curlx_str_casecompare(&out, "doh")) {
+      struct Curl_str dns = { "dns", 3 };
+      trc_apply_level_by_name(&dns, lvl);
+    }
     else
-      trc_apply_level_by_name(token, lvl);
+      trc_apply_level_by_name(&out, lvl);
 
-    token = Curl_strtok_r(NULL, ", ", &tok_buf);
+    if(curlx_str_single(&config, ','))
+      break;
   }
-  free(tmp);
   return CURLE_OK;
 }
 
@@ -449,8 +594,7 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
   (void)data; (void)fmt;
 }
 
-void Curl_trc_cf_infof(struct Curl_easy *data,
-                       struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
                        const char *fmt, ...)
 {
   (void)data; (void)cf; (void)fmt;
@@ -458,11 +602,21 @@ void Curl_trc_cf_infof(struct Curl_easy *data,
 
 struct curl_trc_feat;
 
+void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
 void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
 {
   (void)data; (void)fmt;
 }
 
+void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
 void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
 {
   (void)data; (void)fmt;

+ 23 - 5
Utilities/cmcurl/lib/curl_trc.h

@@ -52,7 +52,7 @@ CURLcode Curl_trc_opt(const char *config);
 
 /* the function used to output verbose information */
 void Curl_debug(struct Curl_easy *data, curl_infotype type,
-                char *ptr, size_t size);
+                const char *ptr, size_t size);
 
 /**
  * Output a failure message on registered callbacks for transfer.
@@ -80,12 +80,17 @@ void Curl_infof(struct Curl_easy *data,
  * Output an informational message when both transfer's verbose logging
  * and connection filters verbose logging are enabled.
  */
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
                        const char *fmt, ...) CURL_PRINTF(3, 4);
+void Curl_trc_multi(struct Curl_easy *data,
+                    const char *fmt, ...) CURL_PRINTF(2, 3);
+const char *Curl_trc_mstate_name(int state);
 void Curl_trc_write(struct Curl_easy *data,
                     const char *fmt, ...) CURL_PRINTF(2, 3);
 void Curl_trc_read(struct Curl_easy *data,
                    const char *fmt, ...) CURL_PRINTF(2, 3);
+void Curl_trc_dns(struct Curl_easy *data,
+                  const char *fmt, ...) CURL_PRINTF(2, 3);
 
 #ifndef CURL_DISABLE_FTP
 extern struct curl_trc_feat Curl_trc_feat_ftp;
@@ -112,6 +117,9 @@ void Curl_trc_ws(struct Curl_easy *data,
 #define infof(data, ...) \
   do { if(Curl_trc_is_verbose(data)) \
          Curl_infof(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_M(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) \
+         Curl_trc_multi(data, __VA_ARGS__); } while(0)
 #define CURL_TRC_CF(data, cf, ...) \
   do { if(Curl_trc_cf_is_verbose(cf, data)) \
          Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
@@ -121,6 +129,9 @@ void Curl_trc_ws(struct Curl_easy *data,
 #define CURL_TRC_READ(data, ...) \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
          Curl_trc_read(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_DNS(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) \
+         Curl_trc_dns(data, __VA_ARGS__); } while(0)
 
 #ifndef CURL_DISABLE_FTP
 #define CURL_TRC_FTP(data, ...) \
@@ -146,9 +157,11 @@ void Curl_trc_ws(struct Curl_easy *data,
 #else /* CURL_HAVE_C99 */
 
 #define infof Curl_infof
+#define CURL_TRC_M  Curl_trc_multi
 #define CURL_TRC_CF Curl_trc_cf_infof
 #define CURL_TRC_WRITE Curl_trc_write
 #define CURL_TRC_READ  Curl_trc_read
+#define CURL_TRC_DNS   Curl_trc_dns
 
 #ifndef CURL_DISABLE_FTP
 #define CURL_TRC_FTP   Curl_trc_ftp
@@ -165,15 +178,18 @@ void Curl_trc_ws(struct Curl_easy *data,
 
 #endif /* !CURL_HAVE_C99 */
 
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-/* informational messages enabled */
-
 struct curl_trc_feat {
   const char *name;
   int log_level;
 };
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/* informational messages enabled */
+
+extern struct curl_trc_feat Curl_trc_feat_multi;
 extern struct curl_trc_feat Curl_trc_feat_read;
 extern struct curl_trc_feat Curl_trc_feat_write;
+extern struct curl_trc_feat Curl_trc_feat_dns;
 
 #define Curl_trc_is_verbose(data) \
             ((data) && (data)->set.verbose && \
@@ -185,6 +201,7 @@ extern struct curl_trc_feat Curl_trc_feat_write;
 #define Curl_trc_ft_is_verbose(data, ft) \
             (Curl_trc_is_verbose(data) && \
              (ft)->log_level >= CURL_LOG_LVL_INFO)
+#define CURL_MSTATE_NAME(s)  Curl_trc_mstate_name((int)(s))
 
 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
 /* All informational messages are not compiled in for size savings */
@@ -192,6 +209,7 @@ extern struct curl_trc_feat Curl_trc_feat_write;
 #define Curl_trc_is_verbose(d)        (FALSE)
 #define Curl_trc_cf_is_verbose(x,y)   (FALSE)
 #define Curl_trc_ft_is_verbose(x,y)   (FALSE)
+#define CURL_MSTATE_NAME(x)           ((void)(x), "-")
 
 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
 

+ 32 - 40
Utilities/cmcurl/lib/base64.c → Utilities/cmcurl/lib/curlx/base64.c

@@ -24,7 +24,7 @@
 
 /* Base64 encoding/decoding */
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
   !defined(CURL_DISABLE_LDAP) || \
@@ -32,21 +32,20 @@
   !defined(CURL_DISABLE_POP3) || \
   !defined(CURL_DISABLE_IMAP) || \
   !defined(CURL_DISABLE_DIGEST_AUTH) || \
-  !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL)
-#include "curl/curl.h"
+  !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || !defined(BUILDING_LIBCURL)
+#include <curl/curl.h>
 #include "warnless.h"
-#include "curl_base64.h"
+#include "base64.h"
 
 /* The last 2 #include files should be in this order */
 #ifdef BUILDING_LIBCURL
-#include "curl_memory.h"
+#include "../curl_memory.h"
 #endif
-#include "memdebug.h"
+#include "../memdebug.h"
 
 /* ---- Base64 Encoding/Decoding Table --- */
-/* Padding character string starts at offset 64. */
-static const char base64encdec[]=
-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+const char Curl_base64encdec[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 /* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
    section 5 */
@@ -60,11 +59,11 @@ static const unsigned char decodetable[] =
   29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
   48, 49, 50, 51 };
 /*
- * Curl_base64_decode()
+ * curlx_base64_decode()
  *
- * Given a base64 NUL-terminated string at src, decode it and return a
- * pointer in *outptr to a newly allocated memory area holding decoded
- * data. Size of decoded data is returned in variable pointed by outlen.
+ * Given a base64 null-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded data.
+ * Size of decoded data is returned in variable pointed by outlen.
  *
  * Returns CURLE_OK on success, otherwise specific error code. Function
  * output shall not be considered valid unless CURLE_OK is returned.
@@ -73,8 +72,8 @@ static const unsigned char decodetable[] =
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64_decode(const char *src,
-                            unsigned char **outptr, size_t *outlen)
+CURLcode curlx_base64_decode(const char *src,
+                             unsigned char **outptr, size_t *outlen)
 {
   size_t srclen = 0;
   size_t padding = 0;
@@ -119,14 +118,6 @@ CURLcode Curl_base64_decode(const char *src,
 
   memset(lookup, 0xff, sizeof(lookup));
   memcpy(&lookup['+'], decodetable, sizeof(decodetable));
-  /* replaces
-  {
-    unsigned char c;
-    const unsigned char *p = (const unsigned char *)base64encdec;
-    for(c = 0; *p; c++, p++)
-      lookup[*p] = c;
-  }
-  */
 
   /* Decode the complete quantums first */
   for(i = 0; i < fullQuantums; i++) {
@@ -186,13 +177,13 @@ bad:
 }
 
 static CURLcode base64_encode(const char *table64,
+                              unsigned char padbyte,
                               const char *inputbuff, size_t insize,
                               char **outptr, size_t *outlen)
 {
   char *output;
   char *base64data;
-  const unsigned char *in = (unsigned char *)inputbuff;
-  const char *padstr = &table64[64];    /* Point to padding string. */
+  const unsigned char *in = (const unsigned char *)inputbuff;
 
   *outptr = NULL;
   *outlen = 0;
@@ -222,17 +213,17 @@ static CURLcode base64_encode(const char *table64,
     *output++ = table64[ in[0] >> 2 ];
     if(insize == 1) {
       *output++ = table64[ ((in[0] & 0x03) << 4) ];
-      if(*padstr) {
-        *output++ = *padstr;
-        *output++ = *padstr;
+      if(padbyte) {
+        *output++ = padbyte;
+        *output++ = padbyte;
       }
     }
     else {
       /* insize == 2 */
       *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ];
       *output++ = table64[ ((in[1] & 0x0F) << 2) ];
-      if(*padstr)
-        *output++ = *padstr;
+      if(padbyte)
+        *output++ = padbyte;
     }
   }
 
@@ -249,45 +240,46 @@ static CURLcode base64_encode(const char *table64,
 }
 
 /*
- * Curl_base64_encode()
+ * curlx_base64_encode()
  *
  * Given a pointer to an input buffer and an input size, encode it and
  * return a pointer in *outptr to a newly allocated memory area holding
  * encoded data. Size of encoded data is returned in variable pointed by
  * outlen.
  *
- * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ * Input length of 0 indicates input buffer holds a null-terminated string.
  *
  * Returns CURLE_OK on success, otherwise specific error code. Function
  * output shall not be considered valid unless CURLE_OK is returned.
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
-                            char **outptr, size_t *outlen)
+CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
+                             char **outptr, size_t *outlen)
 {
-  return base64_encode(base64encdec, inputbuff, insize, outptr, outlen);
+  return base64_encode(Curl_base64encdec, '=',
+                       inputbuff, insize, outptr, outlen);
 }
 
 /*
- * Curl_base64url_encode()
+ * curlx_base64url_encode()
  *
  * Given a pointer to an input buffer and an input size, encode it and
  * return a pointer in *outptr to a newly allocated memory area holding
  * encoded data. Size of encoded data is returned in variable pointed by
  * outlen.
  *
- * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ * Input length of 0 indicates input buffer holds a null-terminated string.
  *
  * Returns CURLE_OK on success, otherwise specific error code. Function
  * output shall not be considered valid unless CURLE_OK is returned.
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
-                               char **outptr, size_t *outlen)
+CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize,
+                                char **outptr, size_t *outlen)
 {
-  return base64_encode(base64url, inputbuff, insize, outptr, outlen);
+  return base64_encode(base64url, 0, inputbuff, insize, outptr, outlen);
 }
 
 #endif /* no users so disabled */

+ 8 - 13
Utilities/cmcurl/lib/curl_base64.h → Utilities/cmcurl/lib/curlx/base64.h

@@ -24,18 +24,13 @@
  *
  ***************************************************************************/
 
-#ifndef BUILDING_LIBCURL
-/* this renames functions so that the tool code can use the same code
-   without getting symbol collisions */
-#define Curl_base64_encode(a,b,c,d) curlx_base64_encode(a,b,c,d)
-#define Curl_base64url_encode(a,b,c,d) curlx_base64url_encode(a,b,c,d)
-#define Curl_base64_decode(a,b,c) curlx_base64_decode(a,b,c)
-#endif
+CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
+                             char **outptr, size_t *outlen);
+CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize,
+                                char **outptr, size_t *outlen);
+CURLcode curlx_base64_decode(const char *src,
+                             unsigned char **outptr, size_t *outlen);
+
+extern const char Curl_base64encdec[];
 
-CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
-                            char **outptr, size_t *outlen);
-CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
-                               char **outptr, size_t *outlen);
-CURLcode Curl_base64_decode(const char *src,
-                            unsigned char **outptr, size_t *outlen);
 #endif /* HEADER_CURL_BASE64_H */

+ 19 - 14
Utilities/cmcurl/lib/curlx.h → Utilities/cmcurl/lib/curlx/curlx.h

@@ -31,17 +31,6 @@
  * be.
  */
 
-/* map standard printf functions to curl implementations */
-#include "curl_printf.h"
-
-#include "strcase.h"
-/* "strcase.h" provides the strcasecompare protos */
-
-#include "strtoofft.h"
-/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
-   curl_off_t number from a given string.
-*/
-
 #include "nonblock.h"
 /* "nonblock.h" provides curlx_nonblock() */
 
@@ -53,8 +42,8 @@
   curlx_uztosi()
 */
 
-#include "curl_multibyte.h"
-/* "curl_multibyte.h" provides these functions and macros:
+#include "multibyte.h"
+/* "multibyte.h" provides these functions and macros:
 
   curlx_convert_UTF8_to_wchar()
   curlx_convert_wchar_to_UTF8()
@@ -64,6 +53,22 @@
 */
 
 #include "version_win32.h"
-/* "version_win32.h" provides curlx_verify_windows_version() */
+/* provides curlx_verify_windows_version() */
+
+#include "strparse.h"
+/* The curlx_str_* parsing functions */
+
+#include "dynbuf.h"
+/* The curlx_dyn_* functions */
+
+#include "base64.h"
+#include "timeval.h"
+#include "timediff.h"
+
+#include "winapi.h"
+/* for curlx_winapi_strerror */
+
+#include "inet_pton.h"
+/* for curlx_inet_pton */
 
 #endif /* HEADER_CURL_CURLX_H */

+ 30 - 26
Utilities/cmcurl/lib/dynbuf.c → Utilities/cmcurl/lib/curlx/dynbuf.c

@@ -22,25 +22,28 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 #include "dynbuf.h"
-#include "curl_printf.h"
+#include "../curl_printf.h"
 #ifdef BUILDING_LIBCURL
-#include "curl_memory.h"
+#include "../curl_memory.h"
 #endif
-#include "memdebug.h"
+#include "../memdebug.h"
 
 #define MIN_FIRST_ALLOC 32
 
+#ifdef DEBUGBUILD
 #define DYNINIT 0xbee51da /* random pattern */
+#endif
 
 /*
  * Init a dynbuf struct.
  */
-void Curl_dyn_init(struct dynbuf *s, size_t toobig)
+void curlx_dyn_init(struct dynbuf *s, size_t toobig)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(toobig);
+  DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
   s->bufr = NULL;
   s->leng = 0;
   s->allc = 0;
@@ -54,9 +57,10 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig)
  * free the buffer and re-init the necessary fields. It does not touch the
  * 'init' field and thus this buffer can be reused to add data to again.
  */
-void Curl_dyn_free(struct dynbuf *s)
+void curlx_dyn_free(struct dynbuf *s)
 {
   DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
   Curl_safefree(s->bufr);
   s->leng = s->allc = 0;
 }
@@ -80,7 +84,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
   DEBUGASSERT(!len || mem);
 
   if(fit > s->toobig) {
-    Curl_dyn_free(s);
+    curlx_dyn_free(s);
     return CURLE_TOO_LARGE;
   }
   else if(!a) {
@@ -106,7 +110,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
        include that as well when it uses this code */
     void *p = realloc(s->bufr, a);
     if(!p) {
-      Curl_dyn_free(s);
+      curlx_dyn_free(s);
       return CURLE_OUT_OF_MEMORY;
     }
     s->bufr = p;
@@ -124,7 +128,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
  * Clears the string, keeps the allocation. This can also be called on a
  * buffer that already was freed.
  */
-void Curl_dyn_reset(struct dynbuf *s)
+void curlx_dyn_reset(struct dynbuf *s)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -138,7 +142,7 @@ void Curl_dyn_reset(struct dynbuf *s)
  * Specify the size of the tail to keep (number of bytes from the end of the
  * buffer). The rest will be dropped.
  */
-CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
+CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -148,7 +152,7 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
   else if(trail == s->leng)
     return CURLE_OK;
   else if(!trail) {
-    Curl_dyn_reset(s);
+    curlx_dyn_reset(s);
   }
   else {
     memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
@@ -162,7 +166,7 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
 /*
  * Appends a buffer with length.
  */
-CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -173,7 +177,7 @@ CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
 /*
  * Append a null-terminated string at the end.
  */
-CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
 {
   size_t n;
   DEBUGASSERT(str);
@@ -181,13 +185,13 @@ CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
   DEBUGASSERT(s->init == DYNINIT);
   DEBUGASSERT(!s->leng || s->bufr);
   n = strlen(str);
-  return dyn_nappend(s, (unsigned char *)str, n);
+  return dyn_nappend(s, (const unsigned char *)str, n);
 }
 
 /*
  * Append a string vprintf()-style
  */
-CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
 {
 #ifdef BUILDING_LIBCURL
   int rc;
@@ -195,7 +199,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
   DEBUGASSERT(s->init == DYNINIT);
   DEBUGASSERT(!s->leng || s->bufr);
   DEBUGASSERT(fmt);
-  rc = Curl_dyn_vprintf(s, fmt, ap);
+  rc = curlx_dyn_vprintf(s, fmt, ap);
 
   if(!rc)
     return CURLE_OK;
@@ -204,15 +208,15 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
   return CURLE_OUT_OF_MEMORY;
 #else
   char *str;
-  str = vaprintf(fmt, ap); /* this allocs a new string to append */
+  str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
 
   if(str) {
-    CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
+    CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
     free(str);
     return result;
   }
   /* If we failed, we cleanup the whole buffer and return error */
-  Curl_dyn_free(s);
+  curlx_dyn_free(s);
   return CURLE_OUT_OF_MEMORY;
 #endif
 }
@@ -220,7 +224,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
 /*
  * Append a string printf()-style
  */
-CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
 {
   CURLcode result;
   va_list ap;
@@ -228,7 +232,7 @@ CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
   DEBUGASSERT(s->init == DYNINIT);
   DEBUGASSERT(!s->leng || s->bufr);
   va_start(ap, fmt);
-  result = Curl_dyn_vaddf(s, fmt, ap);
+  result = curlx_dyn_vaddf(s, fmt, ap);
   va_end(ap);
   return result;
 }
@@ -236,7 +240,7 @@ CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
 /*
  * Returns a pointer to the buffer.
  */
-char *Curl_dyn_ptr(const struct dynbuf *s)
+char *curlx_dyn_ptr(const struct dynbuf *s)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -244,7 +248,7 @@ char *Curl_dyn_ptr(const struct dynbuf *s)
   return s->bufr;
 }
 
-char *Curl_dyn_take(struct dynbuf *s, size_t *plen)
+char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
 {
   char *ptr = s->bufr;
   DEBUGASSERT(s);
@@ -259,7 +263,7 @@ char *Curl_dyn_take(struct dynbuf *s, size_t *plen)
 /*
  * Returns an unsigned pointer to the buffer.
  */
-unsigned char *Curl_dyn_uptr(const struct dynbuf *s)
+unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -270,7 +274,7 @@ unsigned char *Curl_dyn_uptr(const struct dynbuf *s)
 /*
  * Returns the length of the buffer.
  */
-size_t Curl_dyn_len(const struct dynbuf *s)
+size_t curlx_dyn_len(const struct dynbuf *s)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);
@@ -281,7 +285,7 @@ size_t Curl_dyn_len(const struct dynbuf *s)
 /*
  * Set a new (smaller) length.
  */
-CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set)
+CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
 {
   DEBUGASSERT(s);
   DEBUGASSERT(s->init == DYNINIT);

+ 20 - 33
Utilities/cmcurl/lib/dynbuf.h → Utilities/cmcurl/lib/curlx/dynbuf.h

@@ -26,25 +26,6 @@
 
 #include <curl/curl.h>
 
-#ifndef BUILDING_LIBCURL
-/* this renames the functions so that the tool code can use the same code
-   without getting symbol collisions */
-#define Curl_dyn_init(a,b) curlx_dyn_init(a,b)
-#define Curl_dyn_add(a,b) curlx_dyn_add(a,b)
-#define Curl_dyn_addn(a,b,c) curlx_dyn_addn(a,b,c)
-#define Curl_dyn_addf curlx_dyn_addf
-#define Curl_dyn_vaddf curlx_dyn_vaddf
-#define Curl_dyn_free(a) curlx_dyn_free(a)
-#define Curl_dyn_ptr(a) curlx_dyn_ptr(a)
-#define Curl_dyn_uptr(a) curlx_dyn_uptr(a)
-#define Curl_dyn_len(a) curlx_dyn_len(a)
-#define Curl_dyn_reset(a) curlx_dyn_reset(a)
-#define Curl_dyn_take(a,b) curlx_dyn_take(a,b)
-#define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b)
-#define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b)
-#define curlx_dynbuf dynbuf /* for the struct name */
-#endif
-
 struct dynbuf {
   char *bufr;    /* point to a null-terminated allocated buffer */
   size_t leng;   /* number of bytes *EXCLUDING* the null-terminator */
@@ -55,32 +36,34 @@ struct dynbuf {
 #endif
 };
 
-void Curl_dyn_init(struct dynbuf *s, size_t toobig);
-void Curl_dyn_free(struct dynbuf *s);
-CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+void curlx_dyn_init(struct dynbuf *s, size_t toobig);
+void curlx_dyn_free(struct dynbuf *s);
+CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
   WARN_UNUSED_RESULT;
-CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
   WARN_UNUSED_RESULT;
-CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
   WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
-CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
   WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
-void Curl_dyn_reset(struct dynbuf *s);
-CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
-CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set);
-char *Curl_dyn_ptr(const struct dynbuf *s);
-unsigned char *Curl_dyn_uptr(const struct dynbuf *s);
-size_t Curl_dyn_len(const struct dynbuf *s);
+void curlx_dyn_reset(struct dynbuf *s);
+CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail);
+CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set);
+char *curlx_dyn_ptr(const struct dynbuf *s);
+unsigned char *curlx_dyn_uptr(const struct dynbuf *s);
+size_t curlx_dyn_len(const struct dynbuf *s);
 
 /* returns 0 on success, -1 on error */
 /* The implementation of this function exists in mprintf.c */
-int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
+int curlx_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
 
 /* Take the buffer out of the dynbuf. Caller has ownership and
  * dynbuf resets to initial state. */
-char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
+char *curlx_dyn_take(struct dynbuf *s, size_t *plen);
 
 /* Dynamic buffer max sizes */
+#define MAX_DYNBUF_SIZE (SIZE_T_MAX/2)
+
 #define DYN_DOH_RESPONSE    3000
 #define DYN_DOH_CNAME       256
 #define DYN_PAUSE_BUFFER    (64 * 1024 * 1024)
@@ -95,4 +78,8 @@ char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
 #define DYN_PINGPPONG_CMD   (64*1024)
 #define DYN_IMAP_CMD        (64*1024)
 #define DYN_MQTT_RECV       (64*1024)
+#define DYN_MQTT_SEND       0xFFFFFFF
+#define DYN_CRLFILE_SIZE    (400*1024*1024) /* 400mb */
+#define DYN_CERTFILE_SIZE   (100*1024) /* 100KiB */
+#define DYN_KEYFILE_SIZE    (100*1024) /* 100KiB */
 #endif

+ 9 - 20
Utilities/cmcurl/lib/inet_pton.c → Utilities/cmcurl/lib/curlx/inet_pton.c

@@ -18,7 +18,9 @@
  * SPDX-License-Identifier: ISC
  */
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
+#include "../curl_ctype.h"
+#include "strparse.h"
 
 #ifndef HAVE_INET_PTON
 
@@ -72,7 +74,7 @@ static int      inet_pton6(const char *src, unsigned char *dst);
  *      Paul Vixie, 1996.
  */
 int
-Curl_inet_pton(int af, const char *src, void *dst)
+curlx_inet_pton(int af, const char *src, void *dst)
 {
   switch(af) {
   case AF_INET:
@@ -80,7 +82,7 @@ Curl_inet_pton(int af, const char *src, void *dst)
   case AF_INET6:
     return inet_pton6(src, (unsigned char *)dst);
   default:
-    errno = EAFNOSUPPORT;
+    CURL_SETERRNO(SOCKEAFNOSUPPORT);
     return -1;
   }
   /* NOTREACHED */
@@ -99,7 +101,6 @@ Curl_inet_pton(int af, const char *src, void *dst)
 static int
 inet_pton4(const char *src, unsigned char *dst)
 {
-  static const char digits[] = "0123456789";
   int saw_digit, octets, ch;
   unsigned char tmp[INADDRSZ], *tp;
 
@@ -108,12 +109,8 @@ inet_pton4(const char *src, unsigned char *dst)
   tp = tmp;
   *tp = 0;
   while((ch = *src++) != '\0') {
-    const char *pch;
-
-    pch = strchr(digits, ch);
-    if(pch) {
-      unsigned int val = (unsigned int)(*tp * 10) +
-                         (unsigned int)(pch - digits);
+    if(ISDIGIT(ch)) {
+      unsigned int val = (*tp * 10) + (ch - '0');
 
       if(saw_digit && *tp == 0)
         return 0;
@@ -157,8 +154,6 @@ inet_pton4(const char *src, unsigned char *dst)
 static int
 inet_pton6(const char *src, unsigned char *dst)
 {
-  static const char xdigits_l[] = "0123456789abcdef",
-    xdigits_u[] = "0123456789ABCDEF";
   unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
   const char *curtok;
   int ch, saw_xdigit;
@@ -175,15 +170,9 @@ inet_pton6(const char *src, unsigned char *dst)
   saw_xdigit = 0;
   val = 0;
   while((ch = *src++) != '\0') {
-    const char *xdigits;
-    const char *pch;
-
-    pch = strchr((xdigits = xdigits_l), ch);
-    if(!pch)
-      pch = strchr((xdigits = xdigits_u), ch);
-    if(pch) {
+    if(ISXDIGIT(ch)) {
       val <<= 4;
-      val |= (pch - xdigits);
+      val |= Curl_hexval(ch);
       if(++saw_xdigit > 4)
         return 0;
       continue;

+ 5 - 5
Utilities/cmcurl/lib/inet_pton.h → Utilities/cmcurl/lib/curlx/inet_pton.h

@@ -24,9 +24,9 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
-int Curl_inet_pton(int, const char *, void *);
+int curlx_inet_pton(int, const char *, void *);
 
 #ifdef HAVE_INET_PTON
 #ifdef HAVE_NETINET_IN_H
@@ -38,10 +38,10 @@ int Curl_inet_pton(int, const char *, void *);
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#if defined(__AMIGA__)
-#define Curl_inet_pton(x,y,z) inet_pton(x,(unsigned char *)y,z)
+#ifdef __AMIGA__
+#define curlx_inet_pton(x,y,z) inet_pton(x,(unsigned char *)CURL_UNCONST(y),z)
 #else
-#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#define curlx_inet_pton(x,y,z) inet_pton(x,y,z)
 #endif
 #endif
 

+ 34 - 27
Utilities/cmcurl/lib/curl_multibyte.c → Utilities/cmcurl/lib/curlx/multibyte.c

@@ -23,18 +23,18 @@
  ***************************************************************************/
 
 /*
- * This file is 'mem-include-scan' clean, which means memdebug.h and
- * curl_memory.h are purposely not included in this file. See test 1132.
- *
- * The functions in this file are curlx functions which are not tracked by the
- * curl memory tracker memdebug.
+ * This file is 'mem-include-scan' clean, which means its memory allocations
+ * are not tracked by the curl memory tracker memdebug, so they must not use
+ * `CURLDEBUG` macro replacements in memdebug.h for free, malloc, etc. To avoid
+ * these macro replacements, wrap the names in parentheses to call the original
+ * versions: `ptr = (malloc)(123)`, `(free)(ptr)`, etc.
  */
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #ifdef _WIN32
 
-#include "curl_multibyte.h"
+#include "multibyte.h"
 
 /*
  * MultiByte conversions using Windows kernel32 library.
@@ -48,11 +48,11 @@ wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8)
     int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
                                         str_utf8, -1, NULL, 0);
     if(str_w_len > 0) {
-      str_w = malloc(str_w_len * sizeof(wchar_t));
+      str_w = (malloc)(str_w_len * sizeof(wchar_t));
       if(str_w) {
         if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
                                str_w_len) == 0) {
-          free(str_w);
+          (free)(str_w);
           return NULL;
         }
       }
@@ -70,11 +70,11 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
     int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1,
                                     NULL, 0, NULL, NULL);
     if(bytes > 0) {
-      str_utf8 = malloc(bytes);
+      str_utf8 = (malloc)(bytes);
       if(str_utf8) {
         if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes,
                                NULL, NULL) == 0) {
-          free(str_utf8);
+          (free)(str_utf8);
           return NULL;
         }
       }
@@ -84,6 +84,8 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
   return str_utf8;
 }
 
+#ifndef UNDER_CE
+
 /* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
 #if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
   (_WIN32_WINNT < _WIN32_WINNT_WIN10)
@@ -134,7 +136,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
   if(needed == (size_t)-1 || needed >= max_path_len)
     goto cleanup;
   ++needed; /* for NUL */
-  ibuf = malloc(needed * sizeof(wchar_t));
+  ibuf = (malloc)(needed * sizeof(wchar_t));
   if(!ibuf)
     goto cleanup;
   count = mbstowcs(ibuf, in, needed);
@@ -154,7 +156,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
   /* skip paths that are not excessive and do not need modification */
   if(needed <= MAX_PATH)
     goto cleanup;
-  fbuf = malloc(needed * sizeof(wchar_t));
+  fbuf = (malloc)(needed * sizeof(wchar_t));
   if(!fbuf)
     goto cleanup;
   count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
@@ -187,7 +189,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
       if(needed > max_path_len)
         goto cleanup;
 
-      temp = malloc(needed * sizeof(wchar_t));
+      temp = (malloc)(needed * sizeof(wchar_t));
       if(!temp)
         goto cleanup;
 
@@ -200,7 +202,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
       if(needed > max_path_len)
         goto cleanup;
 
-      temp = malloc(needed * sizeof(wchar_t));
+      temp = (malloc)(needed * sizeof(wchar_t));
       if(!temp)
         goto cleanup;
 
@@ -208,7 +210,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
       wcscpy(temp + 4, fbuf);
     }
 
-    free(fbuf);
+    (free)(fbuf);
     fbuf = temp;
   }
 
@@ -218,7 +220,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
   if(needed == (size_t)-1 || needed >= max_path_len)
     goto cleanup;
   ++needed; /* for NUL */
-  obuf = malloc(needed);
+  obuf = (malloc)(needed);
   if(!obuf)
     goto cleanup;
   count = wcstombs(obuf, fbuf, needed);
@@ -232,10 +234,10 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
 #endif
 
 cleanup:
-  free(fbuf);
+  (free)(fbuf);
 #ifndef _UNICODE
-  free(ibuf);
-  free(obuf);
+  (free)(ibuf);
+  (free)(obuf);
 #endif
   return *out ? true : false;
 }
@@ -267,16 +269,17 @@ int curlx_win32_open(const char *filename, int oflag, ...)
     curlx_unicodefree(filename_w);
   }
   else
-    errno = EINVAL;
+    /* !checksrc! disable ERRNOVAR 1 */
+    CURL_SETERRNO(EINVAL);
 #else
   if(fix_excessive_path(filename, &fixed))
     target = fixed;
   else
     target = filename;
-  result = (_open)(target, oflag, pmode);
+  result = _open(target, oflag, pmode);
 #endif
 
-  free(fixed);
+  (free)(fixed);
   return result;
 }
 
@@ -297,7 +300,8 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
     result = _wfopen(target, mode_w);
   }
   else
-    errno = EINVAL;
+    /* !checksrc! disable ERRNOVAR 1 */
+    CURL_SETERRNO(EINVAL);
   curlx_unicodefree(filename_w);
   curlx_unicodefree(mode_w);
 #else
@@ -308,7 +312,7 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
   result = (fopen)(target, mode);
 #endif
 
-  free(fixed);
+  (free)(fixed);
   return result;
 }
 
@@ -333,7 +337,8 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
     curlx_unicodefree(path_w);
   }
   else
-    errno = EINVAL;
+    /* !checksrc! disable ERRNOVAR 1 */
+    CURL_SETERRNO(EINVAL);
 #else
   if(fix_excessive_path(path, &fixed))
     target = fixed;
@@ -346,8 +351,10 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
 #endif
 #endif
 
-  free(fixed);
+  (free)(fixed);
   return result;
 }
 
+#endif /* UNDER_CE */
+
 #endif /* _WIN32 */

+ 4 - 9
Utilities/cmcurl/lib/curl_multibyte.h → Utilities/cmcurl/lib/curlx/multibyte.h

@@ -23,9 +23,9 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
  /*
   * MultiByte conversions using Windows kernel32 library.
@@ -81,12 +81,7 @@ typedef union {
 
 #endif /* UNICODE && _WIN32 */
 
-#define curlx_unicodefree(ptr)                          \
-  do {                                                  \
-    if(ptr) {                                           \
-      (free)(ptr);                                      \
-      (ptr) = NULL;                                     \
-    }                                                   \
-  } while(0)
+/* the purpose of this macro is to free() without being traced by memdebug */
+#define curlx_unicodefree(ptr) (free)(CURL_UNCONST(ptr))
 
 #endif /* HEADER_CURL_MULTIBYTE_H */

+ 1 - 1
Utilities/cmcurl/lib/nonblock.c → Utilities/cmcurl/lib/curlx/nonblock.c

@@ -22,7 +22,7 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>

+ 0 - 0
Utilities/cmcurl/lib/nonblock.h → Utilities/cmcurl/lib/curlx/nonblock.h


+ 303 - 0
Utilities/cmcurl/lib/curlx/strparse.c

@@ -0,0 +1,303 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+
+#include "strparse.h"
+#include "../strcase.h"
+
+void curlx_str_init(struct Curl_str *out)
+{
+  out->str = NULL;
+  out->len = 0;
+}
+
+void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
+{
+  out->str = str;
+  out->len = len;
+}
+
+/* Get a word until the first DELIM or end of string. At least one byte long.
+   return non-zero on error */
+int curlx_str_until(const char **linep, struct Curl_str *out,
+                   const size_t max, char delim)
+{
+  const char *s = *linep;
+  size_t len = 0;
+  DEBUGASSERT(linep && *linep && out && max && delim);
+
+  curlx_str_init(out);
+  while(*s && (*s != delim)) {
+    s++;
+    if(++len > max) {
+      return STRE_BIG;
+    }
+  }
+  if(!len)
+    return STRE_SHORT;
+  out->str = *linep;
+  out->len = len;
+  *linep = s; /* point to the first byte after the word */
+  return STRE_OK;
+}
+
+/* Get a word until the first space or end of string. At least one byte long.
+   return non-zero on error */
+int curlx_str_word(const char **linep, struct Curl_str *out,
+                  const size_t max)
+{
+  return curlx_str_until(linep, out, max, ' ');
+}
+
+/* Get a word until a newline byte or end of string. At least one byte long.
+   return non-zero on error */
+int curlx_str_untilnl(const char **linep, struct Curl_str *out,
+                     const size_t max)
+{
+  const char *s = *linep;
+  size_t len = 0;
+  DEBUGASSERT(linep && *linep && out && max);
+
+  curlx_str_init(out);
+  while(*s && !ISNEWLINE(*s)) {
+    s++;
+    if(++len > max)
+      return STRE_BIG;
+  }
+  if(!len)
+    return STRE_SHORT;
+  out->str = *linep;
+  out->len = len;
+  *linep = s; /* point to the first byte after the word */
+  return STRE_OK;
+}
+
+
+/* Get a "quoted" word. No escaping possible.
+   return non-zero on error */
+int curlx_str_quotedword(const char **linep, struct Curl_str *out,
+                        const size_t max)
+{
+  const char *s = *linep;
+  size_t len = 0;
+  DEBUGASSERT(linep && *linep && out && max);
+
+  curlx_str_init(out);
+  if(*s != '\"')
+    return STRE_BEGQUOTE;
+  s++;
+  while(*s && (*s != '\"')) {
+    s++;
+    if(++len > max)
+      return STRE_BIG;
+  }
+  if(*s != '\"')
+    return STRE_ENDQUOTE;
+  out->str = (*linep) + 1;
+  out->len = len;
+  *linep = s + 1;
+  return STRE_OK;
+}
+
+/* Advance over a single character.
+   return non-zero on error */
+int curlx_str_single(const char **linep, char byte)
+{
+  DEBUGASSERT(linep && *linep);
+  if(**linep != byte)
+    return STRE_BYTE;
+  (*linep)++; /* move over it */
+  return STRE_OK;
+}
+
+/* Advance over a single space.
+   return non-zero on error */
+int curlx_str_singlespace(const char **linep)
+{
+  return curlx_str_single(linep, ' ');
+}
+
+/* given an ASCII character and max ascii, return TRUE if valid */
+#define valid_digit(x,m) \
+  (((x) >= '0') && ((x) <= m) && Curl_hexasciitable[(x)-'0'])
+
+/* We use 16 for the zero index (and the necessary bitwise AND in the loop)
+   to be able to have a non-zero value there to make valid_digit() able to
+   use the info */
+const unsigned char Curl_hexasciitable[] = {
+  16, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* 0x30: 0 - 9 */
+  0, 0, 0, 0, 0, 0, 0,
+  10, 11, 12, 13, 14, 15,        /* 0x41: A - F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  10, 11, 12, 13, 14, 15         /* 0x61: a - f */
+};
+
+/* no support for 0x prefix nor leading spaces */
+static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max,
+                        int base) /* 8, 10 or 16, nothing else */
+{
+  curl_off_t num = 0;
+  const char *p;
+  int m = (base == 10) ? '9' :   /* the largest digit possible */
+    (base == 16) ? 'f' : '7';
+  DEBUGASSERT(linep && *linep && nump);
+  DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
+  DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */
+  *nump = 0;
+  p = *linep;
+  if(!valid_digit(*p, m))
+    return STRE_NO_NUM;
+  if(max < base) {
+    /* special-case low max scenario because check needs to be different */
+    do {
+      int n = Curl_hexval(*p++);
+      num = num * base + n;
+      if(num > max)
+        return STRE_OVERFLOW;
+    } while(valid_digit(*p, m));
+  }
+  else {
+    do {
+      int n = Curl_hexval(*p++);
+      if(num > ((max - n) / base))
+        return STRE_OVERFLOW;
+      num = num * base + n;
+    } while(valid_digit(*p, m));
+  }
+  *nump = num;
+  *linep = p;
+  return STRE_OK;
+}
+
+/* Get an unsigned decimal number with no leading space or minus. Leading
+   zeroes are accepted. return non-zero on error */
+int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+  return str_num_base(linep, nump, max, 10);
+}
+
+/* Get an unsigned hexadecimal number with no leading space or minus and no
+   "0x" support. Leading zeroes are accepted. return non-zero on error */
+int curlx_str_hex(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+  return str_num_base(linep, nump, max, 16);
+}
+
+/* Get an unsigned octal number with no leading space or minus and no "0"
+   prefix support. Leading zeroes are accepted. return non-zero on error */
+int curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+  return str_num_base(linep, nump, max, 8);
+}
+
+/*
+ * Parse a positive number up to 63-bit number written in ASCII. Skip leading
+ * blanks. No support for prefixes.
+ */
+int curlx_str_numblanks(const char **str, curl_off_t *num)
+{
+  curlx_str_passblanks(str);
+  return curlx_str_number(str, num, CURL_OFF_T_MAX);
+}
+
+/* CR or LF
+   return non-zero on error */
+int curlx_str_newline(const char **linep)
+{
+  DEBUGASSERT(linep && *linep);
+  if(ISNEWLINE(**linep)) {
+    (*linep)++;
+    return STRE_OK; /* yessir */
+  }
+  return STRE_NEWLINE;
+}
+
+#ifndef WITHOUT_LIBCURL
+/* case insensitive compare that the parsed string matches the given string.
+   Returns non-zero on match. */
+int curlx_str_casecompare(struct Curl_str *str, const char *check)
+{
+  size_t clen = check ? strlen(check) : 0;
+  return ((str->len == clen) && strncasecompare(str->str, check, clen));
+}
+#endif
+
+/* case sensitive string compare. Returns non-zero on match. */
+int curlx_str_cmp(struct Curl_str *str, const char *check)
+{
+  if(check) {
+    size_t clen = strlen(check);
+    return ((str->len == clen) && !strncmp(str->str, check, clen));
+  }
+  return !!(str->len);
+}
+
+/* Trim off 'num' number of bytes from the beginning (left side) of the
+   string. If 'num' is larger than the string, return error. */
+int curlx_str_nudge(struct Curl_str *str, size_t num)
+{
+  if(num <= str->len) {
+    str->str += num;
+    str->len -= num;
+    return STRE_OK;
+  }
+  return STRE_OVERFLOW;
+}
+
+/* Get the following character sequence that consists only of bytes not
+   present in the 'reject' string. Like strcspn(). */
+int curlx_str_cspn(const char **linep, struct Curl_str *out,
+                   const char *reject)
+{
+  const char *s = *linep;
+  size_t len;
+  DEBUGASSERT(linep && *linep);
+
+  len = strcspn(s, reject);
+  if(len) {
+    out->str = s;
+    out->len = len;
+    *linep = &s[len];
+    return STRE_OK;
+  }
+  curlx_str_init(out);
+  return STRE_SHORT;
+}
+
+/* remove ISBLANK()s from both ends of the string */
+void curlx_str_trimblanks(struct Curl_str *out)
+{
+  while(out->len && ISBLANK(*out->str))
+    curlx_str_nudge(out, 1);
+
+  /* trim trailing spaces and tabs */
+  while(out->len && ISBLANK(out->str[out->len - 1]))
+    out->len--;
+}
+
+/* increase the pointer until it has moved over all blanks */
+void curlx_str_passblanks(const char **linep)
+{
+  while(ISBLANK(**linep))
+    (*linep)++; /* move over it */
+}

+ 112 - 0
Utilities/cmcurl/lib/curlx/strparse.h

@@ -0,0 +1,112 @@
+#ifndef HEADER_CURL_STRPARSE_H
+#define HEADER_CURL_STRPARSE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+#include "../curl_setup.h"
+
+#define STRE_OK       0
+#define STRE_BIG      1
+#define STRE_SHORT    2
+#define STRE_BEGQUOTE 3
+#define STRE_ENDQUOTE 4
+#define STRE_BYTE     5
+#define STRE_NEWLINE  6
+#define STRE_OVERFLOW 7
+#define STRE_NO_NUM   8
+
+/* public struct, but all accesses should be done using the provided
+   functions */
+struct Curl_str {
+  const char *str;
+  size_t len;
+};
+
+void curlx_str_init(struct Curl_str *out);
+void curlx_str_assign(struct Curl_str *out, const char *str, size_t len);
+
+#define curlx_str(x) ((x)->str)
+#define curlx_strlen(x) ((x)->len)
+
+/* Get a word until the first space
+   return non-zero on error */
+int curlx_str_word(const char **linep, struct Curl_str *out, const size_t max);
+
+/* Get a word until the first DELIM or end of string
+   return non-zero on error */
+int curlx_str_until(const char **linep, struct Curl_str *out, const size_t max,
+                   char delim);
+
+/* Get a word until a newline byte or end of string. At least one byte long.
+   return non-zero on error */
+int curlx_str_untilnl(const char **linep, struct Curl_str *out,
+                     const size_t max);
+
+/* Get a "quoted" word. No escaping possible.
+   return non-zero on error */
+int curlx_str_quotedword(const char **linep, struct Curl_str *out,
+                        const size_t max);
+
+/* Advance over a single character.
+   return non-zero on error */
+int curlx_str_single(const char **linep, char byte);
+
+/* Advance over a single space.
+   return non-zero on error */
+int curlx_str_singlespace(const char **linep);
+
+/* Get an unsigned decimal number. Return non-zero on error */
+int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* As above with CURL_OFF_T_MAX but also pass leading blanks */
+int curlx_str_numblanks(const char **str, curl_off_t *num);
+
+/* Get an unsigned hexadecimal number. Return non-zero on error */
+int curlx_str_hex(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* Get an unsigned octal number. Return non-zero on error */
+int curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* Check for CR or LF
+   return non-zero on error */
+int curlx_str_newline(const char **linep);
+
+/* case insensitive compare that the parsed string matches the
+   given string. */
+int curlx_str_casecompare(struct Curl_str *str, const char *check);
+int curlx_str_cmp(struct Curl_str *str, const char *check);
+
+int curlx_str_nudge(struct Curl_str *str, size_t num);
+
+int curlx_str_cspn(const char **linep, struct Curl_str *out, const char *cspn);
+void curlx_str_trimblanks(struct Curl_str *out);
+void curlx_str_passblanks(const char **linep);
+
+/* given a hexadecimal letter, return the binary value. '0' returns 0, 'a'
+   returns 10. THIS ONLY WORKS ON VALID HEXADECIMAL LETTER INPUT. Verify
+   before calling this!
+*/
+extern const unsigned char Curl_hexasciitable[];
+#define Curl_hexval(x) (unsigned char)(Curl_hexasciitable[(x) - '0'] & 0x0f)
+
+#endif /* HEADER_CURL_STRPARSE_H */

+ 2 - 2
Utilities/cmcurl/lib/timediff.c → Utilities/cmcurl/lib/curlx/timediff.c

@@ -44,7 +44,7 @@ struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
 
   if(ms > 0) {
     timediff_t tv_sec = ms / 1000;
-    timediff_t tv_usec = (ms % 1000) * 1000; /* max=999999 */
+    timediff_t tv_usec = (ms % 1000) * 1000; /* max=999000 */
 #ifdef HAVE_SUSECONDS_T
 #if TIMEDIFF_T_MAX > TIME_T_MAX
     /* tv_sec overflow check in case time_t is signed */
@@ -84,5 +84,5 @@ struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
  */
 timediff_t curlx_tvtoms(struct timeval *tv)
 {
-  return (tv->tv_sec*1000) + (timediff_t)(((double)tv->tv_usec)/1000.0);
+  return (tv->tv_sec*1000) + (timediff_t)(tv->tv_usec/1000);
 }

+ 1 - 1
Utilities/cmcurl/lib/timediff.h → Utilities/cmcurl/lib/curlx/timediff.h

@@ -24,7 +24,7 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 /* Use a larger type even for 32-bit time_t systems so that we can keep
    microsecond accuracy in it */

+ 38 - 16
Utilities/cmcurl/lib/timeval.c → Utilities/cmcurl/lib/curlx/timeval.c

@@ -24,30 +24,52 @@
 
 #include "timeval.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 #include <curl/curl.h>
-#include "system_win32.h"
+#include "version_win32.h"
+#include "../system_win32.h"
+
+LARGE_INTEGER Curl_freq;
+bool Curl_isVistaOrGreater;
+
+/* For tool or tests, we must initialize before calling curlx_now().
+   Providing this function here is wrong. */
+void curlx_now_init(void)
+{
+  if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL))
+    Curl_isVistaOrGreater = true;
+  else
+    Curl_isVistaOrGreater = false;
+
+  QueryPerformanceFrequency(&Curl_freq);
+}
 
 /* In case of bug fix this function has a counterpart in tool_util.c */
-struct curltime Curl_now(void)
+struct curltime curlx_now(void)
 {
   struct curltime now;
-  if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
+  bool isVistaOrGreater;
+  isVistaOrGreater = Curl_isVistaOrGreater;
+  if(isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
     LARGE_INTEGER count;
+    LARGE_INTEGER freq;
+    freq = Curl_freq;
+    DEBUGASSERT(freq.QuadPart);
     QueryPerformanceCounter(&count);
-    now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
-    now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
-                        Curl_freq.QuadPart);
+    now.tv_sec = (time_t)(count.QuadPart / freq.QuadPart);
+    now.tv_usec = (int)((count.QuadPart % freq.QuadPart) * 1000000 /
+                        freq.QuadPart);
   }
   else {
     /* Disable /analyze warning that GetTickCount64 is preferred  */
-#if defined(_MSC_VER)
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:28159)
 #endif
     DWORD milliseconds = GetTickCount();
-#if defined(_MSC_VER)
+#ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
@@ -60,7 +82,7 @@ struct curltime Curl_now(void)
 #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) ||  \
   defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
 
-struct curltime Curl_now(void)
+struct curltime curlx_now(void)
 {
   /*
   ** clock_gettime() is granted to be increased monotonically when the
@@ -134,7 +156,7 @@ struct curltime Curl_now(void)
 #include <stdint.h>
 #include <mach/mach_time.h>
 
-struct curltime Curl_now(void)
+struct curltime curlx_now(void)
 {
   /*
   ** Monotonic timer on macOS is provided by mach_absolute_time(), which
@@ -162,7 +184,7 @@ struct curltime Curl_now(void)
 
 #elif defined(HAVE_GETTIMEOFDAY)
 
-struct curltime Curl_now(void)
+struct curltime curlx_now(void)
 {
   /*
   ** gettimeofday() is not granted to be increased monotonically, due to
@@ -179,7 +201,7 @@ struct curltime Curl_now(void)
 
 #else
 
-struct curltime Curl_now(void)
+struct curltime curlx_now(void)
 {
   /*
   ** time() returns the value of time in seconds since the Epoch.
@@ -198,7 +220,7 @@ struct curltime Curl_now(void)
  *
  * @unittest: 1323
  */
-timediff_t Curl_timediff(struct curltime newer, struct curltime older)
+timediff_t curlx_timediff(struct curltime newer, struct curltime older)
 {
   timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
   if(diff >= (TIMEDIFF_T_MAX/1000))
@@ -212,7 +234,7 @@ timediff_t Curl_timediff(struct curltime newer, struct curltime older)
  * Returns: time difference in number of milliseconds, rounded up.
  * For too large diffs it returns max value.
  */
-timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older)
+timediff_t curlx_timediff_ceil(struct curltime newer, struct curltime older)
 {
   timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
   if(diff >= (TIMEDIFF_T_MAX/1000))
@@ -226,7 +248,7 @@ timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older)
  * Returns: time difference in number of microseconds. For too large diffs it
  * returns max value.
  */
-timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
+timediff_t curlx_timediff_us(struct curltime newer, struct curltime older)
 {
   timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
   if(diff >= (TIMEDIFF_T_MAX/1000000))

+ 10 - 5
Utilities/cmcurl/lib/timeval.h → Utilities/cmcurl/lib/curlx/timeval.h

@@ -24,7 +24,7 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #include "timediff.h"
 
@@ -33,7 +33,12 @@ struct curltime {
   int tv_usec;   /* microseconds */
 };
 
-struct curltime Curl_now(void);
+#ifdef _WIN32
+/* For tool or tests, we must initialize before calling curlx_now() */
+void curlx_now_init(void);
+#endif
+
+struct curltime curlx_now(void);
 
 /*
  * Make sure that the first argument (newer) is the more recent time and older
@@ -41,7 +46,7 @@ struct curltime Curl_now(void);
  *
  * Returns: the time difference in number of milliseconds.
  */
-timediff_t Curl_timediff(struct curltime newer, struct curltime older);
+timediff_t curlx_timediff(struct curltime newer, struct curltime older);
 
 /*
  * Make sure that the first argument (newer) is the more recent time and older
@@ -49,7 +54,7 @@ timediff_t Curl_timediff(struct curltime newer, struct curltime older);
  *
  * Returns: the time difference in number of milliseconds, rounded up.
  */
-timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older);
+timediff_t curlx_timediff_ceil(struct curltime newer, struct curltime older);
 
 /*
  * Make sure that the first argument (newer) is the more recent time and older
@@ -57,6 +62,6 @@ timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older);
  *
  * Returns: the time difference in number of microseconds.
  */
-timediff_t Curl_timediff_us(struct curltime newer, struct curltime older);
+timediff_t curlx_timediff_us(struct curltime newer, struct curltime older);
 
 #endif /* HEADER_CURL_TIMEVAL_H */

+ 11 - 89
Utilities/cmcurl/lib/version_win32.c → Utilities/cmcurl/lib/curlx/version_win32.c

@@ -22,19 +22,17 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 #include <curl/curl.h>
 #include "version_win32.h"
 #include "warnless.h"
 
 /* The last 2 #include files should be in this order */
-#ifdef BUILDING_LIBCURL
-#include "curl_memory.h"
-#endif
-#include "memdebug.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
 
 /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
    and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
@@ -79,7 +77,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
 {
   bool matched = FALSE;
 
-#if defined(CURL_WINDOWS_UWP)
+#ifdef CURL_WINDOWS_UWP
   /* We have no way to determine the Windows version from Windows apps,
      so let's assume we are running on the target Windows version. */
   const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
@@ -113,88 +111,12 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
     /* we are always running on PLATFORM_WINNT */
     matched = FALSE;
   }
-#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
-    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
-  OSVERSIONINFO osver;
-
-  memset(&osver, 0, sizeof(osver));
-  osver.dwOSVersionInfoSize = sizeof(osver);
-
-  /* Find out Windows version */
-  if(GetVersionEx(&osver)) {
-    /* Verify the Operating System version number */
-    switch(condition) {
-    case VERSION_LESS_THAN:
-      if(osver.dwMajorVersion < majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion < minorVersion) ||
-        (buildVersion != 0 &&
-         (osver.dwMajorVersion == majorVersion &&
-          osver.dwMinorVersion == minorVersion &&
-          osver.dwBuildNumber < buildVersion)))
-        matched = TRUE;
-      break;
-
-    case VERSION_LESS_THAN_EQUAL:
-      if(osver.dwMajorVersion < majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion < minorVersion) ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion == minorVersion &&
-         (buildVersion == 0 ||
-          osver.dwBuildNumber <= buildVersion)))
-        matched = TRUE;
-      break;
-
-    case VERSION_EQUAL:
-      if(osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion == minorVersion &&
-        (buildVersion == 0 ||
-         osver.dwBuildNumber == buildVersion))
-        matched = TRUE;
-      break;
-
-    case VERSION_GREATER_THAN_EQUAL:
-      if(osver.dwMajorVersion > majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion > minorVersion) ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion == minorVersion &&
-         (buildVersion == 0 ||
-          osver.dwBuildNumber >= buildVersion)))
-        matched = TRUE;
-      break;
-
-    case VERSION_GREATER_THAN:
-      if(osver.dwMajorVersion > majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion > minorVersion) ||
-        (buildVersion != 0 &&
-         (osver.dwMajorVersion == majorVersion &&
-          osver.dwMinorVersion == minorVersion &&
-          osver.dwBuildNumber > buildVersion)))
-        matched = TRUE;
-      break;
-    }
-
-    /* Verify the platform identifier (if necessary) */
-    if(matched) {
-      switch(platform) {
-      case PLATFORM_WINDOWS:
-        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
-          matched = FALSE;
-        break;
-
-      case PLATFORM_WINNT:
-        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
-          matched = FALSE;
-        break;
-
-      default: /* like platform == PLATFORM_DONT_CARE */
-        break;
-      }
-    }
-  }
+#elif defined(UNDER_CE)
+  (void)majorVersion;
+  (void)minorVersion;
+  (void)buildVersion;
+  (void)platform;
+  (void)condition;
 #else
   ULONGLONG cm = 0;
   struct OUR_OSVERSIONINFOEXW osver;

+ 2 - 2
Utilities/cmcurl/lib/version_win32.h → Utilities/cmcurl/lib/curlx/version_win32.h

@@ -24,9 +24,9 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 /* Version condition */
 typedef enum {

+ 2 - 29
Utilities/cmcurl/lib/warnless.c → Utilities/cmcurl/lib/curlx/warnless.c

@@ -22,7 +22,7 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "warnless.h"
 
 #if defined(__INTEL_COMPILER) && defined(__unix__)
 
@@ -35,8 +35,6 @@
 
 #endif /* __INTEL_COMPILER && __unix__ */
 
-#include "warnless.h"
-
 #ifdef _WIN32
 #undef read
 #undef write
@@ -45,42 +43,17 @@
 #include <limits.h>
 
 #define CURL_MASK_UCHAR   ((unsigned char)~0)
-#define CURL_MASK_SCHAR   (CURL_MASK_UCHAR >> 1)
 
 #define CURL_MASK_USHORT  ((unsigned short)~0)
-#define CURL_MASK_SSHORT  (CURL_MASK_USHORT >> 1)
 
 #define CURL_MASK_UINT    ((unsigned int)~0)
 #define CURL_MASK_SINT    (CURL_MASK_UINT >> 1)
 
 #define CURL_MASK_ULONG   ((unsigned long)~0)
-#define CURL_MASK_SLONG   (CURL_MASK_ULONG >> 1)
-
-#define CURL_MASK_UCOFFT  ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
-#define CURL_MASK_SCOFFT  (CURL_MASK_UCOFFT >> 1)
 
 #define CURL_MASK_USIZE_T ((size_t)~0)
 #define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
 
-/*
-** unsigned long to unsigned short
-*/
-
-unsigned short curlx_ultous(unsigned long ulnum)
-{
-#ifdef __INTEL_COMPILER
-#  pragma warning(push)
-#  pragma warning(disable:810) /* conversion may lose significant bits */
-#endif
-
-  DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
-  return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
-
-#ifdef __INTEL_COMPILER
-#  pragma warning(pop)
-#endif
-}
-
 /*
 ** unsigned long to unsigned char
 */
@@ -323,7 +296,7 @@ size_t curlx_sitouz(int sinum)
 #endif
 }
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 ssize_t curlx_read(int fd, void *buf, size_t count)
 {

+ 3 - 5
Utilities/cmcurl/lib/warnless.h → Utilities/cmcurl/lib/curlx/warnless.h

@@ -24,7 +24,7 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #ifdef USE_WINSOCK
 #include <curl/curl.h> /* for curl_socket_t */
@@ -33,8 +33,6 @@
 #define CURLX_FUNCTION_CAST(target_type, func) \
   (target_type)(void (*) (void))(func)
 
-unsigned short curlx_ultous(unsigned long ulnum);
-
 unsigned char curlx_ultouc(unsigned long ulnum);
 
 int curlx_uztosi(size_t uznum);
@@ -59,7 +57,7 @@ unsigned short curlx_uitous(unsigned int uinum);
 
 size_t curlx_sitouz(int sinum);
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 ssize_t curlx_read(int fd, void *buf, size_t count);
 
@@ -72,7 +70,7 @@ ssize_t curlx_write(int fd, const void *buf, size_t count);
 #ifndef HEADER_CURL_WARNLESS_H_REDEFS
 #define HEADER_CURL_WARNLESS_H_REDEFS
 
-#if defined(_WIN32)
+#ifdef _WIN32
 #undef  read
 #define read(fd, buf, count)  curlx_read(fd, buf, count)
 #undef  write

+ 135 - 0
Utilities/cmcurl/lib/curlx/winapi.c

@@ -0,0 +1,135 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+#include "../curl_setup.h"
+
+/*
+ * curlx_winapi_strerror:
+ * Variant of Curl_strerror if the error code is definitely Windows API.
+ */
+#ifdef _WIN32
+#include "winapi.h"
+
+#ifdef BUILDING_LIBCURL
+#include <curl/mprintf.h>
+#define SNPRINTF curl_msnprintf
+#else
+/* when built for the test servers */
+
+/* adjust for old MSVC */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+# define SNPRINTF _snprintf
+#else
+#define SNPRINTF snprintf
+#endif
+
+#endif /* !BUILDING_LIBCURL */
+
+#ifdef _WIN32
+/* This is a helper function for Curl_strerror that converts Windows API error
+ * codes (GetLastError) to error messages.
+ * Returns NULL if no error message was found for error code.
+ */
+const char *curlx_get_winapi_error(int err, char *buf, size_t buflen)
+{
+  char *p;
+  wchar_t wbuf[256];
+
+  if(!buflen)
+    return NULL;
+
+  *buf = '\0';
+  *wbuf = L'\0';
+
+  /* We return the local codepage version of the error string because if it is
+     output to the user's terminal it will likely be with functions which
+     expect the local codepage (eg fprintf, failf, infof).
+     FormatMessageW -> wcstombs is used for Windows CE compatibility. */
+  if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
+                     FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
+                    LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) {
+    size_t written = wcstombs(buf, wbuf, buflen - 1);
+    if(written != (size_t)-1)
+      buf[written] = '\0';
+    else
+      *buf = '\0';
+  }
+
+  /* Truncate multiple lines */
+  p = strchr(buf, '\n');
+  if(p) {
+    if(p > buf && *(p-1) == '\r')
+      *(p-1) = '\0';
+    else
+      *p = '\0';
+  }
+
+  return *buf ? buf : NULL;
+}
+#endif /* _WIN32 */
+
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
+{
+#ifdef _WIN32
+  DWORD old_win_err = GetLastError();
+#endif
+  int old_errno = errno;
+
+  if(!buflen)
+    return NULL;
+
+  *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(!curlx_get_winapi_error((int)err, buf, buflen)) {
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wformat-truncation=1"
+#endif
+    /* some GCC compilers cause false positive warnings if we allow this
+       warning */
+    SNPRINTF(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic pop
+#endif
+
+  }
+#else
+  {
+    const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
+    if(strlen(txt) < buflen)
+      strcpy(buf, txt);
+  }
+#endif
+
+  if(errno != old_errno)
+    CURL_SETERRNO(old_errno);
+
+#ifdef _WIN32
+  if(old_win_err != GetLastError())
+    SetLastError(old_win_err);
+#endif
+
+  return buf;
+}
+#endif /* _WIN32 */

+ 7 - 10
Utilities/cmcurl/lib/strtok.h → Utilities/cmcurl/lib/curlx/winapi.h

@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_STRTOK_H
-#define HEADER_CURL_STRTOK_H
+#ifndef HEADER_CURLX_WINAPI_H
+#define HEADER_CURLX_WINAPI_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -23,14 +23,11 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
-#include "curl_setup.h"
-#include <stddef.h>
 
-#ifdef HAVE_STRTOK_R
-#include <string.h>
-#define Curl_strtok_r strtok_r
-#else
-char *Curl_strtok_r(char *s, const char *delim, char **last);
+#ifdef _WIN32
+#define WINAPI_ERROR_LEN 100
+const char *curlx_get_winapi_error(int err, char *buf, size_t buflen);
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
 #endif
 
-#endif /* HEADER_CURL_STRTOK_H */
+#endif /* HEADER_CURLX_WINAPI_H */

+ 64 - 42
Utilities/cmcurl/lib/cw-out.c

@@ -32,6 +32,7 @@
 #include "multiif.h"
 #include "sendf.h"
 #include "cw-out.h"
+#include "cw-pause.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -86,7 +87,7 @@ static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
   struct cw_out_buf *cwbuf = calloc(1, sizeof(*cwbuf));
   if(cwbuf) {
     cwbuf->type = otype;
-    Curl_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
+    curlx_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
   }
   return cwbuf;
 }
@@ -94,7 +95,7 @@ static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
 static void cw_out_buf_free(struct cw_out_buf *cwbuf)
 {
   if(cwbuf) {
-    Curl_dyn_free(&cwbuf->b);
+    curlx_dyn_free(&cwbuf->b);
     free(cwbuf);
   }
 }
@@ -113,7 +114,7 @@ static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer);
 static CURLcode cw_out_init(struct Curl_easy *data,
                             struct Curl_cwriter *writer);
 
-struct Curl_cwtype Curl_cwt_out = {
+const struct Curl_cwtype Curl_cwt_out = {
   "cw-out",
   NULL,
   cw_out_init,
@@ -145,7 +146,7 @@ static size_t cw_out_bufs_len(struct cw_out_ctx *ctx)
   struct cw_out_buf *cwbuf = ctx->buf;
   size_t len = 0;
   while(cwbuf) {
-    len += Curl_dyn_len(&cwbuf->b);
+    len += curlx_dyn_len(&cwbuf->b);
     cwbuf = cwbuf->next;
   }
   return len;
@@ -198,7 +199,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
                                  const char *buf, size_t blen,
                                  size_t *pconsumed)
 {
-  curl_write_callback wcb;
+  curl_write_callback wcb = NULL;
   void *wcb_data;
   size_t max_write, min_write;
   size_t wlen, nwritten;
@@ -220,9 +221,9 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
       break;
     wlen = max_write ? CURLMIN(blen, max_write) : blen;
     Curl_set_in_callback(data, TRUE);
-    nwritten = wcb((char *)buf, 1, wlen, wcb_data);
+    nwritten = wcb((char *)CURL_UNCONST(buf), 1, wlen, wcb_data);
     Curl_set_in_callback(data, FALSE);
-    CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
+    CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
                    wlen, (otype == CW_OUT_BODY) ? "body" : "header",
                    nwritten);
     if(CURL_WRITEFUNC_PAUSE == nwritten) {
@@ -236,7 +237,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
       /* mark the connection as RECV paused */
       data->req.keepon |= KEEP_RECV_PAUSE;
       ctx->paused = TRUE;
-      CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
+      CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
       break;
     }
     else if(CURL_WRITEFUNC_ERROR == nwritten) {
@@ -262,23 +263,24 @@ static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx,
 {
   CURLcode result = CURLE_OK;
 
-  if(Curl_dyn_len(&cwbuf->b)) {
+  if(curlx_dyn_len(&cwbuf->b)) {
     size_t consumed;
 
     result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all,
-                              Curl_dyn_ptr(&cwbuf->b),
-                              Curl_dyn_len(&cwbuf->b),
+                              curlx_dyn_ptr(&cwbuf->b),
+                              curlx_dyn_len(&cwbuf->b),
                               &consumed);
     if(result)
       return result;
 
     if(consumed) {
-      if(consumed == Curl_dyn_len(&cwbuf->b)) {
-        Curl_dyn_free(&cwbuf->b);
+      if(consumed == curlx_dyn_len(&cwbuf->b)) {
+        curlx_dyn_free(&cwbuf->b);
       }
       else {
-        DEBUGASSERT(consumed < Curl_dyn_len(&cwbuf->b));
-        result = Curl_dyn_tail(&cwbuf->b, Curl_dyn_len(&cwbuf->b) - consumed);
+        DEBUGASSERT(consumed < curlx_dyn_len(&cwbuf->b));
+        result = curlx_dyn_tail(&cwbuf->b,
+                                curlx_dyn_len(&cwbuf->b) - consumed);
         if(result)
           return result;
       }
@@ -318,7 +320,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
   result = cw_out_buf_flush(ctx, data, cwbuf, flush_all);
   if(result)
     return result;
-  if(!Curl_dyn_len(&cwbuf->b)) {
+  if(!curlx_dyn_len(&cwbuf->b)) {
     cw_out_buf_free(cwbuf);
     *pcwbuf = NULL;
   }
@@ -326,11 +328,16 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
 }
 
 static CURLcode cw_out_append(struct cw_out_ctx *ctx,
+                              struct Curl_easy *data,
                               cw_out_type otype,
                               const char *buf, size_t blen)
 {
-  if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER)
+  CURL_TRC_WRITE(data, "[OUT] paused, buffering %zu more bytes (%zu/%d)",
+                 blen, cw_out_bufs_len(ctx), DYN_PAUSE_BUFFER);
+  if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER) {
+    failf(data, "pause buffer not large enough -> CURLE_TOO_LARGE");
     return CURLE_TOO_LARGE;
+  }
 
   /* if we do not have a buffer, or it is of another type, make a new one.
    * And for CW_OUT_HDS always make a new one, so we "replay" headers
@@ -343,7 +350,7 @@ static CURLcode cw_out_append(struct cw_out_ctx *ctx,
     ctx->buf = cwbuf;
   }
   DEBUGASSERT(ctx->buf && (ctx->buf->type == otype));
-  return Curl_dyn_addn(&ctx->buf->b, buf, blen);
+  return curlx_dyn_addn(&ctx->buf->b, buf, blen);
 }
 
 static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
@@ -364,7 +371,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
 
   if(ctx->buf) {
     /* still have buffered data, append and flush */
-    result = cw_out_append(ctx, otype, buf, blen);
+    result = cw_out_append(ctx, data, otype, buf, blen);
     if(result)
       return result;
     result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
@@ -380,7 +387,8 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
       return result;
     if(consumed < blen) {
       /* did not write all, append the rest */
-      result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
+      result = cw_out_append(ctx, data, otype,
+                             buf + consumed, blen - consumed);
       if(result)
         goto out;
     }
@@ -430,44 +438,58 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data)
     return FALSE;
 
   ctx = (struct cw_out_ctx *)cw_out;
-  CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused ? "" : " not");
   return ctx->paused;
 }
 
 static CURLcode cw_out_flush(struct Curl_easy *data,
-                             bool unpause, bool flush_all)
+                             struct Curl_cwriter *cw_out,
+                             bool flush_all)
 {
-  struct Curl_cwriter *cw_out;
+  struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
   CURLcode result = CURLE_OK;
 
-  cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
-  if(cw_out) {
-    struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
-    if(ctx->errored)
-      return CURLE_WRITE_ERROR;
-    if(unpause && ctx->paused)
-      ctx->paused = FALSE;
-    if(ctx->paused)
-      return CURLE_OK;  /* not doing it */
+  if(ctx->errored)
+    return CURLE_WRITE_ERROR;
+  if(ctx->paused)
+    return CURLE_OK;  /* not doing it */
 
-    result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
-    if(result) {
-      ctx->errored = TRUE;
-      cw_out_bufs_free(ctx);
-      return result;
-    }
+  result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
+  if(result) {
+    ctx->errored = TRUE;
+    cw_out_bufs_free(ctx);
+    return result;
   }
   return result;
 }
 
 CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
 {
-  CURL_TRC_WRITE(data, "cw-out unpause");
-  return cw_out_flush(data, TRUE, FALSE);
+  struct Curl_cwriter *cw_out;
+  CURLcode result = CURLE_OK;
+
+  cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
+  if(cw_out) {
+    struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
+    CURL_TRC_WRITE(data, "[OUT] unpause");
+    ctx->paused = FALSE;
+    result = Curl_cw_pause_flush(data);
+    if(!result)
+      result = cw_out_flush(data, cw_out, FALSE);
+  }
+  return result;
 }
 
 CURLcode Curl_cw_out_done(struct Curl_easy *data)
 {
-  CURL_TRC_WRITE(data, "cw-out done");
-  return cw_out_flush(data, FALSE, TRUE);
+  struct Curl_cwriter *cw_out;
+  CURLcode result = CURLE_OK;
+
+  cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
+  if(cw_out) {
+    CURL_TRC_WRITE(data, "[OUT] done");
+    result = Curl_cw_pause_flush(data);
+    if(!result)
+      result = cw_out_flush(data, cw_out, TRUE);
+  }
+  return result;
 }

+ 1 - 1
Utilities/cmcurl/lib/cw-out.h

@@ -33,7 +33,7 @@
  * the client callbacks. Intended to be the last installed in the
  * client writer stack of a transfer.
  */
-extern struct Curl_cwtype Curl_cwt_out;
+extern const struct Curl_cwtype Curl_cwt_out;
 
 /**
  * Return TRUE iff 'cw-out' client write has paused data.

+ 242 - 0
Utilities/cmcurl/lib/cw-pause.c

@@ -0,0 +1,242 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "bufq.h"
+#include "cfilters.h"
+#include "headers.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "cw-pause.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/* body dynbuf sizes */
+#define CW_PAUSE_BUF_CHUNK         (16 * 1024)
+/* when content decoding, write data in chunks */
+#define CW_PAUSE_DEC_WRITE_CHUNK   (4096)
+
+struct cw_pause_buf {
+  struct cw_pause_buf *next;
+  struct bufq b;
+  int type;
+};
+
+static struct cw_pause_buf *cw_pause_buf_create(int type, size_t buflen)
+{
+  struct cw_pause_buf *cwbuf = calloc(1, sizeof(*cwbuf));
+  if(cwbuf) {
+    cwbuf->type = type;
+    if(type & CLIENTWRITE_BODY)
+      Curl_bufq_init2(&cwbuf->b, CW_PAUSE_BUF_CHUNK, 1,
+                      (BUFQ_OPT_SOFT_LIMIT|BUFQ_OPT_NO_SPARES));
+    else
+      Curl_bufq_init(&cwbuf->b, buflen, 1);
+  }
+  return cwbuf;
+}
+
+static void cw_pause_buf_free(struct cw_pause_buf *cwbuf)
+{
+  if(cwbuf) {
+    Curl_bufq_free(&cwbuf->b);
+    free(cwbuf);
+  }
+}
+
+struct cw_pause_ctx {
+  struct Curl_cwriter super;
+  struct cw_pause_buf *buf;
+  size_t buf_total;
+};
+
+static CURLcode cw_pause_write(struct Curl_easy *data,
+                               struct Curl_cwriter *writer, int type,
+                               const char *buf, size_t nbytes);
+static void cw_pause_close(struct Curl_easy *data,
+                           struct Curl_cwriter *writer);
+static CURLcode cw_pause_init(struct Curl_easy *data,
+                              struct Curl_cwriter *writer);
+
+const struct Curl_cwtype Curl_cwt_pause = {
+  "cw-pause",
+  NULL,
+  cw_pause_init,
+  cw_pause_write,
+  cw_pause_close,
+  sizeof(struct cw_pause_ctx)
+};
+
+static CURLcode cw_pause_init(struct Curl_easy *data,
+                              struct Curl_cwriter *writer)
+{
+  struct cw_pause_ctx *ctx = writer->ctx;
+  (void)data;
+  ctx->buf = NULL;
+  return CURLE_OK;
+}
+
+static void cw_pause_bufs_free(struct cw_pause_ctx *ctx)
+{
+  while(ctx->buf) {
+    struct cw_pause_buf *next = ctx->buf->next;
+    cw_pause_buf_free(ctx->buf);
+    ctx->buf = next;
+  }
+}
+
+static void cw_pause_close(struct Curl_easy *data, struct Curl_cwriter *writer)
+{
+  struct cw_pause_ctx *ctx = writer->ctx;
+
+  (void)data;
+  cw_pause_bufs_free(ctx);
+}
+
+static CURLcode cw_pause_flush(struct Curl_easy *data,
+                               struct Curl_cwriter *cw_pause)
+{
+  struct cw_pause_ctx *ctx = (struct cw_pause_ctx *)cw_pause;
+  bool decoding = Curl_cwriter_is_content_decoding(data);
+  CURLcode result = CURLE_OK;
+
+  /* write the end of the chain until it blocks or gets empty */
+  while(ctx->buf && !Curl_cwriter_is_paused(data)) {
+    struct cw_pause_buf **plast = &ctx->buf;
+    size_t blen, wlen = 0;
+    const unsigned char *buf = NULL;
+
+    while((*plast)->next) /* got to last in list */
+      plast = &(*plast)->next;
+    if(Curl_bufq_peek(&(*plast)->b, &buf, &blen)) {
+      wlen = (decoding && ((*plast)->type & CLIENTWRITE_BODY)) ?
+             CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
+      result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
+                                  (const char *)buf, wlen);
+      CURL_TRC_WRITE(data, "[PAUSE] flushed %zu/%zu bytes, type=%x -> %d",
+                     wlen, ctx->buf_total, (*plast)->type, result);
+      Curl_bufq_skip(&(*plast)->b, wlen);
+      DEBUGASSERT(ctx->buf_total >= wlen);
+      ctx->buf_total -= wlen;
+      if(result)
+        return result;
+    }
+    else if((*plast)->type & CLIENTWRITE_EOS) {
+      result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
+                                  (const char *)buf, 0);
+      CURL_TRC_WRITE(data, "[PAUSE] flushed 0/%zu bytes, type=%x -> %d",
+                     ctx->buf_total, (*plast)->type, result);
+    }
+
+    if(Curl_bufq_is_empty(&(*plast)->b)) {
+      cw_pause_buf_free(*plast);
+      *plast = NULL;
+    }
+  }
+  return result;
+}
+
+static CURLcode cw_pause_write(struct Curl_easy *data,
+                               struct Curl_cwriter *writer, int type,
+                               const char *buf, size_t blen)
+{
+  struct cw_pause_ctx *ctx = writer->ctx;
+  CURLcode result = CURLE_OK;
+  size_t wlen = 0;
+  bool decoding = Curl_cwriter_is_content_decoding(data);
+
+  if(ctx->buf && !Curl_cwriter_is_paused(data)) {
+    result = cw_pause_flush(data, writer);
+    if(result)
+      return result;
+  }
+
+  while(!ctx->buf && !Curl_cwriter_is_paused(data)) {
+    int wtype = type;
+    DEBUGASSERT(!ctx->buf);
+    /* content decoding might blow up size considerably, write smaller
+     * chunks to make pausing need buffer less. */
+    wlen = (decoding && (type & CLIENTWRITE_BODY)) ?
+           CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
+    if(wlen < blen)
+      wtype &= ~CLIENTWRITE_EOS;
+    result = Curl_cwriter_write(data, writer->next, wtype, buf, wlen);
+    CURL_TRC_WRITE(data, "[PAUSE] writing %zu/%zu bytes of type %x -> %d",
+                   wlen, blen, wtype, result);
+    if(result)
+      return result;
+    buf += wlen;
+    blen -= wlen;
+    if(!blen)
+      return result;
+  }
+
+  do {
+    size_t nwritten = 0;
+    if(ctx->buf && (ctx->buf->type == type) && (type & CLIENTWRITE_BODY)) {
+      /* same type and body, append to current buffer which has a soft
+       * limit and should take everything up to OOM. */
+      result = Curl_bufq_cwrite(&ctx->buf->b, buf, blen, &nwritten);
+    }
+    else {
+      /* Need a new buf, type changed */
+      struct cw_pause_buf *cwbuf = cw_pause_buf_create(type, blen);
+      if(!cwbuf)
+        return CURLE_OUT_OF_MEMORY;
+      cwbuf->next = ctx->buf;
+      ctx->buf = cwbuf;
+      result = Curl_bufq_cwrite(&ctx->buf->b, buf, blen, &nwritten);
+    }
+    CURL_TRC_WRITE(data, "[PAUSE] buffer %zu more bytes of type %x, "
+                   "total=%zu -> %d", nwritten, type, ctx->buf_total + wlen,
+                   result);
+    if(result)
+      return result;
+    buf += nwritten;
+    blen -= nwritten;
+    ctx->buf_total += nwritten;
+  } while(blen);
+
+  return result;
+}
+
+CURLcode Curl_cw_pause_flush(struct Curl_easy *data)
+{
+  struct Curl_cwriter *cw_pause;
+  CURLcode result = CURLE_OK;
+
+  cw_pause = Curl_cwriter_get_by_type(data, &Curl_cwt_pause);
+  if(cw_pause)
+    result = cw_pause_flush(data, cw_pause);
+
+  return result;
+}

+ 10 - 24
Utilities/cmcurl/lib/strtoofft.h → Utilities/cmcurl/lib/cw-pause.h

@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_STRTOOFFT_H
-#define HEADER_CURL_STRTOOFFT_H
+#ifndef HEADER_CURL_CW_PAUSE_H
+#define HEADER_CURL_CW_PAUSE_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -26,29 +26,15 @@
 
 #include "curl_setup.h"
 
-/*
- * Determine which string to integral data type conversion function we use
- * to implement string conversion to our curl_off_t integral data type.
- *
- * Notice that curl_off_t might be 64 or 32 bits wide, and that it might use
- * an underlying data type which might be 'long', 'int64_t', 'long long' or
- * '__int64' and more remotely other data types.
- *
- * On systems where the size of curl_off_t is greater than the size of 'long'
- * the conversion function to use is strtoll() if it is available, otherwise,
- * we emulate its functionality with our own clone.
- *
- * On systems where the size of curl_off_t is smaller or equal than the size
- * of 'long' the conversion function to use is strtol().
+#include "sendf.h"
+
+/**
+ * The client writer type "cw-pause" that buffers writes for
+ * paused transfer writes.
  */
+extern const struct Curl_cwtype Curl_cwt_pause;
 
-typedef enum {
-  CURL_OFFT_OK,    /* parsed fine */
-  CURL_OFFT_FLOW,  /* over or underflow */
-  CURL_OFFT_INVAL  /* nothing was parsed */
-} CURLofft;
+CURLcode Curl_cw_pause_flush(struct Curl_easy *data);
 
-CURLofft curlx_strtoofft(const char *str, char **endp, int base,
-                         curl_off_t *num);
 
-#endif /* HEADER_CURL_STRTOOFFT_H */
+#endif /* HEADER_CURL_CW_PAUSE_H */

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff