curl 2025-06-04 (fdb8a789)

Code extracted from:

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

at commit fdb8a789d2b446b77bd7cdd2eff95f6cbc814cf4 (curl-8_14_1).
This commit is contained in:
Curl Upstream
2025-06-04 07:40:18 +02:00
committed by Brad King
parent 1865f86e28
commit 3207de53f4
318 changed files with 26668 additions and 20680 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -35,10 +35,11 @@ string(REGEX REPLACE "\n" ";" _files "${_files}")
foreach(_file ${_files})
message(STATUS "Uninstalling $ENV{DESTDIR}${_file}")
if(IS_SYMLINK "$ENV{DESTDIR}${_file}" OR EXISTS "$ENV{DESTDIR}${_file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${_file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
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}")

View File

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

316
CMake/unix-cache.cmake Normal file
View File

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

View File

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

View File

@@ -23,26 +23,6 @@
###########################################################################
# by Tetetest and Sukender (Benoit Neil)
# Note: By default this CMake build script detects the version of some
# dependencies using `check_symbol_exists`. Those checks do not work in
# the case that both CURL and its dependency are included as sub-projects
# in a larger build using `FetchContent`. To support that case, additional
# variables may be defined by the parent project, ideally in the "extra"
# find package redirect file:
# https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package
#
# The following variables are available:
# HAVE_SSL_SET0_WBIO: `SSL_set0_wbio` present in OpenSSL/wolfSSL
# HAVE_OPENSSL_SRP: `SSL_CTX_set_srp_username` present in OpenSSL/wolfSSL
# HAVE_GNUTLS_SRP: `gnutls_srp_verifier` present in GnuTLS
# HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT: `SSL_set_quic_use_legacy_codepoint` present in OpenSSL/wolfSSL
# HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in quiche
# HAVE_ECH: ECH API checks for OpenSSL, BoringSSL or wolfSSL
#
# For each of the above variables, if the variable is DEFINED (either
# to ON or OFF), the symbol detection is skipped. If the variable is
# NOT DEFINED, the symbol detection is performed.
cmake_minimum_required(VERSION 3.7...3.16 FATAL_ERROR)
message(STATUS "Using CMake version ${CMAKE_VERSION}")
@@ -91,7 +71,38 @@ if(WINDOWS_STORE AND MINGW) # mingw UWP build
# CMake (as of v3.31.2) gets confused and applies the MSVC rc.exe command-line
# template to windres. Reset it to the windres template via 'Modules/Platform/Windows-windres.cmake':
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
elseif(DOS AND CMAKE_COMPILER_IS_GNUCC) # DJGPP
elseif(WIN32 AND WINCE AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # mingw32ce build
if(NOT MINGW32CE_LIBRARY_DIR)
message(FATAL_ERROR "Set MINGW32CE_LIBRARY_DIR variable to the mingw32ce platform library directory.")
endif()
set(MINGW 1)
set(MINGW32CE 1)
# Build implib with libcurl DLL. Copied from CMake's 'Modules/Platform/Windows-GNU.cmake'.
set(CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS>")
string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB>")
string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
# Build resources. Copied from CMake's 'Modules/Platform/Windows-windres.cmake'.
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
enable_language(RC)
# To compile long long integer literals
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-std=gnu99")
string(APPEND CMAKE_REQUIRED_FLAGS " -std=gnu99")
set(CMAKE_C_COMPILE_OPTIONS_PIC "") # CMake sets it to '-fPIC', confusing the toolchain and breaking builds. Zap it.
set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
set(CMAKE_IMPORT_LIBRARY_PREFIX "lib")
set(CMAKE_IMPORT_LIBRARY_SUFFIX ".dll.a")
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
elseif(DOS AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # DJGPP
set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
@@ -119,22 +130,22 @@ endif()
if(WIN32)
string(APPEND _target_flags " WIN32")
endif()
if(WINCE)
string(APPEND _target_flags " WINCE")
endif()
if(WINDOWS_STORE)
string(APPEND _target_flags " UWP")
endif()
if(CYGWIN)
string(APPEND _target_flags " CYGWIN")
endif()
if(MSYS)
string(APPEND _target_flags " MSYS")
endif()
if(DOS)
string(APPEND _target_flags " DOS")
endif()
if(AMIGA)
string(APPEND _target_flags " AMIGA")
endif()
if(CMAKE_COMPILER_IS_GNUCC)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
string(APPEND _target_flags " GCC")
endif()
if(MINGW)
@@ -163,7 +174,9 @@ else()
set(CURL_OS "\"${CMAKE_SYSTEM_NAME}\"")
endif()
include_directories("${PROJECT_SOURCE_DIR}/include")
set(LIB_NAME "libcurl")
set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/include")
if(NOT DEFINED CMAKE_UNITY_BUILD_BATCH_SIZE)
set(CMAKE_UNITY_BUILD_BATCH_SIZE 0)
@@ -190,21 +203,14 @@ option(ENABLE_ARES "Enable c-ares support" OFF)
option(CURL_DISABLE_INSTALL "Disable installation targets" OFF)
if(WIN32)
option(CURL_STATIC_CRT "Build libcurl with static CRT with MSVC (/MT)" OFF)
if(CURL_STATIC_CRT AND MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
string(APPEND CMAKE_C_FLAGS_RELEASE " -MT")
string(APPEND CMAKE_C_FLAGS_DEBUG " -MTd")
endif()
option(ENABLE_UNICODE "Use the Unicode version of the Windows API functions" OFF)
if(WINDOWS_STORE)
if(WINDOWS_STORE OR WINCE)
set(ENABLE_UNICODE ON)
endif()
if(ENABLE_UNICODE)
add_definitions("-DUNICODE" "-D_UNICODE")
if(MINGW)
add_compile_options("-municode")
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "UNICODE" "_UNICODE")
if(MINGW AND NOT MINGW32CE)
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-municode")
endif()
endif()
@@ -216,7 +222,7 @@ if(WIN32)
set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
if(CURL_TARGET_WINDOWS_VERSION)
add_definitions("-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}") # Apply to all feature checks
endif()
@@ -237,7 +243,9 @@ if(WIN32)
if(MINGW64_VERSION)
string(REGEX MATCH "MINGW64_VERSION=[0-9]+\.[0-9]+" CURL_TEST_OUTPUT "${CURL_TEST_OUTPUT}")
string(REGEX REPLACE "MINGW64_VERSION=" "" MINGW64_VERSION "${CURL_TEST_OUTPUT}")
message(STATUS "Found MINGW64_VERSION=${MINGW64_VERSION}")
if(MINGW64_VERSION)
message(STATUS "Found MINGW64_VERSION=${MINGW64_VERSION}")
endif()
endif()
unset(MINGW64_VERSION CACHE) # Avoid storing in CMake cache
endif()
@@ -259,27 +267,34 @@ endif()
include(PickyWarnings)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
string(APPEND CMAKE_C_FLAGS " -D_GNU_SOURCE") # Required for sendmmsg()
if(CYGWIN OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "_GNU_SOURCE") # Required for accept4(), pipe2(), sendmmsg()
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)
if(ENABLE_DEBUG)
message(WARNING "This curl build is Debug-enabled, do not use in production.")
message(WARNING "This curl build is Debug-enabled and insecure, do not use in production.")
endif()
option(ENABLE_CURLDEBUG "Enable TrackMemory debug feature" ${ENABLE_DEBUG})
option(ENABLE_SERVER_DEBUG "Apply curl debug options to test servers" OFF)
set(CURL_DEBUG_MACROS "")
if(ENABLE_DEBUG)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "DEBUGBUILD")
list(APPEND CURL_DEBUG_MACROS "DEBUGBUILD")
endif()
if(ENABLE_CURLDEBUG)
list(APPEND CURL_DEBUG_MACROS "CURLDEBUG")
endif()
if(ENABLE_CURLDEBUG)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "CURLDEBUG")
endif()
option(CURL_TEST_BUNDLES "Build tests into single-binary bundles" OFF)
option(CURL_CLANG_TIDY "Run the build through clang-tidy" OFF)
if(CURL_CLANG_TIDY)
# clang-tidy is not looking into #included sources, thus not compatible with
# unity builds and test bundles.
set(CMAKE_UNITY_BUILD OFF)
set(CURL_TEST_BUNDLES OFF)
set(_tidy_checks "")
list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.strcpy")
list(APPEND _tidy_checks "-clang-analyzer-optin.performance.Padding")
@@ -327,6 +342,19 @@ else()
set(LIB_SELECTED ${LIB_STATIC})
endif()
if(WIN32)
option(CURL_STATIC_CRT "Build libcurl with static CRT with MSVC (/MT)" OFF)
if(CURL_STATIC_CRT AND MSVC)
if(MSVC_VERSION GREATER_EQUAL 1900 OR BUILD_STATIC_CURL OR NOT BUILD_CURL_EXE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "$<$<CONFIG:Release>:-MT>")
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "$<$<CONFIG:Debug>:-MTd>")
else()
message(WARNING "Static CRT requires UCRT, static libcurl or no curl executable.")
endif()
endif()
endif()
# Override to force-disable or force-enable the use of pkg-config.
if((UNIX AND NOT ANDROID AND (NOT APPLE OR CMAKE_SYSTEM_NAME MATCHES "Darwin")) OR
VCPKG_TOOLCHAIN OR
@@ -430,9 +458,9 @@ mark_as_advanced(CURL_DISABLE_PROXY)
option(CURL_DISABLE_IPFS "Disable IPFS" OFF)
mark_as_advanced(CURL_DISABLE_IPFS)
option(CURL_DISABLE_RTSP "Disable RTSP" OFF)
mark_as_advanced(CURL_DISABLE_SHA512_256)
option(CURL_DISABLE_SHA512_256 "Disable SHA-512/256 hash algorithm" OFF)
mark_as_advanced(CURL_DISABLE_RTSP)
option(CURL_DISABLE_SHA512_256 "Disable SHA-512/256 hash algorithm" OFF)
mark_as_advanced(CURL_DISABLE_SHA512_256)
option(CURL_DISABLE_SHUFFLE_DNS "Disable shuffle DNS feature" OFF)
mark_as_advanced(CURL_DISABLE_SHUFFLE_DNS)
option(CURL_DISABLE_SMB "Disable SMB" OFF)
@@ -479,7 +507,7 @@ if(HTTP_ONLY)
set(CURL_DISABLE_TFTP ON)
endif()
if(WINDOWS_STORE)
if(WINDOWS_STORE OR WINCE)
set(CURL_DISABLE_TELNET ON) # telnet code needs fixing to compile for UWP.
endif()
@@ -511,14 +539,9 @@ if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS)
endif()
endif()
# Disable warnings on Borland to avoid changing 3rd party code.
if(BORLAND)
string(APPEND CMAKE_C_FLAGS " -w-")
endif()
# If we are on AIX, do the _ALL_SOURCE magic
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
add_definitions("-D_ALL_SOURCE")
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "_ALL_SOURCE")
endif()
# If we are on Haiku, make sure that the network library is brought in.
@@ -539,15 +562,21 @@ include(CheckSymbolExists)
include(CheckTypeSize)
include(CheckCSourceCompiles)
option(_CURL_QUICK_DETECT "Fast-track known feature detection results (Windows, some Apple)" ON)
if(_CURL_QUICK_DETECT)
option(_CURL_PREFILL "Fast-track known feature detection results (Windows, some Apple)" "${WIN32}")
if(_CURL_PREFILL)
if(WIN32)
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/win32-cache.cmake")
elseif(APPLE)
set(HAVE_EVENTFD 0)
set(HAVE_GETPASS_R 0)
set(HAVE_SENDMMSG 0)
elseif(UNIX)
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/unix-cache.cmake")
message(STATUS "Pre-filling feature detection results for UNIX")
endif()
elseif(WIN32)
message(STATUS "Pre-filling feature detection results disabled.")
elseif(APPLE)
set(HAVE_EVENTFD 0)
set(HAVE_GETPASS_R 0)
set(HAVE_WRITABLE_ARGV 1)
set(HAVE_SENDMMSG 0)
endif()
if(AMIGA)
@@ -569,7 +598,19 @@ if(ENABLE_THREADED_RESOLVER)
endif()
# Check for all needed libraries
if(DOS)
if(WIN32)
if(WINCE)
set(_win32_winsock "ws2")
else()
set(_win32_winsock "ws2_32")
endif()
set(_win32_crypt32 "crypt32")
if(MINGW32CE) # FIXME upstream: must specify the full path to avoid CMake converting "ws2" to "ws2.lib"
set(_win32_winsock "${MINGW32CE_LIBRARY_DIR}/lib${_win32_winsock}.a")
set(_win32_crypt32 "${MINGW32CE_LIBRARY_DIR}/lib${_win32_crypt32}.a")
endif()
elseif(DOS)
if(WATT_ROOT)
set(USE_WATT32 ON)
# FIXME upstream: must specify the full path to avoid CMake converting "watt" to "watt.lib"
@@ -590,7 +631,7 @@ elseif(AMIGA)
set(CURL_USE_OPENSSL ON)
set(CURL_CA_FALLBACK ON CACHE BOOL "")
endif()
elseif(NOT WIN32 AND NOT APPLE)
elseif(NOT APPLE)
check_library_exists("socket" "connect" "" HAVE_LIBSOCKET)
if(HAVE_LIBSOCKET)
set(CURL_LIBS "socket" ${CURL_LIBS})
@@ -604,8 +645,8 @@ if(ENABLE_IPV6)
if(WIN32)
check_struct_has_member("struct sockaddr_in6" "sin6_scope_id" "winsock2.h;ws2tcpip.h" HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
else()
check_struct_has_member("struct sockaddr_in6" "sin6_addr" "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_ADDR)
check_struct_has_member("struct sockaddr_in6" "sin6_scope_id" "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
check_struct_has_member("struct sockaddr_in6" "sin6_addr" "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_ADDR)
if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
if(NOT DOS AND NOT AMIGA)
message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
@@ -625,7 +666,7 @@ if(ENABLE_IPV6)
endif()
endif()
endif()
if(ENABLE_IPV6)
if(ENABLE_IPV6 AND NOT WINCE)
set(USE_IPV6 ON)
endif()
@@ -688,7 +729,7 @@ endif()
if(CURL_USE_SCHANNEL)
set(_ssl_enabled ON)
set(USE_SCHANNEL ON) # Windows native SSL/TLS support
set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI
set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL requires CURL_WINDOWS_SSPI
if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "schannel")
set(_valid_default_ssl_backend TRUE)
@@ -779,9 +820,6 @@ if(CURL_USE_OPENSSL)
set(_openssl "AmiSSL")
else()
set(_openssl "OpenSSL")
if(OPENSSL_VERSION VERSION_LESS 1.1.1)
message(WARNING "OpenSSL ${OPENSSL_VERSION} does not support TLS 1.3.")
endif()
endif()
endif()
@@ -872,8 +910,8 @@ if(CURL_USE_GNUTLS)
if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${GNUTLS_LIBRARIES})
list(APPEND CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}")
check_symbol_exists("gnutls_srp_verifier" "gnutls/gnutls.h" HAVE_GNUTLS_SRP)
cmake_pop_check_state()
endif()
@@ -892,6 +930,22 @@ if(CURL_USE_RUSTLS)
string(APPEND CMAKE_C_FLAGS " ${RUSTLS_CFLAGS}")
endif()
if(NOT DEFINED HAVE_RUSTLS_SUPPORTED_HPKE)
if(RUSTLS_VERSION AND RUSTLS_VERSION VERSION_GREATER_EQUAL 0.15)
set(HAVE_RUSTLS_SUPPORTED_HPKE TRUE)
elseif(NOT RUSTLS_VERSION)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES "${RUSTLS_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${RUSTLS_LIBRARIES}")
curl_required_libpaths("${RUSTLS_LIBRARY_DIRS}")
check_symbol_exists("rustls_supported_hpke" "rustls.h" HAVE_RUSTLS_SUPPORTED_HPKE)
cmake_pop_check_state()
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.")
endif()
if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "rustls")
set(_valid_default_ssl_backend TRUE)
endif()
@@ -903,7 +957,7 @@ if(CURL_DEFAULT_SSL_BACKEND AND NOT _valid_default_ssl_backend)
endif()
# Keep ZLIB detection after TLS detection,
# and before calling curl_openssl_check_symbol_exists().
# and before calling curl_openssl_check_exists().
set(HAVE_LIBZ OFF)
curl_dependency_option(CURL_ZLIB ZLIB "ZLIB")
@@ -932,7 +986,7 @@ endif()
set(HAVE_ZSTD OFF)
curl_dependency_option(CURL_ZSTD Zstd "zstd")
if(ZSTD_FOUND)
if(NOT ZSTD_VERSION VERSION_LESS 1.0.0)
if(ZSTD_VERSION VERSION_GREATER_EQUAL 1.0.0)
set(HAVE_ZSTD ON)
list(APPEND CURL_LIBS ${ZSTD_LIBRARIES})
list(APPEND CURL_LIBDIRS ${ZSTD_LIBRARY_DIRS})
@@ -947,8 +1001,8 @@ if(ZSTD_FOUND)
endif()
endif()
# Check symbol in an OpenSSL-like TLS backend.
macro(curl_openssl_check_symbol_exists _symbol _files _variable)
# Check function in an OpenSSL-like TLS backend.
macro(curl_openssl_check_exists)
cmake_push_check_state()
if(USE_OPENSSL)
list(APPEND CMAKE_REQUIRED_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
@@ -956,78 +1010,88 @@ macro(curl_openssl_check_symbol_exists _symbol _files _variable)
if(HAVE_LIBZ)
list(APPEND CMAKE_REQUIRED_LIBRARIES ZLIB::ZLIB)
endif()
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
if(WIN32 AND NOT WINCE)
list(APPEND CMAKE_REQUIRED_LIBRARIES "bcrypt") # for OpenSSL/LibreSSL
endif()
endif()
if(USE_WOLFSSL)
list(APPEND CMAKE_REQUIRED_INCLUDES "${WOLFSSL_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${WOLFSSL_LIBRARIES}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${WOLFSSL_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${WOLFSSL_LIBRARIES}")
curl_required_libpaths("${WOLFSSL_LIBRARY_DIRS}")
if(HAVE_LIBZ)
list(APPEND CMAKE_REQUIRED_LIBRARIES ZLIB::ZLIB) # Public wolfSSL headers also require zlib headers
endif()
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32" "crypt32")
endif()
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DHAVE_UINTPTR_T") # to pull in stdint.h (as of wolfSSL v5.5.4)
endif()
check_symbol_exists("${_symbol}" "${_files}" "${_variable}")
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${_win32_winsock}" "${_win32_crypt32}") # for OpenSSL/wolfSSL
endif()
if(${ARGC} EQUAL 2)
check_function_exists(${ARGN})
else()
check_symbol_exists(${ARGN}) # Uses CMAKE_REQUIRED_INCLUDES and CMAKE_REQUIRED_DEFINITIONS
endif()
cmake_pop_check_state()
endmacro()
# Ensure that the OpenSSL fork actually supports QUIC.
# Ensure that OpenSSL (or fork) or wolfSSL actually supports QUICTLS API.
macro(curl_openssl_check_quic)
if(NOT DEFINED HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
if(USE_OPENSSL)
curl_openssl_check_symbol_exists("SSL_set_quic_use_legacy_codepoint" "openssl/ssl.h" HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
endif()
if(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_set_quic_use_legacy_codepoint" "wolfssl/options.h;wolfssl/openssl/ssl.h"
HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
if(USE_OPENSSL AND NOT USE_OPENSSL_QUIC)
if(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.5.0)
if(NOT DEFINED HAVE_SSL_SET_QUIC_TLS_CBS)
curl_openssl_check_exists("SSL_set_quic_tls_cbs" HAVE_SSL_SET_QUIC_TLS_CBS)
endif()
else()
if(NOT DEFINED HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
curl_openssl_check_exists("SSL_set_quic_use_legacy_codepoint" HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
endif()
endif()
endif()
if(NOT HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT)
message(FATAL_ERROR "QUIC support is missing in OpenSSL fork. Try setting -DOPENSSL_ROOT_DIR")
if(USE_WOLFSSL AND NOT DEFINED HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT)
curl_openssl_check_exists("wolfSSL_set_quic_use_legacy_codepoint" HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT)
endif()
if(NOT HAVE_SSL_SET_QUIC_TLS_CBS AND
NOT HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT AND
NOT HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT)
message(FATAL_ERROR "QUICTLS API support is missing from OpenSSL/fork/wolfSSL. Try setting -DOPENSSL_ROOT_DIR")
endif()
endmacro()
if(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_DES_ecb_encrypt" "wolfssl/options.h;wolfssl/openssl/des.h" HAVE_WOLFSSL_DES_ECB_ENCRYPT)
curl_openssl_check_symbol_exists("wolfSSL_BIO_new" "wolfssl/options.h;wolfssl/ssl.h" HAVE_WOLFSSL_BIO)
curl_openssl_check_symbol_exists("wolfSSL_BIO_set_shutdown" "wolfssl/options.h;wolfssl/ssl.h" HAVE_WOLFSSL_FULL_BIO)
curl_openssl_check_exists("wolfSSL_get_peer_certificate" HAVE_WOLFSSL_GET_PEER_CERTIFICATE)
curl_openssl_check_exists("wolfSSL_UseALPN" HAVE_WOLFSSL_USEALPN)
curl_openssl_check_exists("wolfSSL_DES_ecb_encrypt" HAVE_WOLFSSL_DES_ECB_ENCRYPT)
curl_openssl_check_exists("wolfSSL_BIO_new" HAVE_WOLFSSL_BIO_NEW)
curl_openssl_check_exists("wolfSSL_BIO_set_shutdown" HAVE_WOLFSSL_BIO_SET_SHUTDOWN)
endif()
if(USE_OPENSSL OR USE_WOLFSSL)
if(USE_OPENSSL)
if(NOT DEFINED HAVE_SSL_SET0_WBIO)
curl_openssl_check_symbol_exists("SSL_set0_wbio" "openssl/ssl.h" 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_symbol_exists("SSL_CTX_set_srp_username" "openssl/ssl.h" HAVE_OPENSSL_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" OFF)
option(USE_ECH "Enable ECH support" OFF)
if(USE_ECH)
if(USE_OPENSSL OR USE_WOLFSSL)
if(USE_OPENSSL OR USE_WOLFSSL OR USE_RUSTLS)
# Be sure that the TLS library actually supports ECH.
if(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_CTX_GenerateEchConfig" "wolfssl/options.h;wolfssl/ssl.h"
HAVE_WOLFSSL_CTX_GENERATEECHCONFIG)
curl_openssl_check_exists("wolfSSL_CTX_GenerateEchConfig" HAVE_WOLFSSL_CTX_GENERATEECHCONFIG)
endif()
if(HAVE_BORINGSSL OR HAVE_AWSLC)
curl_openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ssl.h" HAVE_SSL_SET1_ECH_CONFIG_LIST)
elseif(HAVE_OPENSSL)
curl_openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ech.h" HAVE_SSL_SET1_ECH_CONFIG_LIST)
if(USE_OPENSSL)
curl_openssl_check_exists("SSL_set1_ech_config_list" HAVE_SSL_SET1_ECH_CONFIG_LIST)
endif()
if(HAVE_WOLFSSL_CTX_GENERATEECHCONFIG OR
HAVE_SSL_SET1_ECH_CONFIG_LIST)
HAVE_SSL_SET1_ECH_CONFIG_LIST OR
USE_RUSTLS)
set(HAVE_ECH 1)
endif()
if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL")
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL/rustls-ffi")
else()
message(STATUS "ECH enabled")
# ECH wants HTTPSRR
@@ -1035,7 +1099,7 @@ if(USE_ECH)
message(STATUS "HTTPSRR enabled")
endif()
else()
message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL")
message(FATAL_ERROR "ECH requires ECH-enabled OpenSSL, BoringSSL, AWS-LC, wolfSSL or rustls-ffi")
endif()
endif()
@@ -1072,6 +1136,12 @@ if(USE_NGTCP2)
find_package(NGTCP2 REQUIRED "wolfSSL")
elseif(HAVE_BORINGSSL OR HAVE_AWSLC)
find_package(NGTCP2 REQUIRED "BoringSSL")
elseif(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.5.0 AND NOT USE_OPENSSL_QUIC)
find_package(NGTCP2 REQUIRED "ossl")
if(NGTCP2_VERSION VERSION_LESS 1.12.0)
message(FATAL_ERROR "ngtcp2 1.12.0 or upper required for OpenSSL")
endif()
set(OPENSSL_QUIC_API2 1)
else()
find_package(NGTCP2 REQUIRED "quictls")
if(NOT HAVE_LIBRESSL)
@@ -1082,7 +1152,7 @@ if(USE_NGTCP2)
elseif(USE_GNUTLS)
find_package(NGTCP2 REQUIRED "GnuTLS")
else()
message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
message(FATAL_ERROR "ngtcp2 requires a supported TLS-backend")
endif()
list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES})
list(APPEND CURL_LIBDIRS ${NGTCP2_LIBRARY_DIRS})
@@ -1125,8 +1195,8 @@ if(USE_QUICHE)
endif()
if(NOT DEFINED HAVE_QUICHE_CONN_SET_QLOG_FD)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES "${QUICHE_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${QUICHE_LIBRARIES}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${QUICHE_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${QUICHE_LIBRARIES}")
check_symbol_exists("quiche_conn_set_qlog_fd" "quiche.h" HAVE_QUICHE_CONN_SET_QLOG_FD)
cmake_pop_check_state()
endif()
@@ -1162,9 +1232,14 @@ if(USE_OPENSSL_QUIC)
find_package(NGHTTP3 REQUIRED)
set(USE_NGHTTP3 ON)
include_directories(SYSTEM ${NGHTTP3_INCLUDE_DIRS})
list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
list(APPEND CURL_LIBDIRS ${NGHTTP3_LIBRARY_DIRS})
list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${NGHTTP3_PC_REQUIRES})
include_directories(SYSTEM ${NGHTTP3_INCLUDE_DIRS})
link_directories(${NGHTTP3_LIBRARY_DIRS})
if(NGHTTP3_CFLAGS)
string(APPEND CMAKE_C_FLAGS " ${NGHTTP3_CFLAGS}")
endif()
endif()
if(CURL_WITH_MULTI_SSL AND (USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC))
@@ -1176,7 +1251,7 @@ if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
endif()
if(NOT CURL_DISABLE_LDAP)
if(WIN32 AND NOT WINDOWS_STORE)
if(WIN32 AND NOT WINDOWS_STORE AND NOT WINCE)
option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
if(USE_WIN32_LDAP)
list(APPEND CURL_LIBS "wldap32")
@@ -1210,7 +1285,7 @@ if(NOT CURL_DISABLE_LDAP)
# LDAP feature checks
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DLDAP_DEPRECATED=1")
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LDAP_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES "${LDAP_LIBRARIES}")
curl_required_libpaths("${LDAP_LIBRARY_DIRS}")
check_function_exists("ldap_url_parse" HAVE_LDAP_URL_PARSE)
@@ -1393,7 +1468,7 @@ if(CURL_USE_GSSAPI)
set(HAVE_GSSGNU 1)
else()
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_INCLUDES "${GSS_INCLUDE_DIRS}")
set(_include_list "")
check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H)
@@ -1413,7 +1488,7 @@ if(CURL_USE_GSSAPI)
if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE)
string(APPEND CMAKE_REQUIRED_FLAGS " ${GSS_CFLAGS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES "${GSS_LIBRARIES}")
curl_required_libpaths("${GSS_LIBRARY_DIRS}")
check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" "${_include_list}" HAVE_GSS_C_NT_HOSTBASED_SERVICE)
endif()
@@ -1462,7 +1537,7 @@ if(USE_LIBRTMP)
endif()
option(ENABLE_UNIX_SOCKETS "Enable Unix domain sockets support" ON)
if(ENABLE_UNIX_SOCKETS)
if(ENABLE_UNIX_SOCKETS AND NOT WINCE)
if(WIN32 OR DOS)
set(USE_UNIX_SOCKETS ON)
else()
@@ -1572,24 +1647,9 @@ if(WIN32)
list(APPEND CURL_INCLUDES "winsock2.h")
list(APPEND CURL_INCLUDES "ws2tcpip.h")
if(HAVE_WIN32_WINNT)
if(HAVE_WIN32_WINNT LESS 0x0501)
# Windows XP is required for freeaddrinfo, getaddrinfo
message(FATAL_ERROR "Building for Windows XP or newer is required.")
endif()
# Pre-fill detection results based on target OS version
if(MINGW OR MSVC)
if(HAVE_WIN32_WINNT LESS 0x0600)
set(HAVE_INET_NTOP 0)
set(HAVE_INET_PTON 0)
else() # Windows Vista or newer
set(HAVE_INET_NTOP 1)
set(HAVE_INET_PTON 1)
endif()
unset(HAVE_INET_NTOP CACHE)
unset(HAVE_INET_PTON CACHE)
endif()
if(HAVE_WIN32_WINNT AND HAVE_WIN32_WINNT LESS 0x0501 AND NOT WINCE)
# Windows XP is required for freeaddrinfo, getaddrinfo
message(FATAL_ERROR "Building for Windows XP or newer is required.")
endif()
endif()
@@ -1631,6 +1691,7 @@ check_include_file("poll.h" HAVE_POLL_H)
check_include_file("pwd.h" HAVE_PWD_H)
check_include_file("stdatomic.h" HAVE_STDATOMIC_H)
check_include_file("stdbool.h" HAVE_STDBOOL_H)
check_include_file("stdint.h" HAVE_STDINT_H)
check_include_file("strings.h" HAVE_STRINGS_H)
check_include_file("stropts.h" HAVE_STROPTS_H)
check_include_file("termio.h" HAVE_TERMIO_H)
@@ -1687,13 +1748,14 @@ endif()
# Apply to all feature checks
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${_win32_winsock}")
elseif(HAVE_LIBSOCKET)
list(APPEND CMAKE_REQUIRED_LIBRARIES "socket")
elseif(DOS)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${WATT_ROOT}/lib/libwatt.a")
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)
@@ -1706,7 +1768,6 @@ 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("strdup" "string.h" HAVE_STRDUP)
check_symbol_exists("strtok_r" "string.h" HAVE_STRTOK_R)
check_symbol_exists("memrchr" "string.h" HAVE_MEMRCHR)
check_symbol_exists("alarm" "unistd.h" HAVE_ALARM)
check_symbol_exists("fcntl" "fcntl.h" HAVE_FCNTL)
@@ -1727,7 +1788,6 @@ check_symbol_exists("gethostbyname_r" "netdb.h" HAVE_GETHOSTBYNAME_R)
check_symbol_exists("gethostname" "${CURL_INCLUDES}" HAVE_GETHOSTNAME) # winsock2.h unistd.h proto/bsdsocket.h
check_symbol_exists("signal" "signal.h" HAVE_SIGNAL)
check_symbol_exists("strtoll" "stdlib.h" HAVE_STRTOLL)
check_symbol_exists("strerror_r" "stdlib.h;string.h" HAVE_STRERROR_R)
check_symbol_exists("sigaction" "signal.h" HAVE_SIGACTION)
check_symbol_exists("siginterrupt" "signal.h" HAVE_SIGINTERRUPT)
@@ -1735,13 +1795,13 @@ check_symbol_exists("getaddrinfo" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_
check_symbol_exists("getifaddrs" "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS) # ifaddrs.h
check_symbol_exists("freeaddrinfo" "${CURL_INCLUDES}" HAVE_FREEADDRINFO) # ws2tcpip.h sys/socket.h netdb.h
check_function_exists("pipe" HAVE_PIPE)
check_function_exists("pipe2" HAVE_PIPE2)
check_function_exists("eventfd" HAVE_EVENTFD)
check_symbol_exists("ftruncate" "unistd.h" HAVE_FTRUNCATE)
check_symbol_exists("getpeername" "${CURL_INCLUDES}" HAVE_GETPEERNAME) # winsock2.h unistd.h proto/bsdsocket.h
check_symbol_exists("getsockname" "${CURL_INCLUDES}" HAVE_GETSOCKNAME) # winsock2.h unistd.h proto/bsdsocket.h
check_function_exists("getrlimit" HAVE_GETRLIMIT)
check_function_exists("setlocale" HAVE_SETLOCALE)
check_function_exists("setmode" HAVE_SETMODE)
check_function_exists("setrlimit" HAVE_SETRLIMIT)
if(NOT WIN32)
@@ -1753,8 +1813,11 @@ if(NOT WIN32)
check_symbol_exists("strcmpi" "string.h" HAVE_STRCMPI)
endif()
if(WIN32 OR CYGWIN)
check_function_exists("_setmode" HAVE__SETMODE)
if(NOT MINGW32CE) # Avoid false detections
check_function_exists("setmode" HAVE_SETMODE)
if(WIN32 OR CYGWIN)
check_function_exists("_setmode" HAVE__SETMODE)
endif()
endif()
if(AMIGA)
@@ -1773,8 +1836,10 @@ endif()
if(APPLE)
check_function_exists("mach_absolute_time" HAVE_MACH_ABSOLUTE_TIME)
endif()
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
if(NOT WIN32)
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
endif()
check_symbol_exists("fsetxattr" "sys/xattr.h" HAVE_FSETXATTR)
if(HAVE_FSETXATTR)
@@ -1807,18 +1872,44 @@ foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6
HAVE_GETHOSTBYNAME_R_3_REENTRANT
HAVE_GETHOSTBYNAME_R_5_REENTRANT
HAVE_GETHOSTBYNAME_R_6_REENTRANT
HAVE_IN_ADDR_T
HAVE_BOOL_T
STDC_HEADERS
HAVE_FILE_OFFSET_BITS
HAVE_ATOMIC
)
curl_internal_test(${_curl_test})
endforeach()
# Check for reentrant
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_REENTRANT")
foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6)
curl_internal_test(${_curl_test}_REENTRANT)
if(NOT ${_curl_test} AND ${_curl_test}_REENTRANT)
set(NEED_REENTRANT 1)
endif()
endforeach()
cmake_pop_check_state()
if(NEED_REENTRANT)
foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6)
set(${_curl_test} 0)
if(${_curl_test}_REENTRANT)
set(${_curl_test} 1)
endif()
endforeach()
endif()
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64")
curl_internal_test(HAVE_FILE_OFFSET_BITS)
cmake_pop_check_state()
cmake_push_check_state()
if(HAVE_FILE_OFFSET_BITS)
set(_FILE_OFFSET_BITS 64)
@@ -1872,30 +1963,6 @@ endif()
curl_internal_test(HAVE_GLIBC_STRERROR_R)
curl_internal_test(HAVE_POSIX_STRERROR_R)
# Check for reentrant
foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6)
if(NOT ${_curl_test})
if(${_curl_test}_REENTRANT)
set(NEED_REENTRANT 1)
endif()
endif()
endforeach()
if(NEED_REENTRANT)
foreach(_curl_test IN ITEMS
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6)
set(${_curl_test} 0)
if(${_curl_test}_REENTRANT)
set(${_curl_test} 1)
endif()
endforeach()
endif()
if(NOT WIN32)
curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC) # Check clock_gettime(CLOCK_MONOTONIC, x) support
endif()
@@ -1906,26 +1973,6 @@ endif()
# Some other minor tests
if(NOT HAVE_IN_ADDR_T)
set(in_addr_t "unsigned long")
endif()
if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
include(CheckCCompilerFlag)
check_c_compiler_flag("-Wno-long-double" HAVE_C_FLAG_Wno_long_double)
if(HAVE_C_FLAG_Wno_long_double)
# The Mac version of GCC warns about use of long double. Disable it.
get_source_file_property(_mprintf_compile_flags "mprintf.c" COMPILE_FLAGS)
if(_mprintf_compile_flags)
string(APPEND _mprintf_compile_flags " -Wno-long-double")
else()
set(_mprintf_compile_flags "-Wno-long-double")
endif()
set_source_files_properties("mprintf.c" PROPERTIES
COMPILE_FLAGS ${_mprintf_compile_flags})
endif()
endif()
if(_cmake_try_compile_target_type_save)
set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_cmake_try_compile_target_type_save})
unset(_cmake_try_compile_target_type_save)
@@ -1933,18 +1980,17 @@ endif()
include(CMake/OtherTests.cmake)
add_definitions("-DHAVE_CONFIG_H")
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H")
if(WIN32)
list(APPEND CURL_LIBS "ws2_32" "bcrypt")
# _fseeki64() requires VS2005
if(NOT MSVC OR (MSVC_VERSION GREATER_EQUAL 1400))
set(USE_WIN32_LARGE_FILES ON)
list(APPEND CURL_LIBS "${_win32_winsock}")
if(NOT WINCE)
list(APPEND CURL_LIBS "bcrypt")
endif()
# Use the manifest embedded in the Windows Resource
string(APPEND CMAKE_RC_FLAGS " -DCURL_EMBED_MANIFEST")
if(NOT WINCE)
set(USE_WIN32_LARGE_FILES ON)
endif()
# We use crypto functions that are not available for UWP apps
if(NOT WINDOWS_STORE)
@@ -1953,32 +1999,15 @@ if(WIN32)
# Link required libraries for USE_WIN32_CRYPTO or USE_SCHANNEL
if(USE_WIN32_CRYPTO OR USE_SCHANNEL)
list(APPEND CURL_LIBS "advapi32" "crypt32")
if(NOT WINCE)
list(APPEND CURL_LIBS "advapi32")
endif()
list(APPEND CURL_LIBS "${_win32_crypt32}")
endif()
endif()
if(MSVC)
# Disable default manifest added by CMake
string(APPEND CMAKE_EXE_LINKER_FLAGS " -MANIFEST:NO")
if(CMAKE_C_FLAGS MATCHES "[/-]W[0-4]")
string(REGEX REPLACE "[/-]W[0-4]" "-W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
string(APPEND CMAKE_C_FLAGS " -W4")
endif()
# Use multithreaded compilation on VS2008+
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1500)
string(APPEND CMAKE_C_FLAGS " -MP")
endif()
endif()
if(CURL_WERROR)
if(MSVC)
string(APPEND CMAKE_C_FLAGS " -WX")
else()
string(APPEND CMAKE_C_FLAGS " -Werror") # This assumes clang or gcc style options
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-MP") # Parallel compilation
endif()
if(CURL_LTO)
@@ -2005,9 +2034,9 @@ function(curl_transform_makefile_inc _input_file _output_file)
string(REPLACE "$(top_srcdir)" "\${PROJECT_SOURCE_DIR}" _makefile_inc_text ${_makefile_inc_text})
string(REPLACE "$(top_builddir)" "\${PROJECT_BINARY_DIR}" _makefile_inc_text ${_makefile_inc_text})
string(REGEX REPLACE "\\\\\n" "!π!α!" _makefile_inc_text ${_makefile_inc_text})
string(REGEX REPLACE "\\\\\n" "!^!^!" _makefile_inc_text ${_makefile_inc_text})
string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "set(\\1 \\2)" _makefile_inc_text ${_makefile_inc_text})
string(REPLACE "!π!α!" "\n" _makefile_inc_text ${_makefile_inc_text})
string(REPLACE "!^!^!" "\n" _makefile_inc_text ${_makefile_inc_text})
# Replace $() with ${}
string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" _makefile_inc_text ${_makefile_inc_text})
@@ -2027,7 +2056,7 @@ set(_project_config "${_generated_dir}/${PROJECT_NAME}Config.cmake")
set(_version_config "${_generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
option(BUILD_TESTING "Build tests" ON)
if(BUILD_TESTING AND PERL_FOUND AND NOT CURL_DISABLE_TESTS)
if(BUILD_TESTING AND PERL_FOUND)
set(CURL_BUILD_TESTING ON)
else()
set(CURL_BUILD_TESTING OFF)
@@ -2039,6 +2068,10 @@ if(HAVE_MANUAL_TOOLS)
add_subdirectory(docs)
endif()
add_subdirectory(scripts) # for shell completions
list(REMOVE_DUPLICATES CURL_LIBDIRS)
add_subdirectory(lib)
if(BUILD_CURL_EXE)
@@ -2143,16 +2176,16 @@ 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" NOT (CURL_DISABLE_NTLM) AND
curl_add_if("NTLM" NOT CURL_DISABLE_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 OR USE_MSH3 OR USE_OPENSSL_QUIC)
curl_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
curl_add_if("HTTPS-proxy" _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
curl_add_if("HTTPS-proxy" NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
USE_MBEDTLS OR USE_SECTRANSP OR
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO)))
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO_NEW)))
curl_add_if("Unicode" ENABLE_UNICODE)
curl_add_if("threadsafe" HAVE_ATOMIC OR
(USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
@@ -2165,7 +2198,7 @@ curl_add_if("PSL" USE_LIBPSL)
curl_add_if("CAcert" CURL_CA_EMBED_SET)
curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT)
if(_items)
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
list(SORT _items CASE INSENSITIVE)
else()
list(SORT _items)
@@ -2179,7 +2212,7 @@ message(STATUS "Features: ${SUPPORT_FEATURES}")
set(_items "")
curl_add_if("Schannel" _ssl_enabled AND USE_SCHANNEL)
curl_add_if("${_openssl}" _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_LESS 3.0.0)
curl_add_if("${_openssl} v3+" _ssl_enabled AND USE_OPENSSL AND NOT OPENSSL_VERSION VERSION_LESS 3.0.0)
curl_add_if("${_openssl} v3+" _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
curl_add_if("Secure Transport" _ssl_enabled AND USE_SECTRANSP)
curl_add_if("mbedTLS" _ssl_enabled AND USE_MBEDTLS)
curl_add_if("BearSSL" _ssl_enabled AND USE_BEARSSL)
@@ -2188,7 +2221,7 @@ curl_add_if("GnuTLS" _ssl_enabled AND USE_GNUTLS)
curl_add_if("rustls" _ssl_enabled AND USE_RUSTLS)
if(_items)
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
list(SORT _items CASE INSENSITIVE)
else()
list(SORT _items)
@@ -2266,7 +2299,7 @@ if(NOT CURL_DISABLE_INSTALL)
endforeach()
foreach(_libdir IN LISTS _custom_libdirs CURL_LIBDIRS)
if(NOT CMAKE_VERSION VERSION_LESS 3.20)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(SET _libdir NORMALIZE "${_libdir}")
endif()
list(FIND _sys_libdirs "${_libdir}" _libdir_index)
@@ -2303,7 +2336,7 @@ if(NOT CURL_DISABLE_INSTALL)
get_filename_component(_libdir ${_lib} DIRECTORY)
get_filename_component(_libname ${_lib} NAME_WE)
if(_libname MATCHES "^lib")
if(NOT CMAKE_VERSION VERSION_LESS 3.20)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(SET _libdir NORMALIZE "${_libdir}")
endif()
list(FIND _sys_libdirs "${_libdir}" _libdir_index)
@@ -2432,6 +2465,7 @@ if(NOT CURL_DISABLE_INSTALL)
# Consumed custom variables:
# CURLVERSION
# LIB_NAME
# LIB_SELECTED
# TARGETS_EXPORT_NAME
# USE_OPENSSL OPENSSL_VERSION_MAJOR
@@ -2462,7 +2496,7 @@ if(NOT CURL_DISABLE_INSTALL)
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake")
endif()
install(FILES "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
install(FILES "${PROJECT_SOURCE_DIR}/scripts/wcurl"
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

196
lib/asyn-base.c Normal file
View File

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

760
lib/asyn-thrdd.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

581
lib/cshutdn.c Normal file
View File

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

110
lib/cshutdn.h Normal file
View File

@@ -0,0 +1,110 @@
#ifndef HEADER_CURL_CSHUTDN_H
#define HEADER_CURL_CSHUTDN_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include <curl/curl.h>
#include "curlx/timeval.h"
struct connectdata;
struct Curl_easy;
struct curl_pollfds;
struct Curl_waitfds;
struct Curl_multi;
struct Curl_share;
/* Run the shutdown of the connection once.
* Will shortly attach/detach `data` to `conn` while doing so.
* `done` will be set TRUE if any error was encountered or if
* the connection was shut down completely. */
void Curl_cshutdn_run_once(struct Curl_easy *data,
struct connectdata *conn,
bool *done);
/* Terminates the connection, e.g. closes and destroys it.
* If `run_shutdown` is TRUE, the shutdown will be run once before
* terminating it.
* Takes ownership of `conn`. */
void Curl_cshutdn_terminate(struct Curl_easy *data,
struct connectdata *conn,
bool run_shutdown);
/* A `cshutdown` is always owned by a multi handle to maintain
* the connections to be shut down. It registers timers and
* sockets to monitor via the multi handle. */
struct cshutdn {
struct Curl_llist list; /* connections being shut down */
struct Curl_multi *multi; /* the multi owning this */
BIT(initialised);
};
/* Init as part of the given multi handle. */
int Curl_cshutdn_init(struct cshutdn *cshutdn,
struct Curl_multi *multi);
/* Terminate all remaining connections and free resources. */
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
struct Curl_easy *data);
/* Number of connections being shut down. */
size_t Curl_cshutdn_count(struct Curl_easy *data);
/* Number of connections to the destination being shut down. */
size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
const char *destination);
/* Close the oldest connection in shutdown to destination or,
* when destination is NULL for any destination.
* Return TRUE if a connection has been closed. */
bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
const char *destination);
/* Add a connection to have it shut down. Will terminate the oldest
* connection when total connection limit of multi is being reached. */
void Curl_cshutdn_add(struct cshutdn *cshutdn,
struct connectdata *conn,
size_t conns_in_pool);
/* Add sockets and POLLIN/OUT flags for connections being shut down. */
CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct curl_pollfds *cpfds);
unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct Curl_waitfds *cwfds);
void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
struct Curl_easy *data,
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd);
/* Run shut down connections using socket. If socket is CURL_SOCKET_TIMEOUT,
* run maintenance on all connections. */
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
curl_socket_t s);
#endif /* HEADER_CURL_CSHUTDN_H */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

303
lib/curlx/strparse.c Normal file
View File

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

112
lib/curlx/strparse.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

135
lib/curlx/winapi.c Normal file
View File

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

View File

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

View File

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

View File

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

242
lib/cw-pause.c Normal file
View File

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

View File

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

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