浏览代码

Merge topic 'update-curl'

022d16659b curl: Work around missing OpenSSL symbol with LCC 1.23
01dde28dab ci: curl with Secure Transport on macOS does not support TLS 1.3
da52e4e571 curl: Set build options the way we need for CMake
ce908c42a3 Merge branch 'upstream-curl' into update-curl
1a2b208170 curl 2024-09-18 (7eb8c048)
862bd5defc curl: Update script to get curl 8.10.1

Acked-by: Kitware Robot <[email protected]>
Merge-request: !9832
Brad King 1 年之前
父节点
当前提交
2cfe2ac0c7
共有 100 个文件被更改,包括 4118 次插入2840 次删除
  1. 1 4
      .gitlab/ci/configure_macos_arm64_curl.cmake
  2. 1 1
      Utilities/Scripts/update-curl.bash
  3. 29 34
      Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
  4. 2 2
      Utilities/cmcurl/CMake/CurlTests.c
  5. 32 5
      Utilities/cmcurl/CMake/FindBearSSL.cmake
  6. 48 11
      Utilities/cmcurl/CMake/FindBrotli.cmake
  7. 0 47
      Utilities/cmcurl/CMake/FindCARES.cmake
  8. 80 0
      Utilities/cmcurl/CMake/FindCares.cmake
  9. 139 130
      Utilities/cmcurl/CMake/FindGSS.cmake
  10. 0 45
      Utilities/cmcurl/CMake/FindLibSSH2.cmake
  11. 78 0
      Utilities/cmcurl/CMake/FindLibgsasl.cmake
  12. 78 0
      Utilities/cmcurl/CMake/FindLibidn2.cmake
  13. 80 0
      Utilities/cmcurl/CMake/FindLibpsl.cmake
  14. 92 0
      Utilities/cmcurl/CMake/FindLibssh.cmake
  15. 80 0
      Utilities/cmcurl/CMake/FindLibssh2.cmake
  16. 88 0
      Utilities/cmcurl/CMake/FindLibuv.cmake
  17. 26 23
      Utilities/cmcurl/CMake/FindMSH3.cmake
  18. 83 8
      Utilities/cmcurl/CMake/FindMbedTLS.cmake
  19. 48 9
      Utilities/cmcurl/CMake/FindNGHTTP2.cmake
  20. 29 27
      Utilities/cmcurl/CMake/FindNGHTTP3.cmake
  21. 48 48
      Utilities/cmcurl/CMake/FindNGTCP2.cmake
  22. 35 27
      Utilities/cmcurl/CMake/FindNettle.cmake
  23. 27 24
      Utilities/cmcurl/CMake/FindQuiche.cmake
  24. 42 14
      Utilities/cmcurl/CMake/FindRustls.cmake
  25. 64 0
      Utilities/cmcurl/CMake/FindWolfSSH.cmake
  26. 59 21
      Utilities/cmcurl/CMake/FindWolfSSL.cmake
  27. 58 35
      Utilities/cmcurl/CMake/FindZstd.cmake
  28. 31 35
      Utilities/cmcurl/CMake/Macros.cmake
  29. 27 31
      Utilities/cmcurl/CMake/OtherTests.cmake
  30. 13 13
      Utilities/cmcurl/CMake/PickyWarnings.cmake
  31. 10 7
      Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
  32. 2 2
      Utilities/cmcurl/CMake/Utilities.cmake
  33. 9 9
      Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
  34. 8 0
      Utilities/cmcurl/CMake/curl-config.cmake.in
  35. 346 195
      Utilities/cmcurl/CMakeLists.txt
  36. 13 11
      Utilities/cmcurl/include/curl/curl.h
  37. 3 3
      Utilities/cmcurl/include/curl/curlver.h
  38. 7 1
      Utilities/cmcurl/include/curl/mprintf.h
  39. 1 1
      Utilities/cmcurl/include/curl/system.h
  40. 83 45
      Utilities/cmcurl/lib/CMakeLists.txt
  41. 22 22
      Utilities/cmcurl/lib/altsvc.c
  42. 1 1
      Utilities/cmcurl/lib/altsvc.h
  43. 1 251
      Utilities/cmcurl/lib/asyn-thread.c
  44. 69 0
      Utilities/cmcurl/lib/bufq.c
  45. 6 0
      Utilities/cmcurl/lib/bufq.h
  46. 170 145
      Utilities/cmcurl/lib/c-hyper.c
  47. 2 3
      Utilities/cmcurl/lib/cf-h1-proxy.c
  48. 108 84
      Utilities/cmcurl/lib/cf-h2-proxy.c
  49. 19 17
      Utilities/cmcurl/lib/cf-haproxy.c
  50. 43 6
      Utilities/cmcurl/lib/cf-https-connect.c
  51. 96 52
      Utilities/cmcurl/lib/cf-socket.c
  52. 1 1
      Utilities/cmcurl/lib/cf-socket.h
  53. 64 12
      Utilities/cmcurl/lib/cfilters.c
  54. 31 10
      Utilities/cmcurl/lib/cfilters.h
  55. 423 376
      Utilities/cmcurl/lib/conncache.c
  56. 145 108
      Utilities/cmcurl/lib/conncache.h
  57. 50 96
      Utilities/cmcurl/lib/connect.c
  58. 0 3
      Utilities/cmcurl/lib/connect.h
  59. 7 7
      Utilities/cmcurl/lib/content_encoding.c
  60. 7 2
      Utilities/cmcurl/lib/cookie.c
  61. 1 1
      Utilities/cmcurl/lib/curl_addrinfo.c
  62. 22 12
      Utilities/cmcurl/lib/curl_config.h.cmake
  63. 4 4
      Utilities/cmcurl/lib/curl_des.c
  64. 4 4
      Utilities/cmcurl/lib/curl_des.h
  65. 1 1
      Utilities/cmcurl/lib/curl_fnmatch.h
  66. 4 13
      Utilities/cmcurl/lib/curl_gethostname.c
  67. 4 0
      Utilities/cmcurl/lib/curl_memrchr.c
  68. 4 0
      Utilities/cmcurl/lib/curl_memrchr.h
  69. 3 3
      Utilities/cmcurl/lib/curl_multibyte.h
  70. 15 11
      Utilities/cmcurl/lib/curl_ntlm_core.c
  71. 4 1
      Utilities/cmcurl/lib/curl_printf.h
  72. 6 9
      Utilities/cmcurl/lib/curl_range.c
  73. 2 1
      Utilities/cmcurl/lib/curl_rtmp.c
  74. 24 10
      Utilities/cmcurl/lib/curl_setup.h
  75. 2 7
      Utilities/cmcurl/lib/curl_sha256.h
  76. 41 34
      Utilities/cmcurl/lib/curl_sha512_256.c
  77. 1 1
      Utilities/cmcurl/lib/curl_sha512_256.h
  78. 13 13
      Utilities/cmcurl/lib/curl_sspi.c
  79. 2 2
      Utilities/cmcurl/lib/curl_sspi.h
  80. 2 0
      Utilities/cmcurl/lib/curl_threads.c
  81. 152 53
      Utilities/cmcurl/lib/curl_trc.c
  82. 32 0
      Utilities/cmcurl/lib/curl_trc.h
  83. 2 41
      Utilities/cmcurl/lib/curlx.h
  84. 1 1
      Utilities/cmcurl/lib/dict.c
  85. 266 259
      Utilities/cmcurl/lib/doh.c
  86. 40 19
      Utilities/cmcurl/lib/doh.h
  87. 70 89
      Utilities/cmcurl/lib/easy.c
  88. 2 2
      Utilities/cmcurl/lib/escape.c
  89. 2 3
      Utilities/cmcurl/lib/file.c
  90. 1 1
      Utilities/cmcurl/lib/fileinfo.h
  91. 3 3
      Utilities/cmcurl/lib/formdata.c
  92. 57 57
      Utilities/cmcurl/lib/ftp.c
  93. 30 18
      Utilities/cmcurl/lib/getinfo.c
  94. 2 2
      Utilities/cmcurl/lib/gopher.c
  95. 48 30
      Utilities/cmcurl/lib/hash.c
  96. 13 3
      Utilities/cmcurl/lib/hash.h
  97. 22 22
      Utilities/cmcurl/lib/headers.c
  98. 1 1
      Utilities/cmcurl/lib/headers.h
  99. 1 1
      Utilities/cmcurl/lib/hostasyn.c
  100. 49 44
      Utilities/cmcurl/lib/hostip.c

+ 1 - 4
.gitlab/ci/configure_macos_arm64_curl.cmake

@@ -3,10 +3,7 @@ set(CMAKE_USE_SYSTEM_CURL "OFF" CACHE BOOL "")
 
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
-
-# Test that our vendored curl accepts CURL_SSLVERSION_TLSv1_3.  It is passed
-# through to Secure Transport, but macOS does not actually enforce it.
-set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 1 - 1
Utilities/Scripts/update-curl.bash

@@ -8,7 +8,7 @@ readonly name="curl"
 readonly ownership="Curl Upstream <[email protected]>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-8_9_1"
+readonly tag="curl-8_10_1"
 readonly shortlog=false
 readonly paths="
   CMake/*

+ 29 - 34
Utilities/cmcurl/CMake/CurlSymbolHiding.cmake

@@ -23,7 +23,7 @@
 ###########################################################################
 include(CheckCSourceCompiles)
 
-option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
+option(CURL_HIDDEN_SYMBOLS "Hide libcurl internal symbols (=hide all symbols that are not officially external)" ON)
 mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 
 if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
@@ -34,52 +34,47 @@ if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
 endif()
 
 if(CURL_HIDDEN_SYMBOLS)
-  set(SUPPORTS_SYMBOL_HIDING FALSE)
+  set(_supports_symbol_hiding FALSE)
 
   if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)
-    set(SUPPORTS_SYMBOL_HIDING TRUE)
-    set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
-    set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+    set(_supports_symbol_hiding TRUE)
+    set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
+    set(_cflag_symbols_hide "-fvisibility=hidden")
   elseif(CMAKE_COMPILER_IS_GNUCC)
     if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
-      # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact
-      set(SUPPORTS_SYMBOL_HIDING TRUE)
-      set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
-      set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+      # Note: This is considered buggy prior to 4.0 but the autotools do not care, so let us ignore that fact
+      set(_supports_symbol_hiding TRUE)
+      set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
+      set(_cflag_symbols_hide "-fvisibility=hidden")
     endif()
   elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
-    set(SUPPORTS_SYMBOL_HIDING TRUE)
-    set(_SYMBOL_EXTERN "__global")
-    set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden")
+    set(_supports_symbol_hiding TRUE)
+    set(_symbol_extern "__global")
+    set(_cflag_symbols_hide "-xldscope=hidden")
   elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
-    # note: this should probably just check for version 9.1.045 but I'm not 100% sure
-    #       so let's do it the same way autotools do.
-    set(SUPPORTS_SYMBOL_HIDING TRUE)
-    set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
-    set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+    # Note: This should probably just check for version 9.1.045 but I am not 100% sure
+    #       so let us do it the same way autotools do.
+    set(_supports_symbol_hiding TRUE)
+    set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
+    set(_cflag_symbols_hide "-fvisibility=hidden")
     check_c_source_compiles("#include <stdio.h>
-        int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug)
+      int main(void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug)
     if(NOT _no_bug)
-      set(SUPPORTS_SYMBOL_HIDING FALSE)
-      set(_SYMBOL_EXTERN "")
-      set(_CFLAG_SYMBOLS_HIDE "")
+      set(_supports_symbol_hiding FALSE)
+      set(_symbol_extern "")
+      set(_cflag_symbols_hide "")
     endif()
   elseif(MSVC)
-    set(SUPPORTS_SYMBOL_HIDING TRUE)
+    set(_supports_symbol_hiding TRUE)
   endif()
 
-  set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING})
-elseif(MSVC)
-  if(NOT CMAKE_VERSION VERSION_LESS 3.7)
-    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken
-    set(HIDES_CURL_PRIVATE_SYMBOLS FALSE)
-  else()
-    message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.")
-    set(HIDES_CURL_PRIVATE_SYMBOLS TRUE)
-  endif()
+  set(CURL_HIDES_PRIVATE_SYMBOLS ${_supports_symbol_hiding})
 else()
-  set(HIDES_CURL_PRIVATE_SYMBOLS FALSE)
+  if(MSVC)
+    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+  endif()
+  set(CURL_HIDES_PRIVATE_SYMBOLS FALSE)
 endif()
 
-set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE})
-set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN})
+set(CURL_CFLAG_SYMBOLS_HIDE ${_cflag_symbols_hide})
+set(CURL_EXTERN_SYMBOL ${_symbol_extern})

+ 2 - 2
Utilities/cmcurl/CMake/CurlTests.c

@@ -152,7 +152,7 @@ int main(void) { return 0; }
 #define _FILE_OFFSET_BITS 64
 #include <sys/types.h>
  /* Check that off_t can represent 2**63 - 1 correctly.
-    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    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))
@@ -337,7 +337,7 @@ int main(void)
 #include <string.h>
 #include <errno.h>
 
-/* float, because a pointer can't be implicitly cast to float */
+/* Float, because a pointer cannot be implicitly cast to float */
 void check(float f) {}
 
 int main(void)

+ 32 - 5
Utilities/cmcurl/CMake/FindBearSSL.cmake

@@ -21,12 +21,39 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-find_path(BEARSSL_INCLUDE_DIRS bearssl.h)
+# Find the bearssl library
+#
+# Input variables:
+#
+# BEARSSL_INCLUDE_DIR   The bearssl include directory
+# BEARSSL_INCLUDE_DIRS  The bearssl include directory (deprecated)
+# BEARSSL_LIBRARY       Path to bearssl library
+#
+# Result variables:
+#
+# BEARSSL_FOUND         System has bearssl
+# BEARSSL_INCLUDE_DIRS  The bearssl include directories
+# BEARSSL_LIBRARIES     The bearssl library names
+
+if(DEFINED BEARSSL_INCLUDE_DIRS AND NOT DEFINED BEARSSL_INCLUDE_DIR)
+  message(WARNING "BEARSSL_INCLUDE_DIRS is deprecated, use BEARSSL_INCLUDE_DIR instead.")
+  set(BEARSSL_INCLUDE_DIR "${BEARSSL_INCLUDE_DIRS}")
+  unset(BEARSSL_INCLUDE_DIRS)
+endif()
 
-find_library(BEARSSL_LIBRARY bearssl)
+find_path(BEARSSL_INCLUDE_DIR NAMES "bearssl.h")
+find_library(BEARSSL_LIBRARY NAMES "bearssl")
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(BEARSSL DEFAULT_MSG
-  BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
+find_package_handle_standard_args(BearSSL
+  REQUIRED_VARS
+    BEARSSL_INCLUDE_DIR
+    BEARSSL_LIBRARY
+)
+
+if(BEARSSL_FOUND)
+  set(BEARSSL_INCLUDE_DIRS ${BEARSSL_INCLUDE_DIR})
+  set(BEARSSL_LIBRARIES    ${BEARSSL_LIBRARY})
+endif()
 
-mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
+mark_as_advanced(BEARSSL_INCLUDE_DIR BEARSSL_LIBRARY)

+ 48 - 11
Utilities/cmcurl/CMake/FindBrotli.cmake

@@ -21,23 +21,60 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-include(FindPackageHandleStandardArgs)
+# Find the brotli library
+#
+# Input variables:
+#
+# BROTLI_INCLUDE_DIR   The brotli include directory
+# BROTLICOMMON_LIBRARY Path to brotlicommon library
+# BROTLIDEC_LIBRARY    Path to brotlidec library
+#
+# Result variables:
+#
+# BROTLI_FOUND         System has brotli
+# BROTLI_INCLUDE_DIRS  The brotli include directories
+# BROTLI_LIBRARIES     The brotli library names
+# BROTLI_VERSION       Version of brotli
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_BROTLI "libbrotlidec")
+endif()
+
+find_path(BROTLI_INCLUDE_DIR "brotli/decode.h"
+  HINTS
+    ${PC_BROTLI_INCLUDEDIR}
+    ${PC_BROTLI_INCLUDE_DIRS}
+)
 
-find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
+find_library(BROTLICOMMON_LIBRARY NAMES "brotlicommon"
+  HINTS
+    ${PC_BROTLI_LIBDIR}
+    ${PC_BROTLI_LIBRARY_DIRS}
+)
+find_library(BROTLIDEC_LIBRARY NAMES "brotlidec"
+  HINTS
+    ${PC_BROTLI_LIBDIR}
+    ${PC_BROTLI_LIBRARY_DIRS}
+)
 
-find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
-find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
+if(PC_BROTLI_VERSION)
+  set(BROTLI_VERSION ${PC_BROTLI_VERSION})
+endif()
 
+include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Brotli
-  FOUND_VAR
-    BROTLI_FOUND
   REQUIRED_VARS
+    BROTLI_INCLUDE_DIR
     BROTLIDEC_LIBRARY
     BROTLICOMMON_LIBRARY
-    BROTLI_INCLUDE_DIR
-  FAIL_MESSAGE
-    "Could NOT find Brotli"
+  VERSION_VAR
+    BROTLI_VERSION
 )
 
-set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
-set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
+if(BROTLI_FOUND)
+  set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
+  set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
+endif()
+
+mark_as_advanced(BROTLI_INCLUDE_DIR BROTLIDEC_LIBRARY BROTLICOMMON_LIBRARY)

+ 0 - 47
Utilities/cmcurl/CMake/FindCARES.cmake

@@ -1,47 +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
-#
-###########################################################################
-# - Find c-ares
-# Find the c-ares includes and library
-# This module defines
-#  CARES_INCLUDE_DIR, where to find ares.h, etc.
-#  CARES_LIBRARIES, the libraries needed to use c-ares.
-#  CARES_FOUND, If false, do not try to use c-ares.
-# also defined, but not for general use are
-# CARES_LIBRARY, where to find the c-ares library.
-
-find_path(CARES_INCLUDE_DIR ares.h)
-
-set(CARES_NAMES ${CARES_NAMES} cares)
-find_library(CARES_LIBRARY
-  NAMES ${CARES_NAMES}
-  )
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(CARES
-  REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)
-
-mark_as_advanced(
-  CARES_LIBRARY
-  CARES_INCLUDE_DIR
-  )

+ 80 - 0
Utilities/cmcurl/CMake/FindCares.cmake

@@ -0,0 +1,80 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the c-ares library
+#
+# Input variables:
+#
+# CARES_INCLUDE_DIR   The c-ares include directory
+# CARES_LIBRARY       Path to c-ares library
+#
+# Result variables:
+#
+# CARES_FOUND         System has c-ares
+# CARES_INCLUDE_DIRS  The c-ares include directories
+# CARES_LIBRARIES     The c-ares library names
+# CARES_VERSION       Version of c-ares
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_CARES "libcares")
+endif()
+
+find_path(CARES_INCLUDE_DIR NAMES "ares.h"
+  HINTS
+    ${PC_CARES_INCLUDEDIR}
+    ${PC_CARES_INCLUDE_DIRS}
+)
+
+find_library(CARES_LIBRARY NAMES ${CARES_NAMES} "cares"
+  HINTS
+    ${PC_CARES_LIBDIR}
+    ${PC_CARES_LIBRARY_DIRS}
+)
+
+if(PC_CARES_VERSION)
+  set(CARES_VERSION ${PC_CARES_VERSION})
+elseif(CARES_INCLUDE_DIR AND EXISTS "${CARES_INCLUDE_DIR}/ares_version.h")
+  set(_version_regex "#[\t ]*define[\t ]+ARES_VERSION_STR[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(CARES_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Cares
+  REQUIRED_VARS
+    CARES_INCLUDE_DIR
+    CARES_LIBRARY
+  VERSION_VAR
+    CARES_VERSION
+)
+
+if(CARES_FOUND)
+  set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIR})
+  set(CARES_LIBRARIES    ${CARES_LIBRARY})
+endif()
+
+mark_as_advanced(CARES_INCLUDE_DIR CARES_LIBRARY)

+ 139 - 130
Utilities/cmcurl/CMake/FindGSS.cmake

@@ -21,275 +21,276 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# - Try to find the GSS Kerberos library
-# Once done this will define
+# Find the GSS Kerberos library
 #
-#  GSS_ROOT_DIR - Set this variable to the root installation of GSS
+# Input variables:
 #
-# Read-Only variables:
-#  GSS_FOUND - system has the Heimdal library
-#  GSS_FLAVOUR - "MIT" or "Heimdal" if anything found.
-#  GSS_INCLUDE_DIR - the Heimdal include directory
-#  GSS_LIBRARIES - The libraries needed to use GSS
-#  GSS_LINK_DIRECTORIES - Directories to add to linker search path
-#  GSS_LINKER_FLAGS - Additional linker flags
-#  GSS_COMPILER_FLAGS - Additional compiler flags
-#  GSS_VERSION - This is set to version advertised by pkg-config or read from manifest.
-#                In case the library is found but no version info available it'll be set to "unknown"
-
-set(_MIT_MODNAME mit-krb5-gssapi)
-set(_HEIMDAL_MODNAME heimdal-gssapi)
+# GSS_ROOT_DIR      Set this variable to the root installation of GSS
+#
+# Result variables:
+#
+# GSS_FOUND         System has the Heimdal library
+# GSS_FLAVOUR       "MIT" or "Heimdal" if anything found
+# GSS_INCLUDE_DIRS  The GSS include directories
+# GSS_LIBRARIES     The GSS library names
+# GSS_LIBRARY_DIRS  The GSS library directories
+# GSS_LDFLAGS       Required linker flags
+# GSS_CFLAGS        Required compiler flags
+# GSS_VERSION       This is set to version advertised by pkg-config or read from manifest.
+#                   In case the library is found but no version info available it is set to "unknown"
+
+set(_mit_modname "mit-krb5-gssapi")
+set(_heimdal_modname "heimdal-gssapi")
 
 include(CheckIncludeFile)
 include(CheckIncludeFiles)
 include(CheckTypeSize)
 
-set(_GSS_ROOT_HINTS
+set(_gss_root_hints
   "${GSS_ROOT_DIR}"
   "$ENV{GSS_ROOT_DIR}"
 )
 
-# try to find library using system pkg-config if user didn't specify root dir
+# Try to find library using system pkg-config if user did not specify root dir
 if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
-  if(UNIX)
+  if(CURL_USE_PKGCONFIG)
     find_package(PkgConfig QUIET)
-    pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME})
-    list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}")
-  elseif(WIN32)
-    list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
+    pkg_search_module(_GSS ${_mit_modname} ${_heimdal_modname})
+    list(APPEND _gss_root_hints "${_GSS_PREFIX}")
+  endif()
+  if(WIN32)
+    list(APPEND _gss_root_hints "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
   endif()
 endif()
 
-if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
-  find_file(_GSS_CONFIGURE_SCRIPT
+if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional approach.
+  find_file(_gss_configure_script
     NAMES
       "krb5-config"
     HINTS
-      ${_GSS_ROOT_HINTS}
+      ${_gss_root_hints}
     PATH_SUFFIXES
-      bin
+      "bin"
     NO_CMAKE_PATH
     NO_CMAKE_ENVIRONMENT_PATH
   )
 
-  # if not found in user-supplied directories, maybe system knows better
-  find_file(_GSS_CONFIGURE_SCRIPT
+  # If not found in user-supplied directories, maybe system knows better
+  find_file(_gss_configure_script
     NAMES
       "krb5-config"
     PATH_SUFFIXES
-      bin
+      "bin"
   )
 
-  if(_GSS_CONFIGURE_SCRIPT)
+  if(_gss_configure_script)
     execute_process(
-      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
+      COMMAND ${_gss_configure_script} "--cflags" "gssapi"
       OUTPUT_VARIABLE _GSS_CFLAGS
-      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
-      )
-    message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
-    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
-      # should also work in an odd case when multiple directories are given
+    )
+    message(STATUS "FindGSS CFLAGS: ${_GSS_CFLAGS}")
+    if(NOT _gss_configure_failed)  # 0 means success
+      # Should also work in an odd case when multiple directories are given
       string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
       string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
       string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
 
-      foreach(_flag ${_GSS_CFLAGS})
+      foreach(_flag IN LISTS _GSS_CFLAGS)
         if(_flag MATCHES "^-I.*")
           string(REGEX REPLACE "^-I" "" _val "${_flag}")
-          list(APPEND _GSS_INCLUDE_DIR "${_val}")
+          list(APPEND _GSS_INCLUDE_DIRS "${_val}")
         else()
-          list(APPEND _GSS_COMPILER_FLAGS "${_flag}")
+          list(APPEND _GSS_CFLAGS "${_flag}")
         endif()
       endforeach()
     endif()
 
     execute_process(
-      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
-      OUTPUT_VARIABLE _GSS_LIB_FLAGS
-      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      COMMAND ${_gss_configure_script} "--libs" "gssapi"
+      OUTPUT_VARIABLE _gss_lib_flags
+      RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
-    message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")
+    message(STATUS "FindGSS LDFLAGS: ${_gss_lib_flags}")
 
-    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
-      # this script gives us libraries and link directories. Blah. We have to deal with it.
-      string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
-      string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
-      string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
+    if(NOT _gss_configure_failed)  # 0 means success
+      # This script gives us libraries and link directories. Blah. We have to deal with it.
+      string(STRIP "${_gss_lib_flags}" _gss_lib_flags)
+      string(REGEX REPLACE " +-(L|l)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
+      string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
 
-      foreach(_flag ${_GSS_LIB_FLAGS})
+      foreach(_flag IN LISTS _gss_lib_flags)
         if(_flag MATCHES "^-l.*")
           string(REGEX REPLACE "^-l" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARIES "${_val}")
         elseif(_flag MATCHES "^-L.*")
           string(REGEX REPLACE "^-L" "" _val "${_flag}")
-          list(APPEND _GSS_LINK_DIRECTORIES "${_val}")
+          list(APPEND _GSS_LIBRARY_DIRS "${_val}")
         else()
-          list(APPEND _GSS_LINKER_FLAGS "${_flag}")
+          list(APPEND _GSS_LDFLAGS "${_flag}")
         endif()
       endforeach()
     endif()
 
     execute_process(
-      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
+      COMMAND ${_gss_configure_script} "--version"
       OUTPUT_VARIABLE _GSS_VERSION
-      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
 
-    # older versions may not have the "--version" parameter. In this case we just don't care.
-    if(_GSS_CONFIGURE_FAILED)
+    # Older versions may not have the "--version" parameter. In this case we just do not care.
+    if(_gss_configure_failed)
       set(_GSS_VERSION 0)
     endif()
 
     execute_process(
-      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
-      OUTPUT_VARIABLE _GSS_VENDOR
-      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      COMMAND ${_gss_configure_script} "--vendor"
+      OUTPUT_VARIABLE _gss_vendor
+      RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
 
-    # older versions may not have the "--vendor" parameter. In this case we just don't care.
-    if(_GSS_CONFIGURE_FAILED)
-      set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter
+    # Older versions may not have the "--vendor" parameter. In this case we just do not care.
+    if(_gss_configure_failed)
+      set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
     else()
-      if(_GSS_VENDOR MATCHES ".*H|heimdal.*")
+      if(_gss_vendor MATCHES ".*H|heimdal.*")
         set(GSS_FLAVOUR "Heimdal")
       else()
         set(GSS_FLAVOUR "MIT")
       endif()
     endif()
 
-  else() # either there is no config script or we are on a platform that doesn't provide one (Windows?)
+  else()  # Either there is no config script or we are on a platform that does not provide one (Windows?)
 
-    find_path(_GSS_INCLUDE_DIR
-      NAMES
-        "gssapi/gssapi.h"
+    find_path(_GSS_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
       HINTS
-        ${_GSS_ROOT_HINTS}
+        ${_gss_root_hints}
       PATH_SUFFIXES
-        include
-        inc
+        "include"
+        "inc"
     )
 
-    if(_GSS_INCLUDE_DIR) #jay, we've found something
-      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}")
-      check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS)
+    if(_GSS_INCLUDE_DIRS)  # jay, we have found something
+      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
+      check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
 
-      if(_GSS_HAVE_MIT_HEADERS)
+      if(_gss_have_mit_headers)
         set(GSS_FLAVOUR "MIT")
       else()
-        # prevent compiling the header - just check if we can include it
-        list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__)
-        check_include_file( "roken.h" _GSS_HAVE_ROKEN_H)
+        # Prevent compiling the header - just check if we can include it
+        list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
+        check_include_file("roken.h" _gss_have_roken_h)
 
-        check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H)
-        if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H)
+        check_include_file("heimdal/roken.h" _gss_have_heimdal_roken_h)
+        if(_gss_have_roken_h OR _gss_have_heimdal_roken_h)
           set(GSS_FLAVOUR "Heimdal")
         endif()
-        list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__)
+        list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
       endif()
     else()
-      # I'm not convinced if this is the right way but this is what autotools do at the moment
-      find_path(_GSS_INCLUDE_DIR
-        NAMES
-          "gssapi.h"
+      # I am not convinced if this is the right way but this is what autotools do at the moment
+      find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
         HINTS
-          ${_GSS_ROOT_HINTS}
+          ${_gss_root_hints}
         PATH_SUFFIXES
-          include
-          inc
+          "include"
+          "inc"
       )
 
-      if(_GSS_INCLUDE_DIR)
+      if(_GSS_INCLUDE_DIRS)
         set(GSS_FLAVOUR "Heimdal")
       endif()
     endif()
 
-    # if we have headers, check if we can link libraries
+    # If we have headers, check if we can link libraries
     if(GSS_FLAVOUR)
-      set(_GSS_LIBDIR_SUFFIXES "")
-      set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS})
-      get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH)
-      list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT})
+      set(_gss_libdir_suffixes "")
+      set(_gss_libdir_hints ${_gss_root_hints})
+      get_filename_component(_gss_calculated_potential_root "${_GSS_INCLUDE_DIRS}" DIRECTORY)
+      list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
 
       if(WIN32)
         if(CMAKE_SIZEOF_VOID_P EQUAL 8)
-          list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64")
+          list(APPEND _gss_libdir_suffixes "lib/AMD64")
           if(GSS_FLAVOUR STREQUAL "MIT")
-            set(_GSS_LIBNAME "gssapi64")
+            set(_gss_libname "gssapi64")
           else()
-            set(_GSS_LIBNAME "libgssapi")
+            set(_gss_libname "libgssapi")
           endif()
         else()
-          list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386")
+          list(APPEND _gss_libdir_suffixes "lib/i386")
           if(GSS_FLAVOUR STREQUAL "MIT")
-            set(_GSS_LIBNAME "gssapi32")
+            set(_gss_libname "gssapi32")
           else()
-            set(_GSS_LIBNAME "libgssapi")
+            set(_gss_libname "libgssapi")
           endif()
         endif()
       else()
-        list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS
+        list(APPEND _gss_libdir_suffixes "lib;lib64")  # those suffixes are not checked for HINTS
         if(GSS_FLAVOUR STREQUAL "MIT")
-          set(_GSS_LIBNAME "gssapi_krb5")
+          set(_gss_libname "gssapi_krb5")
         else()
-          set(_GSS_LIBNAME "gssapi")
+          set(_gss_libname "gssapi")
         endif()
       endif()
 
-      find_library(_GSS_LIBRARIES
-        NAMES
-          ${_GSS_LIBNAME}
+      find_library(_GSS_LIBRARIES NAMES ${_gss_libname}
         HINTS
-          ${_GSS_LIBDIR_HINTS}
+          ${_gss_libdir_hints}
         PATH_SUFFIXES
-          ${_GSS_LIBDIR_SUFFIXES}
+          ${_gss_libdir_suffixes}
       )
-
     endif()
   endif()
 else()
-  if(_GSS_PKG_${_MIT_MODNAME}_VERSION)
+  if(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)  # _GSS_MODULE_NAME set since CMake 3.16
     set(GSS_FLAVOUR "MIT")
-    set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION)
+    if(NOT _GSS_VERSION)  # for old CMake versions?
+      set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
+    endif()
   else()
     set(GSS_FLAVOUR "Heimdal")
-    set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION)
+    if(NOT _GSS_VERSION)  # for old CMake versions?
+      set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
+    endif()
   endif()
+  message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
 endif()
 
-set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR})
+set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
 set(GSS_LIBRARIES ${_GSS_LIBRARIES})
-set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES})
-set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS})
-set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS})
+set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
+set(GSS_LDFLAGS ${_GSS_LDFLAGS})
+set(GSS_CFLAGS ${_GSS_CFLAGS})
 set(GSS_VERSION ${_GSS_VERSION})
 
 if(GSS_FLAVOUR)
   if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
     if(CMAKE_SIZEOF_VOID_P EQUAL 8)
-      set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest")
+      set(_heimdal_manifest_file "Heimdal.Application.amd64.manifest")
     else()
-      set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest")
+      set(_heimdal_manifest_file "Heimdal.Application.x86.manifest")
     endif()
 
-    if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}")
-      file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str
-           REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")
+    if(EXISTS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}")
+      file(STRINGS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}" _heimdal_version_str
+        REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")
 
-      string(REGEX MATCH "[0-9]\\.[^\"]+"
-             GSS_VERSION "${heimdal_version_str}")
+      string(REGEX MATCH "[0-9]\\.[^\"]+" GSS_VERSION "${_heimdal_version_str}")
     endif()
 
     if(NOT GSS_VERSION)
       set(GSS_VERSION "Heimdal Unknown")
     endif()
   elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT")
-    get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE)
-    if(WIN32 AND _MIT_VERSION)
-      set(GSS_VERSION "${_MIT_VERSION}")
+    get_filename_component(_mit_version "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME
+      CACHE)
+    if(WIN32 AND _mit_version)
+      set(GSS_VERSION "${_mit_version}")
     else()
       set(GSS_VERSION "MIT Unknown")
     endif()
@@ -297,16 +298,24 @@ if(GSS_FLAVOUR)
 endif()
 
 include(FindPackageHandleStandardArgs)
-
-set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)
-
 find_package_handle_standard_args(GSS
   REQUIRED_VARS
-    ${_GSS_REQUIRED_VARS}
+    GSS_FLAVOUR
+    GSS_LIBRARIES
   VERSION_VAR
     GSS_VERSION
   FAIL_MESSAGE
     "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
 )
 
-mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)
+mark_as_advanced(
+  _GSS_CFLAGS
+  _GSS_FOUND
+  _GSS_INCLUDE_DIRS
+  _GSS_LDFLAGS
+  _GSS_LIBRARIES
+  _GSS_LIBRARY_DIRS
+  _GSS_MODULE_NAME
+  _GSS_PREFIX
+  _GSS_VERSION
+)

+ 0 - 45
Utilities/cmcurl/CMake/FindLibSSH2.cmake

@@ -1,45 +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
-#
-###########################################################################
-# - Try to find the libssh2 library
-# Once done this will define
-#
-# LIBSSH2_FOUND - system has the libssh2 library
-# LIBSSH2_INCLUDE_DIR - the libssh2 include directory
-# LIBSSH2_LIBRARY - the libssh2 library name
-
-find_path(LIBSSH2_INCLUDE_DIR libssh2.h)
-
-find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2)
-
-if(LIBSSH2_INCLUDE_DIR)
-  file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"")
-  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBSSH2_VERSION "${libssh2_version_str}")
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(LibSSH2
-  REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
-  VERSION_VAR LIBSSH2_VERSION)
-
-mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)

+ 78 - 0
Utilities/cmcurl/CMake/FindLibgsasl.cmake

@@ -0,0 +1,78 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libgsasl library
+#
+# Input variables:
+#
+# LIBGSASL_INCLUDE_DIR   The libgsasl include directory
+# LIBGSASL_LIBRARY       Path to libgsasl library
+#
+# Result variables:
+#
+# LIBGSASL_FOUND         System has libgsasl
+# LIBGSASL_INCLUDE_DIRS  The libgsasl include directories
+# LIBGSASL_LIBRARIES     The libgsasl library names
+# LIBGSASL_LIBRARY_DIRS  The libgsasl library directories
+# LIBGSASL_CFLAGS        Required compiler flags
+# LIBGSASL_VERSION       Version of libgsasl
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBGSASL_INCLUDE_DIR AND
+   NOT DEFINED LIBGSASL_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LIBGSASL "libgsasl")
+endif()
+
+if(LIBGSASL_FOUND)
+  string(REPLACE ";" " " LIBGSASL_CFLAGS "${LIBGSASL_CFLAGS}")
+  message(STATUS "Found Libgsasl (via pkg-config): ${LIBGSASL_INCLUDE_DIRS} (found version \"${LIBGSASL_VERSION}\")")
+else()
+  find_path(LIBGSASL_INCLUDE_DIR NAMES "gsasl.h")
+  find_library(LIBGSASL_LIBRARY NAMES "gsasl" "libgsasl")
+
+  if(LIBGSASL_INCLUDE_DIR AND EXISTS "${LIBGSASL_INCLUDE_DIR}/gsasl-version.h")
+    set(_version_regex "#[\t ]*define[\t ]+GSASL_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${LIBGSASL_INCLUDE_DIR}/gsasl-version.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(LIBGSASL_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+    find_package_handle_standard_args(Libgsasl
+    REQUIRED_VARS
+      LIBGSASL_INCLUDE_DIR
+      LIBGSASL_LIBRARY
+    VERSION_VAR
+      LIBGSASL_VERSION
+  )
+
+  if(LIBGSASL_FOUND)
+    set(LIBGSASL_INCLUDE_DIRS ${LIBGSASL_INCLUDE_DIR})
+    set(LIBGSASL_LIBRARIES    ${LIBGSASL_LIBRARY})
+  endif()
+
+  mark_as_advanced(LIBGSASL_INCLUDE_DIR LIBGSASL_LIBRARY)
+endif()

+ 78 - 0
Utilities/cmcurl/CMake/FindLibidn2.cmake

@@ -0,0 +1,78 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libidn2 library
+#
+# Input variables:
+#
+# LIBIDN2_INCLUDE_DIR   The libidn2 include directory
+# LIBIDN2_LIBRARY       Path to libidn2 library
+#
+# Result variables:
+#
+# LIBIDN2_FOUND         System has libidn2
+# LIBIDN2_INCLUDE_DIRS  The libidn2 include directories
+# LIBIDN2_LIBRARIES     The libidn2 library names
+# LIBIDN2_LIBRARY_DIRS  The libidn2 library directories
+# LIBIDN2_CFLAGS        Required compiler flags
+# LIBIDN2_VERSION       Version of libidn2
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBIDN2_INCLUDE_DIR AND
+   NOT DEFINED LIBIDN2_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LIBIDN2 "libidn2")
+endif()
+
+if(LIBIDN2_FOUND)
+  string(REPLACE ";" " " LIBIDN2_CFLAGS "${LIBIDN2_CFLAGS}")
+  message(STATUS "Found Libidn2 (via pkg-config): ${LIBIDN2_INCLUDE_DIRS} (found version \"${LIBIDN2_VERSION}\")")
+else()
+  find_path(LIBIDN2_INCLUDE_DIR NAMES "idn2.h")
+  find_library(LIBIDN2_LIBRARY NAMES "idn2" "libidn2")
+
+  if(LIBIDN2_INCLUDE_DIR AND EXISTS "${LIBIDN2_INCLUDE_DIR}/idn2.h")
+    set(_version_regex "#[\t ]*define[\t ]+IDN2_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${LIBIDN2_INCLUDE_DIR}/idn2.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(LIBIDN2_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Libidn2
+    REQUIRED_VARS
+      LIBIDN2_INCLUDE_DIR
+      LIBIDN2_LIBRARY
+    VERSION_VAR
+      LIBIDN2_VERSION
+  )
+
+  if(LIBIDN2_FOUND)
+    set(LIBIDN2_INCLUDE_DIRS ${LIBIDN2_INCLUDE_DIR})
+    set(LIBIDN2_LIBRARIES    ${LIBIDN2_LIBRARY})
+  endif()
+
+  mark_as_advanced(LIBIDN2_INCLUDE_DIR LIBIDN2_LIBRARY)
+endif()

+ 80 - 0
Utilities/cmcurl/CMake/FindLibpsl.cmake

@@ -0,0 +1,80 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libpsl library
+#
+# Input variables:
+#
+# LIBPSL_INCLUDE_DIR   The libpsl include directory
+# LIBPSL_LIBRARY       Path to libpsl library
+#
+# Result variables:
+#
+# LIBPSL_FOUND         System has libpsl
+# LIBPSL_INCLUDE_DIRS  The libpsl include directories
+# LIBPSL_LIBRARIES     The libpsl library names
+# LIBPSL_VERSION       Version of libpsl
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_LIBPSL "libpsl")
+endif()
+
+find_path(LIBPSL_INCLUDE_DIR NAMES "libpsl.h"
+  HINTS
+    ${PC_LIBPSL_INCLUDEDIR}
+    ${PC_LIBPSL_INCLUDE_DIRS}
+)
+
+find_library(LIBPSL_LIBRARY NAMES "psl" "libpsl"
+  HINTS
+    ${PC_LIBPSL_LIBDIR}
+    ${PC_LIBPSL_LIBRARY_DIRS}
+)
+
+if(PC_LIBPSL_VERSION)
+  set(LIBPSL_VERSION ${PC_LIBPSL_VERSION})
+elseif(LIBPSL_INCLUDE_DIR AND EXISTS "${LIBPSL_INCLUDE_DIR}/libpsl.h")
+  set(_version_regex "#[\t ]*define[\t ]+PSL_VERSION[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(LIBPSL_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libpsl
+  REQUIRED_VARS
+    LIBPSL_INCLUDE_DIR
+    LIBPSL_LIBRARY
+  VERSION_VAR
+    LIBPSL_VERSION
+)
+
+if(LIBPSL_FOUND)
+  set(LIBPSL_INCLUDE_DIRS ${LIBPSL_INCLUDE_DIR})
+  set(LIBPSL_LIBRARIES    ${LIBPSL_LIBRARY})
+endif()
+
+mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)

+ 92 - 0
Utilities/cmcurl/CMake/FindLibssh.cmake

@@ -0,0 +1,92 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libssh library
+#
+# Input variables:
+#
+# LIBSSH_INCLUDE_DIR   The libssh include directory
+# LIBSSH_LIBRARY       Path to libssh library
+#
+# Result variables:
+#
+# LIBSSH_FOUND         System has libssh
+# LIBSSH_INCLUDE_DIRS  The libssh include directories
+# LIBSSH_LIBRARIES     The libssh library names
+# LIBSSH_LIBRARY_DIRS  The libssh library directories
+# LIBSSH_CFLAGS        Required compiler flags
+# LIBSSH_VERSION       Version of libssh
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBSSH_INCLUDE_DIR AND
+   NOT DEFINED LIBSSH_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LIBSSH "libssh")
+endif()
+
+if(LIBSSH_FOUND)
+  string(REPLACE ";" " " LIBSSH_CFLAGS "${LIBSSH_CFLAGS}")
+  message(STATUS "Found Libssh (via pkg-config): ${LIBSSH_INCLUDE_DIRS} (found version \"${LIBSSH_VERSION}\")")
+else()
+  find_path(LIBSSH_INCLUDE_DIR NAMES "libssh/libssh.h")
+  find_library(LIBSSH_LIBRARY NAMES "ssh" "libssh")
+
+  if(LIBSSH_INCLUDE_DIR AND EXISTS "${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h")
+    set(_version_regex1 "#[\t ]*define[\t ]+LIBSSH_VERSION_MAJOR[\t ]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[\t ]+LIBSSH_VERSION_MINOR[\t ]+([0-9]+).*")
+    set(_version_regex3 "#[\t ]*define[\t ]+LIBSSH_VERSION_MICRO[\t ]+([0-9]+).*")
+    file(STRINGS "${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h" _version_str2 REGEX "${_version_regex2}")
+    file(STRINGS "${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h" _version_str3 REGEX "${_version_regex3}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+    set(LIBSSH_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_regex3)
+    unset(_version_str1)
+    unset(_version_str2)
+    unset(_version_str3)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Libssh
+    REQUIRED_VARS
+      LIBSSH_INCLUDE_DIR
+      LIBSSH_LIBRARY
+    VERSION_VAR
+      LIBSSH_VERSION
+  )
+
+  if(LIBSSH_FOUND)
+    set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR})
+    set(LIBSSH_LIBRARIES    ${LIBSSH_LIBRARY})
+  endif()
+
+  mark_as_advanced(LIBSSH_INCLUDE_DIR LIBSSH_LIBRARY)
+endif()
+
+if(LIBSSH_FOUND AND WIN32)
+  list(APPEND LIBSSH_LIBRARIES "iphlpapi")  # for if_nametoindex
+endif()

+ 80 - 0
Utilities/cmcurl/CMake/FindLibssh2.cmake

@@ -0,0 +1,80 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libssh2 library
+#
+# Input variables:
+#
+# LIBSSH2_INCLUDE_DIR   The libssh2 include directory
+# LIBSSH2_LIBRARY       Path to libssh2 library
+#
+# Result variables:
+#
+# LIBSSH2_FOUND         System has libssh2
+# LIBSSH2_INCLUDE_DIRS  The libssh2 include directories
+# LIBSSH2_LIBRARIES     The libssh2 library names
+# LIBSSH2_VERSION       Version of libssh2
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_LIBSSH2 "libssh2")
+endif()
+
+find_path(LIBSSH2_INCLUDE_DIR NAMES "libssh2.h"
+  HINTS
+    ${PC_LIBSSH2_INCLUDEDIR}
+    ${PC_LIBSSH2_INCLUDE_DIRS}
+)
+
+find_library(LIBSSH2_LIBRARY NAMES "ssh2" "libssh2"
+  HINTS
+    ${PC_LIBSSH2_LIBDIR}
+    ${PC_LIBSSH2_LIBRARY_DIRS}
+)
+
+if(PC_LIBSSH2_VERSION)
+  set(LIBSSH2_VERSION ${PC_LIBSSH2_VERSION})
+elseif(LIBSSH2_INCLUDE_DIR AND EXISTS "${LIBSSH2_INCLUDE_DIR}/libssh2.h")
+  set(_version_regex "#[\t ]*define[\t ]+LIBSSH2_VERSION[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(LIBSSH2_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libssh2
+  REQUIRED_VARS
+    LIBSSH2_INCLUDE_DIR
+    LIBSSH2_LIBRARY
+  VERSION_VAR
+    LIBSSH2_VERSION
+)
+
+if(LIBSSH2_FOUND)
+  set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR})
+  set(LIBSSH2_LIBRARIES    ${LIBSSH2_LIBRARY})
+endif()
+
+mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)

+ 88 - 0
Utilities/cmcurl/CMake/FindLibuv.cmake

@@ -0,0 +1,88 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the libuv library
+#
+# Input variables:
+#
+# LIBUV_INCLUDE_DIR   The libuv include directory
+# LIBUV_LIBRARY       Path to libuv library
+#
+# Result variables:
+#
+# LIBUV_FOUND         System has libuv
+# LIBUV_INCLUDE_DIRS  The libuv include directories
+# LIBUV_LIBRARIES     The libuv library names
+# LIBUV_LIBRARY_DIRS  The libuv library directories
+# LIBUV_CFLAGS        Required compiler flags
+# LIBUV_VERSION       Version of libuv
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBUV_INCLUDE_DIR AND
+   NOT DEFINED LIBUV_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LIBUV "libuv")
+endif()
+
+if(LIBUV_FOUND)
+  string(REPLACE ";" " " LIBUV_CFLAGS "${LIBUV_CFLAGS}")
+  message(STATUS "Found Libuv (via pkg-config): ${LIBUV_INCLUDE_DIRS} (found version \"${LIBUV_VERSION}\")")
+else()
+  find_path(LIBUV_INCLUDE_DIR NAMES "uv.h")
+  find_library(LIBUV_LIBRARY NAMES "uv" "libuv")
+
+  if(LIBUV_INCLUDE_DIR AND EXISTS "${LIBUV_INCLUDE_DIR}/uv/version.h")
+    set(_version_regex1 "#[\t ]*define[\t ]+UV_VERSION_MAJOR[\t ]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[\t ]+UV_VERSION_MINOR[\t ]+([0-9]+).*")
+    set(_version_regex3 "#[\t ]*define[\t ]+UV_VERSION_PATCH[\t ]+([0-9]+).*")
+    file(STRINGS "${LIBUV_INCLUDE_DIR}/uv/version.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${LIBUV_INCLUDE_DIR}/uv/version.h" _version_str2 REGEX "${_version_regex2}")
+    file(STRINGS "${LIBUV_INCLUDE_DIR}/uv/version.h" _version_str3 REGEX "${_version_regex3}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+    set(LIBUV_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_regex3)
+    unset(_version_str1)
+    unset(_version_str2)
+    unset(_version_str3)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Libuv
+    REQUIRED_VARS
+      LIBUV_INCLUDE_DIR
+      LIBUV_LIBRARY
+    VERSION_VAR
+      LIBUV_VERSION
+  )
+
+  if(LIBUV_FOUND)
+    set(LIBUV_INCLUDE_DIRS ${LIBUV_INCLUDE_DIR})
+    set(LIBUV_LIBRARIES    ${LIBUV_LIBRARY})
+  endif()
+
+  mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY)
+endif()

+ 26 - 23
Utilities/cmcurl/CMake/FindMSH3.cmake

@@ -21,50 +21,53 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the msh3 library
+#
+# Input variables:
+#
+# MSH3_INCLUDE_DIR   The msh3 include directory
+# MSH3_LIBRARY       Path to msh3 library
+#
+# Result variables:
+#
+# MSH3_FOUND         System has msh3
+# MSH3_INCLUDE_DIRS  The msh3 include directories
+# MSH3_LIBRARIES     The msh3 library names
+# MSH3_VERSION       Version of msh3
 
-#[=======================================================================[.rst:
-FindMSH3
-----------
-
-Find the msh3 library
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-``MSH3_FOUND``
-  System has msh3
-``MSH3_INCLUDE_DIRS``
-  The msh3 include directories.
-``MSH3_LIBRARIES``
-  The libraries needed to use msh3
-#]=======================================================================]
-if(UNIX)
+if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
-  pkg_search_module(PC_MSH3 libmsh3)
+  pkg_check_modules(PC_MSH3 "libmsh3")
 endif()
 
-find_path(MSH3_INCLUDE_DIR msh3.h
+find_path(MSH3_INCLUDE_DIR NAMES "msh3.h"
   HINTS
     ${PC_MSH3_INCLUDEDIR}
     ${PC_MSH3_INCLUDE_DIRS}
 )
 
-find_library(MSH3_LIBRARY NAMES msh3
+find_library(MSH3_LIBRARY NAMES "msh3"
   HINTS
     ${PC_MSH3_LIBDIR}
     ${PC_MSH3_LIBRARY_DIRS}
 )
 
+if(PC_MSH3_VERSION)
+  set(MSH3_VERSION ${PC_MSH3_VERSION})
+endif()
+
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(MSH3
   REQUIRED_VARS
-    MSH3_LIBRARY
     MSH3_INCLUDE_DIR
+    MSH3_LIBRARY
+  VERSION_VAR
+    MSH3_VERSION
 )
 
 if(MSH3_FOUND)
-  set(MSH3_LIBRARIES    ${MSH3_LIBRARY})
   set(MSH3_INCLUDE_DIRS ${MSH3_INCLUDE_DIR})
+  set(MSH3_LIBRARIES    ${MSH3_LIBRARY})
 endif()
 
-mark_as_advanced(MSH3_INCLUDE_DIRS MSH3_LIBRARIES)
+mark_as_advanced(MSH3_INCLUDE_DIR MSH3_LIBRARY)

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

@@ -21,16 +21,91 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
+# Find the mbedtls library
+#
+# Input variables:
+#
+# MBEDTLS_INCLUDE_DIR   The mbedtls include directory
+# MBEDTLS_INCLUDE_DIRS  The mbedtls include directory (deprecated)
+# MBEDTLS_LIBRARY       Path to mbedtls library
+# MBEDX509_LIBRARY      Path to mbedx509 library
+# MBEDCRYPTO_LIBRARY    Path to mbedcrypto library
+#
+# Result variables:
+#
+# MBEDTLS_FOUND         System has mbedtls
+# MBEDTLS_INCLUDE_DIRS  The mbedtls include directories
+# MBEDTLS_LIBRARIES     The mbedtls library names
+# MBEDTLS_VERSION       Version of mbedtls
 
-find_library(MBEDTLS_LIBRARY mbedtls)
-find_library(MBEDX509_LIBRARY mbedx509)
-find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
+if(DEFINED MBEDTLS_INCLUDE_DIRS AND NOT DEFINED MBEDTLS_INCLUDE_DIR)
+  message(WARNING "MBEDTLS_INCLUDE_DIRS is deprecated, use MBEDTLS_INCLUDE_DIR instead.")
+  set(MBEDTLS_INCLUDE_DIR "${MBEDTLS_INCLUDE_DIRS}")
+  unset(MBEDTLS_INCLUDE_DIRS)
+endif()
 
-set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_MBEDTLS "mbedtls")
+endif()
+
+find_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h"
+  HINTS
+    ${PC_MBEDTLS_INCLUDEDIR}
+    ${PC_MBEDTLS_INCLUDE_DIRS}
+)
+
+find_library(MBEDTLS_LIBRARY NAMES "mbedtls"
+  HINTS
+    ${PC_MBEDTLS_LIBDIR}
+    ${PC_MBEDTLS_LIBRARY_DIRS}
+)
+find_library(MBEDX509_LIBRARY NAMES "mbedx509"
+  HINTS
+    ${PC_MBEDTLS_LIBDIR}
+    ${PC_MBEDTLS_LIBRARY_DIRS}
+)
+find_library(MBEDCRYPTO_LIBRARY NAMES "mbedcrypto"
+  HINTS
+    ${PC_MBEDTLS_LIBDIR}
+    ${PC_MBEDTLS_LIBRARY_DIRS}
+)
+
+if(PC_MBEDTLS_VERSION)
+  set(MBEDTLS_VERSION ${PC_MBEDTLS_VERSION})
+elseif(MBEDTLS_INCLUDE_DIR)
+  if(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")  # 3.x
+    set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
+  elseif(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")  # 2.x
+    set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+  else()
+    unset(_version_header)
+  endif()
+  if(_version_header)
+    set(_version_regex "#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"([0-9.]+)\"")
+    file(STRINGS "${_version_header}" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(MBEDTLS_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+    unset(_version_header)
+  endif()
+endif()
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MbedTLS DEFAULT_MSG
-  MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+find_package_handle_standard_args(MbedTLS
+  REQUIRED_VARS
+    MBEDTLS_INCLUDE_DIR
+    MBEDTLS_LIBRARY
+    MBEDX509_LIBRARY
+    MBEDCRYPTO_LIBRARY
+  VERSION_VAR
+    MBEDTLS_VERSION
+)
+
+if(MBEDTLS_FOUND)
+  set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR})
+  set(MBEDTLS_LIBRARIES    ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
+endif()
 
-mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)

+ 48 - 9
Utilities/cmcurl/CMake/FindNGHTTP2.cmake

@@ -21,21 +21,60 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-include(FindPackageHandleStandardArgs)
+# Find the nghttp2 library
+#
+# Input variables:
+#
+# NGHTTP2_INCLUDE_DIR   The nghttp2 include directory
+# NGHTTP2_LIBRARY       Path to nghttp2 library
+#
+# Result variables:
+#
+# NGHTTP2_FOUND         System has nghttp2
+# NGHTTP2_INCLUDE_DIRS  The nghttp2 include directories
+# NGHTTP2_LIBRARIES     The nghttp2 library names
+# NGHTTP2_VERSION       Version of nghttp2
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_NGHTTP2 "libnghttp2")
+endif()
 
-find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")
+find_path(NGHTTP2_INCLUDE_DIR NAMES "nghttp2/nghttp2.h"
+  HINTS
+    ${PC_NGHTTP2_INCLUDEDIR}
+    ${PC_NGHTTP2_INCLUDE_DIRS}
+)
+
+find_library(NGHTTP2_LIBRARY NAMES "nghttp2" "nghttp2_static"
+  HINTS
+    ${PC_NGHTTP2_LIBDIR}
+    ${PC_NGHTTP2_LIBRARY_DIRS}
+)
 
-find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static)
+if(PC_NGHTTP2_VERSION)
+  set(NGHTTP2_VERSION ${PC_NGHTTP2_VERSION})
+elseif(NGHTTP2_INCLUDE_DIR AND EXISTS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h")
+  set(_version_regex "#[\t ]*define[\t ]+NGHTTP2_VERSION[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(NGHTTP2_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
+endif()
 
+include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(NGHTTP2
-  FOUND_VAR
-    NGHTTP2_FOUND
   REQUIRED_VARS
-    NGHTTP2_LIBRARY
     NGHTTP2_INCLUDE_DIR
+    NGHTTP2_LIBRARY
+  VERSION_VAR
+    NGHTTP2_VERSION
 )
 
-set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
-set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY})
+if(NGHTTP2_FOUND)
+  set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
+  set(NGHTTP2_LIBRARIES    ${NGHTTP2_LIBRARY})
+endif()
 
-mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES)
+mark_as_advanced(NGHTTP2_INCLUDE_DIR NGHTTP2_LIBRARY)

+ 29 - 27
Utilities/cmcurl/CMake/FindNGHTTP3.cmake

@@ -21,38 +21,32 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the nghttp3 library
+#
+# Input variables:
+#
+# NGHTTP3_INCLUDE_DIR   The nghttp3 include directory
+# NGHTTP3_LIBRARY       Path to nghttp3 library
+#
+# Result variables:
+#
+# NGHTTP3_FOUND         System has nghttp3
+# NGHTTP3_INCLUDE_DIRS  The nghttp3 include directories
+# NGHTTP3_LIBRARIES     The nghttp3 library names
+# NGHTTP3_VERSION       Version of nghttp3
 
-#[=======================================================================[.rst:
-FindNGHTTP3
-----------
-
-Find the nghttp3 library
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-``NGHTTP3_FOUND``
-  System has nghttp3
-``NGHTTP3_INCLUDE_DIRS``
-  The nghttp3 include directories.
-``NGHTTP3_LIBRARIES``
-  The libraries needed to use nghttp3
-``NGHTTP3_VERSION``
-  version of nghttp3.
-#]=======================================================================]
-
-if(UNIX)
+if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
-  pkg_search_module(PC_NGHTTP3 libnghttp3)
+  pkg_check_modules(PC_NGHTTP3 "libnghttp3")
 endif()
 
-find_path(NGHTTP3_INCLUDE_DIR nghttp3/nghttp3.h
+find_path(NGHTTP3_INCLUDE_DIR NAMES "nghttp3/nghttp3.h"
   HINTS
     ${PC_NGHTTP3_INCLUDEDIR}
     ${PC_NGHTTP3_INCLUDE_DIRS}
 )
 
-find_library(NGHTTP3_LIBRARY NAMES nghttp3
+find_library(NGHTTP3_LIBRARY NAMES "nghttp3"
   HINTS
     ${PC_NGHTTP3_LIBDIR}
     ${PC_NGHTTP3_LIBRARY_DIRS}
@@ -60,19 +54,27 @@ find_library(NGHTTP3_LIBRARY NAMES nghttp3
 
 if(PC_NGHTTP3_VERSION)
   set(NGHTTP3_VERSION ${PC_NGHTTP3_VERSION})
+elseif(NGHTTP3_INCLUDE_DIR AND EXISTS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h")
+  set(_version_regex "#[\t ]*define[\t ]+NGHTTP3_VERSION[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(NGHTTP3_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(NGHTTP3
   REQUIRED_VARS
-    NGHTTP3_LIBRARY
     NGHTTP3_INCLUDE_DIR
-  VERSION_VAR NGHTTP3_VERSION
+    NGHTTP3_LIBRARY
+  VERSION_VAR
+    NGHTTP3_VERSION
 )
 
 if(NGHTTP3_FOUND)
-  set(NGHTTP3_LIBRARIES    ${NGHTTP3_LIBRARY})
   set(NGHTTP3_INCLUDE_DIRS ${NGHTTP3_INCLUDE_DIR})
+  set(NGHTTP3_LIBRARIES    ${NGHTTP3_LIBRARY})
 endif()
 
-mark_as_advanced(NGHTTP3_INCLUDE_DIRS NGHTTP3_LIBRARIES)
+mark_as_advanced(NGHTTP3_INCLUDE_DIR NGHTTP3_LIBRARY)

+ 48 - 48
Utilities/cmcurl/CMake/FindNGTCP2.cmake

@@ -21,46 +21,40 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the ngtcp2 library
+#
+# This module accepts optional COMPONENTS to control the crypto library (these are
+# mutually exclusive):
+#
+# quictls:    Use libngtcp2_crypto_quictls   (choose this for LibreSSL)
+# BoringSSL:  Use libngtcp2_crypto_boringssl (choose this for AWS-LC)
+# wolfSSL:    Use libngtcp2_crypto_wolfssl
+# GnuTLS:     Use libngtcp2_crypto_gnutls
+#
+# Input variables:
+#
+# NGTCP2_INCLUDE_DIR   The ngtcp2 include directory
+# NGTCP2_LIBRARY       Path to ngtcp2 library
+#
+# Result variables:
+#
+# NGTCP2_FOUND         System has ngtcp2
+# NGTCP2_INCLUDE_DIRS  The ngtcp2 include directories
+# NGTCP2_LIBRARIES     The ngtcp2 library names
+# NGTCP2_VERSION       Version of ngtcp2
 
-#[=======================================================================[.rst:
-FindNGTCP2
-----------
-
-Find the ngtcp2 library
-
-This module accepts optional COMPONENTS to control the crypto library (these are
-mutually exclusive)::
-
-  quictls, LibreSSL:  Use libngtcp2_crypto_quictls
-  BoringSSL, AWS-LC:  Use libngtcp2_crypto_boringssl
-  wolfSSL:            Use libngtcp2_crypto_wolfssl
-  GnuTLS:             Use libngtcp2_crypto_gnutls
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-``NGTCP2_FOUND``
-  System has ngtcp2
-``NGTCP2_INCLUDE_DIRS``
-  The ngtcp2 include directories.
-``NGTCP2_LIBRARIES``
-  The libraries needed to use ngtcp2
-``NGTCP2_VERSION``
-  version of ngtcp2.
-#]=======================================================================]
-
-if(UNIX)
+if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
-  pkg_search_module(PC_NGTCP2 libngtcp2)
+  pkg_check_modules(PC_NGTCP2 "libngtcp2")
 endif()
 
-find_path(NGTCP2_INCLUDE_DIR ngtcp2/ngtcp2.h
+find_path(NGTCP2_INCLUDE_DIR NAMES "ngtcp2/ngtcp2.h"
   HINTS
     ${PC_NGTCP2_INCLUDEDIR}
     ${PC_NGTCP2_INCLUDE_DIRS}
 )
 
-find_library(NGTCP2_LIBRARY NAMES ngtcp2
+find_library(NGTCP2_LIBRARY NAMES "ngtcp2"
   HINTS
     ${PC_NGTCP2_LIBDIR}
     ${PC_NGTCP2_LIBRARY_DIRS}
@@ -68,33 +62,38 @@ find_library(NGTCP2_LIBRARY NAMES ngtcp2
 
 if(PC_NGTCP2_VERSION)
   set(NGTCP2_VERSION ${PC_NGTCP2_VERSION})
+elseif(NGTCP2_INCLUDE_DIR AND EXISTS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h")
+  set(_version_regex "#[\t ]*define[\t ]+NGTCP2_VERSION[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(NGTCP2_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
 endif()
 
 if(NGTCP2_FIND_COMPONENTS)
-  set(NGTCP2_CRYPTO_BACKEND "")
-  foreach(component IN LISTS NGTCP2_FIND_COMPONENTS)
-    if(component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)")
-      if(NGTCP2_CRYPTO_BACKEND)
+  set(_ngtcp2_crypto_backend "")
+  foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
+    if(_component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)")
+      if(_ngtcp2_crypto_backend)
         message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
       endif()
-      set(NGTCP2_CRYPTO_BACKEND ${component})
+      set(_ngtcp2_crypto_backend ${_component})
     endif()
   endforeach()
 
-  if(NGTCP2_CRYPTO_BACKEND)
-    string(TOLOWER "ngtcp2_crypto_${NGTCP2_CRYPTO_BACKEND}" _crypto_library)
-    if(UNIX)
-      pkg_search_module(PC_${_crypto_library} lib${_crypto_library})
+  if(_ngtcp2_crypto_backend)
+    string(TOLOWER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library)
+    if(CURL_USE_PKGCONFIG)
+      pkg_check_modules(PC_${_crypto_library} "lib${_crypto_library}")
     endif()
-    find_library(${_crypto_library}_LIBRARY
-      NAMES
-        ${_crypto_library}
+    find_library(${_crypto_library}_LIBRARY NAMES ${_crypto_library}
       HINTS
         ${PC_${_crypto_library}_LIBDIR}
         ${PC_${_crypto_library}_LIBRARY_DIRS}
     )
     if(${_crypto_library}_LIBRARY)
-      set(NGTCP2_${NGTCP2_CRYPTO_BACKEND}_FOUND TRUE)
+      set(NGTCP2_${_ngtcp2_crypto_backend}_FOUND TRUE)
       set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY})
     endif()
   endif()
@@ -103,15 +102,16 @@ endif()
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(NGTCP2
   REQUIRED_VARS
-    NGTCP2_LIBRARY
     NGTCP2_INCLUDE_DIR
-  VERSION_VAR NGTCP2_VERSION
+    NGTCP2_LIBRARY
+  VERSION_VAR
+    NGTCP2_VERSION
   HANDLE_COMPONENTS
 )
 
 if(NGTCP2_FOUND)
-  set(NGTCP2_LIBRARIES    ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY})
   set(NGTCP2_INCLUDE_DIRS ${NGTCP2_INCLUDE_DIR})
+  set(NGTCP2_LIBRARIES    ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY})
 endif()
 
-mark_as_advanced(NGTCP2_INCLUDE_DIRS NGTCP2_LIBRARIES)
+mark_as_advanced(NGTCP2_INCLUDE_DIR NGTCP2_LIBRARY NGTCP2_CRYPTO_LIBRARY)

+ 35 - 27
Utilities/cmcurl/CMake/FindNettle.cmake

@@ -21,50 +21,58 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# - Try to find the nettle library
-# Once done this will define
+# Find the nettle library
 #
-# NETTLE_FOUND - system has nettle
-# NETTLE_INCLUDE_DIRS - nettle include directories
-# NETTLE_LIBRARIES - nettle library names
+# Input variables:
+#
+# NETTLE_INCLUDE_DIR   The nettle include directory
+# NETTLE_LIBRARY       Path to nettle library
+#
+# Result variables:
+#
+# NETTLE_FOUND         System has nettle
+# NETTLE_INCLUDE_DIRS  The nettle include directories
+# NETTLE_LIBRARIES     The nettle library names
+# NETTLE_LIBRARY_DIRS  The nettle library directories
+# NETTLE_CFLAGS        Required compiler flags
+# NETTLE_VERSION       Version of nettle
 
-if(UNIX)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED NETTLE_INCLUDE_DIR AND
+   NOT DEFINED NETTLE_LIBRARY)
   find_package(PkgConfig QUIET)
   pkg_check_modules(NETTLE "nettle")
 endif()
 
 if(NETTLE_FOUND)
-  set(NETTLE_LIBRARIES ${NETTLE_LINK_LIBRARIES})
+  string(REPLACE ";" " " NETTLE_CFLAGS "${NETTLE_CFLAGS}")
+  message(STATUS "Found Nettle (via pkg-config): ${NETTLE_INCLUDE_DIRS} (found version \"${NETTLE_VERSION}\")")
 else()
   find_path(NETTLE_INCLUDE_DIR NAMES "nettle/sha2.h")
   find_library(NETTLE_LIBRARY NAMES "nettle")
 
-  if(NETTLE_INCLUDE_DIR)
-    if(EXISTS "${NETTLE_INCLUDE_DIR}/nettle/version.h")
-      set(_version_regex_major "^#define[ \t]+NETTLE_VERSION_MAJOR[ \t]+([0-9]+).*")
-      set(_version_regex_minor "^#define[ \t]+NETTLE_VERSION_MINOR[ \t]+([0-9]+).*")
-      file(STRINGS "${NETTLE_INCLUDE_DIR}/nettle/version.h"
-        _version_major REGEX "${_version_regex_major}")
-      file(STRINGS "${NETTLE_INCLUDE_DIR}/nettle/version.h"
-        _version_minor REGEX "${_version_regex_minor}")
-      string(REGEX REPLACE "${_version_regex_major}" "\\1" _version_major "${_version_major}")
-      string(REGEX REPLACE "${_version_regex_minor}" "\\1" _version_minor "${_version_minor}")
-      unset(_version_regex_major)
-      unset(_version_regex_minor)
-      set(NETTLE_VERSION "${_version_major}.${_version_minor}")
-      unset(_version_major)
-      unset(_version_minor)
-    else()
-      set(NETTLE_VERSION "0.0")
-    endif()
+  if(NETTLE_INCLUDE_DIR AND EXISTS "${NETTLE_INCLUDE_DIR}/nettle/version.h")
+    set(_version_regex1 "#[\t ]*define[ \t]+NETTLE_VERSION_MAJOR[ \t]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[ \t]+NETTLE_VERSION_MINOR[ \t]+([0-9]+).*")
+    file(STRINGS "${NETTLE_INCLUDE_DIR}/nettle/version.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${NETTLE_INCLUDE_DIR}/nettle/version.h" _version_str2 REGEX "${_version_regex2}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    set(NETTLE_VERSION "${_version_str1}.${_version_str2}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_str1)
+    unset(_version_str2)
   endif()
 
   include(FindPackageHandleStandardArgs)
-  find_package_handle_standard_args("nettle"
+  find_package_handle_standard_args(Nettle
     REQUIRED_VARS
       NETTLE_INCLUDE_DIR
       NETTLE_LIBRARY
-    VERSION_VAR NETTLE_VERSION)
+    VERSION_VAR
+      NETTLE_VERSION
+  )
 
   if(NETTLE_FOUND)
     set(NETTLE_INCLUDE_DIRS ${NETTLE_INCLUDE_DIR})

+ 27 - 24
Utilities/cmcurl/CMake/FindQUICHE.cmake → Utilities/cmcurl/CMake/FindQuiche.cmake

@@ -21,50 +21,53 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the quiche library
+#
+# Input variables:
+#
+# QUICHE_INCLUDE_DIR   The quiche include directory
+# QUICHE_LIBRARY       Path to quiche library
+#
+# Result variables:
+#
+# QUICHE_FOUND         System has quiche
+# QUICHE_INCLUDE_DIRS  The quiche include directories
+# QUICHE_LIBRARIES     The quiche library names
+# QUICHE_VERSION       Version of quiche
 
-#[=======================================================================[.rst:
-FindQUICHE
-----------
-
-Find the quiche library
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-``QUICHE_FOUND``
-  System has quiche
-``QUICHE_INCLUDE_DIRS``
-  The quiche include directories.
-``QUICHE_LIBRARIES``
-  The libraries needed to use quiche
-#]=======================================================================]
-if(UNIX)
+if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
-  pkg_search_module(PC_QUICHE quiche)
+  pkg_check_modules(PC_QUICHE "quiche")
 endif()
 
-find_path(QUICHE_INCLUDE_DIR quiche.h
+find_path(QUICHE_INCLUDE_DIR NAMES "quiche.h"
   HINTS
     ${PC_QUICHE_INCLUDEDIR}
     ${PC_QUICHE_INCLUDE_DIRS}
 )
 
-find_library(QUICHE_LIBRARY NAMES quiche
+find_library(QUICHE_LIBRARY NAMES "quiche"
   HINTS
     ${PC_QUICHE_LIBDIR}
     ${PC_QUICHE_LIBRARY_DIRS}
 )
 
+if(PC_QUICHE_VERSION)
+  set(QUICHE_VERSION ${PC_QUICHE_VERSION})
+endif()
+
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(QUICHE
+find_package_handle_standard_args(Quiche
   REQUIRED_VARS
-    QUICHE_LIBRARY
     QUICHE_INCLUDE_DIR
+    QUICHE_LIBRARY
+  VERSION_VAR
+    QUICHE_VERSION
 )
 
 if(QUICHE_FOUND)
-  set(QUICHE_LIBRARIES    ${QUICHE_LIBRARY})
   set(QUICHE_INCLUDE_DIRS ${QUICHE_INCLUDE_DIR})
+  set(QUICHE_LIBRARIES    ${QUICHE_LIBRARY})
 endif()
 
-mark_as_advanced(QUICHE_INCLUDE_DIRS QUICHE_LIBRARIES)
+mark_as_advanced(QUICHE_INCLUDE_DIR QUICHE_LIBRARY)

+ 42 - 14
Utilities/cmcurl/CMake/FindLibPSL.cmake → Utilities/cmcurl/CMake/FindRustls.cmake

@@ -21,25 +21,53 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# - Try to find the libpsl library
-# Once done this will define
+# Find the rustls library
 #
-# LIBPSL_FOUND - system has the libpsl library
-# LIBPSL_INCLUDE_DIR - the libpsl include directory
-# LIBPSL_LIBRARY - the libpsl library name
+# Input variables:
+#
+# RUSTLS_INCLUDE_DIR   The rustls include directory
+# RUSTLS_LIBRARY       Path to rustls library
+#
+# Result variables:
+#
+# RUSTLS_FOUND         System has rustls
+# RUSTLS_INCLUDE_DIRS  The rustls include directories
+# RUSTLS_LIBRARIES     The rustls library names
+# RUSTLS_VERSION       Version of rustls
 
-find_path(LIBPSL_INCLUDE_DIR libpsl.h)
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_RUSTLS "rustls")
+endif()
 
-find_library(LIBPSL_LIBRARY NAMES psl libpsl)
+find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h"
+  HINTS
+    ${PC_RUSTLS_INCLUDEDIR}
+    ${PC_RUSTLS_INCLUDE_DIRS}
+)
 
-if(LIBPSL_INCLUDE_DIR)
-  file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" libpsl_version_str REGEX "^#define[\t ]+PSL_VERSION[\t ]+\"(.*)\"")
-  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBPSL_VERSION "${libpsl_version_str}")
+find_library(RUSTLS_LIBRARY NAMES "rustls"
+  HINTS
+    ${PC_RUSTLS_LIBDIR}
+    ${PC_RUSTLS_LIBRARY_DIRS}
+)
+
+if(PC_RUSTLS_VERSION)
+  set(RUSTLS_VERSION ${PC_RUSTLS_VERSION})
 endif()
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(LibPSL
-  REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR
-  VERSION_VAR LIBPSL_VERSION)
+find_package_handle_standard_args(Rustls
+  REQUIRED_VARS
+    RUSTLS_INCLUDE_DIR
+    RUSTLS_LIBRARY
+  VERSION_VAR
+    RUSTLS_VERSION
+)
+
+if(RUSTLS_FOUND)
+  set(RUSTLS_INCLUDE_DIRS ${RUSTLS_INCLUDE_DIR})
+  set(RUSTLS_LIBRARIES    ${RUSTLS_LIBRARY})
+endif()
 
-mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)
+mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)

+ 64 - 0
Utilities/cmcurl/CMake/FindWolfSSH.cmake

@@ -0,0 +1,64 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the wolfssh library
+#
+# Input variables:
+#
+# WOLFSSH_INCLUDE_DIR   The wolfssh include directory
+# WOLFSSH_LIBRARY       Path to wolfssh library
+#
+# Result variables:
+#
+# WOLFSSH_FOUND         System has wolfssh
+# WOLFSSH_INCLUDE_DIRS  The wolfssh include directories
+# WOLFSSH_LIBRARIES     The wolfssh library names
+# WOLFSSH_VERSION       Version of wolfssh
+
+find_path(WOLFSSH_INCLUDE_DIR NAMES "wolfssh/ssh.h")
+find_library(WOLFSSH_LIBRARY NAMES "wolfssh" "libwolfssh")
+
+if(WOLFSSH_INCLUDE_DIR AND EXISTS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h")
+  set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSH_VERSION_STRING[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(WOLFSSH_VERSION "${_version_str}")
+  unset(_version_regex)
+  unset(_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WolfSSH
+  REQUIRED_VARS
+    WOLFSSH_INCLUDE_DIR
+    WOLFSSH_LIBRARY
+  VERSION_VAR
+    WOLFSSH_VERSION
+)
+
+if(WOLFSSH_FOUND)
+  set(WOLFSSH_INCLUDE_DIRS ${WOLFSSH_INCLUDE_DIR})
+  set(WOLFSSH_LIBRARIES    ${WOLFSSH_LIBRARY})
+endif()
+
+mark_as_advanced(WOLFSSH_INCLUDE_DIR WOLFSSH_LIBRARY)

+ 59 - 21
Utilities/cmcurl/CMake/FindWolfSSL.cmake

@@ -21,40 +21,78 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the wolfssl library
+#
+# Input variables:
+#
+# WOLFSSL_INCLUDE_DIR   The wolfssl include directory
+# WolfSSL_INCLUDE_DIR   The wolfssl include directory (deprecated)
+# WOLFSSL_LIBRARY       Path to wolfssl library
+# WolfSSL_LIBRARY       Path to wolfssl library (deprecated)
+#
+# Result variables:
+#
+# WOLFSSL_FOUND         System has wolfssl
+# WOLFSSL_INCLUDE_DIRS  The wolfssl include directories
+# WOLFSSL_LIBRARIES     The wolfssl library names
+# WOLFSSL_VERSION       Version of wolfssl
 
-find_package(PkgConfig QUIET)
-pkg_check_modules(PC_WOLFSSL QUIET "wolfssl")
+if(DEFINED WolfSSL_INCLUDE_DIR AND NOT DEFINED WOLFSSL_INCLUDE_DIR)
+  message(WARNING "WolfSSL_INCLUDE_DIR is deprecated, use WOLFSSL_INCLUDE_DIR instead.")
+  set(WOLFSSL_INCLUDE_DIR "${WolfSSL_INCLUDE_DIR}")
+endif()
+if(DEFINED WolfSSL_LIBRARY AND NOT DEFINED WOLFSSL_LIBRARY)
+  message(WARNING "WolfSSL_LIBRARY is deprecated, use WOLFSSL_LIBRARY instead.")
+  set(WOLFSSL_LIBRARY "${WolfSSL_LIBRARY}")
+endif()
+
+if(CURL_USE_PKGCONFIG)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(PC_WOLFSSL "wolfssl")
+endif()
 
-find_path(WolfSSL_INCLUDE_DIR
-  NAMES "wolfssl/ssl.h"
-  HINTS ${PC_WOLFSSL_INCLUDE_DIRS}
+find_path(WOLFSSL_INCLUDE_DIR NAMES "wolfssl/ssl.h"
+  HINTS
+    ${PC_WOLFSSL_INCLUDEDIR}
+    ${PC_WOLFSSL_INCLUDE_DIRS}
 )
 
-find_library(WolfSSL_LIBRARY
-  NAMES "wolfssl"
-  HINTS ${PC_WOLFSSL_LIBRARY_DIRS}
+find_library(WOLFSSL_LIBRARY NAMES "wolfssl"
+  HINTS
+    ${PC_WOLFSSL_LIBDIR}
+    ${PC_WOLFSSL_LIBRARY_DIRS}
 )
 
-if(WolfSSL_INCLUDE_DIR)
-  set(_version_regex "^#define[ \t]+LIBWOLFSSL_VERSION_STRING[ \t]+\"([^\"]+)\".*")
-  file(STRINGS "${WolfSSL_INCLUDE_DIR}/wolfssl/version.h"
-    WolfSSL_VERSION REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1"
-    WolfSSL_VERSION "${WolfSSL_VERSION}")
+if(PC_WOLFSSL_VERSION)
+  set(WOLFSSL_VERSION ${PC_WOLFSSL_VERSION})
+elseif(WOLFSSL_INCLUDE_DIR AND EXISTS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h")
+  set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSL_VERSION_STRING[\t ]+\"([^\"]*)\"")
+  file(STRINGS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h" _version_str REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+  set(WOLFSSL_VERSION "${_version_str}")
   unset(_version_regex)
+  unset(_version_str)
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(WolfSSL
   REQUIRED_VARS
-    WolfSSL_INCLUDE_DIR
-    WolfSSL_LIBRARY
-  VERSION_VAR WolfSSL_VERSION
+    WOLFSSL_INCLUDE_DIR
+    WOLFSSL_LIBRARY
+  VERSION_VAR
+    WOLFSSL_VERSION
 )
 
-if(WolfSSL_FOUND)
-  set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR})
-  set(WolfSSL_LIBRARIES    ${WolfSSL_LIBRARY})
+if(WOLFSSL_FOUND)
+  set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
+  set(WOLFSSL_LIBRARIES    ${WOLFSSL_LIBRARY})
+
+  if(NOT WIN32)
+    find_library(_math_library "m")
+    if(_math_library)
+      list(APPEND WOLFSSL_LIBRARIES "m")  # for log and pow
+    endif()
+  endif()
 endif()
 
-mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY)
+mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)

+ 58 - 35
Utilities/cmcurl/CMake/FindZstd.cmake

@@ -21,58 +21,81 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Find the zstd library
+#
+# Input variables:
+#
+# ZSTD_INCLUDE_DIR   The zstd include directory
+# Zstd_INCLUDE_DIR   The zstd include directory (deprecated)
+# ZSTD_LIBRARY       Path to zstd library
+# Zstd_LIBRARY       Path to zstd library (deprecated)
+#
+# Result variables:
+#
+# ZSTD_FOUND         System has zstd
+# ZSTD_INCLUDE_DIRS  The zstd include directories
+# ZSTD_LIBRARIES     The zstd library names
+# ZSTD_VERSION       Version of zstd
 
-#[=======================================================================[.rst:
-FindZstd
-----------
-
-Find the zstd library
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-``Zstd_FOUND``
-  System has zstd
-``Zstd_INCLUDE_DIRS``
-  The zstd include directories.
-``Zstd_LIBRARIES``
-  The libraries needed to use zstd
-#]=======================================================================]
+if(DEFINED Zstd_INCLUDE_DIR AND NOT DEFINED ZSTD_INCLUDE_DIR)
+  message(WARNING "Zstd_INCLUDE_DIR is deprecated, use ZSTD_INCLUDE_DIR instead.")
+  set(ZSTD_INCLUDE_DIR "${Zstd_INCLUDE_DIR}")
+endif()
+if(DEFINED Zstd_LIBRARY AND NOT DEFINED ZSTD_LIBRARY)
+  message(WARNING "Zstd_LIBRARY is deprecated, use ZSTD_LIBRARY instead.")
+  set(ZSTD_LIBRARY "${Zstd_LIBRARY}")
+endif()
 
-if(UNIX)
+if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
-  pkg_search_module(PC_Zstd libzstd)
+  pkg_check_modules(PC_ZSTD "libzstd")
 endif()
 
-find_path(Zstd_INCLUDE_DIR zstd.h
+find_path(ZSTD_INCLUDE_DIR NAMES "zstd.h"
   HINTS
-    ${PC_Zstd_INCLUDEDIR}
-    ${PC_Zstd_INCLUDE_DIRS}
+    ${PC_ZSTD_INCLUDEDIR}
+    ${PC_ZSTD_INCLUDE_DIRS}
 )
 
-find_library(Zstd_LIBRARY NAMES zstd
+find_library(ZSTD_LIBRARY NAMES "zstd"
   HINTS
-    ${PC_Zstd_LIBDIR}
-    ${PC_Zstd_LIBRARY_DIRS}
+    ${PC_ZSTD_LIBDIR}
+    ${PC_ZSTD_LIBRARY_DIRS}
 )
 
-if(Zstd_INCLUDE_DIR)
-  file(READ "${Zstd_INCLUDE_DIR}/zstd.h" _zstd_header)
-  string(REGEX MATCH ".*define ZSTD_VERSION_MAJOR *([0-9]+).*define ZSTD_VERSION_MINOR *([0-9]+).*define ZSTD_VERSION_RELEASE *([0-9]+)" _zstd_ver "${_zstd_header}")
-  set(Zstd_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+if(PC_ZSTD_VERSION)
+  set(ZSTD_VERSION ${PC_ZSTD_VERSION})
+elseif(ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h")
+  set(_version_regex1 "#[\t ]*define[ \t]+ZSTD_VERSION_MAJOR[ \t]+([0-9]+).*")
+  set(_version_regex2 "#[\t ]*define[ \t]+ZSTD_VERSION_MINOR[ \t]+([0-9]+).*")
+  set(_version_regex3 "#[\t ]*define[ \t]+ZSTD_VERSION_RELEASE[ \t]+([0-9]+).*")
+  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str1 REGEX "${_version_regex1}")
+  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str2 REGEX "${_version_regex2}")
+  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str3 REGEX "${_version_regex3}")
+  string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+  string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+  string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+  set(ZSTD_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+  unset(_version_regex1)
+  unset(_version_regex2)
+  unset(_version_regex3)
+  unset(_version_str1)
+  unset(_version_str2)
+  unset(_version_str3)
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Zstd
   REQUIRED_VARS
-    Zstd_LIBRARY
-    Zstd_INCLUDE_DIR
-  VERSION_VAR Zstd_VERSION
+    ZSTD_INCLUDE_DIR
+    ZSTD_LIBRARY
+  VERSION_VAR
+    ZSTD_VERSION
 )
 
-if(Zstd_FOUND)
-  set(Zstd_LIBRARIES    ${Zstd_LIBRARY})
-  set(Zstd_INCLUDE_DIRS ${Zstd_INCLUDE_DIR})
+if(ZSTD_FOUND)
+  set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR})
+  set(ZSTD_LIBRARIES    ${ZSTD_LIBRARY})
 endif()
 
-mark_as_advanced(Zstd_INCLUDE_DIRS Zstd_LIBRARIES)
+mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)

+ 31 - 35
Utilities/cmcurl/CMake/Macros.cmake

@@ -21,60 +21,56 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-#File defines convenience macros for available feature testing
+# File defines convenience macros for available feature testing
 
 # Check if header file exists and add it to the list.
 # This macro is intended to be called multiple times with a sequence of
 # possibly dependent header files.  Some headers depend on others to be
 # compiled correctly.
-macro(check_include_file_concat FILE VARIABLE)
-  check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE})
-  if(${VARIABLE})
-    set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE})
-    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}")
+macro(check_include_file_concat _file _variable)
+  check_include_files("${CURL_INCLUDES};${_file}" ${_variable})
+  if(${_variable})
+    set(CURL_INCLUDES ${CURL_INCLUDES} ${_file})
+    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${_variable}")
   endif()
 endmacro()
 
 # For other curl specific tests, use this macro.
-macro(curl_internal_test CURL_TEST)
-  if(NOT DEFINED "${CURL_TEST}")
-    set(MACRO_CHECK_FUNCTION_DEFINITIONS
-      "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}")
+# Return result in variable: CURL_TEST_OUTPUT
+macro(curl_internal_test _curl_test)
+  if(NOT DEFINED "${_curl_test}")
+    set(_macro_check_function_definitions
+      "-D${_curl_test} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}")
     if(CMAKE_REQUIRED_LIBRARIES)
-      set(CURL_TEST_ADD_LIBRARIES
+      set(_curl_test_add_libraries
         "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
     endif()
 
-    message(STATUS "Performing Test ${CURL_TEST}")
-    try_compile(${CURL_TEST}
+    message(STATUS "Performing Test ${_curl_test}")
+    try_compile(${_curl_test}
       ${CMAKE_BINARY_DIR}
-      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c
-      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
-      "${CURL_TEST_ADD_LIBRARIES}"
-      OUTPUT_VARIABLE OUTPUT)
-    if(${CURL_TEST})
-      set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
-      message(STATUS "Performing Test ${CURL_TEST} - Success")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-        "Performing Test ${CURL_TEST} passed with the following output:\n"
-        "${OUTPUT}\n")
+      "${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c"
+      CMAKE_FLAGS
+        "-DCOMPILE_DEFINITIONS:STRING=${_macro_check_function_definitions}"
+        "${_curl_test_add_libraries}"
+      OUTPUT_VARIABLE CURL_TEST_OUTPUT)
+    if(${_curl_test})
+      set(${_curl_test} 1 CACHE INTERNAL "Curl test")
+      message(STATUS "Performing Test ${_curl_test} - Success")
     else()
-      message(STATUS "Performing Test ${CURL_TEST} - Failed")
-      set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-        "Performing Test ${CURL_TEST} failed with the following output:\n"
-        "${OUTPUT}\n")
+      set(${_curl_test} "" CACHE INTERNAL "Curl test")
+      message(STATUS "Performing Test ${_curl_test} - Failed")
     endif()
   endif()
 endmacro()
 
-macro(optional_dependency DEPENDENCY)
-  set(CURL_${DEPENDENCY} AUTO CACHE STRING "Build curl with ${DEPENDENCY} support (AUTO, ON or OFF)")
-  set_property(CACHE CURL_${DEPENDENCY} PROPERTY STRINGS AUTO ON OFF)
+macro(optional_dependency _dependency)
+  set(CURL_${_dependency} "AUTO" CACHE STRING "Build curl with ${_dependency} support (AUTO, ON or OFF)")
+  set_property(CACHE CURL_${_dependency} PROPERTY STRINGS "AUTO" "ON" "OFF")
 
-  if(CURL_${DEPENDENCY} STREQUAL AUTO)
-    find_package(${DEPENDENCY})
-  elseif(CURL_${DEPENDENCY})
-    find_package(${DEPENDENCY} REQUIRED)
+  if(CURL_${_dependency} STREQUAL "AUTO")
+    find_package(${_dependency})
+  elseif(CURL_${_dependency})
+    find_package(${_dependency} REQUIRED)
   endif()
 endmacro()

+ 27 - 31
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -25,17 +25,17 @@ include(CheckCSourceCompiles)
 include(CheckCSourceRuns)
 include(CheckTypeSize)
 
-macro(add_header_include check header)
-  if(${check})
+macro(add_header_include _check _header)
+  if(${_check})
     set(_source_epilogue "${_source_epilogue}
-      #include <${header}>")
+      #include <${_header}>")
   endif()
 endmacro()
 
 set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
 
 if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
-  set(CMAKE_EXTRA_INCLUDE_FILES)
+  unset(CMAKE_EXTRA_INCLUDE_FILES)
   if(WIN32)
     set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
     set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")
@@ -45,6 +45,7 @@ if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
   endif()
   check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
   set(HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE})
+  set(CMAKE_EXTRA_INCLUDE_FILES "")
 endif()
 
 if(NOT WIN32)
@@ -75,37 +76,32 @@ check_c_source_compiles("${_source_epilogue}
 
 unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
 
-if(NOT CMAKE_CROSSCOMPILING AND NOT APPLE)
+if(NOT APPLE)
   set(_source_epilogue "#undef inline")
   add_header_include(HAVE_SYS_POLL_H "sys/poll.h")
   add_header_include(HAVE_POLL_H "poll.h")
-  check_c_source_runs("${_source_epilogue}
-    #include <stdlib.h>
-    #include <sys/time.h>
-    int main(void)
-    {
-      if(0 != poll(0, 0, 10)) {
-        return 1; /* fail */
-      }
-      else {
-        /* detect the 10.12 poll() breakage */
-        struct timeval before, after;
-        int rc;
-        size_t us;
-
-        gettimeofday(&before, NULL);
-        rc = poll(NULL, 0, 500);
-        gettimeofday(&after, NULL);
-
-        us = (after.tv_sec - before.tv_sec) * 1000000 +
-          (after.tv_usec - before.tv_usec);
-
-        if(us < 400000) {
-          return 1;
+  if(NOT CMAKE_CROSSCOMPILING)
+    check_c_source_runs("${_source_epilogue}
+      #include <stdlib.h>
+      int main(void)
+      {
+        if(0 != poll(0, 0, 10)) {
+          return 1; /* fail */
         }
-      }
-      return 0;
-    }" HAVE_POLL_FINE)
+        return 0;
+      }" HAVE_POLL_FINE)
+  elseif(UNIX)
+    check_c_source_compiles("${_source_epilogue}
+      #include <stdlib.h>
+      int main(void)
+      {
+        #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
+          (void)poll(0, 0, 0);
+        #else
+          #error force compilation error
+        #endif
+      }" HAVE_POLL_FINE)
+  endif()
 endif()
 
 # Detect HAVE_GETADDRINFO_THREADSAFE

+ 13 - 13
Utilities/cmcurl/CMake/PickyWarnings.cmake

@@ -28,7 +28,7 @@ unset(WPICKY)
 if(CURL_WERROR AND
    ((CMAKE_COMPILER_IS_GNUCC AND
      NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
-     NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # check_symbol_exists() incompatible with GCC -pedantic-errors in earlier CMake versions
+     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"))
   set(WPICKY "${WPICKY} -pedantic-errors")
 endif()
@@ -104,13 +104,13 @@ if(PICKY_COMPILER)
       -Wmissing-noreturn                   # clang  2.7  gcc  4.1
       -Wno-format-nonliteral               # clang  1.0  gcc  2.96 (3.0)
       -Wno-system-headers                  # clang  1.0  gcc  3.0
-    # -Wpadded                             # clang  2.9  gcc  4.1               # Not used because we cannot change public structs
+    # -Wpadded                             # clang  2.9  gcc  4.1               # Not used: We cannot change public structs
       -Wold-style-definition               # clang  2.7  gcc  3.4
       -Wredundant-decls                    # clang  2.7  gcc  4.1
       -Wsign-conversion                    # clang  2.9  gcc  4.3
         -Wno-error=sign-conversion                                              # FIXME
       -Wstrict-prototypes                  # clang  1.0  gcc  3.3
-    # -Wswitch-enum                        # clang  2.7  gcc  4.1               # Not used because this basically disallows default case
+    # -Wswitch-enum                        # clang  2.7  gcc  4.1               # Not used: It basically disallows default case
       -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
@@ -160,7 +160,7 @@ if(PICKY_COMPILER)
       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))
         list(APPEND WPICKY_ENABLE
-          -Wimplicit-fallthrough           # clang  4.0  gcc  7.0  appleclang 12.4  # we have silencing markup for clang 10.0 and above only
+          -Wimplicit-fallthrough           # clang  4.0  gcc  7.0  appleclang 12.4  # We do silencing for clang 10.0 and above only
         )
       endif()
     else()  # gcc
@@ -180,7 +180,7 @@ if(PICKY_COMPILER)
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
         list(APPEND WPICKY_ENABLE
-          -Wno-pedantic-ms-format          #             gcc  4.5 (mingw-only)
+          -Wno-pedantic-ms-format          #             gcc  4.5 (MinGW-only)
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
@@ -206,7 +206,7 @@ if(PICKY_COMPILER)
         list(APPEND WPICKY_ENABLE
           -Walloc-zero                     #             gcc  7.0
           -Wduplicated-branches            #             gcc  7.0
-          -Wformat-overflow=2              #             gcc  7.0
+          -Wno-format-overflow             #             gcc  7.0
           -Wformat-truncation=2            #             gcc  7.0
           -Wimplicit-fallthrough           # clang  4.0  gcc  7.0
           -Wrestrict                       #             gcc  7.0
@@ -221,20 +221,20 @@ if(PICKY_COMPILER)
 
     #
 
-    foreach(_CCOPT IN LISTS WPICKY_ENABLE)
-      set(WPICKY "${WPICKY} ${_CCOPT}")
+    foreach(_ccopt IN LISTS WPICKY_ENABLE)
+      set(WPICKY "${WPICKY} ${_ccopt}")
     endforeach()
 
-    foreach(_CCOPT IN LISTS WPICKY_DETECT)
+    foreach(_ccopt IN LISTS WPICKY_DETECT)
       # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
       # test result in.
-      string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
+      string(MAKE_C_IDENTIFIER "OPT${_ccopt}" _optvarname)
       # GCC only warns about unknown -Wno- options if there are also other diagnostic messages,
       # so test for the positive form instead
-      string(REPLACE "-Wno-" "-W" _CCOPT_ON "${_CCOPT}")
-      check_c_compiler_flag(${_CCOPT_ON} ${_optvarname})
+      string(REPLACE "-Wno-" "-W" _ccopt_on "${_ccopt}")
+      check_c_compiler_flag(${_ccopt_on} ${_optvarname})
       if(${_optvarname})
-        set(WPICKY "${WPICKY} ${_CCOPT}")
+        set(WPICKY "${WPICKY} ${_ccopt}")
       endif()
     endforeach()
   endif()

+ 10 - 7
Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake

@@ -41,6 +41,10 @@ if(MINGW)
   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_UTIME_H 1)  # wrapper to sys/utime.h
+  set(HAVE_DIRENT_H 1)
+  set(HAVE_OPENDIR 1)
 else()
   set(HAVE_LIBGEN_H 0)
   set(HAVE_STRCASECMP 0)
@@ -48,6 +52,10 @@ else()
   set(HAVE_SYS_PARAM_H 0)
   set(HAVE_SYS_TIME_H 0)
   set(HAVE_GETTIMEOFDAY 0)
+  set(HAVE_STRINGS_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_LOCALE_H 1)
@@ -121,7 +129,6 @@ set(HAVE_IOCTL_SIOCGIFADDR 0)
 set(HAVE_POLL_H 0)
 set(HAVE_POLL_FINE 0)
 set(HAVE_PWD_H 0)
-set(HAVE_STRINGS_H 0)  # mingw-w64 has it (wrapper to string.h)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
 set(HAVE_SYS_WAIT_H 0)
@@ -137,12 +144,9 @@ set(HAVE_SYS_UN_H 0)
 set(HAVE_SYS_UTIME_H 1)
 set(HAVE_TERMIOS_H 0)
 set(HAVE_TERMIO_H 0)
-set(HAVE_UTIME_H 0)  # mingw-w64 has it (wrapper to sys/utime.h)
-
-set(HAVE_DIRENT_H 0)
-set(HAVE_OPENDIR 0)
+set(HAVE_LINUX_TCP_H 0)
 
-set(HAVE_FSEEKO 0)
+set(HAVE_FSEEKO 0)  # mingw-w64 2.0.0 and newer has it
 set(HAVE__FSEEKI64 1)
 set(HAVE_SOCKET 1)
 set(HAVE_SELECT 1)
@@ -161,7 +165,6 @@ set(HAVE_GMTIME_R 0)
 set(HAVE_GETHOSTBYNAME_R 0)
 set(HAVE_SIGNAL 1)
 set(HAVE_SIGACTION 0)
-set(HAVE_LINUX_TCP_H 0)
 set(HAVE_GLIBC_STRERROR_R 0)
 set(HAVE_MACH_ABSOLUTE_TIME 0)
 set(HAVE_GETIFADDRS 0)

+ 2 - 2
Utilities/cmcurl/CMake/Utilities.cmake

@@ -24,12 +24,12 @@
 # File containing various utilities
 
 # Returns number of arguments that evaluate to true
-function(count_true output_count_var)
+function(count_true _output_count_var)
   set(lst_len 0)
   foreach(option_var IN LISTS ARGN)
     if(${option_var})
       math(EXPR lst_len "${lst_len} + 1")
     endif()
   endforeach()
-  set(${output_count_var} ${lst_len} PARENT_SCOPE)
+  set(${_output_count_var} ${lst_len} PARENT_SCOPE)
 endfunction()

+ 9 - 9
Utilities/cmcurl/CMake/cmake_uninstall.cmake.in

@@ -30,20 +30,20 @@ if(NOT DEFINED CMAKE_INSTALL_PREFIX)
 endif()
 message(${CMAKE_INSTALL_PREFIX})
 
-file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
-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}")
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" _files)
+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}\""
+      "@CMAKE_COMMAND@" ARGS "-E rm -f \"$ENV{DESTDIR}${_file}\""
       OUTPUT_VARIABLE rm_out
       RETURN_VALUE rm_retval
-      )
+    )
     if(NOT "${rm_retval}" STREQUAL 0)
-      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${_file}")
     endif()
   else()
-    message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+    message(STATUS "File $ENV{DESTDIR}${_file} does not exist.")
   endif()
 endforeach()

+ 8 - 0
Utilities/cmcurl/CMake/curl-config.cmake.in

@@ -23,6 +23,14 @@
 ###########################################################################
 @PACKAGE_INIT@
 
+if(NOT DEFINED CURL_USE_PKGCONFIG)
+  if(UNIX OR (MSVC AND VCPKG_TOOLCHAIN))  # Keep in sync with root CMakeLists.txt
+    set(CURL_USE_PKGCONFIG ON)
+  else()
+    set(CURL_USE_PKGCONFIG OFF)
+  endif()
+endif()
+
 include(CMakeFindDependencyMacro)
 if(@USE_OPENSSL@)
   find_dependency(OpenSSL @OPENSSL_VERSION_MAJOR@)

文件差异内容过多而无法显示
+ 346 - 195
Utilities/cmcurl/CMakeLists.txt


+ 13 - 11
Utilities/cmcurl/include/curl/curl.h

@@ -76,7 +76,7 @@
 #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
 #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
       defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
-/* The check above prevents the winsock2 inclusion if winsock.h already was
+/* The check above prevents the winsock2.h inclusion if winsock.h already was
    included, since they cannot co-exist without problems */
 #include <winsock2.h>
 #include <ws2tcpip.h>
@@ -721,6 +721,8 @@ typedef enum {
    with them. */
 #define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
 #define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
+#define CURLOPT_OBSOLETE72 9999
+#define CURLOPT_OBSOLETE40 9999
 
 #endif /* !CURL_NO_OLDIES */
 
@@ -1250,8 +1252,7 @@ typedef enum {
   /* send linked-list of post-transfer QUOTE commands */
   CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39),
 
-   /* OBSOLETE, do not use! */
-  CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40),
+  /* 40 is not used */
 
   /* talk a lot */
   CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41),
@@ -1352,9 +1353,7 @@ typedef enum {
   /* Max amount of cached alive connections */
   CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71),
 
-  /* OBSOLETE, do not use! */
-  CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),
-
+  /* 72 = OBSOLETE */
   /* 73 = OBSOLETE */
 
   /* Set to explicitly use a new connection for the upcoming transfer.
@@ -1398,7 +1397,7 @@ typedef enum {
      operation. Set filename to "-" (dash) to make it go to stdout. */
   CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),
 
-  /* Specify which SSL ciphers to use */
+  /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use */
   CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),
 
   /* Specify which HTTP version to use! This must be set to one of the
@@ -2022,7 +2021,7 @@ typedef enum {
   /* password for the SSL private key for proxy */
   CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258),
 
-  /* Specify which SSL ciphers to use for proxy */
+  /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use for proxy */
   CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259),
 
   /* CRL file for proxy */
@@ -2203,7 +2202,7 @@ typedef enum {
   /* specify which protocols that libcurl is allowed to follow directs to */
   CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319),
 
-  /* websockets options */
+  /* WebSockets options */
   CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320),
 
   /* CA cache timeout */
@@ -2645,7 +2644,7 @@ CURL_EXTERN char *curl_getenv(const char *variable);
  *
  * DESCRIPTION
  *
- * Returns a static ascii string of the libcurl version.
+ * Returns a static ASCII string of the libcurl version.
  */
 CURL_EXTERN char *curl_version(void);
 
@@ -2953,7 +2952,8 @@ typedef enum {
   CURLINFO_CONN_ID          = CURLINFO_OFF_T + 64,
   CURLINFO_QUEUE_TIME_T     = CURLINFO_OFF_T + 65,
   CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
-  CURLINFO_LASTONE          = 66
+  CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
+  CURLINFO_LASTONE          = 67
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -3236,7 +3236,9 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #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.9.1"
+#define LIBCURL_VERSION "8.10.1"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 9
+#define LIBCURL_VERSION_MINOR 10
 #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 0x080901
+#define LIBCURL_VERSION_NUM 0x080a01
 
 /*
  * This is the date and time when the full source package was created. The

+ 7 - 1
Utilities/cmcurl/include/curl/mprintf.h

@@ -32,13 +32,18 @@
 extern "C" {
 #endif
 
+#ifndef CURL_TEMP_PRINTF
 #if (defined(__GNUC__) || defined(__clang__) ||                         \
   defined(__IAR_SYSTEMS_ICC__)) &&                                      \
   defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
   !defined(CURL_NO_FMT_CHECKS)
 #if defined(__MINGW32__) && !defined(__clang__)
+#if defined(__MINGW_PRINTF_FORMAT)  /* mingw-w64 3.0.0+. Needs stdio.h. */
 #define CURL_TEMP_PRINTF(fmt, arg) \
-  __attribute__((format(gnu_printf, fmt, arg)))
+  __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg)))
+#else
+#define CURL_TEMP_PRINTF(fmt, arg)
+#endif
 #else
 #define CURL_TEMP_PRINTF(fmt, arg) \
   __attribute__((format(printf, fmt, arg)))
@@ -46,6 +51,7 @@ extern "C" {
 #else
 #define CURL_TEMP_PRINTF(fmt, arg)
 #endif
+#endif
 
 CURL_EXTERN int curl_mprintf(const char *format, ...)
   CURL_TEMP_PRINTF(1, 2);

+ 1 - 1
Utilities/cmcurl/include/curl/system.h

@@ -31,7 +31,7 @@
  * changed.
  *
  * In order to differentiate between platforms/compilers/architectures use
- * only compiler built in predefined preprocessor symbols.
+ * only compiler built-in predefined preprocessor symbols.
  *
  * curl_off_t
  * ----------

+ 83 - 45
Utilities/cmcurl/lib/CMakeLists.txt

@@ -23,29 +23,27 @@
 ###########################################################################
 set(LIB_NAME libcurl)
 set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
-add_definitions(-DBUILDING_LIBCURL)
+add_definitions("-DBUILDING_LIBCURL")
 
-configure_file(curl_config.h.cmake
-  ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
+configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
+# Get 'CSOURCES', 'HHEADERS' variables
 transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
-include(${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(REMOVE_ITEM CSOURCES "dllmain.c")
 
-list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
+list(APPEND HHEADERS "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
 # The rest of the build
 
-include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
-include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(
+  "${CMAKE_CURRENT_BINARY_DIR}"
+  "${CMAKE_CURRENT_SOURCE_DIR}"
+)
 if(USE_ARES)
-  include_directories(${CARES_INCLUDE_DIR})
+  include_directories(${CARES_INCLUDE_DIRS})
 endif()
 
 #-----------------------------------------------------------------------------
@@ -88,19 +86,19 @@ return() # The rest of this file is not needed for building within CMake.
 
 if(BUILD_TESTING)
   add_library(
-    curlu # special libcurlu library just for unittests
+    curlu  # special libcurlu library just for unittests
     STATIC
     EXCLUDE_FROM_ALL
     ${HHEADERS} ${CSOURCES}
   )
-  target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
+  target_compile_definitions(curlu PUBLIC "UNITTESTS" "CURL_STATICLIB")
   target_link_libraries(curlu PRIVATE ${CURL_LIBS})
 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)
+  set_source_files_properties("memdebug.c" "curl_multibyte.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 endif()
 
 ## Library definition
@@ -135,13 +133,12 @@ if(SHARE_LIB_OBJECT)
     # exported libcurl symbols. We handle exports via libcurl.def instead.
     # Except with symbol hiding disabled or debug mode enabled, when we export
     # _all_ symbols from libcurl DLL, without using libcurl.def.
-    set_property(TARGET ${LIB_OBJECT} APPEND
-      PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
+    set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
   endif()
   target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
   set_target_properties(${LIB_OBJECT} PROPERTIES
     POSITION_INDEPENDENT_CODE ON)
-  if(HIDES_CURL_PRIVATE_SYMBOLS)
+  if(CURL_HIDES_PRIVATE_SYMBOLS)
     set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
     set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
@@ -152,22 +149,21 @@ if(SHARE_LIB_OBJECT)
   endif()
 
   target_include_directories(${LIB_OBJECT} INTERFACE
-    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
 
   set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
 else()
   set(LIB_SOURCE ${HHEADERS} ${CSOURCES})
 endif()
 
-# we want it to be called libcurl on all platforms
+# We want it to be called libcurl on all platforms
 if(BUILD_STATIC_LIBS)
   list(APPEND libcurl_export ${LIB_STATIC})
   add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
   add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
   if(WIN32)
-    set_property(TARGET ${LIB_OBJECT} APPEND
-      PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
+    set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
   endif()
   target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
   # Remove the "lib" prefix since the library is already named "libcurl".
@@ -175,7 +171,7 @@ if(BUILD_STATIC_LIBS)
     PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
     SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
     INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
-  if(HIDES_CURL_PRIVATE_SYMBOLS)
+  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()
@@ -186,8 +182,8 @@ if(BUILD_STATIC_LIBS)
   endif()
 
   target_include_directories(${LIB_STATIC} INTERFACE
-    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
 endif()
 
 if(BUILD_SHARED_LIBS)
@@ -198,15 +194,15 @@ if(BUILD_SHARED_LIBS)
     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
+      set_source_files_properties("dllmain.c" PROPERTIES
         SKIP_UNITY_BUILD_INCLUSION ON)
     endif()
-    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
   endif()
   if(WIN32)
-    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
-    if(HIDES_CURL_PRIVATE_SYMBOLS)
-      set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "libcurl.rc")
+    if(CURL_HIDES_PRIVATE_SYMBOLS)
+      set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/lib/libcurl.def")
     endif()
   endif()
   target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
@@ -215,7 +211,7 @@ if(BUILD_SHARED_LIBS)
     PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
     IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
     POSITION_INDEPENDENT_CODE ON)
-  if(HIDES_CURL_PRIVATE_SYMBOLS)
+  if(CURL_HIDES_PRIVATE_SYMBOLS)
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
@@ -226,8 +222,8 @@ if(BUILD_SHARED_LIBS)
   endif()
 
   target_include_directories(${LIB_SHARED} INTERFACE
-    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+    "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
 
   if(CMAKE_DLL_NAME_WITH_SOVERSION OR
     CYGWIN OR
@@ -241,22 +237,64 @@ if(BUILD_SHARED_LIBS)
     # up to v3.x and ELF from v3.x. I cannot imagine someone running CMake
     # on those ancient systems.
     CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
-    set(soversion_default TRUE)
+    set(_soversion_default TRUE)
   else()
-    set(soversion_default FALSE)
+    set(_soversion_default FALSE)
   endif()
 
-  option(CURL_LIBCURL_SOVERSION "Enable libcurl SOVERSION" ${soversion_default})
+  option(CURL_LIBCURL_SOVERSION "Enable libcurl SOVERSION" ${_soversion_default})
+  option(CURL_LIBCURL_VERSIONED_SYMBOLS "Enable libcurl versioned symbols" OFF)
 
-  if(CURL_LIBCURL_SOVERSION)
+  if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
+    # Get 'VERSIONCHANGE', 'VERSIONADD', 'VERSIONDEL', 'VERSIONINFO' variables
     transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
-    include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
+    include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 
-    math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
-    set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
+    math(EXPR _cmakesoname "${VERSIONCHANGE} - ${VERSIONDEL}")
+    set(_cmakeversion "${_cmakesoname}.${VERSIONDEL}.${VERSIONADD}")
+  endif()
 
+  if(CURL_LIBCURL_SOVERSION)
     set_target_properties(${LIB_SHARED} PROPERTIES
-      VERSION "${CMAKEVERSION}" SOVERSION "${CMAKESONAME}")
+      VERSION "${_cmakeversion}" SOVERSION "${_cmakesoname}")
+  endif()
+
+  ## Versioned symbols
+
+  if(CURL_LIBCURL_VERSIONED_SYMBOLS)
+    if(NOT DEFINED CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX)
+      # Default to prefixes used by autotools
+      if(CURL_WITH_MULTI_SSL)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MULTISSL_")
+      elseif(CURL_USE_OPENSSL)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "OPENSSL_")
+      elseif(CURL_USE_MBEDTLS)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MBEDTLS_")
+      elseif(CURL_USE_BEARSSL)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "BEARSSL_")
+      elseif(CURL_USE_WOLFSSL)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "WOLFSSL_")
+      elseif(CURL_USE_GNUTLS)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "GNUTLS_")
+      endif()
+    endif()
+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers" "
+      HIDDEN {};
+      CURL_${CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX}${_cmakesoname}
+      {
+        global: curl_*;
+        local: *;
+      };")
+    include(CheckCSourceCompiles)
+    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}")
+    else()
+      message(WARNING "Versioned symbols requested, but not supported by the toolchain.")
+    endif()
+    unset(CMAKE_REQUIRED_LINK_OPTIONS)
   endif()
 endif()
 
@@ -282,7 +320,7 @@ if(CURL_ENABLE_EXPORT_TARGET)
   endif()
 
   export(TARGETS ${libcurl_export}
-         FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
-         NAMESPACE ${PROJECT_NAME}::
+    FILE "${PROJECT_BINARY_DIR}/libcurl-target.cmake"
+    NAMESPACE ${PROJECT_NAME}::
   )
 endif()

+ 22 - 22
Utilities/cmcurl/lib/altsvc.c

@@ -337,13 +337,13 @@ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
  */
 void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *n;
   if(*altsvcp) {
+    struct Curl_llist_node *e;
+    struct Curl_llist_node *n;
     struct altsvcinfo *altsvc = *altsvcp;
-    for(e = altsvc->list.head; e; e = n) {
-      struct altsvc *as = e->ptr;
-      n = e->next;
+    for(e = Curl_llist_head(&altsvc->list); e; e = n) {
+      struct altsvc *as = Curl_node_elem(e);
+      n = Curl_node_next(e);
       altsvc_free(as);
     }
     free(altsvc->filename);
@@ -358,8 +358,6 @@ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
 CURLcode Curl_altsvc_save(struct Curl_easy *data,
                           struct altsvcinfo *altsvc, const char *file)
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *n;
   CURLcode result = CURLE_OK;
   FILE *out;
   char *tempstore = NULL;
@@ -378,12 +376,14 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
 
   result = Curl_fopen(data, file, &out, &tempstore);
   if(!result) {
+    struct Curl_llist_node *e;
+    struct Curl_llist_node *n;
     fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
           "# This file was generated by libcurl! Edit at your own risk.\n",
           out);
-    for(e = altsvc->list.head; e; e = n) {
-      struct altsvc *as = e->ptr;
-      n = e->next;
+    for(e = Curl_llist_head(&altsvc->list); e; e = n) {
+      struct altsvc *as = Curl_node_elem(e);
+      n = Curl_node_next(e);
       result = altsvc_out(as, out);
       if(result)
         break;
@@ -440,15 +440,15 @@ static bool hostcompare(const char *host, const char *check)
 static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
                          const char *srchost, unsigned short srcport)
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *n;
-  for(e = asi->list.head; e; e = n) {
-    struct altsvc *as = e->ptr;
-    n = e->next;
+  struct Curl_llist_node *e;
+  struct Curl_llist_node *n;
+  for(e = Curl_llist_head(&asi->list); e; e = n) {
+    struct altsvc *as = Curl_node_elem(e);
+    n = Curl_node_next(e);
     if((srcalpnid == as->src.alpnid) &&
        (srcport == as->src.port) &&
        hostcompare(srchost, as->src.host)) {
-      Curl_llist_remove(&asi->list, e, NULL);
+      Curl_node_remove(e);
       altsvc_free(as);
     }
   }
@@ -677,19 +677,19 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
                         struct altsvc **dstentry,
                         const int versions) /* one or more bits */
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *n;
+  struct Curl_llist_node *e;
+  struct Curl_llist_node *n;
   time_t now = time(NULL);
   DEBUGASSERT(asi);
   DEBUGASSERT(srchost);
   DEBUGASSERT(dstentry);
 
-  for(e = asi->list.head; e; e = n) {
-    struct altsvc *as = e->ptr;
-    n = e->next;
+  for(e = Curl_llist_head(&asi->list); e; e = n) {
+    struct altsvc *as = Curl_node_elem(e);
+    n = Curl_node_next(e);
     if(as->expires < now) {
       /* an expired entry, remove */
-      Curl_llist_remove(&asi->list, e, NULL);
+      Curl_node_remove(e);
       altsvc_free(as);
       continue;
     }

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

@@ -48,7 +48,7 @@ struct altsvc {
   time_t expires;
   bool persist;
   unsigned int prio;
-  struct Curl_llist_element node;
+  struct Curl_llist_node node;
 };
 
 struct altsvcinfo {

+ 1 - 251
Utilities/cmcurl/lib/asyn-thread.c

@@ -54,7 +54,6 @@
 #  define RESOLVER_ENOMEM  ENOMEM
 #endif
 
-#include "system_win32.h"
 #include "urldata.h"
 #include "sendf.h"
 #include "hostip.h"
@@ -145,22 +144,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints);
 
-#ifdef _WIN32
-/* Thread sync data used by GetAddrInfoExW for win8+ */
-struct thread_sync_data_w8
-{
-  OVERLAPPED overlapped;
-  ADDRINFOEXW_ *res;
-  HANDLE cancel_ev;
-  ADDRINFOEXW_ hints;
-};
-#endif
 
 /* Data for synchronization between resolver thread and its parent */
 struct thread_sync_data {
-#ifdef _WIN32
-  struct thread_sync_data_w8 w8;
-#endif
   curl_mutex_t *mtx;
   int done;
   int port;
@@ -179,9 +165,6 @@ struct thread_sync_data {
 };
 
 struct thread_data {
-#ifdef _WIN32
-  HANDLE complete_ev;
-#endif
   curl_thread_t thread_hnd;
   unsigned int poll_interval;
   timediff_t interval_end;
@@ -293,162 +276,6 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
   return result;
 }
 
-#ifdef _WIN32
-static VOID WINAPI
-query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
-{
-  size_t ss_size;
-  const ADDRINFOEXW_ *ai;
-  struct Curl_addrinfo *ca;
-  struct Curl_addrinfo *cafirst = NULL;
-  struct Curl_addrinfo *calast = NULL;
-#ifndef CURL_DISABLE_SOCKETPAIR
-#ifdef USE_EVENTFD
-  const void *buf;
-  const uint64_t val = 1;
-#else
-  char buf[1];
-#endif
-#endif
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wcast-align"
-#endif
-  struct thread_sync_data *tsd =
-    CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-  struct thread_data *td = tsd->td;
-  const ADDRINFOEXW_ *res = tsd->w8.res;
-  int error = (int)err;
-  (void)bytes;
-
-  if(error == ERROR_SUCCESS) {
-    /* traverse the addrinfo list */
-
-    for(ai = res; ai != NULL; ai = ai->ai_next) {
-      size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
-      /* ignore elements with unsupported address family, */
-      /* settle family-specific sockaddr structure size.  */
-      if(ai->ai_family == AF_INET)
-        ss_size = sizeof(struct sockaddr_in);
-#ifdef USE_IPV6
-      else if(ai->ai_family == AF_INET6)
-        ss_size = sizeof(struct sockaddr_in6);
-#endif
-      else
-        continue;
-
-      /* ignore elements without required address info */
-      if(!ai->ai_addr || !(ai->ai_addrlen > 0))
-        continue;
-
-      /* ignore elements with bogus address size */
-      if((size_t)ai->ai_addrlen < ss_size)
-        continue;
-
-      ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
-      if(!ca) {
-        error = EAI_MEMORY;
-        break;
-      }
-
-      /* copy each structure member individually, member ordering, */
-      /* size, or padding might be different for each platform.    */
-      ca->ai_flags     = ai->ai_flags;
-      ca->ai_family    = ai->ai_family;
-      ca->ai_socktype  = ai->ai_socktype;
-      ca->ai_protocol  = ai->ai_protocol;
-      ca->ai_addrlen   = (curl_socklen_t)ss_size;
-      ca->ai_addr      = NULL;
-      ca->ai_canonname = NULL;
-      ca->ai_next      = NULL;
-
-      ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
-      memcpy(ca->ai_addr, ai->ai_addr, ss_size);
-
-      if(namelen) {
-        size_t i;
-        ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
-        for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
-          ca->ai_canonname[i] = (char)ai->ai_canonname[i];
-        ca->ai_canonname[namelen] = '\0';
-      }
-
-      /* if the return list is empty, this becomes the first element */
-      if(!cafirst)
-        cafirst = ca;
-
-      /* add this element last in the return list */
-      if(calast)
-        calast->ai_next = ca;
-      calast = ca;
-    }
-
-    /* if we failed, also destroy the Curl_addrinfo list */
-    if(error) {
-      Curl_freeaddrinfo(cafirst);
-      cafirst = NULL;
-    }
-    else if(!cafirst) {
-#ifdef EAI_NONAME
-      /* rfc3493 conformant */
-      error = EAI_NONAME;
-#else
-      /* rfc3493 obsoleted */
-      error = EAI_NODATA;
-#endif
-#ifdef USE_WINSOCK
-      SET_SOCKERRNO(error);
-#endif
-    }
-    tsd->res = cafirst;
-  }
-
-  if(tsd->w8.res) {
-    Curl_FreeAddrInfoExW(tsd->w8.res);
-    tsd->w8.res = NULL;
-  }
-
-  if(error) {
-    tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
-    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
-      buf = &val;
-#else
-      buf[0] = 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 = 1;
-    Curl_mutex_release(tsd->mtx);
-    if(td->complete_ev)
-      SetEvent(td->complete_ev); /* Notify caller that the query completed */
-  }
-}
-#endif
 
 #ifdef HAVE_GETADDRINFO
 
@@ -585,26 +412,9 @@ static void destroy_async_data(struct Curl_async *async)
     Curl_mutex_release(td->tsd.mtx);
 
     if(!done) {
-#ifdef _WIN32
-      if(td->complete_ev) {
-        CloseHandle(td->complete_ev);
-        td->complete_ev = NULL;
-      }
-#endif
-      if(td->thread_hnd != curl_thread_t_null) {
-        Curl_thread_destroy(td->thread_hnd);
-        td->thread_hnd = curl_thread_t_null;
-      }
+      Curl_thread_destroy(td->thread_hnd);
     }
     else {
-#ifdef _WIN32
-      if(td->complete_ev) {
-        Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
-        WaitForSingleObject(td->complete_ev, INFINITE);
-        CloseHandle(td->complete_ev);
-        td->complete_ev = NULL;
-      }
-#endif
       if(td->thread_hnd != curl_thread_t_null)
         Curl_thread_join(&td->thread_hnd);
 
@@ -650,9 +460,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
   asp->status = 0;
   asp->dns = NULL;
   td->thread_hnd = curl_thread_t_null;
-#ifdef _WIN32
-  td->complete_ev = NULL;
-#endif
 
   if(!init_thread_sync_data(td, hostname, port, hints)) {
     asp->tdata = NULL;
@@ -668,42 +475,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
   /* The thread will set this to 1 when complete. */
   td->tsd.done = 0;
 
-#ifdef _WIN32
-  if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
-     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW &&
-     !Curl_win32_impersonating()) {
-#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
-#define MAX_PORT_LEN 8
-    WCHAR namebuf[MAX_NAME_LEN];
-    WCHAR portbuf[MAX_PORT_LEN];
-    /* calculate required length */
-    int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
-                                    -1, NULL, 0);
-    if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
-      /* do utf8 conversion */
-      w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
-      if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
-        swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
-        td->tsd.w8.hints.ai_family = hints->ai_family;
-        td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
-        td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
-        if(!td->complete_ev) {
-          /* failed to start, mark it as done here for proper cleanup. */
-          td->tsd.done = 1;
-          goto err_exit;
-        }
-        err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
-                                  NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
-                                  NULL, &td->tsd.w8.overlapped,
-                                  &query_complete, &td->tsd.w8.cancel_ev);
-        if(err != WSA_IO_PENDING)
-          query_complete((DWORD)err, 0, &td->tsd.w8.overlapped);
-        return TRUE;
-      }
-    }
-  }
-#endif
-
 #ifdef HAVE_GETADDRINFO
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
 #else
@@ -740,23 +511,9 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
   DEBUGASSERT(data);
   td = data->state.async.tdata;
   DEBUGASSERT(td);
-#ifdef _WIN32
-  DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
-#else
   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
-#endif
 
   /* wait for the thread to resolve the name */
-#ifdef _WIN32
-  if(td->complete_ev) {
-    WaitForSingleObject(td->complete_ev, INFINITE);
-    CloseHandle(td->complete_ev);
-    td->complete_ev = NULL;
-    if(entry)
-      result = getaddrinfo_complete(data);
-  }
-  else
-#endif
   if(Curl_thread_join(&td->thread_hnd)) {
     if(entry)
       result = getaddrinfo_complete(data);
@@ -793,13 +550,6 @@ void Curl_resolver_kill(struct Curl_easy *data)
   /* 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. */
-#ifdef _WIN32
-  if(td && td->complete_ev) {
-    Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
-    (void)thread_wait_resolv(data, NULL, FALSE);
-  }
-  else
-#endif
   if(td && td->thread_hnd != curl_thread_t_null
      && (data->set.quick_exit != 1L))
     (void)thread_wait_resolv(data, NULL, FALSE);

+ 69 - 0
Utilities/cmcurl/lib/bufq.c

@@ -91,6 +91,23 @@ static size_t chunk_read(struct buf_chunk *chunk,
   }
 }
 
+static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len)
+{
+  size_t n = chunk->w_offset - chunk->r_offset;
+  DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
+  if(!n) {
+    return 0;
+  }
+  else if(n <= len) {
+    chunk->r_offset = chunk->w_offset = 0;
+    return n;
+  }
+  else {
+    chunk->w_offset -= len;
+    return len;
+  }
+}
+
 static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
                             Curl_bufq_reader *reader,
                             void *reader_ctx, CURLcode *err)
@@ -363,6 +380,49 @@ static void prune_head(struct bufq *q)
   }
 }
 
+static struct buf_chunk *chunk_prev(struct buf_chunk *head,
+                                    struct buf_chunk *chunk)
+{
+  while(head) {
+    if(head == chunk)
+      return NULL;
+    if(head->next == chunk)
+      return head;
+    head = head->next;
+  }
+  return NULL;
+}
+
+static void prune_tail(struct bufq *q)
+{
+  struct buf_chunk *chunk;
+
+  while(q->tail && chunk_is_empty(q->tail)) {
+    chunk = q->tail;
+    q->tail = chunk_prev(q->head, chunk);
+    if(q->tail)
+      q->tail->next = NULL;
+    if(q->head == chunk)
+      q->head = q->tail;
+    if(q->pool) {
+      bufcp_put(q->pool, chunk);
+      --q->chunk_count;
+    }
+    else if((q->chunk_count > q->max_chunks) ||
+       (q->opts & BUFQ_OPT_NO_SPARES)) {
+      /* SOFT_LIMIT allowed us more than max. free spares until
+       * we are at max again. Or free them if we are configured
+       * to not use spares. */
+      free(chunk);
+      --q->chunk_count;
+    }
+    else {
+      chunk->next = q->spare;
+      q->spare = chunk;
+    }
+  }
+}
+
 static struct buf_chunk *get_non_full_tail(struct bufq *q)
 {
   struct buf_chunk *chunk;
@@ -428,6 +488,15 @@ CURLcode Curl_bufq_cwrite(struct bufq *q,
   return result;
 }
 
+CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
+{
+  while(len && q->tail) {
+    len -= chunk_unwrite(q->head, len);
+    prune_tail(q);
+  }
+  return len? CURLE_AGAIN : CURLE_OK;
+}
+
 ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
                        CURLcode *err)
 {

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

@@ -182,6 +182,12 @@ CURLcode Curl_bufq_cwrite(struct bufq *q,
                          const char *buf, size_t len,
                          size_t *pnwritten);
 
+/**
+ * Remove `len` bytes from the end of the buffer queue again.
+ * Returns CURLE_AGAIN if less than `len` bytes were in the queue.
+ */
+CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
+
 /**
  * Read buf from the start of the buffer queue. The buf is copied
  * and the amount of copied bytes is returned.

+ 170 - 145
Utilities/cmcurl/lib/c-hyper.c

@@ -119,7 +119,7 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx,
 
   DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
   result = Curl_conn_send(data, io_ctx->sockindex,
-                          (void *)buf, buflen, &nwrote);
+                          (void *)buf, buflen, FALSE, &nwrote);
   if(result == CURLE_AGAIN) {
     DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
     /* would block, register interest */
@@ -352,6 +352,8 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
   (void)conn;
 
   if(data->hyp.send_body_waker) {
+    /* If there is still something to upload, wake it to give it
+     * another try. */
     hyper_waker_wake(data->hyp.send_body_waker);
     data->hyp.send_body_waker = NULL;
   }
@@ -367,7 +369,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
     h->write_waker = NULL;
   }
 
-  do {
+  while(1) {
     hyper_task_return_type t;
     task = hyper_executor_poll(h->exec);
     if(!task) {
@@ -391,22 +393,22 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
         switch(code) {
         case HYPERE_ABORTED_BY_CALLBACK:
           result = CURLE_OK;
-          break;
+          goto out;
         case HYPERE_UNEXPECTED_EOF:
           if(!data->req.bytecount)
             result = CURLE_GOT_NOTHING;
           else
             result = CURLE_RECV_ERROR;
-          break;
+          goto out;
         case HYPERE_INVALID_PEER_MESSAGE:
           /* bump headerbytecount to avoid the count remaining at zero and
              appearing to not having read anything from the peer at all */
           data->req.headerbytecount++;
           result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
-          break;
+          goto out;
         default:
           result = CURLE_RECV_ERROR;
-          break;
+          goto out;
         }
       }
       data->req.done = TRUE;
@@ -416,7 +418,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
     else if(t == HYPER_TASK_EMPTY) {
       void *userdata = hyper_task_userdata(task);
       hyper_task_free(task);
-      if((userdata_t)userdata == USERDATA_RESP_BODY) {
+      if(userdata == (void *)USERDATA_RESP_BODY) {
         /* end of transfer */
         data->req.done = TRUE;
         infof(data, "hyperstream is done");
@@ -428,103 +430,115 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
       }
       else {
         /* A background task for hyper; ignore */
+        DEBUGF(infof(data, "hyper: some background task done"));
         continue;
       }
     }
+    else if(t == HYPER_TASK_RESPONSE) {
+      resp = hyper_task_value(task);
+      hyper_task_free(task);
 
-    DEBUGASSERT(HYPER_TASK_RESPONSE);
-
-    resp = hyper_task_value(task);
-    hyper_task_free(task);
-
-    *didwhat = KEEP_RECV;
-    if(!resp) {
-      failf(data, "hyperstream: could not get response");
-      return CURLE_RECV_ERROR;
-    }
+      *didwhat = KEEP_RECV;
+      if(!resp) {
+        failf(data, "hyperstream: could not get response");
+        result = CURLE_RECV_ERROR;
+        goto out;
+      }
 
-    http_status = hyper_response_status(resp);
-    http_version = hyper_response_version(resp);
-    reasonp = hyper_response_reason_phrase(resp);
-    reason_len = hyper_response_reason_phrase_len(resp);
+      http_status = hyper_response_status(resp);
+      http_version = hyper_response_version(resp);
+      reasonp = hyper_response_reason_phrase(resp);
+      reason_len = hyper_response_reason_phrase_len(resp);
 
-    if(http_status == 417 && Curl_http_exp100_is_selected(data)) {
-      infof(data, "Got 417 while waiting for a 100");
-      data->state.disableexpect = TRUE;
-      data->req.newurl = strdup(data->state.url);
-      Curl_req_abort_sending(data);
-    }
+      if(http_status == 417 && Curl_http_exp100_is_selected(data)) {
+        infof(data, "Got 417 while waiting for a 100");
+        data->state.disableexpect = TRUE;
+        data->req.newurl = strdup(data->state.url);
+        Curl_req_abort_sending(data);
+      }
 
-    result = status_line(data, conn,
-                         http_status, http_version, reasonp, reason_len);
-    if(result)
-      break;
+      result = status_line(data, conn,
+                           http_status, http_version, reasonp, reason_len);
+      if(result)
+        goto out;
 
-    headers = hyper_response_headers(resp);
-    if(!headers) {
-      failf(data, "hyperstream: could not get response headers");
-      result = CURLE_RECV_ERROR;
-      break;
-    }
+      headers = hyper_response_headers(resp);
+      if(!headers) {
+        failf(data, "hyperstream: could not get response headers");
+        result = CURLE_RECV_ERROR;
+        goto out;
+      }
 
-    /* the headers are already received */
-    hyper_headers_foreach(headers, hyper_each_header, data);
-    if(data->state.hresult) {
-      result = data->state.hresult;
-      break;
-    }
+      /* the headers are already received */
+      hyper_headers_foreach(headers, hyper_each_header, data);
+      if(data->state.hresult) {
+        result = data->state.hresult;
+        goto out;
+      }
 
-    result = empty_header(data);
-    if(result)
-      break;
+      result = empty_header(data);
+      if(result)
+        goto out;
 
-    k->deductheadercount =
-      (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
+      k->deductheadercount =
+        (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
 #ifdef USE_WEBSOCKETS
-    if(k->upgr101 == UPGR101_WS) {
-      if(http_status == 101) {
-        /* verify the response */
-        result = Curl_ws_accept(data, NULL, 0);
-        if(result)
-          return result;
-      }
-      else {
-        failf(data, "Expected 101, got %u", k->httpcode);
-        result = CURLE_HTTP_RETURNED_ERROR;
-        break;
+      if(k->upgr101 == UPGR101_WS) {
+        if(http_status == 101) {
+          /* verify the response */
+          result = Curl_ws_accept(data, NULL, 0);
+          if(result)
+            goto out;
+        }
+        else {
+          failf(data, "Expected 101, got %u", k->httpcode);
+          result = CURLE_HTTP_RETURNED_ERROR;
+          goto out;
+        }
       }
-    }
 #endif
 
-    /* Curl_http_auth_act() checks what authentication methods that are
-     * available and decides which one (if any) to use. It will set 'newurl'
-     * if an auth method was picked. */
-    result = Curl_http_auth_act(data);
-    if(result)
-      break;
+      /* Curl_http_auth_act() checks what authentication methods that are
+       * available and decides which one (if any) to use. It will set 'newurl'
+       * if an auth method was picked. */
+      result = Curl_http_auth_act(data);
+      if(result)
+        goto out;
 
-    resp_body = hyper_response_body(resp);
-    if(!resp_body) {
-      failf(data, "hyperstream: could not get response body");
-      result = CURLE_RECV_ERROR;
-      break;
-    }
-    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
-    if(!foreach) {
-      failf(data, "hyperstream: body foreach failed");
-      result = CURLE_OUT_OF_MEMORY;
-      break;
+      resp_body = hyper_response_body(resp);
+      if(!resp_body) {
+        failf(data, "hyperstream: could not get response body");
+        result = CURLE_RECV_ERROR;
+        goto out;
+      }
+      foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+      if(!foreach) {
+        failf(data, "hyperstream: body foreach failed");
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
+      if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
+        failf(data, "Couldn't hyper_executor_push the body-foreach");
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+
+      hyper_response_free(resp);
+      resp = NULL;
     }
-    hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
-    if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
-      failf(data, "Couldn't hyper_executor_push the body-foreach");
-      result = CURLE_OUT_OF_MEMORY;
-      break;
+    else {
+      DEBUGF(infof(data, "hyper: unhandled tasktype %x", t));
     }
+  } /* while(1) */
 
-    hyper_response_free(resp);
-    resp = NULL;
-  } while(1);
+  if(!result && Curl_xfer_needs_flush(data)) {
+    DEBUGF(infof(data, "Curl_hyper_stream(), connection needs flush"));
+    result = Curl_xfer_flush(data);
+  }
+
+out:
+  DEBUGF(infof(data, "Curl_hyper_stream() -> %d", result));
   if(resp)
     hyper_response_free(resp);
   return result;
@@ -671,10 +685,13 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
     /* increasing the writebytecount here is a little premature but we
        do not know exactly when the body is sent */
     data->req.writebytecount += fillcount;
+    if(eos)
+      data->req.eos_read = TRUE;
     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
     rc = HYPER_POLL_READY;
   }
   else if(eos) {
+    data->req.eos_read = TRUE;
     *chunk = NULL;
     rc = HYPER_POLL_READY;
   }
@@ -686,9 +703,15 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
     rc = HYPER_POLL_PENDING;
   }
 
+  if(!data->req.upload_done && data->req.eos_read) {
+    DEBUGF(infof(data, "hyper: uploadstreamed(), upload is done"));
+    result = Curl_req_set_upload_done(data);
+  }
+
 out:
   Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
   data->state.hresult = result;
+  DEBUGF(infof(data, "hyper: uploadstreamed() -> %d", result));
   return rc;
 }
 
@@ -702,8 +725,9 @@ static CURLcode finalize_request(struct Curl_easy *data,
 {
   CURLcode result = CURLE_OK;
   struct dynbuf req;
-  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
     Curl_pgrsSetUploadSize(data, 0); /* no request body */
+  }
   else {
     hyper_body *body;
     Curl_dyn_init(&req, DYN_HTTP_REQUEST);
@@ -821,21 +845,21 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   *done = TRUE;
   result = Curl_client_start(data);
   if(result)
-    return result;
+    goto out;
 
   /* Add collecting of headers written to client. For a new connection,
    * we might have done that already, but reuse
    * or multiplex needs it here as well. */
   result = Curl_headers_init(data);
   if(result)
-    return result;
+    goto out;
 
   infof(data, "Time for the Hyper dance");
   memset(h, 0, sizeof(struct hyptransfer));
 
   result = Curl_http_host(data, conn);
   if(result)
-    return result;
+    goto out;
 
   Curl_http_method(data, conn, &method, &httpreq);
 
@@ -846,33 +870,35 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     char *pq = NULL;
     if(data->state.up.query) {
       pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
-      if(!pq)
-        return CURLE_OUT_OF_MEMORY;
+      if(!pq) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
     }
     result = Curl_http_output_auth(data, conn, method, httpreq,
                                    (pq ? pq : data->state.up.path), FALSE);
     free(pq);
     if(result)
-      return result;
+      goto out;
   }
 
   result = Curl_http_req_set_reader(data, httpreq, &te);
   if(result)
-    goto error;
+    goto out;
 
   result = Curl_http_range(data, httpreq);
   if(result)
-    return result;
+    goto out;
 
   result = Curl_http_useragent(data);
   if(result)
-    return result;
+    goto out;
 
   io = hyper_io_new();
   if(!io) {
     failf(data, "Couldn't create hyper IO");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   /* tell Hyper how to read/write network data */
   h->io_ctx.data = data;
@@ -887,7 +913,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     if(!h->exec) {
       failf(data, "Couldn't create hyper executor");
       result = CURLE_OUT_OF_MEMORY;
-      goto error;
+      goto out;
     }
   }
 
@@ -895,12 +921,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!options) {
     failf(data, "Couldn't create hyper client options");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   if(conn->alpn == CURL_HTTP_VERSION_2) {
     failf(data, "ALPN protocol h2 not supported with Hyper");
     result = CURLE_UNSUPPORTED_PROTOCOL;
-    goto error;
+    goto out;
   }
   hyper_clientconn_options_set_preserve_header_case(options, 1);
   hyper_clientconn_options_set_preserve_header_order(options, 1);
@@ -913,7 +939,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!handshake) {
     failf(data, "Couldn't create hyper client handshake");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   io = NULL;
   options = NULL;
@@ -921,7 +947,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
     failf(data, "Couldn't hyper_executor_push the handshake");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   handshake = NULL; /* ownership passed on */
 
@@ -929,7 +955,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!task) {
     failf(data, "Couldn't hyper_executor_poll the handshake");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
 
   client = hyper_task_value(task);
@@ -939,7 +965,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!req) {
     failf(data, "Couldn't hyper_request_new");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
 
   if(!Curl_use_http_1_1plus(data, conn)) {
@@ -947,57 +973,57 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
                                               HYPER_HTTP_VERSION_1_0)) {
       failf(data, "error setting HTTP version");
       result = CURLE_OUT_OF_MEMORY;
-      goto error;
+      goto out;
     }
   }
 
   if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
     failf(data, "error setting method");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
 
   result = request_target(data, conn, method, req);
   if(result)
-    goto error;
+    goto out;
 
   headers = hyper_request_headers(req);
   if(!headers) {
     failf(data, "hyper_request_headers");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
 
   rc = hyper_request_on_informational(req, http1xx_cb, data);
   if(rc) {
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
 
   if(data->state.aptr.host) {
     result = Curl_hyper_header(data, headers, data->state.aptr.host);
     if(result)
-      goto error;
+      goto out;
   }
 
 #ifndef CURL_DISABLE_PROXY
   if(data->state.aptr.proxyuserpwd) {
     result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
     if(result)
-      goto error;
+      goto out;
   }
 #endif
 
   if(data->state.aptr.userpwd) {
     result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
     if(result)
-      goto error;
+      goto out;
   }
 
   if((data->state.use_range && data->state.aptr.rangeline)) {
     result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
     if(result)
-      goto error;
+      goto out;
   }
 
   if(data->set.str[STRING_USERAGENT] &&
@@ -1005,7 +1031,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
      data->state.aptr.uagent) {
     result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
     if(result)
-      goto error;
+      goto out;
   }
 
   p_accept = Curl_checkheaders(data,
@@ -1013,12 +1039,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(p_accept) {
     result = Curl_hyper_header(data, headers, p_accept);
     if(result)
-      goto error;
+      goto out;
   }
   if(te) {
     result = Curl_hyper_header(data, headers, te);
     if(result)
-      goto error;
+      goto out;
   }
 
 #ifndef CURL_DISABLE_ALTSVC
@@ -1027,11 +1053,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
                             conn->conn_to_host.name, conn->conn_to_port);
     if(!altused) {
       result = CURLE_OUT_OF_MEMORY;
-      goto error;
+      goto out;
     }
     result = Curl_hyper_header(data, headers, altused);
     if(result)
-      goto error;
+      goto out;
     free(altused);
   }
 #endif
@@ -1042,7 +1068,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
      !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
     result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
     if(result)
-      goto error;
+      goto out;
   }
 #endif
 
@@ -1054,17 +1080,17 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     else
       result = Curl_hyper_header(data, headers, data->state.aptr.ref);
     if(result)
-      goto error;
+      goto out;
   }
 
 #ifdef HAVE_LIBZ
   /* we only consider transfer-encoding magic if libz support is built-in */
   result = Curl_transferencode(data);
   if(result)
-    goto error;
+    goto out;
   result = Curl_hyper_header(data, headers, data->state.aptr.te);
   if(result)
-    goto error;
+    goto out;
 #endif
 
   if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
@@ -1078,29 +1104,29 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       result = Curl_hyper_header(data, headers,
                                  data->state.aptr.accept_encoding);
     if(result)
-      goto error;
+      goto out;
   }
   else
     Curl_safefree(data->state.aptr.accept_encoding);
 
   result = cookies(data, conn, headers);
   if(result)
-    goto error;
+    goto out;
 
   if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
     result = Curl_ws_request(data, headers);
 
   result = Curl_add_timecondition(data, headers);
   if(result)
-    goto error;
+    goto out;
 
   result = Curl_add_custom_headers(data, FALSE, headers);
   if(result)
-    goto error;
+    goto out;
 
   result = finalize_request(data, headers, req, httpreq);
   if(result)
-    goto error;
+    goto out;
 
   Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
 
@@ -1114,14 +1140,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!sendtask) {
     failf(data, "hyper_clientconn_send");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   req = NULL;
 
   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
     failf(data, "Couldn't hyper_executor_push the send");
     result = CURLE_OUT_OF_MEMORY;
-    goto error;
+    goto out;
   }
   sendtask = NULL; /* ownership passed on */
 
@@ -1131,6 +1157,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
     /* HTTP GET/HEAD download */
     Curl_pgrsSetUploadSize(data, 0); /* nothing */
+    result = Curl_req_set_upload_done(data);
+    if(result)
+      goto out;
   }
 
   Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
@@ -1142,24 +1171,20 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 #ifndef CURL_DISABLE_PROXY
   Curl_safefree(data->state.aptr.proxyuserpwd);
 #endif
-  return CURLE_OK;
-error:
-  DEBUGASSERT(result);
-  if(io)
-    hyper_io_free(io);
-
-  if(options)
-    hyper_clientconn_options_free(options);
-
-  if(handshake)
-    hyper_task_free(handshake);
-
-  if(client)
-    hyper_clientconn_free(client);
-
-  if(req)
-    hyper_request_free(req);
 
+out:
+  if(result) {
+    if(io)
+      hyper_io_free(io);
+    if(options)
+      hyper_clientconn_options_free(options);
+    if(handshake)
+      hyper_task_free(handshake);
+    if(client)
+      hyper_clientconn_free(client);
+    if(req)
+      hyper_request_free(req);
+  }
   return result;
 }
 

+ 2 - 3
Utilities/cmcurl/lib/cf-h1-proxy.c

@@ -266,7 +266,7 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
   blen -= ts->nsent;
   buf += ts->nsent;
 
-  nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result);
+  nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result);
   if(nwritten < 0) {
     if(result == CURLE_AGAIN) {
       result = CURLE_OK;
@@ -489,8 +489,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
         ts->keepon = KEEPON_IGNORE;
 
         if(ts->cl) {
-          infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
-                " bytes of response-body", ts->cl);
+          infof(data, "Ignore %" FMT_OFF_T " bytes of response-body", ts->cl);
         }
         else if(ts->chunked_encoding) {
           infof(data, "Ignore chunked response-body");

+ 108 - 84
Utilities/cmcurl/lib/cf-h2-proxy.c

@@ -73,7 +73,6 @@ struct tunnel_stream {
   char *authority;
   int32_t stream_id;
   uint32_t error;
-  size_t upload_blocked_len;
   h2_tunnel_state state;
   BIT(has_final_response);
   BIT(closed);
@@ -217,11 +216,13 @@ static void drain_tunnel(struct Curl_cfilter *cf,
                          struct Curl_easy *data,
                          struct tunnel_stream *tunnel)
 {
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
   unsigned char bits;
 
   (void)cf;
   bits = CURL_CSELECT_IN;
-  if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
+  if(!tunnel->closed && !tunnel->reset &&
+     !Curl_bufq_is_empty(&ctx->tunnel.sendbuf))
     bits |= CURL_CSELECT_OUT;
   if(data->state.select_bits != bits) {
     CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
@@ -260,7 +261,7 @@ static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
   if(cf) {
     struct Curl_easy *data = CF_DATA_CURRENT(cf);
     nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
-                                 err);
+                                 FALSE, err);
     CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
                 buflen, nwritten, *err);
   }
@@ -1079,7 +1080,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
   } while(ts->state == H2_TUNNEL_INIT);
 
 out:
-  if(result || ctx->tunnel.closed)
+  if((result && (result != CURLE_AGAIN)) || ctx->tunnel.closed)
     h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
   return result;
 }
@@ -1185,7 +1186,8 @@ static CURLcode cf_h2_proxy_shutdown(struct Curl_cfilter *cf,
   if(!ctx->sent_goaway) {
     rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
                                0, 0,
-                               (const uint8_t *)"shutown", sizeof("shutown"));
+                               (const uint8_t *)"shutdown",
+                               sizeof("shutdown"));
     if(rv) {
       failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
             nghttp2_strerror(rv), rv);
@@ -1231,7 +1233,9 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
   bool want_recv, want_send;
 
   if(!cf->connected && ctx->h2) {
-    want_send = nghttp2_session_want_write(ctx->h2);
+    want_send = nghttp2_session_want_write(ctx->h2) ||
+                !Curl_bufq_is_empty(&ctx->outbufq) ||
+                !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
     want_recv = nghttp2_session_want_read(ctx->h2);
   }
   else
@@ -1247,17 +1251,25 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
                    ctx->h2, ctx->tunnel.stream_id);
     want_recv = (want_recv || c_exhaust || s_exhaust);
     want_send = (!s_exhaust && want_send) ||
-                (!c_exhaust && nghttp2_session_want_write(ctx->h2));
+                (!c_exhaust && nghttp2_session_want_write(ctx->h2)) ||
+                !Curl_bufq_is_empty(&ctx->outbufq) ||
+                !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
 
     Curl_pollset_set(data, ps, sock, want_recv, want_send);
+    CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
+                want_recv, want_send);
     CF_DATA_RESTORE(cf, save);
   }
   else if(ctx->sent_goaway && !cf->shutdown) {
     /* shutdown in progress */
     CF_DATA_SAVE(save, cf, data);
-    want_send = nghttp2_session_want_write(ctx->h2);
+    want_send = nghttp2_session_want_write(ctx->h2) ||
+                !Curl_bufq_is_empty(&ctx->outbufq) ||
+                !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
     want_recv = nghttp2_session_want_read(ctx->h2);
     Curl_pollset_set(data, ps, sock, want_recv, want_send);
+    CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
+                want_recv, want_send);
     CF_DATA_RESTORE(cf, save);
   }
 }
@@ -1364,16 +1376,7 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
   }
 
   result = proxy_h2_progress_egress(cf, data);
-  if(result == CURLE_AGAIN) {
-    /* pending data to send, need to be called again. Ideally, we would
-     * monitor the socket for POLLOUT, but we might not be in SENDING
-     * transfer state any longer and are unable to make this happen.
-     */
-    CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
-                ctx->tunnel.stream_id);
-    drain_tunnel(cf, data, &ctx->tunnel);
-  }
-  else if(result) {
+  if(result && (result != CURLE_AGAIN)) {
     *err = result;
     nread = -1;
   }
@@ -1393,15 +1396,16 @@ out:
 
 static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
-                                const void *buf, size_t len, CURLcode *err)
+                                const void *buf, size_t len, bool eos,
+                                CURLcode *err)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   struct cf_call_data save;
   int rv;
   ssize_t nwritten;
   CURLcode result;
-  int blocked = 0;
 
+  (void)eos; /* TODO, maybe useful for blocks? */
   if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
     *err = CURLE_SEND_ERROR;
     return -1;
@@ -1413,29 +1417,10 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
     *err = CURLE_SEND_ERROR;
     goto out;
   }
-  else if(ctx->tunnel.upload_blocked_len) {
-    /* the data in `buf` has already been submitted or added to the
-     * buffers, but have been EAGAINed on the last invocation. */
-    DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len);
-    if(len < ctx->tunnel.upload_blocked_len) {
-      /* Did we get called again with a smaller `len`? This should not
-       * happen. We are not prepared to handle that. */
-      failf(data, "HTTP/2 proxy, send again with decreased length");
-      *err = CURLE_HTTP2;
-      nwritten = -1;
-      goto out;
-    }
-    nwritten = (ssize_t)ctx->tunnel.upload_blocked_len;
-    ctx->tunnel.upload_blocked_len = 0;
-    *err = CURLE_OK;
-  }
   else {
     nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
-    if(nwritten < 0) {
-      if(*err != CURLE_AGAIN)
-        goto out;
-      nwritten = 0;
-    }
+    if(nwritten < 0 && (*err != CURLE_AGAIN))
+      goto out;
   }
 
   if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
@@ -1458,52 +1443,13 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
   /* Call the nghttp2 send loop and flush to write ALL buffered data,
    * headers and/or request body completely out to the network */
   result = proxy_h2_progress_egress(cf, data);
-  if(result == CURLE_AGAIN) {
-    blocked = 1;
-  }
-  else if(result) {
+  if(result && (result != CURLE_AGAIN)) {
     *err = result;
     nwritten = -1;
     goto out;
   }
-  else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
-    /* although we wrote everything that nghttp2 wants to send now,
-     * there is data left in our stream send buffer unwritten. This may
-     * be due to the stream's HTTP/2 flow window being exhausted. */
-    blocked = 1;
-  }
-
-  if(blocked) {
-    /* Unable to send all data, due to connection blocked or H2 window
-     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
-     * frame buffer or our network out buffer. */
-    size_t rwin = (size_t)nghttp2_session_get_stream_remote_window_size(
-                    ctx->h2, ctx->tunnel.stream_id);
-    if(rwin == 0) {
-      /* H2 flow window exhaustion.
-       * FIXME: there is no way to HOLD all transfers that use this
-       * proxy connection AND to UNHOLD all of them again when the
-       * window increases.
-       * We *could* iterate over all data on this conn maybe? */
-      CURL_TRC_CF(data, cf, "[%d] remote flow "
-                  "window is exhausted", ctx->tunnel.stream_id);
-    }
 
-    /* Whatever the cause, we need to return CURL_EAGAIN for this call.
-     * We have unwritten state that needs us being invoked again and EAGAIN
-     * is the only way to ensure that. */
-    ctx->tunnel.upload_blocked_len = nwritten;
-    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
-                "blocked_len=%zu",
-                ctx->tunnel.stream_id, len,
-                nghttp2_session_get_remote_window_size(ctx->h2), rwin,
-                nwritten);
-    drain_tunnel(cf, data, &ctx->tunnel);
-    *err = CURLE_AGAIN;
-    nwritten = -1;
-    goto out;
-  }
-  else if(proxy_h2_should_close_session(ctx)) {
+  if(proxy_h2_should_close_session(ctx)) {
     /* nghttp2 thinks this session is done. If the stream has not been
      * closed, this is an error state for out transfer */
     if(ctx->tunnel.closed) {
@@ -1536,6 +1482,38 @@ out:
   return nwritten;
 }
 
+static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+  CURLcode result = CURLE_OK;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
+    /* resume the potentially suspended tunnel */
+    int rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
+    if(nghttp2_is_fatal(rv)) {
+      result = CURLE_SEND_ERROR;
+      goto out;
+    }
+  }
+
+  result = proxy_h2_progress_egress(cf, data);
+
+out:
+  CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
+              "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
+              ctx->tunnel.stream_id, result,
+              nghttp2_session_get_stream_remote_window_size(
+                ctx->h2, ctx->tunnel.stream_id),
+              nghttp2_session_get_remote_window_size(ctx->h2),
+              Curl_bufq_len(&ctx->tunnel.sendbuf),
+              Curl_bufq_len(&ctx->outbufq));
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
 static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool *input_pending)
@@ -1589,6 +1567,52 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
   return result;
 }
 
+static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int query, int *pres1, void *pres2)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_NEED_FLUSH: {
+    if(!Curl_bufq_is_empty(&ctx->outbufq) ||
+       !Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
+      CURL_TRC_CF(data, cf, "needs flush");
+      *pres1 = TRUE;
+      return CURLE_OK;
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static CURLcode cf_h2_proxy_cntrl(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+
+  (void)arg1;
+  (void)arg2;
+
+  switch(event) {
+  case CF_CTRL_FLUSH:
+    CF_DATA_SAVE(save, cf, data);
+    result = cf_h2_proxy_flush(cf, data);
+    CF_DATA_RESTORE(cf, save);
+    break;
+  default:
+    break;
+  }
+  return result;
+}
+
 struct Curl_cftype Curl_cft_h2_proxy = {
   "H2-PROXY",
   CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
@@ -1602,10 +1626,10 @@ struct Curl_cftype Curl_cft_h2_proxy = {
   cf_h2_proxy_data_pending,
   cf_h2_proxy_send,
   cf_h2_proxy_recv,
-  Curl_cf_def_cntrl,
+  cf_h2_proxy_cntrl,
   cf_h2_proxy_is_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  cf_h2_proxy_query,
 };
 
 CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,

+ 19 - 17
Utilities/cmcurl/lib/cf-haproxy.c

@@ -70,8 +70,9 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
 {
   struct cf_haproxy_ctx *ctx = cf->ctx;
   CURLcode result;
-  const char *tcp_version;
   const char *client_ip;
+  struct ip_quadruple ipquad;
+  int is_ipv6;
 
   DEBUGASSERT(ctx);
   DEBUGASSERT(ctx->state == HAPROXY_INIT);
@@ -81,19 +82,20 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
     result = Curl_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);
+  if(result)
+    return result;
+
   /* Emit the correct prefix for IPv6 */
-  tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
   if(data->set.str[STRING_HAPROXY_CLIENT_IP])
     client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
   else
-    client_ip = data->info.primary.local_ip;
+    client_ip = ipquad.local_ip;
 
   result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
-                         tcp_version,
-                         client_ip,
-                         data->info.primary.remote_ip,
-                         data->info.primary.local_port,
-                         data->info.primary.remote_port);
+                         is_ipv6? "TCP6" : "TCP4",
+                         client_ip, ipquad.remote_ip,
+                         ipquad.local_port, ipquad.remote_port);
 
 #ifdef USE_UNIX_SOCKETS
   }
@@ -129,17 +131,17 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
   case HAPROXY_SEND:
     len = Curl_dyn_len(&ctx->data_out);
     if(len > 0) {
-      size_t written;
-      result = Curl_conn_send(data, cf->sockindex,
-                              Curl_dyn_ptr(&ctx->data_out),
-                              len, &written);
-      if(result == CURLE_AGAIN) {
+      ssize_t nwritten;
+      nwritten = Curl_conn_cf_send(cf->next, data,
+                                   Curl_dyn_ptr(&ctx->data_out), len, FALSE,
+                                   &result);
+      if(nwritten < 0) {
+        if(result != CURLE_AGAIN)
+          goto out;
         result = CURLE_OK;
-        written = 0;
+        nwritten = 0;
       }
-      else if(result)
-        goto out;
-      Curl_dyn_tail(&ctx->data_out, len - written);
+      Curl_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
       if(Curl_dyn_len(&ctx->data_out) > 0) {
         result = CURLE_OK;
         goto out;

+ 43 - 6
Utilities/cmcurl/lib/cf-https-connect.c

@@ -96,6 +96,21 @@ static bool cf_hc_baller_data_pending(struct cf_hc_baller *b,
   return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data);
 }
 
+static bool cf_hc_baller_needs_flush(struct cf_hc_baller *b,
+                                     struct Curl_easy *data)
+{
+  return b->cf && !b->result && Curl_conn_cf_needs_flush(b->cf, data);
+}
+
+static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
+                                   struct Curl_easy *data,
+                                   int event, int arg1, void *arg2)
+{
+  if(b->cf && !b->result)
+    return Curl_conn_cf_cntrl(b->cf, data, FALSE, event, arg1, arg2);
+  return CURLE_OK;
+}
+
 struct cf_hc_ctx {
   cf_hc_state state;
   const struct Curl_dns_entry *remotehost;
@@ -174,7 +189,6 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
 
   switch(cf->conn->alpn) {
   case CURL_HTTP_VERSION_3:
-    infof(data, "using HTTP/3");
     break;
   case CURL_HTTP_VERSION_2:
 #ifdef USE_NGHTTP2
@@ -187,16 +201,12 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
       return result;
     }
 #endif
-    infof(data, "using HTTP/2");
     break;
   default:
-    infof(data, "using HTTP/1.x");
     break;
   }
   ctx->state = CF_HC_SUCCESS;
   cf->connected = TRUE;
-  Curl_conn_cf_cntrl(cf->next, data, TRUE,
-                     CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
   return result;
 }
 
@@ -428,6 +438,8 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             int query, int *pres1, void *pres2)
 {
+  struct cf_hc_ctx *ctx = cf->ctx;
+
   if(!cf->connected) {
     switch(query) {
     case CF_QUERY_TIMER_CONNECT: {
@@ -440,6 +452,14 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
       *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
       return CURLE_OK;
     }
+    case CF_QUERY_NEED_FLUSH: {
+      if(cf_hc_baller_needs_flush(&ctx->h3_baller, data)
+         || cf_hc_baller_needs_flush(&ctx->h21_baller, data)) {
+        *pres1 = TRUE;
+        return CURLE_OK;
+      }
+      break;
+    }
     default:
       break;
     }
@@ -449,6 +469,23 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
     CURLE_UNKNOWN_OPTION;
 }
 
+static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int event, int arg1, void *arg2)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  if(!cf->connected) {
+    result = cf_hc_baller_cntrl(&ctx->h3_baller, data, event, arg1, arg2);
+    if(!result || (result == CURLE_AGAIN))
+      result = cf_hc_baller_cntrl(&ctx->h21_baller, data, event, arg1, arg2);
+    if(result == CURLE_AGAIN)
+      result = CURLE_OK;
+  }
+  return result;
+}
+
 static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   CURL_TRC_CF(data, cf, "close");
@@ -484,7 +521,7 @@ struct Curl_cftype Curl_cft_http_connect = {
   cf_hc_data_pending,
   Curl_cf_def_send,
   Curl_cf_def_recv,
-  Curl_cf_def_cntrl,
+  cf_hc_cntrl,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   cf_hc_query,

+ 96 - 52
Utilities/cmcurl/lib/cf-socket.c

@@ -124,7 +124,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
 }
 
 #ifdef SO_NOSIGPIPE
-/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+/* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
    sending data to a dead peer (instead of relying on the 4th argument to send
    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
    systems? */
@@ -146,7 +146,13 @@ static void nosigpipe(struct Curl_easy *data,
 #define nosigpipe(x,y) Curl_nop_stmt
 #endif
 
-#if defined(USE_WINSOCK) || \
+#if defined(USE_WINSOCK) && \
+    defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
+/*  Win 10, v 1709 (10.0.16299) and later can use SetSockOpt TCP_KEEP____
+ *  so should use seconds */
+#define CURL_WINSOCK_KEEP_SSO
+#define KEEPALIVE_FACTOR(x)
+#elif defined(USE_WINSOCK) || \
    (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
    (defined(__DragonFly__) && __DragonFly_version < 500702) || \
    (defined(_WIN32) && !defined(TCP_KEEPIDLE))
@@ -177,19 +183,19 @@ tcpkeepalive(struct Curl_easy *data,
   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
         (void *)&optval, sizeof(optval)) < 0) {
     infof(data, "Failed to set SO_KEEPALIVE on fd "
-          "%" CURL_FORMAT_SOCKET_T ": errno %d",
+          "%" FMT_SOCKET_T ": errno %d",
           sockfd, SOCKERRNO);
   }
   else {
 #if defined(SIO_KEEPALIVE_VALS) /* Windows */
 /* Windows 10, version 1709 (10.0.16299) and later versions */
-#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
+#if defined(CURL_WINSOCK_KEEP_SSO)
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
                 (const char *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPIDLE on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
     optval = curlx_sltosi(data->set.tcp_keepintvl);
@@ -197,14 +203,14 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
                 (const char *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPINTVL on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
     optval = curlx_sltosi(data->set.tcp_keepcnt);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
                 (const char *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPCNT on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
 #else /* Windows < 10.0.16299 */
@@ -220,8 +226,7 @@ tcpkeepalive(struct Curl_easy *data,
     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                 NULL, 0, &dummy, NULL, NULL) != 0) {
       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
-                  "%" CURL_FORMAT_SOCKET_T ": errno %d",
-                  sockfd, SOCKERRNO);
+            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
     }
 #endif
 #else /* !Windows */
@@ -231,17 +236,17 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
           (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPIDLE on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
 #elif defined(TCP_KEEPALIVE)
-    /* Mac OS X style */
+    /* macOS style */
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
       (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
 #elif defined(TCP_KEEPALIVE_THRESHOLD)
@@ -251,7 +256,7 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
       (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
 #endif
@@ -261,7 +266,7 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
           (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPINTVL on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            "%" FMT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
 #elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
@@ -282,8 +287,7 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
           (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
-            sockfd, SOCKERRNO);
+            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
     }
 #endif
 #ifdef TCP_KEEPCNT
@@ -291,8 +295,7 @@ tcpkeepalive(struct Curl_easy *data,
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
                 (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPCNT on fd "
-            "%" CURL_FORMAT_SOCKET_T ": errno %d",
-            sockfd, SOCKERRNO);
+            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
     }
 #endif
 #endif
@@ -404,6 +407,9 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
 static int socket_close(struct Curl_easy *data, struct connectdata *conn,
                         int use_callback, curl_socket_t sock)
 {
+  if(CURL_SOCKET_BAD == sock)
+    return 0;
+
   if(use_callback && conn && conn->fclosesocket) {
     int rc;
     Curl_multi_closed(data, sock);
@@ -502,32 +508,37 @@ void Curl_sndbuf_init(curl_socket_t sockfd)
  *
  * Returns CURLE_OK on success.
  */
-CURLcode Curl_parse_interface(const char *input, size_t len,
+CURLcode Curl_parse_interface(const char *input,
                               char **dev, char **iface, char **host)
 {
   static const char if_prefix[] = "if!";
   static const char host_prefix[] = "host!";
   static const char if_host_prefix[] = "ifhost!";
+  size_t len;
 
   DEBUGASSERT(dev);
   DEBUGASSERT(iface);
   DEBUGASSERT(host);
 
-  if(strncmp(if_prefix, input, strlen(if_prefix)) == 0) {
+  len = strlen(input);
+  if(len > 512)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(!strncmp(if_prefix, input, strlen(if_prefix))) {
     input += strlen(if_prefix);
     if(!*input)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     *iface = Curl_memdup0(input, len - strlen(if_prefix));
     return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
   }
-  if(strncmp(host_prefix, input, strlen(host_prefix)) == 0) {
+  else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
     input += strlen(host_prefix);
     if(!*input)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     *host = Curl_memdup0(input, len - strlen(host_prefix));
     return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
   }
-  if(strncmp(if_host_prefix, input, strlen(if_host_prefix)) == 0) {
+  else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
     const char *host_part;
     input += strlen(if_host_prefix);
     len -= strlen(if_host_prefix);
@@ -679,12 +690,13 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
       conn->ip_version = ipver;
 
       if(h) {
+        int h_af = h->addr->ai_family;
         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
         Curl_printable_address(h->addr, myhost, sizeof(myhost));
         infof(data, "Name '%s' family %i resolved to '%s' family %i",
-              host, af, myhost, h->addr->ai_family);
-        Curl_resolv_unlock(data, h);
-        if(af != h->addr->ai_family) {
+              host, af, myhost, h_af);
+        Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
+        if(af != h_af) {
           /* bad IP version combo, signal the caller to try another address
              family if available */
           return CURLE_UNSUPPORTED_PROTOCOL;
@@ -694,7 +706,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
       else {
         /*
          * provided dev was no interface (or interfaces are not supported
-         * e.g. solaris) no ip address and no domain we fail here
+         * e.g. Solaris) no ip address and no domain we fail here
          */
         done = -1;
       }
@@ -843,7 +855,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
-  /* Old WinCE versions do not support SO_ERROR */
+  /* Old Windows CE versions do not support SO_ERROR */
   if(WSAENOPROTOOPT == err) {
     SET_SOCKERRNO(0);
     err = 0;
@@ -938,6 +950,7 @@ struct cf_socket_ctx {
   size_t recv_max;                  /* max enforced read size */
 #endif
   BIT(got_first_byte);               /* if first byte was received */
+  BIT(listening);                    /* socket is listening */
   BIT(accepted);                     /* socket was accepted, not connected */
   BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
   BIT(active);
@@ -986,8 +999,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(%" CURL_FORMAT_SOCKET_T
-                ")", ctx->sock);
+    CURL_TRC_CF(data, cf, "cf_socket_close(%" 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);
@@ -1009,8 +1021,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(%" CURL_FORMAT_SOCKET_T
-                ")", ctx->sock);
+    CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" 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. */
@@ -1220,7 +1231,7 @@ out:
     ctx->connected_at = Curl_now();
     cf->connected = TRUE;
   }
-  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
+  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
               result, ctx->sock);
   return result;
 }
@@ -1262,8 +1273,8 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
     if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
                   (void *)&optval, sizeof(optval)) < 0)
-      infof(data, "Failed to enable TCP Fast Open on fd %"
-            CURL_FORMAT_SOCKET_T, ctx->sock);
+      infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
+            ctx->sock);
 
     rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
 #elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1398,15 +1409,24 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
   struct cf_socket_ctx *ctx = cf->ctx;
 
   if(ctx->sock != CURL_SOCKET_BAD) {
-    if(!cf->connected) {
+    /* A listening socket filter needs to be connected before the accept
+     * for some weird FTP interaction. This should be rewritten, so that
+     * FTP no longer does the socket checks and accept calls and delegates
+     * all that to the filter. TODO. */
+    if(ctx->listening) {
+      Curl_pollset_set_in_only(data, ps, ctx->sock);
+      CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
+                  FMT_SOCKET_T, ctx->sock);
+    }
+    else if(!cf->connected) {
       Curl_pollset_set_out_only(data, ps, ctx->sock);
       CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
-                  CURL_FORMAT_SOCKET_T, ctx->sock);
+                  FMT_SOCKET_T, ctx->sock);
     }
     else if(!ctx->active) {
       Curl_pollset_add_in(data, ps, ctx->sock);
       CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
-                  CURL_FORMAT_SOCKET_T, ctx->sock);
+                  FMT_SOCKET_T, ctx->sock);
     }
   }
 }
@@ -1449,13 +1469,15 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
 #endif /* USE_WINSOCK */
 
 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              const void *buf, size_t len, CURLcode *err)
+                              const void *buf, size_t len, bool eos,
+                              CURLcode *err)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   curl_socket_t fdsave;
   ssize_t nwritten;
   size_t orig_len = len;
 
+  (void)eos; /* unused */
   *err = CURLE_OK;
   fdsave = cf->conn->sock[cf->sockindex];
   cf->conn->sock[cf->sockindex] = ctx->sock;
@@ -1464,7 +1486,7 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   /* simulate network blocking/partial writes */
   if(ctx->wblock_percent > 0) {
     unsigned char c = 0;
-    Curl_rand(data, &c, 1);
+    Curl_rand_bytes(data, FALSE, &c, 1);
     if(c >= ((100-ctx->wblock_percent)*256/100)) {
       CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
       *err = CURLE_AGAIN;
@@ -1597,6 +1619,18 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   return nread;
 }
 
+static void cf_socket_update_data(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data)
+{
+  /* Update the IP info held in the transfer, if we have that. */
+  if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
+    struct cf_socket_ctx *ctx = cf->ctx;
+    data->info.primary = ctx->ip;
+    /* not sure if this is redundant... */
+    data->info.conn_remote_port = cf->conn->remote_port;
+  }
+}
+
 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
@@ -1604,17 +1638,15 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
   /* use this socket from now on */
   cf->conn->sock[cf->sockindex] = ctx->sock;
   set_local_ip(cf, data);
-  if(cf->sockindex == SECONDARYSOCKET)
-    cf->conn->secondary = ctx->ip;
-  else
-    cf->conn->primary = ctx->ip;
-  /* the first socket info gets some specials */
   if(cf->sockindex == FIRSTSOCKET) {
+    cf->conn->primary = ctx->ip;
     cf->conn->remote_addr = &ctx->addr;
   #ifdef USE_IPV6
     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
   #endif
-    Curl_persistconninfo(data, cf->conn, &ctx->ip);
+  }
+  else {
+    cf->conn->secondary = ctx->ip;
   }
   ctx->active = TRUE;
 }
@@ -1630,9 +1662,10 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
   switch(event) {
   case CF_CTRL_CONN_INFO_UPDATE:
     cf_socket_active(cf, data);
+    cf_socket_update_data(cf, data);
     break;
   case CF_CTRL_DATA_SETUP:
-    Curl_persistconninfo(data, cf->conn, &ctx->ip);
+    cf_socket_update_data(cf, data);
     break;
   case CF_CTRL_FORGET_SOCKET:
     ctx->sock = CURL_SOCKET_BAD;
@@ -1715,6 +1748,14 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
     }
     return CURLE_OK;
   }
+  case CF_QUERY_IP_INFO:
+#ifdef USE_IPV6
+    *pres1 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+#else
+    *pres1 = FALSE;
+#endif
+    *(struct ip_quadruple *)pres2 = ctx->ip;
+    return CURLE_OK;
   default:
     break;
   }
@@ -1793,7 +1834,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
   }
   ctx->sock_connected = TRUE;
   set_local_ip(cf, data);
-  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
+  CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
               " connected: [%s:%d] -> [%s:%d]",
               (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
               ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
@@ -1858,12 +1899,12 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
       if(result)
         goto out;
       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
-                  CURL_FORMAT_SOCKET_T " (%s:%d)",
+                  FMT_SOCKET_T " (%s:%d)",
                   ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
     }
     else {
       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
-                  CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
+                  FMT_SOCKET_T " (unconnected)", ctx->sock);
     }
     *done = TRUE;
     cf->connected = TRUE;
@@ -2027,6 +2068,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
   }
   ctx->transport = conn->transport;
   ctx->sock = *s;
+  ctx->listening = TRUE;
   ctx->accepted = FALSE;
   result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
   if(result)
@@ -2038,8 +2080,8 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
   ctx->active = TRUE;
   ctx->connected_at = Curl_now();
   cf->connected = TRUE;
-  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
-              CURL_FORMAT_SOCKET_T ")", ctx->sock);
+  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%" FMT_SOCKET_T ")",
+              ctx->sock);
 
 out:
   if(result) {
@@ -2093,8 +2135,10 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
     return CURLE_FAILED_INIT;
 
   ctx = cf->ctx;
+  DEBUGASSERT(ctx->listening);
   /* discard the listen socket */
   socket_close(data, conn, TRUE, ctx->sock);
+  ctx->listening = FALSE;
   ctx->sock = *s;
   conn->sock[sockindex] = ctx->sock;
   set_accepted_remote_ip(cf, data);
@@ -2103,7 +2147,7 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
   ctx->accepted = TRUE;
   ctx->connected_at = Curl_now();
   cf->connected = TRUE;
-  CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
+  CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
               ", remote=%s port=%d)",
               ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
 

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

@@ -57,7 +57,7 @@ struct Curl_sockaddr_ex {
 /*
  * Parse interface option, and return the interface name and the host part.
 */
-CURLcode Curl_parse_interface(const char *input, size_t len,
+CURLcode Curl_parse_interface(const char *input,
                               char **dev, char **iface, char **host);
 
 /*

+ 64 - 12
Utilities/cmcurl/lib/cfilters.c

@@ -45,6 +45,9 @@
 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 #endif
 
+static void cf_cntrl_update_info(struct Curl_easy *data,
+                                 struct connectdata *conn);
+
 #ifdef UNITTESTS
 /* used by unit2600.c */
 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -98,10 +101,11 @@ bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
 }
 
 ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          const void *buf, size_t len, CURLcode *err)
+                          const void *buf, size_t len, bool eos,
+                          CURLcode *err)
 {
   return cf->next?
-    cf->next->cft->do_send(cf->next, data, buf, len, err) :
+    cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
     CURLE_RECV_ERROR;
 }
 
@@ -256,7 +260,8 @@ ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
 }
 
 ssize_t Curl_cf_send(struct Curl_easy *data, int num,
-                     const void *mem, size_t len, CURLcode *code)
+                     const void *mem, size_t len, bool eos,
+                     CURLcode *code)
 {
   struct Curl_cfilter *cf;
 
@@ -268,7 +273,7 @@ ssize_t Curl_cf_send(struct Curl_easy *data, int num,
     cf = cf->next;
   }
   if(cf) {
-    ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
+    ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code);
     DEBUGASSERT(nwritten >= 0 || *code);
     DEBUGASSERT(nwritten < 0 || !*code || !len);
     return nwritten;
@@ -379,10 +384,11 @@ 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, CURLcode *err)
+                          const void *buf, size_t len, bool eos,
+                          CURLcode *err)
 {
   if(cf)
-    return cf->cft->do_send(cf, data, buf, len, err);
+    return cf->cft->do_send(cf, data, buf, len, eos, err);
   *err = CURLE_SEND_ERROR;
   return -1;
 }
@@ -416,11 +422,22 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
 
   *done = cf->connected;
   if(!*done) {
+    if(Curl_conn_needs_flush(data, sockindex)) {
+      DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
+      result = Curl_conn_flush(data, sockindex);
+      if(result && (result != CURLE_AGAIN))
+        return result;
+    }
+
     result = cf->cft->do_connect(cf, data, blocking, done);
     if(!result && *done) {
-      Curl_conn_ev_update_info(data, data->conn);
+      /* 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();
+      Curl_verboseconnect(data, data->conn, sockindex);
     }
     else if(result) {
       conn_report_connect_stats(data, data->conn);
@@ -501,6 +518,21 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
   return FALSE;
 }
 
+bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  CURLcode result;
+  int pending = FALSE;
+  result = cf? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
+                              &pending, NULL) : CURLE_UNKNOWN_OPTION;
+  return (result || pending == FALSE)? FALSE : TRUE;
+}
+
+bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
+{
+  return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
+}
+
 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
@@ -627,6 +659,15 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
   return CURL_SOCKET_BAD;
 }
 
+CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int *is_ipv6, struct ip_quadruple *ipquad)
+{
+  if(cf)
+    return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad);
+  return CURLE_UNKNOWN_OPTION;
+}
+
 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
 {
   struct Curl_cfilter *cf;
@@ -693,6 +734,13 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
                       CF_CTRL_DATA_IDLE, 0, NULL);
 }
 
+
+CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
+{
+  return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE,
+                            CF_CTRL_FLUSH, 0, NULL);
+}
+
 /**
  * Notify connection filters that the transfer represented by `data`
  * is done with sending data (e.g. has uploaded everything).
@@ -717,8 +765,8 @@ CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
 }
 
-void Curl_conn_ev_update_info(struct Curl_easy *data,
-                              struct connectdata *conn)
+static void cf_cntrl_update_info(struct Curl_easy *data,
+                                 struct connectdata *conn)
 {
   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
 }
@@ -811,9 +859,10 @@ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
 }
 
 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
-                        const void *buf, size_t blen,
+                        const void *buf, size_t blen, bool eos,
                         size_t *pnwritten)
 {
+  size_t write_len = blen;
   ssize_t nwritten;
   CURLcode result = CURLE_OK;
   struct connectdata *conn;
@@ -831,11 +880,14 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
     if(p) {
       size_t altsize = (size_t)strtoul(p, NULL, 10);
       if(altsize)
-        blen = CURLMIN(blen, altsize);
+        write_len = CURLMIN(write_len, altsize);
     }
   }
 #endif
-  nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
+  if(write_len != blen)
+    eos = FALSE;
+  nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
+                                   &result);
   DEBUGASSERT((nwritten >= 0) || result);
   *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
   return result;

+ 31 - 10
Utilities/cmcurl/lib/cfilters.h

@@ -30,6 +30,7 @@ struct Curl_cfilter;
 struct Curl_easy;
 struct Curl_dns_entry;
 struct connectdata;
+struct ip_quadruple;
 
 /* Callback to destroy resources held by this filter instance.
  * Implementations MUST NOT chain calls to cf->next.
@@ -105,6 +106,7 @@ typedef ssize_t  Curl_cft_send(struct Curl_cfilter *cf,
                                struct Curl_easy *data, /* transfer */
                                const void *buf,        /* data to write */
                                size_t len,             /* amount to write */
+                               bool eos,               /* last chunk */
                                CURLcode *err);         /* error to return */
 
 typedef ssize_t  Curl_cft_recv(struct Curl_cfilter *cf,
@@ -140,6 +142,7 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
 /* update conn info at connection and data */
 #define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0          NULL     ignored */
 #define CF_CTRL_FORGET_SOCKET    (256+1) /* 0          NULL     ignored */
+#define CF_CTRL_FLUSH            (256+2) /* 0          NULL     first fail */
 
 /**
  * Handle event/control for the filter.
@@ -162,6 +165,9 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
  *                   were received.
  *                   -1 if not determined yet.
  * - CF_QUERY_SOCKET: the socket used by the filter chain
+ * - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data
+ * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
+ *                   ip quadruple
  */
 /*      query                             res1       res2     */
 #define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
@@ -170,6 +176,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
 #define CF_QUERY_TIMER_CONNECT      4  /* -          struct curltime */
 #define CF_QUERY_TIMER_APPCONNECT   5  /* -          struct curltime */
 #define CF_QUERY_STREAM_ERROR       6  /* error code - */
+#define CF_QUERY_NEED_FLUSH         7  /* TRUE/FALSE - */
+#define CF_QUERY_IP_INFO            8  /* TRUE/FALSE struct ip_quadruple */
 
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -241,7 +249,8 @@ void     Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
 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,
-                          const void *buf, size_t len, CURLcode *err);
+                          const void *buf, size_t len, bool eos,
+                          CURLcode *err);
 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,
@@ -317,7 +326,8 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
                               bool blocking, 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, CURLcode *err);
+                          const void *buf, size_t len, bool eos,
+                          CURLcode *err);
 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                           char *buf, size_t len, CURLcode *err);
 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
@@ -338,6 +348,12 @@ bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf);
 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
                                       struct Curl_easy *data);
 
+CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int *is_ipv6, struct ip_quadruple *ipquad);
+
+bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
+                              struct Curl_easy *data);
 
 #define CURL_CF_SSL_DEFAULT  -1
 #define CURL_CF_SSL_DISABLE  0
@@ -398,6 +414,17 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);
 bool Curl_conn_data_pending(struct Curl_easy *data,
                             int sockindex);
 
+/**
+ * Return TRUE if any of the connection filters at chain `sockindex`
+ * have data still to send.
+ */
+bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex);
+
+/**
+ * Flush any pending data on the connection filters at chain `sockindex`.
+ */
+CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex);
+
 /**
  * Return the socket used on data's connection for the index.
  * Returns CURL_SOCKET_BAD if not available.
@@ -447,7 +474,7 @@ ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
  * The error code is placed into `*code`.
  */
 ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
-                     const void *buf, size_t len, CURLcode *code);
+                     const void *buf, size_t len, bool eos, CURLcode *code);
 
 /**
  * The easy handle `data` is being attached to `conn`. This does
@@ -496,12 +523,6 @@ void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature);
  */
 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause);
 
-/**
- * Inform connection filters to update their info in `conn`.
- */
-void Curl_conn_ev_update_info(struct Curl_easy *data,
-                              struct connectdata *conn);
-
 /**
  * Check if FIRSTSOCKET's cfilter chain deems connection alive.
  */
@@ -557,7 +578,7 @@ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
  * Will return CURLE_AGAIN iff blocked on sending.
  */
 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
-                        const void *buf, size_t blen,
+                        const void *buf, size_t blen, bool eos,
                         size_t *pnwritten);
 
 

文件差异内容过多而无法显示
+ 423 - 376
Utilities/cmcurl/lib/conncache.c


+ 145 - 108
Utilities/cmcurl/lib/conncache.h

@@ -25,140 +25,177 @@
  *
  ***************************************************************************/
 
-/*
- * All accesses to struct fields and changing of data in the connection cache
- * and connectbundles must be done with the conncache LOCKED. The cache might
- * be shared.
- */
-
 #include <curl/curl.h>
 #include "timeval.h"
 
 struct connectdata;
+struct Curl_easy;
 struct curl_pollfds;
 struct curl_waitfds;
 struct Curl_multi;
+struct Curl_share;
 
-struct connshutdowns {
-  struct Curl_llist conn_list;  /* The connectdata to shut down */
-  BIT(iter_locked);  /* TRUE while iterating the list */
-};
-
-struct conncache {
-  struct Curl_hash hash;
+/**
+ * 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);
+
+struct cpool {
+   /* the pooled connections, bundled per destination */
+  struct Curl_hash dest2bundle;
   size_t num_conn;
   curl_off_t next_connection_id;
   curl_off_t next_easy_id;
   struct curltime last_cleanup;
-  struct connshutdowns shutdowns;
-  /* handle used for closing cached connections */
-  struct Curl_easy *closure_handle;
-  struct Curl_multi *multi; /* Optional, set if cache belongs to multi */
+  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;
+  BIT(locked);
 };
 
-#define BUNDLE_NO_MULTIUSE -1
-#define BUNDLE_UNKNOWN     0  /* initial value */
-#define BUNDLE_MULTIPLEX   2
-
-#ifdef DEBUGBUILD
-/* the debug versions of these macros make extra certain that the lock is
-   never doubly locked or unlocked */
-#define CONNCACHE_LOCK(x)                                               \
-  do {                                                                  \
-    if((x)->share) {                                                    \
-      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
-                      CURL_LOCK_ACCESS_SINGLE);                         \
-      DEBUGASSERT(!(x)->state.conncache_lock);                          \
-      (x)->state.conncache_lock = TRUE;                                 \
-    }                                                                   \
-  } while(0)
-
-#define CONNCACHE_UNLOCK(x)                                             \
-  do {                                                                  \
-    if((x)->share) {                                                    \
-      DEBUGASSERT((x)->state.conncache_lock);                           \
-      (x)->state.conncache_lock = FALSE;                                \
-      Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                   \
-    }                                                                   \
-  } while(0)
-#else
-#define CONNCACHE_LOCK(x) if((x)->share)                                \
-    Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
-#define CONNCACHE_UNLOCK(x) if((x)->share)              \
-    Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
-#endif
-
-struct connectbundle {
-  int multiuse;                 /* supports multi-use */
-  size_t num_connections;       /* Number of connections in the bundle */
-  struct Curl_llist conn_list;  /* The connectdata members of the bundle */
-};
-
-/* Init the cache, pass multi only if cache is owned by it.
+/* Init the pool, pass multi only if pool is owned by it.
  * returns 1 on error, 0 is fine.
  */
-int Curl_conncache_init(struct conncache *,
-                        struct Curl_multi *multi,
-                        size_t size);
-void Curl_conncache_destroy(struct conncache *connc);
-
-/* return the correct bundle, to a host or a proxy */
-struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
-                                                 struct connectdata *conn,
-                                                 struct conncache *connc);
-/* returns number of connections currently held in the connection cache */
-size_t Curl_conncache_size(struct Curl_easy *data);
-
-bool Curl_conncache_return_conn(struct Curl_easy *data,
-                                struct connectdata *conn);
-CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT;
-void Curl_conncache_remove_conn(struct Curl_easy *data,
-                                struct connectdata *conn,
-                                bool lock);
-bool Curl_conncache_foreach(struct Curl_easy *data,
-                            struct conncache *connc,
-                            void *param,
-                            int (*func)(struct Curl_easy *data,
-                                        struct connectdata *conn,
-                                        void *param));
-
-struct connectdata *
-Curl_conncache_find_first_connection(struct conncache *connc);
-
-struct connectdata *
-Curl_conncache_extract_bundle(struct Curl_easy *data,
-                              struct connectbundle *bundle);
-struct connectdata *
-Curl_conncache_extract_oldest(struct Curl_easy *data);
-void Curl_conncache_close_all_connections(struct conncache *connc);
-void Curl_conncache_print(struct conncache *connc);
+int Curl_cpool_init(struct cpool *cpool,
+                    Curl_cpool_disconnect_cb *disconnect_cb,
+                    struct Curl_multi *multi,
+                    struct Curl_share *share,
+                    size_t size);
+
+/* Destroy all connections and free all members */
+void Curl_cpool_destroy(struct cpool *connc);
+
+/* Init the transfer to be used within its connection pool.
+ * Assigns `data->id`. */
+void Curl_cpool_xfer_init(struct Curl_easy *data);
 
 /**
- * Tear down the connection. If `aborted` is FALSE, the connection
- * will be shut down first before discarding. If the shutdown
- * is not immediately complete, the connection
- * will be placed into the cache is shutdown queue.
+ * Get the connection with the given id from the transfer's pool.
  */
-void Curl_conncache_disconnect(struct Curl_easy *data,
-                               struct connectdata *conn,
-                               bool aborted);
+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 sockets and POLLIN/OUT flags for connections handled by the cache.
+ * Return if the pool has reached its configured limits for adding
+ * the given connection. Will try to discard the oldest, idle
+ * connections to make space.
  */
-CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
-                                    struct curl_pollfds *cpfds);
-CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
-                                    struct curl_waitfds *cwfds);
+#define CPOOL_LIMIT_OK     0
+#define CPOOL_LIMIT_DEST   1
+#define CPOOL_LIMIT_TOTAL  2
+int Curl_cpool_check_limits(struct Curl_easy *data,
+                            struct connectdata *conn);
+
+/* Return of conn is suitable. If so, stops iteration. */
+typedef bool Curl_cpool_conn_match_cb(struct connectdata *conn,
+                                      void *userdata);
+
+/* Act on the result of the find, may override it. */
+typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
+
+/**
+ * Find a connection in the pool matching `destination`.
+ * 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
+ * @param result_cb   if not NULL, is called at the end with the result
+ *                    of the `conn_cb` or FALSE if never called.
+ * @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,
+                     Curl_cpool_conn_match_cb *conn_cb,
+                     Curl_cpool_done_match_cb *done_cb,
+                     void *userdata);
+
+/*
+ * A connection (already in the pool) is now idle. Do any
+ * cleanups in regard to the pool's limits.
+ *
+ * Return TRUE if idle connection kept in pool, FALSE if closed.
+ */
+bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
+                              struct connectdata *conn);
 
 /**
- * Perform maintenance on connections in the cache. Specifically,
+ * 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.
+ * The cleanup is done at most once per second.
+ *
+ * When called, this transfer has no connection attached.
+ */
+void Curl_cpool_prune_dead(struct Curl_easy *data);
+
+/**
+ * Perform upkeep actions on connections in the transfer's pool.
+ */
+CURLcode Curl_cpool_upkeep(void *data);
+
+typedef void Curl_cpool_conn_do_cb(struct connectdata *conn,
+                                   struct Curl_easy *data,
+                                   void *cbdata);
+
+/**
+ * Invoke the callback on the pool's connection with the
+ * given connection id (if it exists).
+ */
+void Curl_cpool_do_by_id(struct Curl_easy *data,
+                         curl_off_t conn_id,
+                         Curl_cpool_conn_do_cb *cb, void *cbdata);
+
+/**
+ * Invoked the callback for the given data + connection under the
+ * connection pool's lock.
+ * The callback is always invoked, even if the transfer has no connection
+ * pool associated.
+ */
+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);
+CURLcode Curl_cpool_add_waitfds(struct cpool *connc,
+                                struct curl_waitfds *cwfds);
+
+/**
+ * Perform maintenance on connections in the pool. Specifically,
  * progress the shutdown of connections in the queue.
  */
-void Curl_conncache_multi_perform(struct Curl_multi *multi);
+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);
 
-void Curl_conncache_multi_socket(struct Curl_multi *multi,
-                                 curl_socket_t s, int ev_bitmask);
-void Curl_conncache_multi_close_all(struct Curl_multi *multi);
 
 #endif /* HEADER_CURL_CONNCACHE_H */

+ 50 - 96
Utilities/cmcurl/lib/connect.c

@@ -208,31 +208,6 @@ bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
   return (pt->tv_sec > 0) || (pt->tv_usec > 0);
 }
 
-/* Copies connection info into the transfer handle to make it available when
-   the transfer handle is no longer associated with the connection. */
-void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          struct ip_quadruple *ip)
-{
-  if(ip)
-    data->info.primary = *ip;
-  else {
-    memset(&data->info.primary, 0, sizeof(data->info.primary));
-    data->info.primary.remote_port = -1;
-    data->info.primary.local_port = -1;
-  }
-  data->info.conn_scheme = conn->handler->scheme;
-  /* conn_protocol can only provide "old" protocols */
-  data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
-  data->info.conn_remote_port = conn->remote_port;
-  data->info.used_proxy =
-#ifdef CURL_DISABLE_PROXY
-    0
-#else
-    conn->bits.proxy
-#endif
-    ;
-}
-
 static const struct Curl_addrinfo *
 addr_first_match(const struct Curl_addrinfo *addr, int family)
 {
@@ -312,23 +287,6 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
   return FALSE;
 }
 
-struct connfind {
-  curl_off_t id_tofind;
-  struct connectdata *found;
-};
-
-static int conn_is_conn(struct Curl_easy *data,
-                        struct connectdata *conn, void *param)
-{
-  struct connfind *f = (struct connfind *)param;
-  (void)data;
-  if(conn->connection_id == f->id_tofind) {
-    f->found = conn;
-    return 1;
-  }
-  return 0;
-}
-
 /*
  * Used to extract socket and connectdata struct for the most recent
  * transfer on the given Curl_easy.
@@ -345,30 +303,19 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
    * - that is associated with a multi handle, and whose connection
    *   was detached with CURLOPT_CONNECT_ONLY
    */
-  if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
-    struct connectdata *c;
-    struct connfind find;
-    find.id_tofind = data->state.lastconnect_id;
-    find.found = NULL;
-
-    Curl_conncache_foreach(data,
-                           data->share && (data->share->specifier
-                           & (1<< CURL_LOCK_DATA_CONNECT))?
-                           &data->share->conn_cache:
-                           data->multi_easy?
-                           &data->multi_easy->conn_cache:
-                           &data->multi->conn_cache, &find, conn_is_conn);
-
-    if(!find.found) {
+  if(data->state.lastconnect_id != -1) {
+    struct connectdata *conn;
+
+    conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
+    if(!conn) {
       data->state.lastconnect_id = -1;
       return CURL_SOCKET_BAD;
     }
 
-    c = find.found;
     if(connp)
       /* only store this if the caller cares for it */
-      *connp = c;
-    return c->sock[FIRSTSOCKET];
+      *connp = conn;
+    return conn->sock[FIRSTSOCKET];
   }
   return CURL_SOCKET_BAD;
 }
@@ -600,9 +547,11 @@ static CURLcode baller_start_next(struct Curl_cfilter *cf,
 {
   if(cf->sockindex == FIRSTSOCKET) {
     baller_next_addr(baller);
-    /* If we get inconclusive answers from the server(s), we make
-     * a second iteration over the address list */
-    if(!baller->addr && baller->inconclusive && !baller->rewinded)
+    /* If we get inconclusive answers from the server(s), we start
+     * again until this whole thing times out. This allows us to
+     * connect to servers that are gracefully restarting and the
+     * packet routing to the new instance has not happened yet (e.g. QUIC). */
+    if(!baller->addr && baller->inconclusive)
       baller_rewind(baller);
     baller_start(cf, data, baller, timeoutms);
   }
@@ -634,7 +583,7 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
         baller->is_done = TRUE;
       }
       else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
-        infof(data, "%s connect timeout after %" CURL_FORMAT_TIMEDIFF_T
+        infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
               "ms, move on!", baller->name, baller->timeoutms);
 #if defined(ETIMEDOUT)
         baller->error = ETIMEDOUT;
@@ -725,7 +674,7 @@ evaluate:
   /* Nothing connected, check the time before we might
    * start new ballers or return ok. */
   if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
-    failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms",
+    failf(data, "Connection timeout after %" FMT_OFF_T " ms",
           Curl_timediff(now, data->progress.t_startsingle));
     return CURLE_OPERATION_TIMEDOUT;
   }
@@ -748,8 +697,7 @@ evaluate:
           CURL_TRC_CF(data, cf, "%s done", baller->name);
         }
         else {
-          CURL_TRC_CF(data, cf, "%s starting (timeout=%"
-                      CURL_FORMAT_TIMEDIFF_T "ms)",
+          CURL_TRC_CF(data, cf, "%s starting (timeout=%" FMT_TIMEDIFF_T "ms)",
                       baller->name, baller->timeoutms);
           ++ongoing;
           ++added;
@@ -794,7 +742,7 @@ evaluate:
     hostname = conn->host.name;
 
   failf(data, "Failed to connect to %s port %u after "
-        "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+        "%" FMT_TIMEDIFF_T " ms: %s",
         hostname, conn->primary.remote_port,
         Curl_timediff(now, data->progress.t_startsingle),
         curl_easy_strerror(result));
@@ -821,9 +769,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
   struct cf_he_ctx *ctx = cf->ctx;
   struct connectdata *conn = cf->conn;
   CURLcode result = CURLE_COULDNT_CONNECT;
-  int ai_family0, ai_family1;
+  int ai_family0 = 0, ai_family1 = 0;
   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
-  const struct Curl_addrinfo *addr0, *addr1;
+  const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
 
   if(timeout_ms < 0) {
     /* a precaution, no need to continue if time already is up */
@@ -842,33 +790,33 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
    * the 2 connect attempt ballers to try different families, if possible.
    *
    */
-  if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
-    /* any IP version is allowed */
-    ai_family0 = remotehost->addr?
-      remotehost->addr->ai_family : 0;
+  if(conn->ip_version == CURL_IPRESOLVE_V6) {
 #ifdef USE_IPV6
-    ai_family1 = ai_family0 == AF_INET6 ?
-      AF_INET : AF_INET6;
-#else
-    ai_family1 = AF_UNSPEC;
+    ai_family0 = AF_INET6;
+    addr0 = addr_first_match(remotehost->addr, ai_family0);
 #endif
   }
+  else if(conn->ip_version == CURL_IPRESOLVE_V4) {
+    ai_family0 = AF_INET;
+    addr0 = addr_first_match(remotehost->addr, ai_family0);
+  }
   else {
-    /* only one IP version is allowed */
-    ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
-      AF_INET :
+    /* no user preference, we try ipv6 always first when available */
 #ifdef USE_IPV6
-      AF_INET6;
-#else
-      AF_UNSPEC;
+    ai_family0 = AF_INET6;
+    addr0 = addr_first_match(remotehost->addr, ai_family0);
 #endif
-    ai_family1 = AF_UNSPEC;
+    /* next candidate is ipv4 */
+    ai_family1 = AF_INET;
+    addr1 = addr_first_match(remotehost->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);
+    }
   }
 
-  /* Get the first address in the list that matches the family,
-   * this might give NULL, if we do not have any matches. */
-  addr0 = addr_first_match(remotehost->addr, ai_family0);
-  addr1 = addr_first_match(remotehost->addr, ai_family1);
   if(!addr0 && addr1) {
     /* switch around, so a single baller always uses addr0 */
     addr0 = addr1;
@@ -887,8 +835,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
                           timeout_ms,  EXPIRE_DNS_PER_NAME);
   if(result)
     return result;
-  CURL_TRC_CF(data, cf, "created %s (timeout %"
-              CURL_FORMAT_TIMEDIFF_T "ms)",
+  CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
               ctx->baller[0]->name, ctx->baller[0]->timeoutms);
   if(addr1) {
     /* second one gets a delayed start */
@@ -899,8 +846,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
                             timeout_ms,  EXPIRE_DNS_PER_NAME2);
     if(result)
       return result;
-    CURL_TRC_CF(data, cf, "created %s (timeout %"
-                CURL_FORMAT_TIMEDIFF_T "ms)",
+    CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
                 ctx->baller[1]->name, ctx->baller[1]->timeoutms);
     Curl_expire(data, data->set.happy_eyeballs_timeout,
                 EXPIRE_HAPPY_EYEBALLS);
@@ -1020,12 +966,20 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
         cf->next = ctx->winner->cf;
         ctx->winner->cf = NULL;
         cf_he_ctx_clear(cf, data);
-        Curl_conn_cf_cntrl(cf->next, data, TRUE,
-                           CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
 
         if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
           Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
-        Curl_verboseconnect(data, cf->conn, cf->sockindex);
+        if(Curl_trc_cf_is_verbose(cf, data)) {
+          struct ip_quadruple ipquad;
+          int is_ipv6;
+          if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
+            const char *host, *disphost;
+            int port;
+            cf->next->cft->get_host(cf->next, data, &host, &disphost, &port);
+            CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
+                        disphost, ipquad.remote_ip, ipquad.remote_port);
+          }
+        }
         data->info.numconnects++; /* to track the # of connections made */
       }
       break;

+ 0 - 3
Utilities/cmcurl/lib/connect.h

@@ -72,9 +72,6 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
                       char *addr, int *port);
 
-void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          struct ip_quadruple *ip);
-
 /*
  * Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
  * argument specifies if it is the end of a connection or a stream.

+ 7 - 7
Utilities/cmcurl/lib/content_encoding.c

@@ -79,7 +79,7 @@
 #define GZIP_MAGIC_1 0x8b
 
 /* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
 #define ORIG_NAME    0x08 /* bit 3 set: original filename present */
@@ -909,18 +909,18 @@ static CURLcode error_do_write(struct Curl_easy *data,
                                      struct Curl_cwriter *writer, int type,
                                      const char *buf, size_t nbytes)
 {
-  char all[256];
-  (void)Curl_all_content_encodings(all, sizeof(all));
-
   (void) writer;
   (void) buf;
   (void) nbytes;
 
   if(!(type & CLIENTWRITE_BODY) || !nbytes)
     return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
-
-  failf(data, "Unrecognized content encoding type. "
-        "libcurl understands %s content encodings.", all);
+  else {
+    char all[256];
+    (void)Curl_all_content_encodings(all, sizeof(all));
+    failf(data, "Unrecognized content encoding type. "
+          "libcurl understands %s content encodings.", all);
+  }
   return CURLE_BAD_CONTENT_ENCODING;
 }
 

+ 7 - 2
Utilities/cmcurl/lib/cookie.c

@@ -1028,6 +1028,8 @@ Curl_cookie_add(struct Curl_easy *data,
    * must also check that the data handle is not NULL since the psl code will
    * dereference it.
    */
+  DEBUGF(infof(data, "PSL check set-cookie '%s' for domain=%s in %s",
+         co->name, co->domain, domain));
   if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
     bool acceptable = FALSE;
     char lcase[256];
@@ -1054,6 +1056,9 @@ Curl_cookie_add(struct Curl_easy *data,
       return NULL;
     }
   }
+#else
+  DEBUGF(infof(data, "NO PSL to check set-cookie '%s' for domain=%s in %s",
+         co->name, co->domain, domain));
 #endif
 
   /* A non-secure cookie may not overlay an existing secure cookie. */
@@ -1165,7 +1170,7 @@ Curl_cookie_add(struct Curl_easy *data,
   if(c->running)
     /* Only show this when NOT reading the cookies from a file */
     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
-          "expire %" CURL_FORMAT_CURL_OFF_T,
+          "expire %" FMT_OFF_T,
           replace_old?"Replaced":"Added", co->name, co->value,
           co->domain, co->path, co->expires);
 
@@ -1584,7 +1589,7 @@ static char *get_netscape_format(const struct Cookie *co)
     "%s\t"   /* tailmatch */
     "%s\t"   /* path */
     "%s\t"   /* secure */
-    "%" CURL_FORMAT_CURL_OFF_T "\t"   /* expires */
+    "%" FMT_OFF_T "\t"   /* expires */
     "%s\t"   /* name */
     "%s",    /* value */
     co->httponly?"#HttpOnly_":"",

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

@@ -571,7 +571,7 @@ curl_dbg_getaddrinfo(const char *hostname,
 
 #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
 /*
- * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
+ * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and macOS
  * 10.11.5.
  */
 void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)

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

@@ -82,6 +82,9 @@
 /* disables HTTP */
 #cmakedefine CURL_DISABLE_HTTP 1
 
+/* disabled all HTTP authentication methods */
+#cmakedefine CURL_DISABLE_HTTP_AUTH 1
+
 /* disables IMAP */
 #cmakedefine CURL_DISABLE_IMAP 1
 
@@ -124,6 +127,12 @@
 /* disables RTSP */
 #cmakedefine CURL_DISABLE_RTSP 1
 
+/* disables SHA-512/256 hash algorithm */
+#cmakedefine CURL_DISABLE_SHA512_256 1
+
+/* disabled shuffle DNS feature */
+#cmakedefine CURL_DISABLE_SHUFFLE_DNS 1
+
 /* disables SMB */
 #cmakedefine CURL_DISABLE_SMB 1
 
@@ -297,9 +306,6 @@
 /* if you have the GNU gssapi libraries */
 #cmakedefine HAVE_GSSGNU 1
 
-/* Define to 1 if you have the `idna_strerror' function. */
-#cmakedefine HAVE_IDNA_STRERROR 1
-
 /* Define to 1 if you have the <ifaddrs.h> header file. */
 #cmakedefine HAVE_IFADDRS_H 1
 
@@ -627,9 +633,6 @@
 /* Define to the version of this package. */
 #cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
 
-/* a suitable file to read random data from */
-#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
-
 /*
  Note: SIZEOF_* variables are fetched with CMake through check_type_size().
  As per CMake documentation on CheckTypeSize, C preprocessor code is
@@ -686,7 +689,7 @@ ${SIZEOF_TIME_T_CODE}
 /* Define if you want to enable POSIX threaded DNS lookup */
 #cmakedefine USE_THREADS_POSIX 1
 
-/* Define if you want to enable WIN32 threaded DNS lookup */
+/* Define if you want to enable Win32 threaded DNS lookup */
 #cmakedefine USE_THREADS_WIN32 1
 
 /* if GnuTLS is enabled */
@@ -701,6 +704,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if BearSSL is enabled */
 #cmakedefine USE_BEARSSL 1
 
+/* if Rustls is enabled */
+#cmakedefine USE_RUSTLS 1
+
 /* if wolfSSL is enabled */
 #cmakedefine USE_WOLFSSL 1
 
@@ -716,6 +722,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if libssh2 is in use */
 #cmakedefine USE_LIBSSH2 1
 
+/* if wolfssh is in use */
+#cmakedefine USE_WOLFSSH 1
+
 /* if libpsl is in use */
 #cmakedefine USE_LIBPSL 1
 
@@ -731,6 +740,12 @@ ${SIZEOF_TIME_T_CODE}
 /* if GSASL is in use */
 #cmakedefine USE_GSASL 1
 
+/* if libuv is in use */
+#cmakedefine USE_LIBUV 1
+
+/* Define to 1 if you have the <uv.h> header file. */
+#cmakedefine HAVE_UV_H 1
+
 /* Define to 1 if you do not want the OpenSSL configuration to be loaded
    automatically */
 #cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
@@ -771,11 +786,6 @@ ${SIZEOF_TIME_T_CODE}
 /* Version number of package */
 #cmakedefine VERSION ${VERSION}
 
-/* Define to 1 if OS is AIX. */
-#ifndef _ALL_SOURCE
-#  undef _ALL_SOURCE
-#endif
-
 /* Number of bits in a file offset, on hosts where this is settable. */
 #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 

+ 4 - 4
Utilities/cmcurl/lib/curl_des.c

@@ -24,10 +24,10 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
-  (defined(USE_GNUTLS) ||                                       \
-   defined(USE_SECTRANSP) ||                                    \
-   defined(USE_OS400CRYPTO) ||                                  \
+#if defined(USE_CURL_NTLM_CORE) && \
+  (defined(USE_GNUTLS) ||          \
+   defined(USE_SECTRANSP) ||       \
+   defined(USE_OS400CRYPTO) ||     \
    defined(USE_WIN32_CRYPTO))
 
 #include "curl_des.h"

+ 4 - 4
Utilities/cmcurl/lib/curl_des.h

@@ -26,10 +26,10 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
-  (defined(USE_GNUTLS) ||                                       \
-   defined(USE_SECTRANSP) ||                                    \
-   defined(USE_OS400CRYPTO) ||                                  \
+#if defined(USE_CURL_NTLM_CORE) && \
+  (defined(USE_GNUTLS) ||          \
+   defined(USE_SECTRANSP) ||       \
+   defined(USE_OS400CRYPTO) ||     \
    defined(USE_WIN32_CRYPTO))
 
 /* Applies odd parity to the given byte array */

+ 1 - 1
Utilities/cmcurl/lib/curl_fnmatch.h

@@ -31,7 +31,7 @@
 /* default pattern matching function
  * =================================
  * Implemented with recursive backtracking, if you want to use Curl_fnmatch,
- * please note that there is not implemented UTF/UNICODE support.
+ * please note that there is not implemented UTF/Unicode support.
  *
  * Implemented features:
  * '?' notation, does not match UTF characters

+ 4 - 13
Utilities/cmcurl/lib/curl_gethostname.c

@@ -39,15 +39,6 @@
  *
  * Note: The function always returns the un-qualified hostname rather
  * than being provider dependent.
- *
- * For libcurl shared library release builds the test suite preloads
- * another shared library named libhostname using the LD_PRELOAD
- * mechanism which intercepts, and might override, the gethostname()
- * function call. In this case a given platform must support the
- * LD_PRELOAD mechanism and additionally have environment variable
- * CURL_GETHOSTNAME set in order to override the returned hostname.
- *
- * For libcurl static library release builds no overriding takes place.
  */
 
 int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
@@ -68,7 +59,10 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
   /* Override hostname when environment variable CURL_GETHOSTNAME is set */
   const char *force_hostname = getenv("CURL_GETHOSTNAME");
   if(force_hostname) {
-    strncpy(name, force_hostname, namelen - 1);
+    if(strlen(force_hostname) < (size_t)namelen)
+      strcpy(name, force_hostname);
+    else
+      return 1; /* can't do it */
     err = 0;
   }
   else {
@@ -78,9 +72,6 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
 
 #else /* DEBUGBUILD */
 
-  /* The call to system's gethostname() might get intercepted by the
-     libhostname library when libcurl is built as a non-debug shared
-     library when running the test suite. */
   name[0] = '\0';
   err = gethostname(name, namelen);
 

+ 4 - 0
Utilities/cmcurl/lib/curl_memrchr.c

@@ -33,6 +33,9 @@
 #include "memdebug.h"
 
 #ifndef HAVE_MEMRCHR
+#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
+  defined(USE_OPENSSL) || \
+  defined(USE_SCHANNEL)
 
 /*
  * Curl_memrchr()
@@ -61,4 +64,5 @@ Curl_memrchr(const void *s, int c, size_t n)
   return NULL;
 }
 
+#endif
 #endif /* HAVE_MEMRCHR */

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

@@ -34,11 +34,15 @@
 #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 */

+ 3 - 3
Utilities/cmcurl/lib/curl_multibyte.h

@@ -39,12 +39,12 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
  * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
  * and curlx_unicodefree() main purpose is to minimize the number of
  * preprocessor conditional directives needed by code using these
- * to differentiate UNICODE from non-UNICODE builds.
+ * to differentiate Unicode from non-Unicode builds.
  *
- * In the case of a non-UNICODE build the tchar strings are char strings that
+ * In the case of a non-Unicode build the tchar strings are char strings that
  * are duplicated via strdup and remain in whatever the passed in encoding is,
  * which is assumed to be UTF-8 but may be other encoding. Therefore the
- * significance of the conversion functions is primarily for UNICODE builds.
+ * significance of the conversion functions is primarily for Unicode builds.
  *
  * Allocated memory should be free'd with curlx_unicodefree().
  *

+ 15 - 11
Utilities/cmcurl/lib/curl_ntlm_core.c

@@ -57,9 +57,14 @@
   #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0)
     #define USE_OPENSSL_DES
   #endif
+#elif defined(USE_WOLFSSL)
+  #include <wolfssl/options.h>
+  #if !defined(NO_DES3)
+    #define USE_OPENSSL_DES
+  #endif
 #endif
 
-#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES)
 
 #if defined(USE_OPENSSL)
 #  include <openssl/des.h>
@@ -67,7 +72,6 @@
 #  include <openssl/ssl.h>
 #  include <openssl/rand.h>
 #else
-#  include <wolfssl/options.h>
 #  include <wolfssl/openssl/des.h>
 #  include <wolfssl/openssl/md5.h>
 #  include <wolfssl/openssl/ssl.h>
@@ -148,7 +152,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key)
 }
 #endif
 
-#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES)
 /*
  * Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The
  * key schedule ks is also set.
@@ -313,7 +317,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                             const unsigned char *plaintext,
                             unsigned char *results)
 {
-#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES)
   DES_key_schedule ks;
 
   setup_des_key(keys, DESKEY(ks));
@@ -367,7 +371,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
   {
     /* Create LanManager hashed password. */
 
-#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES)
     DES_key_schedule ks;
 
     setup_des_key(pw, DESKEY(ks));
@@ -534,13 +538,13 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
 /*
  * Curl_ntlm_core_mk_ntlmv2_resp()
  *
- * This creates the NTLMv2 response as set in the ntlm type-3 message.
+ * This creates the NTLMv2 response as set in the NTLM type-3 message.
  *
  * Parameters:
  *
- * ntlmv2hash       [in] - The ntlmv2 hash (16 bytes)
+ * ntlmv2hash       [in] - The NTLMv2 hash (16 bytes)
  * challenge_client [in] - The client nonce (8 bytes)
- * ntlm             [in] - The ntlm data struct being used to read TargetInfo
+ * ntlm             [in] - The NTLM data struct being used to read TargetInfo
                            and Server challenge received in the type-2 message
  * ntresp          [out] - The address where a pointer to newly allocated
  *                         memory holding the NTLMv2 response.
@@ -629,11 +633,11 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
 /*
  * Curl_ntlm_core_mk_lmv2_resp()
  *
- * This creates the LMv2 response as used in the ntlm type-3 message.
+ * This creates the LMv2 response as used in the NTLM type-3 message.
  *
  * Parameters:
  *
- * ntlmv2hash        [in] - The ntlmv2 hash (16 bytes)
+ * ntlmv2hash        [in] - The NTLMv2 hash (16 bytes)
  * challenge_client  [in] - The client nonce (8 bytes)
  * challenge_client  [in] - The server challenge (8 bytes)
  * lmresp           [out] - The LMv2 response (24 bytes)
@@ -657,7 +661,7 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
   if(result)
     return result;
 
-  /* Concatenate the HMAC MD5 output  with the client nonce */
+  /* Concatenate the HMAC MD5 output with the client nonce */
   memcpy(lmresp, hmac_output, 16);
   memcpy(lmresp + 16, challenge_client, 8);
 

+ 4 - 1
Utilities/cmcurl/lib/curl_printf.h

@@ -29,6 +29,10 @@
  * *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
@@ -40,7 +44,6 @@
 # undef msnprintf
 # undef vprintf
 # undef vfprintf
-# undef vsnprintf
 # undef mvsnprintf
 # undef aprintf
 # undef vaprintf

+ 6 - 9
Utilities/cmcurl/lib/curl_range.c

@@ -55,15 +55,13 @@ CURLcode Curl_range(struct Curl_easy *data)
     if((to_t == CURL_OFFT_INVAL) && !from_t) {
       /* X - */
       data->state.resume_from = from;
-      DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file",
-                   from));
+      DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
     }
     else if((from_t == CURL_OFFT_INVAL) && !to_t) {
       /* -Y */
       data->req.maxdownload = to;
       data->state.resume_from = -to;
-      DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes",
-                   to));
+      DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));
     }
     else {
       /* X-Y */
@@ -79,13 +77,12 @@ CURLcode Curl_range(struct Curl_easy *data)
 
       data->req.maxdownload = totalsize + 1; /* include last byte */
       data->state.resume_from = from;
-      DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
-                   " getting %" CURL_FORMAT_CURL_OFF_T " bytes",
+      DEBUGF(infof(data, "RANGE from %" FMT_OFF_T
+                   " getting %" FMT_OFF_T " bytes",
                    from, data->req.maxdownload));
     }
-    DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
-                 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
-                 CURL_FORMAT_CURL_OFF_T " bytes",
+    DEBUGF(infof(data, "range-download from %" FMT_OFF_T
+                 " to %" FMT_OFF_T ", totally %" FMT_OFF_T " bytes",
                  from, to, data->req.maxdownload));
   }
   else

+ 2 - 1
Utilities/cmcurl/lib/curl_rtmp.c

@@ -329,13 +329,14 @@ static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
 }
 
 static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
-                         const void *buf, size_t len, CURLcode *err)
+                         const void *buf, size_t len, bool eos, CURLcode *err)
 {
   struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   ssize_t num;
 
   (void)sockindex; /* unused */
+  (void)eos; /* unused */
 
   num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
   if(num < 0)

+ 24 - 10
Utilities/cmcurl/lib/curl_setup.h

@@ -28,6 +28,9 @@
 #define CURL_NO_OLDIES
 #endif
 
+/* Tell "curl/curl.h" not to include "curl/mprintf.h" */
+#define CURL_SKIP_INCLUDE_MPRINTF
+
 /* FIXME: Delete this once the warnings have been fixed. */
 #if !defined(CURL_WARN_SIGN_CONVERSION)
 #ifdef __GNUC__
@@ -323,7 +326,7 @@
 
 /* curl uses its own printf() function internally. It understands the GNU
  * format. Use this format, so that is matches the GNU format attribute we
- * use with the mingw compiler, allowing it to verify them at compile-time.
+ * use with the MinGW compiler, allowing it to verify them at compile-time.
  */
 #ifdef  __MINGW32__
 #  undef CURL_FORMAT_CURL_OFF_T
@@ -349,6 +352,9 @@
 #define CURL_PRINTF(fmt, arg)
 #endif
 
+/* Override default printf mask check rules in "curl/mprintf.h" */
+#define CURL_TEMP_PRINTF CURL_PRINTF
+
 /* Workaround for mainline llvm v16 and earlier missing a built-in macro
    expected by macOS SDK v14 / Xcode v15 (2023) and newer.
    gcc (as of v14) is also missing it. */
@@ -459,7 +465,7 @@
 #endif
 
 /*
- * Large file (>2Gb) support using WIN32 functions.
+ * Large file (>2Gb) support using Win32 functions.
  */
 
 #ifdef USE_WIN32_LARGE_FILES
@@ -482,7 +488,7 @@
 #endif
 
 /*
- * Small file (<2Gb) support using WIN32 functions.
+ * Small file (<2Gb) support using Win32 functions.
  */
 
 #ifdef USE_WIN32_SMALL_FILES
@@ -528,11 +534,11 @@
 #endif
 
 #if SIZEOF_CURL_SOCKET_T < 8
-#  define CURL_FORMAT_SOCKET_T "d"
+#  define FMT_SOCKET_T "d"
 #elif defined(__MINGW32__)
-#  define CURL_FORMAT_SOCKET_T "zd"
+#  define FMT_SOCKET_T "zd"
 #else
-#  define CURL_FORMAT_SOCKET_T "qd"
+#  define FMT_SOCKET_T "qd"
 #endif
 
 /*
@@ -580,10 +586,13 @@
 #  endif
 #  define CURL_UINT64_SUFFIX  CURL_SUFFIX_CURL_OFF_TU
 #  define CURL_UINT64_C(val)  CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
-# define CURL_PRId64  CURL_FORMAT_CURL_OFF_T
-# define CURL_PRIu64  CURL_FORMAT_CURL_OFF_TU
+# define FMT_PRId64  CURL_FORMAT_CURL_OFF_T
+# define FMT_PRIu64  CURL_FORMAT_CURL_OFF_TU
 #endif
 
+#define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
+#define FMT_OFF_TU CURL_FORMAT_CURL_OFF_TU
+
 #if (SIZEOF_TIME_T == 4)
 #  ifdef HAVE_TIME_T_UNSIGNED
 #  define TIME_T_MAX UINT_MAX
@@ -730,6 +739,11 @@
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 
+#if defined(USE_WOLFSSL) && defined(USE_GNUTLS)
+/* Avoid defining unprefixed wolfSSL SHA macros colliding with nettle ones */
+#define NO_OLD_WC_NAMES
+#endif
+
 /* Single point where USE_SPNEGO definition might be defined */
 #if !defined(CURL_DISABLE_NEGOTIATE_AUTH) && \
     (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
@@ -831,7 +845,7 @@
 
 #if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
 #  if defined(SOCKET) || defined(USE_WINSOCK)
-#    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
+#    error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
 #  endif
 #endif
 
@@ -869,7 +883,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 #define FOPEN_WRITETEXT "wt"
 #define FOPEN_APPENDTEXT "at"
 #elif defined(__CYGWIN__)
-/* Cygwin has specific behavior we need to address when WIN32 is not defined.
+/* Cygwin has specific behavior we need to address when _WIN32 is not defined.
 https://cygwin.com/cygwin-ug-net/using-textbinary.html
 For write we want our output to have line endings of LF and be compatible with
 other Cygwin utilities. For read we want to handle input that may have line

+ 2 - 7
Utilities/cmcurl/lib/curl_sha256.h

@@ -33,13 +33,8 @@
 
 extern const struct HMAC_params Curl_HMAC_SHA256[1];
 
-#ifdef USE_WOLFSSL
-/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
- * sha.h */
-#include <wolfssl/options.h>
-#include <wolfssl/openssl/sha.h>
-#else
-#define SHA256_DIGEST_LENGTH 32
+#ifndef CURL_SHA256_DIGEST_LENGTH
+#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
 #endif
 
 CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,

+ 41 - 34
Utilities/cmcurl/lib/curl_sha512_256.c

@@ -37,7 +37,7 @@
  * * SecureTransport (Darwin)
  * * mbedTLS
  * * BearSSL
- * * rustls
+ * * Rustls
  * Skip the backend if it does not support the required algorithm */
 
 #if defined(USE_OPENSSL)
@@ -93,13 +93,13 @@
 /**
  * Size of the SHA-512/256 single processing block in bytes.
  */
-#define SHA512_256_BLOCK_SIZE 128
+#define CURL_SHA512_256_BLOCK_SIZE 128
 
 /**
  * Size of the SHA-512/256 resulting digest in bytes.
  * This is the final digest size, not intermediate hash.
  */
-#define SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_LENGTH
+#define CURL_SHA512_256_DIGEST_SIZE CURL_SHA512_256_DIGEST_LENGTH
 
 /**
  * Context type used for SHA-512/256 calculations
@@ -124,9 +124,9 @@ Curl_sha512_256_init(void *context)
 
   if(EVP_DigestInit_ex(*ctx, EVP_sha512_256(), NULL)) {
     /* Check whether the header and this file use the same numbers */
-    DEBUGASSERT(EVP_MD_CTX_size(*ctx) == SHA512_256_DIGEST_SIZE);
+    DEBUGASSERT(EVP_MD_CTX_size(*ctx) == CURL_SHA512_256_DIGEST_SIZE);
     /* Check whether the block size is correct */
-    DEBUGASSERT(EVP_MD_CTX_block_size(*ctx) == SHA512_256_BLOCK_SIZE);
+    DEBUGASSERT(EVP_MD_CTX_block_size(*ctx) == CURL_SHA512_256_BLOCK_SIZE);
 
     return CURLE_OK; /* Success */
   }
@@ -163,7 +163,8 @@ Curl_sha512_256_update(void *context,
  * Finalise SHA-512/256 calculation, return digest.
  *
  * @param context the calculation context
- * @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
+ * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
+ #             bytes
  * @return CURLE_OK if succeed,
  *         error code otherwise
  */
@@ -177,11 +178,11 @@ Curl_sha512_256_finish(unsigned char *digest,
 #ifdef NEED_NETBSD_SHA512_256_WORKAROUND
   /* Use a larger buffer to work around a bug in NetBSD:
      https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039 */
-  unsigned char tmp_digest[SHA512_256_DIGEST_SIZE * 2];
+  unsigned char tmp_digest[CURL_SHA512_256_DIGEST_SIZE * 2];
   ret = EVP_DigestFinal_ex(*ctx,
                            tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
   if(ret == CURLE_OK)
-    memcpy(digest, tmp_digest, SHA512_256_DIGEST_SIZE);
+    memcpy(digest, tmp_digest, CURL_SHA512_256_DIGEST_SIZE);
   explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
 #else  /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
   ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
@@ -195,6 +196,9 @@ Curl_sha512_256_finish(unsigned char *digest,
 
 #elif defined(USE_GNUTLS_SHA512_256)
 
+#define CURL_SHA512_256_BLOCK_SIZE  SHA512_256_BLOCK_SIZE
+#define CURL_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE
+
 /**
  * Context type used for SHA-512/256 calculations
  */
@@ -212,7 +216,7 @@ Curl_sha512_256_init(void *context)
   Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
 
   /* Check whether the header and this file use the same numbers */
-  DEBUGASSERT(SHA512_256_DIGEST_LENGTH == SHA512_256_DIGEST_SIZE);
+  DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
 
   sha512_256_init(ctx);
 
@@ -247,7 +251,8 @@ Curl_sha512_256_update(void *context,
  * Finalise SHA-512/256 calculation, return digest.
  *
  * @param context the calculation context
- * @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
+ * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
+ #             bytes
  * @return always CURLE_OK
  */
 static CURLcode
@@ -256,7 +261,8 @@ Curl_sha512_256_finish(unsigned char *digest,
 {
   Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
 
-  sha512_256_digest(ctx, (size_t)SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
+  sha512_256_digest(ctx,
+                    (size_t)CURL_SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
 
   return CURLE_OK;
 }
@@ -360,7 +366,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
  * Size of the SHA-512/256 resulting digest in bytes
  * This is the final digest size, not intermediate hash.
  */
-#define SHA512_256_DIGEST_SIZE \
+#define CURL_SHA512_256_DIGEST_SIZE \
   (SHA512_256_DIGEST_SIZE_WORDS * SHA512_256_BYTES_IN_WORD)
 
 /**
@@ -371,7 +377,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
 /**
  * Size of the SHA-512/256 single processing block in bytes.
  */
-#define SHA512_256_BLOCK_SIZE (SHA512_256_BLOCK_SIZE_BITS / 8)
+#define CURL_SHA512_256_BLOCK_SIZE (SHA512_256_BLOCK_SIZE_BITS / 8)
 
 /**
  * Size of the SHA-512/256 single processing block in words.
@@ -425,7 +431,7 @@ MHDx_sha512_256_init(void *context)
   struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *) context;
 
   /* Check whether the header and this file use the same numbers */
-  DEBUGASSERT(SHA512_256_DIGEST_LENGTH == SHA512_256_DIGEST_SIZE);
+  DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
 
   DEBUGASSERT(sizeof(curl_uint64_t) == 8);
 
@@ -453,7 +459,7 @@ MHDx_sha512_256_init(void *context)
  * Base of the SHA-512/256 transformation.
  * Gets a full 128 bytes block of data and updates hash values;
  * @param H     hash values
- * @param data  the data buffer with #SHA512_256_BLOCK_SIZE bytes block
+ * @param data  the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block
  */
 static void
 MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
@@ -636,9 +642,9 @@ MHDx_sha512_256_update(void *context,
   if(0 == length)
     return CURLE_OK; /* Shortcut, do nothing */
 
-  /* Note: (count & (SHA512_256_BLOCK_SIZE-1))
-     equals (count % SHA512_256_BLOCK_SIZE) for this block size. */
-  bytes_have = (unsigned int) (ctx->count & (SHA512_256_BLOCK_SIZE - 1));
+  /* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
+     equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
+  bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
   ctx->count += length;
   if(length > ctx->count)
     ctx->count_bits_hi += 1U << 3; /* Value wrap */
@@ -646,7 +652,7 @@ MHDx_sha512_256_update(void *context,
   ctx->count &= CURL_UINT64_C(0x1FFFFFFFFFFFFFFF);
 
   if(0 != bytes_have) {
-    unsigned int bytes_left = SHA512_256_BLOCK_SIZE - bytes_have;
+    unsigned int bytes_left = CURL_SHA512_256_BLOCK_SIZE - bytes_have;
     if(length >= bytes_left) {
       /* Combine new data with data in the buffer and process the full
          block. */
@@ -660,12 +666,12 @@ MHDx_sha512_256_update(void *context,
     }
   }
 
-  while(SHA512_256_BLOCK_SIZE <= length) {
+  while(CURL_SHA512_256_BLOCK_SIZE <= length) {
     /* Process any full blocks of new data directly,
        without copying to the buffer. */
     MHDx_sha512_256_transform(ctx->H, data);
-    data += SHA512_256_BLOCK_SIZE;
-    length -= SHA512_256_BLOCK_SIZE;
+    data += CURL_SHA512_256_BLOCK_SIZE;
+    length -= CURL_SHA512_256_BLOCK_SIZE;
   }
 
   if(0 != length) {
@@ -694,7 +700,8 @@ MHDx_sha512_256_update(void *context,
  * Finalise SHA-512/256 calculation, return digest.
  *
  * @param context the calculation context
- * @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
+ * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
+ #             bytes
  * @return always CURLE_OK
  */
 static CURLcode
@@ -712,9 +719,9 @@ MHDx_sha512_256_finish(unsigned char *digest,
      not change the amount of hashed data. */
   num_bits = ctx->count << 3;
 
-  /* Note: (count & (SHA512_256_BLOCK_SIZE-1))
-           equals (count % SHA512_256_BLOCK_SIZE) for this block size. */
-  bytes_have = (unsigned int) (ctx->count & (SHA512_256_BLOCK_SIZE - 1));
+  /* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
+           equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
+  bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
 
   /* Input data must be padded with a single bit "1", then with zeros and
      the finally the length of data in bits must be added as the final bytes
@@ -728,12 +735,12 @@ MHDx_sha512_256_finish(unsigned char *digest,
      processed when formed). */
   ((unsigned char *) ctx_buf)[bytes_have++] = 0x80U;
 
-  if(SHA512_256_BLOCK_SIZE - bytes_have < SHA512_256_SIZE_OF_LEN_ADD) {
+  if(CURL_SHA512_256_BLOCK_SIZE - bytes_have < SHA512_256_SIZE_OF_LEN_ADD) {
     /* No space in the current block to put the total length of message.
        Pad the current block with zeros and process it. */
-    if(bytes_have < SHA512_256_BLOCK_SIZE)
+    if(bytes_have < CURL_SHA512_256_BLOCK_SIZE)
       memset(((unsigned char *) ctx_buf) + bytes_have, 0,
-             SHA512_256_BLOCK_SIZE - bytes_have);
+             CURL_SHA512_256_BLOCK_SIZE - bytes_have);
     /* Process the full block. */
     MHDx_sha512_256_transform(ctx->H, ctx->buffer);
     /* Start the new block. */
@@ -742,17 +749,17 @@ MHDx_sha512_256_finish(unsigned char *digest,
 
   /* Pad the rest of the buffer with zeros. */
   memset(((unsigned char *) ctx_buf) + bytes_have, 0,
-         SHA512_256_BLOCK_SIZE - SHA512_256_SIZE_OF_LEN_ADD - bytes_have);
+         CURL_SHA512_256_BLOCK_SIZE - SHA512_256_SIZE_OF_LEN_ADD - bytes_have);
   /* Put high part of number of bits in processed message and then lower
      part of number of bits as big-endian values.
      See FIPS PUB 180-4 section 5.1.2. */
   /* Note: the target location is predefined and buffer is always aligned */
   MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf)  \
-                      + SHA512_256_BLOCK_SIZE         \
+                      + CURL_SHA512_256_BLOCK_SIZE    \
                       - SHA512_256_SIZE_OF_LEN_ADD,   \
                       ctx->count_bits_hi);
   MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf)      \
-                      + SHA512_256_BLOCK_SIZE             \
+                      + CURL_SHA512_256_BLOCK_SIZE        \
                       - SHA512_256_SIZE_OF_LEN_ADD        \
                       + SHA512_256_BYTES_IN_WORD,         \
                       num_bits);
@@ -841,9 +848,9 @@ const struct HMAC_params Curl_HMAC_SHA512_256[] = {
     /* Context structure size. */
     sizeof(Curl_sha512_256_ctx),
     /* Maximum key length (bytes). */
-    SHA512_256_BLOCK_SIZE,
+    CURL_SHA512_256_BLOCK_SIZE,
     /* Result length (bytes). */
-    SHA512_256_DIGEST_SIZE
+    CURL_SHA512_256_DIGEST_SIZE
   }
 };
 

+ 1 - 1
Utilities/cmcurl/lib/curl_sha512_256.h

@@ -33,7 +33,7 @@
 
 extern const struct HMAC_params Curl_HMAC_SHA512_256[1];
 
-#define SHA512_256_DIGEST_LENGTH 32
+#define CURL_SHA512_256_DIGEST_LENGTH 32
 
 CURLcode
 Curl_sha512_256it(unsigned char *output, const unsigned char *input,

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

@@ -52,10 +52,10 @@ typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
 #endif
 
 /* Handle of security.dll or secur32.dll, depending on Windows version */
-HMODULE s_hSecDll = NULL;
+HMODULE Curl_hSecDll = NULL;
 
 /* Pointer to SSPI dispatch table */
-PSecurityFunctionTable s_pSecFn = NULL;
+PSecurityFunctionTable Curl_pSecFn = NULL;
 
 /*
  * Curl_sspi_global_init()
@@ -79,29 +79,29 @@ CURLcode Curl_sspi_global_init(void)
   INITSECURITYINTERFACE_FN pInitSecurityInterface;
 
   /* If security interface is not yet initialized try to do this */
-  if(!s_hSecDll) {
+  if(!Curl_hSecDll) {
     /* Security Service Provider Interface (SSPI) functions are located in
      * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
      * have both these DLLs (security.dll forwards calls to secur32.dll) */
 
     /* Load SSPI dll into the address space of the calling process */
     if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
-      s_hSecDll = Curl_load_library(TEXT("security.dll"));
+      Curl_hSecDll = Curl_load_library(TEXT("security.dll"));
     else
-      s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
-    if(!s_hSecDll)
+      Curl_hSecDll = Curl_load_library(TEXT("secur32.dll"));
+    if(!Curl_hSecDll)
       return CURLE_FAILED_INIT;
 
     /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
     pInitSecurityInterface =
       CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
-                          (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT)));
+                          (GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT)));
     if(!pInitSecurityInterface)
       return CURLE_FAILED_INIT;
 
     /* Get pointer to Security Service Provider Interface dispatch table */
-    s_pSecFn = pInitSecurityInterface();
-    if(!s_pSecFn)
+    Curl_pSecFn = pInitSecurityInterface();
+    if(!Curl_pSecFn)
       return CURLE_FAILED_INIT;
   }
 
@@ -119,10 +119,10 @@ CURLcode Curl_sspi_global_init(void)
  */
 void Curl_sspi_global_cleanup(void)
 {
-  if(s_hSecDll) {
-    FreeLibrary(s_hSecDll);
-    s_hSecDll = NULL;
-    s_pSecFn = NULL;
+  if(Curl_hSecDll) {
+    FreeLibrary(Curl_hSecDll);
+    Curl_hSecDll = NULL;
+    Curl_pSecFn = NULL;
   }
 }
 

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

@@ -57,8 +57,8 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
 void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
 
 /* Forward-declaration of global variables defined in curl_sspi.c */
-extern HMODULE s_hSecDll;
-extern PSecurityFunctionTable s_pSecFn;
+extern HMODULE Curl_hSecDll;
+extern PSecurityFunctionTable Curl_pSecFn;
 
 /* Provide some definitions missing in old headers */
 #define SP_NAME_DIGEST              "WDigest"

+ 2 - 0
Utilities/cmcurl/lib/curl_threads.c

@@ -35,7 +35,9 @@
 #endif
 
 #include "curl_threads.h"
+#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
+#endif
 /* The last #include file should be: */
 #include "memdebug.h"
 

+ 152 - 53
Utilities/cmcurl/lib/curl_trc.c

@@ -53,6 +53,9 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
 
 void Curl_debug(struct Curl_easy *data, curl_infotype type,
                 char *ptr, size_t size)
@@ -118,10 +121,16 @@ static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
                       const char * const fmt, va_list ap)
 {
   int len = 0;
-  char buffer[MAXINFO + 2];
+  char buffer[MAXINFO + 5];
   if(feat)
-    len = msnprintf(buffer, MAXINFO, "[%s] ", feat->name);
-  len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+    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++] = '.';
+  }
   buffer[len++] = '\n';
   buffer[len] = '\0';
   Curl_debug(data, CURLINFO_TEXT, buffer, len);
@@ -212,58 +221,144 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
 }
 #endif /* !CURL_DISABLE_FTP */
 
-static struct curl_trc_feat *trc_feats[] = {
-  &Curl_trc_feat_read,
-  &Curl_trc_feat_write,
+#ifndef CURL_DISABLE_SMTP
+struct curl_trc_feat Curl_trc_feat_smtp = {
+  "SMTP",
+  CURL_LOG_LVL_NONE,
+};
+
+void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  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);
+    va_end(ap);
+  }
+}
+#endif /* !CURL_DISABLE_SMTP */
+
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+struct curl_trc_feat Curl_trc_feat_ws = {
+  "WS",
+  CURL_LOG_LVL_NONE,
+};
+
+void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  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);
+    va_end(ap);
+  }
+}
+#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
+
+#define TRC_CT_NONE        (0)
+#define TRC_CT_PROTOCOL    (1<<(0))
+#define TRC_CT_NETWORK     (1<<(1))
+#define TRC_CT_PROXY       (1<<(2))
+
+struct trc_feat_def {
+  struct curl_trc_feat *feat;
+  unsigned int category;
+};
+
+static struct trc_feat_def trc_feats[] = {
+  { &Curl_trc_feat_read,      TRC_CT_NONE },
+  { &Curl_trc_feat_write,     TRC_CT_NONE },
 #ifndef CURL_DISABLE_FTP
-  &Curl_trc_feat_ftp,
+  { &Curl_trc_feat_ftp,       TRC_CT_PROTOCOL },
 #endif
 #ifndef CURL_DISABLE_DOH
-  &Curl_doh_trc,
+  { &Curl_doh_trc,            TRC_CT_NETWORK },
+#endif
+#ifndef CURL_DISABLE_SMTP
+  { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
 #endif
-  NULL,
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+  { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
+#endif
+};
+
+struct trc_cft_def {
+  struct Curl_cftype *cft;
+  unsigned int category;
 };
 
-static struct Curl_cftype *cf_types[] = {
-  &Curl_cft_tcp,
-  &Curl_cft_udp,
-  &Curl_cft_unix,
-  &Curl_cft_tcp_accept,
-  &Curl_cft_happy_eyeballs,
-  &Curl_cft_setup,
+static struct trc_cft_def trc_cfts[] = {
+  { &Curl_cft_tcp,            TRC_CT_NETWORK },
+  { &Curl_cft_udp,            TRC_CT_NETWORK },
+  { &Curl_cft_unix,           TRC_CT_NETWORK },
+  { &Curl_cft_tcp_accept,     TRC_CT_NETWORK },
+  { &Curl_cft_happy_eyeballs, TRC_CT_NETWORK },
+  { &Curl_cft_setup,          TRC_CT_PROTOCOL },
 #ifdef USE_NGHTTP2
-  &Curl_cft_nghttp2,
+  { &Curl_cft_nghttp2,        TRC_CT_PROTOCOL },
 #endif
 #ifdef USE_SSL
-  &Curl_cft_ssl,
+  { &Curl_cft_ssl,            TRC_CT_NETWORK },
 #ifndef CURL_DISABLE_PROXY
-  &Curl_cft_ssl_proxy,
+  { &Curl_cft_ssl_proxy,      TRC_CT_PROXY },
 #endif
 #endif
 #if !defined(CURL_DISABLE_PROXY)
 #if !defined(CURL_DISABLE_HTTP)
-  &Curl_cft_h1_proxy,
+  { &Curl_cft_h1_proxy,       TRC_CT_PROXY },
 #ifdef USE_NGHTTP2
-  &Curl_cft_h2_proxy,
+  { &Curl_cft_h2_proxy,       TRC_CT_PROXY },
 #endif
-  &Curl_cft_http_proxy,
+  { &Curl_cft_http_proxy,     TRC_CT_PROXY },
 #endif /* !CURL_DISABLE_HTTP */
-  &Curl_cft_haproxy,
-  &Curl_cft_socks_proxy,
+  { &Curl_cft_haproxy,        TRC_CT_PROXY },
+  { &Curl_cft_socks_proxy,    TRC_CT_PROXY },
 #endif /* !CURL_DISABLE_PROXY */
 #ifdef USE_HTTP3
-  &Curl_cft_http3,
+  { &Curl_cft_http3,          TRC_CT_PROTOCOL },
 #endif
 #if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
-  &Curl_cft_http_connect,
+  { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
 #endif
-  NULL,
 };
 
-CURLcode Curl_trc_opt(const char *config)
+static void trc_apply_level_by_name(const char * const token, int lvl)
+{
+  size_t i;
+
+  for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
+    if(strcasecompare(token, trc_cfts[i].cft->name)) {
+      trc_cfts[i].cft->log_level = lvl;
+      break;
+    }
+  }
+  for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
+    if(strcasecompare(token, trc_feats[i].feat->name)) {
+      trc_feats[i].feat->log_level = lvl;
+      break;
+    }
+  }
+}
+
+static void trc_apply_level_by_category(int category, int lvl)
 {
-  char *token, *tok_buf, *tmp;
   size_t i;
+
+  for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
+    if(!category || (trc_cfts[i].category & category))
+      trc_cfts[i].cft->log_level = lvl;
+  }
+  for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
+    if(!category || (trc_feats[i].category & category))
+      trc_feats[i].feat->log_level = lvl;
+  }
+}
+
+static CURLcode trc_opt(const char *config)
+{
+  char *token, *tok_buf, *tmp;
   int lvl;
 
   tmp = strdup(config);
@@ -285,42 +380,46 @@ CURLcode Curl_trc_opt(const char *config)
         lvl = CURL_LOG_LVL_INFO;
         break;
     }
-    for(i = 0; cf_types[i]; ++i) {
-      if(strcasecompare(token, "all")) {
-        cf_types[i]->log_level = lvl;
-      }
-      else if(strcasecompare(token, cf_types[i]->name)) {
-        cf_types[i]->log_level = lvl;
-        break;
-      }
-    }
-    for(i = 0; trc_feats[i]; ++i) {
-      if(strcasecompare(token, "all")) {
-        trc_feats[i]->log_level = lvl;
-      }
-      else if(strcasecompare(token, trc_feats[i]->name)) {
-        trc_feats[i]->log_level = lvl;
-        break;
-      }
-    }
+    if(strcasecompare(token, "all"))
+      trc_apply_level_by_category(TRC_CT_NONE, lvl);
+    else if(strcasecompare(token, "protocol"))
+      trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
+    else if(strcasecompare(token, "network"))
+      trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
+    else if(strcasecompare(token, "proxy"))
+      trc_apply_level_by_category(TRC_CT_PROXY, lvl);
+    else
+      trc_apply_level_by_name(token, lvl);
+
     token = strtok_r(NULL, ", ", &tok_buf);
   }
   free(tmp);
   return CURLE_OK;
 }
 
-CURLcode Curl_trc_init(void)
+CURLcode Curl_trc_opt(const char *config)
 {
+  CURLcode result = config? trc_opt(config) : CURLE_OK;
 #ifdef DEBUGBUILD
-  /* WIP: we use the auto-init from an env var only in DEBUG builds for
-   * convenience. */
-  const char *config = getenv("CURL_DEBUG");
-  if(config) {
-    return Curl_trc_opt(config);
+  /* CURL_DEBUG can override anything */
+  if(!result) {
+    const char *dbg_config = getenv("CURL_DEBUG");
+    if(dbg_config)
+      result = trc_opt(dbg_config);
   }
 #endif /* DEBUGBUILD */
+  return result;
+}
+
+CURLcode Curl_trc_init(void)
+{
+#ifdef DEBUGBUILD
+  return Curl_trc_opt(NULL);
+#else
   return CURLE_OK;
+#endif
 }
+
 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
 
 CURLcode Curl_trc_init(void)

+ 32 - 0
Utilities/cmcurl/lib/curl_trc.h

@@ -89,6 +89,16 @@ void Curl_failf(struct Curl_easy *data,
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) \
          Curl_trc_ftp(data, __VA_ARGS__); } while(0)
 #endif /* !CURL_DISABLE_FTP */
+#ifndef CURL_DISABLE_SMTP
+#define CURL_TRC_SMTP(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
+         Curl_trc_smtp(data, __VA_ARGS__); } while(0)
+#endif /* !CURL_DISABLE_SMTP */
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#define CURL_TRC_WS(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
+         Curl_trc_ws(data, __VA_ARGS__); } while(0)
+#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
 
 #else /* CURL_HAVE_C99 */
 
@@ -100,6 +110,12 @@ void Curl_failf(struct Curl_easy *data,
 #ifndef CURL_DISABLE_FTP
 #define CURL_TRC_FTP   Curl_trc_ftp
 #endif
+#ifndef CURL_DISABLE_SMTP
+#define CURL_TRC_SMTP  Curl_trc_smtp
+#endif
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#define CURL_TRC_WS    Curl_trc_ws
+#endif
 
 #endif /* !CURL_HAVE_C99 */
 
@@ -148,6 +164,16 @@ extern struct curl_trc_feat Curl_trc_feat_ftp;
 void Curl_trc_ftp(struct Curl_easy *data,
                   const char *fmt, ...) CURL_PRINTF(2, 3);
 #endif
+#ifndef CURL_DISABLE_SMTP
+extern struct curl_trc_feat Curl_trc_feat_smtp;
+void Curl_trc_smtp(struct Curl_easy *data,
+                   const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+extern struct curl_trc_feat Curl_trc_feat_ws;
+void Curl_trc_ws(struct Curl_easy *data,
+                 const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
 
 
 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
@@ -194,6 +220,12 @@ static void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
   (void)data; (void)fmt;
 }
 #endif
+#ifndef CURL_DISABLE_SMTP
+static void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+#endif
 
 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
 

+ 2 - 41
Utilities/cmcurl/lib/curlx.h

@@ -31,10 +31,8 @@
  * be.
  */
 
-#include <curl/mprintf.h>
-/* this is still a public header file that provides the curl_mprintf()
-   functions while they still are offered publicly. They will be made library-
-   private one day */
+/* map standard printf functions to curl implementations */
+#include "curl_printf.h"
 
 #include "strcase.h"
 /* "strcase.h" provides the strcasecompare protos */
@@ -77,41 +75,4 @@
 
 */
 
-#define curlx_mvsnprintf curl_mvsnprintf
-#define curlx_msnprintf curl_msnprintf
-#define curlx_maprintf curl_maprintf
-#define curlx_mvaprintf curl_mvaprintf
-#define curlx_msprintf curl_msprintf
-#define curlx_mprintf curl_mprintf
-#define curlx_mfprintf curl_mfprintf
-#define curlx_mvsprintf curl_mvsprintf
-#define curlx_mvprintf curl_mvprintf
-#define curlx_mvfprintf curl_mvfprintf
-
-#ifdef ENABLE_CURLX_PRINTF
-/* If this define is set, we define all "standard" printf() functions to use
-   the curlx_* version instead. It makes the source code transparent and
-   easier to understand/patch. Undefine them first. */
-# undef printf
-# undef fprintf
-# undef sprintf
-# undef msnprintf
-# undef vprintf
-# undef vfprintf
-# undef vsprintf
-# undef mvsnprintf
-# undef aprintf
-# undef vaprintf
-
-# define printf curlx_mprintf
-# define fprintf curlx_mfprintf
-# define sprintf curlx_msprintf
-# define msnprintf curlx_msnprintf
-# define vprintf curlx_mvprintf
-# define vfprintf curlx_mvfprintf
-# define mvsnprintf curlx_mvsnprintf
-# define aprintf curlx_maprintf
-# define vaprintf curlx_mvaprintf
-#endif /* ENABLE_CURLX_PRINTF */
-
 #endif /* HEADER_CURL_CURLX_H */

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

@@ -146,7 +146,7 @@ static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
 
   for(;;) {
     /* Write the buffer to the socket */
-    result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
+    result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
 
     if(result)
       break;

+ 266 - 259
Utilities/cmcurl/lib/doh.c

@@ -46,7 +46,7 @@
 
 #define DNS_CLASS_IN 0x01
 
-/* local_print_buf truncates if the hex string will be more than this */
+/* doh_print_buf truncates if the hex string will be more than this */
 #define LOCAL_PB_HEXMAX 400
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -82,11 +82,11 @@ struct curl_trc_feat Curl_doh_trc = {
 
 /* @unittest 1655
  */
-UNITTEST DOHcode doh_encode(const char *host,
-                            DNStype dnstype,
-                            unsigned char *dnsp, /* buffer */
-                            size_t len,  /* buffer size */
-                            size_t *olen) /* output length */
+UNITTEST DOHcode doh_req_encode(const char *host,
+                                DNStype dnstype,
+                                unsigned char *dnsp, /* buffer */
+                                size_t len,  /* buffer size */
+                                size_t *olen) /* output length */
 {
   const size_t hostlen = strlen(host);
   unsigned char *orig = dnsp;
@@ -192,9 +192,9 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
 }
 
 #if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
-static void local_print_buf(struct Curl_easy *data,
-                            const char *prefix,
-                            unsigned char *buf, size_t len)
+static void doh_print_buf(struct Curl_easy *data,
+                          const char *prefix,
+                          unsigned char *buf, size_t len)
 {
   unsigned char hexstr[LOCAL_PB_HEXMAX];
   size_t hlen = LOCAL_PB_HEXMAX;
@@ -214,19 +214,26 @@ static void local_print_buf(struct Curl_easy *data,
 /* called from multi.c when this DoH transfer is complete */
 static int doh_done(struct Curl_easy *doh, CURLcode result)
 {
-  struct Curl_easy *data = doh->set.dohfor;
-  struct dohdata *dohp = data->req.doh;
-  /* so one of the DoH request done for the 'data' transfer is now complete! */
-  dohp->pending--;
-  infof(doh, "a DoH request is completed, %u to go", dohp->pending);
-  if(result)
-    infof(doh, "DoH request %s", curl_easy_strerror(result));
+  struct Curl_easy *data; /* the transfer that asked for the DoH probe */
 
-  if(!dohp->pending) {
-    /* DoH completed */
-    curl_slist_free_all(dohp->headers);
-    dohp->headers = NULL;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  data = Curl_multi_get_handle(doh->multi, doh->set.dohfor_mid);
+  if(!data) {
+    DEBUGF(infof(doh, "doh_done: xfer for mid=%" FMT_OFF_T
+                 " not found", doh->set.dohfor_mid));
+    DEBUGASSERT(0);
+  }
+  else {
+    struct doh_probes *dohp = data->req.doh;
+    /* one of the DoH request done for the 'data' transfer is now complete! */
+    dohp->pending--;
+    infof(doh, "a DoH request is completed, %u to go", dohp->pending);
+    if(result)
+      infof(doh, "DoH request %s", curl_easy_strerror(result));
+
+    if(!dohp->pending) {
+      /* DoH completed, run the transfer picking up the results */
+      Curl_expire(data, 0, EXPIRE_RUN_NOW);
+    }
   }
   return 0;
 }
@@ -240,24 +247,24 @@ do {                                          \
     goto error;                               \
 } while(0)
 
-static CURLcode dohprobe(struct Curl_easy *data,
-                         struct dnsprobe *p, DNStype dnstype,
-                         const char *host,
-                         const char *url, CURLM *multi,
-                         struct curl_slist *headers)
+static CURLcode doh_run_probe(struct Curl_easy *data,
+                              struct doh_probe *p, DNStype dnstype,
+                              const char *host,
+                              const char *url, CURLM *multi,
+                              struct curl_slist *headers)
 {
   struct Curl_easy *doh = NULL;
   CURLcode result = CURLE_OK;
   timediff_t timeout_ms;
-  DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
-                         &p->dohlen);
+  DOHcode d = doh_req_encode(host, dnstype, p->req_body, sizeof(p->req_body),
+                             &p->req_body_len);
   if(d) {
     failf(data, "Failed to encode DoH packet [%d]", d);
     return CURLE_OUT_OF_MEMORY;
   }
 
   p->dnstype = dnstype;
-  Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
+  Curl_dyn_init(&p->resp_body, DYN_DOH_RESPONSE);
 
   timeout_ms = Curl_timeleft(data, NULL, TRUE);
   if(timeout_ms <= 0) {
@@ -266,126 +273,126 @@ static CURLcode dohprobe(struct Curl_easy *data,
   }
   /* Curl_open() is the internal version of curl_easy_init() */
   result = Curl_open(&doh);
-  if(!result) {
-    /* pass in the struct pointer via a local variable to please coverity and
-       the gcc typecheck helpers */
-    struct dynbuf *resp = &p->serverdoh;
-    doh->state.internal = true;
+  if(result)
+    goto error;
+
+  /* pass in the struct pointer via a local variable to please coverity and
+     the gcc typecheck helpers */
+  doh->state.internal = true;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-    doh->state.feat = &Curl_doh_trc;
+  doh->state.feat = &Curl_doh_trc;
 #endif
-    ERROR_CHECK_SETOPT(CURLOPT_URL, url);
-    ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
-    ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
-    ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
-    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
-    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
-    ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
+  ERROR_CHECK_SETOPT(CURLOPT_URL, url);
+  ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
+  ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
+  ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, &p->resp_body);
+  ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->req_body);
+  ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->req_body_len);
+  ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
 #ifdef USE_HTTP2
-    ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
-    ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
+  ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+  ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
 #endif
 #ifndef DEBUGBUILD
-    /* enforce HTTPS if not debug */
-    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+  /* enforce HTTPS if not debug */
+  ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
 #else
-    /* in debug mode, also allow http */
-    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
+  /* in debug mode, also allow http */
+  ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
 #endif
-    ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
-    ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
-    if(data->set.err && data->set.err != stderr)
-      ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
-    if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
-      ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
-    if(data->set.no_signal)
-      ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
-
-    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
-      data->set.doh_verifyhost ? 2L : 0L);
-    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
-      data->set.doh_verifypeer ? 1L : 0L);
-    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
-      data->set.doh_verifystatus ? 1L : 0L);
-
-    /* Inherit *some* SSL options from the user's transfer. This is a
-       best-guess as to which options are needed for compatibility. #3661
-
-       Note DoH does not inherit the user's proxy server so proxy SSL settings
-       have no effect and are not inherited. If that changes then two new
-       options should be added to check doh proxy insecure separately,
-       CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
-       */
-    if(data->set.ssl.falsestart)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
-    if(data->set.str[STRING_SSL_CAFILE]) {
-      ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
-                         data->set.str[STRING_SSL_CAFILE]);
-    }
-    if(data->set.blobs[BLOB_CAINFO]) {
-      ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
-                         data->set.blobs[BLOB_CAINFO]);
-    }
-    if(data->set.str[STRING_SSL_CAPATH]) {
-      ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
-                         data->set.str[STRING_SSL_CAPATH]);
-    }
-    if(data->set.str[STRING_SSL_CRLFILE]) {
-      ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
-                         data->set.str[STRING_SSL_CRLFILE]);
-    }
-    if(data->set.ssl.certinfo)
-      ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
-    if(data->set.ssl.fsslctx)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
-    if(data->set.ssl.fsslctxp)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
-    if(data->set.fdebug)
-      ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
-    if(data->set.debugdata)
-      ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
-    if(data->set.str[STRING_SSL_EC_CURVES]) {
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
-                         data->set.str[STRING_SSL_EC_CURVES]);
-    }
+  ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+  ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+  if(data->set.err && data->set.err != stderr)
+    ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
+  if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
+    ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+  if(data->set.no_signal)
+    ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
+
+  ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
+    data->set.doh_verifyhost ? 2L : 0L);
+  ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
+    data->set.doh_verifypeer ? 1L : 0L);
+  ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
+    data->set.doh_verifystatus ? 1L : 0L);
+
+  /* Inherit *some* SSL options from the user's transfer. This is a
+     best-guess as to which options are needed for compatibility. #3661
+
+     Note DoH does not inherit the user's proxy server so proxy SSL settings
+     have no effect and are not inherited. If that changes then two new
+     options should be added to check doh proxy insecure separately,
+     CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
+     */
+  if(data->set.ssl.falsestart)
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
+  if(data->set.str[STRING_SSL_CAFILE]) {
+    ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
+                       data->set.str[STRING_SSL_CAFILE]);
+  }
+  if(data->set.blobs[BLOB_CAINFO]) {
+    ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
+                       data->set.blobs[BLOB_CAINFO]);
+  }
+  if(data->set.str[STRING_SSL_CAPATH]) {
+    ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
+                       data->set.str[STRING_SSL_CAPATH]);
+  }
+  if(data->set.str[STRING_SSL_CRLFILE]) {
+    ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
+                       data->set.str[STRING_SSL_CRLFILE]);
+  }
+  if(data->set.ssl.certinfo)
+    ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
+  if(data->set.ssl.fsslctx)
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
+  if(data->set.ssl.fsslctxp)
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
+  if(data->set.fdebug)
+    ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
+  if(data->set.debugdata)
+    ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
+  if(data->set.str[STRING_SSL_EC_CURVES]) {
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
+                       data->set.str[STRING_SSL_EC_CURVES]);
+  }
 
-    {
-      long mask =
-        (data->set.ssl.enable_beast ?
-         CURLSSLOPT_ALLOW_BEAST : 0) |
-        (data->set.ssl.no_revoke ?
-         CURLSSLOPT_NO_REVOKE : 0) |
-        (data->set.ssl.no_partialchain ?
-         CURLSSLOPT_NO_PARTIALCHAIN : 0) |
-        (data->set.ssl.revoke_best_effort ?
-         CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
-        (data->set.ssl.native_ca_store ?
-         CURLSSLOPT_NATIVE_CA : 0) |
-        (data->set.ssl.auto_client_cert ?
-         CURLSSLOPT_AUTO_CLIENT_CERT : 0);
-
-      (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
-    }
+  {
+    long mask =
+      (data->set.ssl.enable_beast ?
+       CURLSSLOPT_ALLOW_BEAST : 0) |
+      (data->set.ssl.no_revoke ?
+       CURLSSLOPT_NO_REVOKE : 0) |
+      (data->set.ssl.no_partialchain ?
+       CURLSSLOPT_NO_PARTIALCHAIN : 0) |
+      (data->set.ssl.revoke_best_effort ?
+       CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
+      (data->set.ssl.native_ca_store ?
+       CURLSSLOPT_NATIVE_CA : 0) |
+      (data->set.ssl.auto_client_cert ?
+       CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+    (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
+  }
 
-    doh->set.fmultidone = doh_done;
-    doh->set.dohfor = data; /* identify for which transfer this is done */
-    p->easy = doh;
+  doh->set.fmultidone = doh_done;
+  doh->set.dohfor_mid = data->mid; /* for which transfer this is done */
 
-    /* DoH handles must not inherit private_data. The handles may be passed to
-       the user via callbacks and the user will be able to identify them as
-       internal handles because private data is not set. The user can then set
-       private_data via CURLOPT_PRIVATE if they so choose. */
-    DEBUGASSERT(!doh->set.private_data);
+  /* DoH handles must not inherit private_data. The handles may be passed to
+     the user via callbacks and the user will be able to identify them as
+     internal handles because private data is not set. The user can then set
+     private_data via CURLOPT_PRIVATE if they so choose. */
+  DEBUGASSERT(!doh->set.private_data);
 
-    if(curl_multi_add_handle(multi, doh))
-      goto error;
-  }
-  else
+  if(curl_multi_add_handle(multi, doh))
     goto error;
+
+  p->easy_mid = doh->mid;
   return CURLE_OK;
 
 error:
   Curl_close(&doh);
+  p->easy_mid = -1;
   return result;
 }
 
@@ -400,8 +407,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                int *waitp)
 {
   CURLcode result = CURLE_OK;
-  struct dohdata *dohp;
+  struct doh_probes *dohp;
   struct connectdata *conn = data->conn;
+  size_t i;
 #ifdef USE_HTTPSRR
   /* for now, this is only used when ECH is enabled */
 # ifdef USE_ECH
@@ -416,23 +424,27 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   DEBUGASSERT(conn);
 
   /* start clean, consider allocating this struct on demand */
-  dohp = data->req.doh = calloc(1, sizeof(struct dohdata));
+  dohp = data->req.doh = calloc(1, sizeof(struct doh_probes));
   if(!dohp)
     return NULL;
 
+  for(i = 0; i < DOH_SLOT_COUNT; ++i) {
+    dohp->probe[i].easy_mid = -1;
+  }
+
   conn->bits.doh = TRUE;
   dohp->host = hostname;
   dohp->port = port;
-  dohp->headers =
+  dohp->req_hds =
     curl_slist_append(NULL,
                       "Content-Type: application/dns-message");
-  if(!dohp->headers)
+  if(!dohp->req_hds)
     goto error;
 
   /* create IPv4 DoH request */
-  result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
-                    DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
-                    data->multi, dohp->headers);
+  result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV4],
+                         DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
+                         data->multi, dohp->req_hds);
   if(result)
     goto error;
   dohp->pending++;
@@ -440,9 +452,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
 #ifdef USE_IPV6
   if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
     /* create IPv6 DoH request */
-    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
-                      DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
-                      data->multi, dohp->headers);
+    result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV6],
+                           DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
+                           data->multi, dohp->req_hds);
     if(result)
       goto error;
     dohp->pending++;
@@ -469,9 +481,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
       qname = aprintf("_%d._https.%s", port, hostname);
     if(!qname)
       goto error;
-    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
-                      DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
-                      data->multi, dohp->headers);
+    result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
+                           DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
+                           data->multi, dohp->req_hds);
     Curl_safefree(qname);
     if(result)
       goto error;
@@ -487,8 +499,8 @@ error:
   return NULL;
 }
 
-static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
-                         unsigned int *indexp)
+static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
+                             unsigned int *indexp)
 {
   unsigned char length;
   do {
@@ -511,12 +523,13 @@ static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
   return DOH_OK;
 }
 
-static unsigned short get16bit(const unsigned char *doh, unsigned int index)
+static unsigned short doh_get16bit(const unsigned char *doh,
+                                   unsigned int index)
 {
   return (unsigned short)((doh[index] << 8) | doh[index + 1]);
 }
 
-static unsigned int get32bit(const unsigned char *doh, unsigned int index)
+static unsigned int doh_get32bit(const unsigned char *doh, unsigned int index)
 {
   /* make clang and gcc optimize this to bswap by incrementing
      the pointer first. */
@@ -529,7 +542,8 @@ static unsigned int get32bit(const unsigned char *doh, unsigned int index)
          ((unsigned)doh[2] << 8) | doh[3];
 }
 
-static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
+static void doh_store_a(const unsigned char *doh, int index,
+                        struct dohentry *d)
 {
   /* silently ignore addresses over the limit */
   if(d->numaddr < DOH_MAX_ADDR) {
@@ -538,12 +552,10 @@ static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
     memcpy(&a->ip.v4, &doh[index], 4);
     d->numaddr++;
   }
-  return DOH_OK;
 }
 
-static DOHcode store_aaaa(const unsigned char *doh,
-                          int index,
-                          struct dohentry *d)
+static void doh_store_aaaa(const unsigned char *doh, int index,
+                              struct dohentry *d)
 {
   /* silently ignore addresses over the limit */
   if(d->numaddr < DOH_MAX_ADDR) {
@@ -552,14 +564,11 @@ static DOHcode store_aaaa(const unsigned char *doh,
     memcpy(&a->ip.v6, &doh[index], 16);
     d->numaddr++;
   }
-  return DOH_OK;
 }
 
 #ifdef USE_HTTPSRR
-static DOHcode store_https(const unsigned char *doh,
-                           int index,
-                           struct dohentry *d,
-                           uint16_t len)
+static DOHcode doh_store_https(const unsigned char *doh, int index,
+                               struct dohentry *d, uint16_t len)
 {
   /* silently ignore RRs over the limit */
   if(d->numhttps_rrs < DOH_MAX_HTTPS) {
@@ -574,10 +583,8 @@ static DOHcode store_https(const unsigned char *doh,
 }
 #endif
 
-static DOHcode store_cname(const unsigned char *doh,
-                           size_t dohlen,
-                           unsigned int index,
-                           struct dohentry *d)
+static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
+                               unsigned int index, struct dohentry *d)
 {
   struct dynbuf *c;
   unsigned int loop = 128; /* a valid DNS name can never loop this much */
@@ -626,12 +633,12 @@ static DOHcode store_cname(const unsigned char *doh,
   return DOH_OK;
 }
 
-static DOHcode rdata(const unsigned char *doh,
-                     size_t dohlen,
-                     unsigned short rdlength,
-                     unsigned short type,
-                     int index,
-                     struct dohentry *d)
+static DOHcode doh_rdata(const unsigned char *doh,
+                         size_t dohlen,
+                         unsigned short rdlength,
+                         unsigned short type,
+                         int index,
+                         struct dohentry *d)
 {
   /* RDATA
      - A (TYPE 1):  4 bytes
@@ -644,26 +651,22 @@ static DOHcode rdata(const unsigned char *doh,
   case DNS_TYPE_A:
     if(rdlength != 4)
       return DOH_DNS_RDATA_LEN;
-    rc = store_a(doh, index, d);
-    if(rc)
-      return rc;
+    doh_store_a(doh, index, d);
     break;
   case DNS_TYPE_AAAA:
     if(rdlength != 16)
       return DOH_DNS_RDATA_LEN;
-    rc = store_aaaa(doh, index, d);
-    if(rc)
-      return rc;
+    doh_store_aaaa(doh, index, d);
     break;
 #ifdef USE_HTTPSRR
   case DNS_TYPE_HTTPS:
-    rc = store_https(doh, index, d, rdlength);
+    rc = doh_store_https(doh, index, d, rdlength);
     if(rc)
       return rc;
     break;
 #endif
   case DNS_TYPE_CNAME:
-    rc = store_cname(doh, dohlen, (unsigned int)index, d);
+    rc = doh_store_cname(doh, dohlen, (unsigned int)index, d);
     if(rc)
       return rc;
     break;
@@ -687,10 +690,10 @@ UNITTEST void de_init(struct dohentry *de)
 }
 
 
-UNITTEST DOHcode doh_decode(const unsigned char *doh,
-                            size_t dohlen,
-                            DNStype dnstype,
-                            struct dohentry *d)
+UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
+                                 size_t dohlen,
+                                 DNStype dnstype,
+                                 struct dohentry *d)
 {
   unsigned char rcode;
   unsigned short qdcount;
@@ -710,9 +713,9 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
   if(rcode)
     return DOH_DNS_BAD_RCODE; /* bad rcode */
 
-  qdcount = get16bit(doh, 4);
+  qdcount = doh_get16bit(doh, 4);
   while(qdcount) {
-    rc = skipqname(doh, dohlen, &index);
+    rc = doh_skipqname(doh, dohlen, &index);
     if(rc)
       return rc; /* bad qname */
     if(dohlen < (index + 4))
@@ -721,19 +724,19 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     qdcount--;
   }
 
-  ancount = get16bit(doh, 6);
+  ancount = doh_get16bit(doh, 6);
   while(ancount) {
     unsigned short class;
     unsigned int ttl;
 
-    rc = skipqname(doh, dohlen, &index);
+    rc = doh_skipqname(doh, dohlen, &index);
     if(rc)
       return rc; /* bad qname */
 
     if(dohlen < (index + 2))
       return DOH_DNS_OUT_OF_RANGE;
 
-    type = get16bit(doh, index);
+    type = doh_get16bit(doh, index);
     if((type != DNS_TYPE_CNAME)    /* may be synthesized from DNAME */
        && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
        && (type != dnstype))
@@ -743,7 +746,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
 
     if(dohlen < (index + 2))
       return DOH_DNS_OUT_OF_RANGE;
-    class = get16bit(doh, index);
+    class = doh_get16bit(doh, index);
     if(DNS_CLASS_IN != class)
       return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
     index += 2;
@@ -751,7 +754,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     if(dohlen < (index + 4))
       return DOH_DNS_OUT_OF_RANGE;
 
-    ttl = get32bit(doh, index);
+    ttl = doh_get32bit(doh, index);
     if(ttl < d->ttl)
       d->ttl = ttl;
     index += 4;
@@ -759,21 +762,21 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     if(dohlen < (index + 2))
       return DOH_DNS_OUT_OF_RANGE;
 
-    rdlength = get16bit(doh, index);
+    rdlength = doh_get16bit(doh, index);
     index += 2;
     if(dohlen < (index + rdlength))
       return DOH_DNS_OUT_OF_RANGE;
 
-    rc = rdata(doh, dohlen, rdlength, type, (int)index, d);
+    rc = doh_rdata(doh, dohlen, rdlength, type, (int)index, d);
     if(rc)
-      return rc; /* bad rdata */
+      return rc; /* bad doh_rdata */
     index += rdlength;
     ancount--;
   }
 
-  nscount = get16bit(doh, 8);
+  nscount = doh_get16bit(doh, 8);
   while(nscount) {
-    rc = skipqname(doh, dohlen, &index);
+    rc = doh_skipqname(doh, dohlen, &index);
     if(rc)
       return rc; /* bad qname */
 
@@ -785,7 +788,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     if(dohlen < (index + 2))
       return DOH_DNS_OUT_OF_RANGE;
 
-    rdlength = get16bit(doh, index);
+    rdlength = doh_get16bit(doh, index);
     index += 2;
     if(dohlen < (index + rdlength))
       return DOH_DNS_OUT_OF_RANGE;
@@ -793,9 +796,9 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     nscount--;
   }
 
-  arcount = get16bit(doh, 10);
+  arcount = doh_get16bit(doh, 10);
   while(arcount) {
-    rc = skipqname(doh, dohlen, &index);
+    rc = doh_skipqname(doh, dohlen, &index);
     if(rc)
       return rc; /* bad qname */
 
@@ -807,7 +810,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     if(dohlen < (index + 2))
       return DOH_DNS_OUT_OF_RANGE;
 
-    rdlength = get16bit(doh, index);
+    rdlength = doh_get16bit(doh, index);
     index += 2;
     if(dohlen < (index + rdlength))
       return DOH_DNS_OUT_OF_RANGE;
@@ -830,8 +833,8 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
 }
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-static void showdoh(struct Curl_easy *data,
-                    const struct dohentry *d)
+static void doh_show(struct Curl_easy *data,
+                     const struct dohentry *d)
 {
   int i;
   infof(data, "[DoH] TTL: %u seconds", d->ttl);
@@ -864,8 +867,8 @@ static void showdoh(struct Curl_easy *data,
 #ifdef USE_HTTPSRR
   for(i = 0; i < d->numhttps_rrs; i++) {
 # ifdef DEBUGBUILD
-    local_print_buf(data, "DoH HTTPS",
-                    d->https_rrs[i].val, d->https_rrs[i].len);
+    doh_print_buf(data, "DoH HTTPS",
+                  d->https_rrs[i].val, d->https_rrs[i].len);
 # else
     infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
 # endif
@@ -876,7 +879,7 @@ static void showdoh(struct Curl_easy *data,
   }
 }
 #else
-#define showdoh(x,y)
+#define doh_show(x,y)
 #endif
 
 /*
@@ -996,7 +999,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
 }
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-static const char *type2name(DNStype dnstype)
+static const char *doh_type2name(DNStype dnstype)
 {
   switch(dnstype) {
     case DNS_TYPE_A:
@@ -1041,8 +1044,8 @@ UNITTEST void de_cleanup(struct dohentry *d)
  * just after the end of the DNS name encoding on output. (And
  * that is why it is an "unsigned char **" :-)
  */
-static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
-                                        char **dnsname)
+static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
+                                      char **dnsname)
 {
   unsigned char *cp = NULL;
   int rem = 0;
@@ -1088,8 +1091,8 @@ static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
   return CURLE_OK;
 }
 
-static CURLcode local_decode_rdata_alpn(unsigned char *rrval, size_t len,
-                                        char **alpns)
+static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
+                                      char **alpns)
 {
   /*
    * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
@@ -1145,7 +1148,7 @@ err:
 }
 
 #ifdef DEBUGBUILD
-static CURLcode test_alpn_escapes(void)
+static CURLcode doh_test_alpn_escapes(void)
 {
   /* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
   static unsigned char example[] = {
@@ -1158,7 +1161,7 @@ static CURLcode test_alpn_escapes(void)
   char *aval = NULL;
   static const char *expected = "f\\\\oo\\,bar,h2";
 
-  if(local_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
+  if(doh_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
     return CURLE_BAD_CONTENT_ENCODING;
   if(strlen(aval) != strlen(expected))
     return CURLE_BAD_CONTENT_ENCODING;
@@ -1168,7 +1171,7 @@ static CURLcode test_alpn_escapes(void)
 }
 #endif
 
-static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
+static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
                                         struct Curl_https_rrinfo **hrr)
 {
   size_t remaining = len;
@@ -1179,7 +1182,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
 
 #ifdef DEBUGBUILD
   /* a few tests of escaping, should not be here but ok for now */
-  if(test_alpn_escapes() != CURLE_OK)
+  if(doh_test_alpn_escapes() != CURLE_OK)
     return CURLE_OUT_OF_MEMORY;
 #endif
   lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
@@ -1194,7 +1197,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
   lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
   cp += 2;
   remaining -= (uint16_t)2;
-  if(local_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
+  if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
     goto err;
   lhrr->target = dnsname;
   while(remaining >= 4) {
@@ -1204,7 +1207,7 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
     cp += 2;
     remaining -= 4;
     if(pcode == HTTPS_RR_CODE_ALPN) {
-      if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
+      if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
         goto err;
     }
     if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
@@ -1253,8 +1256,8 @@ err:
 }
 
 # ifdef DEBUGBUILD
-static void local_print_httpsrr(struct Curl_easy *data,
-                                struct Curl_https_rrinfo *hrr)
+static void doh_print_httpsrr(struct Curl_easy *data,
+                              struct Curl_https_rrinfo *hrr)
 {
   DEBUGASSERT(hrr);
   infof(data, "HTTPS RR: priority %d, target: %s",
@@ -1268,20 +1271,20 @@ static void local_print_httpsrr(struct Curl_easy *data,
   else
     infof(data, "HTTPS RR: no_def_alpn not set");
   if(hrr->ipv4hints) {
-    local_print_buf(data, "HTTPS RR: ipv4hints",
-                    hrr->ipv4hints, hrr->ipv4hints_len);
+    doh_print_buf(data, "HTTPS RR: ipv4hints",
+                  hrr->ipv4hints, hrr->ipv4hints_len);
   }
   else
     infof(data, "HTTPS RR: no ipv4hints");
   if(hrr->echconfiglist) {
-    local_print_buf(data, "HTTPS RR: ECHConfigList",
-                    hrr->echconfiglist, hrr->echconfiglist_len);
+    doh_print_buf(data, "HTTPS RR: ECHConfigList",
+                  hrr->echconfiglist, hrr->echconfiglist_len);
   }
   else
     infof(data, "HTTPS RR: no ECHConfigList");
   if(hrr->ipv6hints) {
-    local_print_buf(data, "HTTPS RR: ipv6hint",
-                    hrr->ipv6hints, hrr->ipv6hints_len);
+    doh_print_buf(data, "HTTPS RR: ipv6hint",
+                  hrr->ipv6hints, hrr->ipv6hints_len);
   }
   else
     infof(data, "HTTPS RR: no ipv6hints");
@@ -1294,52 +1297,45 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dnsp)
 {
   CURLcode result;
-  struct dohdata *dohp = data->req.doh;
+  struct doh_probes *dohp = data->req.doh;
   *dnsp = NULL; /* defaults to no response */
   if(!dohp)
     return CURLE_OUT_OF_MEMORY;
 
-  if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
-     !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
+  if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
+     dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
     failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
     return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
       CURLE_COULDNT_RESOLVE_HOST;
   }
   else if(!dohp->pending) {
-#ifndef USE_HTTPSRR
-    DOHcode rc[DOH_PROBE_SLOTS] = {
-      DOH_OK, DOH_OK
-    };
-#else
-    DOHcode rc[DOH_PROBE_SLOTS] = {
-      DOH_OK, DOH_OK, DOH_OK
-    };
-#endif
+    DOHcode rc[DOH_SLOT_COUNT];
     struct dohentry de;
     int slot;
+
+    memset(rc, 0, sizeof(rc));
     /* remove DoH handles from multi handle and close them */
     Curl_doh_close(data);
     /* parse the responses, create the struct and return it! */
     de_init(&de);
-    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      struct dnsprobe *p = &dohp->probe[slot];
+    for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
+      struct doh_probe *p = &dohp->probe[slot];
       if(!p->dnstype)
         continue;
-      rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
-                            Curl_dyn_len(&p->serverdoh),
-                            p->dnstype,
-                            &de);
-      Curl_dyn_free(&p->serverdoh);
+      rc[slot] = doh_resp_decode(Curl_dyn_uptr(&p->resp_body),
+                                 Curl_dyn_len(&p->resp_body),
+                                 p->dnstype, &de);
+      Curl_dyn_free(&p->resp_body);
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
       if(rc[slot]) {
         infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
-              type2name(p->dnstype), dohp->host);
+              doh_type2name(p->dnstype), dohp->host);
       }
 #endif
     } /* next slot */
 
     result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
-    if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
+    if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
       /* we have an address, of one kind or other */
       struct Curl_dns_entry *dns;
       struct Curl_addrinfo *ai;
@@ -1347,7 +1343,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
       if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
         infof(data, "[DoH] hostname: %s", dohp->host);
-        showdoh(data, &de);
+        doh_show(data, &de);
       }
 
       result = doh2ai(&de, dohp->host, dohp->port, &ai);
@@ -1360,7 +1356,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
       /* we got a response, store it in the cache */
-      dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port);
+      dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port, FALSE);
 
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1380,7 +1376,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 #ifdef USE_HTTPSRR
     if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
       struct Curl_https_rrinfo *hrr = NULL;
-      result = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
+      result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
                                        &hrr);
       if(result) {
         infof(data, "Failed to decode HTTPS RR");
@@ -1388,7 +1384,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
       }
       infof(data, "Some HTTPS RR to process");
 # ifdef DEBUGBUILD
-      local_print_httpsrr(data, hrr);
+      doh_print_httpsrr(data, hrr);
 # endif
       (*dnsp)->hinfo = hrr;
     }
@@ -1396,7 +1392,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
     /* All done */
     de_cleanup(&de);
-    Curl_safefree(data->req.doh);
+    Curl_doh_cleanup(data);
     return result;
 
   } /* !dohp->pending */
@@ -1407,28 +1403,39 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
 void Curl_doh_close(struct Curl_easy *data)
 {
-  struct dohdata *doh = data->req.doh;
-  if(doh) {
+  struct doh_probes *doh = data->req.doh;
+  if(doh && data->multi) {
+    struct Curl_easy *probe_data;
+    curl_off_t mid;
     size_t slot;
-    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      if(!doh->probe[slot].easy)
+    for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
+      mid = doh->probe[slot].easy_mid;
+      if(mid < 0)
         continue;
+      doh->probe[slot].easy_mid = -1;
+      /* should have been called before data is removed from multi handle */
+      DEBUGASSERT(data->multi);
+      probe_data = data->multi? Curl_multi_get_handle(data->multi, mid) : NULL;
+      if(!probe_data) {
+        DEBUGF(infof(data, "Curl_doh_close: xfer for mid=%"
+                     FMT_OFF_T " not found!",
+                     doh->probe[slot].easy_mid));
+        continue;
+      }
       /* data->multi might already be reset at this time */
-      if(doh->probe[slot].easy->multi)
-        curl_multi_remove_handle(doh->probe[slot].easy->multi,
-                                 doh->probe[slot].easy);
-      Curl_close(&doh->probe[slot].easy);
+      curl_multi_remove_handle(data->multi, probe_data);
+      Curl_close(&probe_data);
     }
   }
 }
 
 void Curl_doh_cleanup(struct Curl_easy *data)
 {
-  struct dohdata *doh = data->req.doh;
+  struct doh_probes *doh = data->req.doh;
   if(doh) {
     Curl_doh_close(data);
-    curl_slist_free_all(doh->headers);
-    data->req.doh->headers = NULL;
+    curl_slist_free_all(doh->req_hds);
+    data->req.doh->req_hds = NULL;
     Curl_safefree(data->req.doh);
   }
 }

+ 40 - 19
Utilities/cmcurl/lib/doh.h

@@ -59,18 +59,39 @@ typedef enum {
 } DNStype;
 
 /* one of these for each DoH request */
-struct dnsprobe {
-  CURL *easy;
+struct doh_probe {
+  curl_off_t easy_mid; /* multi id of easy handle doing the lookup */
   DNStype dnstype;
-  unsigned char dohbuffer[512];
-  size_t dohlen;
-  struct dynbuf serverdoh;
+  unsigned char req_body[512];
+  size_t req_body_len;
+  struct dynbuf resp_body;
 };
 
-struct dohdata {
-  struct curl_slist *headers;
-  struct dnsprobe probe[DOH_PROBE_SLOTS];
-  unsigned int pending; /* still outstanding requests */
+enum doh_slot_num {
+  /* Explicit values for first two symbols so as to match hard-coded
+   * constants in existing code
+   */
+  DOH_SLOT_IPV4 = 0, /* make 'V4' stand out for readability */
+  DOH_SLOT_IPV6 = 1, /* 'V6' likewise */
+
+  /* Space here for (possibly build-specific) additional slot definitions */
+#ifdef USE_HTTPSRR
+  DOH_SLOT_HTTPS_RR = 2,     /* for HTTPS RR */
+#endif
+
+  /* for example */
+  /* #ifdef WANT_DOH_FOOBAR_TXT */
+  /*   DOH_PROBE_SLOT_FOOBAR_TXT, */
+  /* #endif */
+
+  /* AFTER all slot definitions, establish how many we have */
+  DOH_SLOT_COUNT
+};
+
+struct doh_probes {
+  struct curl_slist *req_hds;
+  struct doh_probe probe[DOH_SLOT_COUNT];
+  unsigned int pending; /* still outstanding probes */
   int port;
   const char *host;
 };
@@ -116,7 +137,7 @@ struct dohaddr {
 #define HTTPS_RR_CODE_IPV6            0x06
 
 /*
- * These may need escaping when found within an alpn string
+ * These may need escaping when found within an ALPN string
  * value.
  */
 #define COMMA_CHAR                    ','
@@ -144,15 +165,15 @@ void Curl_doh_close(struct Curl_easy *data);
 void Curl_doh_cleanup(struct Curl_easy *data);
 
 #ifdef UNITTESTS
-UNITTEST DOHcode doh_encode(const char *host,
-                            DNStype dnstype,
-                            unsigned char *dnsp,  /* buffer */
-                            size_t len,  /* buffer size */
-                            size_t *olen);  /* output length */
-UNITTEST DOHcode doh_decode(const unsigned char *doh,
-                            size_t dohlen,
-                            DNStype dnstype,
-                            struct dohentry *d);
+UNITTEST DOHcode doh_req_encode(const char *host,
+                                DNStype dnstype,
+                                unsigned char *dnsp,  /* buffer */
+                                size_t len,  /* buffer size */
+                                size_t *olen);  /* output length */
+UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
+                                 size_t dohlen,
+                                 DNStype dnstype,
+                                 struct dohentry *d);
 
 UNITTEST void de_init(struct dohentry *d);
 UNITTEST void de_cleanup(struct dohentry *d);

+ 70 - 89
Utilities/cmcurl/lib/easy.c

@@ -113,6 +113,7 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
 #endif
 
 #if defined(_MSC_VER) && defined(_DLL)
+#  pragma warning(push)
 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
 #endif
 
@@ -130,7 +131,7 @@ curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
 #endif
 
 #if defined(_MSC_VER) && defined(_DLL)
-#  pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#  pragma warning(pop)
 #endif
 
 #ifdef DEBUGBUILD
@@ -390,25 +391,22 @@ struct events {
   int running_handles;  /* store the returned number */
 };
 
+#define DEBUG_EV_POLL   0
+
 /* events_timer
  *
  * Callback that gets called with a new value when the timeout should be
  * updated.
  */
-
 static int events_timer(struct Curl_multi *multi,    /* multi handle */
                         long timeout_ms, /* see above */
                         void *userp)    /* private callback pointer */
 {
   struct events *ev = userp;
   (void)multi;
-  if(timeout_ms == -1)
-    /* timeout removed */
-    timeout_ms = 0;
-  else if(timeout_ms == 0)
-    /* timeout is already reached! */
-    timeout_ms = 1; /* trigger asap */
-
+#if DEBUG_EV_POLL
+  fprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms);
+#endif
   ev->ms = timeout_ms;
   ev->msbump = TRUE;
   return 0;
@@ -462,6 +460,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
   struct events *ev = userp;
   struct socketmonitor *m;
   struct socketmonitor *prev = NULL;
+  bool found = FALSE;
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) easy;
@@ -471,7 +470,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
   m = ev->list;
   while(m) {
     if(m->socket.fd == s) {
-
+      found = TRUE;
       if(what == CURL_POLL_REMOVE) {
         struct socketmonitor *nxt = m->next;
         /* remove this node from the list of monitored sockets */
@@ -480,15 +479,13 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
         else
           ev->list = nxt;
         free(m);
-        m = nxt;
-        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
-              " REMOVED", s);
+        infof(easy, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s);
       }
       else {
         /* The socket 's' is already being monitored, update the activity
            mask. Convert from libcurl bitmask to the poll one. */
         m->socket.events = socketcb2poll(what);
-        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
+        infof(easy, "socket cb: socket %" FMT_SOCKET_T
               " UPDATED as %s%s", s,
               (what&CURL_POLL_IN)?"IN":"",
               (what&CURL_POLL_OUT)?"OUT":"");
@@ -498,12 +495,13 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
     prev = m;
     m = m->next; /* move to next node */
   }
-  if(!m) {
+
+  if(!found) {
     if(what == CURL_POLL_REMOVE) {
-      /* this happens a bit too often, libcurl fix perhaps? */
-      /* fprintf(stderr,
-         "%s: socket %d asked to be REMOVED but not present!\n",
-                 __func__, s); */
+      /* should not happen if our logic is correct, but is no drama. */
+      DEBUGF(infof(easy, "socket cb: asked to REMOVE socket %"
+                   FMT_SOCKET_T "but not present!", s));
+      DEBUGASSERT(0);
     }
     else {
       m = malloc(sizeof(struct socketmonitor));
@@ -513,8 +511,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
         m->socket.events = socketcb2poll(what);
         m->socket.revents = 0;
         ev->list = m;
-        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
-              " ADDED as %s%s", s,
+        infof(easy, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s,
               (what&CURL_POLL_IN)?"IN":"",
               (what&CURL_POLL_OUT)?"OUT":"");
       }
@@ -564,14 +561,15 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     int pollrc;
     int i;
     struct curltime before;
-    struct curltime after;
 
     /* populate the fds[] array */
     for(m = ev->list, f = &fds[0]; m; m = m->next) {
       f->fd = m->socket.fd;
       f->events = m->socket.events;
       f->revents = 0;
-      /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
+#if DEBUG_EV_POLL
+      fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd);
+#endif
       f++;
       numfds++;
     }
@@ -579,12 +577,27 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     /* get the time stamp to use to figure out how long poll takes */
     before = Curl_now();
 
-    /* wait for activity or timeout */
-    pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
-    if(pollrc < 0)
-      return CURLE_UNRECOVERABLE_POLL;
-
-    after = Curl_now();
+    if(numfds) {
+      /* wait for activity or timeout */
+#if DEBUG_EV_POLL
+      fprintf(stderr, "poll(numfds=%d, timeout=%ldms)\n", numfds, ev->ms);
+#endif
+      pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
+#if DEBUG_EV_POLL
+      fprintf(stderr, "poll(numfds=%d, timeout=%ldms) -> %d\n",
+              numfds, ev->ms, pollrc);
+#endif
+      if(pollrc < 0)
+        return CURLE_UNRECOVERABLE_POLL;
+    }
+    else {
+#if DEBUG_EV_POLL
+      fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms);
+#endif
+      pollrc = 0;
+      if(ev->ms > 0)
+        Curl_wait_ms(ev->ms);
+    }
 
     ev->msbump = FALSE; /* reset here */
 
@@ -597,26 +610,37 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     }
     else {
       /* here pollrc is > 0 */
+      struct Curl_llist_node *e = Curl_llist_head(&multi->process);
+      struct Curl_easy *data;
+      DEBUGASSERT(e);
+      data = Curl_node_elem(e);
+      DEBUGASSERT(data);
 
       /* loop over the monitored sockets to see which ones had activity */
       for(i = 0; i< numfds; i++) {
         if(fds[i].revents) {
           /* socket activity, tell libcurl */
           int act = poll2cselect(fds[i].revents); /* convert */
-          infof(multi->easyp,
-                "call curl_multi_socket_action(socket "
-                "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd);
+
+          /* sending infof "randomly" to the first easy handle */
+          infof(data, "call curl_multi_socket_action(socket "
+                "%" FMT_SOCKET_T ")", (curl_socket_t)fds[i].fd);
           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
                                            &ev->running_handles);
         }
       }
 
-      if(!ev->msbump) {
+
+      if(!ev->msbump && ev->ms >= 0) {
         /* If nothing updated the timeout, we decrease it by the spent time.
          * If it was updated, it has the new timeout time stored already.
          */
-        timediff_t timediff = Curl_timediff(after, before);
+        timediff_t timediff = Curl_timediff(Curl_now(), before);
         if(timediff > 0) {
+#if DEBUG_EV_POLL
+        fprintf(stderr, "poll timeout %ldms not updated, decrease by "
+                "time spent %ldms\n", ev->ms, (long)timediff);
+#endif
           if(timediff > ev->ms)
             ev->ms = 0;
           else
@@ -649,7 +673,7 @@ static CURLcode easy_events(struct Curl_multi *multi)
 {
   /* this struct is made static to allow it to be used after this function
      returns and curl_multi_remove_handle() is called */
-  static struct events evs = {2, FALSE, 0, NULL, 0};
+  static struct events evs = {-1, FALSE, 0, NULL, 0};
 
   /* if running event-based, do some further multi inits */
   events_setup(multi, &evs);
@@ -914,8 +938,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
 
   Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
 
-  /* the connection cache is setup on demand */
-  outcurl->state.conn_cache = NULL;
+  /* the connection pool is setup on demand */
   outcurl->state.lastconnect_id = -1;
   outcurl->state.recent_conn_id = -1;
   outcurl->id = -1;
@@ -1012,7 +1035,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
       goto fail;
   }
 #endif /* USE_ARES */
-
+#ifndef CURL_DISABLE_HTTP
+  Curl_llist_init(&outcurl->state.httphdrs, NULL);
+#endif
   Curl_initinfo(outcurl);
 
   outcurl->magic = CURLEASY_MAGIC_NUMBER;
@@ -1112,7 +1137,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
                   (data->mstate == MSTATE_PERFORMING ||
                    data->mstate == MSTATE_RATELIMITING));
   /* Unpausing writes is detected on the next run in
-   * transfer.c:Curl_readwrite(). This is because this may result
+   * transfer.c:Curl_sendrecv(). This is because this may result
    * in a transfer error if the application's callbacks fail */
 
   /* Set the new keepon state, so it takes effect no matter what error
@@ -1264,7 +1289,7 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
     Curl_attach_connection(data, c);
 
   sigpipe_ignore(data, &pipe_st);
-  result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, n);
+  result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
   sigpipe_restore(&pipe_st);
 
   if(result && result != CURLE_AGAIN)
@@ -1289,47 +1314,6 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
   return result;
 }
 
-/*
- * Wrapper to call functions in Curl_conncache_foreach()
- *
- * Returns always 0.
- */
-static int conn_upkeep(struct Curl_easy *data,
-                       struct connectdata *conn,
-                       void *param)
-{
-  struct curltime *now = param;
-
-  if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
-    return 0;
-
-  /* briefly attach for action */
-  Curl_attach_connection(data, conn);
-  if(conn->handler->connection_check) {
-    /* Do a protocol-specific keepalive check on the connection. */
-    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
-  }
-  else {
-    /* Do the generic action on the FIRSTSOCKET filter chain */
-    Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
-  }
-  Curl_detach_connection(data);
-
-  conn->keepalive = *now;
-  return 0; /* continue iteration */
-}
-
-static CURLcode upkeep(struct conncache *conn_cache, void *data)
-{
-  struct curltime now = Curl_now();
-  /* Loop over every connection and make connection alive. */
-  Curl_conncache_foreach(data,
-                         conn_cache,
-                         &now,
-                         conn_upkeep);
-  return CURLE_OK;
-}
-
 /*
  * Performs connection upkeep for the given session handle.
  */
@@ -1339,12 +1323,9 @@ CURLcode curl_easy_upkeep(struct Curl_easy *data)
   if(!GOOD_EASY_HANDLE(data))
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
-  if(data->multi_easy) {
-    /* Use the common function to keep connections alive. */
-    return upkeep(&data->multi_easy->conn_cache, data);
-  }
-  else {
-    /* No connections, so just return success */
-    return CURLE_OK;
-  }
+  if(Curl_is_in_callback(data))
+    return CURLE_RECURSIVE_API_CALL;
+
+  /* Use the common function to keep connections alive. */
+  return Curl_cpool_upkeep(data);
 }

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

@@ -63,12 +63,12 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
   if(!string || (inlength < 0))
     return NULL;
 
-  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);
-
   length = (inlength?(size_t)inlength:strlen(string));
   if(!length)
     return strdup("");
 
+  Curl_dyn_init(&d, length * 3 + 1);
+
   while(length--) {
     /* treat the characters unsigned */
     unsigned char in = (unsigned char)*string++;

+ 2 - 3
Utilities/cmcurl/lib/file.c

@@ -223,7 +223,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
    * A leading slash in an AmigaDOS path denotes the parent
    * directory, and hence we block this as it is relative.
    * Absolute paths start with 'volumename:', so we check for
-   * this first. Failing that, we treat the path as a real unix
+   * this first. Failing that, we treat the path as a real Unix
    * path, but only if the application was compiled with -lunix.
    */
   fd = -1;
@@ -468,8 +468,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
     static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" };
     if(expected_size >= 0) {
       headerlen =
-        msnprintf(header, sizeof(header),
-                  "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+        msnprintf(header, sizeof(header), "Content-Length: %" FMT_OFF_T "\r\n",
                   expected_size);
       result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
       if(result)

+ 1 - 1
Utilities/cmcurl/lib/fileinfo.h

@@ -30,7 +30,7 @@
 
 struct fileinfo {
   struct curl_fileinfo info;
-  struct Curl_llist_element list;
+  struct Curl_llist_node list;
   struct dynbuf buf;
 };
 

+ 3 - 3
Utilities/cmcurl/lib/formdata.c

@@ -790,10 +790,10 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
 /* wrap call to fseeko so it matches the calling convention of callback */
 static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
 {
-#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
-  return fseeko(stream, (off_t)offset, whence);
-#elif defined(HAVE__FSEEKI64)
+#if defined(HAVE__FSEEKI64)
   return _fseeki64(stream, (__int64)offset, whence);
+#elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
+  return fseeko(stream, (off_t)offset, whence);
 #else
   if(offset > LONG_MAX)
     return -1;

+ 57 - 57
Utilities/cmcurl/lib/ftp.c

@@ -188,7 +188,7 @@ static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 static void ftp_pasv_verbose(struct Curl_easy *data,
                              struct Curl_addrinfo *ai,
-                             char *newhost, /* ascii version */
+                             char *newhost, /* ASCII version */
                              int port);
 #endif
 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
@@ -327,7 +327,7 @@ static void freedirs(struct ftp_conn *ftpc)
   Curl_safefree(ftpc->newhost);
 }
 
-#ifdef CURL_DO_LINEEND_CONV
+#ifdef CURL_PREFER_LF_LINEENDS
 /***********************************************************************
  *
  * Lineend Conversions
@@ -369,7 +369,6 @@ static CURLcode ftp_cw_lc_write(struct Curl_easy *data,
       }
       /* either we just wrote the newline or it is part of the next
        * chunk of bytes we write. */
-      data->state.crlf_conversions++;
       ctx->newline_pending = FALSE;
     }
 
@@ -400,7 +399,6 @@ static CURLcode ftp_cw_lc_write(struct Curl_easy *data,
     /* EndOfStream, if we have a trailing cr, now is the time to write it */
     if(ctx->newline_pending) {
       ctx->newline_pending = FALSE;
-      data->state.crlf_conversions++;
       return Curl_cwriter_write(data, writer->next, type, &nl, 1);
     }
     /* Always pass on the EOS type indicator */
@@ -418,7 +416,7 @@ static const struct Curl_cwtype ftp_cw_lc = {
   sizeof(struct ftp_cw_lc_ctx)
 };
 
-#endif /* CURL_DO_LINEEND_CONV */
+#endif /* CURL_PREFER_LF_LINEENDS */
 /***********************************************************************
  *
  * AcceptServerConnect()
@@ -819,6 +817,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
   int cache_skip = 0;
   int value_to_be_ignored = 0;
 
+  CURL_TRC_FTP(data, "getFTPResponse start");
+
   if(ftpcode)
     *ftpcode = 0; /* 0 for errors */
   else
@@ -864,21 +864,27 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
        */
     }
     else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
-      switch(SOCKET_READABLE(sockfd, interval_ms)) {
-      case -1: /* select() error, stop reading */
+      curl_socket_t wsock = Curl_pp_needs_flush(data, pp)?
+                            sockfd : CURL_SOCKET_BAD;
+      int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms);
+      if(ev < 0) {
         failf(data, "FTP response aborted due to select/poll error: %d",
               SOCKERRNO);
         return CURLE_RECV_ERROR;
-
-      case 0: /* timeout */
+      }
+      else if(ev == 0) {
         if(Curl_pgrsUpdate(data))
           return CURLE_ABORTED_BY_CALLBACK;
         continue; /* just continue in our loop for the timeout duration */
+      }
+    }
 
-      default: /* for clarity */
+    if(Curl_pp_needs_flush(data, pp)) {
+      result = Curl_pp_flushsend(data, pp);
+      if(result)
         break;
-      }
     }
+
     result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
     if(result)
       break;
@@ -897,6 +903,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
   } /* while there is buffer left and loop is requested */
 
   pp->pending_resp = FALSE;
+  CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d",
+               result, *nreadp, *ftpcode);
 
   return result;
 }
@@ -1042,7 +1050,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
   int error;
   char *host = NULL;
   char *string_ftpport = data->set.str[STRING_FTPPORT];
-  struct Curl_dns_entry *h = NULL;
+  struct Curl_dns_entry *dns_entry = NULL;
   unsigned short port_min = 0;
   unsigned short port_max = 0;
   unsigned short port;
@@ -1178,15 +1186,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
   }
 
   /* resolv ip/host to ip */
-  rc = Curl_resolv(data, host, 0, FALSE, &h);
+  rc = Curl_resolv(data, host, 0, FALSE, &dns_entry);
   if(rc == CURLRESOLV_PENDING)
-    (void)Curl_resolver_wait_resolv(data, &h);
-  if(h) {
-    res = h->addr;
-    /* when we return from this function, we can forget about this entry
-       to we can unlock it now already */
-    Curl_resolv_unlock(data, h);
-  } /* (h) */
+    (void)Curl_resolver_wait_resolv(data, &dns_entry);
+  if(dns_entry) {
+    res = dns_entry->addr;
+  }
   else
     res = NULL; /* failure! */
 
@@ -1381,6 +1386,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
   ftp_state(data, FTP_PORT);
 
 out:
+  /* If we looked up a dns_entry, now is the time to safely release it */
+  if(dns_entry)
+    Curl_resolv_unlink(data, &dns_entry);
   if(result) {
     ftp_state(data, FTP_STOP);
   }
@@ -2072,7 +2080,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
 
     /* postponed address resolution in case of tcp fastopen */
     if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
-      Curl_conn_ev_update_info(data, conn);
       Curl_safefree(ftpc->newhost);
       ftpc->newhost = strdup(control_address(conn));
       if(!ftpc->newhost)
@@ -2098,7 +2105,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
                            CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
 
   if(result) {
-    Curl_resolv_unlock(data, addr); /* we are done using this address */
+    Curl_resolv_unlink(data, &addr); /* we are done using this address */
     if(ftpc->count1 == 0 && ftpcode == 229)
       return ftp_epsv_disable(data, conn);
 
@@ -2116,7 +2123,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     /* this just dumps information about this second connection */
     ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
 
-  Curl_resolv_unlock(data, addr); /* we are done using this address */
+  Curl_resolv_unlink(data, &addr); /* we are done using this address */
 
   Curl_safefree(conn->secondaryhostname);
   conn->secondary_port = ftpc->newport;
@@ -2383,8 +2390,8 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
       if(data->state.resume_from< 0) {
         /* We are supposed to download the last abs(from) bytes */
         if(filesize < -data->state.resume_from) {
-          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
-                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+          failf(data, "Offset (%" FMT_OFF_T
+                ") was beyond file size (%" FMT_OFF_T ")",
                 data->state.resume_from, filesize);
           return CURLE_BAD_DOWNLOAD_RESUME;
         }
@@ -2395,8 +2402,8 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
       }
       else {
         if(filesize < data->state.resume_from) {
-          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
-                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+          failf(data, "Offset (%" FMT_OFF_T
+                ") was beyond file size (%" FMT_OFF_T ")",
                 data->state.resume_from, filesize);
           return CURLE_BAD_DOWNLOAD_RESUME;
         }
@@ -2418,10 +2425,10 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
     }
 
     /* Set resume file transfer offset */
-    infof(data, "Instructs server to resume from offset %"
-          CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
+    infof(data, "Instructs server to resume from offset %" FMT_OFF_T,
+          data->state.resume_from);
 
-    result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
+    result = Curl_pp_sendf(data, &ftpc->pp, "REST %" FMT_OFF_T,
                            data->state.resume_from);
     if(!result)
       ftp_state(data, FTP_RETR_REST);
@@ -2479,7 +2486,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
     if(-1 != filesize) {
       char clbuf[128];
       int clbuflen = msnprintf(clbuf, sizeof(clbuf),
-                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
+                "Content-Length: %" FMT_OFF_T "\r\n", filesize);
       result = client_write_header(data, clbuf, clbuflen);
       if(result)
         return result;
@@ -2659,12 +2666,10 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
     else if((instate != FTP_LIST) && (data->state.prefer_ascii))
       size = -1; /* kludge for servers that understate ASCII mode file size */
 
-    infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
-          data->req.maxdownload);
+    infof(data, "Maxdownload = %" FMT_OFF_T, data->req.maxdownload);
 
     if(instate != FTP_LIST)
-      infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
-            size);
+      infof(data, "Getting file with size: %" FMT_OFF_T, size);
 
     /* FTP download: */
     conn->proto.ftpc.state_saved = instate;
@@ -3529,8 +3534,8 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
        (data->state.infilesize != data->req.writebytecount) &&
        !data->set.crlf &&
        (ftp->transfer == PPTRANSFER_BODY)) {
-      failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
-            " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
+      failf(data, "Uploaded unaligned file size (%" FMT_OFF_T
+            " out of %" FMT_OFF_T " bytes)",
             data->req.writebytecount, data->state.infilesize);
       result = CURLE_PARTIAL_FILE;
     }
@@ -3538,17 +3543,9 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
   else {
     if((-1 != data->req.size) &&
        (data->req.size != data->req.bytecount) &&
-#ifdef CURL_DO_LINEEND_CONV
-       /* Most FTP servers do not adjust their file SIZE response for CRLFs,
-        * so we will check to see if the discrepancy can be explained by the
-        * number of CRLFs we have changed to LFs.
-        */
-       ((data->req.size + data->state.crlf_conversions) !=
-        data->req.bytecount) &&
-#endif /* CURL_DO_LINEEND_CONV */
        (data->req.maxdownload != data->req.bytecount)) {
-      failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
-            " bytes", data->req.bytecount);
+      failf(data, "Received only partial file: %" FMT_OFF_T " bytes",
+            data->req.bytecount);
       result = CURLE_PARTIAL_FILE;
     }
     else if(!ftpc->dont_check &&
@@ -3684,7 +3681,7 @@ static CURLcode ftp_nb_type(struct Curl_easy *data,
 static void
 ftp_pasv_verbose(struct Curl_easy *data,
                  struct Curl_addrinfo *ai,
-                 char *newhost, /* ascii version */
+                 char *newhost, /* ASCII version */
                  int port)
 {
   char buf[256];
@@ -4028,7 +4025,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         wildcard->state = CURLWC_CLEAN;
         continue;
       }
-      if(wildcard->filelist.size == 0) {
+      if(Curl_llist_count(&wildcard->filelist) == 0) {
         /* no corresponding file */
         wildcard->state = CURLWC_CLEAN;
         return CURLE_REMOTE_FILE_NOT_FOUND;
@@ -4039,7 +4036,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
     case CURLWC_DOWNLOADING: {
       /* filelist has at least one file, lets get first one */
       struct ftp_conn *ftpc = &conn->proto.ftpc;
-      struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+      struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist);
+      struct curl_fileinfo *finfo = Curl_node_elem(head);
       struct FTP *ftp = data->req.p.ftp;
 
       char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
@@ -4055,7 +4053,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         long userresponse;
         Curl_set_in_callback(data, true);
         userresponse = data->set.chunk_bgn(
-          finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
+          finfo, data->set.wildcardptr,
+          (int)Curl_llist_count(&wildcard->filelist));
         Curl_set_in_callback(data, false);
         switch(userresponse) {
         case CURL_CHUNK_BGN_FUNC_SKIP:
@@ -4081,9 +4080,10 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         return result;
 
       /* we do not need the Curl_fileinfo of first file anymore */
-      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+      Curl_node_remove(Curl_llist_head(&wildcard->filelist));
 
-      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+      if(Curl_llist_count(&wildcard->filelist) == 0) {
+        /* remains only one file to down. */
         wildcard->state = CURLWC_CLEAN;
         /* after that will be ftp_do called once again and no transfer
            will be done because of CURLWC_CLEAN state */
@@ -4098,8 +4098,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         data->set.chunk_end(data->set.wildcardptr);
         Curl_set_in_callback(data, false);
       }
-      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
-      wildcard->state = (wildcard->filelist.size == 0) ?
+      Curl_node_remove(Curl_llist_head(&wildcard->filelist));
+      wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ?
         CURLWC_CLEAN : CURLWC_DOWNLOADING;
       continue;
     }
@@ -4145,7 +4145,7 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
   *done = FALSE; /* default to false */
   ftpc->wait_data_conn = FALSE; /* default to no such wait */
 
-#ifdef CURL_DO_LINEEND_CONV
+#ifdef CURL_PREFER_LF_LINEENDS
   {
     /* FTP data may need conversion. */
     struct Curl_cwriter *ftp_lc_writer;
@@ -4161,7 +4161,7 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
       return result;
     }
   }
-#endif /* CURL_DO_LINEEND_CONV */
+#endif /* CURL_PREFER_LF_LINEENDS */
 
   if(data->state.wildcardmatch) {
     result = wc_statemach(data);

+ 30 - 18
Utilities/cmcurl/lib/getinfo.c

@@ -53,6 +53,7 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   pro->t_connect = 0;
   pro->t_appconnect = 0;
   pro->t_pretransfer = 0;
+  pro->t_posttransfer = 0;
   pro->t_starttransfer = 0;
   pro->timespent = 0;
   pro->t_redirect = 0;
@@ -76,10 +77,9 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   free(info->wouldredirect);
   info->wouldredirect = NULL;
 
-  info->primary.remote_ip[0] = '\0';
-  info->primary.local_ip[0] = '\0';
-  info->primary.remote_port = 0;
-  info->primary.local_port = 0;
+  memset(&info->primary, 0, sizeof(info->primary));
+  info->primary.remote_port = -1;
+  info->primary.local_port = -1;
   info->retry_after = 0;
 
   info->conn_scheme = 0;
@@ -252,11 +252,13 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_SSL_VERIFYRESULT:
     *param_longp = data->set.ssl.certverifyresult;
     break;
-#ifndef CURL_DISABLE_PROXY
   case CURLINFO_PROXY_SSL_VERIFYRESULT:
+#ifndef CURL_DISABLE_PROXY
     *param_longp = data->set.proxy_ssl.certverifyresult;
-    break;
+#else
+    *param_longp = 0;
 #endif
+    break;
   case CURLINFO_REDIRECT_COUNT:
     *param_longp = data->state.followlocation;
     break;
@@ -314,6 +316,12 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_RTSP_CSEQ_RECV:
     *param_longp = data->state.rtsp_CSeq_recv;
     break;
+#else
+  case CURLINFO_RTSP_CLIENT_CSEQ:
+  case CURLINFO_RTSP_SERVER_CSEQ:
+  case CURLINFO_RTSP_CSEQ_RECV:
+    *param_longp = 0;
+    break;
 #endif
   case CURLINFO_HTTP_VERSION:
     switch(data->info.httpversion) {
@@ -368,6 +376,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
     case CURLINFO_CONNECT_TIME_T:
     case CURLINFO_APPCONNECT_TIME_T:
     case CURLINFO_PRETRANSFER_TIME_T:
+    case CURLINFO_POSTTRANSFER_TIME_T:
     case CURLINFO_STARTTRANSFER_TIME_T:
     case CURLINFO_REDIRECT_TIME_T:
     case CURLINFO_SPEED_DOWNLOAD_T:
@@ -384,24 +393,24 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
     *param_offt = (curl_off_t)data->info.filetime;
     break;
   case CURLINFO_SIZE_UPLOAD_T:
-    *param_offt = data->progress.uploaded;
+    *param_offt = data->progress.ul.cur_size;
     break;
   case CURLINFO_SIZE_DOWNLOAD_T:
-    *param_offt = data->progress.downloaded;
+    *param_offt = data->progress.dl.cur_size;
     break;
   case CURLINFO_SPEED_DOWNLOAD_T:
-    *param_offt = data->progress.dlspeed;
+    *param_offt = data->progress.dl.speed;
     break;
   case CURLINFO_SPEED_UPLOAD_T:
-    *param_offt = data->progress.ulspeed;
+    *param_offt = data->progress.ul.speed;
     break;
   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
-      data->progress.size_dl:-1;
+      data->progress.dl.total_size:-1;
     break;
   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
-      data->progress.size_ul:-1;
+      data->progress.ul.total_size:-1;
     break;
    case CURLINFO_TOTAL_TIME_T:
     *param_offt = data->progress.timespent;
@@ -418,6 +427,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_PRETRANSFER_TIME_T:
     *param_offt = data->progress.t_pretransfer;
     break;
+  case CURLINFO_POSTTRANSFER_TIME_T:
+    *param_offt = data->progress.t_posttransfer;
+    break;
   case CURLINFO_STARTTRANSFER_TIME_T:
     *param_offt = data->progress.t_starttransfer;
     break;
@@ -488,24 +500,24 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
     break;
   case CURLINFO_SIZE_UPLOAD:
-    *param_doublep = (double)data->progress.uploaded;
+    *param_doublep = (double)data->progress.ul.cur_size;
     break;
   case CURLINFO_SIZE_DOWNLOAD:
-    *param_doublep = (double)data->progress.downloaded;
+    *param_doublep = (double)data->progress.dl.cur_size;
     break;
   case CURLINFO_SPEED_DOWNLOAD:
-    *param_doublep = (double)data->progress.dlspeed;
+    *param_doublep = (double)data->progress.dl.speed;
     break;
   case CURLINFO_SPEED_UPLOAD:
-    *param_doublep = (double)data->progress.ulspeed;
+    *param_doublep = (double)data->progress.ul.speed;
     break;
   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
-      (double)data->progress.size_dl:-1;
+      (double)data->progress.dl.total_size:-1;
     break;
   case CURLINFO_CONTENT_LENGTH_UPLOAD:
     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
-      (double)data->progress.size_ul:-1;
+      (double)data->progress.ul.total_size:-1;
     break;
   case CURLINFO_REDIRECT_TIME:
     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);

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

@@ -187,7 +187,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
     if(strlen(sel) < 1)
       break;
 
-    result = Curl_xfer_send(data, sel, k, &amount);
+    result = Curl_xfer_send(data, sel, k, FALSE, &amount);
     if(!result) { /* Which may not have written it all! */
       result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
       if(result)
@@ -229,7 +229,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
   free(sel_org);
 
   if(!result)
-    result = Curl_xfer_send(data, "\r\n", 2, &amount);
+    result = Curl_xfer_send(data, "\r\n", 2, FALSE, &amount);
   if(result) {
     failf(data, "Failed sending Gopher request");
     return result;

+ 48 - 30
Utilities/cmcurl/lib/hash.c

@@ -33,6 +33,10 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+/* random patterns for API verification */
+#define HASHINIT 0x7017e781
+#define ITERINIT 0x5FEDCBA9
+
 static void
 hash_element_dtor(void *user, void *element)
 {
@@ -77,6 +81,9 @@ Curl_hash_init(struct Curl_hash *h,
   h->dtor = dtor;
   h->size = 0;
   h->slots = slots;
+#ifdef DEBUGBUILD
+  h->init = HASHINIT;
+#endif
 }
 
 static struct Curl_hash_element *
@@ -102,11 +109,12 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
                      Curl_hash_elem_dtor dtor)
 {
   struct Curl_hash_element  *he;
-  struct Curl_llist_element *le;
+  struct Curl_llist_node *le;
   struct Curl_llist *l;
 
   DEBUGASSERT(h);
   DEBUGASSERT(h->slots);
+  DEBUGASSERT(h->init == HASHINIT);
   if(!h->table) {
     size_t i;
     h->table = malloc(h->slots * sizeof(struct Curl_llist));
@@ -118,10 +126,10 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
 
   l = FETCH_LIST(h, key, key_len);
 
-  for(le = l->head; le; le = le->next) {
-    he = (struct Curl_hash_element *) le->ptr;
+  for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
+    he = (struct Curl_hash_element *) Curl_node_elem(le);
     if(h->comp_func(he->key, he->key_len, key, key_len)) {
-      Curl_llist_remove(l, le, (void *)h);
+      Curl_node_uremove(le, (void *)h);
       --h->size;
       break;
     }
@@ -158,18 +166,17 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
  */
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
 {
-  struct Curl_llist_element *le;
-  struct Curl_llist *l;
-
   DEBUGASSERT(h);
   DEBUGASSERT(h->slots);
+  DEBUGASSERT(h->init == HASHINIT);
   if(h->table) {
-    l = FETCH_LIST(h, key, key_len);
+    struct Curl_llist_node *le;
+    struct Curl_llist *l = FETCH_LIST(h, key, key_len);
 
-    for(le = l->head; le; le = le->next) {
-      struct Curl_hash_element *he = le->ptr;
+    for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
+      struct Curl_hash_element *he = Curl_node_elem(le);
       if(h->comp_func(he->key, he->key_len, key, key_len)) {
-        Curl_llist_remove(l, le, (void *) h);
+        Curl_node_uremove(le, (void *) h);
         --h->size;
         return 0;
       }
@@ -185,15 +192,15 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
 void *
 Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
 {
-  struct Curl_llist_element *le;
-  struct Curl_llist *l;
-
   DEBUGASSERT(h);
+  DEBUGASSERT(h->init == HASHINIT);
   if(h->table) {
+    struct Curl_llist_node *le;
+    struct Curl_llist *l;
     DEBUGASSERT(h->slots);
     l = FETCH_LIST(h, key, key_len);
-    for(le = l->head; le; le = le->next) {
-      struct Curl_hash_element *he = le->ptr;
+    for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
+      struct Curl_hash_element *he = Curl_node_elem(le);
       if(h->comp_func(he->key, he->key_len, key, key_len)) {
         return he->ptr;
       }
@@ -213,6 +220,7 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
 void
 Curl_hash_destroy(struct Curl_hash *h)
 {
+  DEBUGASSERT(h->init == HASHINIT);
   if(h->table) {
     size_t i;
     for(i = 0; i < h->slots; ++i) {
@@ -234,28 +242,33 @@ Curl_hash_clean(struct Curl_hash *h)
   Curl_hash_clean_with_criterium(h, NULL, NULL);
 }
 
+size_t Curl_hash_count(struct Curl_hash *h)
+{
+  DEBUGASSERT(h->init == HASHINIT);
+  return h->size;
+}
+
 /* Cleans all entries that pass the comp function criteria. */
 void
 Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                int (*comp)(void *, void *))
 {
-  struct Curl_llist_element *le;
-  struct Curl_llist_element *lnext;
-  struct Curl_llist *list;
   size_t i;
 
   if(!h || !h->table)
     return;
 
+  DEBUGASSERT(h->init == HASHINIT);
   for(i = 0; i < h->slots; ++i) {
-    list = &h->table[i];
-    le = list->head; /* get first list entry */
+    struct Curl_llist *list = &h->table[i];
+    struct Curl_llist_node *le =
+      Curl_llist_head(list); /* get first list entry */
     while(le) {
-      struct Curl_hash_element *he = le->ptr;
-      lnext = le->next;
+      struct Curl_hash_element *he = Curl_node_elem(le);
+      struct Curl_llist_node *lnext = Curl_node_next(le);
       /* ask the callback function if we shall remove this entry or not */
       if(!comp || comp(user, he->ptr)) {
-        Curl_llist_remove(list, le, (void *) h);
+        Curl_node_uremove(le, (void *) h);
         --h->size; /* one less entry in the hash now */
       }
       le = lnext;
@@ -290,29 +303,34 @@ size_t Curl_str_key_compare(void *k1, size_t key1_len,
 void Curl_hash_start_iterate(struct Curl_hash *hash,
                              struct Curl_hash_iterator *iter)
 {
+  DEBUGASSERT(hash->init == HASHINIT);
   iter->hash = hash;
   iter->slot_index = 0;
   iter->current_element = NULL;
+#ifdef DEBUGBUILD
+  iter->init = ITERINIT;
+#endif
 }
 
 struct Curl_hash_element *
 Curl_hash_next_element(struct Curl_hash_iterator *iter)
 {
-  struct Curl_hash *h = iter->hash;
-
+  struct Curl_hash *h;
+  DEBUGASSERT(iter->init == ITERINIT);
+  h = iter->hash;
   if(!h->table)
     return NULL; /* empty hash, nothing to return */
 
   /* Get the next element in the current list, if any */
   if(iter->current_element)
-    iter->current_element = iter->current_element->next;
+    iter->current_element = Curl_node_next(iter->current_element);
 
   /* If we have reached the end of the list, find the next one */
   if(!iter->current_element) {
     size_t i;
     for(i = iter->slot_index; i < h->slots; i++) {
-      if(h->table[i].head) {
-        iter->current_element = h->table[i].head;
+      if(Curl_llist_head(&h->table[i])) {
+        iter->current_element = Curl_llist_head(&h->table[i]);
         iter->slot_index = i + 1;
         break;
       }
@@ -320,7 +338,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
   }
 
   if(iter->current_element) {
-    struct Curl_hash_element *he = iter->current_element->ptr;
+    struct Curl_hash_element *he = Curl_node_elem(iter->current_element);
     return he;
   }
   return NULL;

+ 13 - 3
Utilities/cmcurl/lib/hash.h

@@ -56,22 +56,31 @@ struct Curl_hash {
   Curl_hash_dtor   dtor;
   size_t slots;
   size_t size;
+#ifdef DEBUGBUILD
+  int init;
+#endif
 };
 
 typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
 
 struct Curl_hash_element {
-  struct Curl_llist_element list;
+  struct Curl_llist_node list;
   void   *ptr;
   Curl_hash_elem_dtor dtor;
   size_t key_len;
+#ifdef DEBUGBUILD
+  int init;
+#endif
   char   key[1]; /* allocated memory following the struct */
 };
 
 struct Curl_hash_iterator {
   struct Curl_hash *hash;
   size_t slot_index;
-  struct Curl_llist_element *current_element;
+  struct Curl_llist_node *current_element;
+#ifdef DEBUGBUILD
+  int init;
+#endif
 };
 
 void Curl_hash_init(struct Curl_hash *h,
@@ -85,8 +94,9 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
                      Curl_hash_elem_dtor dtor);
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
 void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
-#define Curl_hash_count(h) ((h)->size)
+
 void Curl_hash_destroy(struct Curl_hash *h);
+size_t Curl_hash_count(struct Curl_hash *h);
 void Curl_hash_clean(struct Curl_hash *h);
 void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                     int (*comp)(void *, void *));

+ 22 - 22
Utilities/cmcurl/lib/headers.c

@@ -42,7 +42,7 @@
 static void copy_header_external(struct Curl_header_store *hs,
                                  size_t index,
                                  size_t amount,
-                                 struct Curl_llist_element *e,
+                                 struct Curl_llist_node *e,
                                  struct curl_header *hout)
 {
   struct curl_header *h = hout;
@@ -66,8 +66,8 @@ CURLHcode curl_easy_header(CURL *easy,
                            int request,
                            struct curl_header **hout)
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *e_pick = NULL;
+  struct Curl_llist_node *e;
+  struct Curl_llist_node *e_pick = NULL;
   struct Curl_easy *data = easy;
   size_t match = 0;
   size_t amount = 0;
@@ -85,8 +85,8 @@ CURLHcode curl_easy_header(CURL *easy,
     request = data->state.requests;
 
   /* we need a first round to count amount of this header */
-  for(e = data->state.httphdrs.head; e; e = e->next) {
-    hs = e->ptr;
+  for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
+    hs = Curl_node_elem(e);
     if(strcasecompare(hs->name, name) &&
        (hs->type & type) &&
        (hs->request == request)) {
@@ -104,8 +104,8 @@ CURLHcode curl_easy_header(CURL *easy,
     /* if the last or only occurrence is what's asked for, then we know it */
     hs = pick;
   else {
-    for(e = data->state.httphdrs.head; e; e = e->next) {
-      hs = e->ptr;
+    for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
+      hs = Curl_node_elem(e);
       if(strcasecompare(hs->name, name) &&
          (hs->type & type) &&
          (hs->request == request) &&
@@ -131,8 +131,8 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
                                          struct curl_header *prev)
 {
   struct Curl_easy *data = easy;
-  struct Curl_llist_element *pick;
-  struct Curl_llist_element *e;
+  struct Curl_llist_node *pick;
+  struct Curl_llist_node *e;
   struct Curl_header_store *hs;
   size_t amount = 0;
   size_t index = 0;
@@ -147,18 +147,18 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
     if(!pick)
       /* something is wrong */
       return NULL;
-    pick = pick->next;
+    pick = Curl_node_next(pick);
   }
   else
-    pick = data->state.httphdrs.head;
+    pick = Curl_llist_head(&data->state.httphdrs);
 
   if(pick) {
     /* make sure it is the next header of the desired type */
     do {
-      hs = pick->ptr;
+      hs = Curl_node_elem(pick);
       if((hs->type & type) && (hs->request == request))
         break;
-      pick = pick->next;
+      pick = Curl_node_next(pick);
     } while(pick);
   }
 
@@ -166,12 +166,12 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
     /* no more headers available */
     return NULL;
 
-  hs = pick->ptr;
+  hs = Curl_node_elem(pick);
 
   /* count number of occurrences of this name within the mask and figure out
      the index for the currently selected entry */
-  for(e = data->state.httphdrs.head; e; e = e->next) {
-    struct Curl_header_store *check = e->ptr;
+  for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
+    struct Curl_header_store *check = Curl_node_elem(e);
     if(strcasecompare(hs->name, check->name) &&
        (check->request == request) &&
        (check->type & type))
@@ -247,7 +247,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
   /* since this header block might move in the realloc below, it needs to
      first be unlinked from the list and then re-added again after the
      realloc */
-  Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
+  Curl_node_remove(&hs->node);
 
   /* new size = struct + new value length + old name+value length */
   newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
@@ -405,12 +405,12 @@ CURLcode Curl_headers_init(struct Curl_easy *data)
  */
 CURLcode Curl_headers_cleanup(struct Curl_easy *data)
 {
-  struct Curl_llist_element *e;
-  struct Curl_llist_element *n;
+  struct Curl_llist_node *e;
+  struct Curl_llist_node *n;
 
-  for(e = data->state.httphdrs.head; e; e = n) {
-    struct Curl_header_store *hs = e->ptr;
-    n = e->next;
+  for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
+    struct Curl_header_store *hs = Curl_node_elem(e);
+    n = Curl_node_next(e);
     free(hs);
   }
   headers_reset(data);

+ 1 - 1
Utilities/cmcurl/lib/headers.h

@@ -28,7 +28,7 @@
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
 
 struct Curl_header_store {
-  struct Curl_llist_element node;
+  struct Curl_llist_node node;
   char *name; /* points into 'buffer' */
   char *value; /* points into 'buffer */
   int request; /* 0 is the first request, then 1.. 2.. */

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

@@ -79,7 +79,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
 
       dns = Curl_cache_addr(data, ai,
                             data->state.async.hostname, 0,
-                            data->state.async.port);
+                            data->state.async.port, FALSE);
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
 

+ 49 - 44
Utilities/cmcurl/lib/hostip.c

@@ -115,7 +115,7 @@
  * CURLRES_* defines based on the config*.h and curl_setup.h defines.
  */
 
-static void freednsentry(void *freethis);
+static void hostcache_unlink_entry(void *entry);
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 static void show_resolve_info(struct Curl_easy *data,
@@ -178,7 +178,7 @@ create_hostcache_id(const char *name,
 struct hostcache_prune_data {
   time_t now;
   time_t oldest; /* oldest time in cache not pruned. */
-  int cache_timeout;
+  int max_age_sec;
 };
 
 /*
@@ -189,16 +189,16 @@ struct hostcache_prune_data {
  * cache.
  */
 static int
-hostcache_timestamp_remove(void *datap, void *hc)
+hostcache_entry_is_stale(void *datap, void *hc)
 {
   struct hostcache_prune_data *prune =
     (struct hostcache_prune_data *) datap;
-  struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+  struct Curl_dns_entry *dns = (struct Curl_dns_entry *) hc;
 
-  if(c->timestamp) {
+  if(dns->timestamp) {
     /* age in seconds */
-    time_t age = prune->now - c->timestamp;
-    if(age >= prune->cache_timeout)
+    time_t age = prune->now - dns->timestamp;
+    if(age >= prune->max_age_sec)
       return TRUE;
     if(age > prune->oldest)
       prune->oldest = age;
@@ -216,13 +216,13 @@ hostcache_prune(struct Curl_hash *hostcache, int cache_timeout,
 {
   struct hostcache_prune_data user;
 
-  user.cache_timeout = cache_timeout;
+  user.max_age_sec = cache_timeout;
   user.now = now;
   user.oldest = 0;
 
   Curl_hash_clean_with_criterium(hostcache,
                                  (void *) &user,
-                                 hostcache_timestamp_remove);
+                                 hostcache_entry_is_stale);
 
   return user.oldest;
 }
@@ -257,7 +257,8 @@ void Curl_hostcache_prune(struct Curl_easy *data)
 
     /* if the cache size is still too big, use the oldest age as new
        prune limit */
-  } while(timeout && (data->dns.hostcache->size > MAX_DNS_CACHE_SIZE));
+  } while(timeout &&
+          (Curl_hash_count(data->dns.hostcache) > MAX_DNS_CACHE_SIZE));
 
   if(data->share)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -299,10 +300,10 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
     struct hostcache_prune_data user;
 
     user.now = time(NULL);
-    user.cache_timeout = data->set.dns_cache_timeout;
+    user.max_age_sec = data->set.dns_cache_timeout;
     user.oldest = 0;
 
-    if(hostcache_timestamp_remove(&user, dns)) {
+    if(hostcache_entry_is_stale(&user, dns)) {
       infof(data, "Hostname in DNS cache was stale, zapped");
       dns = NULL; /* the memory deallocation is being handled by the hash */
       Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
@@ -348,7 +349,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
  *
  * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
  *
- * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * The returned data *MUST* be "released" with Curl_resolv_unlink() after
  * use, or we will leak memory!
  */
 struct Curl_dns_entry *
@@ -364,7 +365,7 @@ Curl_fetch_addr(struct Curl_easy *data,
   dns = fetch_addr(data, hostname, port);
 
   if(dns)
-    dns->inuse++; /* we use it! */
+    dns->refcount++; /* we use it! */
 
   if(data->share)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -468,7 +469,8 @@ Curl_cache_addr(struct Curl_easy *data,
                 struct Curl_addrinfo *addr,
                 const char *hostname,
                 size_t hostlen, /* length or zero */
-                int port)
+                int port,
+                bool permanent)
 {
   char entry_id[MAX_HOSTCACHE_LEN];
   size_t entry_len;
@@ -496,11 +498,15 @@ Curl_cache_addr(struct Curl_easy *data,
   entry_len = create_hostcache_id(hostname, hostlen, port,
                                   entry_id, sizeof(entry_id));
 
-  dns->inuse = 1;   /* the cache has the first reference */
+  dns->refcount = 1; /* the cache has the first reference */
   dns->addr = addr; /* this is the address(es) */
-  time(&dns->timestamp);
-  if(dns->timestamp == 0)
-    dns->timestamp = 1;   /* zero indicates permanent CURLOPT_RESOLVE entry */
+  if(permanent)
+    dns->timestamp = 0; /* an entry that never goes stale */
+  else {
+    dns->timestamp = time(NULL);
+    if(dns->timestamp == 0)
+      dns->timestamp = 1;
+  }
   dns->hostport = port;
   if(hostlen)
     memcpy(dns->hostname, hostname, hostlen);
@@ -514,7 +520,7 @@ Curl_cache_addr(struct Curl_easy *data,
   }
 
   dns = dns2;
-  dns->inuse++;         /* mark entry as in-use */
+  dns->refcount++;         /* mark entry as in-use */
   return dns;
 }
 
@@ -666,8 +672,8 @@ static bool tailmatch(const char *full, const char *part)
  * resolves. See the return codes.
  *
  * The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlock() later (when you are
- * done using this struct) to decrease the counter again.
+ * function is used. You MUST call Curl_resolv_unlink() later (when you are
+ * done using this struct) to decrease the reference counter again.
  *
  * Return codes:
  *
@@ -708,7 +714,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
 
   if(dns) {
     infof(data, "Hostname %s was found in DNS cache", hostname);
-    dns->inuse++; /* we use it! */
+    dns->refcount++; /* we use it! */
     rc = CURLRESOLV_RESOLVED;
   }
 
@@ -828,7 +834,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
       /* we got a response, store it in the cache */
-      dns = Curl_cache_addr(data, addr, hostname, 0, port);
+      dns = Curl_cache_addr(data, addr, hostname, 0, port, FALSE);
 
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -868,8 +874,8 @@ void alarmfunc(int sig)
  * resolves. See the return codes.
  *
  * The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlock() later (when you are
- * done using this struct) to decrease the counter again.
+ * function is used. You MUST call Curl_resolv_unlink() later (when you are
+ * done using this struct) to decrease the reference counter again.
  *
  * If built with a synchronous resolver and use of signals is not
  * disabled by the application, then a nonzero timeout will cause a
@@ -955,7 +961,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
     keep_copysig = TRUE; /* yes, we have a copy */
     sigact.sa_handler = alarmfunc;
 #ifdef SA_RESTART
-    /* HPUX does not have SA_RESTART but defaults to that behavior! */
+    /* HP-UX does not have SA_RESTART but defaults to that behavior! */
     sigact.sa_flags &= ~SA_RESTART;
 #endif
     /* now set the new struct */
@@ -1037,18 +1043,20 @@ clean_up:
 }
 
 /*
- * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
- * made, the struct may be destroyed due to pruning. It is important that only
- * one unlock is made for each Curl_resolv() call.
+ * Curl_resolv_unlink() releases a reference to the given cached DNS entry.
+ * When the reference count reaches 0, the entry is destroyed. It is important
+ * that only one unlink is made for each Curl_resolv() call.
  *
  * May be called with 'data' == NULL for global cache.
  */
-void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
+void Curl_resolv_unlink(struct Curl_easy *data, struct Curl_dns_entry **pdns)
 {
+  struct Curl_dns_entry *dns = *pdns;
+  *pdns = NULL;
   if(data && data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-  freednsentry(dns);
+  hostcache_unlink_entry(dns);
 
   if(data && data->share)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1057,13 +1065,13 @@ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
 /*
  * File-internal: release cache dns entry reference, free if inuse drops to 0
  */
-static void freednsentry(void *freethis)
+static void hostcache_unlink_entry(void *entry)
 {
-  struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
-  DEBUGASSERT(dns && (dns->inuse>0));
+  struct Curl_dns_entry *dns = (struct Curl_dns_entry *) entry;
+  DEBUGASSERT(dns && (dns->refcount>0));
 
-  dns->inuse--;
-  if(dns->inuse == 0) {
+  dns->refcount--;
+  if(dns->refcount == 0) {
     Curl_freeaddrinfo(dns->addr);
 #ifdef USE_HTTPSRR
     if(dns->hinfo) {
@@ -1092,7 +1100,7 @@ static void freednsentry(void *freethis)
 void Curl_init_dnscache(struct Curl_hash *hash, size_t size)
 {
   Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare,
-                 freednsentry);
+                 hostcache_unlink_entry);
 }
 
 /*
@@ -1285,13 +1293,11 @@ err:
       }
 
       /* put this new host in the cache */
-      dns = Curl_cache_addr(data, head, host_begin, hlen, port);
+      dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent);
       if(dns) {
-        if(permanent)
-          dns->timestamp = 0; /* mark as permanent */
         /* release the returned reference; the cache itself will keep the
          * entry alive: */
-        dns->inuse--;
+        dns->refcount--;
       }
 
       if(data->share)
@@ -1443,8 +1449,7 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
 
   if(result) {
     Curl_detach_connection(data);
-    Curl_conncache_remove_conn(data, conn, TRUE);
-    Curl_disconnect(data, conn, TRUE);
+    Curl_cpool_disconnect(data, conn, TRUE);
   }
   return result;
 }

部分文件因为文件数量过多而无法显示