curl 2026-09-02 (01346829)

Code extracted from:

    https://github.com/curl/curl.git

at commit 01346829096c61b372692f6dc43ffa778c6caccd (curl-8_22_0).
This commit is contained in:
Curl Upstream
2026-09-02 17:14:26 -04:00
committed by Brad King
parent ecbccb29a7
commit 6da4dcc009
263 changed files with 13213 additions and 8761 deletions
+33 -44
View File
@@ -48,7 +48,7 @@ int main(void)
{
/* O_NONBLOCK source test */
int flags = 0;
if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
if(fcntl(0, F_SETFL, flags | O_NONBLOCK))
return 1;
return 0;
}
@@ -65,7 +65,7 @@ int main(void)
#include <netdb.h>
int main(void)
{
const char *address = "example.com";
static const char address[] = "localhost";
struct hostent h;
int rc = 0;
#if defined(HAVE_GETHOSTBYNAME_R_3) || \
@@ -114,17 +114,6 @@ int main(void)
}
#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
int main(void)
{
return 0;
}
#endif
#ifdef HAVE_FILE_OFFSET_BITS
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
@@ -144,7 +133,7 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET
#ifdef _WIN32
# include <winsock2.h>
#include <winsock2.h>
#endif
int main(void)
{
@@ -162,7 +151,7 @@ int main(void)
int main(void)
{
/* IoctlSocket source code */
if(0 != IoctlSocket(0, 0, 0))
if(IoctlSocket(0, 0, 0))
return 1;
return 0;
}
@@ -171,13 +160,13 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
#include <proto/bsdsocket.h>
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#include <sys/ioctl.h>
#endif
int main(void)
{
/* IoctlSocket source code */
long flags = 0;
if(0 != IoctlSocket(0, FIONBIO, &flags))
if(IoctlSocket(0, FIONBIO, &flags))
return 1;
(void)flags;
return 0;
@@ -186,12 +175,12 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET_FIONBIO
#ifdef _WIN32
# include <winsock2.h>
#include <winsock2.h>
#endif
int main(void)
{
unsigned long flags = 0;
if(0 != ioctlsocket(0, FIONBIO, &flags))
if(ioctlsocket(0, FIONBIO, &flags))
return 1;
(void)flags;
return 0;
@@ -201,24 +190,24 @@ int main(void)
#ifdef HAVE_IOCTL_FIONBIO
/* headers for FIONBIO test */
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#include <unistd.h>
#endif
#ifndef _WIN32
# include <sys/socket.h>
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#include <sys/ioctl.h>
#endif
#ifdef HAVE_STROPTS_H
# include <stropts.h>
#include <stropts.h>
#endif
int main(void)
{
int flags = 0;
if(0 != ioctl(0, FIONBIO, &flags))
if(ioctl(0, FIONBIO, &flags))
return 1;
(void)flags;
return 0;
@@ -226,27 +215,27 @@ int main(void)
#endif
#ifdef HAVE_IOCTL_SIOCGIFADDR
/* headers for FIONBIO test */
/* headers for SIOCGIFADDR test */
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#include <unistd.h>
#endif
#ifndef _WIN32
# include <sys/socket.h>
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#include <sys/ioctl.h>
#endif
#ifdef HAVE_STROPTS_H
# include <stropts.h>
#include <stropts.h>
#endif
#include <net/if.h>
int main(void)
{
struct ifreq ifr;
if(0 != ioctl(0, SIOCGIFADDR, &ifr))
if(ioctl(0, SIOCGIFADDR, &ifr))
return 1;
(void)ifr;
return 0;
@@ -255,17 +244,17 @@ int main(void)
#ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
#ifdef _WIN32
# include <winsock2.h>
#include <winsock2.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#include <sys/types.h>
#endif
#ifndef _WIN32
# include <sys/socket.h>
#include <sys/socket.h>
#endif
int main(void)
{
if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
if(setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
return 1;
return 0;
}
@@ -349,13 +338,13 @@ int main(void)
#ifdef HAVE_ATOMIC
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#include <unistd.h>
#endif
#ifdef HAVE_STDATOMIC_H
# include <stdatomic.h>
#include <stdatomic.h>
#endif
int main(void)
{
@@ -367,10 +356,10 @@ int main(void)
#ifdef HAVE_WIN32_WINNT
#ifdef _WIN32
# ifndef NOGDI
# define NOGDI
# endif
# include <windows.h>
#ifndef NOGDI
#define NOGDI
#endif
#include <windows.h>
#endif
#define enquote(x) #x
@@ -385,7 +374,7 @@ int main(void)
#ifdef MINGW64_VERSION
#ifdef __MINGW32__
# include <_mingw.h>
#include <_mingw.h>
#endif
#define enquote(x) #x
+135 -117
View File
@@ -23,6 +23,10 @@
###########################################################################
# Find the GSS Kerberos library
#
# This module accepts optional COMPONENTS to control the GSS library flavor:
#
# - Apple
#
# Input variables:
#
# - `GSS_ROOT_DIR`: Absolute path to the root installation of GSS. (also supported as environment)
@@ -32,7 +36,7 @@
# - `GSS_FOUND`: System has GSS.
# - `GSS_VERSION`: Version of GSS.
# - `CURL::gss`: GSS library target.
# - `INTERFACE_CURL_GSS_FLAVOR`: Custom property. "GNU" or "MIT" if detected.
# - `INTERFACE_CURL_GSS_FLAVOR`: Custom property. "Apple", "GNU" or "MIT" if detected.
set(_gnu_modname "gss")
set(_mit_modname "mit-krb5-gssapi")
@@ -46,8 +50,12 @@ set(_gss_root_hints "${GSS_ROOT_DIR}" "$ENV{GSS_ROOT_DIR}")
set(_gss_CFLAGS "")
set(_gss_LIBRARY_DIRS "")
if(NOT APPLE AND GSS_FIND_COMPONENTS STREQUAL "Apple")
set(GSS_FIND_COMPONENTS "")
endif()
# 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(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}" AND NOT GSS_FIND_COMPONENTS STREQUAL "Apple")
if(CURL_USE_PKGCONFIG)
find_package(PkgConfig QUIET)
pkg_search_module(_gss ${_mit_modname} ${_gnu_modname})
@@ -60,136 +68,146 @@ if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
endif()
if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional approach.
find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin" HINTS ${_gss_root_hints}
NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
# If not found in user-supplied directories, maybe system knows better
find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin")
if(GSS_FIND_COMPONENTS STREQUAL "Apple")
find_path(_gss_INCLUDE_DIRS NAMES "GSS/gssapi.h" PATH_SUFFIXES "include")
find_library(_gss_LIBRARIES NAMES "GSS")
if(_gss_configure_script)
set(_gss_INCLUDE_DIRS "")
set(_gss_LIBRARIES "")
execute_process(COMMAND ${_gss_configure_script} "--cflags" "gssapi"
OUTPUT_VARIABLE _gss_cflags_raw
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "FindGSS krb5-config --cflags: ${_gss_cflags_raw}")
if(NOT _gss_configure_failed) # 0 means success
# Should also work in an odd case when multiple directories are given.
string(STRIP "${_gss_cflags_raw}" _gss_cflags_raw)
string(REGEX REPLACE " +-(I)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
foreach(_flag IN LISTS _gss_cflags_raw)
if(_flag MATCHES "^-I")
string(REGEX REPLACE "^-I" "" _flag "${_flag}")
list(APPEND _gss_INCLUDE_DIRS "${_flag}")
else()
list(APPEND _gss_CFLAGS "${_flag}")
endif()
endforeach()
if(_gss_INCLUDE_DIRS AND _gss_LIBRARIES)
message(STATUS "Found AppleGSS: ${_gss_INCLUDE_DIRS}")
set(_gss_flavor "Apple")
endif()
else()
find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin" HINTS ${_gss_root_hints}
NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
# If not found in user-supplied directories, maybe system knows better
find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin")
execute_process(COMMAND ${_gss_configure_script} "--libs" "gssapi"
OUTPUT_VARIABLE _gss_lib_flags
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
if(_gss_configure_script)
if(NOT _gss_configure_failed) # 0 means success
# This script gives us libraries and link directories.
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}")
set(_gss_INCLUDE_DIRS "")
set(_gss_LIBRARIES "")
foreach(_flag IN LISTS _gss_lib_flags)
if(_flag MATCHES "^-l")
string(REGEX REPLACE "^-l" "" _flag "${_flag}")
list(APPEND _gss_LIBRARIES "${_flag}")
elseif(_flag MATCHES "^-L")
string(REGEX REPLACE "^-L" "" _flag "${_flag}")
list(APPEND _gss_LIBRARY_DIRS "${_flag}")
endif()
endforeach()
endif()
execute_process(COMMAND ${_gss_configure_script} "--cflags" "gssapi"
OUTPUT_VARIABLE _gss_cflags_raw
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "FindGSS krb5-config --cflags: ${_gss_cflags_raw}")
execute_process(COMMAND ${_gss_configure_script} "--version"
OUTPUT_VARIABLE _gss_version
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _gss_configure_failed) # 0 means success
# Should also work in an odd case when multiple directories are given.
string(STRIP "${_gss_cflags_raw}" _gss_cflags_raw)
string(REGEX REPLACE " +-(I)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
# Older versions may not have the "--version" parameter. In this case we do not care.
if(_gss_configure_failed)
set(_gss_version 0)
else()
# Strip prefix string to leave the version number only
string(REPLACE "Kerberos 5 release " "" _gss_version "${_gss_version}")
endif()
execute_process(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 do not care.
if(NOT _gss_configure_failed AND NOT _gss_vendor MATCHES "Heimdal|heimdal")
set(_gss_flavor "MIT") # assume a default, should not really matter
endif()
else() # Either there is no config script or we are on a platform that does not provide one (Windows?)
find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc")
if(_gss_INCLUDE_DIRS) # We have found something
set(_gss_libdir_suffixes "")
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}")
check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
cmake_pop_check_state()
if(_gss_have_mit_headers)
set(_gss_flavor "MIT")
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND _gss_libdir_suffixes "lib/AMD64")
set(_gss_libname "gssapi64")
foreach(_flag IN LISTS _gss_cflags_raw)
if(_flag MATCHES "^-I")
string(REGEX REPLACE "^-I" "" _flag "${_flag}")
list(APPEND _gss_INCLUDE_DIRS "${_flag}")
else()
list(APPEND _gss_libdir_suffixes "lib/i386")
set(_gss_libname "gssapi32")
list(APPEND _gss_CFLAGS "${_flag}")
endif()
else()
list(APPEND _gss_libdir_suffixes "lib" "lib64") # those suffixes are not checked for HINTS
set(_gss_libname "gssapi_krb5")
endforeach()
endif()
execute_process(COMMAND ${_gss_configure_script} "--libs" "gssapi"
OUTPUT_VARIABLE _gss_lib_flags
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
if(NOT _gss_configure_failed) # 0 means success
# This script gives us libraries and link directories.
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 IN LISTS _gss_lib_flags)
if(_flag MATCHES "^-l")
string(REGEX REPLACE "^-l" "" _flag "${_flag}")
list(APPEND _gss_LIBRARIES "${_flag}")
elseif(_flag MATCHES "^-L")
string(REGEX REPLACE "^-L" "" _flag "${_flag}")
list(APPEND _gss_LIBRARY_DIRS "${_flag}")
endif()
endforeach()
endif()
execute_process(COMMAND ${_gss_configure_script} "--version"
OUTPUT_VARIABLE _gss_version
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Older versions may not have the "--version" parameter. In this case we do not care.
if(_gss_configure_failed)
set(_gss_version 0)
else()
# Strip prefix string to leave the version number only
string(REPLACE "Kerberos 5 release " "" _gss_version "${_gss_version}")
endif()
execute_process(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 do not care.
if(NOT _gss_configure_failed AND NOT _gss_vendor MATCHES "Heimdal|heimdal")
set(_gss_flavor "MIT") # assume a default, should not really matter
endif()
else() # Either there is no config script or we are on a platform that does not provide one (Windows?)
find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc")
if(_gss_INCLUDE_DIRS) # We have found something
set(_gss_libdir_suffixes "")
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}")
check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
cmake_pop_check_state()
if(_gss_have_mit_headers)
set(_gss_flavor "MIT")
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND _gss_libdir_suffixes "lib/AMD64")
set(_gss_libname "gssapi64")
else()
list(APPEND _gss_libdir_suffixes "lib/i386")
set(_gss_libname "gssapi32")
endif()
else()
list(APPEND _gss_libdir_suffixes "lib" "lib64") # those suffixes are not checked for HINTS
set(_gss_libname "gssapi_krb5")
endif()
endif()
else()
find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include")
if(_gss_INCLUDE_DIRS)
set(_gss_flavor "GNU")
set(_gss_pc_requires ${_gnu_modname})
set(_gss_libname "gss")
endif()
endif()
else()
find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include")
if(_gss_INCLUDE_DIRS)
set(_gss_flavor "GNU")
set(_gss_pc_requires ${_gnu_modname})
set(_gss_libname "gss")
# If we have headers, look up libraries
if(_gss_flavor)
set(_gss_libdir_hints ${_gss_root_hints})
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root)
else()
get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY)
endif()
list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes})
endif()
endif()
# If we have headers, look up libraries
if(_gss_flavor)
set(_gss_libdir_hints ${_gss_root_hints})
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root)
else()
get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY)
endif()
list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes})
endif()
endif()
if(NOT _gss_flavor)
message(FATAL_ERROR "GNU or MIT GSS is required")
message(FATAL_ERROR "MIT, GNU or Apple GSS is required")
endif()
else()
if(_gss_MODULE_NAME STREQUAL _gnu_modname)
@@ -199,7 +217,7 @@ else()
set(_gss_flavor "MIT")
set(_gss_pc_requires ${_mit_modname})
else()
message(FATAL_ERROR "GNU or MIT GSS is required")
message(FATAL_ERROR "MIT, GNU or Apple GSS is required")
endif()
message(STATUS "Found GSS/${_gss_flavor} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")")
endif()
+1
View File
@@ -46,6 +46,7 @@ endif()
if(_libgsasl_FOUND)
set(Libgsasl_FOUND TRUE)
set(LIBGSASL_FOUND TRUE)
set(LIBGSASL_VERSION ${_libgsasl_VERSION})
message(STATUS "Found Libgsasl (via pkg-config): ${_libgsasl_INCLUDE_DIRS} (found version \"${LIBGSASL_VERSION}\")")
else()
find_path(LIBGSASL_INCLUDE_DIR NAMES "gsasl.h")
+13 -9
View File
@@ -25,19 +25,21 @@
#
# Input variables:
#
# - `NETTLE_INCLUDE_DIR`: Absolute path to nettle include directory.
# - `NETTLE_LIBRARY`: Absolute path to `nettle` library.
# - `NETTLE_INCLUDE_DIR`: Absolute path to nettle include directory.
# - `NETTLE_HOGWEED_LIBRARY`: Absolute path to `hogweed` library.
# - `NETTLE_LIBRARY`: Absolute path to `nettle` library.
#
# Defines:
#
# - `NETTLE_FOUND`: System has nettle.
# - `NETTLE_VERSION`: Version of nettle.
# - `CURL::nettle`: nettle library target.
# - `NETTLE_FOUND`: System has nettle.
# - `NETTLE_VERSION`: Version of nettle.
# - `CURL::nettle`: nettle library target.
set(_nettle_pc_requires "nettle")
set(_nettle_pc_requires "hogweed" "nettle")
if(CURL_USE_PKGCONFIG AND
NOT DEFINED NETTLE_INCLUDE_DIR AND
NOT DEFINED NETTLE_HOGWEED_LIBRARY AND
NOT DEFINED NETTLE_LIBRARY)
find_package(PkgConfig QUIET)
pkg_check_modules(_nettle ${_nettle_pc_requires})
@@ -46,10 +48,11 @@ endif()
if(_nettle_FOUND)
set(Nettle_FOUND TRUE)
set(NETTLE_FOUND TRUE)
set(NETTLE_VERSION ${_nettle_VERSION})
set(NETTLE_VERSION ${_nettle_nettle_VERSION})
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_HOGWEED_LIBRARY NAMES "hogweed")
find_library(NETTLE_LIBRARY NAMES "nettle")
unset(NETTLE_VERSION CACHE)
@@ -71,6 +74,7 @@ else()
find_package_handle_standard_args(Nettle
REQUIRED_VARS
NETTLE_INCLUDE_DIR
NETTLE_HOGWEED_LIBRARY
NETTLE_LIBRARY
VERSION_VAR
NETTLE_VERSION
@@ -78,10 +82,10 @@ else()
if(NETTLE_FOUND)
set(_nettle_INCLUDE_DIRS ${NETTLE_INCLUDE_DIR})
set(_nettle_LIBRARIES ${NETTLE_LIBRARY})
set(_nettle_LIBRARIES ${NETTLE_HOGWEED_LIBRARY} ${NETTLE_LIBRARY})
endif()
mark_as_advanced(NETTLE_INCLUDE_DIR NETTLE_LIBRARY)
mark_as_advanced(NETTLE_INCLUDE_DIR NETTLE_HOGWEED_LIBRARY NETTLE_LIBRARY)
endif()
if(NETTLE_FOUND)
+2 -2
View File
@@ -54,7 +54,7 @@ if(NOT DEFINED ZSTD_INCLUDE_DIR AND
endif()
if(NOT _zstd_FOUND AND CURL_USE_CMAKECONFIG)
find_package(zstd CONFIG QUIET)
# Skip using if older than v1.4.5
# Only use if 1.4.5 or greater
if(zstd_CONFIG AND
NOT TARGET zstd::libzstd_static AND
NOT TARGET zstd::libzstd_shared)
@@ -81,7 +81,7 @@ elseif(zstd_CONFIG)
if(ZSTD_USE_STATIC_LIBS)
set(_zstd_LIBRARIES zstd::libzstd_static)
elseif(TARGET zstd::libzstd)
set(_zstd_LIBRARIES zstd::libzstd) # v1.5.6+
set(_zstd_LIBRARIES zstd::libzstd) # 1.5.6+
else()
set(_zstd_LIBRARIES zstd::libzstd_shared)
endif()
+2 -2
View File
@@ -43,7 +43,7 @@ macro(curl_internal_test _curl_test)
message(STATUS "Performing Test ${_curl_test}")
try_compile(${_curl_test}
${PROJECT_BINARY_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c"
"${PROJECT_SOURCE_DIR}/CMake/CurlTests.c"
COMPILE_DEFINITIONS "-D${_curl_test}" ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS} ${CMAKE_REQUIRED_DEFINITIONS}
LINK_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}"
OUTPUT_VARIABLE CURL_TEST_OUTPUT)
@@ -255,7 +255,7 @@ macro(curl_collect_target_link_options _target)
get_target_property(_val ${_target} IMPORTED)
if(_val)
# LOCATION is empty for interface library targets and safe to ignore.
# Explicitly skip this query to avoid CMake v3.18 and older erroring out.
# Explicitly skip this query to avoid CMake 3.18 and older erroring out.
get_target_property(_val ${_target} TYPE)
if(NOT "${_val}" STREQUAL "INTERFACE_LIBRARY")
get_target_property(_val ${_target} LOCATION)
+8 -6
View File
@@ -77,12 +77,14 @@ if(WIN32)
set(HAVE_GETADDRINFO_THREADSAFE ${HAVE_GETADDRINFO})
elseif(NOT HAVE_GETADDRINFO)
set(HAVE_GETADDRINFO_THREADSAFE FALSE)
elseif(APPLE OR
AIX OR CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "HP-UX" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
elseif(APPLE OR # Darwin 9+ / macOS 10.5+
AIX OR CMAKE_SYSTEM_NAME STREQUAL "AIX" OR # 5.2+
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR # 2.2.0+
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR # 5.5+
CMAKE_SYSTEM_NAME STREQUAL "HP-UX" OR # 11.11+
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR # all versions
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR # 4+
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR # 5.4+
CMAKE_SYSTEM_NAME STREQUAL "SunOS")
set(HAVE_GETADDRINFO_THREADSAFE TRUE)
elseif(BSD OR CMAKE_SYSTEM_NAME MATCHES "BSD")
+5 -2
View File
@@ -97,7 +97,7 @@ if(PICKY_COMPILER)
# to suppress undesired warnings in case -Weverything is passed as a custom option.
# Assume these options always exist with both clang and gcc.
# Require clang 3.0 / gcc 2.95 or later.
# Require clang 3.0 / gcc 2.95 or greater.
list(APPEND _picky_enable
-Wbad-function-cast # clang 2.7 gcc 2.95
-Wconversion # clang 2.7 gcc 2.95
@@ -215,7 +215,7 @@ if(PICKY_COMPILER)
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12))
list(APPEND _picky_enable
-Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 # We do silencing for clang 10.0 and above only
-Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 # We do silencing for clang 10.0+ only
-Wxor-used-as-pow # clang 10.0 gcc 13.0 appleclang 12.0
)
endif()
@@ -451,6 +451,9 @@ if(_picky_nocheck OR _picky)
string(REPLACE ";" " " _picky_tmp "${_picky_tmp}")
string(STRIP "${_picky_tmp}" _picky_tmp)
message(STATUS "Picky compiler options: ${_picky_tmp}")
if(_CURL_SAVE_PICKY_OPTIONS)
file(WRITE "${PROJECT_BINARY_DIR}/picky-options.txt" "${_picky_tmp}")
endif()
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "${_picky_nocheck}" "${_picky}")
# Apply to all feature checks
+23 -16
View File
@@ -37,24 +37,30 @@ endfunction()
# Dump all defined variables with their values
function(curl_dumpvars)
message("::group::CMake Variable Dump")
get_cmake_property(_vars VARIABLES)
foreach(_var IN ITEMS ${_vars})
get_property(_var_type CACHE ${_var} PROPERTY TYPE)
get_property(_var_advanced CACHE ${_var} PROPERTY ADVANCED)
if(_var_type)
set(_var_type ":${_var_type}")
endif()
if(_var_advanced)
set(_var_advanced " [adv]")
endif()
message("${_var}${_var_type}${_var_advanced} = '${${_var}}'")
endforeach()
if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.5)
cmake_language(PRINT_VARIABLES ALL)
else()
get_cmake_property(_vars VARIABLES)
foreach(_var IN ITEMS ${_vars})
get_property(_var_type CACHE ${_var} PROPERTY TYPE)
get_property(_var_advanced CACHE ${_var} PROPERTY ADVANCED)
if(_var_type)
set(_var_type ":${_var_type}")
endif()
if(_var_advanced)
set(_var_advanced " [adv]")
endif()
message(" ${_var}${_var_type}${_var_advanced} = \"${${_var}}\"")
endforeach()
endif()
message("::endgroup::")
endfunction()
# Dump all target properties
function(curl_dumptargetprops _target)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND TARGET "${_target}")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.5)
cmake_language(PRINT_PROPERTIES TARGETS "${_target}" ALL)
elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND TARGET "${_target}")
execute_process(COMMAND "${CMAKE_COMMAND}" "--help-property-list" OUTPUT_VARIABLE _cmake_property_list)
string(REPLACE "\n" ";" _cmake_property_list "${_cmake_property_list}")
list(REMOVE_DUPLICATES _cmake_property_list)
@@ -64,21 +70,22 @@ function(curl_dumptargetprops _target)
if(NOT _target_imported)
list(REMOVE_ITEM _cmake_property_list "LOCATION" "LOCATION_<CONFIG>" "MACOSX_PACKAGE_LOCATION" "VS_DEPLOYMENT_LOCATION")
endif()
list(SORT _cmake_property_list)
foreach(_prop IN LISTS _cmake_property_list)
if(_prop MATCHES "<CONFIG>")
foreach(_config IN ITEMS "DEBUG" "RELEASE" "MINSIZEREL" "RELWITHDEBINFO")
foreach(_config IN ITEMS "DEBUG" "MINSIZEREL" "RELEASE" "RELWITHDEBINFO")
string(REPLACE "<CONFIG>" "${_config}" _propconfig "${_prop}")
get_property(_is_set TARGET "${_target}" PROPERTY "${_propconfig}" SET)
if(_is_set)
get_target_property(_val "${_target}" "${_propconfig}")
message("${_target}.${_propconfig} = '${_val}'")
message(" ${_target}.${_propconfig} = \"${_val}\"")
endif()
endforeach()
else()
get_property(_is_set TARGET "${_target}" PROPERTY "${_prop}" SET)
if(_is_set)
get_target_property(_val "${_target}" "${_prop}")
message("${_target}.${_prop} = '${_val}'")
message(" ${_target}.${_prop} = \"${_val}\"")
endif()
endif()
endforeach()
+16 -18
View File
@@ -21,30 +21,28 @@
# SPDX-License-Identifier: curl
#
###########################################################################
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
set(_manifest "@PROJECT_BINARY_DIR@/install_manifest.txt")
if(NOT EXISTS "${_manifest}")
message(FATAL_ERROR "Cannot find install manifest: ${_manifest}")
endif()
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@")
set(_destdir "$ENV{DESTDIR}")
if(NOT _destdir STREQUAL "")
message(STATUS "DESTDIR environment: ${_destdir}")
endif()
message(${CMAKE_INSTALL_PREFIX})
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" _files)
file(READ "${_manifest}" _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}")
execute_process(
COMMAND "@CMAKE_COMMAND@" -E remove "$ENV{DESTDIR}${_file}"
RESULT_VARIABLE rm_retval
OUTPUT_QUIET
ERROR_QUIET
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${_file}")
foreach(_file IN LISTS _files)
set(_target "${_destdir}${_file}")
if(IS_SYMLINK "${_target}" OR EXISTS "${_target}")
file(REMOVE "${_target}")
if(IS_SYMLINK "${_target}" OR EXISTS "${_target}")
message(STATUS "Failed to delete: ${_target}")
else()
message(STATUS "Uninstalled: ${_target}")
endif()
else()
message(STATUS "File $ENV{DESTDIR}${_file} does not exist.")
message(STATUS "File does not exist: ${_target}")
endif()
endforeach()
+2 -2
View File
@@ -30,7 +30,7 @@ option(CURL_USE_PKGCONFIG "Enable pkg-config to detect @PROJECT_NAME@ dependenci
if(CMAKE_VERSION VERSION_LESS @CMAKE_MINIMUM_REQUIRED_VERSION@)
message(STATUS "@PROJECT_NAME@: @PROJECT_NAME@-specific Find modules require "
"CMake @CMAKE_MINIMUM_REQUIRED_VERSION@ or upper, found: ${CMAKE_VERSION}.")
"CMake @CMAKE_MINIMUM_REQUIRED_VERSION@ or greater, found: ${CMAKE_VERSION}.")
endif()
include(CMakeFindDependencyMacro)
@@ -74,7 +74,7 @@ if("@USE_ARES@")
list(APPEND _curl_libs CURL::cares)
endif()
if("@HAVE_GSSAPI@")
find_dependency(GSS MODULE)
find_dependency(GSS MODULE COMPONENTS "@GSS_FLAVOR@")
list(APPEND _curl_libs CURL::gss)
endif()
if("@USE_BACKTRACE@")
+8 -22
View File
@@ -73,9 +73,9 @@ if(ANDROID AND ANDROID_PLATFORM_LEVEL GREATER_EQUAL 34)
set(HAVE_MEMSET_EXPLICIT 1)
endif()
if((APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.9) OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR # v6+
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR # v11.2+
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") # v1.3+
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR # 6+
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR # 11.2+
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") # 1.3+
set(HAVE_MEMSET_S 1)
elseif(NOT APPLE)
set(HAVE_MEMSET_S 0)
@@ -106,14 +106,7 @@ elseif(CYGWIN OR
set(HAVE_FSETXATTR_6 0)
endif()
set(HAVE_GETADDRINFO 1)
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_GETADDRINFO_THREADSAFE 0)
elseif(CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
if(CYGWIN)
set(HAVE_GETADDRINFO_THREADSAFE 1)
endif()
set(HAVE_GETEUID 1)
@@ -134,6 +127,7 @@ set(HAVE_GETHOSTBYNAME_R_5 0)
set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
set(HAVE_GETHOSTBYNAME_R_6 1)
set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 1)
@@ -173,8 +167,6 @@ endif()
set(HAVE_GMTIME_R 1)
set(HAVE_IFADDRS_H 1)
set(HAVE_IF_NAMETOINDEX 1)
set(HAVE_INET_NTOP 1)
set(HAVE_INET_PTON 1)
set(HAVE_IOCTLSOCKET 0)
set(HAVE_IOCTLSOCKET_CAMEL 0)
set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
@@ -210,6 +202,7 @@ else()
set(HAVE_NETINET_IN6_H 0)
endif()
set(HAVE_NETINET_IN_H 1)
set(HAVE_NETINET_IP_H 1)
set(HAVE_NETINET_TCP_H 1)
set(HAVE_NETINET_UDP_H 1)
set(HAVE_NET_IF_H 1)
@@ -219,12 +212,7 @@ if(APPLE OR
CYGWIN)
set(HAVE_PIPE2 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
BSD OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
BSD OR CMAKE_SYSTEM_NAME MATCHES "BSD" OR
CMAKE_SYSTEM_NAME STREQUAL "SunOS")
set(HAVE_PIPE2 1)
endif()
@@ -240,7 +228,6 @@ set(HAVE_REALPATH 1)
set(HAVE_RECV 1)
set(HAVE_SA_FAMILY_T 1)
set(HAVE_SCHED_YIELD 1)
set(HAVE_SELECT 1)
set(HAVE_SEND 1)
if(APPLE OR
CYGWIN OR
@@ -273,7 +260,7 @@ set(HAVE_STRINGS_H 1)
if(_CURL_OLD_LINUX)
set(HAVE_STROPTS_H 1)
else()
set(HAVE_STROPTS_H 0) # glibc 2.30 or newer. https://sourceware.org/legacy-ml/libc-alpha/2019-08/msg00029.html
set(HAVE_STROPTS_H 0) # glibc 2.30 or greater. https://sourceware.org/legacy-ml/libc-alpha/2019-08/msg00029.html
endif()
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
set(HAVE_STRUCT_TIMEVAL 1)
@@ -328,5 +315,4 @@ set(HAVE_UTIME 1)
set(HAVE_UTIMES 1)
set(HAVE_UTIME_H 1)
set(HAVE_WRITABLE_ARGV 1)
set(STDC_HEADERS 1)
set(USE_UNIX_SOCKETS 1)
+5 -13
View File
@@ -28,10 +28,7 @@ endif()
if(MINGW)
set(HAVE_BASENAME 1)
set(HAVE_BOOL_T 1) # = HAVE_STDBOOL_H
set(HAVE_DIRENT_H 1)
set(HAVE_GETTIMEOFDAY 1)
set(HAVE_LIBGEN_H 1)
set(HAVE_OPENDIR 1)
set(HAVE_STDBOOL_H 1)
set(HAVE_STDDEF_H 1) # detected by CMake internally in check_type_size()
set(HAVE_STDINT_H 1) # detected by CMake internally in check_type_size()
@@ -40,24 +37,22 @@ if(MINGW)
set(HAVE_UNISTD_H 1)
set(HAVE_UTIME_H 1) # wrapper to sys/utime.h
else()
set(HAVE_DIRENT_H 0)
set(HAVE_GETTIMEOFDAY 0)
set(HAVE_LIBGEN_H 0)
set(HAVE_OPENDIR 0)
set(HAVE_STRINGS_H 0)
set(HAVE_SYS_PARAM_H 0)
set(HAVE_UTIME_H 0)
if(MSVC)
set(HAVE_UNISTD_H 0)
set(HAVE_BASENAME 0)
set(HAVE_STDDEF_H 1) # detected by CMake internally in check_type_size()
set(HAVE_STDINT_H 1) # detected by CMake internally in check_type_size()
if(MSVC_VERSION GREATER_EQUAL 1800)
set(HAVE_BOOL_T 1) # = HAVE_STDBOOL_H
set(HAVE_STDBOOL_H 1)
else()
set(HAVE_BOOL_T 0) # = HAVE_STDBOOL_H
set(HAVE_STDBOOL_H 0)
endif()
set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
set(HAVE_BASENAME 0)
set(HAVE_UNISTD_H 0)
endif()
endif()
@@ -104,8 +99,6 @@ set(HAVE_GETSOCKNAME 1)
set(HAVE_GLIBC_STRERROR_R 0)
set(HAVE_GMTIME_R 0)
set(HAVE_IFADDRS_H 0)
set(HAVE_INET_NTOP 0)
set(HAVE_INET_PTON 0)
set(HAVE_IOCTLSOCKET 1)
set(HAVE_IOCTLSOCKET_CAMEL 0)
set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
@@ -120,6 +113,7 @@ set(HAVE_MEMRCHR 0)
set(HAVE_NETDB_H 0)
set(HAVE_NETINET_IN6_H 0)
set(HAVE_NETINET_IN_H 0)
set(HAVE_NETINET_IP_H 0)
set(HAVE_NETINET_TCP_H 0)
set(HAVE_NETINET_UDP_H 0)
set(HAVE_NET_IF_H 0)
@@ -130,7 +124,6 @@ set(HAVE_POLL_H 0)
set(HAVE_POSIX_STRERROR_R 0)
set(HAVE_PWD_H 0)
set(HAVE_RECV 1)
set(HAVE_SELECT 1)
set(HAVE_SEND 1)
set(HAVE_SENDMMSG 0)
set(HAVE_SENDMSG 0)
@@ -163,7 +156,6 @@ set(HAVE_TERMIO_H 0)
set(HAVE_TIME_T_UNSIGNED 0)
set(HAVE_UTIME 1)
set(HAVE_UTIMES 0)
set(STDC_HEADERS 1)
# Types and sizes
+105 -82
View File
@@ -61,13 +61,14 @@ unset(_curl_version_h_contents)
message(STATUS "curl version=[${_curl_version}]")
string(REGEX REPLACE "([0-9]+\.[0-9]+\.[0-9]+).+" "\\1" _curl_version_sem "${_curl_version}")
# Initializes PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR
project(CURL
VERSION "${_curl_version_sem}"
LANGUAGES C)
# CMake does not recognize some targets accurately. Touch up configuration manually as a workaround.
if(WINDOWS_STORE AND MINGW) # MinGW UWP build
# CMake (as of v3.31.2) gets confused and applies the MSVC rc.exe command-line
# CMake (as of 3.31.2) gets confused and applies the MSVC rc.exe command-line
# template to windres. Reset it to the windres template as in 'Modules/Platform/Windows-windres.cmake':
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
elseif(DOS AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # DJGPP
@@ -89,7 +90,7 @@ endif()
if(UNIX)
string(APPEND _target_flags " UNIX")
endif()
if(BSD)
if(BSD OR CMAKE_SYSTEM_NAME MATCHES "BSD")
string(APPEND _target_flags " BSD")
endif()
if(ANDROID)
@@ -229,7 +230,7 @@ if(WIN32)
if(MINGW64_VERSION)
message(STATUS "Found MINGW64_VERSION=${MINGW64_VERSION}")
if(MINGW64_VERSION VERSION_LESS 3.0)
message(FATAL_ERROR "mingw-w64 3.0 or upper is required")
message(FATAL_ERROR "mingw-w64 3.0 or greater required")
endif()
endif()
endif()
@@ -256,8 +257,11 @@ if(CYGWIN OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "G
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") # Apply to all feature checks
endif()
option(ENABLE_DEBUG "Enable curl debug features (for developing curl itself)" OFF)
option(ENABLE_DEBUG "Enable curl debug features (for developing curl)" OFF)
if(ENABLE_DEBUG)
if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(FATAL_ERROR "Debug-enabled (aka development mode) curl requires the Debug configuration")
endif()
message(WARNING "This curl build is Debug-enabled and insecure, do not use in production.")
endif()
@@ -420,8 +424,6 @@ mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)
option(CURL_DISABLE_ALTSVC "Disable alt-svc support" OFF)
mark_as_advanced(CURL_DISABLE_ALTSVC)
option(CURL_DISABLE_SRP "Disable TLS-SRP support" OFF)
mark_as_advanced(CURL_DISABLE_SRP)
option(CURL_DISABLE_COOKIES "Disable cookies support" OFF)
mark_as_advanced(CURL_DISABLE_COOKIES)
option(CURL_DISABLE_BASIC_AUTH "Disable Basic authentication" OFF)
@@ -456,6 +458,8 @@ option(CURL_DISABLE_HTTP "Disable HTTP" OFF)
mark_as_advanced(CURL_DISABLE_HTTP)
option(CURL_DISABLE_HTTP_AUTH "Disable all HTTP authentication methods" OFF)
mark_as_advanced(CURL_DISABLE_HTTP_AUTH)
option(CURL_DISABLE_HTTPSIG "Disable HTTP Message Signatures (RFC 9421) (experimental)" ON)
mark_as_advanced(CURL_DISABLE_HTTPSIG)
option(CURL_DISABLE_IMAP "Disable IMAP" OFF)
mark_as_advanced(CURL_DISABLE_IMAP)
option(CURL_DISABLE_LDAP "Disable LDAP" OFF)
@@ -618,13 +622,13 @@ include(CheckSymbolExists)
include(CheckTypeSize)
include(CheckCSourceCompiles)
option(_CURL_PREFILL "Fast-track known feature detection results (Windows, some Apple)" "${WIN32}")
option(_CURL_PREFILL "Pre-fill known feature detection results (Windows, some Apple)" "${WIN32}")
mark_as_advanced(_CURL_PREFILL)
if(_CURL_PREFILL)
if(WIN32)
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/win32-cache.cmake")
include("${PROJECT_SOURCE_DIR}/CMake/win32-cache.cmake")
elseif(UNIX)
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/unix-cache.cmake")
include("${PROJECT_SOURCE_DIR}/CMake/unix-cache.cmake")
message(STATUS "Pre-filling feature detection results for UNIX")
endif()
elseif(WIN32)
@@ -804,6 +808,14 @@ else()
set(USE_APPLE_SECTRUST OFF)
endif()
set(USE_APPLE_FAST_UDP 0)
if(APPLE)
option(CURL_ENABLE_APPLE_FAST_UDP "Use Apple fast UDP (experimental)" OFF)
if(CURL_ENABLE_APPLE_FAST_UDP)
set(USE_APPLE_FAST_UDP 1)
endif()
endif()
if(_use_core_foundation_and_core_services)
find_library(COREFOUNDATION_FRAMEWORK NAMES "CoreFoundation")
mark_as_advanced(COREFOUNDATION_FRAMEWORK)
@@ -839,10 +851,10 @@ if(CURL_USE_OPENSSL)
if(NOT DEFINED HAVE_AWSLC)
check_symbol_exists("OPENSSL_IS_AWSLC" "openssl/base.h" HAVE_AWSLC)
endif()
if(NOT DEFINED HAVE_BORINGSSL)
if(NOT DEFINED HAVE_BORINGSSL AND NOT HAVE_AWSLC)
check_symbol_exists("OPENSSL_IS_BORINGSSL" "openssl/base.h" HAVE_BORINGSSL)
endif()
if(NOT DEFINED HAVE_LIBRESSL)
if(NOT DEFINED HAVE_LIBRESSL AND NOT HAVE_AWSLC AND NOT HAVE_BORINGSSL)
check_symbol_exists("LIBRESSL_VERSION_NUMBER" "openssl/opensslv.h" HAVE_LIBRESSL)
endif()
cmake_pop_check_state()
@@ -883,7 +895,7 @@ endif()
if(CURL_USE_MBEDTLS)
find_package(MbedTLS MODULE REQUIRED)
if(MBEDTLS_VERSION VERSION_LESS 3.2.0)
message(FATAL_ERROR "mbedTLS v3.2.0 or newer is required.")
message(FATAL_ERROR "mbedTLS 3.2.0 or greater required")
endif()
set(_ssl_enabled ON)
set(USE_MBEDTLS ON)
@@ -917,7 +929,7 @@ if(CURL_USE_WOLFSSL)
set(_curl_ca_bundle_supported TRUE)
if(USE_OPENSSL AND WOLFSSL_VERSION VERSION_LESS 5.7.6)
message(FATAL_ERROR "wolfSSL 5.7.6 or newer is required to coexist with OpenSSL.")
message(FATAL_ERROR "wolfSSL 5.7.6 or greater required to coexist with OpenSSL")
endif()
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "WOLFSSL_OPTIONS_IGNORE_SYS")
@@ -935,15 +947,6 @@ if(CURL_USE_GNUTLS)
set(_valid_default_ssl_backend TRUE)
endif()
set(_curl_ca_bundle_supported TRUE)
if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES CURL::gnutls)
# In GnuTLS 3.8.0 (2023-02-10) and upper, this check always succeeds.
# Detecting actual TLS-SRP support needs poking the API at runtime.
check_symbol_exists("gnutls_srp_verifier" "gnutls/gnutls.h" HAVE_GNUTLS_SRP)
cmake_pop_check_state()
endif()
endif()
if(CURL_USE_RUSTLS)
@@ -963,7 +966,7 @@ if(CURL_USE_RUSTLS)
endif()
endif()
if(NOT HAVE_RUSTLS_SUPPORTED_HPKE)
message(FATAL_ERROR "rustls-ffi library does not provide rustls_supported_hpke function. Required version is 0.15 or newer.")
message(FATAL_ERROR "rustls-ffi library does not provide rustls_supported_hpke function. Required version is 0.15 or greater.")
endif()
if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "rustls")
@@ -1002,7 +1005,7 @@ if(ZSTD_FOUND)
set(HAVE_ZSTD ON)
list(APPEND CURL_LIBS CURL::zstd)
else()
message(WARNING "zstd v1.0.0 or newer is required, disabling zstd support.")
message(WARNING "zstd 1.0.0 or greater required, disabling zstd support")
endif()
endif()
@@ -1011,7 +1014,6 @@ macro(curl_openssl_check_exists)
cmake_push_check_state()
if(USE_OPENSSL)
list(APPEND CMAKE_REQUIRED_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DOPENSSL_SUPPRESS_DEPRECATED") # for SSL_CTX_set_srp_username deprecated since 3.0.0
if(HAVE_LIBZ)
list(APPEND CMAKE_REQUIRED_LIBRARIES ZLIB::ZLIB)
endif()
@@ -1025,7 +1027,7 @@ macro(curl_openssl_check_exists)
if(HAVE_LIBZ)
list(APPEND CMAKE_REQUIRED_LIBRARIES ZLIB::ZLIB) # Public wolfSSL headers also require zlib headers
endif()
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DHAVE_UINTPTR_T") # to pull in stdint.h (as of wolfSSL v5.5.4)
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DHAVE_UINTPTR_T") # to pull in stdint.h (as of wolfSSL 5.5.4)
endif()
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32" "crypt32") # for OpenSSL/wolfSSL
@@ -1076,9 +1078,6 @@ if(USE_OPENSSL)
if(NOT DEFINED HAVE_SSL_SET0_WBIO)
curl_openssl_check_exists("SSL_set0_wbio" HAVE_SSL_SET0_WBIO)
endif()
if(NOT DEFINED HAVE_OPENSSL_SRP AND NOT CURL_DISABLE_SRP)
curl_openssl_check_exists("SSL_CTX_set_srp_username" "openssl/ssl.h" HAVE_OPENSSL_SRP)
endif()
endif()
option(USE_HTTPSRR "Enable HTTPS RR support (experimental)" OFF)
@@ -1110,6 +1109,11 @@ if(USE_ECH)
endif()
endif()
if(NOT CURL_DISABLE_HTTPSIG AND NOT USE_GNUTLS AND NOT USE_OPENSSL AND NOT USE_WOLFSSL)
message(WARNING "HTTPSIG requires GnuTLS, OpenSSL or wolfSSL. HTTPSIG support disabled.")
set(CURL_DISABLE_HTTPSIG ON)
endif()
option(USE_SSLS_EXPORT "Enable SSL session import/export (experimental)" OFF)
if(USE_SSLS_EXPORT)
if(_ssl_enabled)
@@ -1143,7 +1147,7 @@ if(USE_NGTCP2)
elseif(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.5.0)
find_package(NGTCP2 MODULE REQUIRED COMPONENTS "ossl")
if(NGTCP2_VERSION VERSION_LESS 1.12.0)
message(FATAL_ERROR "ngtcp2 1.12.0 or upper required for OpenSSL")
message(FATAL_ERROR "ngtcp2 1.12.0 or greater required for OpenSSL")
endif()
set(OPENSSL_QUIC_API2 1)
elseif(HAVE_LIBRESSL)
@@ -1203,10 +1207,6 @@ if(USE_PROXY_HTTP3)
endif()
endif()
if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
set(USE_TLS_SRP 1)
endif()
if(NOT CURL_DISABLE_LDAP)
if(WIN32 AND NOT WINDOWS_STORE)
option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
@@ -1336,6 +1336,9 @@ option(CURL_USE_GSASL "Use libgsasl" OFF)
mark_as_advanced(CURL_USE_GSASL)
if(CURL_USE_GSASL)
find_package(Libgsasl MODULE REQUIRED)
if(LIBGSASL_VERSION VERSION_LESS 1.6.0)
message(FATAL_ERROR "libgsasl 1.6.0 or greater required")
endif()
list(APPEND CURL_LIBS CURL::libgsasl)
set(USE_GSASL ON)
endif()
@@ -1344,18 +1347,27 @@ option(CURL_USE_GSSAPI "Use GSSAPI implementation" OFF)
mark_as_advanced(CURL_USE_GSSAPI)
if(CURL_USE_GSSAPI)
find_package(GSS MODULE)
set(CURL_GSS_FLAVOR "" CACHE STRING "Set preferred GSSAPI implementation ('Apple'). Default: MIT, then GNU (experimental)")
find_package(GSS MODULE COMPONENTS "${CURL_GSS_FLAVOR}")
set(HAVE_GSSAPI ${GSS_FOUND})
if(GSS_FOUND)
list(APPEND CURL_LIBS CURL::gss)
get_target_property(_gss_flavor CURL::gss INTERFACE_CURL_GSS_FLAVOR)
if(_gss_flavor STREQUAL "GNU")
get_target_property(GSS_FLAVOR CURL::gss INTERFACE_CURL_GSS_FLAVOR)
if(GSS_FLAVOR STREQUAL "Apple")
set(HAVE_GSSAPPLE 1)
elseif(GSS_FLAVOR STREQUAL "GNU")
set(HAVE_GSSGNU 1)
elseif(GSS_VERSION) # MIT
set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"")
endif()
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES CURL::gss)
check_function_exists("gss_set_neg_mechs" HAVE_GSS_SET_NEG_MECHS)
cmake_pop_check_state()
else()
message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.")
endif()
@@ -1545,7 +1557,6 @@ check_include_file("sys/un.h" HAVE_SYS_UN_H)
check_include_file_concat_curl("sys/utime.h" HAVE_SYS_UTIME_H) # sys/types.h (AmigaOS)
check_include_file_concat_curl("arpa/inet.h" HAVE_ARPA_INET_H)
check_include_file("dirent.h" HAVE_DIRENT_H)
check_include_file("fcntl.h" HAVE_FCNTL_H)
check_include_file_concat_curl("ifaddrs.h" HAVE_IFADDRS_H)
check_include_file("io.h" HAVE_IO_H)
@@ -1556,6 +1567,7 @@ check_include_file_concat_curl("net/if.h" HAVE_NET_IF_H) # sys/select.h
check_include_file_concat_curl("netdb.h" HAVE_NETDB_H)
check_include_file_concat_curl("netinet/in.h" HAVE_NETINET_IN_H)
check_include_file("netinet/in6.h" HAVE_NETINET_IN6_H)
check_include_file("netinet/ip.h" HAVE_NETINET_IP_H)
check_include_file_concat_curl("netinet/tcp.h" HAVE_NETINET_TCP_H) # sys/types.h (e.g. Cygwin) netinet/in.h
check_include_file_concat_curl("netinet/udp.h" HAVE_NETINET_UDP_H) # sys/types.h (e.g. Cygwin)
check_include_file("poll.h" HAVE_POLL_H)
@@ -1626,7 +1638,6 @@ endif()
check_function_exists("accept4" HAVE_ACCEPT4)
check_function_exists("fnmatch" HAVE_FNMATCH)
check_symbol_exists("basename" "${CURL_INCLUDES};string.h" HAVE_BASENAME) # libgen.h unistd.h
check_symbol_exists("opendir" "dirent.h" HAVE_OPENDIR)
check_function_exists("poll" HAVE_POLL) # poll.h
check_symbol_exists("socket" "${CURL_INCLUDES}" HAVE_SOCKET) # winsock2.h sys/socket.h
check_symbol_exists("socketpair" "${CURL_INCLUDES}" HAVE_SOCKETPAIR) # sys/socket.h
@@ -1634,14 +1645,12 @@ check_symbol_exists("recv" "${CURL_INCLUDES}" HAVE_RECV) # proto/bsd
check_symbol_exists("send" "${CURL_INCLUDES}" HAVE_SEND) # proto/bsdsocket.h sys/types.h sys/socket.h
check_function_exists("sendmsg" HAVE_SENDMSG)
check_function_exists("sendmmsg" HAVE_SENDMMSG)
check_symbol_exists("select" "${CURL_INCLUDES}" HAVE_SELECT) # proto/bsdsocket.h sys/select.h sys/socket.h
check_symbol_exists("memrchr" "string.h" HAVE_MEMRCHR)
check_symbol_exists("alarm" "unistd.h" HAVE_ALARM)
check_symbol_exists("fcntl" "fcntl.h" HAVE_FCNTL)
check_function_exists("getppid" HAVE_GETPPID)
check_function_exists("utimes" HAVE_UTIMES)
check_function_exists("gettimeofday" HAVE_GETTIMEOFDAY) # sys/time.h
check_symbol_exists("closesocket" "${CURL_INCLUDES}" HAVE_CLOSESOCKET) # winsock2.h
check_symbol_exists("sigsetjmp" "setjmp.h" HAVE_SIGSETJMP)
check_function_exists("getpass_r" HAVE_GETPASS_R)
@@ -1680,12 +1689,14 @@ else()
endif()
if(NOT WIN32)
check_include_file("dirent.h" HAVE_DIRENT_H)
check_function_exists("gettimeofday" HAVE_GETTIMEOFDAY) # sys/time.h
check_function_exists("if_nametoindex" HAVE_IF_NAMETOINDEX) # net/if.h
check_function_exists("realpath" HAVE_REALPATH)
check_function_exists("sched_yield" HAVE_SCHED_YIELD)
check_symbol_exists("inet_ntop" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP) # arpa/inet.h netinet/in.h sys/socket.h
check_symbol_exists("inet_pton" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON) # arpa/inet.h netinet/in.h sys/socket.h
check_symbol_exists("opendir" "dirent.h" HAVE_OPENDIR)
check_symbol_exists("strcasecmp" "string.h" HAVE_STRCASECMP)
check_symbol_exists("stricmp" "string.h" HAVE_STRICMP)
check_symbol_exists("strcmpi" "string.h" HAVE_STRCMPI)
@@ -1732,7 +1743,6 @@ foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6
HAVE_BOOL_T
STDC_HEADERS
HAVE_ATOMIC
)
curl_internal_test(${_curl_test})
@@ -1801,7 +1811,7 @@ if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
# On non-Windows and not cross-compiling, check for writable argv[]
include(CheckCSourceRuns)
check_c_source_runs("
int main(int argc, char **argv)
int main(int argc, char *argv[])
{
(void)argc;
argv[0][0] = ' ';
@@ -1813,7 +1823,8 @@ if(NOT CMAKE_CROSSCOMPILING)
include(CheckCSourceRuns)
check_c_source_runs("
#include <time.h>
int main(void) {
int main(void)
{
time_t t = -1;
return t < 0;
}" HAVE_TIME_T_UNSIGNED)
@@ -1937,9 +1948,8 @@ include(GNUInstallDirs)
set(_install_cmake_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(_project_config "${_generated_dir}/${PROJECT_NAME}Config.cmake")
set(_version_config "${_generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
set(_project_config "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake")
set(_version_config "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
option(BUILD_TESTING "Build tests" ON)
if(BUILD_TESTING AND Perl_FOUND)
@@ -2054,13 +2064,13 @@ curl_add_if("SSPI" USE_WINDOWS_SSPI)
curl_add_if("GSS-API" HAVE_GSSAPI)
curl_add_if("alt-svc" NOT CURL_DISABLE_ALTSVC)
curl_add_if("HSTS" NOT CURL_DISABLE_HSTS)
curl_add_if("HTTPSIG" NOT CURL_DISABLE_HTTPSIG)
curl_add_if("SPNEGO" NOT CURL_DISABLE_NEGOTIATE_AUTH AND
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
curl_add_if("Kerberos" NOT CURL_DISABLE_KERBEROS_AUTH AND
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
curl_add_if("NTLM" CURL_ENABLE_NTLM AND
(_use_curl_ntlm_core OR USE_WINDOWS_SSPI))
curl_add_if("TLS-SRP" USE_TLS_SRP)
curl_add_if("HTTP2" USE_NGHTTP2)
curl_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE)
curl_add_if("proxy-HTTP3" USE_PROXY_HTTP3)
@@ -2087,12 +2097,12 @@ message(STATUS "Features: ${SUPPORT_FEATURES}")
# Clear list and collect SSL backends
set(_items "")
curl_add_if("Schannel" _ssl_enabled AND USE_SCHANNEL)
curl_add_if("${_openssl}" _ssl_enabled AND USE_OPENSSL)
curl_add_if("mbedTLS" _ssl_enabled AND USE_MBEDTLS)
curl_add_if("wolfSSL" _ssl_enabled AND USE_WOLFSSL)
curl_add_if("GnuTLS" _ssl_enabled AND USE_GNUTLS)
curl_add_if("Rustls" _ssl_enabled AND USE_RUSTLS)
curl_add_if("Schannel" _ssl_enabled AND USE_SCHANNEL)
curl_add_if("${_openssl}" _ssl_enabled AND USE_OPENSSL)
curl_add_if("mbedTLS" _ssl_enabled AND USE_MBEDTLS)
curl_add_if("wolfSSL" _ssl_enabled AND USE_WOLFSSL)
curl_add_if("GnuTLS" _ssl_enabled AND USE_GNUTLS)
curl_add_if("Rustls" _ssl_enabled AND USE_RUSTLS)
if(_items)
list(SORT _items CASE INSENSITIVE)
@@ -2296,6 +2306,7 @@ if(NOT CURL_DISABLE_INSTALL)
set(LIBCURL_PC_REQUIRES "${LIBCURL_PC_REQUIRES_PRIVATE}")
set(LIBCURL_PC_LIBS "${LIBCURL_PC_LIBS_PRIVATE}")
set(LIBCURL_PC_CFLAGS "${LIBCURL_PC_CFLAGS_PRIVATE}")
set(LIBCURL_PC_REQUIRES_PRIVATE "")
endif()
if(BUILD_STATIC_LIBS)
set(ENABLE_STATIC "yes")
@@ -2335,6 +2346,7 @@ if(NOT CURL_DISABLE_INSTALL)
# Generate a pkg-config file matching this config.
# Consumed variables:
# CURL_PACKAGE_MAINTAINER
# CURLVERSION
# exec_prefix
# includedir
@@ -2354,9 +2366,18 @@ if(NOT CURL_DISABLE_INSTALL)
# https://manpages.debian.org/unstable/pkgconf/pkg-config.1.en.html
# https://manpages.debian.org/unstable/pkg-config/pkg-config.1.en.html
# https://www.msys2.org/docs/pkgconfig/
if(NOT "$ENV{CURL_CI}" STREQUAL "")
set(CURL_PACKAGE_MAINTAINER "https://curl.se/")
endif()
configure_file(
"${PROJECT_SOURCE_DIR}/libcurl.pc.in"
"${PROJECT_BINARY_DIR}/libcurl.pc" @ONLY)
# Strip trailing spaces, duplicate spaces after colon, empty properties
file(READ "${PROJECT_BINARY_DIR}/libcurl.pc" _libcurl_pc)
string(REGEX REPLACE " +\n" "\n" _libcurl_pc "${_libcurl_pc}")
string(REGEX REPLACE "\nLibs\.private: +" "\nLibs.private: " _libcurl_pc "${_libcurl_pc}")
string(REGEX REPLACE "\n([A-Za-z.]+:\n)+" "\n" _libcurl_pc "${_libcurl_pc}")
file(WRITE "${PROJECT_BINARY_DIR}/libcurl.pc" "${_libcurl_pc}")
install(FILES "${PROJECT_BINARY_DIR}/libcurl.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
@@ -2378,7 +2399,7 @@ if(NOT CURL_DISABLE_INSTALL)
endif()
${_generated_version_config}")
# Consumed custom variables:
# Consumed variables:
# CMAKE_MINIMUM_REQUIRED_VERSION
# CURLVERSION
# LIBCURL_PC_LIBS_PRIVATE_LIST
@@ -2390,6 +2411,7 @@ if(NOT CURL_DISABLE_INSTALL)
# CURL_SUPPORTED_PROTOCOLS_LIST
# CURL_USE_CMAKECONFIG
# CURL_USE_PKGCONFIG
# GSS_FLAVOR
# HAVE_BROTLI
# HAVE_GSSAPI
# HAVE_LIBIDN2
@@ -2429,37 +2451,38 @@ if(NOT CURL_DISABLE_INSTALL)
FILES
${_version_config}
${_project_config}
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindBrotli.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindCares.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindGSS.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindGnuTLS.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLDAP.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibbacktrace.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibgsasl.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibidn2.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibpsl.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibssh.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibssh2.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindLibuv.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindMbedTLS.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindNGHTTP2.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindNGHTTP3.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindNGTCP2.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindNettle.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindQuiche.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindRustls.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindWolfSSL.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/FindZstd.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindBrotli.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindCares.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindGSS.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindGnuTLS.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLDAP.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibbacktrace.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibgsasl.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibidn2.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibpsl.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibssh.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibssh2.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindLibuv.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindMbedTLS.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindNGHTTP2.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindNGHTTP3.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindNGTCP2.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindNettle.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindQuiche.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindRustls.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindWolfSSL.cmake"
"${PROJECT_SOURCE_DIR}/CMake/FindZstd.cmake"
DESTINATION ${_install_cmake_dir})
if(NOT TARGET curl_uninstall)
# Consumed variable:
# PROJECT_BINARY_DIR
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.in.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake"
@ONLY)
"${PROJECT_SOURCE_DIR}/CMake/cmake_uninstall.in.cmake"
"${PROJECT_BINARY_DIR}/cmake_uninstall.cmake" @ONLY)
add_custom_target(curl_uninstall
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake")
COMMAND ${CMAKE_COMMAND} -P "${PROJECT_BINARY_DIR}/cmake_uninstall.cmake")
endif()
if(BUILD_CURL_EXE)
+42 -16
View File
@@ -93,7 +93,9 @@
defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
(defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
defined(__sun__) || defined(__serenity__) || defined(__vxworks__)
defined(__sun__) || defined(__serenity__) || defined(__vxworks__) || \
(defined(__linux__) && defined(_POSIX_C_SOURCE) && \
_POSIX_C_SOURCE >= 200112L)
#include <sys/select.h>
#endif
@@ -632,7 +634,7 @@ typedef enum {
match */
CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */
CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer
*/
*/
CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from
inside a callback */
CURLE_AUTH_ERROR, /* 94 - an authentication function returned an
@@ -843,12 +845,20 @@ typedef enum {
#endif
#define CURLAUTH_BEARER (((unsigned long)1) << 6)
#define CURLAUTH_AWS_SIGV4 (((unsigned long)1) << 7)
#define CURLAUTH_HTTPSIG (((unsigned long)1) << 8)
#define CURLAUTH_ONLY (((unsigned long)1) << 31)
#define CURLAUTH_ANY ((~CURLAUTH_DIGEST_IE) & \
#define CURLAUTH_ANY ((~(CURLAUTH_DIGEST_IE | \
CURLAUTH_HTTPSIG)) & \
((unsigned long)0xffffffff))
#define CURLAUTH_ANYSAFE ((~(CURLAUTH_BASIC | CURLAUTH_DIGEST_IE)) & \
#define CURLAUTH_ANYSAFE ((~(CURLAUTH_BASIC | CURLAUTH_DIGEST_IE | \
CURLAUTH_HTTPSIG)) & \
((unsigned long)0xffffffff))
/* constants for CURLOPT_HTTPSIG_ALGORITHM */
#define CURLHTTPSIG_NONE 0L
#define CURLHTTPSIG_ED25519 1L
#define CURLHTTPSIG_HMAC_SHA256 2L
/* all types supported by server */
#define CURLSSH_AUTH_ANY ((unsigned long)0xffffffff)
#define CURLSSH_AUTH_NONE 0L /* none allowed, silly but complete */
@@ -1537,8 +1547,7 @@ typedef enum {
/* FTP Option that causes missing dirs to be created on the remote server.
In 7.19.4 we introduced the convenience enums for this option using the
CURLFTP_CREATE_DIR prefix.
*/
CURLFTP_CREATE_DIR prefix. */
CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110),
/* Set this to a bitmask value to enable the particular authentications
@@ -1589,7 +1598,7 @@ typedef enum {
CURLUSESSL_TRY - try using SSL, proceed anyway otherwise
CURLUSESSL_CONTROL - SSL for the control connection or fail
CURLUSESSL_ALL - SSL for all communication or fail
*/
*/
CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119),
/* The _LARGE version of the standard POSTFIELDSIZE option */
@@ -1615,7 +1624,7 @@ typedef enum {
CURLFTPAUTH_DEFAULT - let libcurl decide
CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS
CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL
*/
*/
CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129),
CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130,
@@ -1650,8 +1659,7 @@ typedef enum {
CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139),
/* Number of ports to try, including the first one set with LOCALPORT.
Thus, setting it to 1 makes no additional attempts but the first.
*/
Thus, setting it to 1 makes no additional attempts but the first. */
CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140),
/* no transfer, set up connection and let application use the socket by
@@ -1863,13 +1871,16 @@ typedef enum {
CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203),
/* Set a username for authenticated TLS */
CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204),
CURLOPTDEPRECATED(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204,
8.22.0, "Support was removed"),
/* Set a password for authenticated TLS */
CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205),
CURLOPTDEPRECATED(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205,
8.22.0, "Support was removed"),
/* Set authentication type for authenticated TLS */
CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206),
CURLOPTDEPRECATED(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206,
8.22.0, "Support was removed"),
/* Set to 1 to enable the "TE:" header in HTTP requests to ask for
compressed transfer-encoded responses. Set to 0 to disable the use of TE:
@@ -2030,13 +2041,16 @@ typedef enum {
CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_VALUES, 250),
/* Set a username for authenticated TLS for proxy */
CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251),
CURLOPTDEPRECATED(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT,
251, 8.22.0, "Support was removed"),
/* Set a password for authenticated TLS for proxy */
CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252),
CURLOPTDEPRECATED(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT,
252, 8.22.0, "Support was removed"),
/* Set authentication type for authenticated TLS for proxy */
CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253),
CURLOPTDEPRECATED(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253,
8.22.0, "Support was removed"),
/* name of the file keeping your private SSL-certificate for proxy */
CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254),
@@ -2262,6 +2276,18 @@ typedef enum {
/* set TLS supported signature algorithms */
CURLOPT(CURLOPT_SSL_SIGNATURE_ALGORITHMS, CURLOPTTYPE_STRINGPOINT, 328),
/* RFC 9421 HTTP Message Signatures algorithm */
CURLOPT(CURLOPT_HTTPSIG_ALGORITHM, CURLOPTTYPE_VALUES, 329),
/* Hex-encoded key for HTTP Message Signatures */
CURLOPT(CURLOPT_HTTPSIG_KEY, CURLOPTTYPE_STRINGPOINT, 330),
/* Key identifier for HTTP Message Signatures */
CURLOPT(CURLOPT_HTTPSIG_KEYID, CURLOPTTYPE_STRINGPOINT, 331),
/* Space-separated list of components to sign for HTTP Message Signatures */
CURLOPT(CURLOPT_HTTPSIG_HEADERS, CURLOPTTYPE_STRINGPOINT, 332),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
+4 -5
View File
@@ -32,12 +32,12 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "8.21.0-DEV"
#define LIBCURL_VERSION "8.22.0-DEV"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 21
#define LIBCURL_VERSION_MINOR 22
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define always
@@ -56,9 +56,8 @@
Note: This define is the full hex number and _does not_ use the
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 0x081500
and needs it to contain the full number. */
#define LIBCURL_VERSION_NUM 0x081600
/*
* This is the date and time when the full source package was created. The
+14 -14
View File
@@ -24,20 +24,20 @@
*
***************************************************************************/
/*
This is an "external" header file. Do not give away any internals here!
GOALS
o Enable a "pull" interface. The application that uses libcurl decides where
and when to ask libcurl to get/send data.
o Enable multiple simultaneous transfers in the same thread without making it
complicated for the application.
o Enable the application to select() on its own file descriptors and curl's
file descriptors simultaneous easily.
*/
* This is an "external" header file. Do not give away any internals here!
*
* GOALS
*
* o Enable a "pull" interface. The application that uses libcurl decides where
* and when to ask libcurl to get/send data.
*
* o Enable multiple simultaneous transfers in the same thread without making
* it complicated for the application.
*
* o Enable the application to select() on its own file descriptors and curl's
* file descriptors simultaneous easily.
*
*/
/*
* This header file should not really need to include "curl.h" since curl.h
+7 -3
View File
@@ -496,6 +496,9 @@ CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_USERAGENT || \
(option) == CURLOPT_USERNAME || \
(option) == CURLOPT_AWS_SIGV4 || \
(option) == CURLOPT_HTTPSIG_HEADERS || \
(option) == CURLOPT_HTTPSIG_KEY || \
(option) == CURLOPT_HTTPSIG_KEYID || \
(option) == CURLOPT_USERPWD || \
(option) == CURLOPT_XOAUTH2_BEARER || \
0)
@@ -605,9 +608,10 @@ CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t,
* == or whatsoever.
*/
/* XXX: should evaluate to true if expr is a pointer */
/* XXX: should evaluate to true if expr is a pointer or a char[] array */
#define curlcheck_any_ptr(expr) \
(sizeof(expr) == sizeof(void *))
(sizeof(expr) == sizeof(void *) || \
__builtin_types_compatible_p(__typeof__(expr), char[]))
/* evaluates to true if expr is NULL */
/* XXX: must not evaluate expr, so this check is not accurate */
@@ -674,7 +678,7 @@ CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t,
(__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
/* XXX: also check size of an char[] array? */
/* XXX: also check size of a char[] array? */
#define curlcheck_error_buffer(expr) \
(curlcheck_NULL(expr) || \
__builtin_types_compatible_p(__typeof__(expr), char *) || \
+1
View File
@@ -64,6 +64,7 @@ typedef enum {
CURLUE_BAD_USER, /* 29 */
CURLUE_LACKS_IDN, /* 30 */
CURLUE_TOO_LARGE, /* 31 */
CURLUE_BACKSLASH, /* 32 */
CURLUE_LAST
} CURLUcode;
-1
View File
@@ -251,7 +251,6 @@ if(BUILD_SHARED_LIBS)
CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
CMAKE_SYSTEM_NAME STREQUAL "OHOS" OR # OpenHarmony
CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
# FreeBSD comes with the a.out and ELF flavors but a.out was supported
# up to v3.x and ELF from v3.x. I cannot imagine someone running CMake
# on those ancient systems.
+34 -20
View File
@@ -84,6 +84,26 @@ LIB_VAUTH_HFILES = \
vauth/digest.h \
vauth/vauth.h
LIB_VDNS_CFILES = \
vdns/asyn-ares.c \
vdns/asyn-base.c \
vdns/asyn-thrdd.c \
vdns/cf-dns.c \
vdns/dnscache.c \
vdns/doh.c \
vdns/hostip.c \
vdns/hostip4.c \
vdns/hostip6.c \
vdns/httpsrr.c
LIB_VDNS_HFILES = \
vdns/asyn.h \
vdns/cf-dns.h \
vdns/dnscache.h \
vdns/doh.h \
vdns/hostip.h \
vdns/httpsrr.h
LIB_VTLS_CFILES = \
vtls/apple.c \
vtls/cipher_suite.c \
@@ -154,12 +174,9 @@ LIB_VSSH_HFILES = \
LIB_CFILES = \
altsvc.c \
amigaos.c \
asyn-ares.c \
asyn-base.c \
asyn-thrdd.c \
api.c \
bufq.c \
bufref.c \
cf-dns.c \
cf-h1-proxy.c \
cf-h2-proxy.c \
cf-haproxy.c \
@@ -194,8 +211,6 @@ LIB_CFILES = \
cw-out.c \
cw-pause.c \
dict.c \
dnscache.c \
doh.c \
dynhds.c \
easy.c \
easygetopt.c \
@@ -213,20 +228,18 @@ LIB_CFILES = \
hash.c \
headers.c \
hmac.c \
hostip.c \
hostip4.c \
hostip6.c \
hsts.c \
http.c \
http1.c \
http2.c \
http_aws_sigv4.c \
http_httpsig.c \
curl_ed25519.c \
http_chunks.c \
http_digest.c \
http_negotiate.c \
http_ntlm.c \
http_proxy.c \
httpsrr.c \
idn.c \
if2ip.c \
imap.c \
@@ -279,6 +292,7 @@ LIB_CFILES = \
transfer.c \
uint-bset.c \
uint-hash.c \
uint-hashset.c \
uint-spbset.c \
uint-table.c \
url.c \
@@ -289,11 +303,10 @@ LIB_CFILES = \
LIB_HFILES = \
altsvc.h \
amigaos.h \
api.h \
arpa_telnet.h \
asyn.h \
bufq.h \
bufref.h \
cf-dns.h \
cf-h1-proxy.h \
cf-h2-proxy.h \
cf-haproxy.h \
@@ -336,8 +349,6 @@ LIB_HFILES = \
cw-out.h \
cw-pause.h \
dict.h \
dnscache.h \
doh.h \
dynhds.h \
easy_lock.h \
easyif.h \
@@ -355,18 +366,18 @@ LIB_HFILES = \
gopher.h \
hash.h \
headers.h \
hostip.h \
hsts.h \
http.h \
http1.h \
http2.h \
http_aws_sigv4.h \
http_httpsig.h \
curl_ed25519.h \
http_chunks.h \
http_digest.h \
http_negotiate.h \
http_ntlm.h \
http_proxy.h \
httpsrr.h \
idn.h \
if2ip.h \
imap.h \
@@ -415,6 +426,7 @@ LIB_HFILES = \
transfer.h \
uint-bset.h \
uint-hash.h \
uint-hashset.h \
uint-spbset.h \
uint-table.h \
url.h \
@@ -424,7 +436,9 @@ LIB_HFILES = \
LIB_RCFILES = libcurl.rc
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
$(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) $(LIB_CURLX_CFILES)
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
$(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) $(LIB_CURLX_HFILES)
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VDNS_CFILES) \
$(LIB_VTLS_CFILES) $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) \
$(LIB_CURLX_CFILES)
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VDNS_HFILES) \
$(LIB_VTLS_HFILES) $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) \
$(LIB_CURLX_HFILES)
+203 -161
View File
@@ -78,6 +78,12 @@ const char *Curl_alpnid2str(enum alpnid id)
}
}
static enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
{
return Curl_alpn2alpnid((const unsigned char *)curlx_str(cstr),
curlx_strlen(cstr));
}
#define altsvc_free(x) curlx_free(x)
static struct altsvc *altsvc_createid(const char *srchost,
@@ -447,23 +453,125 @@ static bool hostcompare(const char *host, const char *check)
/* altsvc_flush() removes all alternatives for this source origin from the
list */
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
const char *srchost, unsigned short srcport)
static void altsvc_flush(struct altsvcinfo *asi,
struct Curl_peer *origin,
enum alpnid origin_alpnid)
{
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)) {
if((origin_alpnid == as->src.alpnid) &&
(origin->port == as->src.port) &&
hostcompare(origin->hostname, as->src.host)) {
Curl_node_remove(e);
altsvc_free(as);
}
}
}
#define ALTSVC_MA 1
#define ALTSVC_PERSIST 2
static void altsvc_parse_params(const char **pp,
time_t *pmaxage,
bool *ppersist)
{
curlx_str_passblanks(pp);
if(curlx_str_single(pp, ';'))
return;
for(;;) {
struct Curl_str name;
struct Curl_str val;
curl_off_t num;
int keyword = 0;
/* allow some extra whitespaces around name and value */
if(curlx_str_until(pp, &name, MAX_ALTSVC_LINE, '=') ||
curlx_str_single(pp, '='))
break; /* skip further parameter parsing */
curlx_str_trimblanks(&name);
curlx_str_passblanks(pp);
if(**pp == '\"') {
if(curlx_str_quotedword(pp, &val, MAX_ALTSVC_LINE))
break;
}
else {
if(curlx_str_cspn(pp, &val, ",;\r\n"))
break;
}
curlx_str_trimblanks(&val);
if(curlx_str_casecompare(&name, "ma"))
keyword = ALTSVC_MA;
else if(curlx_str_casecompare(&name, "persist"))
keyword = ALTSVC_PERSIST;
if(keyword) {
const char *vp = curlx_str(&val);
const char *vend = vp + curlx_strlen(&val);
if(curlx_str_number(&vp, &num, TIME_T_MAX))
break; /* not a number, skip further parameter parsing */
if(vp != vend)
break; /* not entirely a number, skip further parameter parsing */
if(keyword == ALTSVC_MA)
*pmaxage = (time_t)num;
else if(num == 1)
*ppersist = TRUE;
}
curlx_str_passblanks(pp);
if(curlx_str_single(pp, ';'))
break; /* no further parameters */
}
}
static bool altsvc_parse_dest(const char **pp,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_str *dsthost,
uint16_t *pdstport)
{
curl_off_t port = 0;
if(curlx_str_single(pp, '\"'))
return FALSE;
/* quoted string, with hostname or just :port ? */
if(curlx_str_single(pp, ':')) { /* is hostname:port ? */
if(curlx_str_single(pp, '[')) { /* DNS hostname/IPv4 */
if(curlx_str_until(pp, dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
infof(data, "Bad alt-svc hostname, ignoring.");
return FALSE;
}
}
else { /* IPv6 hostname */
if(curlx_str_until(pp, dsthost, MAX_IPADR_LEN, ']') ||
curlx_str_single(pp, ']')) {
infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
return FALSE;
}
}
if(curlx_str_single(pp, ':'))
return FALSE; /* not followed by ':' */
}
else /* is only :port, hostname is effectively origin */
curlx_str_assign(dsthost, origin->hostname,
strlen(origin->hostname));
if(curlx_str_number(pp, &port, 0xffff)) {
infof(data, "Unknown alt-svc port number, ignoring.");
return FALSE;
}
*pdstport = (uint16_t)port;
if(curlx_str_single(pp, '\"'))
return FALSE; /* quoted string not ending here as expected */
return TRUE;
}
/*
* Curl_altsvc_parse() takes an incoming alt-svc response header and stores
* the data correctly in the cache.
@@ -477,161 +585,91 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
*/
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
struct altsvcinfo *asi, const char *value,
enum alpnid srcalpnid, const char *srchost,
unsigned short srcport)
struct Curl_peer *origin,
enum alpnid origin_alpnid)
{
const char *p = value;
struct altsvc *as;
unsigned short dstport = srcport; /* the same by default */
size_t entries = 0;
struct Curl_str alpn;
const char *p;
DEBUGASSERT(asi);
DEBUGASSERT(origin);
/* RFC 7838, The "Alt-Svc" header field value is basically
* Alt-Svc: (clear|alpn="(host)?:port"\s*(;\s*parameter=value)*)
* This can be repeated, comma-separated.
*
* We parse "best effort", ignoring values we do not recognize.
*/
/* initial check for "clear" */
/* Try to catch a standalone "clear" */
p = value;
if(!curlx_str_cspn(&p, &alpn, ";\n\r")) {
curlx_str_trimblanks(&alpn);
/* "clear" is a magic keyword */
if(curlx_str_casecompare(&alpn, "clear")) {
/* Flush cached alternatives for this source origin */
altsvc_flush(asi, srcalpnid, srchost, srcport);
altsvc_flush(asi, origin, origin_alpnid);
return CURLE_OK;
}
}
p = value;
/* Not a standalone "clear", parse from start for alpn entries */
for(p = value; *p;) {
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
enum alpnid dstalpnid;
struct Curl_str dsthost;
uint16_t dstport;
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
return CURLE_OK; /* strange line */
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
break; /* not another entry, leave */
curlx_str_trimblanks(&alpn);
dstalpnid = Curl_str2alpnid(&alpn);
curlx_str_trimblanks(&alpn);
if(curlx_str_single(&p, '='))
break;
do {
if(!curlx_str_single(&p, '=')) {
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
/* [protocol]="[host][:port], [protocol]="[host][:port]" */
enum alpnid dstalpnid = Curl_str2alpnid(&alpn);
if(!curlx_str_single(&p, '\"')) {
struct Curl_str dsthost;
curl_off_t port = 0;
if(curlx_str_single(&p, ':')) {
/* hostname starts here */
if(curlx_str_single(&p, '[')) {
if(curlx_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
infof(data, "Bad alt-svc hostname, ignoring.");
break;
}
}
else {
/* IPv6 hostname */
if(curlx_str_until(&p, &dsthost, MAX_IPADR_LEN, ']') ||
curlx_str_single(&p, ']')) {
infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
break;
}
}
if(curlx_str_single(&p, ':'))
break;
}
/* Parse altsvc hostname:port */
if(!altsvc_parse_dest(&p, data, origin, &dsthost, &dstport))
break;
/* Parse optional parameters */
altsvc_parse_params(&p, &maxage, &persist);
if(dstalpnid) { /* this is a known ALPN id, e.g. not ALPN_none */
if(!entries++)
/* Flush cached alternatives for this source origin, if any - when
this is the first entry of the line. */
altsvc_flush(asi, origin, origin_alpnid);
as = altsvc_createid(origin->hostname, strlen(origin->hostname),
curlx_str(&dsthost),
curlx_strlen(&dsthost),
origin_alpnid, dstalpnid,
origin->port, dstport);
if(as) {
time_t secs = time(NULL);
/* The expires time also needs to take the Age: value (if any)
into account. [See RFC 7838 section 3.1] */
if(maxage > (TIME_T_MAX - secs))
as->expires = TIME_T_MAX;
else
/* no destination name, use source host */
curlx_str_assign(&dsthost, srchost, strlen(srchost));
if(curlx_str_number(&p, &port, 0xffff)) {
infof(data, "Unknown alt-svc port number, ignoring.");
break;
}
dstport = (unsigned short)port;
if(curlx_str_single(&p, '\"'))
break;
/* Handle the optional 'ma' and 'persist' flags. Unknown flags are
skipped. */
curlx_str_passblanks(&p);
if(!curlx_str_single(&p, ';')) {
for(;;) {
struct Curl_str name;
struct Curl_str val;
const char *vp;
curl_off_t num;
bool quoted;
/* allow some extra whitespaces around name and value */
if(curlx_str_until(&p, &name, 20, '=') ||
curlx_str_single(&p, '=') ||
curlx_str_cspn(&p, &val, ",;"))
break;
curlx_str_trimblanks(&name);
curlx_str_trimblanks(&val);
/* the value might be quoted */
vp = curlx_str(&val);
quoted = (*vp == '\"');
if(quoted)
vp++;
if(!curlx_str_number(&vp, &num, TIME_T_MAX)) {
if(curlx_str_casecompare(&name, "ma"))
maxage = (time_t)num;
else if(curlx_str_casecompare(&name, "persist") && (num == 1))
persist = TRUE;
}
else
break;
p = vp; /* point to the byte ending the value */
curlx_str_passblanks(&p);
if(quoted && curlx_str_single(&p, '\"'))
break;
curlx_str_passblanks(&p);
if(curlx_str_single(&p, ';'))
break;
}
}
if(dstalpnid) {
if(!entries++)
/* Flush cached alternatives for this source origin, if any - when
this is the first entry of the line. */
altsvc_flush(asi, srcalpnid, srchost, srcport);
as = altsvc_createid(srchost, strlen(srchost),
curlx_str(&dsthost),
curlx_strlen(&dsthost),
srcalpnid, dstalpnid,
srcport, dstport);
if(as) {
time_t secs = time(NULL);
/* The expires time also needs to take the Age: value (if any)
into account. [See RFC 7838 section 3.1] */
if(maxage > (TIME_T_MAX - secs))
as->expires = TIME_T_MAX;
else
as->expires = maxage + secs;
as->persist = persist;
altsvc_append(asi, as);
infof(data, "Added alt-svc: %.*s:%d over %s",
(int)curlx_strlen(&dsthost), curlx_str(&dsthost),
dstport, Curl_alpnid2str(dstalpnid));
}
else
return CURLE_OUT_OF_MEMORY;
}
as->expires = maxage + secs;
as->persist = persist;
altsvc_append(asi, as);
infof(data, "Added alt-svc: %.*s:%u over %s",
(int)curlx_strlen(&dsthost), curlx_str(&dsthost),
dstport, Curl_alpnid2str(dstalpnid));
}
else
break;
/* after the double quote there can be a comma if there is another
string or a semicolon if no more */
if(curlx_str_single(&p, ','))
break;
/* comma means another alternative is present */
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
break;
curlx_str_trimblanks(&alpn);
return CURLE_OUT_OF_MEMORY;
}
else
/* When this is followed by a comma, we expect another entry */
if(curlx_str_single(&p, ','))
break;
} while(1);
}
return CURLE_OK;
}
@@ -640,38 +678,42 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
* Return TRUE on a match
*/
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost,
int srcport,
struct Curl_peer *origin,
enum alpnid origin_alpnid,
struct altsvc **dstentry,
const int versions, /* one or more bits */
bool *psame_destination)
{
struct Curl_llist_node *e;
struct Curl_llist_node *n;
time_t now = time(NULL);
DEBUGASSERT(asi);
DEBUGASSERT(srchost);
DEBUGASSERT(origin);
DEBUGASSERT(dstentry);
*psame_destination = FALSE;
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_node_remove(e);
altsvc_free(as);
continue;
}
if((as->src.alpnid == srcalpnid) &&
hostcompare(srchost, as->src.host) &&
(as->src.port == srcport) &&
(versions & (int)as->dst.alpnid)) {
/* match */
*dstentry = as;
*psame_destination = (srcport == as->dst.port) &&
hostcompare(srchost, as->dst.host);
return TRUE;
if(Curl_llist_count(&asi->list)) {
struct Curl_llist_node *e;
struct Curl_llist_node *n;
time_t now = time(NULL);
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_node_remove(e);
altsvc_free(as);
continue;
}
if((origin_alpnid == as->src.alpnid) &&
(versions & (int)as->dst.alpnid) &&
(origin->port == as->src.port) &&
hostcompare(origin->hostname, as->src.host)) {
/* match */
*dstentry = as;
/* alt-svc on the same host+port or another one? */
*psame_destination = (origin->port == as->dst.port) &&
hostcompare(origin->hostname, as->dst.host);
return TRUE;
}
}
}
return FALSE;
+6 -4
View File
@@ -28,6 +28,8 @@
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
#include "llist.h"
struct Curl_peer;
/* the maximum number of alt-svc entries kept in a single cache */
#define MAX_ALTSVC_ENTRIES 5000
@@ -60,11 +62,11 @@ CURLcode Curl_altsvc_ctrl(struct Curl_easy *data, const long ctrl);
void Curl_altsvc_cleanup(struct altsvcinfo **asi);
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
struct altsvcinfo *asi, const char *value,
enum alpnid srcalpnid, const char *srchost,
unsigned short srcport);
struct Curl_peer *origin,
enum alpnid origin_alpnid);
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost,
int srcport,
struct Curl_peer *origin,
enum alpnid origin_alpnid,
struct altsvc **dstentry,
const int versions, /* CURLALTSVC_H* bits */
bool *psame_destination);
+1 -1
View File
@@ -25,7 +25,7 @@
#ifdef __AMIGA__
#include "hostip.h"
#include "vdns/hostip.h"
#include "curl_addrinfo.h"
#include "amigaos.h"
+451
View File
@@ -0,0 +1,451 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include "urldata.h"
#include "api.h"
#include "curl_threads.h"
#include "multiif.h"
#include "vtls/vtls_scache.h"
struct Curl_eapi_fn_props {
Curl_eapi_fn fn;
uint8_t data_is_killed; /* easy handle is killed in call */
uint8_t recurse; /* may be called when another call is in progress */
uint8_t no_event_cb; /* may not be called during a multi event callback */
uint8_t no_scache_lock; /* may not be called with easy's vtls_scache
locked by current thread */
};
static const struct Curl_eapi_fn_props eapi_fn_props[CURL_EAPI_FN_LAST] = {
/* function kill rec !ev !scach */
{ CURL_EAPI_FN_easy_cleanup, 1, 0, 0, 0 },
{ CURL_EAPI_FN_easy_duphandle, 0, 1, 0, 0 },
{ CURL_EAPI_FN_easy_getinfo, 0, 1, 0, 0 },
{ CURL_EAPI_FN_easy_header, 0, 1, 0, 0 },
{ CURL_EAPI_FN_easy_nextheader, 0, 1, 0, 0 },
{ CURL_EAPI_FN_easy_pause, 0, 1, 1, 0 },
{ CURL_EAPI_FN_easy_perform_ev, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_perform, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_recv, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_reset, 0, 0, 0, 0 },
{ CURL_EAPI_FN_easy_send, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_setopt, 0, 1, 0, 0 },
{ CURL_EAPI_FN_easy_ssls_export, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_ssls_import, 0, 0, 0, 1 },
{ CURL_EAPI_FN_easy_upkeep, 0, 0, 0, 1 },
{ CURL_EAPI_FN_ws_recv, 0, 1, 0, 1 },
{ CURL_EAPI_FN_ws_send, 0, 1, 0, 1 },
{ CURL_EAPI_FN_ws_start_frame, 0, 1, 0, 0 },
};
struct Curl_mapi_fn_props {
Curl_mapi_fn fn;
uint8_t multi_is_killed; /* multi handle is killed during call */
uint8_t recurse; /* may be called when another call is in progress */
uint8_t allow_ntfy_cb; /* may be called during a notify callback */
uint8_t no_scache_lock; /* may not be called with multi's vtls_scache
locked by current thread */
};
static const struct Curl_mapi_fn_props mapi_fn_props[CURL_MAPI_FN_LAST] = {
/* function kill rec ntfy !scach */
{ CURL_MAPI_FN_multi_add_handle, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_assign, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_cleanup, 1, 0, 0, 1 },
{ CURL_MAPI_FN_multi_fdset, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_get_handles, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_get_offt, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_info_read, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_notify_disable, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_notify_enable, 0, 1, 1, 0 },
{ CURL_MAPI_FN_multi_perform, 0, 0, 0, 1 },
{ CURL_MAPI_FN_multi_poll, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_remove_handle, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_setopt, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_socket_action, 0, 0, 0, 1 },
{ CURL_MAPI_FN_multi_socket_all, 0, 0, 0, 1 },
{ CURL_MAPI_FN_multi_socket, 0, 0, 0, 1 },
{ CURL_MAPI_FN_multi_timeout, 0, 0, 1, 1 },
{ CURL_MAPI_FN_multi_wait, 0, 0, 1, 0 },
{ CURL_MAPI_FN_multi_waitfds, 0, 0, 1, 0 },
};
struct Curl_cbapi_fn_props {
Curl_cbapi_fn fn;
uint8_t is_event_cb; /* is a multi event processing callback */
};
static const struct Curl_cbapi_fn_props
cbapi_fn_props[CURL_CBAPI_FN_LAST - CURL_CBAPI_FN_START] = {
{ CURL_CBAPI_FN_easy_chunk_bgn, 0 },
{ CURL_CBAPI_FN_easy_chunk_end, 0 },
{ CURL_CBAPI_FN_easy_closesocket, 0 },
{ CURL_CBAPI_FN_easy_cr_in_read, 0 },
{ CURL_CBAPI_FN_easy_cr_in_resume_from, 0 },
{ CURL_CBAPI_FN_easy_cw_out_cb, 0 },
{ CURL_CBAPI_FN_easy_fdebug, 0 },
{ CURL_CBAPI_FN_easy_fnmatch_data, 0 },
{ CURL_CBAPI_FN_easy_fopensocket, 0 },
{ CURL_CBAPI_FN_easy_fprereq, 0 },
{ CURL_CBAPI_FN_easy_fprogress, 0 },
{ CURL_CBAPI_FN_easy_fread_func, 0 },
{ CURL_CBAPI_FN_easy_fsockopt, 0 },
{ CURL_CBAPI_FN_easy_fsslctx, 0 },
{ CURL_CBAPI_FN_easy_fwrite_rtp, 0 },
{ CURL_CBAPI_FN_easy_fxferinfo, 0 },
{ CURL_CBAPI_FN_easy_ioctl_func, 0 },
{ CURL_CBAPI_FN_easy_resolver_start, 0 },
{ CURL_CBAPI_FN_easy_seek_func, 0 },
{ CURL_CBAPI_FN_easy_ssh_hostkeyfunc, 0 },
{ CURL_CBAPI_FN_easy_ssh_keyfunc, 0 },
{ CURL_CBAPI_FN_easy_trailer_callback, 0 },
{ CURL_CBAPI_FN_multi_ntfy_cb, 0 },
{ CURL_CBAPI_FN_multi_push_cb, 0 },
{ CURL_CBAPI_FN_multi_socket_cb, 1 },
{ CURL_CBAPI_FN_multi_timer_cb, 1 },
};
static bool eapi_in_event_cb(struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
if(multi && multi->callstack.count) {
size_t i;
for(i = 0; i < multi->callstack.count; ++i) {
if(multi->callstack.calls[i] >= CURL_CBAPI_FN_START) {
uint16_t fn = multi->callstack.calls[i];
if((fn < CURL_CBAPI_FN_LAST) &&
cbapi_fn_props[fn - CURL_CBAPI_FN_START].is_event_cb)
return TRUE;
}
}
}
return FALSE;
}
static bool mapi_in_ntfy_cb(struct Curl_multi *multi)
{
if(multi && multi->callstack.count) {
size_t i;
for(i = 0; i < multi->callstack.count; ++i) {
if(multi->callstack.calls[i] == CURL_CBAPI_FN_multi_ntfy_cb)
return TRUE;
}
}
return FALSE;
}
bool Curl_api_multi_is_in_callback(struct Curl_multi *multi)
{
if(multi && multi->callstack.count) {
size_t i;
for(i = 0; i < multi->callstack.count; ++i) {
if(multi->callstack.calls[i] >= CURL_CBAPI_FN_START)
return TRUE;
}
}
return FALSE;
}
bool Curl_api_is_in_callback(struct Curl_easy *data)
{
if(data && data->multi) {
return Curl_api_multi_is_in_callback(data->multi);
}
return FALSE;
}
bool Curl_eapi_enter(struct Curl_eapi_guard *guard,
CURL *curl,
Curl_eapi_fn fn,
CURLcode *presult)
{
struct Curl_easy *data = curl;
const struct Curl_eapi_fn_props *fn_props;
CURLcode result = CURLE_OK;
guard->depth = 0;
/* Verify that we got an easy handle we can work with. */
if(!GOOD_EASY_HANDLE(data)) {
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* verify that is either not added to a multi handle OR has a
* GOOD multi handle that knows `data` for `data->mid`. */
if(data->mid != UINT32_MAX) {
if(GOOD_MULTI_HANDLE(data->multi)) {
if(!Curl_multi_knows_easy(data->multi, data)) {
/* But multi does not know it, something is fishy, better deny call */
DEBUGASSERT(0);
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
}
else {
DEBUGASSERT(0); /* data needs to have a GOOD multi handle */
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
}
else if(data->multi) {
DEBUGASSERT(0); /* data should not have a multi handle */
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* verify that the call `fn` we're about to enter is known
* and check call properties to be admitting. */
if(fn >= CURL_EAPI_FN_LAST) {
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
fn_props = &eapi_fn_props[fn];
DEBUGASSERT(fn_props->fn == fn);
if(!fn_props->recurse) {
if(data->callstack.count) {
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"EAPI guard: calling %hu with call to %u ongoing\n", (uint16_t)fn,
data->callstack.calls[data->callstack.count-1]));
#endif
result = CURLE_RECURSIVE_API_CALL;
goto out;
}
if(data->multi && data->multi->callstack.count) {
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"EAPI guard: calling %hu with multi call to %u ongoing\n",
(uint16_t)fn,
data->multi->callstack.calls[data->multi->callstack.count-1]));
#endif
result = CURLE_RECURSIVE_API_CALL;
goto out;
}
}
if(fn_props->no_event_cb && eapi_in_event_cb(data)) {
/* Not allowed to be invoked while an event cb is ongoing */
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"EAPI guard: calling %hu while event callback ongoing\n",
(uint16_t)fn));
#endif
result = CURLE_RECURSIVE_API_CALL;
goto out;
}
#if defined(USE_SSL) && defined(USE_MUTEX)
if(fn_props->no_scache_lock &&
Curl_ssl_scache_is_locked_by_current_thread(data)) {
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"EAPI guard: calling %hu while vtls_scache is locked by "
"current thread\n", (uint16_t)fn));
#endif
result = CURLE_RECURSIVE_API_CALL;
goto out;
}
#endif
/* all fine, add to data's callstack */
if(data->callstack.count >= CURL_EAPI_MAX_RECURSION) {
result = CURLE_RECURSIVE_API_CALL;
goto out;
}
data->callstack.calls[data->callstack.count] = (uint16_t)fn;
++data->callstack.count;
guard->depth = data->callstack.count;
guard->data = fn_props->data_is_killed ? NULL : data;
out:
if(presult)
*presult = result;
return guard->depth > 0;
}
void Curl_eapi_leave(struct Curl_eapi_guard *guard)
{
if(guard->depth) {
/* guard->data is set when handle is supposed to stay alive during call */
if(guard->data && GOOD_EASY_HANDLE(guard->data)) {
if(guard->depth > guard->data->callstack.count) {
DEBUGASSERT(0); /* something very wrong */
}
else {
if(guard->depth < guard->data->callstack.count) {
DEBUGASSERT(0); /* someone forgot to clean up */
}
/* reset to depth the guard was entered in */
guard->data->callstack.count = (uint16_t)(guard->depth - 1);
}
}
}
}
CURLHcode Curl_eapi_hcode(CURLcode result)
{
switch(result) {
case CURLE_OK:
return CURLHE_OK;
case CURLE_BAD_FUNCTION_ARGUMENT:
return CURLHE_BAD_ARGUMENT;
case CURLE_OUT_OF_MEMORY:
return CURLHE_OUT_OF_MEMORY;
case CURLE_NOT_BUILT_IN:
return CURLHE_NOT_BUILT_IN;
default:
/* Unfortunately, we cannot convert RECURSIVE_API_CALL,
* but since the header API is reentrant, this should not happen. */
return CURLHE_BAD_ARGUMENT;
}
}
bool Curl_mapi_enter(struct Curl_mapi_guard *guard,
CURLM *m,
Curl_mapi_fn fn,
CURLMcode *pmresult)
{
struct Curl_multi *multi = m;
const struct Curl_mapi_fn_props *fn_props;
CURLMcode mresult = CURLM_OK;
guard->depth = 0;
/* Verify that we got an easy handle we can work with. */
if(!GOOD_MULTI_HANDLE(multi)) {
mresult = CURLM_BAD_HANDLE;
goto out;
}
if(fn >= CURL_MAPI_FN_LAST) {
mresult = CURLM_BAD_FUNCTION_ARGUMENT;
goto out;
}
fn_props = &mapi_fn_props[fn];
DEBUGASSERT(fn_props->fn == fn);
if(fn_props->allow_ntfy_cb && mapi_in_ntfy_cb(multi)) {
/* explicitly allowed, even though normal recursion may not */
}
else if(!fn_props->recurse && multi->callstack.count) {
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"MAPI guard: calling %hu with call to %u ongoing\n", (uint16_t)fn,
multi->callstack.calls[multi->callstack.count-1]));
#endif
mresult = CURLM_RECURSIVE_API_CALL;
goto out;
}
#if defined(USE_SSL) && defined(USE_MUTEX)
if(fn_props->no_scache_lock && multi->ssl_scache &&
Curl_ssl_scache_is_locked_by_current_thread(multi->admin)) {
#ifdef CURLVERBOSE
DEBUGF(curl_mfprintf(stderr,
"MAPI guard: calling %hu while its vtls_scache is locked by "
"current thread\n", (uint16_t)fn));
#endif
mresult = CURLM_RECURSIVE_API_CALL;
goto out;
}
#endif
/* all fine, add to data's callstack */
if(multi->callstack.count >= CURL_MAPI_MAX_RECURSION) {
mresult = CURLM_RECURSIVE_API_CALL;
goto out;
}
multi->callstack.calls[multi->callstack.count] = (uint16_t)fn;
++multi->callstack.count;
guard->depth = multi->callstack.count;
guard->multi = fn_props->multi_is_killed ? NULL : multi;
out:
if(pmresult)
*pmresult = mresult;
return guard->depth > 0;
}
void Curl_mapi_leave(struct Curl_mapi_guard *guard)
{
if(guard->depth) {
/* guard->data is set when handle is supposed to stay alive during call */
if(guard->multi && GOOD_MULTI_HANDLE(guard->multi)) {
if(guard->depth > guard->multi->callstack.count) {
DEBUGASSERT(0); /* something very wrong */
}
else {
if(guard->depth < guard->multi->callstack.count) {
DEBUGASSERT(0); /* someone forgot to clean up */
}
/* reset to depth the guard was entered in */
guard->multi->callstack.count = (uint16_t)(guard->depth - 1);
}
}
}
}
void Curl_cbapi_enter(struct Curl_mapi_guard *guard,
struct Curl_easy *data,
struct Curl_multi *multi,
Curl_cbapi_fn fn)
{
guard->depth = 0;
if(!multi)
multi = data ? data->multi : NULL;
/* if not multi is involved here, just leave */
if(!multi)
return;
/* invalid callback specifier? */
if((fn >= CURL_CBAPI_FN_LAST) || (fn < CURL_CBAPI_FN_START)) {
DEBUGASSERT(0);
return;
}
DEBUGASSERT(cbapi_fn_props[fn - CURL_CBAPI_FN_START].fn == fn);
if(multi->callstack.count) {
size_t i;
for(i = multi->callstack.count; i; --i) {
if(multi->callstack.calls[i - 1] == fn) {
/* recursive invocation of the same callback */
DEBUGASSERT(0);
return;
}
}
}
/* all fine, add to data's callstack */
/* if multi callstack already at max depth, leave */
if(multi->callstack.count >= CURL_MAPI_MAX_RECURSION)
return;
multi->callstack.calls[multi->callstack.count] = (uint16_t)fn;
++multi->callstack.count;
guard->depth = multi->callstack.count;
guard->multi = multi;
}
void Curl_cbapi_leave(struct Curl_mapi_guard *guard)
{
Curl_mapi_leave(guard);
}
+212
View File
@@ -0,0 +1,212 @@
#ifndef HEADER_CURL_API_H
#define HEADER_CURL_API_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
#ifdef DEBUGBUILD
/* On a debug build, we want to fail hard on easy handles that
* are not NULL, but no longer have the MAGIC touch. This gives
* us early warning on things only discovered by valgrind otherwise. */
#define GOOD_EASY_HANDLE(x) \
(((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) ? TRUE : \
(DEBUGASSERT(!(x)), FALSE))
#else
#define GOOD_EASY_HANDLE(x) \
((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
#endif
#define CURLMULTI_MAGIC_NUMBER 0x000bab1e
#ifdef DEBUGBUILD
/* On a debug build, we want to fail hard on multi handles that
* are not NULL, but no longer have the MAGIC touch. This gives
* us early warning on things only discovered by valgrind otherwise. */
#define GOOD_MULTI_HANDLE(x) \
(((x) && (x)->magic == CURLMULTI_MAGIC_NUMBER) ? TRUE : \
(DEBUGASSERT(!(x)), FALSE))
#else
#define GOOD_MULTI_HANDLE(x) \
((x) && (x)->magic == CURLMULTI_MAGIC_NUMBER)
#endif
/* the API functions called on a CURL* */
typedef enum {
CURL_EAPI_FN_easy_cleanup,
CURL_EAPI_FN_easy_duphandle,
CURL_EAPI_FN_easy_getinfo,
CURL_EAPI_FN_easy_header,
CURL_EAPI_FN_easy_nextheader,
CURL_EAPI_FN_easy_pause,
CURL_EAPI_FN_easy_perform_ev,
CURL_EAPI_FN_easy_perform,
CURL_EAPI_FN_easy_recv,
CURL_EAPI_FN_easy_reset,
CURL_EAPI_FN_easy_send,
CURL_EAPI_FN_easy_setopt,
CURL_EAPI_FN_easy_ssls_export,
CURL_EAPI_FN_easy_ssls_import,
CURL_EAPI_FN_easy_upkeep,
CURL_EAPI_FN_ws_recv,
CURL_EAPI_FN_ws_send,
CURL_EAPI_FN_ws_start_frame,
CURL_EAPI_FN_LAST
} Curl_eapi_fn;
/* the API functions called on a CURLM* */
typedef enum {
CURL_MAPI_FN_multi_add_handle,
CURL_MAPI_FN_multi_assign,
CURL_MAPI_FN_multi_cleanup,
CURL_MAPI_FN_multi_fdset,
CURL_MAPI_FN_multi_get_handles,
CURL_MAPI_FN_multi_get_offt,
CURL_MAPI_FN_multi_info_read,
CURL_MAPI_FN_multi_notify_disable,
CURL_MAPI_FN_multi_notify_enable,
CURL_MAPI_FN_multi_perform,
CURL_MAPI_FN_multi_poll,
CURL_MAPI_FN_multi_remove_handle,
CURL_MAPI_FN_multi_setopt,
CURL_MAPI_FN_multi_socket_action,
CURL_MAPI_FN_multi_socket_all,
CURL_MAPI_FN_multi_socket,
CURL_MAPI_FN_multi_timeout,
CURL_MAPI_FN_multi_wait,
CURL_MAPI_FN_multi_waitfds,
CURL_MAPI_FN_LAST
} Curl_mapi_fn;
#define CURL_CBAPI_FN_START (16 * 1024)
/* the callback functions */
typedef enum {
CURL_CBAPI_FN_easy_chunk_bgn = CURL_CBAPI_FN_START,
CURL_CBAPI_FN_easy_chunk_end,
CURL_CBAPI_FN_easy_closesocket,
CURL_CBAPI_FN_easy_cr_in_read,
CURL_CBAPI_FN_easy_cr_in_resume_from,
CURL_CBAPI_FN_easy_cw_out_cb,
CURL_CBAPI_FN_easy_fdebug,
CURL_CBAPI_FN_easy_fnmatch_data,
CURL_CBAPI_FN_easy_fopensocket,
CURL_CBAPI_FN_easy_fprereq,
CURL_CBAPI_FN_easy_fprogress,
CURL_CBAPI_FN_easy_fread_func,
CURL_CBAPI_FN_easy_fsockopt,
CURL_CBAPI_FN_easy_fsslctx,
CURL_CBAPI_FN_easy_fwrite_rtp,
CURL_CBAPI_FN_easy_fxferinfo,
CURL_CBAPI_FN_easy_ioctl_func,
CURL_CBAPI_FN_easy_resolver_start,
CURL_CBAPI_FN_easy_seek_func,
CURL_CBAPI_FN_easy_ssh_hostkeyfunc,
CURL_CBAPI_FN_easy_ssh_keyfunc,
CURL_CBAPI_FN_easy_trailer_callback,
CURL_CBAPI_FN_multi_ntfy_cb,
CURL_CBAPI_FN_multi_push_cb,
CURL_CBAPI_FN_multi_socket_cb,
CURL_CBAPI_FN_multi_timer_cb,
CURL_CBAPI_FN_LAST
} Curl_cbapi_fn;
/* EAPI */
#define CURL_EAPI_MAX_RECURSION 7
struct Curl_eapi_stack {
uint16_t count;
uint16_t calls[CURL_EAPI_MAX_RECURSION];
};
struct Curl_eapi_guard {
struct Curl_easy *data; /* != NULL if handle stays */
uint16_t depth; /* > 0 if this guard was entered */
};
bool Curl_eapi_enter(struct Curl_eapi_guard *guard,
CURL *curl,
Curl_eapi_fn fn,
CURLcode *presult);
void Curl_eapi_leave(struct Curl_eapi_guard *guard);
/* Convert an EAPI failure to a header API result */
CURLHcode Curl_eapi_hcode(CURLcode result);
/* Curl_eapi_enter() checks for curl being NULL, but windows compiler
* analyzers do not realize this. *sigh* */
#define CURL_EAPI_ENTER(g, curl, fn, r) \
Curl_eapi_enter((g), (curl), CURL_EAPI_FN_##fn, (r)) && (curl)
#define CURL_EAPI_LEAVE(g) \
Curl_eapi_leave(g)
/* MAPI */
#define CURL_MAPI_MAX_RECURSION 15
struct Curl_mapi_stack {
uint16_t count;
uint16_t calls[CURL_MAPI_MAX_RECURSION];
};
struct Curl_mapi_guard {
struct Curl_multi *multi; /* != NULL if handle stays */
uint16_t depth; /* > 0 if this guard was entered */
};
bool Curl_mapi_enter(struct Curl_mapi_guard *guard,
CURLM *m,
Curl_mapi_fn fn,
CURLMcode *pmresult);
void Curl_mapi_leave(struct Curl_mapi_guard *guard);
/* Curl_mapi_enter() checks for m being NULL, but windows compiler
* analyzers do not realize this. *sigh* */
#define CURL_MAPI_ENTER(g, m, fn, r) \
Curl_mapi_enter((g), (m), CURL_MAPI_FN_##fn, (r)) && (m)
#define CURL_MAPI_LEAVE(g) \
Curl_mapi_leave(g)
void Curl_cbapi_enter(struct Curl_mapi_guard *guard,
struct Curl_easy *data,
struct Curl_multi *multi,
Curl_cbapi_fn fn);
void Curl_cbapi_leave(struct Curl_mapi_guard *guard);
#define CURL_CBAPI_START(g, d, fn) \
Curl_cbapi_enter((g), (d), NULL, CURL_CBAPI_FN_##fn)
#define CURL_CBAPI_MULTI_START(g, m, fn) \
Curl_cbapi_enter((g), NULL, (m), CURL_CBAPI_FN_##fn)
#define CURL_CBAPI_END(g) \
Curl_cbapi_leave(g)
#define CURL_CBAPI_MULTI_END(g) \
Curl_cbapi_leave(g)
bool Curl_api_is_in_callback(struct Curl_easy *data);
bool Curl_api_multi_is_in_callback(struct Curl_multi *multi);
#endif /* HEADER_CURL_API_H */
+4 -4
View File
@@ -135,7 +135,7 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
Curl_httpchunk_init(data, &ts->ch, TRUE);
Curl_httpchunk_init(data, &ts->ch, TRUE, TRUE);
*pts = ts;
return tunnel_reinit(cf, data, ts);
@@ -329,7 +329,7 @@ static CURLcode on_resp_header_udp(struct Curl_cfilter *cf,
k->httpcode);
}
else {
const char *p = header + strlen("Content-Length:");
const char *p = header + CURL_CSTRLEN("Content-Length:");
if(curlx_str_numblanks(&p, &ts->cl)) {
failf(data, "Unsupported Content-Length value");
return CURLE_WEIRD_SERVER_REPLY;
@@ -419,7 +419,7 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
k->httpcode);
}
else {
const char *p = header + strlen("Content-Length:");
const char *p = header + CURL_CSTRLEN("Content-Length:");
if(curlx_str_numblanks(&p, &ts->cl)) {
failf(data, "Unsupported Content-Length value");
return CURLE_WEIRD_SERVER_REPLY;
@@ -980,7 +980,7 @@ CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
ts->httpversion = httpversion;
curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
Curl_httpchunk_init(data, &ts->ch, TRUE);
Curl_httpchunk_init(data, &ts->ch, TRUE, TRUE);
pctx = curlx_calloc(1, sizeof(*pctx));
if(!pctx) {
+9 -3
View File
@@ -187,7 +187,7 @@ struct cf_h2_proxy_ctx {
struct Curl_peer *dest; /* where to tunnel to */
struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
int32_t goaway_error;
int32_t last_stream_id;
int32_t remote_max_sid;
BIT(conn_closed);
BIT(rcvd_goaway);
BIT(sent_goaway);
@@ -500,6 +500,11 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
break;
case NGHTTP2_GOAWAY:
ctx->rcvd_goaway = TRUE;
ctx->remote_max_sid = frame->goaway.last_stream_id;
if(data) {
infof(data, "received GOAWAY, error=%u, last_stream=%d",
frame->goaway.error_code, ctx->remote_max_sid);
}
break;
default:
break;
@@ -574,7 +579,7 @@ static int proxy_h2_on_header(nghttp2_session *session,
return 0;
}
if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
if(namelen == CURL_CSTRLEN(HTTP_PSEUDO_STATUS) &&
!memcmp(HTTP_PSEUDO_STATUS, name, namelen)) {
int http_status;
struct http_resp *resp;
@@ -911,6 +916,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
ctx->remote_max_sid = INT32_MAX;
if(tunnel_stream_init(&ctx->tunnel, ctx->dest))
goto out;
@@ -1187,7 +1193,7 @@ static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
else if(ctx->tunnel.reset ||
(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
(ctx->rcvd_goaway &&
ctx->last_stream_id < ctx->tunnel.stream_id)) {
ctx->remote_max_sid < ctx->tunnel.stream_id)) {
result = CURLE_RECV_ERROR;
}
else
+2 -2
View File
@@ -81,8 +81,8 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf,
if(result)
return result;
if(data->set.str[STRING_HAPROXY_CLIENT_IP]) {
client_source_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
client_source_ip = CURL_EASY_STR(data, STRING_HAPROXY_CLIENT_IP);
if(client_source_ip) {
client_dest_ip = client_source_ip;
is_ipv6 = !Curl_is_ipv4addr(client_source_ip);
}
+55 -64
View File
@@ -28,16 +28,16 @@
#include "urldata.h"
#include "curl_trc.h"
#include "cfilters.h"
#include "cf-dns.h"
#include "cf-setup.h"
#include "connect.h"
#include "hostip.h"
#include "httpsrr.h"
#include "multiif.h"
#include "cf-https-connect.h"
#include "http2.h"
#include "progress.h"
#include "select.h"
#include "vdns/cf-dns.h"
#include "vdns/hostip.h"
#include "vdns/httpsrr.h"
#include "vquic/vquic.h"
typedef enum {
@@ -52,7 +52,6 @@ struct cf_hc_baller {
const char *name;
struct Curl_cfilter *cf;
CURLcode result;
struct curltime started;
int reply_ms;
uint8_t transport;
enum alpnid alpn_id;
@@ -110,6 +109,7 @@ static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
struct cf_hc_ctx {
cf_hc_state state;
struct Curl_peer *destination; /* who we ultimately want to talk to */
struct curltime started; /* when connect started */
CURLcode result; /* overall result */
CURLcode check_h3_result;
@@ -123,21 +123,14 @@ struct cf_hc_ctx {
BIT(ballers_complete);
};
static void cf_hc_ctx_close(struct Curl_easy *data,
struct cf_hc_ctx *ctx)
static void cf_hc_ctx_destroy(struct Curl_easy *data,
struct cf_hc_ctx *ctx)
{
if(ctx) {
size_t i;
for(i = 0; i < ctx->baller_count; ++i)
cf_hc_baller_discard(&ctx->ballers[i], data);
}
}
static void cf_hc_ctx_destroy(struct Curl_easy *data,
struct cf_hc_ctx *ctx)
{
if(ctx) {
cf_hc_ctx_close(data, ctx);
Curl_peer_unlink(&ctx->destination);
curlx_free(ctx);
}
}
@@ -179,7 +172,6 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
struct Curl_cfilter *save = cf->next;
cf->next = NULL;
b->started = *Curl_pgrs_now(data);
b->result = Curl_cf_setup_insert_after(cf, data, b->transport,
CURL_CF_SSL_ENABLE);
b->cf = cf->next;
@@ -222,7 +214,6 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
ctx->state = CF_HC_SUCCESS;
cf->connected = TRUE;
cf_hc_ctx_close(data, ctx);
/* ballers may have failf()'d, the winner resets it, so our
* errorbuf is clean again. */
Curl_reset_fail(data);
@@ -245,7 +236,8 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
}
static bool time_to_start_baller2(struct Curl_cfilter *cf,
struct Curl_easy *data)
struct Curl_easy *data,
const struct curltime *pnow)
{
struct cf_hc_ctx *ctx = cf->ctx;
timediff_t elapsed_ms;
@@ -260,7 +252,7 @@ static bool time_to_start_baller2(struct Curl_cfilter *cf,
return TRUE;
}
elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->started);
elapsed_ms = curlx_ptimediff_ms(pnow, &ctx->started);
if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
CURL_TRC_CF(data, cf, "%s inconclusive after %" FMT_TIMEDIFF_T ", "
"starting %s", ctx->ballers[0].name,
@@ -296,6 +288,7 @@ static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
enum alpnid not_this_one)
{
#ifdef USE_HTTPSRR
struct cf_hc_ctx *ctx = cf->ctx;
/* Is there an HTTPSRR use its ALPNs here.
* We are here after having selected a connection to a host+port and
* can no longer change that. Any HTTPSRR advice for other hosts and ports
@@ -304,9 +297,9 @@ static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
size_t i;
/* Do we have HTTPS-RR information? */
rr = Curl_conn_dns_get_https(
data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
rr = Curl_conn_dns_get_https(data, cf->sockindex, ctx->destination);
CURL_TRC_CF(data, cf, "HTTPS-RR %savailable", rr ? "" : "not ");
/* We do not support `rr->no_def_alpn`. */
if(Curl_httpsrr_applicable(data, rr) && !rr->no_def_alpn) {
for(i = 0; i < CURL_ARRAYSIZE(rr->alpns); ++i) {
@@ -485,6 +478,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
{
struct cf_hc_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
const struct curltime *pnow = NULL;
if(cf->connected) {
*done = TRUE;
@@ -495,7 +489,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
if(!ctx->httpsrr_resolved) {
ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(
data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
data, cf->sockindex, ctx->destination);
#ifdef DEBUGBUILD
if(!ctx->httpsrr_resolved && getenv("CURL_DBG_AWAIT_HTTPSRR")) {
CURL_TRC_CF(data, cf, "awaiting HTTPS-RR");
@@ -519,10 +513,12 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
goto out;
}
cf_hc_set_baller2(cf, data);
ctx->started = *Curl_pgrs_now(data);
pnow = Curl_pgrs_now(data);
ctx->started = *pnow;
cf_hc_baller_init(&ctx->ballers[0], cf, data);
if((ctx->baller_count > 1) || !ctx->ballers_complete) {
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
Curl_expire_set(data, EXPIRE_ALPN_EYEBALLS,
ctx->soft_eyeballs_timeout_ms, pnow);
}
ctx->state = CF_HC_CONNECT;
FALLTHROUGH();
@@ -539,7 +535,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
}
if(time_to_start_baller2(cf, data)) {
pnow = Curl_pgrs_now(data);
if(time_to_start_baller2(cf, data, pnow)) {
cf_hc_baller_init(&ctx->ballers[1], cf, data);
}
@@ -658,26 +655,6 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
return FALSE;
}
static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query)
{
struct cf_hc_ctx *ctx = cf->ctx;
struct curltime t, tmax;
size_t i;
memset(&tmax, 0, sizeof(tmax));
for(i = 0; i < ctx->baller_count; i++) {
struct Curl_cfilter *cfb = ctx->ballers[i].cf;
memset(&t, 0, sizeof(t));
if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0)
tmax = t;
}
}
return tmax;
}
static CURLcode cf_hc_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
@@ -687,16 +664,6 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
if(!cf->connected) {
switch(query) {
case CF_QUERY_TIMER_CONNECT: {
struct curltime *when = pres2;
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
return CURLE_OK;
}
case CF_QUERY_TIMER_APPCONNECT: {
struct curltime *when = pres2;
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
return CURLE_OK;
}
case CF_QUERY_NEED_FLUSH: {
for(i = 0; i < ctx->baller_count; i++)
if(cf_hc_baller_needs_flush(&ctx->ballers[i], data)) {
@@ -723,12 +690,26 @@ static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
size_t i;
if(!cf->connected) {
for(i = 0; i < ctx->baller_count; i++) {
result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2);
if(result && (result != CURLE_AGAIN))
goto out;
switch(event) {
case CF_CTRL_REPORT_STATS:
for(i = 0; i < ctx->baller_count; i++) {
/* Make the first baller that connected at network level report */
if(Curl_conn_cf_is_ip_connected(ctx->ballers[i].cf, data)) {
Curl_conn_cf_cntrl(ctx->ballers[i].cf, data, TRUE,
event, arg1, arg2);
break;
}
}
break;
default:
for(i = 0; i < ctx->baller_count; i++) {
result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2);
if(result && (result != CURLE_AGAIN))
goto out;
}
result = CURLE_OK;
break;
}
result = CURLE_OK;
}
out:
return result;
@@ -744,7 +725,7 @@ static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
struct Curl_cftype Curl_cft_http_connect = {
"HTTPS-CONNECT",
CF_TYPE_SETUP | CF_TYPE_HTTPSRR,
CF_TYPE_SETUP,
CURL_LOG_LVL_NONE,
cf_hc_destroy,
cf_hc_connect,
@@ -761,6 +742,7 @@ struct Curl_cftype Curl_cft_http_connect = {
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *destination,
uint8_t def_transport)
{
struct Curl_cfilter *cf = NULL;
@@ -772,6 +754,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
Curl_peer_link(&ctx->destination, destination);
ctx->def_transport = def_transport;
ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
@@ -788,25 +771,32 @@ out:
}
static CURLcode cf_hc_add(struct Curl_easy *data,
struct Curl_peer *destination,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
uint8_t def_transport)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
result = cf_hc_create(&cf, data, def_transport);
result = cf_hc_create(&cf, data, destination, def_transport);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
#ifdef USE_HTTPSRR
result = Curl_conn_dns_add_https_resolve(data, cf->conn, cf->sockindex,
destination);
#endif
out:
return result;
}
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct Curl_peer *destination,
struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
CURLcode result = CURLE_OK;
@@ -821,7 +811,8 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
!conn->bits.tls_enable_alpn)
goto out;
result = cf_hc_add(data, conn, sockindex, conn->transport_wanted);
result = cf_hc_add(data, destination, conn, sockindex,
conn->transport_wanted);
out:
return result;
+3 -1
View File
@@ -31,12 +31,14 @@ struct Curl_cfilter;
struct Curl_easy;
struct connectdata;
struct Curl_cftype;
struct Curl_peer;
extern struct Curl_cftype Curl_cft_http_connect;
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct Curl_peer *destination,
struct connectdata *conn,
int sockindex);
int8_t sockindex);
#endif /* !CURL_DISABLE_HTTP */
#endif /* HEADER_CURL_CF_HTTP_H */
+32 -67
View File
@@ -49,7 +49,6 @@
#include "urldata.h"
#include "connect.h"
#include "cfilters.h"
#include "cf-dns.h"
#include "cf-ip-happy.h"
#include "curl_addrinfo.h"
#include "curl_trc.h"
@@ -57,6 +56,7 @@
#include "progress.h"
#include "select.h"
#include "sockaddr.h"
#include "vdns/cf-dns.h"
#include "vquic/vquic.h" /* for quic cfilters */
@@ -165,7 +165,6 @@ struct cf_ip_attempt {
struct Curl_sockaddr_ex addr;
struct Curl_cfilter *cf; /* current sub-cfilter connecting */
cf_ip_connect_create *cf_create;
struct curltime started; /* start of current attempt */
CURLcode result;
int ai_family;
uint8_t transport_peer;
@@ -277,7 +276,6 @@ struct cf_ip_ballers {
struct Curl_peer *peer;
struct Curl_peer *tunnel_peer;
cf_ip_connect_create *cf_create; /* for creating cf */
struct curltime started;
struct curltime last_attempt_started;
timediff_t attempt_delay_ms;
int last_attempt_ai_family;
@@ -399,6 +397,7 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs,
bool do_more;
timediff_t next_expire_ms;
uint32_t inconclusive, ongoing;
const struct curltime *pnow = NULL;
VERBOSE(int i);
if(bs->winner)
@@ -409,7 +408,7 @@ evaluate:
/* check if a running baller connects now */
VERBOSE(i = -1);
for(panchor = &bs->running; *panchor; panchor = &((*panchor)->next)) {
for(panchor = &bs->running; *panchor; panchor = &(*panchor)->next) {
VERBOSE(++i);
a = *panchor;
a->result = cf_ip_attempt_connect(a, data, connected);
@@ -439,9 +438,8 @@ evaluate:
"%u ongoing, %u inconclusive", ongoing, inconclusive);
/* no attempt connected yet, start another one? */
pnow = Curl_pgrs_now(data);
if(!ongoing) {
if(!bs->started.tv_sec && !bs->started.tv_usec)
bs->started = *Curl_pgrs_now(data);
do_more = TRUE;
}
else {
@@ -451,7 +449,7 @@ evaluate:
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter, data);
#endif
do_more = more_possible &&
(curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started) >=
(curlx_ptimediff_ms(pnow, &bs->last_attempt_started) >=
bs->attempt_delay_ms);
if(do_more)
CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, "
@@ -509,9 +507,9 @@ evaluate:
/* append to running list */
panchor = &bs->running;
while(*panchor)
panchor = &((*panchor)->next);
panchor = &(*panchor)->next;
*panchor = a;
bs->last_attempt_started = *Curl_pgrs_now(data);
bs->last_attempt_started = *pnow;
bs->last_attempt_ai_family = ai_family;
/* and run everything again */
goto evaluate;
@@ -520,7 +518,7 @@ evaluate:
/* tried all addresses, no success but some where inconclusive.
* Let's restart the inconclusive ones. */
timediff_t since_ms =
curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started);
curlx_ptimediff_ms(pnow, &bs->last_attempt_started);
timediff_t delay_ms = bs->attempt_delay_ms - since_ms;
if(delay_ms <= 0) {
CURL_TRC_CF(data, cf, "all attempts inconclusive, restarting one");
@@ -533,7 +531,7 @@ evaluate:
CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, (int)result);
if(result) /* serious failure */
goto out;
bs->last_attempt_started = *Curl_pgrs_now(data);
bs->last_attempt_started = *pnow;
goto evaluate;
}
DEBUGASSERT(0); /* should not come here */
@@ -542,7 +540,7 @@ evaluate:
/* let's wait some more before restarting */
infof(data, "connect attempts inconclusive, retrying "
"in %" FMT_TIMEDIFF_T "ms", delay_ms);
Curl_expire(data, delay_ms, EXPIRE_HAPPY_EYEBALLS);
Curl_expire_set(data, EXPIRE_HAPPY_EYEBALLS, delay_ms, pnow);
}
/* attempt timeout for restart has not expired yet */
goto out;
@@ -565,11 +563,11 @@ out:
bool more_possible;
/* when do we need to be called again? */
next_expire_ms = Curl_timeleft_ms(data);
pnow = Curl_pgrs_now(data);
next_expire_ms = Curl_timeleft_now_ms(data, pnow);
if(next_expire_ms < 0) {
failf(data, "Connection timeout after %" FMT_OFF_T " ms",
curlx_ptimediff_ms(Curl_pgrs_now(data),
&data->progress.t_startsingle));
Curl_pgrs_since_ms(data, NULL, TIMER_STARTSINGLE));
return CURLE_OPERATION_TIMEDOUT;
}
@@ -580,8 +578,8 @@ out:
#endif
if(more_possible) {
timediff_t expire_ms, elapsed_ms;
elapsed_ms =
curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started);
elapsed_ms = curlx_ptimediff_ms(pnow, &bs->last_attempt_started);
expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0);
next_expire_ms = CURLMIN(next_expire_ms, expire_ms);
if(next_expire_ms <= 0) {
@@ -590,7 +588,7 @@ out:
}
CURL_TRC_CF(data, cf, "next HAPPY_EYEBALLS timeout in %" FMT_TIMEDIFF_T
"ms", next_expire_ms);
Curl_expire(data, next_expire_ms, EXPIRE_HAPPY_EYEBALLS);
Curl_expire_set(data, EXPIRE_HAPPY_EYEBALLS, next_expire_ms, pnow);
}
}
return result;
@@ -646,24 +644,6 @@ static bool cf_ip_ballers_pending(struct cf_ip_ballers *bs,
return FALSE;
}
static struct curltime cf_ip_ballers_max_time(struct cf_ip_ballers *bs,
struct Curl_easy *data,
int query)
{
struct curltime t, tmax;
struct cf_ip_attempt *a;
memset(&tmax, 0, sizeof(tmax));
for(a = bs->running; a; a = a->next) {
memset(&t, 0, sizeof(t));
if(a->cf && !a->cf->cft->query(a->cf, data, query, NULL, &t)) {
if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0)
tmax = t;
}
}
return tmax;
}
static int cf_ip_ballers_min_reply_ms(struct cf_ip_ballers *bs,
struct Curl_easy *data)
{
@@ -690,7 +670,6 @@ struct cf_ip_happy_ctx {
cf_ip_connect_create *cf_create;
cf_connect_state state;
struct cf_ip_ballers ballers;
struct curltime started;
BIT(dns_resolved);
};
@@ -741,8 +720,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
proxy_peer ? "over proxy " : "",
proxy_peer ? proxy_peer->hostname : "",
proxy_peer ? " " : "",
curlx_ptimediff_ms(Curl_pgrs_now(data),
&data->progress.t_startsingle),
Curl_pgrs_since_ms(data, NULL, TIMER_STARTSINGLE),
curl_easy_strerror(result));
#ifdef SOCKETIMEDOUT
@@ -783,7 +761,6 @@ static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "init ip ballers for transport %u",
ctx->ballers.transport_peer);
ctx->started = *Curl_pgrs_now(data);
return CURLE_OK;
}
@@ -857,7 +834,8 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
*done = FALSE;
if(!ctx->dns_resolved) {
result = Curl_conn_dns_result(cf->conn, cf->sockindex, ctx->ballers.peer);
result = Curl_conn_dns_addr_result(cf->conn, cf->sockindex,
ctx->ballers.peer);
if(!result)
ctx->dns_resolved = TRUE;
else if(result == CURLE_AGAIN) {
@@ -888,10 +866,6 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
cf->connected = TRUE;
cf->next = ctx->ballers.winner->cf;
ctx->ballers.winner->cf = NULL;
cf_ip_happy_ctx_clear(ctx, data);
Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
/* whatever errors were reported by ballers, clear our errorbuf */
Curl_reset_fail(data);
if(cf->conn->scheme->protocol & PROTO_FAMILY_SSH)
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
@@ -900,13 +874,16 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
struct ip_quadruple ipquad;
bool is_ipv6;
if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
const char *host;
Curl_conn_get_current_host(data, cf->sockindex, &host, NULL);
CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
host, ipquad.remote_ip, ipquad.remote_port);
ctx->ballers.peer->hostname,
ipquad.remote_ip, ipquad.remote_port);
}
}
#endif
cf_ip_happy_ctx_clear(ctx, data);
Curl_expire_clear(data, EXPIRE_HAPPY_EYEBALLS);
/* whatever errors were reported by ballers, clear our errorbuf */
Curl_reset_fail(data);
data->info.numconnects++; /* to track the # of connections made */
}
break;
@@ -942,18 +919,6 @@ static CURLcode cf_ip_happy_query(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1);
return CURLE_OK;
}
case CF_QUERY_TIMER_CONNECT: {
struct curltime *when = pres2;
*when = cf_ip_ballers_max_time(&ctx->ballers, data,
CF_QUERY_TIMER_CONNECT);
return CURLE_OK;
}
case CF_QUERY_TIMER_APPCONNECT: {
struct curltime *when = pres2;
*when = cf_ip_ballers_max_time(&ctx->ballers, data,
CF_QUERY_TIMER_APPCONNECT);
return CURLE_OK;
}
default:
break;
}
@@ -1031,13 +996,13 @@ out:
return result;
}
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
CURLcode Curl_cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
struct Curl_cfilter *cf;
CURLcode result;
+7 -7
View File
@@ -60,13 +60,13 @@ typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
* With a `tunnel_peer` present, the filter will be used to proxy tunnel
* to it and the tunnel will use `tunnel_transport`.
*/
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
CURLcode Curl_cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
extern struct Curl_cftype Curl_cft_ip_happy;
+1 -1
View File
@@ -137,7 +137,7 @@ out:
CURLcode Curl_cf_recvbuf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
const uint8_t *buf, size_t blen)
{
struct Curl_cfilter *cf;
+1 -1
View File
@@ -30,7 +30,7 @@
CURLcode Curl_cf_recvbuf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
const uint8_t *buf, size_t blen);
extern struct Curl_cftype Curl_cft_recvbuf;
+15 -12
View File
@@ -159,7 +159,7 @@ static CURLcode cf_setup_add_http_proxy(struct Curl_cfilter *cf,
/* Get the origin curl connects its socket to.
* Can be origin or the first proxy. */
static struct Curl_peer *conn_get_first_origin(struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
#ifndef CURL_DISABLE_PROXY
if(conn->socks_proxy.peer)
@@ -202,9 +202,9 @@ static CURLcode cf_setup_add_ip_happy(struct Curl_cfilter *cf,
}
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
result = cf_ip_happy_insert_after(cf, data, first_origin, first_peer,
first_transport,
tunnel_peer, ctx->transport);
result = Curl_cf_ip_happy_insert_after(cf, data, first_origin, first_peer,
first_transport,
tunnel_peer, ctx->transport);
if(result) {
CURL_TRC_CF(data, cf, "adding happy eyeballs failed -> %d", (int)result);
return result;
@@ -251,7 +251,7 @@ static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
(int)result);
return result;
}
result = Curl_cf_quic_insert_after(cf, origin, peer);
result = Curl_cf_quic_insert_after(cf, data, origin, peer);
if(result) {
CURL_TRC_CF(data, cf, "adding QUIC filter failed -> %d", (int)result);
return result;
@@ -273,12 +273,15 @@ static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
else
#endif
{
/* Another FTP quirk: when adding SSL verification, to a DATA
* connection, always verify against the control's origin */
struct Curl_peer *origin = Curl_conn_get_origin(cf->conn, FIRSTSOCKET);
struct Curl_peer *peer =
Curl_conn_get_destination(cf->conn, cf->sockindex);
result = Curl_cf_ssl_insert_after(cf, data, origin, peer);
/* FTP is a bitch. Wherever we really connect to on the DATA
* (secondary) connection, many servers require TLS sessions reuse
* to prove they are talking to the same client.
* For the TLS session lookup to work, we need to instantiate
* the SSL filter with the same peers as FIRSTSOCKET. See #22225
* Meaning: cf->sockindex does not matter here. */
result = Curl_cf_ssl_insert_after(cf, data,
Curl_conn_get_origin(cf->conn, FIRSTSOCKET),
Curl_conn_get_destination(cf->conn, FIRSTSOCKET));
}
if(result) {
CURL_TRC_CF(data, cf, "adding SSL filter for origin failed -> %d",
@@ -442,7 +445,7 @@ out:
CURLcode Curl_cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
uint8_t transport,
int ssl_mode)
{
+1 -1
View File
@@ -32,7 +32,7 @@ struct Curl_str;
CURLcode Curl_cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
uint8_t transport,
int ssl_mode);
+186 -75
View File
@@ -37,6 +37,9 @@
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@@ -75,23 +78,25 @@
#include "rand.h"
#include "sockaddr.h"
#include "curlx/strdup.h"
#include "system_win32.h"
#include "curlx/nonblock.h"
#include "curlx/strcopy.h"
#include "curlx/version_win32.h"
#include "curlx/strerr.h"
#include "curlx/strparse.h"
#ifdef _WIN32
#include <mstcpip.h> /* for TCP_INITIAL_RTO_PARAMETERS */
#endif
/* retrieves ip address and port from a sockaddr structure. note it calls
* curlx_inet_ntop which sets errno on fail, not SOCKERRNO.
* curlx_inet_ntop() and returns CURLcode.
* @unittest 1607
*/
UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port);
UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port)
UNITTEST CURLcode sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port);
UNITTEST CURLcode sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port)
{
CURLcode result;
struct sockaddr_in *si = NULL;
#ifdef USE_IPV6
struct sockaddr_in6 *si6 = NULL;
@@ -105,17 +110,21 @@ UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
switch(sa->sa_family) {
case AF_INET:
si = (struct sockaddr_in *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
result = curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr,
MAX_IPADR_LEN);
if(!result) {
*port = ntohs(si->sin_port);
return TRUE;
return result;
}
break;
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
result = curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
MAX_IPADR_LEN);
if(!result) {
*port = ntohs(si6->sin6_port);
return TRUE;
return result;
}
break;
#endif
@@ -128,16 +137,16 @@ UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
else
addr[0] = 0; /* socket with no name */
*port = 0;
return TRUE;
return CURLE_OK;
#endif
default:
result = CURLE_UNSUPPORTED_PROTOCOL;
break;
}
addr[0] = '\0';
*port = 0;
errno = SOCKEAFNOSUPPORT;
return FALSE;
return result;
}
static void tcpnodelay(struct Curl_cfilter *cf,
@@ -430,11 +439,12 @@ static CURLcode socket_open(struct Curl_easy *data,
* might have been changed and this 'new' address will actually be used
* here to connect.
*/
Curl_set_in_callback(data, TRUE);
struct Curl_mapi_guard guard;
CURL_CBAPI_START(&guard, data, easy_fopensocket);
*sockfd = data->set.fopensocket(data->set.opensocket_client,
CURLSOCKTYPE_IPCXN,
(struct curl_sockaddr *)addr);
Curl_set_in_callback(data, FALSE);
CURL_CBAPI_END(&guard);
}
else {
/* opensocket callback not set, so create the socket now */
@@ -521,11 +531,12 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
return 0;
if(use_callback && conn && conn->fclosesocket) {
struct Curl_mapi_guard guard;
int rc;
Curl_multi_will_close(data, sock);
Curl_set_in_callback(data, TRUE);
CURL_CBAPI_START(&guard, data, easy_closesocket);
rc = conn->fclosesocket(conn->closesocket_client, sock);
Curl_set_in_callback(data, FALSE);
CURL_CBAPI_END(&guard);
return rc;
}
@@ -647,9 +658,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
"random" */
/* how many port numbers to try to bind to, increasing one at a time */
int portnum = data->set.localportrange;
const char *dev = data->set.str[STRING_DEVICE];
const char *iface_input = data->set.str[STRING_INTERFACE];
const char *host_input = data->set.str[STRING_BINDHOST];
const char *dev = CURL_EASY_STR(data, STRING_DEVICE);
const char *iface_input = CURL_EASY_STR(data, STRING_INTERFACE);
const char *host_input = CURL_EASY_STR(data, STRING_BINDHOST);
const char *iface = iface_input ? iface_input : dev;
const char *host = host_input ? host_input : dev;
int sockerr;
@@ -979,6 +990,7 @@ struct cf_socket_ctx {
BIT(accepted); /* socket was accepted, not connected */
BIT(sock_connected); /* socket is "connected", e.g. in UDP */
BIT(active);
BIT(stats_reported);
};
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
@@ -1083,18 +1095,19 @@ static void set_local_ip(struct Curl_cfilter *cf,
/* TFTP does not connect, so it cannot get the IP like this */
struct Curl_sockaddr_storage ssloc;
curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
VERBOSE(char buffer[STRERROR_LEN]);
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(ctx->sock, (struct sockaddr *)&ssloc, &slen)) {
VERBOSE(char buffer[STRERROR_LEN]);
VERBOSE(int sockerr = SOCKERRNO);
infof(data, "getsockname() failed with errno %d: %s",
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
}
else if(!sockaddr2string((struct sockaddr *)&ssloc, slen,
ctx->ip.local_ip, &ctx->ip.local_port)) {
infof(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
else {
CURLcode result = sockaddr2string((struct sockaddr *)&ssloc, slen,
ctx->ip.local_ip, &ctx->ip.local_port);
if(result)
infof(data, "ssloc inet_ntop() failed with %d", (int)result);
}
}
#else
@@ -1106,21 +1119,17 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
CURLcode result;
/* store remote address and port used in this connection attempt */
ctx->ip.transport = ctx->transport;
if(!sockaddr2string(&ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
char buffer[STRERROR_LEN];
/* using bare errno instead of SOCKERRNO is safe here, because
sockaddr2string() calls curlx_inet_ntop(), and they both report failures
via errno (even on Windows builds). */
ctx->sockerr = errno;
result = sockaddr2string(&ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen,
ctx->ip.remote_ip, &ctx->ip.remote_port);
if(result) {
ctx->sockerr = SOCKEAFNOSUPPORT;
/* malformed address or bug in inet_ntop, try next address */
failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
failf(data, "curl_sa_addr inet_ntop() failed with %d", (int)result);
return CURLE_FAILED_INIT;
}
return CURLE_OK;
@@ -1133,12 +1142,56 @@ static int cf_socktype(int x)
#ifdef SOCK_CLOEXEC
x &= ~SOCK_CLOEXEC;
#endif
#ifdef SOCK_NONBLOCK
#ifdef CURL_USE_SOCK_NONBLOCK
x &= ~SOCK_NONBLOCK;
#endif
return x;
}
#ifdef _WIN32
/* Offered by mingw-w64 v10+, MS SDK 8.0/~VS2012+ */
#ifndef SIO_TCP_INITIAL_RTO
#define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR, 17)
#define TCP_INITIAL_RTO_DEFAULT_RTT 0
/* !checksrc! disable TYPEDEFSTRUCT 1 */
typedef struct _TCP_INITIAL_RTO_PARAMETERS {
USHORT Rtt;
UCHAR MaxSynRetransmissions;
} TCP_INITIAL_RTO_PARAMETERS;
#endif /* SIO_TCP_INITIAL_RTO */
#ifndef TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS
#define TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS 0xFE /* -2 */
#endif
static bool targets_localhost(struct cf_socket_ctx *ctx)
{
return (((ctx->addr.family == AF_INET) &&
!strcmp(ctx->ip.remote_ip, "127.0.0.1")) ||
((ctx->addr.family == AF_INET6) &&
!strcmp(ctx->ip.remote_ip, "::1")));
}
/* disable TCP SYN retransmissions for localhost connection on Windows to
detect problems faster */
static void tcplocalhost(struct Curl_cfilter *cf,
curl_socket_t sockfd)
{
if(targets_localhost(cf->ctx)) {
TCP_INITIAL_RTO_PARAMETERS rto;
DWORD bytes = 0;
memset(&rto, 0, sizeof(rto));
rto.Rtt = TCP_INITIAL_RTO_DEFAULT_RTT;
rto.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
(void)WSAIoctl(sockfd, SIO_TCP_INITIAL_RTO, &rto, sizeof(rto),
NULL, 0, &bytes, NULL, NULL);
}
}
#else
#define tcplocalhost(x, y)
#endif /* _WIN32 */
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1150,16 +1203,16 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
ctx->started_at = *Curl_pgrs_now(data);
#ifdef SOCK_NONBLOCK
#ifdef CURL_USE_SOCK_NONBLOCK
/* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
* because we would not know how socketype is about to be used in the
* because we would not know how socktype is about to be used in the
* callback, SOCK_NONBLOCK might get factored out before calling socket().
*/
if(!data->set.fopensocket)
ctx->addr.socktype |= SOCK_NONBLOCK;
#endif
result = socket_open(data, &ctx->addr, &ctx->sock);
#ifdef SOCK_NONBLOCK
#ifdef CURL_USE_SOCK_NONBLOCK
/* Restore the socktype after the socket is created. */
if(!data->set.fopensocket)
ctx->addr.socktype &= ~SOCK_NONBLOCK;
@@ -1212,19 +1265,24 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
is_tcp = (ctx->addr.family == AF_INET) &&
cf_socktype(ctx->addr.socktype) == SOCK_STREAM;
#endif
if(is_tcp && data->set.tcp_nodelay)
tcpnodelay(cf, data, ctx->sock);
if(is_tcp) {
if(data->set.tcp_nodelay)
tcpnodelay(cf, data, ctx->sock);
if(is_tcp && data->set.tcp_keepalive)
tcpkeepalive(cf, data, ctx->sock);
if(data->set.tcp_keepalive)
tcpkeepalive(cf, data, ctx->sock);
tcplocalhost(cf, ctx->sock);
}
if(data->set.fsockopt) {
/* activate callback for setting socket options */
Curl_set_in_callback(data, TRUE);
struct Curl_mapi_guard guard;
CURL_CBAPI_START(&guard, data, easy_fsockopt);
error = data->set.fsockopt(data->set.sockopt_client,
ctx->sock,
CURLSOCKTYPE_IPCXN);
Curl_set_in_callback(data, FALSE);
CURL_CBAPI_END(&guard);
if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
isconnected = TRUE;
@@ -1255,7 +1313,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
}
#endif
#ifndef SOCK_NONBLOCK
#ifndef CURL_USE_SOCK_NONBLOCK
/* Set socket non-blocking, must be a non-blocking socket for
* a non-blocking connect. */
error = curlx_nonblock(ctx->sock, TRUE);
@@ -1673,6 +1731,26 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
case CF_CTRL_FORGET_SOCKET:
ctx->sock = CURL_SOCKET_BAD;
break;
case CF_CTRL_REPORT_STATS:
if(cf->connected && !ctx->stats_reported) {
struct curltime *ts = NULL;
switch(ctx->transport) {
case TRNSPRT_UDP:
case TRNSPRT_QUIC:
/* Since UDP connected sockets work different from TCP, we use the
* time of the first byte from the peer as the "connect" time. */
if(ctx->got_first_byte)
ts = &ctx->first_byte_at;
break;
default:
ts = &ctx->connected_at;
break;
}
if(ts) {
Curl_pgrsTimeWas(data, TIMER_CONNECT, *ts);
ctx->stats_reported = TRUE;
}
}
}
return CURLE_OK;
}
@@ -1743,24 +1821,6 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
else
*pres1 = -1;
return CURLE_OK;
case CF_QUERY_TIMER_CONNECT: {
struct curltime *when = pres2;
switch(ctx->transport) {
case TRNSPRT_UDP:
case TRNSPRT_QUIC:
/* Since UDP connected sockets work different from TCP, we use the
* time of the first byte from the peer as the "connect" time. */
if(ctx->got_first_byte) {
*when = ctx->first_byte_at;
break;
}
FALLTHROUGH();
default:
*when = ctx->connected_at;
break;
}
return CURLE_OK;
}
case CF_QUERY_IP_INFO:
#ifdef USE_IPV6
*pres1 = (ctx->addr.family == AF_INET6);
@@ -1769,6 +1829,12 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
#endif
*(struct ip_quadruple *)pres2 = ctx->ip;
return CURLE_OK;
case CF_QUERY_REALLY_CONNECTED:
if(cf->cft != &Curl_cft_udp)
*pres1 = cf->connected;
else
*pres1 = ctx->got_first_byte;
return CURLE_OK;
default:
break;
}
@@ -1879,6 +1945,47 @@ static void linux_quic_gro(struct cf_socket_ctx *ctx)
#define linux_quic_gro(x)
#endif
#if (defined(__linux__) || defined(__APPLE__)) && defined(IP_RECVTOS)
static void linux_quic_ecn(struct cf_socket_ctx *ctx)
{
unsigned int tos = 1;
switch(ctx->addr.family) {
case AF_INET:
(void)setsockopt(ctx->sock, IPPROTO_IP, IP_RECVTOS, &tos, sizeof(tos));
break;
#ifdef IPV6_RECVTCLASS
case AF_INET6:
(void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_RECVTCLASS,
&tos, sizeof(tos));
break;
#endif
}
}
#else
#define linux_quic_ecn(x)
#endif
#if (defined(__linux__) || defined(__APPLE__)) && defined(IP_DONTFRAG)
static void linux_ip_dontfrag(struct cf_socket_ctx *ctx)
{
int val = 1;
switch(ctx->addr.family) {
case AF_INET:
(void)setsockopt(ctx->sock, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));
break;
#ifdef IPV6_DONTFRAG
case AF_INET6:
(void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_DONTFRAG,
&val, sizeof(val));
break;
#endif
}
}
#else
#define linux_ip_dontfrag(x)
#endif
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1908,7 +2015,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
* non-blocking socket created by cf_socket_open() to it. Thus, we
* do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
*/
linux_quic_ecn(ctx);
linux_quic_mtu(ctx);
linux_ip_dontfrag(ctx);
linux_quic_gro(ctx);
return CURLE_OK;
@@ -2102,7 +2211,7 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
{
struct cf_socket_ctx *ctx = cf->ctx;
#ifdef HAVE_GETPEERNAME
char buffer[STRERROR_LEN];
CURLcode result;
struct Curl_sockaddr_storage ssrem;
curl_socklen_t plen;
@@ -2111,15 +2220,16 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
plen = sizeof(ssrem);
memset(&ssrem, 0, plen);
if(getpeername(ctx->sock, (struct sockaddr *)&ssrem, &plen)) {
char buffer[STRERROR_LEN];
int sockerr = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
return;
}
if(!sockaddr2string((struct sockaddr *)&ssrem, plen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
result = sockaddr2string((struct sockaddr *)&ssrem, plen,
ctx->ip.remote_ip, &ctx->ip.remote_port);
if(result) {
failf(data, "ssrem inet_ntop() failed with %d", (int)result);
return;
}
#else
@@ -2231,13 +2341,14 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
if(data->set.fsockopt) {
struct Curl_mapi_guard guard;
int error = 0;
/* activate callback for setting socket options */
Curl_set_in_callback(data, TRUE);
CURL_CBAPI_START(&guard, data, easy_fsockopt);
error = data->set.fsockopt(data->set.sockopt_client,
ctx->sock, CURLSOCKTYPE_ACCEPT);
Curl_set_in_callback(data, FALSE);
CURL_CBAPI_END(&guard);
if(error)
return CURLE_ABORTED_BY_CALLBACK;
@@ -2265,7 +2376,7 @@ struct Curl_cftype Curl_cft_tcp_accept = {
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
struct connectdata *conn,
int sockindex, curl_socket_t *s)
int8_t sockindex, curl_socket_t *s)
{
CURLcode result;
struct Curl_cfilter *cf = NULL;
@@ -2305,7 +2416,7 @@ out:
}
bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
int sockindex)
int8_t sockindex)
{
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
while(cf) {
+2 -2
View File
@@ -122,7 +122,7 @@ CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
*/
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
curl_socket_t *s);
/**
@@ -130,7 +130,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
* Curl_conn_tcp_listen_set().
*/
bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
int sockindex);
int8_t sockindex);
/**
* Peek at the socket and remote ip/port the socket filter is using.
+88 -72
View File
@@ -128,7 +128,7 @@ CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
#ifdef CURLVERBOSE
void Curl_conn_trc_filters(struct Curl_easy *data,
int sockindex, const char *info)
int8_t sockindex, const char *info)
{
if(CURL_TRC_M_is_verbose(data) && data->conn) {
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
@@ -177,14 +177,15 @@ void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
}
void Curl_conn_cf_discard_all(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
struct connectdata *conn, int8_t sockindex)
{
struct curltime *pt = &conn->shutdown.start[sockindex];
memset(pt, 0, sizeof(*pt));
Curl_conn_cf_discard_chain(&conn->cfilter[sockindex], data);
}
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
CURLcode Curl_conn_shutdown(struct Curl_easy *data,
int8_t sockindex, bool *done)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
@@ -206,7 +207,7 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
}
*done = FALSE;
if(!Curl_shutdown_started(data, sockindex)) {
if(!Curl_shutdown_started(data->conn, sockindex)) {
Curl_shutdown_start(data, sockindex, 0);
}
else {
@@ -239,7 +240,7 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
return result;
}
CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
CURLcode Curl_cf_recv(struct Curl_easy *data, int8_t sockindex, char *buf,
size_t len, size_t *pnread)
{
struct Curl_cfilter *cf;
@@ -257,7 +258,7 @@ CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
return CURLE_FAILED_INIT;
}
CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
CURLcode Curl_cf_send(struct Curl_easy *data, int8_t sockindex,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten)
{
@@ -358,7 +359,7 @@ out:
void Curl_conn_cf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
struct Curl_cfilter *cf)
{
DEBUGASSERT(conn);
@@ -408,7 +409,7 @@ bool Curl_conn_cf_discard(struct Curl_cfilter **pcf,
found = TRUE;
break;
}
pprev = &((*pprev)->next);
pprev = &(*pprev)->next;
}
}
Curl_conn_cf_discard_chain(pcf, data);
@@ -450,9 +451,9 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
int event, int arg1, void *arg2)
{
CURLcode result = CURLE_OK;
size_t i;
int i;
for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
for(i = 0; i < (int)CURL_ARRAYSIZE(conn->cfilter); ++i) {
result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
event, arg1, arg2);
if(!ignore_result && result)
@@ -461,14 +462,34 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
return result;
}
bool Curl_conn_cf_is_ip_connected(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(cf) {
int value = 0;
if(!cf->cft->query(cf, data, CF_QUERY_REALLY_CONNECTED, &value, NULL))
return !!value;
}
return FALSE;
}
void Curl_conn_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn)
{
cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
}
void Curl_conn_cntrl_report_stats(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
{
if((unsigned)sockindex < CURL_ARRAYSIZE(conn->cfilter))
(void)Curl_conn_cf_cntrl(conn->cfilter[sockindex], data, TRUE,
CF_CTRL_REPORT_STATS, 0, NULL);
}
void Curl_conn_remove_setup_filters(struct Curl_easy *data,
int sockindex)
int8_t sockindex)
{
struct Curl_cfilter **anchor = &data->conn->cfilter[sockindex];
while(*anchor) {
@@ -485,14 +506,14 @@ void Curl_conn_remove_setup_filters(struct Curl_easy *data,
}
}
bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
bool Curl_conn_is_setup(struct connectdata *conn, int8_t sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
return !!conn->cfilter[sockindex];
}
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
bool Curl_conn_is_connected(struct connectdata *conn, int8_t sockindex)
{
struct Curl_cfilter *cf;
@@ -506,7 +527,7 @@ bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
return FALSE;
}
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int8_t sockindex)
{
struct Curl_cfilter *cf;
@@ -533,14 +554,14 @@ static bool cf_is_tunneling(struct Curl_cfilter *cf)
return FALSE;
}
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex)
bool Curl_conn_is_tunneling(struct connectdata *conn, int8_t sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
return conn ? cf_is_tunneling(conn->cfilter[sockindex]) : FALSE;
}
#else
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex)
bool Curl_conn_is_tunneling(struct connectdata *conn, int8_t sockindex)
{
(void)conn;
(void)sockindex;
@@ -561,7 +582,7 @@ static bool cf_is_ssl(struct Curl_cfilter *cf)
return FALSE;
}
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
bool Curl_conn_is_ssl(struct connectdata *conn, int8_t sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
@@ -569,7 +590,7 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
}
bool Curl_conn_get_ssl_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct connectdata *conn, int8_t sockindex,
int query,
struct curl_tlssessioninfo *info)
{
@@ -586,7 +607,7 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data,
}
CURLcode Curl_conn_get_ip_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct connectdata *conn, int8_t sockindex,
bool *is_ipv6, struct ip_quadruple *ipquad)
{
struct Curl_cfilter *cf;
@@ -596,15 +617,13 @@ CURLcode Curl_conn_get_ip_info(struct Curl_easy *data,
return Curl_conn_cf_get_ip_info(cf, data, is_ipv6, ipquad);
}
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
bool Curl_conn_is_multiplex(struct connectdata *conn, int8_t sockindex)
{
struct Curl_cfilter *cf;
if(!CONN_SOCK_IDX_VALID(sockindex))
if(!conn || !CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
cf = conn ? conn->cfilter[sockindex] : NULL;
for(; cf; cf = cf->next) {
for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_MULTIPLEX)
return TRUE;
if(cf->cft->flags & (CF_TYPE_IP_CONNECT | CF_TYPE_SSL))
@@ -644,17 +663,6 @@ int Curl_protocol_for_transport(uint8_t transport)
}
}
bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
(void)data;
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_HTTPSRR)
return TRUE;
}
return FALSE;
}
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -686,7 +694,7 @@ unsigned char Curl_conn_http_version(struct Curl_easy *data,
return (unsigned char)(result ? 0 : v);
}
bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
bool Curl_conn_data_pending(struct Curl_easy *data, int8_t sockindex)
{
struct Curl_cfilter *cf;
@@ -716,7 +724,7 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
return (result || !pending) ? FALSE : TRUE;
}
bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
bool Curl_conn_needs_flush(struct Curl_easy *data, int8_t sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
@@ -728,17 +736,17 @@ CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
/* Get the lowest not-connected filter, if there are any */
while(cf && !cf->connected && cf->next && !cf->next->connected)
cf = cf->next;
/* Skip all filters that have already shut down */
while(cf && cf->shutdown)
cf = cf->next;
/* From there on, give all filters a chance to adjust the pollset.
* Lower filters are called later, so they may override */
while(cf && !result) {
result = cf->cft->adjust_pollset(cf, data, ps);
cf = cf->next;
/* Go through all filters, top to bottom, and let them manage the pollset
* - connected filters can do so
* - CF_TYPE_DNS filters can
* - unconnected filters without next or connect next can
*/
for(; cf && !result; cf = cf->next) {
if(cf->shutdown)
continue;
if(cf->connected || (cf->cft->flags & CF_TYPE_DNS) ||
!cf->next || cf->next->connected)
result = cf->cft->adjust_pollset(cf, data, ps);
}
return result;
}
@@ -748,23 +756,29 @@ CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
int i;
bool want_io = !!ps->n;
int8_t i;
DEBUGASSERT(data);
DEBUGASSERT(conn);
/* During connect time, connection filters may add sockets to the pollset
* even when the transfer neither wants to send nor receive. And those
* sockets, when having events, are served.
* Once connected however, a transfer that neither wants to send nor receive
* sockets, when having events, are served. The same applies to a
* filter chain whose shutdown has started.
* Once a filter chain is connected however and before its shutdown
* starts, a transfer that neither wants to send nor receive
* will never call the connection filters. Any sockets added by the filters
* will not change state and POLLIN/POLLOUT events will trigger forever,
* making us busy loop. See #21671 */
if(ps->n || !Curl_conn_is_connected(conn, FIRSTSOCKET) ||
(conn->cfilter[SECONDARYSOCKET] &&
!Curl_conn_is_connected(conn, SECONDARYSOCKET))) {
for(i = 0; (i < 2) && !result && conn; ++i) {
* making us busy loop. See #21671.
* Gate each filter chain on its own state, so that one chain being in
* connect or shutdown does not add poll events for the other. Check
* against the transfer's own interest, before any chain added sockets
* of its own. */
for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) {
if(conn->cfilter[i] &&
(want_io || !Curl_conn_is_connected(conn, i) ||
Curl_shutdown_started(conn, i)))
result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
}
}
return result;
}
@@ -797,7 +811,7 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
return rc;
}
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
void Curl_conn_get_current_host(struct Curl_easy *data, int8_t sockindex,
const char **phost, int *pport)
{
struct Curl_cfilter *cf, *cf_proxy = NULL;
@@ -931,7 +945,7 @@ curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data)
}
const struct Curl_sockaddr_ex *Curl_conn_get_remote_addr(
struct Curl_easy *data, int sockindex)
struct Curl_easy *data, int8_t sockindex)
{
struct Curl_cfilter *cf =
(data->conn && CONN_SOCK_IDX_VALID(sockindex)) ?
@@ -944,7 +958,7 @@ CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
return cf_cntrl_all(data->conn, data, FALSE, CF_CTRL_DATA_SETUP, 0, NULL);
}
CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
CURLcode Curl_conn_flush(struct Curl_easy *data, int8_t sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -985,20 +999,22 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
}
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
struct connectdata *conn)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
int i;
if(!CONN_SOCK_IDX_VALID(sockindex))
return CURLE_BAD_FUNCTION_ARGUMENT;
cf = conn->cfilter[sockindex];
return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK;
for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) {
struct Curl_cfilter *cf = conn->cfilter[i];
if(cf)
result = cf->cft->keep_alive(cf, data);
}
return result;
}
size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
struct Curl_cfilter *cf;
CURLcode result;
@@ -1018,7 +1034,7 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
int Curl_conn_get_stream_error(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
struct Curl_cfilter *cf;
CURLcode result;
@@ -1033,7 +1049,7 @@ int Curl_conn_get_stream_error(struct Curl_easy *data,
return (result || n < 0) ? 0 : n;
}
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
int8_t Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
{
if(data && data->conn &&
sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
@@ -1041,7 +1057,7 @@ int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
return FIRSTSOCKET;
}
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
CURLcode Curl_conn_recv(struct Curl_easy *data, int8_t sockindex,
char *buf, size_t len, size_t *pnread)
{
DEBUGASSERT(data);
@@ -1054,7 +1070,7 @@ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
return CURLE_FAILED_INIT;
}
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
CURLcode Curl_conn_send(struct Curl_easy *data, int8_t sockindex,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
+47 -38
View File
@@ -121,6 +121,7 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
#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 */
#define CF_CTRL_REPORT_STATS (256 + 3) /* 0 NULL ignored */
/**
* Handle event/control for the filter.
@@ -156,13 +157,17 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
null-terminated string or NULL if none
selected/handshake not done. Implemented by filter
types CF_TYPE_SSL or CF_TYPE_IP_CONNECT.
* - CF_QUERY_REALLY_CONNECTED: implemented in socket filters to return
* if a reply from a server has really arrived. For
* non-UDP sockets this is TRUE when the socket became
* writable. For UDP sockets, this is TRUE when the
* first byte from the peer was received.
*/
/* query res1 res2 */
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
#define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
/* unused 4 + 5 */
#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 */
@@ -175,6 +180,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */
#define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */
#define CF_QUERY_ALPN_NEGOTIATED 15 /* - const char * */
#define CF_QUERY_REALLY_CONNECTED 16 /* TRUE/FALSE - */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -197,7 +203,7 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* CF_TYPE_HTTP implement a version of the HTTP protocol
* CF_TYPE_SETUP filter is only needed for connection setup and
* can be removed once connected
* CF_TYPE_HTTPSRR filter that wants HTTPS-RR information
* CF_TYPE_DNS filter managing DNS resolve operations
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
@@ -205,7 +211,7 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
#define CF_TYPE_PROXY (1 << 3)
#define CF_TYPE_HTTP (1 << 4)
#define CF_TYPE_SETUP (1 << 5)
#define CF_TYPE_HTTPSRR (1 << 6)
#define CF_TYPE_DNS (1 << 6)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
@@ -231,7 +237,7 @@ struct Curl_cfilter {
struct Curl_cfilter *next; /* next filter in chain */
void *ctx; /* filter type specific settings */
struct connectdata *conn; /* the connection this filter belongs to */
int sockindex; /* the index the filter is installed at */
int8_t sockindex; /* the index the filter is installed at */
BIT(connected); /* != 0 iff this filter is connected */
BIT(shutdown); /* != 0 iff this filter has shut down */
};
@@ -286,7 +292,7 @@ CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
*/
void Curl_conn_cf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
struct Curl_cfilter *cf);
/**
@@ -314,7 +320,7 @@ void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
* Remove and destroy all filters at chain `sockindex` on connection `conn`.
*/
void Curl_conn_cf_discard_all(struct Curl_easy *data,
struct connectdata *conn, int sockindex);
struct connectdata *conn, int8_t sockindex);
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -343,6 +349,9 @@ CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
struct Curl_easy *data);
bool Curl_conn_cf_is_ip_connected(struct Curl_cfilter *cf,
struct Curl_easy *data);
unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
struct Curl_easy *data);
@@ -352,10 +361,6 @@ int Curl_protocol_for_transport(uint8_t transport);
const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data);
/* The filter (or one of its sub-filters) wants HTTPS-RR information. */
bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
struct Curl_easy *data);
#define CURL_CF_SSL_DEFAULT (-1)
#define CURL_CF_SSL_DISABLE 0
#define CURL_CF_SSL_ENABLE 1
@@ -363,31 +368,31 @@ bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
/**
* Check if a filter chain at `sockindex` for connection `conn` exists.
*/
bool Curl_conn_is_setup(struct connectdata *conn, int sockindex);
bool Curl_conn_is_setup(struct connectdata *conn, int8_t sockindex);
/**
* Check if the filter chain at `sockindex` for connection `conn` is
* completely connected.
*/
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex);
bool Curl_conn_is_connected(struct connectdata *conn, int8_t sockindex);
/**
* Determine if we have reached the remote host on IP level, e.g.
* have a TCP connection. This turns TRUE before a possible SSL
* handshake has been started/done.
*/
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int8_t sockindex);
/**
* Determine if the connection is using SSL to the remote host
* (or will be once connected). This will return FALSE, if SSL
* is only used in proxying and not for the tunnel itself.
*/
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
bool Curl_conn_is_ssl(struct connectdata *conn, int8_t sockindex);
/* Determine if the connection has one or more proxy filters.
* e.g. is tunneling. */
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex);
bool Curl_conn_is_tunneling(struct connectdata *conn, int8_t sockindex);
/*
* Fill `info` with information about the TLS instance securing the connection
@@ -395,18 +400,18 @@ bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex);
* FALSE. 'query' should be CF_QUERY_SSL_INFO or CF_QUERY_SSL_CTX_INFO.
*/
bool Curl_conn_get_ssl_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct connectdata *conn, int8_t sockindex,
int query,
struct curl_tlssessioninfo *info);
CURLcode Curl_conn_get_ip_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct connectdata *conn, int8_t sockindex,
bool *is_ipv6, struct ip_quadruple *ipquad);
/**
* Connection provides multiplexing of easy handles at `socketindex`.
*/
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
bool Curl_conn_is_multiplex(struct connectdata *conn, int8_t sockindex);
/**
* Return the HTTP version used on the FIRSTSOCKET connection filters
@@ -426,33 +431,38 @@ const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
void Curl_conn_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn);
void Curl_conn_cntrl_report_stats(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
void Curl_conn_remove_setup_filters(struct Curl_easy *data,
int sockindex);
int8_t sockindex);
/**
* Shutdown the connection at `sockindex` non-blocking, using timeout
* from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
* Return CURLE_OK and *done == FALSE if not finished.
*/
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);
CURLcode Curl_conn_shutdown(struct Curl_easy *data,
int8_t sockindex, bool *done);
/**
* Return if data is pending in some connection filter at chain
* `sockindex` for connection `data->conn`.
*/
bool Curl_conn_data_pending(struct Curl_easy *data,
int sockindex);
int8_t 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);
bool Curl_conn_needs_flush(struct Curl_easy *data, int8_t sockindex);
/**
* Flush any pending data on the connection filters at chain `sockindex`.
*/
CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex);
CURLcode Curl_conn_flush(struct Curl_easy *data, int8_t sockindex);
/**
* Return the socket used on data's connection for FIRSTSOCKET,
@@ -463,12 +473,12 @@ curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data);
/* Return a pointer to the connected socket address or NULL. */
const struct Curl_sockaddr_ex *
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex);
Curl_conn_get_remote_addr(struct Curl_easy *data, int8_t sockindex);
/**
* Tell filters to forget about the socket at sockindex.
*/
void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
void Curl_conn_forget_socket(struct Curl_easy *data, int8_t sockindex);
/**
* Adjust the pollset for the filter chain starting at `cf`.
@@ -498,7 +508,7 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
* `data->conn`. Copy at most `len` bytes into `buf`. Return the
* actual number of bytes copied in `*pnread`or an error.
*/
CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
CURLcode Curl_cf_recv(struct Curl_easy *data, int8_t sockindex, char *buf,
size_t len, size_t *pnread);
/**
@@ -506,7 +516,7 @@ CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
* at connection `data->conn`. Return the actual number of bytes written
* in `*pnwritten` or on error.
*/
CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
CURLcode Curl_cf_send(struct Curl_easy *data, int8_t sockindex,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten);
@@ -562,11 +572,10 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
bool *input_pending);
/**
* Try to upkeep the connection filters at sockindex.
* Try to upkeep the connection filters.
*/
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
struct connectdata *conn);
/**
* Get the remote hostname and port that the connection is currently
@@ -576,7 +585,7 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
* During connect, when tunneling proxies are involved (http or socks),
* it will be the name and port the proxy currently negotiates with.
*/
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
void Curl_conn_get_current_host(struct Curl_easy *data, int8_t sockindex,
const char **phost, int *pport);
/**
@@ -585,18 +594,18 @@ void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
*/
size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
int8_t sockindex);
/**
* Get the underlying error code for a transfer stream or 0 if not known.
*/
int Curl_conn_get_stream_error(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
int8_t sockindex);
#ifdef CURLVERBOSE
void Curl_conn_trc_filters(struct Curl_easy *data,
int sockindex, const char *info);
int8_t sockindex, const char *info);
#endif
/**
@@ -604,20 +613,20 @@ void Curl_conn_trc_filters(struct Curl_easy *data,
* Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
* correct socket index.
*/
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
int8_t Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
/*
* Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
* Return CURLE_AGAIN iff blocked on receiving.
*/
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
CURLcode Curl_conn_recv(struct Curl_easy *data, int8_t sockindex,
char *buf, size_t len, size_t *pnread);
/*
* Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
* Return CURLE_AGAIN iff blocked on sending.
*/
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
CURLcode Curl_conn_send(struct Curl_easy *data, int8_t sockindex,
const void *buf, size_t len, bool eos,
size_t *pnwritten);
+299 -190
View File
@@ -42,7 +42,7 @@
do { \
if(c) { \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
Curl_share_lock((d), CURL_LOCK_DATA_CONNECT, \
Curl_share_lock_share((c)->share, (d), CURL_LOCK_DATA_CONNECT, \
CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(c)->locked); \
(c)->locked = TRUE; \
@@ -55,7 +55,7 @@
DEBUGASSERT((c)->locked); \
(c)->locked = FALSE; \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
Curl_share_unlock((d), CURL_LOCK_DATA_CONNECT); \
Curl_share_unlock_share((c)->share, (d), CURL_LOCK_DATA_CONNECT); \
} \
} while(0)
@@ -111,16 +111,12 @@ static void cpool_bundle_free_entry(void *freethis)
}
void Curl_cpool_init(struct cpool *cpool,
struct Curl_easy *idata,
struct Curl_share *share,
size_t size)
{
Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
curlx_str_key_compare, cpool_bundle_free_entry);
DEBUGASSERT(idata);
cpool->idata = idata;
cpool->share = share;
cpool->initialized = TRUE;
}
@@ -186,6 +182,8 @@ static void cpool_discard_conn(struct cpool *cpool,
struct connectdata *conn,
bool aborted)
{
struct cshutdn *cshutdn;
struct Curl_easy *admin;
bool done = FALSE;
DEBUGASSERT(data);
@@ -193,12 +191,13 @@ static void cpool_discard_conn(struct cpool *cpool,
DEBUGASSERT(cpool);
DEBUGASSERT(!conn->bits.in_cpool);
admin = Curl_get_admin(data);
/*
* If this connection is not marked to force-close, leave it open if there
* are other users of it
*/
if(CONN_INUSE(conn) && !aborted) {
CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
CURL_TRC_M(admin, "[CPOOL] not discarding #%" FMT_OFF_T
" still in use by %u transfers", conn->connection_id,
conn->attached_xfers);
return;
@@ -219,35 +218,36 @@ static void cpool_discard_conn(struct cpool *cpool,
done = TRUE;
if(!done) {
/* Attempt to shutdown the connection right away. */
Curl_cshutdn_run_once(cpool->idata, conn, &done);
Curl_conn_shutdown_once(admin, conn, &done);
}
if(done || !data->multi)
Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
cshutdn = Curl_cshutdn_get(data);
if(done || !cshutdn)
Curl_conn_terminate(admin, conn, FALSE);
else
Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
Curl_cshutdn_add(cshutdn, conn, cpool->num_conn);
}
void Curl_cpool_destroy(struct cpool *cpool)
void Curl_cpool_destroy(struct cpool *cpool, struct Curl_easy *admin)
{
if(cpool && cpool->initialized && cpool->idata) {
if(cpool && cpool->initialized && admin) {
struct connectdata *conn;
struct Curl_sigpipe_ctx pipe_ctx;
CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections",
CURL_TRC_M(admin, "%s[CPOOL] destroy, %zu connections",
cpool->share ? "[SHARE] " : "", cpool->num_conn);
/* Move all connections to the shutdown list */
sigpipe_init(&pipe_ctx);
CPOOL_LOCK(cpool, cpool->idata);
CPOOL_LOCK(cpool, admin);
conn = cpool_get_first(cpool);
if(conn)
sigpipe_apply(cpool->idata, &pipe_ctx);
sigpipe_apply(admin, &pipe_ctx);
while(conn) {
cpool_remove_conn(cpool, conn);
cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
cpool_discard_conn(cpool, admin, conn, FALSE);
conn = cpool_get_first(cpool);
}
CPOOL_UNLOCK(cpool, cpool->idata);
CPOOL_UNLOCK(cpool, admin);
sigpipe_restore(&pipe_ctx);
Curl_hash_destroy(&cpool->dest2bundle);
}
@@ -255,27 +255,31 @@ void Curl_cpool_destroy(struct cpool *cpool)
static struct cpool *cpool_get_instance(struct Curl_easy *data)
{
if(data) {
if(CURL_SHARE_KEEP_CONNECT(data->share))
return &data->share->cpool;
else if(data->multi_easy)
return &data->multi_easy->cpool;
else if(data->multi)
return &data->multi->cpool;
}
/* admin handles do not necessarily find the correct pool */
DEBUGASSERT(data->mid);
if(CURL_SHARE_KEEP_CONNECT(data->share))
return &data->share->cpool;
else if(data->multi_easy)
return &data->multi_easy->cpool;
else if(data->multi)
return &data->multi->cpool;
return NULL;
}
struct cpool *Curl_cpool_get_instance(struct Curl_easy *data)
{
return cpool_get_instance(data);
}
void Curl_cpool_xfer_init(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
DEBUGASSERT(cpool);
if(cpool) {
CPOOL_LOCK(cpool, data);
/* the identifier inside the connection cache */
data->id = cpool->next_easy_id++;
if(cpool->next_easy_id <= 0)
if(cpool->next_easy_id == CURL_OFF_T_MAX)
cpool->next_easy_id = 0;
data->state.lastconnect_id = -1;
@@ -283,6 +287,7 @@ void Curl_cpool_xfer_init(struct Curl_easy *data)
}
else {
/* We should not get here, but in a non-debug build, do something */
DEBUGASSERT(0);
data->id = 0;
data->state.lastconnect_id = -1;
}
@@ -334,15 +339,16 @@ static struct connectdata *cpool_bundle_get_oldest_idle(
}
static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
const struct curltime *pnow)
const struct curltime *pnow,
timediff_t min_age_ms)
{
struct Curl_hash_iterator iter;
struct Curl_llist_node *curr;
struct Curl_hash_element *he;
struct connectdata *oldest_idle = NULL;
struct cpool_bundle *bundle;
timediff_t highscore = -1;
timediff_t score;
struct connectdata *oldest_idle = NULL;
timediff_t oldest_idle_ms = -1;
timediff_t idle_ms;
Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
@@ -356,10 +362,9 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
conn = Curl_node_elem(curr);
if(CONN_INUSE(conn) || conn->bits.close || conn->bits.connect_only)
continue;
/* Set higher score for the age passed since the connection was used */
score = curlx_ptimediff_ms(pnow, &conn->lastused);
if(score > highscore) {
highscore = score;
idle_ms = curlx_ptimediff_ms(pnow, &conn->lastused);
if((idle_ms >= min_age_ms) && (idle_ms > oldest_idle_ms)) {
oldest_idle_ms = idle_ms;
oldest_idle = conn;
}
}
@@ -367,10 +372,91 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
return oldest_idle;
}
int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *conn)
static void cpool_conn_close(struct cpool *cpool,
struct Curl_easy *data,
struct connectdata *conn,
bool aborted)
{
struct Curl_easy *admin;
bool do_lock;
DEBUGASSERT(cpool);
DEBUGASSERT(data && !data->conn);
if(!cpool)
return;
/* If this connection is not marked to force-close, leave it open if there
* are other users of it */
if(CONN_INUSE(conn) && !aborted) {
DEBUGASSERT(0); /* does this ever happen? */
DEBUGF(infof(data, "conn terminate when inuse: %u", conn->attached_xfers));
return;
}
/* This method may be called while we are under lock, e.g. from a
* user callback in find. */
admin = Curl_get_admin(data);
do_lock = !CPOOL_IS_LOCKED(cpool);
if(do_lock)
CPOOL_LOCK(cpool, admin);
if(conn->bits.in_cpool) {
cpool_remove_conn(cpool, conn);
DEBUGASSERT(!conn->bits.in_cpool);
}
/* treat the connection as aborted in CONNECT_ONLY situations,
* so no graceful shutdown is attempted. */
if(conn->bits.connect_only)
aborted = TRUE;
if(data->multi) {
/* Add it to the multi's cpool for shutdown handling */
infof(data, "%s connection #%" FMT_OFF_T,
aborted ? "closing" : "shutting down", conn->connection_id);
cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
}
else {
/* No multi available, terminate */
infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
Curl_conn_terminate(admin, conn, !aborted);
}
if(do_lock)
CPOOL_UNLOCK(cpool, admin);
}
void Curl_conn_close(struct Curl_easy *data,
struct connectdata *conn,
bool aborted)
{
struct cpool *cpool = cpool_get_instance(data);
cpool_conn_close(cpool, data, conn, aborted);
}
/* Evict an idle connection to make room in the pool. A pool owned by
* a share has no multi that could perform a controlled shutdown of the
* connection; terminate it right away. Otherwise, hand it to the
* transfer's multi for shutdown. Expects the pool to be locked. */
static void cpool_evict_conn(struct cpool *cpool,
struct Curl_easy *admin,
struct connectdata *conn)
{
if(cpool->share) {
cpool_remove_conn(cpool, conn);
Curl_conn_terminate(admin, conn, TRUE);
}
else
cpool_conn_close(cpool, admin, conn, FALSE);
}
int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *conn,
const struct curltime *pnow)
{
struct cpool *cpool = cpool_get_instance(data);
struct cshutdn *cshutdn = Curl_cshutdn_get(data);
struct Curl_easy *admin;
struct cpool_bundle *bundle;
size_t dest_limit = 0;
size_t total_limit = 0;
@@ -380,25 +466,27 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!cpool)
return CPOOL_LIMIT_OK;
if(cpool->idata->multi) {
dest_limit = cpool->idata->multi->max_host_connections;
total_limit = cpool->idata->multi->max_total_connections;
/* multi determines the limits, no matter who owns the pool */
if(data->multi) {
dest_limit = data->multi->max_host_connections;
total_limit = data->multi->max_total_connections;
}
if(!dest_limit && !total_limit)
return CPOOL_LIMIT_OK;
CPOOL_LOCK(cpool, cpool->idata);
admin = Curl_get_admin(data);
CPOOL_LOCK(cpool, admin);
if(dest_limit) {
size_t live;
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
shutdowns = Curl_cshutdn_dest_count(data, conn->destination);
shutdowns = Curl_cshutdn_dest_count(cshutdn, conn->destination);
while((live + shutdowns) >= dest_limit) {
if(shutdowns) {
/* close one connection in shutdown right away, if we can */
if(!Curl_cshutdn_close_oldest(data, conn->destination))
if(!Curl_cshutdn_close_oldest(cshutdn, conn->destination))
break;
}
else if(!bundle)
@@ -407,22 +495,21 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *oldest_idle = NULL;
/* The bundle is full. Extract the oldest connection that may
* be removed now, if there is one. */
oldest_idle = cpool_bundle_get_oldest_idle(bundle,
Curl_pgrs_now(data));
oldest_idle = cpool_bundle_get_oldest_idle(bundle, pnow);
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
CURL_TRC_M(data, "Discarding connection #%" FMT_OFF_T
CURL_TRC_M(admin, "Discarding connection #%" FMT_OFF_T
" from %zu to reach destination limit of %zu",
oldest_idle->connection_id,
Curl_llist_count(&bundle->conns), dest_limit);
Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
cpool_evict_conn(cpool, admin, oldest_idle);
/* in case the bundle was destroyed in disconnect, look it up again */
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
}
shutdowns = Curl_cshutdn_dest_count(cpool->idata, conn->destination);
shutdowns = Curl_cshutdn_dest_count(cshutdn, conn->destination);
}
if((live + shutdowns) >= dest_limit) {
res = CPOOL_LIMIT_DEST;
@@ -431,26 +518,26 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
if(total_limit) {
shutdowns = Curl_cshutdn_count(cpool->idata);
shutdowns = Curl_cshutdn_count(cshutdn);
while((cpool->num_conn + shutdowns) >= total_limit) {
if(shutdowns) {
/* close one connection in shutdown right away, if we can */
if(!Curl_cshutdn_close_oldest(data, NULL))
if(!Curl_cshutdn_close_oldest(cshutdn, NULL))
break;
}
else {
struct connectdata *oldest_idle =
cpool_get_oldest_idle(cpool, Curl_pgrs_now(data));
cpool_get_oldest_idle(cpool, pnow, 0);
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
CURL_TRC_M(data, "Discarding connection #%"
CURL_TRC_M(admin, "Discarding connection #%"
FMT_OFF_T " from %zu to reach total "
"limit of %zu",
oldest_idle->connection_id, cpool->num_conn, total_limit);
Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
cpool_evict_conn(cpool, admin, oldest_idle);
}
shutdowns = Curl_cshutdn_count(cpool->idata);
shutdowns = Curl_cshutdn_count(cshutdn);
}
if((cpool->num_conn + shutdowns) >= total_limit) {
res = CPOOL_LIMIT_TOTAL;
@@ -459,7 +546,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
out:
CPOOL_UNLOCK(cpool, cpool->idata);
CPOOL_UNLOCK(cpool, admin);
return res;
}
@@ -512,7 +599,8 @@ out:
static bool cpool_foreach(struct Curl_easy *data,
struct cpool *cpool,
void *param,
int (*func)(struct Curl_easy *data,
int (*func)(struct cpool *cpool,
struct Curl_easy *data,
struct connectdata *conn, void *param))
{
struct Curl_hash_iterator iter;
@@ -536,7 +624,7 @@ static bool cpool_foreach(struct Curl_easy *data,
struct connectdata *conn = Curl_node_elem(curr);
curr = Curl_node_next(curr);
if(func(data, conn, param) == 1) {
if(func(cpool, data, conn, param) == 1) {
return TRUE;
}
}
@@ -556,37 +644,46 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
unsigned int maxconnects;
struct connectdata *oldest_idle = NULL;
struct cpool *cpool = cpool_get_instance(data);
struct Curl_easy *admin;
bool kept = TRUE;
timediff_t min_age_ms = 0;
if(!data || !data->multi)
return kept;
if(!data->multi->maxconnects) {
unsigned int running = Curl_multi_xfers_running(data->multi);
maxconnects = (running <= UINT_MAX / 4) ? running * 4 : UINT_MAX;
/* Attached transfers is a weak indicator of business. */
uint32_t attached = Curl_multi_xfers_attached(data->multi);
maxconnects = (attached <= UINT_MAX / 2) ? attached * 2 : UINT_MAX;
/* We are guessing. So, only evict a "seemingly superfluous" connection
* when has not been used for this long, */
min_age_ms = 1000;
}
else {
maxconnects = data->multi->maxconnects;
}
conn->lastused = *Curl_pgrs_now(data); /* it was used up until now */
/* remember times, connection had been used just before */
conn->lastchecked = conn->lastupkeep = conn->lastused = *Curl_pgrs_now(data);
if(cpool && maxconnects) {
/* may be called form a callback already under lock */
bool do_lock = !CPOOL_IS_LOCKED(cpool);
admin = Curl_get_admin(data);
if(do_lock)
CPOOL_LOCK(cpool, data);
CPOOL_LOCK(cpool, admin);
if(cpool->num_conn > maxconnects) {
infof(data, "Connection pool is full, closing the oldest of %zu/%u",
cpool->num_conn, maxconnects);
oldest_idle = cpool_get_oldest_idle(cpool, Curl_pgrs_now(data));
oldest_idle = cpool_get_oldest_idle(cpool, &conn->lastused, min_age_ms);
kept = (oldest_idle != conn);
if(oldest_idle) {
Curl_conn_terminate(data, oldest_idle, FALSE);
cpool_evict_conn(cpool, admin, oldest_idle);
}
}
if(do_lock)
CPOOL_UNLOCK(cpool, data);
CPOOL_UNLOCK(cpool, admin);
}
return kept;
@@ -632,78 +729,25 @@ bool Curl_cpool_find(struct Curl_easy *data,
return found;
}
void Curl_conn_terminate(struct Curl_easy *data,
struct connectdata *conn,
bool aborted)
{
struct cpool *cpool = cpool_get_instance(data);
bool do_lock;
DEBUGASSERT(cpool);
DEBUGASSERT(data && !data->conn);
if(!cpool)
return;
/* If this connection is not marked to force-close, leave it open if there
* are other users of it */
if(CONN_INUSE(conn) && !aborted) {
DEBUGASSERT(0); /* does this ever happen? */
DEBUGF(infof(data, "conn terminate when inuse: %u", conn->attached_xfers));
return;
}
/* This method may be called while we are under lock, e.g. from a
* user callback in find. */
do_lock = !CPOOL_IS_LOCKED(cpool);
if(do_lock)
CPOOL_LOCK(cpool, data);
if(conn->bits.in_cpool) {
cpool_remove_conn(cpool, conn);
DEBUGASSERT(!conn->bits.in_cpool);
}
/* treat the connection as aborted in CONNECT_ONLY situations,
* so no graceful shutdown is attempted. */
if(conn->bits.connect_only)
aborted = TRUE;
if(data->multi) {
/* Add it to the multi's cpool for shutdown handling */
infof(data, "%s connection #%" FMT_OFF_T,
aborted ? "closing" : "shutting down", conn->connection_id);
cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
}
else {
/* No multi available, terminate */
infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
Curl_cshutdn_terminate(cpool->idata, conn, !aborted);
}
if(do_lock)
CPOOL_UNLOCK(cpool, data);
}
struct cpool_reaper_ctx {
size_t checked;
size_t reaped;
struct curltime now;
};
static int cpool_reap_dead_cb(struct Curl_easy *data,
static int cpool_reap_dead_cb(struct cpool *cpool,
struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
struct cpool_reaper_ctx *reaper = param;
bool terminate = !CONN_INUSE(conn) && conn->bits.no_reuse;
if(!terminate) {
reaper->checked++;
terminate = Curl_conn_seems_dead(conn, data);
}
if(terminate) {
/* stop the iteration here, pass back the connection that was pruned */
reaper->reaped++;
Curl_conn_terminate(data, conn, FALSE);
return 1;
if(!CONN_INUSE(conn)) {
if(conn->bits.no_reuse || conn->bits.close ||
!Curl_cpool_conn_seems_healthy(conn, admin, &reaper->now)) {
/* terminate conn and stop the iteration */
reaper->reaped++;
cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
}
return 0; /* continue iteration */
}
@@ -715,46 +759,69 @@ static int cpool_reap_dead_cb(struct Curl_easy *data,
*
* When called, this transfer has no connection attached.
*/
void Curl_cpool_prune_dead(struct Curl_easy *data)
void Curl_cpool_prune_dead(struct cpool *cpool,
struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
struct cpool_reaper_ctx reaper;
struct Curl_easy *admin;
timediff_t elapsed;
if(!cpool)
return;
memset(&reaper, 0, sizeof(reaper));
CPOOL_LOCK(cpool, data);
elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), &cpool->last_cleanup);
admin = Curl_get_admin(data);
CPOOL_LOCK(cpool, admin);
elapsed = curlx_ptimediff_ms(Curl_pgrs_now(admin), &cpool->last_cleanup);
if(elapsed >= 1000L) {
while(cpool_foreach(data, cpool, &reaper, cpool_reap_dead_cb))
struct cpool_reaper_ctx reaper;
memset(&reaper, 0, sizeof(reaper));
reaper.now = *Curl_pgrs_now(admin);
while(cpool_foreach(admin, cpool, &reaper, cpool_reap_dead_cb))
;
cpool->last_cleanup = *Curl_pgrs_now(data);
cpool->last_cleanup = *Curl_pgrs_now(admin);
}
CPOOL_UNLOCK(cpool, data);
CPOOL_UNLOCK(cpool, admin);
}
static int conn_upkeep(struct Curl_easy *data,
static int conn_upkeep(struct cpool *cpool,
struct Curl_easy *admin,
struct connectdata *conn,
void *param)
{
const struct curltime *pnow = Curl_pgrs_now(admin);
(void)param;
Curl_conn_upkeep(data, conn);
if(curlx_ptimediff_ms(pnow, &conn->lastupkeep) >=
admin->set.upkeep_interval_ms) {
CURLcode result;
conn->lastupkeep = *pnow;
/* briefly attach for action */
Curl_attach_connection(admin, conn, FALSE);
result = Curl_conn_keep_alive(admin, conn);
Curl_detach_connection(admin);
if(result && !CONN_INUSE(conn)) {
cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
}
return 0; /* continue iteration */
}
CURLcode Curl_cpool_upkeep(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
struct Curl_easy *admin = Curl_get_admin(data);
if(!cpool)
return CURLE_OK;
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, NULL, conn_upkeep);
CPOOL_UNLOCK(cpool, data);
CPOOL_LOCK(cpool, admin);
while(cpool_foreach(admin, cpool, NULL, conn_upkeep))
;
CPOOL_UNLOCK(cpool, admin);
return CURLE_OK;
}
@@ -763,10 +830,12 @@ struct cpool_find_ctx {
struct connectdata *conn;
};
static int cpool_find_conn(struct Curl_easy *data,
static int cpool_find_conn(struct cpool *cpool,
struct Curl_easy *data,
struct connectdata *conn, void *param)
{
struct cpool_find_ctx *fctx = param;
(void)cpool;
(void)data;
if(conn->connection_id == fctx->id) {
fctx->conn = conn;
@@ -791,40 +860,6 @@ struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
return fctx.conn;
}
struct cpool_do_conn_ctx {
curl_off_t id;
Curl_cpool_conn_do_cb *cb;
void *cbdata;
};
static int cpool_do_conn(struct Curl_easy *data,
struct connectdata *conn, void *param)
{
struct cpool_do_conn_ctx *dctx = param;
if(conn->connection_id == dctx->id) {
dctx->cb(conn, data, dctx->cbdata);
return 1;
}
return 0;
}
void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
Curl_cpool_conn_do_cb *cb, void *cbdata)
{
struct cpool *cpool = cpool_get_instance(data);
struct cpool_do_conn_ctx dctx;
if(!cpool)
return;
dctx.id = conn_id;
dctx.cb = cb;
dctx.cbdata = cbdata;
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &dctx, cpool_do_conn);
CPOOL_UNLOCK(cpool, data);
}
void Curl_cpool_do_locked(struct Curl_easy *data,
struct connectdata *conn,
Curl_cpool_conn_do_cb *cb, void *cbdata)
@@ -839,39 +874,113 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
cb(conn, data, cbdata);
}
static int cpool_mark_stale(struct Curl_easy *data,
static int cpool_mark_stale(struct cpool *cpool,
struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
(void)data;
(void)cpool;
(void)admin;
(void)param;
conn->bits.no_reuse = TRUE;
return 0;
}
static int cpool_reap_no_reuse(struct Curl_easy *data,
static int cpool_reap_no_reuse(struct cpool *cpool,
struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
(void)param;
if(!CONN_INUSE(conn) && conn->bits.no_reuse) {
Curl_conn_terminate(data, conn, FALSE);
cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
return 0; /* continue iteration */
}
void Curl_cpool_nw_changed(struct Curl_easy *data)
void Curl_cpool_nw_changed(struct cpool *cpool, struct Curl_easy *admin)
{
struct cpool *cpool = cpool_get_instance(data);
if(cpool) {
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, NULL, cpool_mark_stale);
while(cpool_foreach(data, cpool, NULL, cpool_reap_no_reuse))
if(cpool && admin) {
CPOOL_LOCK(cpool, admin);
cpool_foreach(admin, cpool, NULL, cpool_mark_stale);
while(cpool_foreach(admin, cpool, NULL, cpool_reap_no_reuse))
;
CPOOL_UNLOCK(cpool, data);
CPOOL_UNLOCK(cpool, admin);
}
}
/* A connection has to have been idle for less than 'conn_max_idle_ms'
(the success rate is too low after this), or created less than
'conn_max_age_ms' ago, to be subject for reuse. */
static bool cpool_conn_maxage(struct Curl_easy *data,
struct connectdata *conn,
const struct curltime *pnow)
{
timediff_t age_ms;
if(data->set.conn_max_idle_ms) {
age_ms = curlx_ptimediff_ms(pnow, &conn->lastused);
if(age_ms > data->set.conn_max_idle_ms) {
infof(data, "Too old connection (%" FMT_TIMEDIFF_T
" ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it",
age_ms, data->set.conn_max_idle_ms);
return TRUE;
}
}
if(data->set.conn_max_age_ms) {
age_ms = curlx_ptimediff_ms(pnow, &conn->created);
if(age_ms > data->set.conn_max_age_ms) {
infof(data,
"Too old connection (created %" FMT_TIMEDIFF_T
" ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it",
age_ms, data->set.conn_max_age_ms);
return TRUE;
}
}
return FALSE;
}
bool Curl_cpool_conn_seems_healthy(struct connectdata *conn,
struct Curl_easy *data,
const struct curltime *pnow)
{
struct Curl_easy *admin;
bool healthy = TRUE;
DEBUGASSERT(!data->conn);
if(!CONN_INUSE(conn) && cpool_conn_maxage(data, conn, pnow)) /* too old? */
return FALSE;
if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000)
return TRUE;
admin = Curl_get_admin(data);
if(conn->scheme->run->connection_is_dead) {
Curl_attach_connection(admin, conn, FALSE);
healthy = !conn->scheme->run->connection_is_dead(admin, conn);
Curl_detach_connection(admin);
}
else {
bool input_pending = FALSE;
Curl_attach_connection(admin, conn, FALSE);
healthy = Curl_conn_is_alive(admin, conn, &input_pending);
Curl_detach_connection(admin);
if(healthy && input_pending &&
!CONN_INUSE(conn) && !Curl_conn_is_multiplex(conn, FIRSTSOCKET)) {
/* Non-multiplexed connections without attached transfers should
* not have input pending. The input might be a TLS Notify Close,
* for all we know. */
DEBUGF(infof(data, "connection has no transfer but input, not healthy"));
healthy = FALSE;
}
}
if(healthy)
conn->lastchecked = *pnow;
return healthy;
}
#if 0
/* Useful for debugging the connection pool */
void Curl_cpool_print(struct cpool *cpool)
+21 -21
View File
@@ -34,7 +34,7 @@ struct Curl_multi;
struct Curl_share;
/**
* Terminate the connection, e.g. close and destroy.
* Close and destroy the connection.
* If the connection is in a cpool, remove it.
* If a `cshutdn` is available (e.g. data has a multi handle),
* pass the connection to that for controlled shutdown.
@@ -42,9 +42,9 @@ struct Curl_share;
* Takes ownership of `conn`.
* `data` should not be attached to a connection.
*/
void Curl_conn_terminate(struct Curl_easy *data,
struct connectdata *conn,
bool aborted);
void Curl_conn_close(struct Curl_easy *data,
struct connectdata *conn,
bool aborted);
struct cpool {
/* the pooled connections, bundled per destination */
@@ -53,22 +53,24 @@ struct cpool {
curl_off_t next_connection_id;
curl_off_t next_easy_id;
struct curltime last_cleanup;
struct Curl_easy *idata; /* internal handle for maintenance */
struct Curl_share *share; /* != NULL if pool belongs to share */
BIT(locked);
BIT(initialized);
};
/* Get connection pool instance for data or NULL if none exists */
struct cpool *Curl_cpool_get_instance(struct Curl_easy *data);
/* Init the pool, pass multi only if pool is owned by it.
* Cannot fail.
*/
void Curl_cpool_init(struct cpool *cpool,
struct Curl_easy *idata,
struct Curl_share *share,
size_t size);
/* Destroy all connections and free all members */
void Curl_cpool_destroy(struct cpool *cpool);
void Curl_cpool_destroy(struct cpool *cpool,
struct Curl_easy *admin);
/* Init the transfer to be used within its connection pool.
* Assigns `data->id`. */
@@ -91,7 +93,8 @@ CURLcode Curl_cpool_add(struct Curl_easy *data,
#define CPOOL_LIMIT_DEST 1
#define CPOOL_LIMIT_TOTAL 2
int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *conn);
struct connectdata *conn,
const struct curltime *pnow);
/* Return of conn is suitable. If so, stops iteration. */
typedef bool Curl_cpool_conn_match_cb(struct connectdata *conn,
@@ -126,13 +129,12 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
struct connectdata *conn);
/**
* This function scans the data's connection pool for half-open/dead
* Scans the 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);
void Curl_cpool_prune_dead(struct cpool *cpool,
struct Curl_easy *data);
/**
* Perform upkeep actions on connections in the transfer's pool.
@@ -143,14 +145,6 @@ 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.
@@ -162,6 +156,12 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
Curl_cpool_conn_do_cb *cb, void *cbdata);
/* Close all unused connections, prevent reuse of existing ones. */
void Curl_cpool_nw_changed(struct Curl_easy *data);
void Curl_cpool_nw_changed(struct cpool *cpool, struct Curl_easy *admin);
/* Return TRUE iff the given connection is considered healthy, e.g.
* usable for more transfers. */
bool Curl_cpool_conn_seems_healthy(struct connectdata *conn,
struct Curl_easy *data,
const struct curltime *pnow);
#endif /* HEADER_CURL_CONNCACHE_H */
+69 -80
View File
@@ -28,7 +28,6 @@
#include "strerror.h"
#include "cfilters.h"
#include "connect.h"
#include "cf-dns.h"
#include "cf-https-connect.h"
#include "cf-setup.h"
#include "multiif.h"
@@ -36,6 +35,7 @@
#include "conncache.h"
#include "multihandle.h"
#include "select.h"
#include "vdns/cf-dns.h"
#include "curlx/strparse.h"
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
@@ -57,12 +57,6 @@ enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len)
return ALPN_none; /* unknown, probably rubbish input */
}
enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
{
return Curl_alpn2alpnid((const unsigned char *)curlx_str(cstr),
curlx_strlen(cstr));
}
#endif
/*
@@ -81,13 +75,13 @@ UNITTEST timediff_t timeleft_now_ms(struct Curl_easy *data,
timediff_t timeleft_ms = 0;
timediff_t ctimeleft_ms = 0;
if(Curl_shutdown_started(data, FIRSTSOCKET))
if(data->conn && Curl_shutdown_started(data->conn, FIRSTSOCKET))
return Curl_shutdown_timeleft(data, data->conn, FIRSTSOCKET);
else if(Curl_is_connecting(data)) {
timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
ctimeleft_ms = ctimeout_ms -
curlx_ptimediff_ms(pnow, &data->progress.t_startsingle);
Curl_pgrs_since_ms(data, pnow, TIMER_STARTSINGLE);
if(!ctimeleft_ms)
ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
}
@@ -97,7 +91,7 @@ UNITTEST timediff_t timeleft_now_ms(struct Curl_easy *data,
if(data->set.timeout) {
timeleft_ms = data->set.timeout -
curlx_ptimediff_ms(pnow, &data->progress.t_startop);
Curl_pgrs_since_ms(data, pnow, TIMER_STARTOP);
if(!timeleft_ms)
timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
}
@@ -114,27 +108,34 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data)
return timeleft_now_ms(data, Curl_pgrs_now(data));
}
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
timediff_t Curl_timeleft_now_ms(struct Curl_easy *data,
const struct curltime *pnow)
{
return timeleft_now_ms(data, pnow);
}
void Curl_shutdown_start(struct Curl_easy *data, int8_t sockindex,
int timeout_ms)
{
struct connectdata *conn = data->conn;
const struct curltime *pnow = Curl_pgrs_now(data);
DEBUGASSERT(conn);
conn->shutdown.start[sockindex] = *Curl_pgrs_now(data);
conn->shutdown.start[sockindex] = *pnow;
conn->shutdown.timeout_ms = (timeout_ms > 0) ?
(timediff_t)timeout_ms :
((data->set.shutdowntimeout > 0) ?
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
/* Set a timer, unless we operate on the admin handle */
if(data->mid)
Curl_expire_ex(data, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN);
Curl_expire_set(data, EXPIRE_SHUTDOWN, conn->shutdown.timeout_ms, pnow);
CURL_TRC_M(data, "shutdown start on%s connection",
sockindex ? " secondary" : "");
}
timediff_t Curl_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
timediff_t left_ms;
@@ -152,7 +153,7 @@ timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn)
{
timediff_t left_ms = 0, ms;
int i;
int8_t i;
for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
if(!conn->shutdown.start[i].tv_sec)
@@ -164,19 +165,16 @@ timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
return left_ms;
}
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
void Curl_shutdown_clear(struct Curl_easy *data, int8_t sockindex)
{
struct curltime *pt = &data->conn->shutdown.start[sockindex];
memset(pt, 0, sizeof(*pt));
}
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
bool Curl_shutdown_started(struct connectdata *conn, int8_t sockindex)
{
if(data->conn) {
struct curltime *pt = &data->conn->shutdown.start[sockindex];
return (pt->tv_sec > 0) || (pt->tv_usec > 0);
}
return FALSE;
const struct curltime *pt = &conn->shutdown.start[sockindex];
return (pt->tv_sec > 0) || (pt->tv_usec > 0);
}
/*
@@ -201,67 +199,66 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
if(!conn) {
data->state.lastconnect_id = -1;
if(connp)
*connp = NULL;
return CURL_SOCKET_BAD;
}
if(connp)
/* only store this if the caller cares for it */
*connp = conn;
return conn->sock[FIRSTSOCKET];
}
if(connp)
*connp = NULL;
return CURL_SOCKET_BAD;
}
/*
* Curl_conncontrol() marks streams or connection for closure.
*/
void Curl_conncontrol(struct connectdata *conn,
int ctrl /* see defines in header */
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
, const char *reason
#endif
)
void Curl_conncontrol(struct connectdata *conn, int ctrl)
{
/* close if a connection, or a stream that is not multiplexed. */
/* This function will be called both before and after this connection is
associated with a transfer. */
bool closeit, is_multiplex;
DEBUGASSERT(conn);
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
(void)reason; /* useful for debugging */
#endif
is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
closeit = (ctrl == CONNCTRL_CONNECTION) ||
((ctrl == CONNCTRL_STREAM) && !is_multiplex);
if((ctrl == CONNCTRL_STREAM) && is_multiplex)
; /* stream signal on multiplex conn never affects close state */
else if((curl_bit)closeit != conn->bits.close) {
conn->bits.close = closeit; /* the only place in the source code that
should assign this bit */
if(!conn) {
DEBUGASSERT(0);
return;
}
switch(ctrl) {
case CONNCTRL_CONN_KEEP:
conn->bits.close = FALSE;
break;
case CONNCTRL_CONN_CLOSE:
conn->bits.close = TRUE;
break;
case CONNCTRL_STREAM_CLOSE:
/* stream close when multiplexing does not affect connection */
if(!Curl_conn_is_multiplex(conn, FIRSTSOCKET))
conn->bits.close = TRUE;
break;
default:
DEBUGASSERT(0);
break;
}
}
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
int ssl_mode)
{
struct Curl_peer *first_peer = Curl_conn_get_first_peer(conn, sockindex);
CURLcode result = CURLE_OK;
struct Curl_peer *peer = Curl_conn_get_first_peer(conn, sockindex);
uint8_t dns_queries;
DEBUGASSERT(data);
DEBUGASSERT(conn->scheme);
DEBUGASSERT(!conn->cfilter[sockindex]);
if(!peer)
if(!first_peer)
return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_HTTP
if(!conn->cfilter[sockindex] &&
conn->scheme->protocol == CURLPROTO_HTTPS) {
DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
result = Curl_cf_https_setup(data, conn, sockindex);
result = Curl_cf_https_setup(
data, Curl_conn_get_destination(conn, sockindex), conn, sockindex);
if(result)
goto out;
}
@@ -275,13 +272,16 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
goto out;
}
/* Whatever the filter chain will be in the end, it will need the
* resolving of `first_peer`. Add that now so the resolve is started
* right away. */
dns_queries = Curl_resolv_dns_queries(data, conn->ip_version);
#ifdef USE_HTTPSRR
if(sockindex == FIRSTSOCKET)
dns_queries |= CURL_DNSQ_HTTPS;
#endif
result = Curl_cf_dns_add(data, conn, sockindex, peer, dns_queries,
conn->transport_wanted);
result = Curl_conn_dns_add_addr_resolve(data, conn, sockindex,
first_peer, dns_queries,
conn->transport_wanted);
if(result)
goto out;
DEBUGASSERT(conn->cfilter[sockindex]);
out:
return result;
@@ -313,27 +313,16 @@ static CURLcode conn_connect_trace(struct Curl_easy *data,
/**
* Update connection statistics
*/
static void conn_report_connect_stats(struct Curl_cfilter *cf,
struct Curl_easy *data)
static void conn_report_stats(struct Curl_easy *data, int sockindex)
{
if(cf) {
struct curltime connected;
struct curltime appconnected;
memset(&connected, 0, sizeof(connected));
cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
if(connected.tv_sec || connected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
memset(&appconnected, 0, sizeof(appconnected));
cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
if(appconnected.tv_sec || appconnected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
/* We do gather stats for the second socket...yet */
if(sockindex == FIRSTSOCKET) {
Curl_conn_cntrl_report_stats(data, data->conn, sockindex);
}
}
CURLcode Curl_conn_connect(struct Curl_easy *data,
int sockindex,
int8_t sockindex,
bool blocking,
bool *done)
{
@@ -391,8 +380,8 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
* persist information at the connection. E.g. cf-socket sets the
* socket and ip related information. */
Curl_conn_cntrl_update_info(data, data->conn);
conn_report_connect_stats(cf, data);
data->conn->keepalive = *Curl_pgrs_now(data);
conn_report_stats(data, sockindex);
data->conn->lastupkeep = *Curl_pgrs_now(data);
VERBOSE(result = conn_connect_trace(data, cf));
VERBOSE(Curl_conn_trc_filters(data, sockindex, "connected"));
Curl_conn_remove_setup_filters(data, sockindex);
@@ -403,7 +392,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
(int)result);
VERBOSE(Curl_conn_trc_filters(data, sockindex, "failed to connect"));
conn_report_connect_stats(cf, data);
conn_report_stats(data, sockindex);
goto out;
}
@@ -465,14 +454,14 @@ void Curl_conn_set_multiplex(struct connectdata *conn)
}
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
return (sockindex == SECONDARYSOCKET) ?
conn->origin2 : conn->origin;
}
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
return (sockindex == SECONDARYSOCKET) ?
(conn->via_peer2 ? conn->via_peer2 : conn->origin2) :
@@ -480,7 +469,7 @@ struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
}
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
int sockindex)
int8_t sockindex)
{
#ifndef CURL_DISABLE_PROXY
if(conn->socks_proxy.peer)
+26 -39
View File
@@ -25,41 +25,42 @@
***************************************************************************/
#include "curl_setup.h"
#include "hostip.h"
#include "vdns/hostip.h"
#include "curlx/timeval.h"
struct Curl_peer;
struct Curl_str;
enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len);
enum alpnid Curl_str2alpnid(const struct Curl_str *cstr);
/* generic function that returns how much time there is left to run, according
to the timeouts set */
timediff_t Curl_timeleft_ms(struct Curl_easy *data);
timediff_t Curl_timeleft_now_ms(struct Curl_easy *data,
const struct curltime *pnow);
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
#define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000)
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
void Curl_shutdown_start(struct Curl_easy *data, int8_t sockindex,
int timeout_ms);
/* return how much time there is left to shutdown the connection at
* sockindex. Returns 0 if there is no limit or shutdown has not started. */
timediff_t Curl_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
int8_t sockindex);
/* return how much time there is left to shutdown the connection.
* Returns 0 if there is no limit or shutdown has not started. */
timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn);
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);
void Curl_shutdown_clear(struct Curl_easy *data, int8_t sockindex);
/* TRUE iff shutdown has been started */
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);
bool Curl_shutdown_started(struct connectdata *conn, int8_t sockindex);
/*
* Used to extract socket and connectdata struct for the most recent
@@ -71,37 +72,23 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
struct connectdata **connp);
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'ctrl'
* argument specifies if it is the end of a connection or a stream.
*
* For stream-based protocols (such as HTTP/2), a stream close will not cause
* a connection close. Other protocols will close the connection for both
* cases.
*
* It sets the bit.close bit to TRUE (with an explanation for debug builds),
* when the connection will close.
* Curl_conncontrol() manipulates the `conn->bits.close` bit on
* a connection:
* - CONNCTRL_CONN_KEEP: clear the bit
* - CONNCTRL_CONN_CLOSE: set the bit
* - CONNCTRL_STREAM_CLOSE: set the bit when the connection is not
* multiplexed
* The call does *NOT* cause any immediate connection close.
*/
#define CONNCTRL_CONN_KEEP 0
#define CONNCTRL_CONN_CLOSE 1
#define CONNCTRL_STREAM_CLOSE 2
#define CONNCTRL_KEEP 0 /* undo a marked closure */
#define CONNCTRL_CONNECTION 1
#define CONNCTRL_STREAM 2
void Curl_conncontrol(struct connectdata *conn, int ctrl);
void Curl_conncontrol(struct connectdata *conn,
int ctrl
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
, const char *reason
#endif
);
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
#else /* !DEBUGBUILD || !CURLVERBOSE */
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP)
#endif
#define streamclose(x) Curl_conncontrol((x), CONNCTRL_STREAM_CLOSE)
#define connclose(x) Curl_conncontrol((x), CONNCTRL_CONN_CLOSE)
#define connkeep(x) Curl_conncontrol((x), CONNCTRL_CONN_KEEP)
/**
* Setup the cfilters at `sockindex` in connection `conn`.
@@ -110,7 +97,7 @@ void Curl_conncontrol(struct connectdata *conn,
*/
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
int8_t sockindex,
int ssl_mode);
/**
@@ -120,7 +107,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
* When not `blocking`, calls may return without error and `*done != TRUE`,
* while the individual filters negotiated the connection.
*/
CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
CURLcode Curl_conn_connect(struct Curl_easy *data, int8_t sockindex,
bool blocking, bool *done);
/* Set conn to allow multiplexing. */
@@ -128,17 +115,17 @@ void Curl_conn_set_multiplex(struct connectdata *conn);
/* Get the origin peer at sockindex. */
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
int sockindex);
int8_t sockindex);
/* Get the peer the connection actually connects to at sockindex.
* Often the same as "origin", but can be redirected via "connect-to"
* or "alt-svc". May tunnel through proxies. */
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
int sockindex);
int8_t sockindex);
/* Get the peer curl connects its socket to.
* Can be origin, "connect-to" or the first proxy. */
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
int sockindex);
int8_t sockindex);
#endif /* HEADER_CURL_CONNECT_H */
+23 -2
View File
@@ -65,7 +65,7 @@
#ifdef HAVE_LIBZ
#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1252)
#error "requires zlib 1.2.5.2 or newer"
#error "zlib 1.2.5.2 or greater required"
#endif
typedef enum {
@@ -206,6 +206,14 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* No more data to flush: exit loop. */
break;
case Z_STREAM_END:
if((started == ZLIB_INIT_GZIP) && (z->avail_in >= 2) &&
(z->next_in[0] == 0x1f) && (z->next_in[1] == 0x8b)) {
/* a second gzip member follows; curl does not support
multi-member gzip responses */
failf(data, "Multi-member gzip response not supported");
result = exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
break;
}
result = process_trailer(data, zp);
break;
case Z_DATA_ERROR:
@@ -289,8 +297,10 @@ static void deflate_do_close(struct Curl_easy *data,
static const struct Curl_cwtype deflate_encoding = {
"deflate",
NULL,
CURL_CW_FLAG_BLOWUP,
deflate_do_init,
deflate_do_write,
Curl_cwriter_def_flush,
deflate_do_close,
sizeof(struct zlib_writer)
};
@@ -350,8 +360,10 @@ static void gzip_do_close(struct Curl_easy *data,
static const struct Curl_cwtype gzip_encoding = {
"gzip",
"x-gzip",
CURL_CW_FLAG_BLOWUP,
gzip_do_init,
gzip_do_write,
Curl_cwriter_def_flush,
gzip_do_close,
sizeof(struct zlib_writer)
};
@@ -483,8 +495,10 @@ static void brotli_do_close(struct Curl_easy *data,
static const struct Curl_cwtype brotli_encoding = {
"br",
NULL,
CURL_CW_FLAG_BLOWUP,
brotli_do_init,
brotli_do_write,
Curl_cwriter_def_flush,
brotli_do_close,
sizeof(struct brotli_writer)
};
@@ -596,8 +610,10 @@ static void zstd_do_close(struct Curl_easy *data,
static const struct Curl_cwtype zstd_encoding = {
"zstd",
NULL,
CURL_CW_FLAG_BLOWUP,
zstd_do_init,
zstd_do_write,
Curl_cwriter_def_flush,
zstd_do_close,
sizeof(struct zstd_writer)
};
@@ -607,8 +623,10 @@ static const struct Curl_cwtype zstd_encoding = {
static const struct Curl_cwtype identity_encoding = {
"identity",
"none",
0,
Curl_cwriter_def_init,
Curl_cwriter_def_write,
Curl_cwriter_def_flush,
Curl_cwriter_def_close,
sizeof(struct Curl_cwriter)
};
@@ -694,8 +712,10 @@ static void error_do_close(struct Curl_easy *data,
static const struct Curl_cwtype error_writer = {
"ce-error",
NULL,
0,
error_do_init,
error_do_write,
Curl_cwriter_def_flush,
error_do_close,
sizeof(struct Curl_cwriter)
};
@@ -763,7 +783,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
* Exception is "chunked" transfer-encoding which always must happen */
if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
(!is_transfer && data->set.http_ce_skip)) {
bool is_identity = curl_strnequal(name, "identity", 8);
bool is_identity = (namelen == 8) &&
curl_strnequal(name, "identity", 8);
/* not requested, ignore */
CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
(int)namelen, name);
+80 -60
View File
@@ -48,8 +48,7 @@
future. (from RFC6265bis draft-19)
For the sake of easier testing, align the capped time to an even 60 second
boundary.
*/
boundary. */
static void cap_expires(time_t now, struct Cookie *co)
{
if(co->expires && (TIME_T_MAX - COOKIES_MAXAGE - 30) > now) {
@@ -335,15 +334,14 @@ static bool bad_domain(const char *domain, size_t len)
}
#endif
/*
RFC 6265 section 4.1.1 says a server should accept this range:
/* RFC 6265 section 4.1.1 says a server should accept this range:
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
Yet, Firefox and Chrome as of June 2022 accept space, comma and double-quotes
fine. The prime reason for filtering out control bytes is that some HTTP
servers return 400 for requests that contain such.
*/
Yet, Firefox and Chrome as of June 2022 accept space, comma and
double-quotes fine. The prime reason for filtering out control bytes is that
some HTTP servers return 400 for requests that contain such.
*/
static bool invalid_octets(const char *ptr, size_t len)
{
const unsigned char *p = (const unsigned char *)ptr;
@@ -359,8 +357,7 @@ static bool invalid_octets(const char *ptr, size_t len)
/* The maximum length we accept a date string for the 'expire' keyword. The
standard date formats are within the 30 bytes range. This adds an extra
margin to make sure it realistically works with what is used out there.
*/
margin to make sure it realistically works with what is used out there. */
#define MAX_DATE_LENGTH 80
#define COOKIE_NAME 0
@@ -614,7 +611,7 @@ parse_cookie_header(struct Curl_easy *data,
struct Curl_str name;
/* we have a <name>=<value> pair or a stand-alone word here */
if(!curlx_str_cspn(&ptr, &name, ";\t\r\n=")) {
if(!curlx_str_cspn(&ptr, &name, ";\r\n=")) {
struct Curl_str val;
bool sep = FALSE;
curlx_str_trimblanks(&name);
@@ -801,22 +798,28 @@ static CURLcode parse_netscape(struct Cookie *co,
}
static bool is_public_suffix(struct Curl_easy *data,
const struct Cookie *co,
struct Cookie *co,
const char *domain)
{
#ifdef USE_LIBPSL
/*
* Check if the domain is a Public Suffix and if yes, ignore the cookie. We
* must also check that the data handle is not NULL since the psl code will
* dereference it.
* Check if the domain is a Public Suffix and if yes, ignore the cookie.
* 'domain' is NULL when the cookie is loaded from file or
* CURLOPT_COOKIELIST.
*/
DEBUGASSERT(data);
DEBUGASSERT(co);
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))) {
co->name, co->domain ? co->domain : "[blank]",
domain ? domain : "[file]"));
if(!co->domain || Curl_host_is_ipnum(co->domain))
return FALSE;
else {
bool acceptable = FALSE;
char lcase[256];
char lcookie[256];
size_t dlen = strlen(domain);
size_t dlen = domain ? strlen(domain) : 0;
size_t clen = strlen(co->domain);
/* trim trailing dots */
@@ -829,11 +832,28 @@ static bool is_public_suffix(struct Curl_easy *data,
const psl_ctx_t *psl = Curl_psl_use(data);
if(psl) {
/* the PSL check requires lowercase domain name and pattern */
Curl_strntolower(lcase, domain, dlen);
lcase[dlen] = 0;
Curl_strntolower(lcookie, co->domain, clen);
lcookie[clen] = 0;
acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
if(domain) {
Curl_strntolower(lcase, domain, dlen);
lcase[dlen] = 0;
acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
/* if the cookie is acceptable, but is set for a PSL domain, then it
cannot be tailmatching */
if(acceptable && co->tailmatch &&
curl_strequal(co->domain, domain) &&
psl_is_public_suffix(psl, lcookie))
co->tailmatch = FALSE;
}
else {
/* libpsl says localhost is a PSL, we think not */
acceptable =
curl_strequal(lcookie, "localhost") ||
/* note that this PSL function returns the opposite value than
psl_is_cookie_domain_acceptable() does */
!psl_is_public_suffix(psl, lcookie);
}
Curl_psl_release(data);
}
else
@@ -842,7 +862,8 @@ static bool is_public_suffix(struct Curl_easy *data,
if(!acceptable) {
infof(data, "cookie '%s' dropped, domain '%s' must not "
"set cookies for '%s'", co->name, domain, co->domain);
"set cookies for '%s'", co->name,
domain ? domain : "[file]", co->domain);
return TRUE;
}
}
@@ -851,7 +872,7 @@ static bool is_public_suffix(struct Curl_easy *data,
(void)co;
(void)domain;
DEBUGF(infof(data, "NO PSL to check set-cookie '%s' for domain=%s in %s",
co->name, co->domain, domain));
co->name, co->domain, domain ? domain : "[file]"));
#endif
return FALSE;
}
@@ -971,16 +992,15 @@ static bool replace_existing(struct Curl_easy *data,
* IPv6 address.
*
*/
CURLcode Curl_cookie_add(
struct Curl_easy *data,
struct CookieInfo *ci,
bool httpheader, /* TRUE if HTTP header-style line */
bool noexpire, /* if TRUE, skip remove_expired() */
const char *lineptr, /* first character of the line */
const char *domain, /* default domain */
const char *path, /* full path used when this cookie is set, used
to get default path for the cookie unless set */
bool secure) /* TRUE if connection is over secure origin */
CURLcode Curl_cookie_add(struct Curl_easy *data,
struct CookieInfo *ci,
const char *lineptr, /* first character of the line */
const char *domain, /* default domain */
const char *path, /* full path used when this
cookie is set, used to get
default path for the cookie
unless set */
const int flags)
{
struct Cookie comem;
struct Cookie *co;
@@ -997,11 +1017,11 @@ CURLcode Curl_cookie_add(
co = &comem;
memset(co, 0, sizeof(comem));
if(httpheader)
if(flags & COOKIE_HTTPHEADER)
result = parse_cookie_header(data, co, ci, &okay,
lineptr, domain, path, secure);
lineptr, domain, path, flags & COOKIE_SECURE);
else
result = parse_netscape(co, ci, &okay, lineptr, secure);
result = parse_netscape(co, ci, &okay, lineptr, flags & COOKIE_SECURE);
if(result || !okay)
goto fail;
@@ -1010,6 +1030,9 @@ CURLcode Curl_cookie_add(
/* The __Secure- prefix only requires that the cookie be set secure */
goto fail;
if(!(flags & COOKIE_NOPSL) && is_public_suffix(data, co, domain))
goto fail;
if(co->prefix_host) {
/*
* The __Host- prefix requires the cookie to be secure, have a "/" path
@@ -1029,20 +1052,15 @@ CURLcode Curl_cookie_add(
co->livecookie = ci->running;
co->creationtime = ++ci->lastct;
if(!(flags & COOKIE_NOEXPIRE))
remove_expired(ci);
/*
* Now we have parsed the incoming line, we must now check if this supersedes
* an already existing cookie, which it may if the previous have the same
* domain and path as this.
*/
/* remove expired cookies */
if(!noexpire)
remove_expired(ci);
if(is_public_suffix(data, co, domain))
goto fail;
if(!replace_existing(data, co, ci, secure, &replaces))
if(!replace_existing(data, co, ci, flags & COOKIE_SECURE, &replaces))
goto fail;
/* clone the stack struct into heap */
@@ -1074,7 +1092,7 @@ CURLcode Curl_cookie_add(
if(co->expires && (co->expires < ci->next_expiration))
ci->next_expiration = co->expires;
if(httpheader)
if(flags & COOKIE_HTTPHEADER)
data->req.setcookies++;
return result;
@@ -1123,11 +1141,11 @@ struct CookieInfo *Curl_cookie_init(void)
* Reads cookies from a local file. This is always called before any cookies
* are set. If file is "-" then STDIN is read.
*
* If 'newsession' is TRUE, discard all "session cookies" on read from file.
*
* If 'flags' has the COOKIE_NOSESSION bit set, discard all "session cookies"
* read from file.
*/
static CURLcode cookie_load(struct Curl_easy *data, const char *file,
struct CookieInfo *ci, bool newsession)
struct CookieInfo *ci, int flags)
{
FILE *handle = NULL;
CURLcode result = CURLE_OK;
@@ -1136,7 +1154,7 @@ static CURLcode cookie_load(struct Curl_easy *data, const char *file,
DEBUGASSERT(data);
DEBUGASSERT(file);
ci->newsession = newsession; /* new session? */
ci->newsession = !!(flags & COOKIE_NOSESSION); /* new session? */
ci->running = FALSE; /* this is not running, this is init */
if(file && *file) {
@@ -1176,8 +1194,10 @@ static CURLcode cookie_load(struct Curl_easy *data, const char *file,
curlx_str_passblanks(&lineptr);
}
result = Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL,
NULL, TRUE);
result = Curl_cookie_add(data, ci, lineptr, NULL, NULL,
(headerline ? COOKIE_HTTPHEADER : 0) |
COOKIE_NOEXPIRE | COOKIE_SECURE |
(flags & COOKIE_NOPSL));
/* File reading cookie failures are not propagated back to the
caller because there is no way to do that */
}
@@ -1202,7 +1222,8 @@ static CURLcode cookie_load(struct Curl_easy *data, const char *file,
/*
* Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
*/
CURLcode Curl_cookie_loadfiles(struct Curl_easy *data)
CURLcode Curl_cookie_loadfiles(struct Curl_easy *data,
int flags)
{
CURLcode result = CURLE_OK;
struct curl_slist *list = data->state.cookielist;
@@ -1215,8 +1236,7 @@ CURLcode Curl_cookie_loadfiles(struct Curl_easy *data)
else {
data->state.cookie_engine = TRUE;
while(list) {
result = cookie_load(data, list->data, data->cookies,
(bool)data->set.cookiesession);
result = cookie_load(data, list->data, data->cookies, flags);
if(result)
break;
list = list->next;
@@ -1656,13 +1676,13 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
might be cookie files that were not loaded so saving the file is the
wrong thing. */
if(data->cookies) {
if(data->set.str[STRING_COOKIEJAR] && data->cookies->running) {
const char *cookiejar = CURL_EASY_STR(data, STRING_COOKIEJAR);
if(cookiejar && data->cookies->running) {
/* if we have a destination file for all the cookies to get dumped to */
CURLcode result = cookie_output(data, data->cookies,
data->set.str[STRING_COOKIEJAR]);
CURLcode result = cookie_output(data, data->cookies, cookiejar);
if(result)
infof(data, "WARNING: failed to save cookies in %s: %s",
data->set.str[STRING_COOKIEJAR], curl_easy_strerror(result));
cookiejar, curl_easy_strerror(result));
}
if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
+14 -8
View File
@@ -72,7 +72,7 @@ struct CookieInfo {
In the 6265bis draft document section 5.4 it is phrased even stronger: "If
the sum of the lengths of the name string and the value string is more than
4096 octets, abort these steps and ignore the set-cookie-string entirely."
*/
*/
/** Limits for INCOMING cookies **/
@@ -104,20 +104,25 @@ struct CookieInfo {
struct Curl_easy;
struct connectdata;
bool Curl_secure_context(struct Curl_easy *data, const char *host);
/*
* Add a cookie to the internal list of cookies. The domain and path arguments
* are only used if the header boolean is TRUE.
* are only used if the COOKIE_HTTPHEADER bit is set in the flags.
*/
bool Curl_secure_context(struct Curl_easy *data, const char *host);
#define COOKIE_HTTPHEADER (1<<0) /* if HTTP header-style line */
#define COOKIE_NOEXPIRE (1<<1) /* skip remove_expired() */
#define COOKIE_SECURE (1<<2) /* connection is over secure origin */
#define COOKIE_NOPSL (1<<3) /* skip PSL check */
#define COOKIE_NOSESSION (1<<6) /* drop session cookies */
CURLcode Curl_cookie_add(struct Curl_easy *data,
struct CookieInfo *ci,
bool httpheader,
bool noexpire,
const char *lineptr,
const char *domain,
const char *path,
bool secure) WARN_UNUSED_RESULT;
const int flags) WARN_UNUSED_RESULT;
CURLcode Curl_cookie_getlist(struct Curl_easy *data,
bool *okay, const char *host,
struct Curl_llist *list) WARN_UNUSED_RESULT;
@@ -126,7 +131,7 @@ void Curl_cookie_clearsess(struct CookieInfo *ci);
#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
#define Curl_cookie_list(x) NULL
#define Curl_cookie_loadfiles(x) CURLE_OK
#define Curl_cookie_loadfiles(x, y) CURLE_OK
#define Curl_cookie_init() NULL
#define Curl_cookie_run(x) Curl_nop_stmt
#define Curl_cookie_cleanup(x) Curl_nop_stmt
@@ -136,7 +141,8 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
void Curl_cookie_cleanup(struct CookieInfo *ci);
struct CookieInfo *Curl_cookie_init(void);
struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
CURLcode Curl_cookie_loadfiles(struct Curl_easy *data) WARN_UNUSED_RESULT;
CURLcode Curl_cookie_loadfiles(struct Curl_easy *data,
int flags) WARN_UNUSED_RESULT;
void Curl_cookie_run(struct Curl_easy *data);
#endif
+5 -2
View File
@@ -46,6 +46,7 @@ CURLcode Curl_creds_create(const char *user,
size_t salen = sasl_authzid ? strlen(sasl_authzid) : 0;
size_t sslen = sasl_service ? strlen(sasl_service) : 0;
char *s, *buf;
size_t bufsize;
CURLcode result = CURLE_OK;
Curl_creds_unlink(pcreds);
@@ -64,13 +65,14 @@ CURLcode Curl_creds_create(const char *user,
}
/* null-terminator for user already part of struct */
creds = curlx_calloc(1, sizeof(*creds) +
ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1);
bufsize = ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1;
creds = curlx_calloc(1, sizeof(*creds) + bufsize);
if(!creds) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
creds->bufsize = bufsize;
creds->refcount = 1;
creds->source = source;
/* Some compilers try to be too smart about our dynamic struct size */
@@ -147,6 +149,7 @@ void Curl_creds_unlink(struct Curl_creds **pcreds)
if(creds->refcount)
creds->refcount--;
if(!creds->refcount) {
curlx_memzero(creds, sizeof(*creds) + creds->bufsize);
curlx_free(creds);
}
}
+3 -2
View File
@@ -39,6 +39,7 @@ struct Curl_creds {
const char *sasl_service; /* non-NULL, maybe empty string */
uint32_t refcount;
uint8_t source; /* CREDS_* value */
size_t bufsize; /* extra bytes added to sizeof(struct Curl_creds) */
char buf[1];
};
@@ -73,8 +74,8 @@ bool Curl_creds_equal(struct Curl_creds *c1, struct Curl_creds *c2);
/* Provides properties for creds or, if creds is NULL, the empty string */
#define Curl_creds_has_user(c) ((c) && (c)->user[0])
#define Curl_creds_has_passwd(c) ((c) && (c)->passwd[0])
#define Curl_creds_has_user_or_pass(c) \
((c) && ((c)->user[0] || (c)->passwd[0]))
#define Curl_creds_has_user_or_pass(c) \
((c) && ((c)->user[0] || (c)->passwd[0]))
#define Curl_creds_has_oauth_bearer(c) ((c) && (c)->oauth_bearer[0])
#define Curl_creds_has_sasl_service(c) ((c) && (c)->sasl_service[0])
#define Curl_creds_user(c) ((c) ? (c)->user : "")
+86 -92
View File
@@ -38,6 +38,13 @@
#include "curlx/strparse.h"
struct cshutdn *Curl_cshutdn_get(struct Curl_easy *data)
{
if(data && data->multi)
return &data->multi->cshutdn;
return NULL;
}
static void cshutdn_run_conn_handler(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -76,7 +83,7 @@ static void cshutdn_run_once(struct Curl_easy *data,
/* We expect to be attached when called */
DEBUGASSERT(data->conn == conn);
if(!Curl_shutdown_started(data, FIRSTSOCKET)) {
if(!Curl_shutdown_started(conn, FIRSTSOCKET)) {
Curl_shutdown_start(data, FIRSTSOCKET, 0);
}
@@ -107,22 +114,22 @@ static void cshutdn_run_once(struct Curl_easy *data,
conn->bits.shutdown_filters = TRUE;
}
void Curl_cshutdn_run_once(struct Curl_easy *data,
void Curl_conn_shutdown_once(struct Curl_easy *admin,
struct connectdata *conn,
bool *done)
{
DEBUGASSERT(!data->conn);
Curl_attach_connection(data, conn);
cshutdn_run_once(data, conn, done);
CURL_TRC_M(data, "[SHUTDOWN] shutdown, done=%d", *done);
Curl_detach_connection(data);
DEBUGASSERT(!admin->conn);
DEBUGASSERT(!admin->mid);
Curl_attach_connection(admin, conn, FALSE);
cshutdn_run_once(admin, conn, done);
CURL_TRC_M(admin, "[SHUTDOWN] shutdown, done=%d", *done);
Curl_detach_connection(admin);
}
void Curl_cshutdn_terminate(struct Curl_easy *data,
struct connectdata *conn,
bool do_shutdown)
void Curl_conn_terminate(struct Curl_easy *admin,
struct connectdata *conn,
bool do_shutdown)
{
struct Curl_easy *admin = data;
bool done;
/* there must be a connection to close */
@@ -130,16 +137,10 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
/* it must be removed from the connection pool */
DEBUGASSERT(!conn->bits.in_cpool);
/* the transfer must be detached from the connection */
DEBUGASSERT(data && !data->conn);
DEBUGASSERT(admin && !admin->conn);
DEBUGASSERT(!admin->mid);
/* If we can obtain an internal admin handle, use that to attach
* and terminate the connection. Some protocol will try to mess with
* `data` during shutdown and we do not want that with a `data` from
* the application. */
if(data->multi && data->multi->admin)
admin = data->multi->admin;
Curl_attach_connection(admin, conn);
Curl_attach_connection(admin, conn, FALSE);
cshutdn_run_conn_handler(admin, conn);
if(do_shutdown) {
@@ -154,18 +155,17 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
Curl_conn_cf_discard_all(admin, conn, FIRSTSOCKET);
Curl_detach_connection(admin);
if(data->multi)
Curl_multi_ev_conn_done(data->multi, data, conn);
if(admin->multi)
Curl_multi_ev_conn_done(admin->multi, admin, conn);
Curl_conn_free(admin, conn);
if(data->multi) {
CURL_TRC_M(data, "[SHUTDOWN] trigger multi connchanged");
Curl_multi_connchanged(data->multi);
if(admin->multi) {
CURL_TRC_M(admin, "[SHUTDOWN] trigger multi connchanged");
Curl_multi_connchanged(admin->multi);
}
}
static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn,
struct Curl_easy *data,
const char *destination)
{
struct Curl_llist_node *e;
@@ -184,20 +184,19 @@ static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn,
conn = Curl_node_elem(e);
Curl_node_remove(e);
sigpipe_init(&sigpipe_ctx);
sigpipe_apply(data, &sigpipe_ctx);
Curl_cshutdn_terminate(data, conn, FALSE);
sigpipe_apply(cshutdn->multi->admin, &sigpipe_ctx);
Curl_conn_terminate(cshutdn->multi->admin, conn, FALSE);
sigpipe_restore(&sigpipe_ctx);
return TRUE;
}
return FALSE;
}
bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
bool Curl_cshutdn_close_oldest(struct cshutdn *cshutdn,
const char *destination)
{
if(data && data->multi) {
struct cshutdn *csd = &data->multi->cshutdn;
return cshutdn_destroy_oldest(csd, data, destination);
if(cshutdn) {
return cshutdn_destroy_oldest(cshutdn, destination);
}
return FALSE;
}
@@ -205,7 +204,6 @@ bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
#define NUM_POLLS_ON_STACK 10
static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
struct Curl_easy *data,
int timeout_ms)
{
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
@@ -214,7 +212,7 @@ static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
result = Curl_cshutdn_add_pollfds(cshutdn, data, &cpfds);
result = Curl_cshutdn_add_pollfds(cshutdn, &cpfds);
if(result)
goto out;
@@ -226,11 +224,11 @@ out:
}
static void cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx)
{
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
struct Curl_llist_node *enext;
struct Curl_easy *admin = cshutdn->multi->admin;
struct connectdata *conn;
timediff_t next_expire_ms = 0, ms;
bool done;
@@ -238,67 +236,64 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
if(!e)
return;
CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections",
CURL_TRC_M(admin, "[SHUTDOWN] perform on %zu connections",
Curl_llist_count(&cshutdn->list));
sigpipe_apply(data, sigpipe_ctx);
sigpipe_apply(admin, sigpipe_ctx);
while(e) {
enext = Curl_node_next(e);
conn = Curl_node_elem(e);
Curl_cshutdn_run_once(data, conn, &done);
Curl_conn_shutdown_once(admin, conn, &done);
if(done) {
Curl_node_remove(e);
Curl_cshutdn_terminate(data, conn, FALSE);
Curl_conn_terminate(admin, conn, FALSE);
}
else {
/* idata has one timer list, but maybe more than one connection.
* Set EXPIRE_SHUTDOWN to the smallest time left for all. */
ms = Curl_conn_shutdown_timeleft(data, conn);
if(ms && ms < next_expire_ms)
ms = Curl_conn_shutdown_timeleft(admin, conn);
if(ms && (!next_expire_ms || (ms < next_expire_ms)))
next_expire_ms = ms;
}
e = enext;
}
if(next_expire_ms)
Curl_expire_ex(data, next_expire_ms, EXPIRE_SHUTDOWN);
Curl_expire(admin, next_expire_ms, EXPIRE_SHUTDOWN);
}
static void cshutdn_terminate_all(struct cshutdn *cshutdn,
struct Curl_easy *data,
int timeout_ms)
{
struct curltime started = *Curl_pgrs_now(data);
struct Curl_easy *admin = cshutdn->multi->admin;
struct curltime started = *Curl_pgrs_now(admin);
struct Curl_llist_node *e;
struct Curl_sigpipe_ctx sigpipe_ctx;
DEBUGASSERT(cshutdn);
DEBUGASSERT(data);
CURL_TRC_M(data, "[SHUTDOWN] shutdown all");
CURL_TRC_M(admin, "[SHUTDOWN] shutdown all");
sigpipe_init(&sigpipe_ctx);
while(Curl_llist_head(&cshutdn->list)) {
timediff_t spent_ms;
int remain_ms;
cshutdn_perform(cshutdn, data, &sigpipe_ctx);
cshutdn_perform(cshutdn, &sigpipe_ctx);
if(!Curl_llist_head(&cshutdn->list)) {
CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly");
CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished cleanly");
break;
}
/* wait for activity, timeout or "nothing" */
spent_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &started);
spent_ms = curlx_ptimediff_ms(Curl_pgrs_now(admin), &started);
if(spent_ms >= (timediff_t)timeout_ms) {
CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s",
CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished, %s",
(timeout_ms > 0) ? "timeout" : "best effort done");
break;
}
remain_ms = timeout_ms - (int)spent_ms;
if(cshutdn_wait(cshutdn, data, remain_ms)) {
CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, aborted");
if(cshutdn_wait(cshutdn, remain_ms)) {
CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished, aborted");
break;
}
}
@@ -308,7 +303,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn,
while(e) {
struct connectdata *conn = Curl_node_elem(e);
Curl_node_remove(e);
Curl_cshutdn_terminate(data, conn, FALSE);
Curl_conn_terminate(admin, conn, FALSE);
e = Curl_llist_head(&cshutdn->list);
}
DEBUGASSERT(!Curl_llist_count(&cshutdn->list));
@@ -327,12 +322,13 @@ int Curl_cshutdn_init(struct cshutdn *cshutdn,
}
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
struct Curl_easy *data)
struct Curl_easy *admin)
{
if(cshutdn->initialized && data) {
if(cshutdn->initialized && admin) {
int timeout_ms = 0;
/* for testing, run graceful shutdown */
#ifdef DEBUGBUILD
DEBUGASSERT(!admin->mid);
{
const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
if(p) {
@@ -343,29 +339,28 @@ void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
}
#endif
CURL_TRC_M(data, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
CURL_TRC_M(admin, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
Curl_llist_count(&cshutdn->list), timeout_ms);
cshutdn_terminate_all(cshutdn, data, timeout_ms);
cshutdn_terminate_all(cshutdn, timeout_ms);
}
cshutdn->multi = NULL;
cshutdn->initialized = FALSE;
}
size_t Curl_cshutdn_count(struct Curl_easy *data)
size_t Curl_cshutdn_count(struct cshutdn *cshutdn)
{
if(data && data->multi) {
struct cshutdn *csd = &data->multi->cshutdn;
return Curl_llist_count(&csd->list);
if(cshutdn) {
return Curl_llist_count(&cshutdn->list);
}
return 0;
}
size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
size_t Curl_cshutdn_dest_count(struct cshutdn *cshutdn,
const char *destination)
{
if(data && data->multi) {
struct cshutdn *csd = &data->multi->cshutdn;
if(cshutdn) {
size_t n = 0;
struct Curl_llist_node *e = Curl_llist_head(&csd->list);
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
while(e) {
struct connectdata *conn = Curl_node_elem(e);
if(!strcmp(destination, conn->destination))
@@ -378,17 +373,17 @@ size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
}
static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct connectdata *conn)
{
struct Curl_easy *admin = cshutdn->multi->admin;
CURLMcode mresult;
DEBUGASSERT(cshutdn);
DEBUGASSERT(cshutdn->multi->socket_cb);
Curl_attach_connection(data, conn);
mresult = Curl_multi_ev_assess_conn(cshutdn->multi, data, conn);
Curl_detach_connection(data);
Curl_attach_connection(admin, conn, FALSE);
mresult = Curl_multi_ev_assess_conn(cshutdn->multi, admin, conn);
Curl_detach_connection(admin);
return mresult;
}
@@ -396,47 +391,46 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn,
struct connectdata *conn,
size_t conns_in_pool)
{
struct Curl_easy *data = cshutdn->multi->admin;
struct Curl_easy *admin = cshutdn->multi->admin;
size_t max_total = cshutdn->multi->max_total_connections;
/* Add the connection to our shutdown list for non-blocking shutdown
* during multi processing. */
if(max_total > 0 &&
(max_total <= (conns_in_pool + Curl_llist_count(&cshutdn->list)))) {
CURL_TRC_M(data, "[SHUTDOWN] discarding oldest shutdown connection "
CURL_TRC_M(admin, "[SHUTDOWN] discarding oldest shutdown connection "
"due to connection limit of %zu", max_total);
cshutdn_destroy_oldest(cshutdn, data, NULL);
cshutdn_destroy_oldest(cshutdn, NULL);
}
if(cshutdn->multi->socket_cb) {
if(cshutdn_update_ev(cshutdn, data, conn)) {
CURL_TRC_M(data, "[SHUTDOWN] update events failed, discarding #%"
if(cshutdn_update_ev(cshutdn, conn)) {
CURL_TRC_M(admin, "[SHUTDOWN] update events failed, discarding #%"
FMT_OFF_T, conn->connection_id);
Curl_cshutdn_terminate(data, conn, FALSE);
Curl_conn_terminate(admin, conn, FALSE);
return;
}
}
Curl_llist_append(&cshutdn->list, conn, &conn->cshutdn_node);
CURL_TRC_M(data, "[SHUTDOWN] added #%" FMT_OFF_T
CURL_TRC_M(admin, "[SHUTDOWN] added #%" FMT_OFF_T
" to shutdowns, now %zu conns in shutdown",
conn->connection_id, Curl_llist_count(&cshutdn->list));
}
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx)
{
cshutdn_perform(cshutdn, data, sigpipe_ctx);
cshutdn_perform(cshutdn, sigpipe_ctx);
}
/* return fd_set info about the shutdown connections */
void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd)
{
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_easy *admin = cshutdn->multi->admin;
struct Curl_llist_node *e;
struct easy_pollset ps;
@@ -447,9 +441,9 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
CURLcode result;
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
Curl_attach_connection(admin, conn, FALSE);
result = Curl_conn_adjust_pollset(admin, conn, &ps);
Curl_detach_connection(admin);
if(result)
continue;
@@ -473,13 +467,13 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
/* return information about the shutdown connections */
unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_waitfds *cwfds)
{
unsigned int need = 0;
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_llist_node *e;
struct Curl_easy *admin = cshutdn->multi->admin;
struct easy_pollset ps;
struct connectdata *conn;
CURLcode result;
@@ -488,9 +482,9 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
Curl_attach_connection(admin, conn, FALSE);
result = Curl_conn_adjust_pollset(admin, conn, &ps);
Curl_detach_connection(admin);
if(!result)
need += Curl_waitfds_add_ps(cwfds, &ps);
@@ -501,7 +495,6 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
}
CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct curl_pollfds *cpfds)
{
CURLcode result = CURLE_OK;
@@ -509,15 +502,16 @@ CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_llist_node *e;
struct easy_pollset ps;
struct Curl_easy *admin = cshutdn->multi->admin;
struct connectdata *conn;
Curl_pollset_init(&ps);
for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
Curl_attach_connection(admin, conn, FALSE);
result = Curl_conn_adjust_pollset(admin, conn, &ps);
Curl_detach_connection(admin);
if(!result)
result = Curl_pollfds_add_ps(cpfds, &ps);
+14 -15
View File
@@ -33,20 +33,20 @@ struct Curl_share;
struct Curl_sigpipe_ctx;
/* Run the shutdown of the connection once.
* Shortly attach/detach `data` to `conn` while doing so.
* Shortly attach/detach the admin handle to `conn` while doing so.
* `done` will be set TRUE if any error was encountered or if
* the connection was shut down completely. */
void Curl_cshutdn_run_once(struct Curl_easy *data,
struct connectdata *conn,
bool *done);
void Curl_conn_shutdown_once(struct Curl_easy *admin,
struct connectdata *conn,
bool *done);
/* Terminates the connection, e.g. closes and destroys it.
* If `do_shutdown` is TRUE, the shutdown will be run once before
* terminating it.
* Takes ownership of `conn`. */
void Curl_cshutdn_terminate(struct Curl_easy *data,
struct connectdata *conn,
bool do_shutdown);
void Curl_conn_terminate(struct Curl_easy *admin,
struct connectdata *conn,
bool do_shutdown);
/* A `cshutdown` is always owned by a multi handle to maintain
* the connections to be shut down. It registers timers and
@@ -57,25 +57,28 @@ struct cshutdn {
BIT(initialized);
};
/* Get the cshutdn instance relevant for `data` or NULL if there is none */
struct cshutdn *Curl_cshutdn_get(struct Curl_easy *data);
/* Init as part of the given multi handle. */
int Curl_cshutdn_init(struct cshutdn *cshutdn,
struct Curl_multi *multi);
/* Terminate all remaining connections and free resources. */
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
struct Curl_easy *data);
struct Curl_easy *admin);
/* Number of connections being shut down. */
size_t Curl_cshutdn_count(struct Curl_easy *data);
size_t Curl_cshutdn_count(struct cshutdn *cshutdn);
/* Number of connections to the destination being shut down. */
size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
size_t Curl_cshutdn_dest_count(struct cshutdn *cshutdn,
const char *destination);
/* Close the oldest connection in shutdown to destination or,
* when destination is NULL for any destination.
* Return TRUE if a connection has been closed. */
bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
bool Curl_cshutdn_close_oldest(struct cshutdn *cshutdn,
const char *destination);
/* Add a connection to have it shut down. Terminate the oldest
@@ -86,21 +89,17 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn,
/* Add sockets and POLLIN/OUT flags for connections being shut down. */
CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct curl_pollfds *cpfds);
unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_waitfds *cwfds);
void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd);
/* Run maintenance on all connections. */
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx);
#endif /* HEADER_CURL_CSHUTDN_H */
+22 -7
View File
@@ -24,24 +24,24 @@
#include "curl_setup.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN6_H
# include <netinet/in6.h>
#include <netinet/in6.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#include <sys/un.h>
#endif
#ifdef __VMS
# include <in.h>
# include <inet.h>
#include <in.h>
#include <inet.h>
#endif
#include <stddef.h> /* for offsetof() */
@@ -79,6 +79,21 @@ void Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
}
}
struct Curl_addrinfo *Curl_addrinfo_get(struct Curl_addrinfo *ai,
int ai_family,
unsigned int n)
{
unsigned int i;
for(i = 0; ai; ai = ai->ai_next) {
if(ai->ai_family == ai_family) {
if(i == n)
return ai;
++i;
}
}
return NULL;
}
#ifdef HAVE_GETADDRINFO
/*
* Curl_getaddrinfo_ex()
+5
View File
@@ -62,6 +62,11 @@ struct Curl_addrinfo {
void Curl_freeaddrinfo(struct Curl_addrinfo *cahead);
/* Get the n-th addrinfo of family ai_family. */
struct Curl_addrinfo *Curl_addrinfo_get(struct Curl_addrinfo *ai,
int ai_family,
unsigned int n);
#ifdef HAVE_GETADDRINFO
int Curl_getaddrinfo_ex(const char *nodename,
const char *servname,
+21 -29
View File
@@ -61,6 +61,9 @@
/* disables aws-sigv4 */
#cmakedefine CURL_DISABLE_AWS 1
/* disables HTTP Message Signatures (RFC 9421) */
#cmakedefine CURL_DISABLE_HTTPSIG 1
/* disables DICT */
#cmakedefine CURL_DISABLE_DICT 1
@@ -321,9 +324,15 @@
/* if you have the gssapi libraries */
#cmakedefine HAVE_GSSAPI 1
/* if you have Apple GSS */
#cmakedefine HAVE_GSSAPPLE 1
/* if you have the GNU gssapi libraries */
#cmakedefine HAVE_GSSGNU 1
/* if you have gss_set_neg_mechs */
#cmakedefine HAVE_GSS_SET_NEG_MECHS 1
/* MIT Kerberos version */
#cmakedefine CURL_KRB5_VERSION ${CURL_KRB5_VERSION}
@@ -336,12 +345,6 @@
/* Define to 1 if you have the <ifaddrs.h> header file. */
#cmakedefine HAVE_IFADDRS_H 1
/* Define to 1 if you have an IPv6 capable working inet_ntop function. */
#cmakedefine HAVE_INET_NTOP 1
/* Define to 1 if you have an IPv6 capable working inet_pton function. */
#cmakedefine HAVE_INET_PTON 1
/* Define to 1 if symbol `sa_family_t' exists */
#cmakedefine HAVE_SA_FAMILY_T 1
@@ -352,7 +355,7 @@
#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1
/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
*/
*/
#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
@@ -421,6 +424,9 @@
/* Define to 1 if you have the <netinet/udp.h> header file. */
#cmakedefine HAVE_NETINET_UDP_H 1
/* Define to 1 if you have the <netinet/ip.h> header file. */
#cmakedefine HAVE_NETINET_IP_H 1
/* Define to 1 if you have the <linux/tcp.h> header file. */
#cmakedefine HAVE_LINUX_TCP_H 1
@@ -457,9 +463,6 @@
/* Define to 1 if you have the recv function. */
#cmakedefine HAVE_RECV 1
/* Define to 1 if you have the select function. */
#cmakedefine HAVE_SELECT 1
/* Define to 1 if you have the sched_yield function. */
#cmakedefine HAVE_SCHED_YIELD 1
@@ -610,14 +613,12 @@
/* cpu-machine-OS */
#cmakedefine CURL_OS ${CURL_OS}
/*
Note: SIZEOF_* variables are fetched with CMake through check_type_size().
As per CMake documentation on CheckTypeSize, C preprocessor code is
generated by CMake into SIZEOF_*_CODE. This is what we use in the
following statements.
Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html
*/
/* Note: SIZEOF_* variables are fetched with CMake through check_type_size().
As per CMake documentation on CheckTypeSize, C preprocessor code is
generated by CMake into SIZEOF_*_CODE. This is what we use in the
following statements.
Ref: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html
*/
/* The size of `int', as computed by sizeof. */
${SIZEOF_INT_CODE}
@@ -640,9 +641,6 @@ ${SIZEOF_SIZE_T_CODE}
/* The size of `time_t', as computed by sizeof. */
${SIZEOF_TIME_T_CODE}
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
/* Define if you have POSIX pthreads */
#cmakedefine HAVE_THREADS_POSIX 1
@@ -776,14 +774,8 @@ ${SIZEOF_TIME_T_CODE}
/* to enable Apple OS-native certificate verification */
#cmakedefine USE_APPLE_SECTRUST 1
/* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */
#cmakedefine HAVE_OPENSSL_SRP 1
/* Define to 1 if GnuTLS has the gnutls_srp_verifier function. */
#cmakedefine HAVE_GNUTLS_SRP 1
/* Define to 1 to enable TLS-SRP support. */
#cmakedefine USE_TLS_SRP 1
/* to use Apple fast UDP (SYS_recvmsg_x, SYS_sendmsg_x) */
#cmakedefine USE_APPLE_FAST_UDP
/* Define to 1 to query for HTTPSRR when using DoH */
#cmakedefine USE_HTTPSRR 1
+2 -4
View File
@@ -30,10 +30,8 @@
#define ISLOWCNTRL(x) ((unsigned char)(x) <= 0x1f)
#define IS7F(x) ((x) == 0x7f)
#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d))
#define ISPRINT(x) (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e)))
#define ISGRAPH(x) (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e)))
#define ISPRINT(x) (((x) >= ' ') && ((x) <= 0x7e))
#define ISGRAPH(x) (((x) > ' ') && ((x) <= 0x7e))
#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALPHA(x) || ISUPHEXALPHA(x))
+175
View File
@@ -0,0 +1,175 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HTTPSIG)
/* Please keep the SSL backend-specific #if branches in this order:
*
* 1. USE_OPENSSL
* 2. USE_WOLFSSL
* 3. USE_GNUTLS
* 4. USE_MBEDTLS
*/
#include "curl_ed25519.h"
#ifdef USE_WOLFSSL
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#endif
#ifdef USE_OPENSSL
#include <openssl/evp.h>
CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
const unsigned char *msg, size_t msglen,
unsigned char *sig, size_t *siglen)
{
EVP_PKEY *pkey;
EVP_MD_CTX *mdctx;
size_t slen;
int rc;
if(keylen != CURL_ED25519_KEYLEN)
return CURLE_BAD_FUNCTION_ARGUMENT;
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, key, keylen);
if(!pkey)
return CURLE_AUTH_ERROR;
mdctx = EVP_MD_CTX_new();
if(!mdctx) {
EVP_PKEY_free(pkey);
return CURLE_OUT_OF_MEMORY;
}
rc = EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey);
if(rc != 1) {
EVP_MD_CTX_free(mdctx);
EVP_PKEY_free(pkey);
return CURLE_AUTH_ERROR;
}
slen = CURL_ED25519_SIGLEN;
rc = EVP_DigestSign(mdctx, sig, &slen, msg, msglen);
EVP_MD_CTX_free(mdctx);
EVP_PKEY_free(pkey);
if(rc != 1)
return CURLE_AUTH_ERROR;
*siglen = slen;
return CURLE_OK;
}
#elif defined(USE_WOLFSSL) && \
(defined(HAVE_ED25519) || defined(WOLFSSL_CURVE25519_USE_ED25519)) && \
defined(HAVE_ED25519_KEY_IMPORT) && defined(HAVE_ED25519_SIGN)
#include <wolfssl/wolfcrypt/ed25519.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/random.h>
CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
const unsigned char *msg, size_t msglen,
unsigned char *sig, size_t *siglen)
{
int ret;
ed25519_key edkey;
word32 outlen;
unsigned char pubkey[ED25519_PUB_KEY_SIZE];
if(keylen != ED25519_KEY_SIZE)
return CURLE_BAD_FUNCTION_ARGUMENT;
ret = wc_ed25519_init(&edkey);
if(ret)
return CURLE_AUTH_ERROR;
ret = wc_ed25519_import_private_only(key, ED25519_KEY_SIZE, &edkey);
if(ret)
goto fail;
ret = wc_ed25519_make_public(&edkey, pubkey, ED25519_PUB_KEY_SIZE);
if(ret)
goto fail;
ret = wc_ed25519_import_private_key(key, ED25519_KEY_SIZE,
pubkey, ED25519_PUB_KEY_SIZE, &edkey);
if(ret)
goto fail;
outlen = ED25519_SIG_SIZE;
ret = wc_ed25519_sign_msg(msg, (word32)msglen, sig, &outlen, &edkey);
if(ret)
goto fail;
*siglen = (size_t)outlen;
wc_ed25519_free(&edkey);
return CURLE_OK;
fail:
wc_ed25519_free(&edkey);
return CURLE_AUTH_ERROR;
}
#elif defined(USE_GNUTLS)
#include <nettle/eddsa.h>
CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
const unsigned char *msg, size_t msglen,
unsigned char *sig, size_t *siglen)
{
uint8_t pubkey[ED25519_KEY_SIZE];
if(keylen != ED25519_KEY_SIZE)
return CURLE_BAD_FUNCTION_ARGUMENT;
nettle_ed25519_sha512_public_key(pubkey, key);
nettle_ed25519_sha512_sign(pubkey, key, msglen, msg, sig);
*siglen = CURL_ED25519_SIGLEN;
return CURLE_OK;
}
#else /* no Ed25519-capable backend */
CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
const unsigned char *msg, size_t msglen,
unsigned char *sig, size_t *siglen)
{
(void)key;
(void)keylen;
(void)msg;
(void)msglen;
(void)sig;
(void)siglen;
return CURLE_NOT_BUILT_IN;
}
#endif /* Ed25519 backends */
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_HTTPSIG */
+44
View File
@@ -0,0 +1,44 @@
#ifndef HEADER_CURL_ED25519_H
#define HEADER_CURL_ED25519_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HTTPSIG)
#define CURL_ED25519_SIGLEN 64
#define CURL_ED25519_KEYLEN 32
/* Sign with Ed25519 (RFC 8032).
* key/keylen: raw 32-byte private seed
* msg/msglen: data to sign
* sig: output buffer (at least CURL_ED25519_SIGLEN bytes)
* siglen: out - actual signature length on success
* Returns CURLE_OK or CURLE_NOT_BUILT_IN if no backend supports Ed25519. */
CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
const unsigned char *msg, size_t msglen,
unsigned char *sig, size_t *siglen);
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_HTTPSIG */
#endif /* HEADER_CURL_ED25519_H */
+7 -8
View File
@@ -30,16 +30,15 @@
#include "rand.h"
#include "curl_fopen.h"
/*
The dirslash() function breaks a null-terminated pathname string into
directory and filename components then returns the directory component up
to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
this instead returns a "" string.
/* The dirslash() function breaks a null-terminated pathname string into
directory and filename components then returns the directory component up
to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
this instead returns a "" string.
This function returns a pointer to malloc'ed memory.
This function returns a pointer to malloc'ed memory.
The input path to this function is expected to have a filename part.
*/
The input path to this function is expected to have a filename part.
*/
#ifdef _WIN32
#define PATHSEP "\\"
+266 -8
View File
@@ -55,7 +55,7 @@
#define CURL_ALIGN8
#endif
#if defined(CURL_HAVE_DIAG) && defined(__APPLE__)
#if defined(CURL_HAVE_DIAG) && defined(__APPLE__) && !defined(HAVE_GSSAPPLE)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
@@ -81,7 +81,6 @@ enum min_err_code {
/* libcurl is also passing this struct to these functions, which are not yet
* stubbed:
* gss_inquire_context()
* gss_unwrap()
* gss_wrap()
*/
@@ -93,6 +92,12 @@ struct stub_gss_ctx_id_t_desc {
char creds[250];
};
/* Stub credential: tracks which mechanisms are allowed */
struct stub_gss_cred_id_t_desc {
int allow_krb5;
int allow_ntlm;
};
static OM_uint32 stub_gss_init_sec_context(
OM_uint32 *min,
gss_cred_id_t initiator_cred_handle,
@@ -116,7 +121,6 @@ static OM_uint32 stub_gss_init_sec_context(
char *token = NULL;
const char *creds = NULL;
(void)initiator_cred_handle;
(void)mech_type;
(void)time_req;
(void)input_chan_bindings;
@@ -214,6 +218,16 @@ static OM_uint32 stub_gss_init_sec_context(
if(strstr(creds, "NTLM"))
ctx->have_ntlm = 1;
/* If a credential restricts allowed mechs, honour it */
if(initiator_cred_handle != GSS_C_NO_CREDENTIAL) {
struct stub_gss_cred_id_t_desc *cred =
(struct stub_gss_cred_id_t_desc *)initiator_cred_handle;
if(!cred->allow_krb5)
ctx->have_krb5 = 0;
if(!cred->allow_ntlm)
ctx->have_ntlm = 0;
}
if(ctx->have_krb5)
ctx->sent = STUB_GSS_KRB5;
else if(ctx->have_ntlm)
@@ -307,6 +321,174 @@ static OM_uint32 stub_gss_delete_sec_context(
return GSS_S_COMPLETE;
}
/* NTLMSSP OID: 1.3.6.1.4.1.311.2.2.10 */
static gss_OID_desc stub_ntlmssp_oid = {
10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")
};
static OM_uint32 stub_gss_inquire_context(
OM_uint32 *min,
struct stub_gss_ctx_id_t_desc *context,
gss_name_t *src_name,
gss_name_t *targ_name,
OM_uint32 *lifetime_rec,
gss_OID *mech_type,
OM_uint32 *ctx_flags,
int *locally_initiated,
int *open_context)
{
(void)src_name;
(void)targ_name;
(void)lifetime_rec;
(void)ctx_flags;
(void)locally_initiated;
(void)open_context;
if(!min)
return GSS_S_FAILURE;
if(!context) {
*min = STUB_GSS_INVALID_CTX;
return GSS_S_FAILURE;
}
*min = 0;
if(mech_type) {
switch(context->sent) {
case STUB_GSS_NTLM1:
case STUB_GSS_NTLM3:
*mech_type = &stub_ntlmssp_oid;
break;
default:
*mech_type = (gss_OID)&Curl_krb5_mech_oid;
break;
}
}
return GSS_S_COMPLETE;
}
static OM_uint32 stub_gss_acquire_cred(
OM_uint32 *min,
gss_name_t desired_name,
OM_uint32 time_req,
gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t *output_cred_handle,
gss_OID_set *actual_mechs,
OM_uint32 *time_rec)
{
(void)desired_name;
(void)time_req;
(void)desired_mechs;
(void)cred_usage;
(void)actual_mechs;
(void)time_rec;
if(!min)
return GSS_S_FAILURE;
*min = 0;
/* Allocate a stub credential that initially allows all mechanisms */
if(output_cred_handle) {
struct stub_gss_cred_id_t_desc *cred =
curlx_calloc(1, sizeof(*cred));
if(!cred) {
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
cred->allow_krb5 = 1;
cred->allow_ntlm = 1;
*output_cred_handle = (gss_cred_id_t)cred;
}
return GSS_S_COMPLETE;
}
static OM_uint32 stub_gss_indicate_mechs(
OM_uint32 *min,
gss_OID_set *mech_set)
{
const char *creds;
OM_uint32 major;
if(!min)
return GSS_S_FAILURE;
*min = 0;
creds = getenv("CURL_STUB_GSS_CREDS");
if(!creds) {
*min = STUB_GSS_INVALID_CREDS;
return GSS_S_FAILURE;
}
major = gss_create_empty_oid_set(min, mech_set);
if(GSS_ERROR(major))
return major;
/* Always include Kerberos */
gss_add_oid_set_member(min, (gss_OID)&Curl_krb5_mech_oid, mech_set);
/* Include NTLM if the stub creds contain NTLM */
if(strstr(creds, "NTLM"))
gss_add_oid_set_member(min, &stub_ntlmssp_oid, mech_set);
return GSS_S_COMPLETE;
}
#ifdef HAVE_GSS_SET_NEG_MECHS /* MIT Kerberos 1.8+ (2010-03-02),
missing from Apple GSS, GNU GSS */
static OM_uint32 stub_gss_set_neg_mechs(OM_uint32 *min,
gss_cred_id_t cred_handle,
const gss_OID_set mech_set)
{
struct stub_gss_cred_id_t_desc *cred;
size_t i;
int found_krb5 = 0;
int found_ntlm = 0;
if(!min)
return GSS_S_FAILURE;
*min = 0;
if(cred_handle == GSS_C_NO_CREDENTIAL)
return GSS_S_FAILURE;
cred = (struct stub_gss_cred_id_t_desc *)cred_handle;
/* Determine which mechs are in the allowed set */
if(mech_set) {
for(i = 0; i < mech_set->count; i++) {
gss_OID oid = &mech_set->elements[i];
if(oid->length == Curl_krb5_mech_oid.length &&
!memcmp(oid->elements, Curl_krb5_mech_oid.elements, oid->length))
found_krb5 = 1;
if(oid->length == stub_ntlmssp_oid.length &&
!memcmp(oid->elements, stub_ntlmssp_oid.elements, oid->length))
found_ntlm = 1;
}
}
cred->allow_krb5 = found_krb5;
cred->allow_ntlm = found_ntlm;
return GSS_S_COMPLETE;
}
#endif /* HAVE_GSS_SET_NEG_MECHS */
static OM_uint32 stub_gss_release_cred(
OM_uint32 *min,
gss_cred_id_t *cred_handle)
{
if(!min)
return GSS_S_FAILURE;
*min = 0;
if(cred_handle && *cred_handle != GSS_C_NO_CREDENTIAL) {
curlx_free(*cred_handle);
*cred_handle = GSS_C_NO_CREDENTIAL;
}
return GSS_S_COMPLETE;
}
#endif /* CURL_GSS_STUB */
OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
@@ -318,7 +500,8 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags)
OM_uint32 *ret_flags,
gss_cred_id_t cred_handle)
{
OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
@@ -326,7 +509,8 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
req_flags |= GSS_C_MUTUAL_FLAG;
if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) {
#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.8+, missing from GNU GSS */
#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.7+ (2009-06-02), Apple GSS,
missing from GNU GSS */
req_flags |= GSS_C_DELEG_POLICY_FLAG;
#else
infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
@@ -340,7 +524,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_init_sec_context(minor_status,
GSS_C_NO_CREDENTIAL, /* cred_handle */
cred_handle,
(struct stub_gss_ctx_id_t_desc **)context,
target_name,
mech_type,
@@ -355,7 +539,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
#endif /* CURL_GSS_STUB */
return gss_init_sec_context(minor_status,
GSS_C_NO_CREDENTIAL, /* cred_handle */
cred_handle,
context,
target_name,
mech_type,
@@ -383,6 +567,80 @@ OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
return gss_delete_sec_context(min, context, output_token);
}
OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status,
gss_ctx_id_t context,
gss_OID *mech_type)
{
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_inquire_context(minor_status,
(struct stub_gss_ctx_id_t_desc *)context,
NULL, NULL, NULL, mech_type,
NULL, NULL, NULL);
#endif /* CURL_GSS_STUB */
return gss_inquire_context(minor_status, context,
NULL, NULL, NULL, mech_type,
NULL, NULL, NULL);
}
OM_uint32 Curl_gss_acquire_cred(OM_uint32 *minor_status,
gss_name_t desired_name,
OM_uint32 time_req,
gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t *output_cred_handle,
gss_OID_set *actual_mechs,
OM_uint32 *time_rec)
{
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_acquire_cred(minor_status, desired_name, time_req,
desired_mechs, cred_usage,
output_cred_handle, actual_mechs, time_rec);
#endif /* CURL_GSS_STUB */
return gss_acquire_cred(minor_status, desired_name, time_req,
desired_mechs, cred_usage,
output_cred_handle, actual_mechs, time_rec);
}
OM_uint32 Curl_gss_indicate_mechs(OM_uint32 *minor_status,
gss_OID_set *mech_set)
{
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_indicate_mechs(minor_status, mech_set);
#endif /* CURL_GSS_STUB */
return gss_indicate_mechs(minor_status, mech_set);
}
#ifdef HAVE_GSS_SET_NEG_MECHS
OM_uint32 Curl_gss_set_neg_mechs(OM_uint32 *minor_status,
gss_cred_id_t cred_handle,
const gss_OID_set mech_set)
{
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_set_neg_mechs(minor_status, cred_handle, mech_set);
#endif /* CURL_GSS_STUB */
return gss_set_neg_mechs(minor_status, cred_handle, mech_set);
}
#endif /* HAVE_GSS_SET_NEG_MECHS */
OM_uint32 Curl_gss_release_cred(OM_uint32 *minor_status,
gss_cred_id_t *cred_handle)
{
#ifdef CURL_GSS_STUB
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_release_cred(minor_status, cred_handle);
#endif /* CURL_GSS_STUB */
return gss_release_cred(minor_status, cred_handle);
}
#ifdef CURLVERBOSE
#define GSS_LOG_BUFFER_LEN 1024
static size_t display_gss_error(OM_uint32 status, int type,
@@ -440,7 +698,7 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
}
#endif /* CURLVERBOSE */
#if defined(CURL_HAVE_DIAG) && defined(__APPLE__)
#if defined(CURL_HAVE_DIAG) && defined(__APPLE__) && !defined(HAVE_GSSAPPLE)
#pragma GCC diagnostic pop
#endif
+27 -1
View File
@@ -41,12 +41,38 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags);
OM_uint32 *ret_flags,
gss_cred_id_t cred_handle);
OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
gss_ctx_id_t *context,
gss_buffer_t output_token);
OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status,
gss_ctx_id_t context,
gss_OID *mech_type);
OM_uint32 Curl_gss_acquire_cred(OM_uint32 *minor_status,
gss_name_t desired_name,
OM_uint32 time_req,
gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t *output_cred_handle,
gss_OID_set *actual_mechs,
OM_uint32 *time_rec);
OM_uint32 Curl_gss_indicate_mechs(OM_uint32 *minor_status,
gss_OID_set *mech_set);
#ifdef HAVE_GSS_SET_NEG_MECHS
OM_uint32 Curl_gss_set_neg_mechs(OM_uint32 *minor_status,
gss_cred_id_t cred_handle,
const gss_OID_set mech_set);
#endif
OM_uint32 Curl_gss_release_cred(OM_uint32 *minor_status,
gss_cred_id_t *cred_handle);
#ifdef CURLVERBOSE
/* Helper to log a GSS-API error status */
void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+1
View File
@@ -26,6 +26,7 @@
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \
!defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
!defined(CURL_DISABLE_HTTPSIG) || \
defined(USE_LIBSSH2) || defined(USE_SSL)
#define HMAC_MD5_LENGTH 16
+2 -2
View File
@@ -76,7 +76,7 @@
#elif defined(USE_MBEDTLS) && defined(HAVE_MBEDTLS_DES_CRYPT_ECB)
# include <mbedtls/version.h>
# if MBEDTLS_VERSION_NUMBER < 0x03020000
# error "mbedTLS 3.2.0 or later required"
# error "mbedTLS 3.2.0 or greater required"
# endif
# include <mbedtls/des.h>
# define USE_MBEDTLS_DES
@@ -551,7 +551,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(const unsigned char *ntlmv2hash,
unsigned char **ntresp,
unsigned int *ntresp_len)
{
/* NTLMv2 response structure :
/* NTLMv2 response structure:
-----------------------------------------------------------------------------
0 HMAC MD5 16 bytes
------BLOB-------------------------------------------------------------------
+3 -5
View File
@@ -142,7 +142,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
const struct SASLproto *params)
{
unsigned long auth = data->set.httpauth;
uint32_t auth = data->set.httpauth;
sasl->params = params; /* Set protocol dependent parameters */
sasl->state = SASL_STOP; /* Not yet running */
@@ -229,7 +229,7 @@ static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
const char *serverdata = Curl_bufref_ptr(out);
if(!*serverdata || *serverdata == '=')
if(!*serverdata)
Curl_bufref_set(out, NULL, 0, NULL);
else {
unsigned char *msg;
@@ -252,9 +252,7 @@ static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
if(sasl->params->flags & SASL_FLAG_BASE64) {
if(!Curl_bufref_ptr(msg)) /* Empty message. */
Curl_bufref_set(msg, "", 0, NULL);
else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
Curl_bufref_set(msg, "=", 1, NULL);
else {
else if(Curl_bufref_len(msg)) {
char *base64;
size_t base64len;
+61 -71
View File
@@ -77,7 +77,7 @@
#if defined(__MINGW32__) && \
(!defined(__MINGW64_VERSION_MAJOR) || (__MINGW64_VERSION_MAJOR < 3))
#error "Building curl requires mingw-w64 3.0 or later"
#error "mingw-w64 3.0 or greater required"
#endif
/* Visual Studio 2010 is the minimum Visual Studio version we support.
@@ -90,7 +90,7 @@
/* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
#pragma warning(disable:4127)
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS /* for getenv(), sscanf() */
#define _CRT_SECURE_NO_WARNINGS /* for getenv(), sscanf(), vsnprintf() */
#endif
#endif /* _MSC_VER */
@@ -149,10 +149,6 @@
# include "config-mac.h"
#endif
#ifdef __riscos__
# include "config-riscos.h"
#endif
#ifdef __OS400__
# include "config-os400.h"
#endif
@@ -182,7 +178,7 @@
#ifdef HAVE_LIBZ
# ifndef ZLIB_CONST
# define ZLIB_CONST /* Use z_const. Supported by v1.2.5.2 and upper. */
# define ZLIB_CONST /* Use z_const. Supported by v1.2.5.2 or greater. */
# endif
#endif
@@ -272,13 +268,6 @@
# endif
#endif
/*
* When http is disabled rtsp is not supported.
*/
#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
# define CURL_DISABLE_RTSP
#endif
/*
* When HTTP is disabled, disable HTTP-only features
*/
@@ -286,8 +275,8 @@
# ifndef CURL_DISABLE_ALTSVC
# define CURL_DISABLE_ALTSVC
# endif
# ifndef CURL_DISABLE_COOKIES
# define CURL_DISABLE_COOKIES
# ifndef CURL_DISABLE_AWS
# define CURL_DISABLE_AWS
# endif
# ifndef CURL_DISABLE_BASIC_AUTH
# define CURL_DISABLE_BASIC_AUTH
@@ -295,8 +284,8 @@
# ifndef CURL_DISABLE_BEARER_AUTH
# define CURL_DISABLE_BEARER_AUTH
# endif
# ifndef CURL_DISABLE_AWS
# define CURL_DISABLE_AWS
# ifndef CURL_DISABLE_COOKIES
# define CURL_DISABLE_COOKIES
# endif
# ifndef CURL_DISABLE_DOH
# define CURL_DISABLE_DOH
@@ -310,9 +299,15 @@
# ifndef CURL_DISABLE_HSTS
# define CURL_DISABLE_HSTS
# endif
# ifndef CURL_DISABLE_HTTPSIG
# define CURL_DISABLE_HTTPSIG
# endif
# ifndef CURL_DISABLE_HTTP_AUTH
# define CURL_DISABLE_HTTP_AUTH
# endif
# ifndef CURL_DISABLE_RTSP
# define CURL_DISABLE_RTSP
# endif
# ifndef CURL_DISABLE_WEBSOCKETS
# define CURL_DISABLE_WEBSOCKETS /* no WebSockets without HTTP present */
# endif
@@ -490,10 +485,6 @@
# endif
#endif
#ifndef STDC_HEADERS /* no standard C headers! */
#include <curl/stdcheaders.h>
#endif
#include <stdint.h>
#define HAVE_UINTPTR_T /* assume uintptr_t is provided by stdint.h */
@@ -510,12 +501,15 @@
#endif
#include <limits.h>
/* Include after setting system macros that may affect type sizes
(e.g. 'off_t' or 'time_t'), or suppress warnings
(e.g. '_CRT_SECURE_NO_WARNINGS`), but before including sys/stat.h */
#include <sys/types.h>
#ifdef _WIN32
# ifdef HAVE_IO_H
# include <io.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
/* Large file (>2Gb) support using Win32 functions. */
# define curl_lseek _lseeki64
@@ -834,10 +828,6 @@
#include <time.h>
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/stat.h>
#if !defined(_WIN32) || defined(__MINGW32__)
@@ -957,7 +947,7 @@ struct timeval {
(RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
#error "Missing definition of macro sread!"
#error "Missing definition of macro sread"
#endif
#endif /* HAVE_RECV */
@@ -980,7 +970,7 @@ struct timeval {
#endif /* SEND_NONCONST_ARG2 */
#else /* HAVE_SEND */
#ifndef swrite
#error "Missing definition of macro swrite!"
#error "Missing definition of macro swrite"
#endif
#endif /* HAVE_SEND */
@@ -1060,6 +1050,10 @@ typedef unsigned int curl_bit;
#include "curl_ctype.h"
#if defined(DEBUGBUILD) && defined(NDEBUG)
#error "Debug-enabled builds cannot be combined with NDEBUG"
#endif
/*
* Macro used to include code only in debug builds.
*/
@@ -1194,7 +1188,7 @@ typedef unsigned int curl_bit;
*/
#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
@@ -1254,19 +1248,17 @@ typedef unsigned int curl_bit;
#endif
/* In Windows the default file mode is text but an application can override it.
Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
*/
Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 */
#if defined(_WIN32) || defined(MSDOS)
#define FOPEN_READTEXT "rt"
#define FOPEN_WRITETEXT "wt"
#define FOPEN_APPENDTEXT "at"
#elif defined(__CYGWIN__)
/* 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
endings either CRLF or LF so 't' is appropriate.
*/
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 endings either CRLF or LF so 't' is appropriate. */
#define FOPEN_READTEXT "rt"
#define FOPEN_WRITETEXT "w"
#define FOPEN_APPENDTEXT "a"
@@ -1295,10 +1287,14 @@ endings either CRLF or LF so 't' is appropriate.
#define CURLMAX(x, y) ((x) > (y) ? (x) : (y))
#define CURLMIN(x, y) ((x) < (y) ? (x) : (y))
/* Convenience macro to provide the length of a string literal size without
the null-terminator. Equivalent to strlen() for constant strings. */
#define CURL_CSTRLEN(x) (sizeof(x) - 1)
/* A convenience macro to provide both the string literal and the length of
the string literal in one go, useful for functions that take "string,len"
as their argument */
#define STRCONST(x) x, sizeof(x) - 1
#define STRCONST(x) x, CURL_CSTRLEN(x)
#define CURL_ARRAYSIZE(A) (sizeof(A) / sizeof((A)[0]))
@@ -1338,20 +1334,6 @@ extern curl_calloc_callback Curl_ccalloc;
(ptr) = NULL; \
} while(0)
/* Same as curlx_safefree() but zeroes memory before freeing */
#define curlx_safefreezero(ptr, size) \
do { \
curlx_freezero(ptr, size); \
(ptr) = NULL; \
} while(0)
/* Same as curlx_safefreezero() but determines length with strlen() */
#define curlx_safefreezeroz(ptr) \
do { \
curlx_freezeroz(ptr); \
(ptr) = NULL; \
} while(0)
#include <curl/curl.h> /* for CURL_EXTERN, curl_socket_t, mprintf.h */
#ifdef DEBUGBUILD
@@ -1387,13 +1369,15 @@ extern FILE *curl_dbg_logfile;
/* memory functions */
CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source);
CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1)
void *curl_dbg_malloc(size_t size, int line, const char *source);
void *curl_dbg_malloc(size_t wantedsize, int line, const char *source);
CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2)
void *curl_dbg_calloc(size_t n, size_t size, int line, const char *source);
void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
int line, const char *source);
CURL_EXTERN ALLOC_SIZE(2)
void *curl_dbg_realloc(void *ptr, size_t size, int line, const char *source);
void *curl_dbg_realloc(void *ptr, size_t wantedsize, int line,
const char *source);
CURL_EXTERN ALLOC_FUNC
char *curl_dbg_strdup(const char *str, int line, const char *src);
char *curl_dbg_strdup(const char *str, int line, const char *source);
#if defined(_WIN32) && defined(UNICODE)
CURL_EXTERN ALLOC_FUNC
wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source);
@@ -1581,7 +1565,7 @@ typedef struct sockaddr_un {
#ifdef USE_OPENSSL
/* OpenSSL 3 marks these functions deprecated but we have no replacements (yet)
so tell the compiler to not warn for them:
- DES_* (for NTLM), SSL_CTX_set_srp_* (for TLS-SRP)
- DES_* (for NTLM)
- EVP_PKEY_get1_RSA, MD5_*, RSA_flags, RSA_free (auto-skipped for OpenSSL
built with no-deprecated) */
# define OPENSSL_SUPPRESS_DEPRECATED
@@ -1637,37 +1621,43 @@ typedef struct sockaddr_un {
__NetBSD_Version__ */
#endif
/* NetBSD before 6.1 did not set SS_NBIO for SOCK_NONBLOCK. */
#if defined(SOCK_NONBLOCK) && \
(!defined(__NetBSD__) || (__NetBSD_Version__ >= 601000000))
#define CURL_USE_SOCK_NONBLOCK
#endif
#ifndef _CURL_LOCAL_MEMZERO /* to be removed after a couple of releases */
#ifdef _WIN32
#if defined(_MSC_VER) && defined(NTDDI_VERSION) && \
(NTDDI_VERSION >= 0x0A000010) /* MS SDK 10.0.26100.0+ */
#pragma comment(lib, "volatileaccessu.lib")
#define curlx_memzero(buf, size) SecureZeroMemory2(buf, size)
#define curlx_memzero_low(buf, size) SecureZeroMemory2(buf, size)
#else
#define curlx_memzero(buf, size) SecureZeroMemory(buf, size)
#define curlx_memzero_low(buf, size) SecureZeroMemory(buf, size)
#endif
#elif defined(HAVE_MEMSET_S)
#define curlx_memzero(buf, size) (void)memset_s(buf, size, 0, size)
#define curlx_memzero_low(buf, size) (void)memset_s(buf, size, 0, size)
#elif defined(HAVE_MEMSET_EXPLICIT)
#define curlx_memzero(buf, size) (void)memset_explicit(buf, 0, size)
#define curlx_memzero_low(buf, size) (void)memset_explicit(buf, 0, size)
#elif defined(__CYGWIN__) || \
(defined(__NEWLIB__) && !defined(__CLIB2__)) || \
(defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) || \
(defined(__DragonFly__) && __DragonFly_version >= 500600 /* v5.6+ */) || \
(defined(__FreeBSD__) && __FreeBSD_version >= 1100037 /* v11.0+ */) || \
(defined(__OpenBSD__) && OpenBSD >= 201405 /* v5.5+ */)
#define curlx_memzero(buf, size) explicit_bzero(buf, size)
#elif defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 /* v7.2+ */
#define curlx_memzero(buf, size) (void)explicit_memset(buf, 0, size)
(defined(__DragonFly__) && __DragonFly_version >= 500600 /* 5.6+ */) || \
(defined(__FreeBSD__) && __FreeBSD_version >= 1100037 /* 11.0+ */) || \
(defined(__OpenBSD__) && OpenBSD >= 201405 /* 5.5+ */)
#define curlx_memzero_low(buf, size) explicit_bzero(buf, size)
#elif defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 /* 7.2+ */
#define curlx_memzero_low(buf, size) (void)explicit_memset(buf, 0, size)
#endif
#endif /* !_CURL_LOCAL_MEMZERO */
#ifndef curlx_memzero
#ifndef curlx_memzero_low
#define USE_CURLX_MEMZERO
void curlx_memzero(void *buf, size_t size);
void curlx_memzero_low(void *buf, size_t size);
#endif
void curlx_freezero(void *buf, size_t size);
void curlx_freezeroz(void *buf);
void curlx_memzero(void *buf, size_t size);
void curlx_strzero(void *buf);
#endif /* HEADER_CURL_SETUP_H */
+2 -1
View File
@@ -26,7 +26,8 @@
***************************************************************************/
#include "curl_setup.h"
#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_HTTPSIG) || \
!defined(CURL_DISABLE_DIGEST_AUTH) || \
defined(USE_LIBSSH2) || defined(USE_SSL)
#include "curl_hmac.h"
+4 -4
View File
@@ -112,7 +112,7 @@ static CURLcode Curl_sha512_256_init(void *context)
{
Curl_sha512_256_ctx * const ctx = (Curl_sha512_256_ctx *)context;
*ctx = EVP_MD_CTX_create();
*ctx = EVP_MD_CTX_new();
if(!*ctx)
return CURLE_OUT_OF_MEMORY;
@@ -126,7 +126,7 @@ static CURLcode Curl_sha512_256_init(void *context)
}
/* Cleanup */
EVP_MD_CTX_destroy(*ctx);
EVP_MD_CTX_free(*ctx);
return CURLE_FAILED_INIT;
}
@@ -178,7 +178,7 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
#endif /* NEED_NETBSD_SHA512_256_WORKAROUND */
EVP_MD_CTX_destroy(*ctx);
EVP_MD_CTX_free(*ctx);
*ctx = NULL;
return result;
@@ -650,7 +650,7 @@ static CURLcode Curl_sha512_256_update(void *context,
if(length == 0)
return CURLE_OK; /* Shortcut, do nothing */
/* Note: (count & (CURL_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;
+34 -16
View File
@@ -34,8 +34,11 @@
static void share_destroy(struct Curl_share *share)
{
if(!share)
return;
if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
Curl_cpool_destroy(&share->cpool);
Curl_cpool_destroy(&share->cpool, share->admin);
}
Curl_dnscache_destroy(&share->dnscache);
@@ -61,7 +64,7 @@ static void share_destroy(struct Curl_share *share)
#ifdef USE_MUTEX
Curl_mutex_destroy(&share->lock);
#endif
share->magic = 0;
curlx_memzero(share, sizeof(*share));
curlx_free(share);
}
@@ -97,11 +100,11 @@ static uint32_t share_ref_inc(struct Curl_share *share)
uint32_t n;
#ifdef USE_MUTEX
Curl_mutex_acquire(&share->lock);
n = ++(share->ref_count);
n = ++share->ref_count;
share->has_been_shared = TRUE;
Curl_mutex_release(&share->lock);
#else
n = ++(share->ref_count);
n = ++share->ref_count;
share->has_been_shared = TRUE;
#endif
return n;
@@ -113,10 +116,10 @@ static uint32_t share_ref_dec(struct Curl_share *share)
#ifdef USE_MUTEX
Curl_mutex_acquire(&share->lock);
DEBUGASSERT(share->ref_count);
n = --(share->ref_count);
n = --share->ref_count;
Curl_mutex_release(&share->lock);
#else
n = --(share->ref_count);
n = --share->ref_count;
#endif
return n;
}
@@ -261,7 +264,7 @@ CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
case CURL_LOCK_DATA_CONNECT:
/* It is safe to set this option several times on a share. */
if(!share->cpool.initialized) {
Curl_cpool_init(&share->cpool, share->admin, share, 103);
Curl_cpool_init(&share->cpool, share, 103);
}
break;
@@ -368,11 +371,11 @@ CURLSHcode curl_share_cleanup(CURLSH *sh)
return CURLSHE_OK;
}
CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
curl_lock_access accesstype)
CURLSHcode Curl_share_lock_share(struct Curl_share *share,
struct Curl_easy *data,
curl_lock_data type,
curl_lock_access accesstype)
{
struct Curl_share *share = data->share;
if(!share)
return CURLSHE_INVALID;
@@ -385,10 +388,16 @@ CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
return CURLSHE_OK;
}
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
curl_lock_access accesstype)
{
struct Curl_share *share = data->share;
return Curl_share_lock_share(data->share, data, type, accesstype);
}
CURLSHcode Curl_share_unlock_share(struct Curl_share *share,
struct Curl_easy *data,
curl_lock_data type)
{
if(!share)
return CURLSHE_INVALID;
@@ -400,6 +409,11 @@ CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
return CURLSHE_OK;
}
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
{
return Curl_share_unlock_share(data->share, data, type);
}
CURLcode Curl_share_easy_unlink(struct Curl_easy *data)
{
struct Curl_share *share = data->share;
@@ -407,9 +421,13 @@ CURLcode Curl_share_easy_unlink(struct Curl_easy *data)
if(share) {
bool locked = share_lock_acquire(share, data);
/* If data has a connection from this share, detach it. */
if(data->conn && (share->specifier & (1 << CURL_LOCK_DATA_CONNECT)))
Curl_detach_connection(data);
/* If share caches connections, detach any existing connection and
* forget its identifier. */
if((share->specifier & (1 << CURL_LOCK_DATA_CONNECT))) {
if(data->conn)
Curl_detach_connection(data);
data->state.lastconnect_id = -1;
}
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(share->cookies == data->cookies)
+8
View File
@@ -80,6 +80,14 @@ CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
curl_lock_access accesstype);
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type);
CURLSHcode Curl_share_lock_share(struct Curl_share *share,
struct Curl_easy *data,
curl_lock_data type,
curl_lock_access accesstype);
CURLSHcode Curl_share_unlock_share(struct Curl_share *share,
struct Curl_easy *data,
curl_lock_data type);
/* convenience macro to check if this handle is using a shared SSL spool */
#define CURL_SHARE_ssl_scache(data) \
((data)->share && \
+16 -14
View File
@@ -93,26 +93,29 @@ void Curl_sspi_global_cleanup(void)
* Returns CURLE_OK on success.
*/
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
SEC_WINNT_AUTH_IDENTITY *identity)
SEC_WINNT_AUTH_IDENTITY_EX *identity)
{
xcharp_u useranddomain;
xcharp_u user, dup_user;
xcharp_u domain, dup_domain;
xcharp_u passwd, dup_passwd;
size_t domlen = 0;
size_t pwlen;
domain.const_tchar_ptr = TEXT("");
domain.const_tchar_ptr = _TEXT("");
/* Initialize the identity */
memset(identity, 0, sizeof(*identity));
identity->Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
identity->Length = sizeof(*identity);
useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp);
if(!useranddomain.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, _TEXT('\\'));
if(!user.const_tchar_ptr)
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, _TEXT('/'));
if(user.tchar_ptr) {
domain.tchar_ptr = useranddomain.tchar_ptr;
@@ -121,7 +124,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
}
else {
user.tchar_ptr = useranddomain.tchar_ptr;
domain.const_tchar_ptr = TEXT("");
domain.const_tchar_ptr = _TEXT("");
domlen = 0;
}
@@ -155,17 +158,20 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
curlx_free(dup_domain.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
pwlen = _tcslen(passwd.tchar_ptr);
dup_passwd.tchar_ptr = curlx_tcsdup(passwd.tchar_ptr);
if(!dup_passwd.tchar_ptr) {
curlx_free(dup_user.tchar_ptr);
curlx_free(dup_domain.tchar_ptr);
curlx_memzero(passwd.tchar_ptr, pwlen * sizeof(*passwd.tchar_ptr));
curlx_free(passwd.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
identity->Password = dup_passwd.tbyte_ptr;
identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
identity->PasswordLength = curlx_uztoul(pwlen);
dup_passwd.tchar_ptr = NULL;
curlx_memzero(passwd.tchar_ptr, pwlen * sizeof(*passwd.tchar_ptr));
curlx_free(passwd.tchar_ptr);
identity->User = dup_user.tbyte_ptr;
@@ -175,13 +181,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
identity->DomainLength = curlx_uztoul(domlen);
dup_domain.tchar_ptr = NULL;
/* Setup the identity's flags */
identity->Flags = (unsigned long)
#ifdef UNICODE
SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
identity->Flags = CURL_SEC_WINNT_AUTH_IDENTITY;
return CURLE_OK;
}
@@ -195,10 +195,12 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
*
* identity [in/out] - The identity structure.
*/
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity)
{
if(identity) {
curlx_safefree(identity->User);
curlx_memzero(identity->Password,
identity->PasswordLength * sizeof(*identity->Password));
curlx_safefree(identity->Password);
curlx_safefree(identity->Domain);
}
+20 -3
View File
@@ -29,19 +29,36 @@
#include <sspi.h>
/* Local helper macro */
#ifdef UNICODE
#define CURL_SEC_WINNT_AUTH_IDENTITY SEC_WINNT_AUTH_IDENTITY_UNICODE
#else
#define CURL_SEC_WINNT_AUTH_IDENTITY SEC_WINNT_AUTH_IDENTITY_ANSI
#endif
/* Offered by mingw-w64 v9+, MS SDK 7.0A/VS2010+ */
#ifndef SECPKG_ATTR_ENDPOINT_BINDINGS
#define SECPKG_ATTR_ENDPOINT_BINDINGS 26
/* !checksrc! disable TYPEDEFSTRUCT 1 */
typedef struct {
unsigned long BindingsLength;
SEC_CHANNEL_BINDINGS *Bindings;
} SecPkgContext_Bindings;
#endif
CURLcode Curl_sspi_global_init(void);
void Curl_sspi_global_cleanup(void);
/* This is used to populate the domain in an SSPI identity structure */
CURLcode Curl_override_sspi_http_realm(const char *chlg,
SEC_WINNT_AUTH_IDENTITY *identity);
SEC_WINNT_AUTH_IDENTITY_EX *identity);
/* This is used to generate an SSPI identity structure */
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
SEC_WINNT_AUTH_IDENTITY *identity);
SEC_WINNT_AUTH_IDENTITY_EX *identity);
/* This is used to free an SSPI identity structure */
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity);
/* Forward-declaration of global variables defined in curl_sspi.c */
extern PSecurityFunctionTable Curl_pSecFn;
+73 -52
View File
@@ -27,7 +27,41 @@
#ifdef USE_THREADS
#ifdef HAVE_THREADS_POSIX
#ifdef _WIN32
curl_thread_t Curl_thread_create(
CURL_THREAD_RETURN_T(CURL_STDCALL *func)(void *), void *arg)
{
curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL);
if(!t) {
DWORD gle = GetLastError();
/* !checksrc! disable ERRNOVAR 1 */
errno = (gle == ERROR_ACCESS_DENIED ||
gle == ERROR_NOT_ENOUGH_MEMORY) ?
EACCES : EINVAL;
return curl_thread_t_null;
}
return t;
}
void Curl_thread_destroy(curl_thread_t *hnd)
{
if(*hnd != curl_thread_t_null) {
CloseHandle(*hnd);
*hnd = curl_thread_t_null;
}
}
int Curl_thread_join(curl_thread_t *hnd)
{
int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
Curl_thread_destroy(hnd);
return ret;
}
#elif defined(HAVE_THREADS_POSIX)
struct Curl_actual_call {
unsigned int (*func)(void *);
@@ -95,40 +129,6 @@ int Curl_thread_join(curl_thread_t *hnd)
return ret;
}
#elif defined(_WIN32)
curl_thread_t Curl_thread_create(
CURL_THREAD_RETURN_T(CURL_STDCALL *func)(void *), void *arg)
{
curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL);
if(!t) {
DWORD gle = GetLastError();
/* !checksrc! disable ERRNOVAR 1 */
errno = (gle == ERROR_ACCESS_DENIED ||
gle == ERROR_NOT_ENOUGH_MEMORY) ?
EACCES : EINVAL;
return curl_thread_t_null;
}
return t;
}
void Curl_thread_destroy(curl_thread_t *hnd)
{
if(*hnd != curl_thread_t_null) {
CloseHandle(*hnd);
*hnd = curl_thread_t_null;
}
}
int Curl_thread_join(curl_thread_t *hnd)
{
int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
Curl_thread_destroy(hnd);
return ret;
}
#else
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
#endif
@@ -136,7 +136,40 @@ int Curl_thread_join(curl_thread_t *hnd)
#ifdef USE_MUTEX
#ifdef HAVE_THREADS_POSIX
#ifdef _WIN32
void Curl_cond_signal(CONDITION_VARIABLE *c)
{
WakeConditionVariable(c);
}
void Curl_cond_wait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m)
{
SleepConditionVariableCS(c, m, INFINITE);
}
CURLcode Curl_cond_timedwait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m,
uint32_t timeout_ms)
{
if(!SleepConditionVariableCS(c, m, (DWORD)timeout_ms)) {
DWORD err = GetLastError();
return (err == ERROR_TIMEOUT) ?
CURLE_OPERATION_TIMEDOUT : CURLE_UNRECOVERABLE_POLL;
}
return CURLE_OK;
}
curl_thread_id_t Curl_thread_get_current_id(void)
{
return GetCurrentThreadId();
}
bool Curl_thread_is_current(curl_thread_id_t tid)
{
return tid == GetCurrentThreadId();
}
#elif defined(HAVE_THREADS_POSIX)
void Curl_cond_signal(pthread_cond_t *c)
{
@@ -186,28 +219,16 @@ CURLcode Curl_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m,
return rc ? CURLE_UNRECOVERABLE_POLL : CURLE_OK;
}
#elif defined(_WIN32)
void Curl_cond_signal(CONDITION_VARIABLE *c)
curl_thread_id_t Curl_thread_get_current_id(void)
{
WakeConditionVariable(c);
return pthread_self();
}
void Curl_cond_wait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m)
bool Curl_thread_is_current(curl_thread_id_t tid)
{
SleepConditionVariableCS(c, m, INFINITE);
return !!pthread_equal(tid, pthread_self());
}
CURLcode Curl_cond_timedwait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m,
uint32_t timeout_ms)
{
if(!SleepConditionVariableCS(c, m, (DWORD)timeout_ms)) {
DWORD err = GetLastError();
return (err == ERROR_TIMEOUT) ?
CURLE_OPERATION_TIMEDOUT : CURLE_UNRECOVERABLE_POLL;
}
return CURLE_OK;
}
#else
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
#endif
+20 -14
View File
@@ -26,24 +26,12 @@
#include "curl_setup.h"
#ifdef USE_MUTEX
#ifdef HAVE_THREADS_POSIX
# define CURL_THREAD_RETURN_T unsigned int
# define CURL_STDCALL
# define curl_mutex_t pthread_mutex_t
# define curl_thread_t pthread_t *
# define curl_thread_t_null (pthread_t *)0
# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
# define curl_cond_t pthread_cond_t
# define Curl_cond_init(c) pthread_cond_init(c, NULL)
# define Curl_cond_destroy(c) pthread_cond_destroy(c)
#elif defined(_WIN32)
#ifdef _WIN32
# define CURL_THREAD_RETURN_T DWORD
# define CURL_STDCALL WINAPI
# define curl_mutex_t CRITICAL_SECTION
# define curl_thread_t HANDLE
# define curl_thread_id_t DWORD
# define curl_thread_t_null (HANDLE)0
# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1)
# define Curl_mutex_acquire(m) EnterCriticalSection(m)
@@ -52,6 +40,20 @@
# define curl_cond_t CONDITION_VARIABLE
# define Curl_cond_init(c) InitializeConditionVariable(c)
# define Curl_cond_destroy(c) (void)(c)
#elif defined(HAVE_THREADS_POSIX)
# define CURL_THREAD_RETURN_T unsigned int
# define CURL_STDCALL
# define curl_mutex_t pthread_mutex_t
# define curl_thread_t pthread_t *
# define curl_thread_id_t pthread_t
# define curl_thread_t_null (pthread_t *)0
# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
# define curl_cond_t pthread_cond_t
# define Curl_cond_init(c) pthread_cond_init(c, NULL)
# define Curl_cond_destroy(c) pthread_cond_destroy(c)
#else
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
#endif
@@ -61,6 +63,10 @@ void Curl_cond_wait(curl_cond_t *c, curl_mutex_t *m);
/* Returns CURLE_OPERATION_TIMEDOUT on timeout */
CURLcode Curl_cond_timedwait(curl_cond_t *c, curl_mutex_t *m,
uint32_t timeout_ms);
curl_thread_id_t Curl_thread_get_current_id(void);
bool Curl_thread_is_current(curl_thread_id_t tid);
#endif /* USE_MUTEX */
#ifdef USE_THREADS
+30 -30
View File
@@ -28,7 +28,6 @@
#include "cfilters.h"
#include "multiif.h"
#include "cf-dns.h"
#include "cf-recvbuf.h"
#include "cf-socket.h"
#include "cf-setup.h"
@@ -42,6 +41,7 @@
#include "progress.h"
#include "socks.h"
#include "curlx/strparse.h"
#include "vdns/cf-dns.h"
#include "vtls/vtls.h"
#include "vquic/vquic.h"
#include "curlx/strcopy.h"
@@ -51,11 +51,11 @@ static void trc_write(struct Curl_easy *data, curl_infotype type,
{
if(data->set.verbose) {
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
Curl_set_in_callback(data, TRUE);
struct Curl_mapi_guard guard;
CURL_CBAPI_START(&guard, data, easy_fdebug);
(void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
data->set.debugdata);
Curl_set_in_callback(data, inCallback);
CURL_CBAPI_END(&guard);
}
else {
static const char s_infotype[CURLINFO_END][3] = {
@@ -92,8 +92,7 @@ static struct curl_trc_feat Curl_trc_feat_ids = {
static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
{
curl_off_t cid = data->conn ?
data->conn->connection_id : data->state.recent_conn_id;
curl_off_t cid = data->state.lastconnect_id;
if(data->id >= 0) {
if(cid >= 0)
return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
@@ -133,22 +132,21 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
char buf[TRC_LINE_MAX];
size_t len;
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
struct Curl_mapi_guard guard;
if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
len = trc_print_ids(data, buf, TRC_LINE_MAX);
len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
(int)size, ptr);
len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
Curl_set_in_callback(data, TRUE);
CURL_CBAPI_START(&guard, data, easy_fdebug);
(void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
Curl_set_in_callback(data, inCallback);
CURL_CBAPI_END(&guard);
}
else {
Curl_set_in_callback(data, TRUE);
CURL_CBAPI_START(&guard, data, easy_fdebug);
(void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
size, data->set.debugdata);
Curl_set_in_callback(data, inCallback);
CURL_CBAPI_END(&guard);
}
}
else {
@@ -220,6 +218,12 @@ struct curl_trc_feat Curl_trc_feat_dns = {
"DNS",
CURL_LOG_LVL_NONE,
};
#ifndef CURL_DISABLE_DOH
struct curl_trc_feat Curl_trc_feat_doh = {
"DoH",
CURL_LOG_LVL_NONE,
};
#endif
struct curl_trc_feat Curl_trc_feat_timer = {
"TIMER",
CURL_LOG_LVL_NONE,
@@ -303,9 +307,6 @@ static const char * const Curl_trc_timer_names[] = {
"100_TIMEOUT",
"ASYNC_NAME",
"CONNECTTIMEOUT",
"DNS_PER_NAME",
"DNS_PER_NAME2",
"HAPPY_EYEBALLS_DNS",
"HAPPY_EYEBALLS",
"MULTI_PENDING",
"SPEEDCHECK",
@@ -321,7 +322,7 @@ static const char *trc_timer_name(int tid)
{
if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names)))
return Curl_trc_timer_names[(size_t)tid];
return "UNKNOWN?";
return "TIMER-???";
}
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
@@ -338,15 +339,15 @@ void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
void Curl_trc_easy_timers(struct Curl_easy *data)
{
if(CURL_TRC_TIMER_is_verbose(data)) {
struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
if(e) {
const struct curltime *pnow = Curl_pgrs_now(data);
while(e) {
struct time_node *n = Curl_node_elem(e);
e = Curl_node_next(e);
CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns",
curlx_ptimediff_us(&n->time, pnow));
if(CURL_TRC_TIMER_is_verbose(data) && data->multi) {
if(data->state.timeouts.first < EXPIRE_LAST) {
struct expire_timers *timeouts = &data->state.timeouts;
timediff_t base_us =
Curl_timeouts_offset_us(&data->multi->timeouts, Curl_pgrs_now(data));
uint8_t id = data->state.timeouts.first;
for(; id < EXPIRE_LAST; id = timeouts->next[id]) {
CURL_TRC_TIMER(data, id, "expires in %" FMT_TIMEDIFF_T "us",
timeouts->offset_us[id] - base_us);
}
}
}
@@ -531,6 +532,9 @@ static struct trc_feat_def trc_feats[] = {
{ &Curl_trc_feat_read, TRC_CT_NONE },
{ &Curl_trc_feat_write, TRC_CT_NONE },
{ &Curl_trc_feat_dns, TRC_CT_NETWORK },
#ifndef CURL_DISABLE_DOH
{ &Curl_trc_feat_doh, TRC_CT_NETWORK },
#endif
{ &Curl_trc_feat_timer, TRC_CT_NETWORK },
#ifdef USE_THREADS
{ &Curl_trc_feat_threads, TRC_CT_NONE },
@@ -545,7 +549,7 @@ static struct trc_feat_def trc_feats[] = {
{ &Curl_trc_feat_ssls, TRC_CT_NETWORK },
#endif
#ifdef USE_SSH
{ &Curl_trc_feat_ssh, TRC_CT_PROTOCOL },
{ &Curl_trc_feat_ssh, TRC_CT_PROTOCOL },
#endif
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
{ &Curl_trc_feat_ws, TRC_CT_PROTOCOL },
@@ -653,10 +657,6 @@ static CURLcode trc_opt(const char *config)
trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
else if(curlx_str_casecompare(&out, "proxy"))
trc_apply_level_by_category(TRC_CT_PROXY, lvl);
else if(curlx_str_casecompare(&out, "doh")) {
struct Curl_str dns = { "dns", 3 };
trc_apply_level_by_name(&dns, lvl);
}
else
trc_apply_level_by_name(&out, lvl);
+3
View File
@@ -307,6 +307,9 @@ extern struct curl_trc_feat Curl_trc_feat_multi;
extern struct curl_trc_feat Curl_trc_feat_read;
extern struct curl_trc_feat Curl_trc_feat_write;
extern struct curl_trc_feat Curl_trc_feat_dns;
#ifndef CURL_DISABLE_DOH
extern struct curl_trc_feat Curl_trc_feat_doh;
#endif
extern struct curl_trc_feat Curl_trc_feat_timer;
#ifdef USE_THREADS
extern struct curl_trc_feat Curl_trc_feat_threads;
+2 -2
View File
@@ -149,7 +149,7 @@ CURLcode curlx_base64_decode(const char *src,
pos += 3 - padding;
}
/* Null-terminate */
/* null-terminate */
*pos = '\0';
/* Return the decoded data */
@@ -213,7 +213,7 @@ static CURLcode base64_encode(const char *table64,
}
}
/* Null-terminate */
/* null-terminate */
*output = '\0';
/* Return the pointer to the new data (allocated memory) */
+17 -19
View File
@@ -27,30 +27,28 @@
#include "curlx/basename.h"
/*
(Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
Edition)
/* (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
Edition)
The basename() function shall take the pathname pointed to by path and
return a pointer to the final component of the pathname, deleting any
trailing '/' characters.
The basename() function shall take the pathname pointed to by path and
return a pointer to the final component of the pathname, deleting any
trailing '/' characters.
If the string pointed to by path consists entirely of the '/' character,
basename() shall return a pointer to the string "/". If the string pointed
to by path is exactly "//", it is implementation-defined whether '/' or "//"
is returned.
If the string pointed to by path consists entirely of the '/' character,
basename() shall return a pointer to the string "/". If the string pointed
to by path is exactly "//", it is implementation-defined whether '/' or "//"
is returned.
If path is a null pointer or points to an empty string, basename() shall
return a pointer to the string ".".
If path is a null pointer or points to an empty string, basename() shall
return a pointer to the string ".".
The basename() function may modify the string pointed to by path, and may
return a pointer to static storage that may then be overwritten by a
subsequent call to basename().
The basename() function may modify the string pointed to by path, and may
return a pointer to static storage that may then be overwritten by a
subsequent call to basename().
The basename() function need not be reentrant. A function that is not
required to be reentrant is not required to be thread-safe.
*/
The basename() function need not be reentrant. A function that is not
required to be reentrant is not required to be thread-safe.
*/
char *curlx_basename(char *path)
{
/* Ignore all the details above for now and make a quick and simple
+34 -3
View File
@@ -68,7 +68,7 @@ static wchar_t *fn_convert_UTF8_to_wchar(const char *str_utf8)
if(str_w_len > 0) {
str_w = CURLX_MALLOC(str_w_len * sizeof(wchar_t));
if(str_w) {
if(MultiByteToWideChar(CP_UTF8, 0,
if(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
str_utf8, -1, str_w, str_w_len) == 0) {
CURLX_FREE(str_w);
return NULL;
@@ -110,7 +110,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
const wchar_t *in_w;
wchar_t *fbuf = NULL;
/* MS documented "approximate" limit for the maximum path length */
/* MS-documented "approximate" limit for the maximum path length */
const size_t max_path_len = 32767;
#ifndef _UNICODE
@@ -121,7 +121,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
*out = NULL;
/* skip paths already normalized */
if(!_tcsncmp(in, _T("\\\\?\\"), 4))
if(!_tcsncmp(in, _TEXT("\\\\?\\"), 4))
goto cleanup;
#ifndef _UNICODE
@@ -291,6 +291,37 @@ HANDLE curlx_CreateFile(const char *filename,
return handle;
}
HANDLE curlx_FindFirstFile(const char *filename,
WIN32_FIND_DATA *find_data)
{
HANDLE handle = INVALID_HANDLE_VALUE;
#ifdef UNICODE
TCHAR *filename_t = curlx_convert_UTF8_to_wchar(filename);
#else
const TCHAR *filename_t = filename;
#endif
if(filename_t) {
TCHAR *fixed = NULL;
const TCHAR *target;
if(fix_excessive_path(filename_t, &fixed))
target = fixed;
else
target = filename_t;
handle = FindFirstFile(target, find_data);
CURLX_FREE(fixed);
#ifdef UNICODE
curlx_free(filename_t);
#endif
}
return handle;
}
#endif /* !CURL_WINDOWS_UWP */
int curlx_win32_open(const char *filename, int oflag, ...)
+2
View File
@@ -43,6 +43,8 @@ HANDLE curlx_CreateFile(const char *filename,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
HANDLE curlx_FindFirstFile(const char *filename,
WIN32_FIND_DATA *find_data);
#endif /* !CURL_WINDOWS_UWP */
#define curlx_fstat _fstati64
#define curlx_struct_stat struct _stati64
+15 -38
View File
@@ -18,8 +18,6 @@
*/
#include "curl_setup.h"
#ifndef HAVE_INET_NTOP
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -50,12 +48,12 @@
/*
* Format an IPv4 address, more or less like inet_ntop().
*
* Returns `dst' (as a const)
* Returns CURLcode.
* Note:
* - uses no static variables
* - takes an unsigned char* not an in_addr as input
*/
static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
static CURLcode inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
char tmp[sizeof("255.255.255.255")];
size_t len;
@@ -70,22 +68,16 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
((int)((unsigned char)src[3])) & 0xff);
len = strlen(tmp);
if(len == 0 || len >= size) {
#ifdef USE_WINSOCK
errno = WSAEINVAL;
#else
errno = ENOSPC;
#endif
return NULL;
}
if(len == 0 || len >= size)
return CURLE_TOO_LARGE;
curlx_strcopy(dst, size, tmp, len);
return dst;
return CURLE_OK;
}
/*
* Convert IPv6 binary address into presentation (printable) format.
*/
static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
static CURLcode inet_ntop6(const unsigned char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
@@ -154,9 +146,9 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
*/
if(i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
return NULL;
}
CURLcode result = inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp));
if(result)
return result;
tp += strlen(tp);
break;
}
@@ -183,31 +175,18 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
*tp++ = ':';
/* Check for overflow, copy, and we are done. */
if((size_t)(tp - tmp) >= size) {
#ifdef USE_WINSOCK
errno = WSAEINVAL;
#else
errno = ENOSPC;
#endif
return NULL;
}
if((size_t)(tp - tmp) >= size)
return CURLE_TOO_LARGE;
curlx_strcopy(dst, size, tmp, tp - tmp);
return dst;
return CURLE_OK;
}
/*
* Convert a network format address to presentation format.
*
* Returns pointer to presentation format address (`buf').
* Returns NULL on error and errno set with the specific
* error, EAFNOSUPPORT or ENOSPC.
*
* On Windows we store the error in the thread errno, not in the Winsock error
* code. This is to avoid losing the actual last Winsock error. When this
* function returns NULL, check errno not SOCKERRNO.
* Copies result to 'buf' and returns CURLcode.
*/
char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
CURLcode curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
{
switch(af) {
case AF_INET:
@@ -215,8 +194,6 @@ char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
case AF_INET6:
return inet_ntop6((const unsigned char *)src, buf, size);
default:
errno = SOCKEAFNOSUPPORT;
return NULL;
return CURLE_UNSUPPORTED_PROTOCOL;
}
}
#endif /* HAVE_INET_NTOP */
+1 -21
View File
@@ -25,26 +25,6 @@
***************************************************************************/
#include "curl_setup.h"
#ifdef HAVE_INET_NTOP
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifndef _WIN32
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef __AMIGA__
#define curlx_inet_ntop(af, src, buf, size) \
(char *)inet_ntop(af, CURL_UNCONST(src), (unsigned char *)(buf), \
(curl_socklen_t)(size))
#else
#define curlx_inet_ntop(af, src, buf, size) \
inet_ntop(af, src, buf, (curl_socklen_t)(size))
#endif
#else
char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size);
#endif /* HAVE_INET_NTOP */
CURLcode curlx_inet_ntop(int af, const void *src, char *buf, size_t size);
#endif /* HEADER_CURL_INET_NTOP_H */
+9 -17
View File
@@ -19,8 +19,6 @@
*/
#include "curl_setup.h"
#ifndef HAVE_INET_PTON
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -189,18 +187,15 @@ static int inet_pton6(const char *src, unsigned char *dst)
return 1;
}
/* int inet_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address was not valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* notice:
* On Windows we store the error in the thread errno, not
* in the Winsock error code. This is to avoid losing the
* actual last Winsock error. When this function returns
* -1, check errno not SOCKERRNO.
/*
* Convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
*
* Return:
* 1 if the address was valid for the specified address family
* 0 if the address was not valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
*
* author:
* Paul Vixie, 1996.
*/
@@ -212,10 +207,7 @@ int curlx_inet_pton(int af, const char *src, void *dst)
case AF_INET6:
return inet_pton6(src, (unsigned char *)dst);
default:
errno = SOCKEAFNOSUPPORT;
return -1;
}
/* NOTREACHED */
}
#endif /* HAVE_INET_PTON */
-19
View File
@@ -25,25 +25,6 @@
***************************************************************************/
#include "curl_setup.h"
#ifdef HAVE_INET_PTON
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifndef _WIN32
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef __AMIGA__
#define curlx_inet_pton(x, y, z) \
inet_pton(x, (unsigned char *)CURL_UNCONST(y), z)
#else
#define curlx_inet_pton(x, y, z) \
inet_pton(x, y, z)
#endif
#else
int curlx_inet_pton(int af, const char *src, void *dst);
#endif /* HAVE_INET_PTON */
#endif /* HEADER_CURL_INET_PTON_H */
+2 -2
View File
@@ -41,8 +41,8 @@ wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8)
if(str_w_len > 0) {
str_w = curlx_malloc(str_w_len * sizeof(wchar_t));
if(str_w) {
if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
str_w_len) == 0) {
if(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
str_utf8, -1, str_w, str_w_len) == 0) {
curlx_free(str_w);
return NULL;
}
+7 -9
View File
@@ -101,25 +101,23 @@ static void *(* const volatile p_curlx_memset)(void *buf, int val,
/* Local fallback in case there is no system function to securely zero a memory
buffer. */
void curlx_memzero(void *buf, size_t size)
void curlx_memzero_low(void *buf, size_t size)
{
if(buf)
p_curlx_memset(buf, 0, size);
}
#endif
/* Free 'buf' after zeroing its content. */
void curlx_freezero(void *buf, size_t size)
/* Fill 'buf' with zeroes. */
void curlx_memzero(void *buf, size_t size)
{
if(buf)
curlx_memzero(buf, size);
curlx_free(buf);
curlx_memzero_low(buf, size);
}
/* Free 'buf' after zeroing its content, where 'buf' is null-terminated. */
void curlx_freezeroz(void *buf)
/* Fill 'buf' with zeroes, where 'buf' is null-terminated. */
void curlx_strzero(void *buf)
{
if(buf)
curlx_memzero(buf, strlen(buf));
curlx_free(buf);
curlx_memzero_low(buf, strlen(buf));
}
+1 -1
View File
@@ -263,7 +263,7 @@ int curlx_str_cmp(struct Curl_str *str, const char *check)
size_t clen = strlen(check);
return ((str->len == clen) && !strncmp(str->str, check, clen));
}
return !!(str->len);
return !!str->len;
}
/* Trim off 'num' number of bytes from the beginning (left side) of the
+1 -2
View File
@@ -106,8 +106,7 @@ void curlx_str_passblanks(const char **linep);
/* given a hexadecimal letter, return the binary value. '0' returns 0, 'a'
returns 10. THIS ONLY WORKS ON VALID HEXADECIMAL LETTER INPUT. Verify
before calling this!
*/
before calling this. */
extern const unsigned char curlx_hexasciitable[];
#define curlx_hexval(x) (unsigned char)(curlx_hexasciitable[(x) - '0'] & 0x0f)
+11 -8
View File
@@ -25,26 +25,24 @@
#ifdef _WIN32
#include "system_win32.h"
LARGE_INTEGER Curl_freq;
static LARGE_INTEGER s_time_freq;
/* For tool or tests, we must initialize before calling curlx_now().
Providing this function here is wrong. */
void curlx_now_init(void)
{
QueryPerformanceFrequency(&Curl_freq);
QueryPerformanceFrequency(&s_time_freq);
}
/* In case of bug fix this function has a counterpart in tool_util.c */
void curlx_pnow(struct curltime *pnow)
{
LARGE_INTEGER count;
DEBUGASSERT(Curl_freq.QuadPart);
DEBUGASSERT(s_time_freq.QuadPart);
QueryPerformanceCounter(&count);
pnow->tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
pnow->tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
Curl_freq.QuadPart);
pnow->tv_sec = (time_t)(count.QuadPart / s_time_freq.QuadPart);
pnow->tv_usec = (int)((count.QuadPart % s_time_freq.QuadPart) * 1000000 /
s_time_freq.QuadPart);
}
#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \
@@ -216,6 +214,11 @@ timediff_t curlx_timediff_ceil_ms(struct curltime newer,
return (diff * 1000) + ((newer.tv_usec - older.tv_usec + 999) / 1000);
}
timediff_t curlx_us_to_ceil_ms(timediff_t us)
{
return (us / 1000) + ((us > 0) && (us % 1000));
}
/*
* Returns: time difference in number of microseconds. For too large diffs it
* returns max value.
+3
View File
@@ -59,6 +59,9 @@ timediff_t curlx_ptimediff_ms(const struct curltime *newer,
timediff_t curlx_timediff_ceil_ms(struct curltime newer,
struct curltime older);
/* Returns milliseconds from microseconds, rounded up. */
timediff_t curlx_us_to_ceil_ms(timediff_t us);
/*
* Make sure that the first argument (newer) is the more recent time and older
* is the older time, as otherwise you get a weird negative time-diff back...
-4
View File
@@ -23,10 +23,6 @@
***************************************************************************/
#include "curl_setup.h"
#ifndef HAVE_SELECT
#error "We cannot compile without select() support."
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
+20
View File
@@ -103,4 +103,24 @@ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
return buf;
}
#ifndef WITHOUT_LIBCURL
#include <bcrypt.h>
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
CURLcode curlx_win32_random(unsigned char *entropy, size_t length)
{
memset(entropy, 0, length);
if(BCryptGenRandom(NULL, entropy, (ULONG)length,
BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
return CURLE_FAILED_INIT;
return CURLE_OK;
}
#endif /* WITHOUT_LIBCURL */
#endif /* _WIN32 */
+1
View File
@@ -28,6 +28,7 @@
#define WINAPI_ERROR_LEN 100
const char *curlx_get_winapi_error(DWORD err, char *buf, size_t buflen);
const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
CURLcode curlx_win32_random(unsigned char *entropy, size_t length);
#endif
#endif /* HEADER_CURLX_WINAPI_H */
+46 -65
View File
@@ -97,7 +97,6 @@ static void cw_out_buf_free(struct cw_out_buf *cwbuf)
struct cw_out_ctx {
struct Curl_cwriter super;
struct cw_out_buf *buf;
BIT(paused);
BIT(errored);
};
@@ -171,8 +170,7 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
}
}
static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
struct Curl_easy *data,
static CURLcode cw_out_cb_write(struct Curl_easy *data,
curl_write_callback wcb,
void *wcb_data,
cw_out_type otype,
@@ -186,12 +184,15 @@ static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
DEBUGASSERT(data->conn);
*pnwritten = 0;
Curl_set_in_callback(data, TRUE);
nwritten = wcb((char *)CURL_UNCONST(buf), 1, blen, wcb_data);
Curl_set_in_callback(data, FALSE);
CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
{
struct Curl_mapi_guard guard;
CURL_CBAPI_START(&guard, data, easy_cw_out_cb);
nwritten = wcb((char *)CURL_UNCONST(buf), 1, blen, wcb_data);
CURL_CBAPI_END(&guard);
}
CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes, type=%x -> %zu",
blen, (otype == CW_OUT_HDS) ? "header" : "body",
nwritten);
(unsigned int)otype, nwritten);
if(nwritten == CURL_WRITEFUNC_PAUSE) {
if(data->conn->scheme->flags & PROTOPT_NONETWORK) {
/* Protocols that work without network cannot be paused. This is
@@ -200,7 +201,7 @@ static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
failf(data, "Write callback asked for PAUSE when not supported");
return CURLE_WRITE_ERROR;
}
ctx->paused = TRUE;
data->req.writer.paused = TRUE;
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
result = Curl_xfer_pause_recv(data, TRUE);
return result ? result : CURLE_AGAIN;
@@ -245,18 +246,18 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
*pconsumed = 0;
if(otype == CW_OUT_BODY_0LEN) {
DEBUGASSERT(!blen);
return cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
return cw_out_cb_write(data, wcb, wcb_data, otype,
buf, blen, &nwritten);
}
else {
while(blen && !ctx->paused) {
while(blen && !data->req.writer.paused) {
if(!flush_all && blen < min_write)
break;
wlen = max_write ? CURLMIN(blen, max_write) : blen;
if(otype == CW_OUT_BODY)
result = Curl_pgrs_deliver_check(data, wlen);
if(!result)
result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
result = cw_out_cb_write(data, wcb, wcb_data, otype,
buf, wlen, &nwritten);
if(result)
return result;
@@ -314,7 +315,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
if(!cwbuf)
return CURLE_OK;
if(ctx->paused)
if(data->req.writer.paused)
return CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@@ -327,7 +328,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
return result;
if(*plast) {
/* could not write last, paused again? */
DEBUGASSERT(ctx->paused);
DEBUGASSERT(data->req.writer.paused);
return CURLE_OK;
}
}
@@ -412,7 +413,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
out:
if(result) {
/* We do not want to invoked client callbacks a second time after
/* We do not want to invoke client callbacks a second time after
* encountering an error. See issue #13337 */
ctx->errored = TRUE;
cw_out_bufs_free(ctx);
@@ -446,66 +447,46 @@ static CURLcode cw_out_write(struct Curl_easy *data,
return CURLE_OK;
}
const struct Curl_cwtype Curl_cwt_out = {
"cw-out",
NULL,
cw_out_init,
cw_out_write,
cw_out_close,
sizeof(struct cw_out_ctx)
};
bool Curl_cw_out_is_paused(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;
struct cw_out_ctx *ctx;
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(!cw_out)
return FALSE;
ctx = (struct cw_out_ctx *)cw_out;
return (bool)ctx->paused;
}
static CURLcode cw_out_flush(struct Curl_easy *data,
struct Curl_cwriter *cw_out,
bool flush_all)
static CURLcode cw_out_do_flush(struct Curl_easy *data,
struct Curl_cwriter *cw_out,
bool flush_all)
{
struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
CURLcode result = CURLE_OK;
if(ctx->errored)
return CURLE_WRITE_ERROR;
if(ctx->paused)
return CURLE_OK; /* not doing it */
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
if(result) {
ctx->errored = TRUE;
cw_out_bufs_free(ctx);
return result;
if(!data->req.writer.paused && ctx->buf) {
CURLcode result;
CURL_TRC_WRITE(data, "[OUT] flush");
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
if(result) {
ctx->errored = TRUE;
cw_out_bufs_free(ctx);
return result;
}
}
return result;
return CURLE_OK;
}
CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
static CURLcode cw_out_flush(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct Curl_cwriter *cw_out;
CURLcode result = CURLE_OK;
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(cw_out) {
struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
CURL_TRC_WRITE(data, "[OUT] unpause");
ctx->paused = FALSE;
result = Curl_cw_pause_flush(data);
if(!result)
result = cw_out_flush(data, cw_out, FALSE);
}
return result;
return cw_out_do_flush(data, writer, FALSE);
}
const struct Curl_cwtype Curl_cwt_out = {
"cw-out",
NULL,
0,
cw_out_init,
cw_out_write,
cw_out_flush,
cw_out_close,
sizeof(struct cw_out_ctx)
};
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;
@@ -514,9 +495,9 @@ CURLcode Curl_cw_out_done(struct Curl_easy *data)
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(cw_out) {
CURL_TRC_WRITE(data, "[OUT] done");
result = Curl_cw_pause_flush(data);
result = Curl_client_flush(data);
if(!result)
result = cw_out_flush(data, cw_out, TRUE);
result = cw_out_do_flush(data, cw_out, TRUE);
}
return result;
}
-10
View File
@@ -34,16 +34,6 @@ struct Curl_easy;
*/
extern const struct Curl_cwtype Curl_cwt_out;
/**
* Return TRUE iff 'cw-out' client write has paused data.
*/
bool Curl_cw_out_is_paused(struct Curl_easy *data);
/**
* Flush any buffered date to the client, chunk collation still applies.
*/
CURLcode Curl_cw_out_unpause(struct Curl_easy *data);
/**
* Mark EndOfStream reached and flush ALL data to the client.
*/
+7 -18
View File
@@ -100,7 +100,6 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
struct Curl_cwriter *cw_pause)
{
struct cw_pause_ctx *ctx = (struct cw_pause_ctx *)cw_pause;
bool decoding = Curl_cwriter_is_content_decoding(data);
CURLcode result = CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@@ -112,7 +111,7 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
while((*plast)->next) /* got to last in list */
plast = &(*plast)->next;
if(Curl_bufq_peek(&(*plast)->b, &buf, &blen)) {
wlen = (decoding && ((*plast)->type & CLIENTWRITE_BODY)) ?
wlen = ((*plast)->type & CLIENTWRITE_BODY) ?
CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
(const char *)buf, wlen);
@@ -138,6 +137,9 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
*plast = NULL;
}
}
if(!result)
result = Curl_cwriter_flush(data, cw_pause->next);
return result;
}
@@ -148,7 +150,6 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
struct cw_pause_ctx *ctx = writer->ctx;
CURLcode result = CURLE_OK;
size_t wlen = 0;
bool decoding = Curl_cwriter_is_content_decoding(data);
if(ctx->buf && !Curl_cwriter_is_paused(data)) {
result = cw_pause_flush(data, writer);
@@ -161,13 +162,11 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
DEBUGASSERT(!ctx->buf);
/* content decoding might blow up size considerably, write smaller
* chunks to make pausing need buffer less. */
wlen = (decoding && (type & CLIENTWRITE_BODY)) ?
wlen = (type & CLIENTWRITE_BODY) ?
CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
if(wlen < blen)
wtype &= ~CLIENTWRITE_EOS;
result = Curl_cwriter_write(data, writer->next, wtype, buf, wlen);
CURL_TRC_WRITE(data, "[PAUSE] writing %zu/%zu bytes of type %x -> %d",
wlen, blen, (unsigned int)wtype, (int)result);
if(result)
return result;
buf += wlen;
@@ -208,20 +207,10 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
const struct Curl_cwtype Curl_cwt_pause = {
"cw-pause",
NULL,
0,
cw_pause_init,
cw_pause_write,
cw_pause_flush,
cw_pause_close,
sizeof(struct cw_pause_ctx)
};
CURLcode Curl_cw_pause_flush(struct Curl_easy *data)
{
struct Curl_cwriter *cw_pause;
CURLcode result = CURLE_OK;
cw_pause = Curl_cwriter_get_by_type(data, &Curl_cwt_pause);
if(cw_pause)
result = cw_pause_flush(data, cw_pause);
return result;
}
-2
View File
@@ -33,6 +33,4 @@ struct Curl_easy;
*/
extern const struct Curl_cwtype Curl_cwt_pause;
CURLcode Curl_cw_pause_flush(struct Curl_easy *data);
#endif /* HEADER_CURL_CW_PAUSE_H */
+34 -6
View File
@@ -55,6 +55,8 @@
#include "transfer.h"
#include "curl_trc.h"
#include "connect.h"
#include "select.h"
#include "escape.h"
#define DICT_MATCH "/MATCH:"
@@ -93,9 +95,12 @@ static CURLcode sendf(struct Curl_easy *data,
static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
{
curl_socket_t sockfd = data->conn->sock[FIRSTSOCKET];
size_t bytes_written;
size_t write_len;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
int what;
char *s;
char *sptr;
va_list ap;
@@ -126,6 +131,29 @@ static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
}
else
break;
timeout_ms = Curl_timeleft_ms(data);
if(timeout_ms < 0) {
result = CURLE_OPERATION_TIMEDOUT;
break;
}
if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
/* Do not busyloop. The entire loop thing is a workaround as it causes a
BLOCKING behavior which is a NO-NO. This function should rather be
split up in a do and a doing piece where the pieces that are not
possible to send now will be sent in the doing function repeatedly
until the entire request is sent. */
what = SOCKET_WRITABLE(sockfd, timeout_ms);
if(what < 0) {
result = CURLE_SEND_ERROR;
break;
}
else if(!what) {
result = CURLE_OPERATION_TIMEDOUT;
break;
}
}
curlx_free(s); /* free the output string */
@@ -153,9 +181,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(result)
return result;
if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH) - 1) ||
curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2) - 1) ||
curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3) - 1)) {
if(curl_strnequal(path, DICT_MATCH, CURL_CSTRLEN(DICT_MATCH)) ||
curl_strnequal(path, DICT_MATCH2, CURL_CSTRLEN(DICT_MATCH2)) ||
curl_strnequal(path, DICT_MATCH3, CURL_CSTRLEN(DICT_MATCH3))) {
word = strchr(path, ':');
if(word) {
@@ -200,9 +228,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
}
Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
}
else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE) - 1) ||
curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2) - 1) ||
curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3) - 1)) {
else if(curl_strnequal(path, DICT_DEFINE, CURL_CSTRLEN(DICT_DEFINE)) ||
curl_strnequal(path, DICT_DEFINE2, CURL_CSTRLEN(DICT_DEFINE2)) ||
curl_strnequal(path, DICT_DEFINE3, CURL_CSTRLEN(DICT_DEFINE3))) {
word = strchr(path, ':');
if(word) {
+283 -245
View File
@@ -44,13 +44,14 @@
#endif
#include "urldata.h"
#include "api.h"
#include "transfer.h"
#include "vdns/hostip.h"
#include "vtls/vtls.h"
#include "vtls/vtls_scache.h"
#include "vquic/vquic.h"
#include "url.h"
#include "getinfo.h"
#include "hostip.h"
#include "curlx/strdup.h"
#include "easyif.h"
#include "multiif.h"
@@ -79,7 +80,9 @@
/* true globals -- for curl_global_init() and curl_global_cleanup() */
static unsigned int initialized;
#ifdef _WIN32
static long easy_init_flags;
#endif
#ifdef GLOBAL_INIT_IS_THREADSAFE
@@ -135,6 +138,11 @@ static CURLcode global_init(long flags, bool memoryfuncs)
Curl_ccalloc = (curl_calloc_callback)calloc;
}
if(Curl_win32_init(flags)) {
DEBUGF(curl_mfprintf(stderr, "Error: win32_init failed\n"));
goto fail;
}
if(Curl_trc_init()) {
DEBUGF(curl_mfprintf(stderr, "Error: Curl_trc_init failed\n"));
goto fail;
@@ -150,11 +158,6 @@ static CURLcode global_init(long flags, bool memoryfuncs)
goto fail;
}
if(Curl_win32_init(flags)) {
DEBUGF(curl_mfprintf(stderr, "Error: win32_init failed\n"));
goto fail;
}
if(Curl_amiga_init()) {
DEBUGF(curl_mfprintf(stderr, "Error: Curl_amiga_init failed\n"));
goto fail;
@@ -166,7 +169,7 @@ static CURLcode global_init(long flags, bool memoryfuncs)
}
if(Curl_async_global_init()) {
DEBUGF(curl_mfprintf(stderr, "Error: resolver_global_init failed\n"));
DEBUGF(curl_mfprintf(stderr, "Error: Curl_async_global_init failed\n"));
goto fail;
}
@@ -175,7 +178,11 @@ static CURLcode global_init(long flags, bool memoryfuncs)
goto fail;
}
#ifdef _WIN32
easy_init_flags = flags;
#else
(void)flags;
#endif
#ifdef DEBUGBUILD
if(getenv("CURL_GLOBAL_INIT"))
@@ -267,10 +274,12 @@ void curl_global_cleanup(void)
}
Curl_ssl_cleanup();
Curl_vquic_cleanup();
Curl_async_global_cleanup();
#ifdef _WIN32
Curl_win32_cleanup(easy_init_flags);
easy_init_flags = 0;
#endif
Curl_amiga_cleanup();
@@ -281,8 +290,6 @@ void curl_global_cleanup(void)
curlx_free(leakpointer);
#endif
easy_init_flags = 0;
global_init_unlock();
}
@@ -756,13 +763,9 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* if the handle has a connection still attached (it is/was a connect-only
handle) then disconnect before performing */
if(data->conn) {
struct connectdata *c;
curl_socket_t s;
struct connectdata *conn = data->conn;
Curl_detach_connection(data);
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
Curl_conn_terminate(data, c, TRUE);
}
Curl_conn_close(data, conn, TRUE);
DEBUGASSERT(!data->conn);
}
@@ -776,7 +779,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
return CURLE_OUT_OF_MEMORY;
}
if(multi->in_callback)
if(Curl_api_multi_is_in_callback(multi))
return CURLE_RECURSIVE_API_CALL;
/* Copy relevant easy options to the multi handle */
@@ -784,7 +787,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
curl_multi_setopt(multi, CURLMOPT_QUICK_EXIT, (long)data->set.quick_exit);
data->multi_easy = NULL; /* pretend it does not exist */
mresult = curl_multi_add_handle(multi, data);
mresult = Curl_multi_add_handle(multi, data);
if(mresult) {
curl_multi_cleanup(multi);
if(mresult == CURLM_OUT_OF_MEMORY)
@@ -803,7 +806,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* ignoring the return code is not nice, but atm we cannot really handle
a failure here, room for future improvement! */
(void)curl_multi_remove_handle(multi, data);
(void)Curl_multi_remove_handle(multi, data);
sigpipe_restore(&sigpipe_ctx);
@@ -817,7 +820,14 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
*/
CURLcode curl_easy_perform(CURL *curl)
{
return easy_perform(curl, FALSE);
struct Curl_eapi_guard guard = { 0 };
CURLcode result;
if(CURL_EAPI_ENTER(&guard, curl, easy_perform, &result)) {
result = easy_perform(curl, FALSE);
}
CURL_EAPI_LEAVE(&guard);
return result;
}
#ifdef DEBUGBUILD
@@ -827,7 +837,14 @@ CURLcode curl_easy_perform(CURL *curl)
*/
CURLcode curl_easy_perform_ev(struct Curl_easy *easy)
{
return easy_perform(easy, TRUE);
struct Curl_eapi_guard guard;
CURLcode result;
if(CURL_EAPI_ENTER(&guard, easy, easy_perform_ev, &result)) {
result = easy_perform(easy, TRUE);
}
CURL_EAPI_LEAVE(&guard);
return result;
}
#endif
@@ -837,13 +854,16 @@ CURLcode curl_easy_perform_ev(struct Curl_easy *easy)
*/
void curl_easy_cleanup(CURL *curl)
{
struct Curl_easy *data = curl;
if(GOOD_EASY_HANDLE(data)) {
struct Curl_eapi_guard guard;
if(CURL_EAPI_ENTER(&guard, curl, easy_cleanup, NULL)) {
struct Curl_easy *data = curl;
struct Curl_sigpipe_ctx sigpipe_ctx;
sigpipe_ignore(data, &sigpipe_ctx);
Curl_close(&data);
sigpipe_restore(&sigpipe_ctx);
}
CURL_EAPI_LEAVE(&guard);
}
/*
@@ -853,27 +873,28 @@ void curl_easy_cleanup(CURL *curl)
#undef curl_easy_getinfo
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
{
struct Curl_easy *data = curl;
va_list arg;
void *paramp;
struct Curl_eapi_guard guard;
CURLcode result;
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(CURL_EAPI_ENTER(&guard, curl, easy_getinfo, &result)) {
struct Curl_easy *data = curl;
va_list arg;
void *paramp;
va_start(arg, info);
paramp = va_arg(arg, void *);
va_start(arg, info);
paramp = va_arg(arg, void *);
result = Curl_getinfo(data, info, paramp);
result = Curl_getinfo(data, info, paramp);
va_end(arg);
va_end(arg);
}
CURL_EAPI_LEAVE(&guard);
return result;
}
static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
{
CURLcode result = CURLE_OK;
enum dupstring i;
enum dupblob j;
/* Copy src->set into dst->set first, then deal with the strings
@@ -882,17 +903,17 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
dst->set.mimepostp = NULL;
#endif
dst->set.str_copypostfields = NULL;
Curl_u8_strset_init(&dst->set.strings);
/* clear all dest string and blob pointers first, in case we error out
mid-function */
memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
/* duplicate all strings */
for(i = (enum dupstring)0; i < STRING_LASTZEROTERMINATED; i++) {
result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
if(result)
return result;
}
result = Curl_u8_strset_copy(&dst->set.strings, &src->set.strings);
if(result)
return result;
/* duplicate all blobs */
for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
@@ -902,18 +923,18 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
}
/* duplicate memory areas pointed to */
i = STRING_COPYPOSTFIELDS;
if(src->set.str[i]) {
if(src->set.str_copypostfields) {
if(src->set.postfieldsize == -1)
dst->set.str[i] = curlx_strdup(src->set.str[i]);
dst->set.str_copypostfields = curlx_strdup(src->set.str_copypostfields);
else
/* postfieldsize is curl_off_t, curlx_memdup() takes a size_t ... */
dst->set.str[i] = curlx_memdup(src->set.str[i],
curlx_sotouz(src->set.postfieldsize));
if(!dst->set.str[i])
dst->set.str_copypostfields =
curlx_memdup(src->set.str_copypostfields,
curlx_sotouz(src->set.postfieldsize));
if(!dst->set.str_copypostfields)
return CURLE_OUT_OF_MEMORY;
/* point to the new copy */
dst->set.postfields = dst->set.str[i];
dst->set.postfields = dst->set.str_copypostfields;
}
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
@@ -952,122 +973,125 @@ static void dupeasy_meta_freeentry(void *p)
*/
CURL *curl_easy_duphandle(CURL *curl)
{
struct Curl_easy *data = curl;
struct Curl_eapi_guard guard;
struct Curl_easy *outcurl = NULL;
if(!GOOD_EASY_HANDLE(data))
goto fail;
outcurl = curlx_calloc(1, sizeof(struct Curl_easy));
if(!outcurl)
goto fail;
if(CURL_EAPI_ENTER(&guard, curl, easy_duphandle, NULL)) {
struct Curl_easy *data = curl;
const char *str;
/*
* We setup a few buffers we need. We should probably make them
* get setup on-demand in the code, as that would probably decrease
* the likeliness of us forgetting to init a buffer here in the future.
*/
outcurl->set.buffer_size = data->set.buffer_size;
outcurl = curlx_calloc(1, sizeof(struct Curl_easy));
if(!outcurl)
goto fail;
Curl_hash_init(&outcurl->meta_hash, 23,
Curl_hash_str, curlx_str_key_compare, dupeasy_meta_freeentry);
curlx_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
Curl_bufref_init(&outcurl->state.url);
Curl_bufref_init(&outcurl->state.referer);
Curl_netrc_init(&outcurl->state.netrc);
/*
* We setup a few buffers we need. We should probably make them
* get setup on-demand in the code, as that would probably decrease
* the likeliness of us forgetting to init a buffer here in the future.
*/
outcurl->set.buffer_size = data->set.buffer_size;
/* the connection pool is setup on demand */
outcurl->state.lastconnect_id = -1;
outcurl->state.recent_conn_id = -1;
outcurl->id = -1;
outcurl->mid = UINT32_MAX;
outcurl->master_mid = UINT32_MAX;
Curl_hash_init(&outcurl->meta_hash, 23,
Curl_hash_str, curlx_str_key_compare,
dupeasy_meta_freeentry);
curlx_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
Curl_bufref_init(&outcurl->state.url);
Curl_bufref_init(&outcurl->state.referer);
Curl_netrc_init(&outcurl->state.netrc);
/* the connection pool is setup on demand */
outcurl->state.lastconnect_id = -1;
outcurl->id = -1;
outcurl->mid = UINT32_MAX;
outcurl->master_mid = UINT32_MAX;
#ifndef CURL_DISABLE_HTTP
Curl_llist_init(&outcurl->state.httphdrs, NULL);
Curl_llist_init(&outcurl->state.httphdrs, NULL);
#endif
Curl_initinfo(outcurl);
Curl_initinfo(outcurl);
/* copy all userdefined values */
if(dupset(outcurl, data))
goto fail;
/* copy all userdefined values */
if(dupset(outcurl, data))
goto fail;
outcurl->progress.hide = data->progress.hide;
outcurl->progress.callback = data->progress.callback;
outcurl->progress.hide = data->progress.hide;
outcurl->progress.callback = data->progress.callback;
#ifndef CURL_DISABLE_COOKIES
outcurl->state.cookielist = NULL;
if(data->cookies && data->state.cookie_engine) {
/* If cookies are enabled in the parent handle, we enable them
in the clone as well! */
outcurl->cookies = Curl_cookie_init();
if(!outcurl->cookies)
goto fail;
outcurl->state.cookie_engine = TRUE;
}
outcurl->state.cookielist = NULL;
if(data->cookies && data->state.cookie_engine) {
/* If cookies are enabled in the parent handle, we enable them
in the clone as well! */
outcurl->cookies = Curl_cookie_init();
if(!outcurl->cookies)
goto fail;
outcurl->state.cookie_engine = TRUE;
}
if(data->state.cookielist) {
outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
if(!outcurl->state.cookielist)
goto fail;
}
if(data->state.cookielist) {
outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
if(!outcurl->state.cookielist)
goto fail;
}
#endif
if(Curl_bufref_ptr(&data->state.url)) {
Curl_bufref_set(&outcurl->state.url,
Curl_bufref_dup(&data->state.url), 0,
curl_free);
if(!Curl_bufref_ptr(&outcurl->state.url))
goto fail;
}
if(Curl_bufref_ptr(&data->state.referer)) {
Curl_bufref_set(&outcurl->state.referer,
Curl_bufref_dup(&data->state.referer), 0,
curl_free);
if(!Curl_bufref_ptr(&outcurl->state.referer))
goto fail;
}
if(Curl_bufref_ptr(&data->state.url)) {
Curl_bufref_set(&outcurl->state.url,
Curl_bufref_dup(&data->state.url), 0,
curl_free);
if(!Curl_bufref_ptr(&outcurl->state.url))
goto fail;
}
if(Curl_bufref_ptr(&data->state.referer)) {
Curl_bufref_set(&outcurl->state.referer,
Curl_bufref_dup(&data->state.referer), 0,
curl_free);
if(!Curl_bufref_ptr(&outcurl->state.referer))
goto fail;
}
/* Reinitialize an SSL engine for the new handle
* note: the engine name has already been copied by dupset */
if(outcurl->set.str[STRING_SSL_ENGINE]) {
if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
goto fail;
}
/* Reinitialize an SSL engine for the new handle
* note: the engine name has already been copied by dupset */
str = CURL_EASY_STR(outcurl, STRING_SSL_ENGINE);
if(str) {
if(Curl_ssl_set_engine(outcurl, str))
goto fail;
}
#ifndef CURL_DISABLE_ALTSVC
if(data->asi) {
outcurl->asi = Curl_altsvc_init();
if(!outcurl->asi)
goto fail;
if(outcurl->set.str[STRING_ALTSVC])
(void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
}
if(data->asi) {
outcurl->asi = Curl_altsvc_init();
if(!outcurl->asi)
goto fail;
str = CURL_EASY_STR(outcurl, STRING_ALTSVC);
if(str)
(void)Curl_altsvc_load(outcurl->asi, str);
}
#endif
#ifndef CURL_DISABLE_HSTS
if(data->hsts) {
outcurl->hsts = Curl_hsts_init();
if(!outcurl->hsts)
goto fail;
if(outcurl->set.str[STRING_HSTS])
(void)Curl_hsts_loadfile(outcurl,
outcurl->hsts, outcurl->set.str[STRING_HSTS]);
(void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
if(data->hsts) {
outcurl->hsts = Curl_hsts_init();
if(!outcurl->hsts)
goto fail;
str = CURL_EASY_STR(outcurl, STRING_HSTS);
if(str)
(void)Curl_hsts_loadfile(outcurl, outcurl->hsts, str);
(void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
/* Copy entries learned at runtime. (E.g. Strict-Transport-Security
headers.) */
if(Curl_hsts_copy(outcurl->hsts, data->hsts))
goto fail;
}
/* Copy entries learned at runtime. (E.g. Strict-Transport-Security
headers.) */
if(Curl_hsts_copy(outcurl->hsts, data->hsts))
goto fail;
}
#endif
outcurl->magic = CURLEASY_MAGIC_NUMBER;
/* we reach this point and thus we are OK */
/* we reach this point and thus we are OK */
outcurl->magic = CURLEASY_MAGIC_NUMBER;
}
CURL_EAPI_LEAVE(&guard);
return outcurl;
fail:
if(outcurl) {
#ifndef CURL_DISABLE_COOKIES
curlx_free(outcurl->cookies);
@@ -1079,6 +1103,7 @@ fail:
curlx_free(outcurl);
}
CURL_EAPI_LEAVE(&guard);
return NULL;
}
@@ -1088,38 +1113,40 @@ fail:
*/
void curl_easy_reset(CURL *curl)
{
struct Curl_easy *data = curl;
if(!GOOD_EASY_HANDLE(data))
return;
struct Curl_eapi_guard guard;
Curl_req_hard_reset(&data->req, data);
Curl_hash_clean(&data->meta_hash);
if(CURL_EAPI_ENTER(&guard, curl, easy_reset, NULL)) {
struct Curl_easy *data = curl;
/* clear all meta data */
Curl_meta_reset(data);
/* zero out UserDefined data: */
Curl_freeset(data);
memset(&data->set, 0, sizeof(struct UserDefined));
Curl_init_userdefined(data);
data->state.lastconnect_id = -1; /* clear remembered connection id */
Curl_req_hard_reset(&data->req, data);
Curl_hash_clean(&data->meta_hash);
/* zero out Progress data: */
memset(&data->progress, 0, sizeof(struct Progress));
/* clear all meta data */
Curl_meta_reset(data);
/* zero out UserDefined data: */
Curl_freeset(data);
memset(&data->set, 0, sizeof(struct UserDefined));
Curl_init_userdefined(data);
/* zero out PureInfo data: */
Curl_initinfo(data);
/* zero out Progress data: */
memset(&data->progress, 0, sizeof(struct Progress));
data->progress.hide = TRUE;
data->state.current_speed = -1; /* init to negative == impossible */
data->state.recent_conn_id = -1; /* clear remembered connection id */
/* zero out PureInfo data: */
Curl_initinfo(data);
/* zero out authentication data: */
memset(&data->state.authhost, 0, sizeof(struct auth));
memset(&data->state.authproxy, 0, sizeof(struct auth));
data->progress.hide = TRUE;
/* zero out authentication data: */
memset(&data->state.authhost, 0, sizeof(struct auth));
memset(&data->state.authproxy, 0, sizeof(struct auth));
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
Curl_http_auth_cleanup_digest(data);
Curl_http_auth_cleanup_digest(data);
#endif
data->master_mid = UINT32_MAX;
data->master_mid = UINT32_MAX;
}
CURL_EAPI_LEAVE(&guard);
}
/*
@@ -1137,62 +1164,60 @@ void curl_easy_reset(CURL *curl)
*/
CURLcode curl_easy_pause(CURL *curl, int action)
{
struct Curl_eapi_guard guard;
CURLcode result = CURLE_OK;
bool recursive = FALSE;
bool changed = FALSE;
struct Curl_easy *data = curl;
bool recv_paused, recv_paused_new;
bool send_paused, send_paused_new;
if(!GOOD_EASY_HANDLE(data) || !data->conn)
/* crazy input, do not continue */
return CURLE_BAD_FUNCTION_ARGUMENT;
if(CURL_EAPI_ENTER(&guard, curl, easy_pause, &result)) {
bool changed = FALSE;
struct Curl_easy *data = curl;
bool recv_paused, recv_paused_new;
bool send_paused, send_paused_new;
if(Curl_is_in_callback(data))
recursive = TRUE;
if(!data->conn) {
/* crazy input, do not continue */
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
recv_paused = Curl_xfer_recv_is_paused(data);
recv_paused_new = (action & CURLPAUSE_RECV);
send_paused = Curl_xfer_send_is_paused(data);
send_paused_new = (action & CURLPAUSE_SEND);
recv_paused = Curl_xfer_recv_is_paused(data);
recv_paused_new = (action & CURLPAUSE_RECV);
send_paused = Curl_xfer_send_is_paused(data);
send_paused_new = (action & CURLPAUSE_SEND);
if((send_paused != send_paused_new) ||
(send_paused_new != Curl_creader_is_paused(data))) {
changed = TRUE;
result = Curl_1st_fatal(
result, Curl_xfer_pause_send(data, send_paused_new));
}
if((send_paused != send_paused_new) ||
(send_paused_new != Curl_creader_is_paused(data))) {
changed = TRUE;
result = Curl_1st_fatal(
result, Curl_xfer_pause_send(data, send_paused_new));
}
if(recv_paused != recv_paused_new) {
changed = TRUE;
result = Curl_1st_fatal(
result, Curl_xfer_pause_recv(data, recv_paused_new));
}
if(recv_paused != recv_paused_new) {
changed = TRUE;
result = Curl_1st_fatal(
result, Curl_xfer_pause_recv(data, recv_paused_new));
}
/* If not completely pausing both directions now, run again in any case. */
if(!Curl_xfer_is_blocked(data)) {
/* reset the too-slow time keeper */
data->state.keeps_speed.tv_sec = 0;
if(data->multi) {
Curl_multi_mark_dirty(data); /* make it run */
/* On changes, tell application to update its timers. */
if(changed) {
if(Curl_update_timer(data->multi) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
/* If not completely pausing both directions, run again in any case. */
if(!Curl_xfer_is_blocked(data)) {
/* reset the too-slow time keeper */
data->state.keeps_speed.tv_sec = 0;
if(data->multi) {
Curl_multi_mark_dirty(data); /* make it run */
/* On changes, tell application to update its timers. */
if(changed) {
if(Curl_update_timer(data->multi) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
}
}
}
if(!result && changed && !data->state.done && data->multi)
/* pause/unpausing may result in multi event changes */
if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
}
if(!result && changed && !data->state.done && data->multi)
/* pause/unpausing may result in multi event changes */
if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
if(recursive)
/* this might have called a callback recursively which might have set this
to false again on exit */
Curl_set_in_callback(data, TRUE);
out:
CURL_EAPI_LEAVE(&guard);
return result;
}
@@ -1213,7 +1238,8 @@ static CURLcode easy_connection(struct Curl_easy *data,
sfd = Curl_getconnectinfo(data, connp);
if(sfd == CURL_SOCKET_BAD) {
failf(data, "Failed to get recent socket");
failf(data, "Failed to get last socket used for connection #%" FMT_OFF_T,
data->state.lastconnect_id);
return CURLE_UNSUPPORTED_PROTOCOL;
}
@@ -1225,16 +1251,11 @@ static CURLcode easy_connection(struct Curl_easy *data,
* curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
* Returns CURLE_OK on success, error code on error.
*/
CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
CURLcode Curl_easy_recv(struct Curl_easy *data,
void *buffer, size_t buflen, size_t *n)
{
CURLcode result;
struct connectdata *c;
struct Curl_easy *data = curl;
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
result = easy_connection(data, &c);
if(result)
@@ -1243,12 +1264,24 @@ CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
Curl_attach_connection(data, c);
Curl_attach_connection(data, c, TRUE);
*n = 0;
return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n);
}
CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
{
struct Curl_eapi_guard guard;
CURLcode result;
if(CURL_EAPI_ENTER(&guard, curl, easy_recv, &result)) {
result = Curl_easy_recv(curl, buffer, buflen, n);
}
CURL_EAPI_LEAVE(&guard);
return result;
}
#ifndef CURL_DISABLE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
{
@@ -1262,7 +1295,7 @@ CURLcode Curl_connect_only_attach(struct Curl_easy *data)
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
Curl_attach_connection(data, c);
Curl_attach_connection(data, c, TRUE);
return CURLE_OK;
}
@@ -1288,7 +1321,7 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
Curl_attach_connection(data, c);
Curl_attach_connection(data, c, TRUE);
sigpipe_ignore(data, &sigpipe_ctx);
result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
@@ -1306,16 +1339,17 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
size_t *n)
{
size_t written = 0;
struct Curl_eapi_guard guard;
CURLcode result;
struct Curl_easy *data = curl;
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
result = Curl_senddata(data, buffer, buflen, &written);
*n = written;
if(CURL_EAPI_ENTER(&guard, curl, easy_send, &result)) {
struct Curl_easy *data = curl;
size_t written = 0;
result = Curl_senddata(data, buffer, buflen, &written);
*n = written;
}
CURL_EAPI_LEAVE(&guard);
return result;
}
@@ -1324,16 +1358,15 @@ CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
*/
CURLcode curl_easy_upkeep(CURL *curl)
{
struct Curl_easy *data = curl;
/* Verify that we got an easy handle we can work with. */
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
struct Curl_eapi_guard guard;
CURLcode result;
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
/* Use the common function to keep connections alive. */
return Curl_cpool_upkeep(data);
if(CURL_EAPI_ENTER(&guard, curl, easy_upkeep, &result)) {
/* Use the common function to keep connections alive. */
result = Curl_cpool_upkeep((struct Curl_easy *)curl);
}
CURL_EAPI_LEAVE(&guard);
return result;
}
CURLcode curl_easy_ssls_import(CURL *curl, const char *session_key,
@@ -1341,13 +1374,15 @@ CURLcode curl_easy_ssls_import(CURL *curl, const char *session_key,
const unsigned char *sdata, size_t sdata_len)
{
#if defined(USE_SSL) && defined(USE_SSLS_EXPORT)
struct Curl_easy *data = curl;
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(Curl_is_in_callback(data) || Curl_ssl_scache_is_locked(data))
return CURLE_RECURSIVE_API_CALL;
return Curl_ssl_session_import(data, session_key,
shmac, shmac_len, sdata, sdata_len);
struct Curl_eapi_guard guard;
CURLcode result;
if(CURL_EAPI_ENTER(&guard, curl, easy_ssls_import, &result)) {
result = Curl_ssl_session_import((struct Curl_easy *)curl, session_key,
shmac, shmac_len, sdata, sdata_len);
}
CURL_EAPI_LEAVE(&guard);
return result;
#else
(void)curl;
(void)session_key;
@@ -1364,12 +1399,15 @@ CURLcode curl_easy_ssls_export(CURL *curl,
void *userptr)
{
#if defined(USE_SSL) && defined(USE_SSLS_EXPORT)
struct Curl_easy *data = curl;
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(Curl_is_in_callback(data) || Curl_ssl_scache_is_locked(data))
return CURLE_RECURSIVE_API_CALL;
return Curl_ssl_session_export(data, export_fn, userptr);
struct Curl_eapi_guard guard;
CURLcode result;
if(CURL_EAPI_ENTER(&guard, curl, easy_ssls_export, &result)) {
result = Curl_ssl_session_export((struct Curl_easy *)curl,
export_fn, userptr);
}
CURL_EAPI_LEAVE(&guard);
return result;
#else
(void)curl;
(void)export_fn;
+1
View File
@@ -71,6 +71,7 @@ static CURL_INLINE void curl_simple_lock_lock(curl_simple_lock *lock)
#ifdef HAVE_BUILTIN_IA32_PAUSE
__builtin_ia32_pause();
#elif defined(__aarch64__)
/* NOLINTNEXTLINE(portability-no-assembler) */
__asm__ volatile("yield" ::: "memory");
#elif defined(HAVE_SCHED_YIELD)
sched_yield();
+5 -1
View File
@@ -140,6 +140,10 @@ const struct curl_easyoption Curl_easyopts[] = {
{ "HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0 },
{ "HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0 },
{ "HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0 },
{ "HTTPSIG_ALGORITHM", CURLOPT_HTTPSIG_ALGORITHM, CURLOT_VALUES, 0 },
{ "HTTPSIG_HEADERS", CURLOPT_HTTPSIG_HEADERS, CURLOT_STRING, 0 },
{ "HTTPSIG_KEY", CURLOPT_HTTPSIG_KEY, CURLOT_STRING, 0 },
{ "HTTPSIG_KEYID", CURLOPT_HTTPSIG_KEYID, CURLOT_STRING, 0 },
{ "HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING, CURLOT_LONG, 0 },
{ "HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING,
CURLOT_LONG, 0 },
@@ -385,6 +389,6 @@ const struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return (CURLOPT_LASTENTRY % 10000) != (328 + 1);
return (CURLOPT_LASTENTRY % 10000) != (332 + 1);
}
#endif

Some files were not shown because too many files have changed in this diff Show More