mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
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:
+33
-44
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 *) || \
|
||||
|
||||
@@ -64,6 +64,7 @@ typedef enum {
|
||||
CURLUE_BAD_USER, /* 29 */
|
||||
CURLUE_LACKS_IDN, /* 30 */
|
||||
CURLUE_TOO_LARGE, /* 31 */
|
||||
CURLUE_BACKSLASH, /* 32 */
|
||||
CURLUE_LAST
|
||||
} CURLUcode;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -25,7 +25,7 @@
|
||||
|
||||
#ifdef __AMIGA__
|
||||
|
||||
#include "hostip.h"
|
||||
#include "vdns/hostip.h"
|
||||
#include "curl_addrinfo.h"
|
||||
#include "amigaos.h"
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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, ...)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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...
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user