mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-11 16:32:14 -06:00
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:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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
316
CMake/unix-cache.cmake
Normal 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)
|
||||
@@ -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()
|
||||
|
||||
506
CMakeLists.txt
506
CMakeLists.txt
@@ -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
|
||||
|
||||
@@ -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__) && \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
356
lib/altsvc.c
356
lib/altsvc.c
@@ -35,12 +35,12 @@
|
||||
#include "strcase.h"
|
||||
#include "parsedate.h"
|
||||
#include "sendf.h"
|
||||
#include "warnless.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "fopen.h"
|
||||
#include "rename.h"
|
||||
#include "strdup.h"
|
||||
#include "inet_pton.h"
|
||||
#include "strparse.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "connect.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
@@ -138,18 +138,20 @@ static struct altsvc *altsvc_create(struct Curl_str *srchost,
|
||||
size_t srcport,
|
||||
size_t dstport)
|
||||
{
|
||||
enum alpnid dstalpnid = Curl_alpn2alpnid(dstalpn->str, dstalpn->len);
|
||||
enum alpnid srcalpnid = Curl_alpn2alpnid(srcalpn->str, srcalpn->len);
|
||||
enum alpnid dstalpnid =
|
||||
Curl_alpn2alpnid(curlx_str(dstalpn), curlx_strlen(dstalpn));
|
||||
enum alpnid srcalpnid =
|
||||
Curl_alpn2alpnid(curlx_str(srcalpn), curlx_strlen(srcalpn));
|
||||
if(!srcalpnid || !dstalpnid)
|
||||
return NULL;
|
||||
return altsvc_createid(srchost->str, srchost->len,
|
||||
dsthost->str, dsthost->len,
|
||||
return altsvc_createid(curlx_str(srchost), curlx_strlen(srchost),
|
||||
curlx_str(dsthost), curlx_strlen(dsthost),
|
||||
srcalpnid, dstalpnid,
|
||||
srcport, dstport);
|
||||
}
|
||||
|
||||
/* only returns SERIOUS errors */
|
||||
static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
|
||||
static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
|
||||
{
|
||||
/* Example line:
|
||||
h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
|
||||
@@ -159,42 +161,42 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
|
||||
struct Curl_str srcalpn;
|
||||
struct Curl_str dstalpn;
|
||||
struct Curl_str date;
|
||||
size_t srcport;
|
||||
size_t dstport;
|
||||
size_t persist;
|
||||
size_t prio;
|
||||
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(×tr, &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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
884
lib/asyn-ares.c
884
lib/asyn-ares.c
File diff suppressed because it is too large
Load Diff
196
lib/asyn-base.c
Normal file
196
lib/asyn-base.c
Normal 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
760
lib/asyn-thrdd.c
Normal 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 */
|
||||
@@ -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 */
|
||||
319
lib/asyn.h
319
lib/asyn.h
@@ -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 *****************/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) */
|
||||
|
||||
188
lib/cf-socket.c
188
lib/cf-socket.c
@@ -74,15 +74,17 @@
|
||||
#include "multiif.h"
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "inet_ntop.h"
|
||||
#include "inet_pton.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "progress.h"
|
||||
#include "warnless.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multihandle.h"
|
||||
#include "rand.h"
|
||||
#include "share.h"
|
||||
#include "strdup.h"
|
||||
#include "version_win32.h"
|
||||
#include "system_win32.h"
|
||||
#include "curlx/version_win32.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@@ -113,8 +115,8 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
|
||||
int level = IPPROTO_TCP;
|
||||
char buffer[STRERROR_LEN];
|
||||
|
||||
if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
|
||||
sizeof(onoff)) < 0)
|
||||
if(setsockopt(sockfd, level, TCP_NODELAY,
|
||||
(void *)&onoff, sizeof(onoff)) < 0)
|
||||
infof(data, "Could not set TCP_NODELAY: %s",
|
||||
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
|
||||
#else
|
||||
@@ -133,8 +135,8 @@ static void nosigpipe(struct Curl_easy *data,
|
||||
{
|
||||
int onoff = 1;
|
||||
(void)data;
|
||||
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
|
||||
sizeof(onoff)) < 0) {
|
||||
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
|
||||
(void *)&onoff, sizeof(onoff)) < 0) {
|
||||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
char buffer[STRERROR_LEN];
|
||||
infof(data, "Could not set SO_NOSIGPIPE: %s",
|
||||
@@ -181,7 +183,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
|
||||
/* only set IDLE and INTVL if setting KEEPALIVE is successful */
|
||||
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set SO_KEEPALIVE on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d",
|
||||
sockfd, SOCKERRNO);
|
||||
@@ -234,7 +236,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
optval = curlx_sltosi(data->set.tcp_keepidle);
|
||||
KEEPALIVE_FACTOR(optval);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPIDLE on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d",
|
||||
sockfd, SOCKERRNO);
|
||||
@@ -244,7 +246,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
optval = curlx_sltosi(data->set.tcp_keepidle);
|
||||
KEEPALIVE_FACTOR(optval);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPALIVE on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d",
|
||||
sockfd, SOCKERRNO);
|
||||
@@ -254,7 +256,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
optval = curlx_sltosi(data->set.tcp_keepidle);
|
||||
KEEPALIVE_FACTOR(optval);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d",
|
||||
sockfd, SOCKERRNO);
|
||||
@@ -264,7 +266,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
optval = curlx_sltosi(data->set.tcp_keepintvl);
|
||||
KEEPALIVE_FACTOR(optval);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPINTVL on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d",
|
||||
sockfd, SOCKERRNO);
|
||||
@@ -285,7 +287,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
curlx_sltosi(data->set.tcp_keepintvl);
|
||||
KEEPALIVE_FACTOR(optval);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
|
||||
}
|
||||
@@ -293,7 +295,7 @@ tcpkeepalive(struct Curl_easy *data,
|
||||
#ifdef TCP_KEEPCNT
|
||||
optval = curlx_sltosi(data->set.tcp_keepcnt);
|
||||
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
(void *)&optval, sizeof(optval)) < 0) {
|
||||
infof(data, "Failed to set TCP_KEEPCNT on fd "
|
||||
"%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
|
||||
}
|
||||
@@ -420,7 +422,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
|
||||
|
||||
if(use_callback && conn && conn->fclosesocket) {
|
||||
int rc;
|
||||
Curl_multi_closed(data, sock);
|
||||
Curl_multi_will_close(data, sock);
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
rc = conn->fclosesocket(conn->closesocket_client, sock);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
@@ -429,7 +431,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
|
||||
|
||||
if(conn)
|
||||
/* tell the multi-socket code about this */
|
||||
Curl_multi_closed(data, sock);
|
||||
Curl_multi_will_close(data, sock);
|
||||
|
||||
sclose(sock);
|
||||
|
||||
@@ -460,9 +462,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
|
||||
Windows. Following function trying to detect OS version and skips
|
||||
SO_SNDBUF adjustment for Windows Vista and above.
|
||||
*/
|
||||
#define DETECT_OS_NONE 0
|
||||
#define DETECT_OS_PREVISTA 1
|
||||
#define DETECT_OS_VISTA_OR_LATER 2
|
||||
|
||||
void Curl_sndbuf_init(curl_socket_t sockfd)
|
||||
{
|
||||
@@ -470,17 +469,7 @@ void Curl_sndbuf_init(curl_socket_t sockfd)
|
||||
int curval = 0;
|
||||
int curlen = sizeof(curval);
|
||||
|
||||
static int detectOsState = DETECT_OS_NONE;
|
||||
|
||||
if(detectOsState == DETECT_OS_NONE) {
|
||||
if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL))
|
||||
detectOsState = DETECT_OS_VISTA_OR_LATER;
|
||||
else
|
||||
detectOsState = DETECT_OS_PREVISTA;
|
||||
}
|
||||
|
||||
if(detectOsState == DETECT_OS_VISTA_OR_LATER)
|
||||
if(Curl_isVistaOrGreater)
|
||||
return;
|
||||
|
||||
if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
|
||||
@@ -685,21 +674,14 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
|
||||
* of the connection. The resolve functions should really be changed
|
||||
* to take a type parameter instead.
|
||||
*/
|
||||
unsigned char ipver = conn->ip_version;
|
||||
int rc;
|
||||
|
||||
if(af == AF_INET)
|
||||
conn->ip_version = CURL_IPRESOLVE_V4;
|
||||
int ip_version = (af == AF_INET) ?
|
||||
CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_WHATEVER;
|
||||
#ifdef USE_IPV6
|
||||
else if(af == AF_INET6)
|
||||
conn->ip_version = CURL_IPRESOLVE_V6;
|
||||
if(af == AF_INET6)
|
||||
ip_version = CURL_IPRESOLVE_V6;
|
||||
#endif
|
||||
|
||||
rc = Curl_resolv(data, host, 80, FALSE, &h);
|
||||
if(rc == CURLRESOLV_PENDING)
|
||||
(void)Curl_resolver_wait_resolv(data, &h);
|
||||
conn->ip_version = ipver;
|
||||
|
||||
(void)Curl_resolv_blocking(data, host, 80, ip_version, &h);
|
||||
if(h) {
|
||||
int h_af = h->addr->ai_family;
|
||||
/* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
|
||||
@@ -732,7 +714,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
|
||||
if(scope_ptr)
|
||||
*(scope_ptr++) = '\0';
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
|
||||
if(curlx_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
|
||||
si6->sin6_family = AF_INET6;
|
||||
si6->sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
@@ -741,10 +723,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
|
||||
Curl_printable_address. The latter returns only numeric scope
|
||||
IDs and the former returns none at all. So the scope ID, if
|
||||
present, is known to be numeric */
|
||||
unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
|
||||
if(scope_id > UINT_MAX)
|
||||
curl_off_t scope_id;
|
||||
if(curlx_str_number((const char **)CURL_UNCONST(&scope_ptr),
|
||||
&scope_id, UINT_MAX))
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
|
||||
si6->sin6_scope_id = (unsigned int)scope_id;
|
||||
}
|
||||
#endif
|
||||
@@ -755,7 +737,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
|
||||
#endif
|
||||
/* IPv4 address */
|
||||
if((af == AF_INET) &&
|
||||
(Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
|
||||
(curlx_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
|
||||
si4->sin_family = AF_INET;
|
||||
si4->sin_port = htons(port);
|
||||
sizeof_sa = sizeof(struct sockaddr_in);
|
||||
@@ -855,7 +837,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
|
||||
* Someone got to verify this on Win-NT 4.0, 2000."
|
||||
*/
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#ifdef UNDER_CE
|
||||
Sleep(0);
|
||||
#else
|
||||
SleepEx(0, FALSE);
|
||||
@@ -865,7 +847,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
|
||||
|
||||
if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
|
||||
err = SOCKERRNO;
|
||||
#ifdef _WIN32_WCE
|
||||
#ifdef UNDER_CE
|
||||
/* Old Windows CE versions do not support SO_ERROR */
|
||||
if(WSAENOPROTOOPT == err) {
|
||||
SET_SOCKERRNO(0);
|
||||
@@ -879,7 +861,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
|
||||
err = 0;
|
||||
}
|
||||
#endif
|
||||
if((0 == err) || (EISCONN == err))
|
||||
if((0 == err) || (SOCKEISCONN == err))
|
||||
/* we are connected, awesome! */
|
||||
rc = TRUE;
|
||||
else
|
||||
@@ -902,10 +884,10 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
|
||||
const char *ipaddress, int error)
|
||||
{
|
||||
switch(error) {
|
||||
case EINPROGRESS:
|
||||
case EWOULDBLOCK:
|
||||
case SOCKEINPROGRESS:
|
||||
case SOCKEWOULDBLOCK:
|
||||
#if defined(EAGAIN)
|
||||
#if (EAGAIN) != (EWOULDBLOCK)
|
||||
#if (EAGAIN) != (SOCKEWOULDBLOCK)
|
||||
/* On some platforms EAGAIN and EWOULDBLOCK are the
|
||||
* same value, and on others they are different, hence
|
||||
* the odd #if
|
||||
@@ -932,15 +914,6 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
|
||||
}
|
||||
}
|
||||
|
||||
/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
|
||||
* This happens often on TLS connections where the TLS implementation
|
||||
* tries to read the head of a TLS record, determine the length of the
|
||||
* full record and then make a subsequent read for that.
|
||||
* On large reads, we will not fill the buffer to avoid the double copy. */
|
||||
#define NW_RECV_CHUNK_SIZE (64 * 1024)
|
||||
#define NW_RECV_CHUNKS 1
|
||||
#define NW_SMALL_READS (1024)
|
||||
|
||||
struct cf_socket_ctx {
|
||||
int transport;
|
||||
struct Curl_sockaddr_ex addr; /* address to connect to */
|
||||
@@ -983,28 +956,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
{
|
||||
char *p = getenv("CURL_DBG_SOCK_WBLOCK");
|
||||
const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
|
||||
if(p) {
|
||||
long l = strtol(p, NULL, 10);
|
||||
if(l >= 0 && l <= 100)
|
||||
curl_off_t l;
|
||||
if(!curlx_str_number(&p, &l, 100))
|
||||
ctx->wblock_percent = (int)l;
|
||||
}
|
||||
p = getenv("CURL_DBG_SOCK_WPARTIAL");
|
||||
if(p) {
|
||||
long l = strtol(p, NULL, 10);
|
||||
if(l >= 0 && l <= 100)
|
||||
curl_off_t l;
|
||||
if(!curlx_str_number(&p, &l, 100))
|
||||
ctx->wpartial_percent = (int)l;
|
||||
}
|
||||
p = getenv("CURL_DBG_SOCK_RBLOCK");
|
||||
if(p) {
|
||||
long l = strtol(p, NULL, 10);
|
||||
if(l >= 0 && l <= 100)
|
||||
curl_off_t l;
|
||||
if(!curlx_str_number(&p, &l, 100))
|
||||
ctx->rblock_percent = (int)l;
|
||||
}
|
||||
p = getenv("CURL_DBG_SOCK_RMAX");
|
||||
if(p) {
|
||||
long l = strtol(p, NULL, 10);
|
||||
if(l >= 0)
|
||||
curl_off_t l;
|
||||
if(!curlx_str_number(&p, &l, CURL_OFF_T_MAX))
|
||||
ctx->recv_max = (size_t)l;
|
||||
}
|
||||
}
|
||||
@@ -1018,7 +991,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
|
||||
if(ctx && CURL_SOCKET_BAD != ctx->sock) {
|
||||
CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
|
||||
CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
|
||||
if(ctx->sock == cf->conn->sock[cf->sockindex])
|
||||
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
|
||||
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
|
||||
@@ -1040,7 +1013,7 @@ static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
|
||||
if(cf->connected) {
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
|
||||
CURL_TRC_CF(data, cf, "cf_socket_shutdown, fd=%" FMT_SOCKET_T, ctx->sock);
|
||||
/* On TCP, and when the socket looks well and non-blocking mode
|
||||
* can be enabled, receive dangling bytes before close to avoid
|
||||
* entering RST states unnecessarily. */
|
||||
@@ -1132,7 +1105,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
|
||||
ctx->started_at = Curl_now();
|
||||
ctx->started_at = curlx_now();
|
||||
#ifdef SOCK_NONBLOCK
|
||||
/* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
|
||||
* because we would not know how socketype is about to be used in the
|
||||
@@ -1248,7 +1221,7 @@ out:
|
||||
}
|
||||
else if(isconnected) {
|
||||
set_local_ip(cf, data);
|
||||
ctx->connected_at = Curl_now();
|
||||
ctx->connected_at = curlx_now();
|
||||
cf->connected = TRUE;
|
||||
}
|
||||
CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
|
||||
@@ -1313,7 +1286,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
|
||||
static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_COULDNT_CONNECT;
|
||||
@@ -1325,9 +1298,6 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(blocking)
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
|
||||
*done = FALSE; /* a negative world view is best */
|
||||
if(ctx->sock == CURL_SOCKET_BAD) {
|
||||
int error;
|
||||
@@ -1370,7 +1340,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
|
||||
else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
|
||||
if(verifyconnect(ctx->sock, &ctx->error)) {
|
||||
/* we are connected with TCP, awesome! */
|
||||
ctx->connected_at = Curl_now();
|
||||
ctx->connected_at = curlx_now();
|
||||
set_local_ip(cf, data);
|
||||
*done = TRUE;
|
||||
cf->connected = TRUE;
|
||||
@@ -1471,9 +1441,9 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
|
||||
{
|
||||
ULONG ideal;
|
||||
DWORD ideallen;
|
||||
struct curltime n = Curl_now();
|
||||
struct curltime n = curlx_now();
|
||||
|
||||
if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
|
||||
if(curlx_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
|
||||
if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
|
||||
&ideal, sizeof(ideal), &ideallen, 0, 0) &&
|
||||
ideal != ctx->sndbuf_size &&
|
||||
@@ -1538,15 +1508,16 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
int sockerr = SOCKERRNO;
|
||||
|
||||
if(
|
||||
#ifdef WSAEWOULDBLOCK
|
||||
#ifdef USE_WINSOCK
|
||||
/* This is how Windows does it */
|
||||
(WSAEWOULDBLOCK == sockerr)
|
||||
(SOCKEWOULDBLOCK == sockerr)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
|
||||
(EINPROGRESS == sockerr)
|
||||
(SOCKEWOULDBLOCK == sockerr) ||
|
||||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
|
||||
(SOCKEINPROGRESS == sockerr)
|
||||
#endif
|
||||
) {
|
||||
/* this is just a case of EWOULDBLOCK */
|
||||
@@ -1606,14 +1577,15 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
int sockerr = SOCKERRNO;
|
||||
|
||||
if(
|
||||
#ifdef WSAEWOULDBLOCK
|
||||
#ifdef USE_WINSOCK
|
||||
/* This is how Windows does it */
|
||||
(WSAEWOULDBLOCK == sockerr)
|
||||
(SOCKEWOULDBLOCK == sockerr)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
|
||||
(SOCKEWOULDBLOCK == sockerr) ||
|
||||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr)
|
||||
#endif
|
||||
) {
|
||||
/* this is just a case of EWOULDBLOCK */
|
||||
@@ -1632,7 +1604,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
|
||||
*err);
|
||||
if(nread > 0 && !ctx->got_first_byte) {
|
||||
ctx->first_byte_at = Curl_now();
|
||||
ctx->first_byte_at = curlx_now();
|
||||
ctx->got_first_byte = TRUE;
|
||||
}
|
||||
return nread;
|
||||
@@ -1743,7 +1715,7 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
case CF_QUERY_CONNECT_REPLY_MS:
|
||||
if(ctx->got_first_byte) {
|
||||
timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
|
||||
timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
|
||||
*pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
|
||||
}
|
||||
else
|
||||
@@ -1849,7 +1821,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
|
||||
/* QUIC needs a connected socket, nonblocking */
|
||||
DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
|
||||
|
||||
rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, /* NOLINT */
|
||||
/* error: The 1st argument to 'connect' is -1 but should be >= 0
|
||||
NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions) */
|
||||
rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
|
||||
(curl_socklen_t)ctx->addr.addrlen);
|
||||
if(-1 == rc) {
|
||||
return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
|
||||
@@ -1867,8 +1841,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
|
||||
* non-blocking socket created by cf_socket_open() to it. Thus, we
|
||||
* do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
|
||||
*/
|
||||
#ifdef __linux__
|
||||
switch(ctx->addr.family) {
|
||||
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
|
||||
#ifdef IP_MTU_DISCOVER
|
||||
case AF_INET: {
|
||||
int val = IP_PMTUDISC_DO;
|
||||
(void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
|
||||
@@ -1876,7 +1851,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
|
||||
#ifdef IPV6_MTU_DISCOVER
|
||||
case AF_INET6: {
|
||||
int val = IPV6_PMTUDISC_DO;
|
||||
(void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
|
||||
@@ -1886,11 +1861,12 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(UDP_GRO) && \
|
||||
#if defined(UDP_GRO) && \
|
||||
(defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) && \
|
||||
((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
|
||||
(void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
|
||||
(socklen_t)sizeof(one));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return CURLE_OK;
|
||||
@@ -1898,12 +1874,11 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
|
||||
|
||||
static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_COULDNT_CONNECT;
|
||||
|
||||
(void)blocking;
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
@@ -2057,7 +2032,7 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
|
||||
timeout_ms = data->set.accepttimeout;
|
||||
#endif
|
||||
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
/* check if the generic timeout possibly is set shorter */
|
||||
other = Curl_timeleft(data, &now, FALSE);
|
||||
if(other && (other < timeout_ms))
|
||||
@@ -2066,7 +2041,7 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
|
||||
timeout_ms = other;
|
||||
else {
|
||||
/* subtract elapsed time */
|
||||
timeout_ms -= Curl_timediff(now, ctx->started_at);
|
||||
timeout_ms -= curlx_timediff(now, ctx->started_at);
|
||||
if(!timeout_ms)
|
||||
/* avoid returning 0 as that means no timeout! */
|
||||
timeout_ms = -1;
|
||||
@@ -2108,7 +2083,7 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
|
||||
|
||||
static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
#ifdef USE_IPV6
|
||||
@@ -2124,7 +2099,6 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
|
||||
/* we start accepted, if we ever close, we cannot go on */
|
||||
(void)data;
|
||||
(void)blocking;
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
@@ -2163,7 +2137,12 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
|
||||
if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
|
||||
size = sizeof(add);
|
||||
#ifdef HAVE_ACCEPT4
|
||||
s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size,
|
||||
SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
#else
|
||||
s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(CURL_SOCKET_BAD == s_accepted) {
|
||||
@@ -2172,7 +2151,9 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
infof(data, "Connection accepted from server");
|
||||
#ifndef HAVE_ACCEPT4
|
||||
(void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
|
||||
#endif
|
||||
/* Replace any filter on SECONDARY with one listening on this socket */
|
||||
ctx->listening = FALSE;
|
||||
ctx->accepted = TRUE;
|
||||
@@ -2183,7 +2164,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
cf_tcp_set_accepted_remote_ip(cf, data);
|
||||
set_local_ip(cf, data);
|
||||
ctx->active = TRUE;
|
||||
ctx->connected_at = Curl_now();
|
||||
ctx->connected_at = curlx_now();
|
||||
cf->connected = TRUE;
|
||||
CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
|
||||
", remote=%s port=%d)",
|
||||
@@ -2201,6 +2182,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
|
||||
if(error)
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -2249,7 +2231,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
|
||||
ctx->started_at = Curl_now();
|
||||
ctx->started_at = curlx_now();
|
||||
conn->sock[sockindex] = ctx->sock;
|
||||
set_local_ip(cf, data);
|
||||
CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T
|
||||
|
||||
@@ -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;
|
||||
|
||||
104
lib/cfilters.c
104
lib/cfilters.c
@@ -28,13 +28,14 @@
|
||||
#include "strerror.h"
|
||||
#include "cfilters.h"
|
||||
#include "connect.h"
|
||||
#include "url.h" /* for Curl_safefree() */
|
||||
#include "url.h"
|
||||
#include "sendf.h"
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "multiif.h"
|
||||
#include "progress.h"
|
||||
#include "select.h"
|
||||
#include "warnless.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@@ -197,11 +198,11 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
|
||||
}
|
||||
|
||||
*done = FALSE;
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
if(!Curl_shutdown_started(data, sockindex)) {
|
||||
DEBUGF(infof(data, "shutdown start on%s connection",
|
||||
sockindex ? " secondary" : ""));
|
||||
Curl_shutdown_start(data, sockindex, &now);
|
||||
CURL_TRC_M(data, "shutdown start on%s connection",
|
||||
sockindex ? " secondary" : "");
|
||||
Curl_shutdown_start(data, sockindex, 0, &now);
|
||||
}
|
||||
else {
|
||||
timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
|
||||
@@ -367,10 +368,10 @@ bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
|
||||
|
||||
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
if(cf)
|
||||
return cf->cft->do_connect(cf, data, blocking, done);
|
||||
return cf->cft->do_connect(cf, data, done);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
@@ -404,6 +405,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
||||
bool blocking,
|
||||
bool *done)
|
||||
{
|
||||
#define CF_CONN_NUM_POLLS_ON_STACK 5
|
||||
struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
|
||||
struct curl_pollfds cpfds;
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -411,14 +415,17 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
||||
DEBUGASSERT(data->conn);
|
||||
|
||||
cf = data->conn->cfilter[sockindex];
|
||||
DEBUGASSERT(cf);
|
||||
if(!cf) {
|
||||
*done = FALSE;
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
*done = cf->connected;
|
||||
if(!*done) {
|
||||
if(*done)
|
||||
return CURLE_OK;
|
||||
|
||||
Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
|
||||
while(!*done) {
|
||||
if(Curl_conn_needs_flush(data, sockindex)) {
|
||||
DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
|
||||
result = Curl_conn_flush(data, sockindex);
|
||||
@@ -426,24 +433,75 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
||||
return result;
|
||||
}
|
||||
|
||||
result = cf->cft->do_connect(cf, data, blocking, done);
|
||||
result = cf->cft->do_connect(cf, data, done);
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
|
||||
blocking, result, *done);
|
||||
if(!result && *done) {
|
||||
/* Now that the complete filter chain is connected, let all filters
|
||||
* persist information at the connection. E.g. cf-socket sets the
|
||||
* socket and ip related information. */
|
||||
cf_cntrl_update_info(data, data->conn);
|
||||
conn_report_connect_stats(data, data->conn);
|
||||
data->conn->keepalive = Curl_now();
|
||||
data->conn->keepalive = curlx_now();
|
||||
Curl_verboseconnect(data, data->conn, sockindex);
|
||||
goto out;
|
||||
}
|
||||
else if(result) {
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
|
||||
result);
|
||||
conn_report_connect_stats(data, data->conn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!blocking)
|
||||
goto out;
|
||||
else {
|
||||
/* check allowed time left */
|
||||
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
struct easy_pollset ps;
|
||||
int rc;
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* no need to continue if time already is up */
|
||||
failf(data, "connect timeout");
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
|
||||
Curl_pollfds_reset(&cpfds);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
/* In general, we want to send after connect, wait on that. */
|
||||
if(sockfd != CURL_SOCKET_BAD)
|
||||
Curl_pollset_set_out_only(data, &ps, sockfd);
|
||||
Curl_conn_adjust_pollset(data, data->conn, &ps);
|
||||
result = Curl_pollfds_add_ps(&cpfds, &ps);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
rc = Curl_poll(cpfds.pfds, cpfds.n,
|
||||
CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
|
||||
rc);
|
||||
if(rc < 0) {
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
goto out;
|
||||
}
|
||||
/* continue iterating */
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
Curl_pollfds_cleanup(&cpfds);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
return (conn->cfilter[sockindex] != NULL);
|
||||
}
|
||||
|
||||
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
@@ -496,13 +554,14 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unsigned char Curl_conn_http_version(struct Curl_easy *data)
|
||||
unsigned char Curl_conn_http_version(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_UNKNOWN_OPTION;
|
||||
unsigned char v = 0;
|
||||
|
||||
cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
|
||||
cf = conn->cfilter[FIRSTSOCKET];
|
||||
for(; cf; cf = cf->next) {
|
||||
if(cf->cft->flags & CF_TYPE_HTTP) {
|
||||
int value = 0;
|
||||
@@ -571,14 +630,15 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
void Curl_conn_adjust_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
struct connectdata *conn,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->conn);
|
||||
DEBUGASSERT(conn);
|
||||
for(i = 0; i < 2; ++i) {
|
||||
Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
|
||||
Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,14 +940,14 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
|
||||
DEBUGASSERT(data->conn);
|
||||
conn = data->conn;
|
||||
#ifdef DEBUGBUILD
|
||||
{
|
||||
if(write_len) {
|
||||
/* Allow debug builds to override this logic to force short sends
|
||||
*/
|
||||
char *p = getenv("CURL_SMALLSENDS");
|
||||
const char *p = getenv("CURL_SMALLSENDS");
|
||||
if(p) {
|
||||
size_t altsize = (size_t)strtoul(p, NULL, 10);
|
||||
if(altsize)
|
||||
write_len = CURLMIN(write_len, altsize);
|
||||
curl_off_t altsize;
|
||||
if(!curlx_str_number(&p, &altsize, write_len))
|
||||
write_len = (size_t)altsize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -24,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) \
|
||||
|
||||
1077
lib/conncache.c
1077
lib/conncache.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
146
lib/connect.c
146
lib/connect.c
@@ -67,14 +67,14 @@
|
||||
#include "multiif.h"
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "inet_ntop.h"
|
||||
#include "inet_pton.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "vtls/vtls.h" /* for vtsl cfilters */
|
||||
#include "progress.h"
|
||||
#include "warnless.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multihandle.h"
|
||||
#include "share.h"
|
||||
#include "version_win32.h"
|
||||
#include "curlx/version_win32.h"
|
||||
#include "vquic/vquic.h" /* for quic cfilters */
|
||||
#include "http_proxy.h"
|
||||
#include "socks.h"
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
|
||||
|
||||
enum alpnid Curl_alpn2alpnid(char *name, size_t len)
|
||||
enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
|
||||
{
|
||||
if(len == 2) {
|
||||
if(strncasecompare(name, "h1", 2))
|
||||
@@ -112,7 +112,7 @@ enum alpnid Curl_alpn2alpnid(char *name, size_t len)
|
||||
* infinite time left). If the value is negative, the timeout time has already
|
||||
* elapsed.
|
||||
* @param data the transfer to check on
|
||||
* @param nowp timestamp to use for calculation, NULL to use Curl_now()
|
||||
* @param nowp timestamp to use for calculation, NULL to use curlx_now()
|
||||
* @param duringconnect TRUE iff connect timeout is also taken into account.
|
||||
* @unittest: 1303
|
||||
*/
|
||||
@@ -133,13 +133,13 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
return 0; /* no timeout in place or checked, return "no limit" */
|
||||
|
||||
if(!nowp) {
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
|
||||
if(data->set.timeout > 0) {
|
||||
timeleft_ms = data->set.timeout -
|
||||
Curl_timediff(*nowp, data->progress.t_startop);
|
||||
curlx_timediff(*nowp, data->progress.t_startop);
|
||||
if(!timeleft_ms)
|
||||
timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
|
||||
if(!duringconnect)
|
||||
@@ -150,7 +150,7 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
|
||||
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
|
||||
ctimeleft_ms = ctimeout_ms -
|
||||
Curl_timediff(*nowp, data->progress.t_startsingle);
|
||||
curlx_timediff(*nowp, data->progress.t_startsingle);
|
||||
if(!ctimeleft_ms)
|
||||
ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
|
||||
if(!timeleft_ms)
|
||||
@@ -161,18 +161,24 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
|
||||
struct curltime *nowp)
|
||||
int timeout_ms, struct curltime *nowp)
|
||||
{
|
||||
struct curltime now;
|
||||
|
||||
DEBUGASSERT(data->conn);
|
||||
if(!nowp) {
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
data->conn->shutdown.start[sockindex] = *nowp;
|
||||
data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
|
||||
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
||||
data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
|
||||
(unsigned int)timeout_ms :
|
||||
((data->set.shutdowntimeout > 0) ?
|
||||
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
||||
/* Set a timer, unless we operate on the admin handle */
|
||||
if(data->mid && data->conn->shutdown.timeout_ms)
|
||||
Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
|
||||
EXPIRE_SHUTDOWN);
|
||||
}
|
||||
|
||||
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
|
||||
@@ -185,11 +191,11 @@ timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
|
||||
return 0; /* not started or no limits */
|
||||
|
||||
if(!nowp) {
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
left_ms = conn->shutdown.timeout_ms -
|
||||
Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
|
||||
curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
|
||||
return left_ms ? left_ms : -1;
|
||||
}
|
||||
|
||||
@@ -204,7 +210,7 @@ timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
|
||||
if(!conn->shutdown.start[i].tv_sec)
|
||||
continue;
|
||||
if(!nowp) {
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
ms = Curl_shutdown_timeleft(conn, i, nowp);
|
||||
@@ -266,8 +272,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
switch(sa->sa_family) {
|
||||
case AF_INET:
|
||||
si = (struct sockaddr_in *)(void *) sa;
|
||||
if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
|
||||
addr, MAX_IPADR_LEN)) {
|
||||
if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
|
||||
unsigned short us_port = ntohs(si->sin_port);
|
||||
*port = us_port;
|
||||
return TRUE;
|
||||
@@ -276,8 +281,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
#ifdef USE_IPV6
|
||||
case AF_INET6:
|
||||
si6 = (struct sockaddr_in6 *)(void *) sa;
|
||||
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
|
||||
addr, MAX_IPADR_LEN)) {
|
||||
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
|
||||
unsigned short us_port = ntohs(si6->sin6_port);
|
||||
*port = us_port;
|
||||
return TRUE;
|
||||
@@ -301,7 +305,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
|
||||
addr[0] = '\0';
|
||||
*port = 0;
|
||||
errno = EAFNOSUPPORT;
|
||||
CURL_SETERRNO(SOCKEAFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -404,7 +408,6 @@ typedef enum {
|
||||
struct cf_he_ctx {
|
||||
int transport;
|
||||
cf_ip_connect_create *cf_create;
|
||||
const struct Curl_dns_entry *remotehost;
|
||||
cf_connect_state state;
|
||||
struct eyeballer *baller[2];
|
||||
struct eyeballer *winner;
|
||||
@@ -541,7 +544,7 @@ static CURLcode baller_start(struct Curl_cfilter *cf,
|
||||
baller->has_started = TRUE;
|
||||
|
||||
while(baller->addr) {
|
||||
baller->started = Curl_now();
|
||||
baller->started = curlx_now();
|
||||
baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ?
|
||||
USETIME(timeoutms) : timeoutms;
|
||||
baller_initiate(cf, data, baller);
|
||||
@@ -593,18 +596,18 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
|
||||
*connected = baller->connected;
|
||||
if(!baller->result && !*connected) {
|
||||
/* evaluate again */
|
||||
baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected);
|
||||
baller->result = Curl_conn_cf_connect(baller->cf, data, connected);
|
||||
|
||||
if(!baller->result) {
|
||||
if(*connected) {
|
||||
baller->connected = TRUE;
|
||||
baller->is_done = TRUE;
|
||||
}
|
||||
else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
|
||||
else if(curlx_timediff(*now, baller->started) >= baller->timeoutms) {
|
||||
infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
|
||||
"ms, move on!", baller->name, baller->timeoutms);
|
||||
#if defined(ETIMEDOUT)
|
||||
baller->error = ETIMEDOUT;
|
||||
#ifdef SOCKETIMEDOUT
|
||||
baller->error = SOCKETIMEDOUT;
|
||||
#endif
|
||||
baller->result = CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
@@ -638,7 +641,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
|
||||
* cot ballers in a QUIC appropriate way. */
|
||||
evaluate:
|
||||
*connected = FALSE; /* a negative world view is best */
|
||||
now = Curl_now();
|
||||
now = curlx_now();
|
||||
ongoing = not_started = 0;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) {
|
||||
struct eyeballer *baller = ctx->baller[i];
|
||||
@@ -693,7 +696,7 @@ evaluate:
|
||||
* start new ballers or return ok. */
|
||||
if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
|
||||
failf(data, "Connection timeout after %" FMT_OFF_T " ms",
|
||||
Curl_timediff(now, data->progress.t_startsingle));
|
||||
curlx_timediff(now, data->progress.t_startsingle));
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -709,7 +712,7 @@ evaluate:
|
||||
/* We start its primary baller has failed to connect or if
|
||||
* its start delay_ms have expired */
|
||||
if((baller->primary && baller->primary->is_done) ||
|
||||
Curl_timediff(now, ctx->started) >= baller->delay_ms) {
|
||||
curlx_timediff(now, ctx->started) >= baller->delay_ms) {
|
||||
baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE));
|
||||
if(baller->is_done) {
|
||||
CURL_TRC_CF(data, cf, "%s done", baller->name);
|
||||
@@ -762,14 +765,11 @@ evaluate:
|
||||
failf(data, "Failed to connect to %s port %u after "
|
||||
"%" FMT_TIMEDIFF_T " ms: %s",
|
||||
hostname, conn->primary.remote_port,
|
||||
Curl_timediff(now, data->progress.t_startsingle),
|
||||
curlx_timediff(now, data->progress.t_startsingle),
|
||||
curl_easy_strerror(result));
|
||||
|
||||
#ifdef WSAETIMEDOUT
|
||||
if(WSAETIMEDOUT == data->state.os_errno)
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
#elif defined(ETIMEDOUT)
|
||||
if(ETIMEDOUT == data->state.os_errno)
|
||||
#ifdef SOCKETIMEDOUT
|
||||
if(SOCKETIMEDOUT == data->state.os_errno)
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
#endif
|
||||
|
||||
@@ -781,8 +781,7 @@ evaluate:
|
||||
* There might be more than one IP address to try out.
|
||||
*/
|
||||
static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_dns_entry *remotehost)
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_he_ctx *ctx = cf->ctx;
|
||||
struct connectdata *conn = cf->conn;
|
||||
@@ -790,6 +789,10 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
int ai_family0 = 0, ai_family1 = 0;
|
||||
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
||||
const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
|
||||
struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
|
||||
|
||||
if(!dns)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
@@ -797,9 +800,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
ctx->started = Curl_now();
|
||||
ctx->started = curlx_now();
|
||||
|
||||
/* remotehost->addr is the list of addresses from the resolver, each
|
||||
/* dns->addr is the list of addresses from the resolver, each
|
||||
* with an address family. The list has at least one entry, possibly
|
||||
* many more.
|
||||
* We try at most 2 at a time, until we either get a connection or
|
||||
@@ -811,27 +814,27 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
if(conn->ip_version == CURL_IPRESOLVE_V6) {
|
||||
#ifdef USE_IPV6
|
||||
ai_family0 = AF_INET6;
|
||||
addr0 = addr_first_match(remotehost->addr, ai_family0);
|
||||
addr0 = addr_first_match(dns->addr, ai_family0);
|
||||
#endif
|
||||
}
|
||||
else if(conn->ip_version == CURL_IPRESOLVE_V4) {
|
||||
ai_family0 = AF_INET;
|
||||
addr0 = addr_first_match(remotehost->addr, ai_family0);
|
||||
addr0 = addr_first_match(dns->addr, ai_family0);
|
||||
}
|
||||
else {
|
||||
/* no user preference, we try ipv6 always first when available */
|
||||
#ifdef USE_IPV6
|
||||
ai_family0 = AF_INET6;
|
||||
addr0 = addr_first_match(remotehost->addr, ai_family0);
|
||||
addr0 = addr_first_match(dns->addr, ai_family0);
|
||||
#endif
|
||||
/* next candidate is ipv4 */
|
||||
ai_family1 = AF_INET;
|
||||
addr1 = addr_first_match(remotehost->addr, ai_family1);
|
||||
addr1 = addr_first_match(dns->addr, ai_family1);
|
||||
/* no ip address families, probably AF_UNIX or something, use the
|
||||
* address family given to us */
|
||||
if(!addr1 && !addr0 && remotehost->addr) {
|
||||
ai_family0 = remotehost->addr->ai_family;
|
||||
addr0 = addr_first_match(remotehost->addr, ai_family0);
|
||||
if(!addr1 && !addr0 && dns->addr) {
|
||||
ai_family0 = dns->addr->ai_family;
|
||||
addr0 = addr_first_match(dns->addr, ai_family0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,7 +951,7 @@ static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
|
||||
|
||||
static CURLcode cf_he_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
struct cf_he_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -958,7 +961,6 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
(void)blocking;
|
||||
DEBUGASSERT(ctx);
|
||||
*done = FALSE;
|
||||
|
||||
@@ -966,7 +968,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
|
||||
case SCFST_INIT:
|
||||
DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
|
||||
DEBUGASSERT(!cf->connected);
|
||||
result = start_connect(cf, data, ctx->remotehost);
|
||||
result = start_connect(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = SCFST_WAITING;
|
||||
@@ -1058,7 +1060,7 @@ static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
|
||||
memset(&t, 0, sizeof(t));
|
||||
if(baller && baller->cf &&
|
||||
!baller->cf->cft->query(baller->cf, data, query, NULL, &t)) {
|
||||
if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
|
||||
if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0)
|
||||
tmax = t;
|
||||
}
|
||||
}
|
||||
@@ -1158,7 +1160,6 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
cf_ip_connect_create *cf_create,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
int transport)
|
||||
{
|
||||
struct cf_he_ctx *ctx = NULL;
|
||||
@@ -1174,14 +1175,13 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
|
||||
}
|
||||
ctx->transport = transport;
|
||||
ctx->cf_create = cf_create;
|
||||
ctx->remotehost = remotehost;
|
||||
|
||||
result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx);
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
Curl_safefree(*pcf);
|
||||
Curl_safefree(ctx);
|
||||
free(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1220,7 +1220,6 @@ static cf_ip_connect_create *get_cf_create(int transport)
|
||||
|
||||
static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
int transport)
|
||||
{
|
||||
cf_ip_connect_create *cf_create;
|
||||
@@ -1235,8 +1234,7 @@ static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
|
||||
cf_create, remotehost,
|
||||
transport);
|
||||
cf_create, transport);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@@ -1256,17 +1254,17 @@ typedef enum {
|
||||
|
||||
struct cf_setup_ctx {
|
||||
cf_setup_state state;
|
||||
const struct Curl_dns_entry *remotehost;
|
||||
int ssl_mode;
|
||||
int transport;
|
||||
};
|
||||
|
||||
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool blocking, bool *done)
|
||||
bool *done)
|
||||
{
|
||||
struct cf_setup_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
@@ -1275,14 +1273,17 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
||||
|
||||
/* connect current sub-chain */
|
||||
connect_sub_chain:
|
||||
if(!dns)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(cf->next && !cf->next->connected) {
|
||||
result = Curl_conn_cf_connect(cf->next, data, blocking, done);
|
||||
result = Curl_conn_cf_connect(cf->next, data, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
|
||||
result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport);
|
||||
result = cf_he_insert_after(cf, data, ctx->transport);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
|
||||
@@ -1410,7 +1411,6 @@ struct Curl_cftype Curl_cft_setup = {
|
||||
|
||||
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
@@ -1425,7 +1425,6 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
|
||||
goto out;
|
||||
}
|
||||
ctx->state = CF_SETUP_INIT;
|
||||
ctx->remotehost = remotehost;
|
||||
ctx->ssl_mode = ssl_mode;
|
||||
ctx->transport = transport;
|
||||
|
||||
@@ -1436,14 +1435,15 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
|
||||
|
||||
out:
|
||||
*pcf = result ? NULL : cf;
|
||||
free(ctx);
|
||||
if(ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_setup_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
@@ -1451,7 +1451,7 @@ static CURLcode cf_setup_add(struct Curl_easy *data,
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
|
||||
result = cf_setup_create(&cf, data, transport, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
@@ -1476,7 +1476,6 @@ void Curl_debug_set_transport_provider(int transport,
|
||||
|
||||
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
@@ -1484,7 +1483,7 @@ CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
|
||||
result = cf_setup_create(&cf, data, transport, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
@@ -1495,19 +1494,23 @@ out:
|
||||
CURLcode Curl_conn_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
const struct Curl_dns_entry *remotehost,
|
||||
struct Curl_dns_entry *dns,
|
||||
int ssl_mode)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(conn->handler);
|
||||
DEBUGASSERT(dns);
|
||||
|
||||
Curl_resolv_unlink(data, &data->state.dns[sockindex]);
|
||||
data->state.dns[sockindex] = dns;
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP)
|
||||
if(!conn->cfilter[sockindex] &&
|
||||
conn->handler->protocol == CURLPROTO_HTTPS) {
|
||||
DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
|
||||
result = Curl_cf_https_setup(data, conn, sockindex, remotehost);
|
||||
result = Curl_cf_https_setup(data, conn, sockindex);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
@@ -1515,13 +1518,14 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
||||
|
||||
/* Still no cfilter set, apply default. */
|
||||
if(!conn->cfilter[sockindex]) {
|
||||
result = cf_setup_add(data, conn, sockindex, remotehost,
|
||||
conn->transport, ssl_mode);
|
||||
result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(conn->cfilter[sockindex]);
|
||||
out:
|
||||
if(result)
|
||||
Curl_resolv_unlink(data, &data->state.dns[sockindex]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
283
lib/cookie.c
283
lib/cookie.c
@@ -76,11 +76,9 @@ Example set of cookies:
|
||||
#include "urldata.h"
|
||||
#include "cookie.h"
|
||||
#include "psl.h"
|
||||
#include "strtok.h"
|
||||
#include "sendf.h"
|
||||
#include "slist.h"
|
||||
#include "share.h"
|
||||
#include "strtoofft.h"
|
||||
#include "strcase.h"
|
||||
#include "curl_get_line.h"
|
||||
#include "curl_memrchr.h"
|
||||
@@ -89,6 +87,7 @@ Example set of cookies:
|
||||
#include "fopen.h"
|
||||
#include "strdup.h"
|
||||
#include "llist.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@@ -160,12 +159,10 @@ static bool cookie_tailmatch(const char *cookie_domain,
|
||||
* matching cookie path and URL path
|
||||
* RFC6265 5.1.4 Paths and Path-Match
|
||||
*/
|
||||
static bool pathmatch(const char *cookie_path, const char *request_uri)
|
||||
static bool pathmatch(const char *cookie_path, const char *uri_path)
|
||||
{
|
||||
size_t cookie_path_len;
|
||||
size_t uri_path_len;
|
||||
char *uri_path = NULL;
|
||||
char *pos;
|
||||
bool ret = FALSE;
|
||||
|
||||
/* cookie_path must not have last '/' separator. ex: /sample */
|
||||
@@ -175,19 +172,9 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uri_path = strdup(request_uri);
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
pos = strchr(uri_path, '?');
|
||||
if(pos)
|
||||
*pos = 0x0;
|
||||
|
||||
/* #-fragments are already cut off! */
|
||||
if(0 == strlen(uri_path) || uri_path[0] != '/') {
|
||||
strstore(&uri_path, "/", 1);
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
}
|
||||
if(0 == strlen(uri_path) || uri_path[0] != '/')
|
||||
uri_path = "/";
|
||||
|
||||
/*
|
||||
* here, RFC6265 5.1.4 says
|
||||
@@ -201,16 +188,12 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
|
||||
|
||||
uri_path_len = strlen(uri_path);
|
||||
|
||||
if(uri_path_len < cookie_path_len) {
|
||||
ret = FALSE;
|
||||
if(uri_path_len < cookie_path_len)
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* not using checkprefix() because matching should be case-sensitive */
|
||||
if(strncmp(cookie_path, uri_path, cookie_path_len)) {
|
||||
ret = FALSE;
|
||||
if(strncmp(cookie_path, uri_path, cookie_path_len))
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* The cookie-path and the uri-path are identical. */
|
||||
if(cookie_path_len == uri_path_len) {
|
||||
@@ -224,10 +207,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
pathmatched:
|
||||
free(uri_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -301,34 +281,27 @@ static size_t cookiehash(const char * const domain)
|
||||
*/
|
||||
static char *sanitize_cookie_path(const char *cookie_path)
|
||||
{
|
||||
size_t len;
|
||||
char *new_path = strdup(cookie_path);
|
||||
if(!new_path)
|
||||
return NULL;
|
||||
size_t len = strlen(cookie_path);
|
||||
|
||||
/* some stupid site sends path attribute with '"'. */
|
||||
len = strlen(new_path);
|
||||
if(new_path[0] == '\"') {
|
||||
memmove(new_path, new_path + 1, len);
|
||||
/* some sites send path attribute within '"'. */
|
||||
if(cookie_path[0] == '\"') {
|
||||
cookie_path++;
|
||||
len--;
|
||||
}
|
||||
if(len && (new_path[len - 1] == '\"')) {
|
||||
new_path[--len] = 0x0;
|
||||
}
|
||||
if(len && (cookie_path[len - 1] == '\"'))
|
||||
len--;
|
||||
|
||||
/* RFC6265 5.2.4 The Path Attribute */
|
||||
if(new_path[0] != '/') {
|
||||
if(cookie_path[0] != '/')
|
||||
/* Let cookie-path be the default-path. */
|
||||
strstore(&new_path, "/", 1);
|
||||
return new_path;
|
||||
}
|
||||
return strdup("/");
|
||||
|
||||
/* remove trailing slash */
|
||||
/* convert /hoge/ to /hoge */
|
||||
if(len && new_path[len - 1] == '/') {
|
||||
new_path[len - 1] = 0x0;
|
||||
}
|
||||
if(len && cookie_path[len - 1] == '/')
|
||||
len--;
|
||||
|
||||
return new_path;
|
||||
return Curl_memdup0(cookie_path, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -370,9 +343,12 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
|
||||
*/
|
||||
static void strstore(char **str, const char *newstr, size_t len)
|
||||
{
|
||||
DEBUGASSERT(newstr);
|
||||
DEBUGASSERT(str);
|
||||
free(*str);
|
||||
if(!len) {
|
||||
len++;
|
||||
newstr = "";
|
||||
}
|
||||
*str = Curl_memdup0(newstr, len);
|
||||
}
|
||||
|
||||
@@ -458,18 +434,16 @@ static bool bad_domain(const char *domain, size_t len)
|
||||
fine. The prime reason for filtering out control bytes is that some HTTP
|
||||
servers return 400 for requests that contain such.
|
||||
*/
|
||||
static bool invalid_octets(const char *p)
|
||||
static bool invalid_octets(const char *ptr)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)ptr;
|
||||
/* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
|
||||
static const char badoctets[] = {
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x0a"
|
||||
"\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
|
||||
"\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
|
||||
};
|
||||
size_t len;
|
||||
/* scan for all the octets that are *not* in cookie-octet */
|
||||
len = strcspn(p, badoctets);
|
||||
return p[len] != '\0';
|
||||
while(*p) {
|
||||
if(((*p != 9) && (*p < 0x20)) || (*p == 0x7f))
|
||||
return TRUE;
|
||||
p++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define CERR_OK 0
|
||||
@@ -486,7 +460,9 @@ static bool invalid_octets(const char *p)
|
||||
#define CERR_COMMENT 11 /* a commented line */
|
||||
#define CERR_RANGE 12 /* expire range problem */
|
||||
#define CERR_FIELDS 13 /* incomplete netscape line */
|
||||
#ifdef USE_LIBPSL
|
||||
#define CERR_PSL 14 /* a public suffix */
|
||||
#endif
|
||||
#define CERR_LIVE_WINS 15
|
||||
|
||||
/* The maximum length we accept a date string for the 'expire' keyword. The
|
||||
@@ -517,51 +493,29 @@ parse_cookie_header(struct Curl_easy *data,
|
||||
|
||||
now = time(NULL);
|
||||
do {
|
||||
size_t vlen;
|
||||
size_t nlen;
|
||||
|
||||
while(*ptr && ISBLANK(*ptr))
|
||||
ptr++;
|
||||
struct Curl_str name;
|
||||
struct Curl_str val;
|
||||
|
||||
/* we have a <name>=<value> pair or a stand-alone word here */
|
||||
nlen = strcspn(ptr, ";\t\r\n=");
|
||||
if(nlen) {
|
||||
if(!curlx_str_cspn(&ptr, &name, ";\t\r\n=")) {
|
||||
bool done = FALSE;
|
||||
bool sep = FALSE;
|
||||
const char *namep = ptr;
|
||||
const char *valuep;
|
||||
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
581
lib/cshutdn.c
Normal 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
110
lib/cshutdn.h
Normal 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 */
|
||||
@@ -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 */
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
108
lib/curl_sasl.c
108
lib/curl_sasl.c
@@ -42,15 +42,14 @@
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
|
||||
#include "curl_base64.h"
|
||||
#include "curlx/base64.h"
|
||||
#include "curl_md5.h"
|
||||
#include "vauth/vauth.h"
|
||||
#include "cfilters.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "curl_hmac.h"
|
||||
#include "curl_sasl.h"
|
||||
#include "warnless.h"
|
||||
#include "strtok.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "sendf.h"
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@@ -284,7 +283,7 @@ static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
|
||||
if(!*serverdata || *serverdata == '=')
|
||||
Curl_bufref_set(out, NULL, 0, NULL);
|
||||
else {
|
||||
result = Curl_base64_decode(serverdata, &msg, &msglen);
|
||||
result = curlx_base64_decode(serverdata, &msg, &msglen);
|
||||
if(!result)
|
||||
Curl_bufref_set(out, msg, msglen, curl_free);
|
||||
}
|
||||
@@ -307,8 +306,8 @@ static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
|
||||
char *base64;
|
||||
size_t base64len;
|
||||
|
||||
result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
|
||||
Curl_bufref_len(msg), &base64, &base64len);
|
||||
result = curlx_base64_encode((const char *) Curl_bufref_ptr(msg),
|
||||
Curl_bufref_len(msg), &base64, &base64len);
|
||||
if(!result)
|
||||
Curl_bufref_set(msg, base64, base64len, curl_free);
|
||||
}
|
||||
@@ -757,4 +756,101 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
static void sasl_unchosen(struct Curl_easy *data, unsigned short mech,
|
||||
unsigned short enabledmechs,
|
||||
bool built_in, bool platform,
|
||||
const char *param_missing)
|
||||
{
|
||||
const char *mname = NULL;
|
||||
size_t i;
|
||||
|
||||
if(!(enabledmechs & mech))
|
||||
return;
|
||||
|
||||
for(i = 0; mechtable[i].name; ++i) {
|
||||
if(mechtable[i].bit == mech) {
|
||||
mname = mechtable[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!mname) /* should not happen */
|
||||
return;
|
||||
if(!built_in)
|
||||
infof(data, "SASL: %s not builtin", mname);
|
||||
else if(!platform)
|
||||
infof(data, "SASL: %s not supported by the platform/libraries", mname);
|
||||
else {
|
||||
if(param_missing)
|
||||
infof(data, "SASL: %s is missing %s", mname, param_missing);
|
||||
if(!data->state.aptr.user)
|
||||
infof(data, "SASL: %s is missing username", mname);
|
||||
}
|
||||
}
|
||||
#endif /* CURL_DISABLE_VERBOSE_STRINGS */
|
||||
|
||||
CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
|
||||
{
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
#ifdef USE_KERBEROS5
|
||||
#define CURL_SASL_KERBEROS5 TRUE
|
||||
#else
|
||||
#define CURL_SASL_KERBEROS5 FALSE
|
||||
#endif
|
||||
#ifdef USE_GSASL
|
||||
#define CURL_SASL_GASL TRUE
|
||||
#else
|
||||
#define CURL_SASL_GASL FALSE
|
||||
#endif
|
||||
#ifdef CURL_DISABLE_DIGEST_AUTH
|
||||
#define CURL_SASL_DIGEST TRUE
|
||||
#else
|
||||
#define CURL_SASL_DIGEST FALSE
|
||||
#endif
|
||||
#ifndef USE_NTLM
|
||||
#define CURL_SASL_NTLM TRUE
|
||||
#else
|
||||
#define CURL_SASL_NTLM FALSE
|
||||
#endif
|
||||
/* Failing SASL authentication is a pain. Give a helping hand if
|
||||
* we were unable to select an AUTH mechanism.
|
||||
* `sasl->authmechs` are mechanisms offered by the peer
|
||||
* `sasl->prefmech` are mechanisms preferred by us */
|
||||
unsigned short enabledmechs = sasl->authmechs & sasl->prefmech;
|
||||
|
||||
if(!sasl->authmechs)
|
||||
infof(data, "SASL: no auth mechanism was offered or recognized");
|
||||
else if(!enabledmechs)
|
||||
infof(data, "SASL: no overlap between offered and configured "
|
||||
"auth mechanisms");
|
||||
else {
|
||||
infof(data, "SASL: no auth mechanism offered could be selected");
|
||||
if((enabledmechs & SASL_MECH_EXTERNAL) && data->conn->passwd[0])
|
||||
infof(data, "SASL: auth EXTERNAL not chosen with password");
|
||||
sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs,
|
||||
CURL_SASL_KERBEROS5, Curl_auth_is_gssapi_supported(), NULL);
|
||||
sasl_unchosen(data, SASL_MECH_SCRAM_SHA_256, enabledmechs,
|
||||
CURL_SASL_GASL, FALSE, NULL);
|
||||
sasl_unchosen(data, SASL_MECH_SCRAM_SHA_1, enabledmechs,
|
||||
CURL_SASL_GASL, FALSE, NULL);
|
||||
sasl_unchosen(data, SASL_MECH_DIGEST_MD5, enabledmechs,
|
||||
CURL_SASL_DIGEST, Curl_auth_is_digest_supported(), NULL);
|
||||
sasl_unchosen(data, SASL_MECH_CRAM_MD5, enabledmechs,
|
||||
CURL_SASL_DIGEST, TRUE, NULL);
|
||||
sasl_unchosen(data, SASL_MECH_NTLM, enabledmechs,
|
||||
CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL);
|
||||
sasl_unchosen(data, SASL_MECH_OAUTHBEARER, enabledmechs, TRUE, TRUE,
|
||||
data->set.str[STRING_BEARER] ?
|
||||
NULL : "CURLOPT_XOAUTH2_BEARER");
|
||||
sasl_unchosen(data, SASL_MECH_XOAUTH2, enabledmechs, TRUE, TRUE,
|
||||
data->set.str[STRING_BEARER] ?
|
||||
NULL : "CURLOPT_XOAUTH2_BEARER");
|
||||
}
|
||||
#endif /* CURL_DISABLE_VERBOSE_STRINGS */
|
||||
(void)sasl;
|
||||
(void)data;
|
||||
return CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
#endif /* protocols are enabled that use SASL */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
105
lib/curl_setup.h
105
lib/curl_setup.h
@@ -28,9 +28,6 @@
|
||||
#define CURL_NO_OLDIES
|
||||
#endif
|
||||
|
||||
/* Tell "curl/curl.h" not to include "curl/mprintf.h" */
|
||||
#define CURL_SKIP_INCLUDE_MPRINTF
|
||||
|
||||
/* Set default _WIN32_WINNT */
|
||||
#ifdef __MINGW32__
|
||||
#include <_mingw.h>
|
||||
@@ -56,7 +53,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#include <TargetConditionals.h>
|
||||
/* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
|
||||
@@ -78,6 +75,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Visual Studio 2008 is the minimum Visual Studio version we support.
|
||||
Workarounds for older versions of Visual Studio have been removed. */
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1500)
|
||||
#error "Ancient versions of Visual Studio are no longer supported due to bugs."
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
|
||||
#pragma warning(disable:4127)
|
||||
@@ -114,6 +117,14 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Avoid bogus format check warnings with mingw32ce gcc 4.4.0 in
|
||||
C99 (-std=gnu99) mode */
|
||||
#if defined(__MINGW32CE__) && !defined(CURL_NO_FMT_CHECKS) && \
|
||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && \
|
||||
(defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4))
|
||||
#define CURL_NO_FMT_CHECKS
|
||||
#endif
|
||||
|
||||
/* Compatibility */
|
||||
#ifdef ENABLE_IPV6
|
||||
#define USE_IPV6 1
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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 ** *
|
||||
|
||||
@@ -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:
|
||||
*
|
||||
|
||||
247
lib/curl_sspi.h
247
lib/curl_sspi.h
@@ -45,7 +45,7 @@
|
||||
CURLcode Curl_sspi_global_init(void);
|
||||
void Curl_sspi_global_cleanup(void);
|
||||
|
||||
/* This is used to populate the domain in a SSPI identity structure */
|
||||
/* This is used to populate the domain in an SSPI identity structure */
|
||||
CURLcode Curl_override_sspi_http_realm(const char *chlg,
|
||||
SEC_WINNT_AUTH_IDENTITY *identity);
|
||||
|
||||
@@ -70,6 +70,225 @@ extern PSecurityFunctionTable Curl_pSecFn;
|
||||
#define ISC_REQ_USE_HTTP_STYLE 0x01000000
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32CE__
|
||||
#ifndef ISC_RET_REPLAY_DETECT
|
||||
#define ISC_RET_REPLAY_DETECT 0x00000004
|
||||
#endif
|
||||
#ifndef ISC_RET_SEQUENCE_DETECT
|
||||
#define ISC_RET_SEQUENCE_DETECT 0x00000008
|
||||
#endif
|
||||
#ifndef ISC_RET_CONFIDENTIALITY
|
||||
#define ISC_RET_CONFIDENTIALITY 0x00000010
|
||||
#endif
|
||||
#ifndef ISC_RET_ALLOCATED_MEMORY
|
||||
#define ISC_RET_ALLOCATED_MEMORY 0x00000100
|
||||
#endif
|
||||
#ifndef ISC_RET_STREAM
|
||||
#define ISC_RET_STREAM 0x00008000
|
||||
#endif
|
||||
|
||||
#ifndef SEC_E_INSUFFICIENT_MEMORY
|
||||
#define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L)
|
||||
#endif
|
||||
#ifndef SEC_E_INVALID_HANDLE
|
||||
#define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L)
|
||||
#endif
|
||||
#ifndef SEC_E_UNSUPPORTED_FUNCTION
|
||||
#define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L)
|
||||
#endif
|
||||
#ifndef SEC_E_TARGET_UNKNOWN
|
||||
#define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L)
|
||||
#endif
|
||||
#ifndef SEC_E_INTERNAL_ERROR
|
||||
#define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L)
|
||||
#endif
|
||||
#ifndef SEC_E_SECPKG_NOT_FOUND
|
||||
#define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L)
|
||||
#endif
|
||||
#ifndef SEC_E_NOT_OWNER
|
||||
#define SEC_E_NOT_OWNER ((HRESULT)0x80090306L)
|
||||
#endif
|
||||
#ifndef SEC_E_CANNOT_INSTALL
|
||||
#define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L)
|
||||
#endif
|
||||
#ifndef SEC_E_INVALID_TOKEN
|
||||
#define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L)
|
||||
#endif
|
||||
#ifndef SEC_E_CANNOT_PACK
|
||||
#define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L)
|
||||
#endif
|
||||
#ifndef SEC_E_QOP_NOT_SUPPORTED
|
||||
#define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_IMPERSONATION
|
||||
#define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL)
|
||||
#endif
|
||||
#ifndef SEC_E_LOGON_DENIED
|
||||
#define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL)
|
||||
#endif
|
||||
#ifndef SEC_E_UNKNOWN_CREDENTIALS
|
||||
#define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_CREDENTIALS
|
||||
#define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL)
|
||||
#endif
|
||||
#ifndef SEC_E_MESSAGE_ALTERED
|
||||
#define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL)
|
||||
#endif
|
||||
#ifndef SEC_E_OUT_OF_SEQUENCE
|
||||
#define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY
|
||||
#define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L)
|
||||
#endif
|
||||
#ifndef SEC_E_BAD_PKGID
|
||||
#define SEC_E_BAD_PKGID ((HRESULT)0x80090316L)
|
||||
#endif
|
||||
#ifndef SEC_E_CONTEXT_EXPIRED
|
||||
#define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L)
|
||||
#endif
|
||||
#ifndef SEC_E_INCOMPLETE_MESSAGE
|
||||
#define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L)
|
||||
#endif
|
||||
#ifndef SEC_E_INCOMPLETE_CREDENTIALS
|
||||
#define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L)
|
||||
#endif
|
||||
#ifndef SEC_E_BUFFER_TOO_SMALL
|
||||
#define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L)
|
||||
#endif
|
||||
#ifndef SEC_E_WRONG_PRINCIPAL
|
||||
#define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L)
|
||||
#endif
|
||||
#ifndef SEC_E_TIME_SKEW
|
||||
#define SEC_E_TIME_SKEW ((HRESULT)0x80090324L)
|
||||
#endif
|
||||
#ifndef SEC_E_UNTRUSTED_ROOT
|
||||
#define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L)
|
||||
#endif
|
||||
#ifndef SEC_E_ILLEGAL_MESSAGE
|
||||
#define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L)
|
||||
#endif
|
||||
#ifndef SEC_E_CERT_UNKNOWN
|
||||
#define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L)
|
||||
#endif
|
||||
#ifndef SEC_E_CERT_EXPIRED
|
||||
#define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L)
|
||||
#endif
|
||||
#ifndef SEC_E_ENCRYPT_FAILURE
|
||||
#define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L)
|
||||
#endif
|
||||
#ifndef SEC_E_DECRYPT_FAILURE
|
||||
#define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L)
|
||||
#endif
|
||||
#ifndef SEC_E_ALGORITHM_MISMATCH
|
||||
#define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L)
|
||||
#endif
|
||||
#ifndef SEC_E_SECURITY_QOS_FAILED
|
||||
#define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L)
|
||||
#endif
|
||||
#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED
|
||||
#define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_TGT_REPLY
|
||||
#define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_IP_ADDRESSES
|
||||
#define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L)
|
||||
#endif
|
||||
#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE
|
||||
#define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L)
|
||||
#endif
|
||||
#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
|
||||
#define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L)
|
||||
#endif
|
||||
#ifndef SEC_E_MAX_REFERRALS_EXCEEDED
|
||||
#define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L)
|
||||
#endif
|
||||
#ifndef SEC_E_MUST_BE_KDC
|
||||
#define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L)
|
||||
#endif
|
||||
#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
|
||||
#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL)
|
||||
#endif
|
||||
#ifndef SEC_E_TOO_MANY_PRINCIPALS
|
||||
#define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_PA_DATA
|
||||
#define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL)
|
||||
#endif
|
||||
#ifndef SEC_E_PKINIT_NAME_MISMATCH
|
||||
#define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL)
|
||||
#endif
|
||||
#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED
|
||||
#define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL)
|
||||
#endif
|
||||
#ifndef SEC_E_SHUTDOWN_IN_PROGRESS
|
||||
#define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL)
|
||||
#endif
|
||||
#ifndef SEC_E_KDC_INVALID_REQUEST
|
||||
#define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L)
|
||||
#endif
|
||||
#ifndef SEC_E_KDC_UNABLE_TO_REFER
|
||||
#define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L)
|
||||
#endif
|
||||
#ifndef SEC_E_KDC_UNKNOWN_ETYPE
|
||||
#define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L)
|
||||
#endif
|
||||
#ifndef SEC_E_UNSUPPORTED_PREAUTH
|
||||
#define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L)
|
||||
#endif
|
||||
#ifndef SEC_E_DELEGATION_REQUIRED
|
||||
#define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L)
|
||||
#endif
|
||||
#ifndef SEC_E_BAD_BINDINGS
|
||||
#define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L)
|
||||
#endif
|
||||
#ifndef SEC_E_MULTIPLE_ACCOUNTS
|
||||
#define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_KERB_KEY
|
||||
#define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L)
|
||||
#endif
|
||||
#ifndef SEC_E_CERT_WRONG_USAGE
|
||||
#define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L)
|
||||
#endif
|
||||
#ifndef SEC_E_DOWNGRADE_DETECTED
|
||||
#define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L)
|
||||
#endif
|
||||
#ifndef SEC_E_SMARTCARD_CERT_REVOKED
|
||||
#define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L)
|
||||
#endif
|
||||
#ifndef SEC_E_ISSUING_CA_UNTRUSTED
|
||||
#define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L)
|
||||
#endif
|
||||
#ifndef SEC_E_REVOCATION_OFFLINE_C
|
||||
#define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L)
|
||||
#endif
|
||||
#ifndef SEC_E_PKINIT_CLIENT_FAILURE
|
||||
#define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L)
|
||||
#endif
|
||||
#ifndef SEC_E_SMARTCARD_CERT_EXPIRED
|
||||
#define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L)
|
||||
#endif
|
||||
#ifndef SEC_E_NO_S4U_PROT_SUPPORT
|
||||
#define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L)
|
||||
#endif
|
||||
#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE
|
||||
#define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L)
|
||||
#endif
|
||||
#ifndef SEC_E_REVOCATION_OFFLINE_KDC
|
||||
#define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L)
|
||||
#endif
|
||||
#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC
|
||||
#define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L)
|
||||
#endif
|
||||
#ifndef SEC_E_KDC_CERT_EXPIRED
|
||||
#define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL)
|
||||
#endif
|
||||
#ifndef SEC_E_KDC_CERT_REVOKED
|
||||
#define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL)
|
||||
#endif
|
||||
#endif /* __MINGW32CE__ */
|
||||
#ifndef SEC_E_INVALID_PARAMETER
|
||||
# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
|
||||
#endif
|
||||
@@ -80,6 +299,32 @@ extern PSecurityFunctionTable Curl_pSecFn;
|
||||
# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL)
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32CE__
|
||||
#ifndef SEC_I_CONTINUE_NEEDED
|
||||
#define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L)
|
||||
#endif
|
||||
#ifndef SEC_I_COMPLETE_NEEDED
|
||||
#define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L)
|
||||
#endif
|
||||
#ifndef SEC_I_COMPLETE_AND_CONTINUE
|
||||
#define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L)
|
||||
#endif
|
||||
#ifndef SEC_I_LOCAL_LOGON
|
||||
#define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L)
|
||||
#endif
|
||||
#ifndef SEC_I_CONTEXT_EXPIRED
|
||||
#define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L)
|
||||
#endif
|
||||
#ifndef SEC_I_INCOMPLETE_CREDENTIALS
|
||||
#define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L)
|
||||
#endif
|
||||
#ifndef SEC_I_RENEGOTIATE
|
||||
#define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L)
|
||||
#endif
|
||||
#ifndef SEC_I_NO_LSA_CONTEXT
|
||||
#define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L)
|
||||
#endif
|
||||
#endif /* __MINGW32CE__ */
|
||||
#ifndef SEC_I_SIGNATURE_NEEDED
|
||||
#define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
326
lib/curl_trc.c
326
lib/curl_trc.c
@@ -30,7 +30,6 @@
|
||||
#include "urldata.h"
|
||||
#include "easyif.h"
|
||||
#include "cfilters.h"
|
||||
#include "timeval.h"
|
||||
#include "multiif.h"
|
||||
#include "strcase.h"
|
||||
|
||||
@@ -44,7 +43,7 @@
|
||||
#include "cf-haproxy.h"
|
||||
#include "cf-https-connect.h"
|
||||
#include "socks.h"
|
||||
#include "strtok.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "vquic/vquic.h"
|
||||
|
||||
@@ -53,19 +52,20 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
void Curl_debug(struct Curl_easy *data, curl_infotype type,
|
||||
char *ptr, size_t size)
|
||||
static void trc_write(struct Curl_easy *data, curl_infotype type,
|
||||
const char *ptr, size_t size)
|
||||
{
|
||||
if(data->set.verbose) {
|
||||
static const char s_infotype[CURLINFO_END][3] = {
|
||||
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
|
||||
if(data->set.fdebug) {
|
||||
bool inCallback = Curl_is_in_callback(data);
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
(void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
|
||||
(void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
|
||||
data->set.debugdata);
|
||||
Curl_set_in_callback(data, inCallback);
|
||||
}
|
||||
else {
|
||||
static const char s_infotype[CURLINFO_END][3] = {
|
||||
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
case CURLINFO_HEADER_OUT:
|
||||
@@ -80,6 +80,101 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
|
||||
}
|
||||
}
|
||||
|
||||
/* max length we trace before ending in '...' */
|
||||
#define TRC_LINE_MAX 2048
|
||||
|
||||
#define CURL_TRC_FMT_IDSC "[x-%" CURL_FORMAT_CURL_OFF_T "] "
|
||||
#define CURL_TRC_FMT_IDSD "[%" CURL_FORMAT_CURL_OFF_T "-x] "
|
||||
#define CURL_TRC_FMT_IDSDC "[%" CURL_FORMAT_CURL_OFF_T "-%" \
|
||||
CURL_FORMAT_CURL_OFF_T "] "
|
||||
|
||||
static struct curl_trc_feat Curl_trc_feat_ids = {
|
||||
"LIB-IDS",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
#define CURL_TRC_IDS(data) \
|
||||
(Curl_trc_is_verbose(data) && \
|
||||
Curl_trc_feat_ids.log_level >= CURL_LOG_LVL_INFO)
|
||||
|
||||
static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
|
||||
{
|
||||
curl_off_t cid = data->conn ?
|
||||
data->conn->connection_id : data->state.recent_conn_id;
|
||||
if(data->id >= 0) {
|
||||
if(cid >= 0)
|
||||
return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
|
||||
else
|
||||
return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
|
||||
}
|
||||
else if(cid >= 0)
|
||||
return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
|
||||
else {
|
||||
return msnprintf(buf, maxlen, "[x-x] ");
|
||||
}
|
||||
}
|
||||
|
||||
static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
|
||||
{
|
||||
/* make sure we end the trace line in `buf` properly. It needs
|
||||
* to end with a terminating '\0' or '\n\0' */
|
||||
if(len >= (maxlen - (addnl ? 2 : 1))) {
|
||||
len = maxlen - 5;
|
||||
buf[len++] = '.';
|
||||
buf[len++] = '.';
|
||||
buf[len++] = '.';
|
||||
buf[len++] = '\n';
|
||||
}
|
||||
else if(addnl)
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
void Curl_debug(struct Curl_easy *data, curl_infotype type,
|
||||
const char *ptr, size_t size)
|
||||
{
|
||||
if(data->set.verbose) {
|
||||
static const char s_infotype[CURLINFO_END][3] = {
|
||||
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
|
||||
char buf[TRC_LINE_MAX];
|
||||
size_t len;
|
||||
if(data->set.fdebug) {
|
||||
bool inCallback = Curl_is_in_callback(data);
|
||||
|
||||
if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
|
||||
len = trc_print_ids(data, buf, TRC_LINE_MAX);
|
||||
len += msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
|
||||
(int)size, ptr);
|
||||
len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
(void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
|
||||
Curl_set_in_callback(data, inCallback);
|
||||
}
|
||||
else {
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
(void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
|
||||
size, data->set.debugdata);
|
||||
Curl_set_in_callback(data, inCallback);
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
case CURLINFO_HEADER_OUT:
|
||||
case CURLINFO_HEADER_IN:
|
||||
if(CURL_TRC_IDS(data)) {
|
||||
len = trc_print_ids(data, buf, TRC_LINE_MAX);
|
||||
fwrite(buf, len, 1, data->set.err);
|
||||
}
|
||||
fwrite(s_infotype[type], 2, 1, data->set.err);
|
||||
fwrite(ptr, size, 1, data->set.err);
|
||||
break;
|
||||
default: /* nada */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Curl_failf() is for messages stating why we failed.
|
||||
* The message SHALL NOT include any LF or CR.
|
||||
@@ -89,7 +184,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(data->set.verbose || data->set.errorbuffer) {
|
||||
va_list ap;
|
||||
int len;
|
||||
size_t len;
|
||||
char error[CURL_ERROR_SIZE + 2];
|
||||
va_start(ap, fmt);
|
||||
len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
|
||||
@@ -100,36 +195,41 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
|
||||
}
|
||||
error[len++] = '\n';
|
||||
error[len] = '\0';
|
||||
Curl_debug(data, CURLINFO_TEXT, error, len);
|
||||
trc_write(data, CURLINFO_TEXT, error, len);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
|
||||
/* Curl_infof() is for info message along the way */
|
||||
#define MAXINFO 2048
|
||||
|
||||
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
|
||||
const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
|
||||
static void trc_infof(struct Curl_easy *data,
|
||||
struct curl_trc_feat *feat,
|
||||
const char *opt_id, int opt_id_idx,
|
||||
const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
|
||||
|
||||
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
|
||||
static void trc_infof(struct Curl_easy *data,
|
||||
struct curl_trc_feat *feat,
|
||||
const char *opt_id, int opt_id_idx,
|
||||
const char * const fmt, va_list ap)
|
||||
{
|
||||
int len = 0;
|
||||
char buffer[MAXINFO + 5];
|
||||
size_t len = 0;
|
||||
char buf[TRC_LINE_MAX];
|
||||
|
||||
if(CURL_TRC_IDS(data))
|
||||
len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
|
||||
if(feat)
|
||||
len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
|
||||
len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
|
||||
if(len >= MAXINFO) { /* too long, shorten with '...' */
|
||||
--len;
|
||||
buffer[len++] = '.';
|
||||
buffer[len++] = '.';
|
||||
buffer[len++] = '.';
|
||||
len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
|
||||
if(opt_id) {
|
||||
if(opt_id_idx > 0)
|
||||
len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
|
||||
opt_id, opt_id_idx);
|
||||
else
|
||||
len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
|
||||
}
|
||||
buffer[len++] = '\n';
|
||||
buffer[len] = '\0';
|
||||
Curl_debug(data, CURLINFO_TEXT, buffer, len);
|
||||
len += mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap);
|
||||
len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE);
|
||||
trc_write(data, CURLINFO_TEXT, buf, len);
|
||||
}
|
||||
|
||||
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
|
||||
@@ -138,36 +238,27 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_is_verbose(data)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, data->state.feat, fmt, ap);
|
||||
trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
|
||||
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(cf);
|
||||
if(Curl_trc_cf_is_verbose(cf, data)) {
|
||||
va_list ap;
|
||||
int len = 0;
|
||||
char buffer[MAXINFO + 2];
|
||||
if(data->state.feat)
|
||||
len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
|
||||
data->state.feat->name);
|
||||
if(cf->sockindex)
|
||||
len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
|
||||
cf->cft->name, cf->sockindex);
|
||||
else
|
||||
len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
|
||||
va_start(ap, fmt);
|
||||
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
|
||||
trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
|
||||
va_end(ap);
|
||||
buffer[len++] = '\n';
|
||||
buffer[len] = '\0';
|
||||
Curl_debug(data, CURLINFO_TEXT, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
struct curl_trc_feat Curl_trc_feat_multi = {
|
||||
"MULTI",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
struct curl_trc_feat Curl_trc_feat_read = {
|
||||
"READ",
|
||||
CURL_LOG_LVL_NONE,
|
||||
@@ -176,6 +267,52 @@ struct curl_trc_feat Curl_trc_feat_write = {
|
||||
"WRITE",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
struct curl_trc_feat Curl_trc_feat_dns = {
|
||||
"DNS",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
|
||||
static const char * const Curl_trc_mstate_names[]={
|
||||
"INIT",
|
||||
"PENDING",
|
||||
"SETUP",
|
||||
"CONNECT",
|
||||
"RESOLVING",
|
||||
"CONNECTING",
|
||||
"TUNNELING",
|
||||
"PROTOCONNECT",
|
||||
"PROTOCONNECTING",
|
||||
"DO",
|
||||
"DOING",
|
||||
"DOING_MORE",
|
||||
"DID",
|
||||
"PERFORMING",
|
||||
"RATELIMITING",
|
||||
"DONE",
|
||||
"COMPLETED",
|
||||
"MSGSENT",
|
||||
};
|
||||
|
||||
const char *Curl_trc_mstate_name(int state)
|
||||
{
|
||||
if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
|
||||
return Curl_trc_mstate_names[(size_t)state];
|
||||
return "?";
|
||||
}
|
||||
|
||||
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
|
||||
const char *sname = (data->id >= 0) ?
|
||||
Curl_trc_mstate_name(data->mstate) : NULL;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
@@ -183,7 +320,7 @@ void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_read, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +331,18 @@ void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_write, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -211,7 +359,7 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +377,7 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -247,7 +395,7 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -265,7 +413,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
|
||||
trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@@ -275,6 +423,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
|
||||
#define TRC_CT_PROTOCOL (1<<(0))
|
||||
#define TRC_CT_NETWORK (1<<(1))
|
||||
#define TRC_CT_PROXY (1<<(2))
|
||||
#define TRC_CT_INTERNALS (1<<(3))
|
||||
|
||||
struct trc_feat_def {
|
||||
struct curl_trc_feat *feat;
|
||||
@@ -282,13 +431,15 @@ struct trc_feat_def {
|
||||
};
|
||||
|
||||
static struct trc_feat_def trc_feats[] = {
|
||||
{ &Curl_trc_feat_ids, TRC_CT_INTERNALS },
|
||||
{ &Curl_trc_feat_multi, TRC_CT_NETWORK },
|
||||
{ &Curl_trc_feat_read, TRC_CT_NONE },
|
||||
{ &Curl_trc_feat_write, TRC_CT_NONE },
|
||||
{ &Curl_trc_feat_dns, TRC_CT_NETWORK },
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
{ &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
{ &Curl_doh_trc, TRC_CT_NETWORK },
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
{ &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
|
||||
@@ -341,18 +492,18 @@ static struct trc_cft_def trc_cfts[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void trc_apply_level_by_name(const char * const token, int lvl)
|
||||
static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
|
||||
if(strcasecompare(token, trc_cfts[i].cft->name)) {
|
||||
if(curlx_str_casecompare(token, trc_cfts[i].cft->name)) {
|
||||
trc_cfts[i].cft->log_level = lvl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
|
||||
if(strcasecompare(token, trc_feats[i].feat->name)) {
|
||||
if(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
|
||||
trc_feats[i].feat->log_level = lvl;
|
||||
break;
|
||||
}
|
||||
@@ -375,42 +526,36 @@ static void trc_apply_level_by_category(int category, int lvl)
|
||||
|
||||
static CURLcode trc_opt(const char *config)
|
||||
{
|
||||
char *token, *tok_buf, *tmp;
|
||||
int lvl;
|
||||
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;
|
||||
|
||||
@@ -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) */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
303
lib/curlx/strparse.c
Normal 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
112
lib/curlx/strparse.h
Normal 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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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))
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
@@ -24,9 +24,9 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
#include "../curl_setup.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
|
||||
/* Version condition */
|
||||
typedef enum {
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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
135
lib/curlx/winapi.c
Normal 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 */
|
||||
@@ -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 */
|
||||
108
lib/cw-out.c
108
lib/cw-out.c
@@ -32,6 +32,7 @@
|
||||
#include "multiif.h"
|
||||
#include "sendf.h"
|
||||
#include "cw-out.h"
|
||||
#include "cw-pause.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@@ -86,7 +87,7 @@ static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
|
||||
struct cw_out_buf *cwbuf = calloc(1, sizeof(*cwbuf));
|
||||
if(cwbuf) {
|
||||
cwbuf->type = otype;
|
||||
Curl_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
|
||||
curlx_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
|
||||
}
|
||||
return cwbuf;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
|
||||
static void cw_out_buf_free(struct cw_out_buf *cwbuf)
|
||||
{
|
||||
if(cwbuf) {
|
||||
Curl_dyn_free(&cwbuf->b);
|
||||
curlx_dyn_free(&cwbuf->b);
|
||||
free(cwbuf);
|
||||
}
|
||||
}
|
||||
@@ -113,7 +114,7 @@ static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer);
|
||||
static CURLcode cw_out_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer);
|
||||
|
||||
struct Curl_cwtype Curl_cwt_out = {
|
||||
const struct Curl_cwtype Curl_cwt_out = {
|
||||
"cw-out",
|
||||
NULL,
|
||||
cw_out_init,
|
||||
@@ -145,7 +146,7 @@ static size_t cw_out_bufs_len(struct cw_out_ctx *ctx)
|
||||
struct cw_out_buf *cwbuf = ctx->buf;
|
||||
size_t len = 0;
|
||||
while(cwbuf) {
|
||||
len += Curl_dyn_len(&cwbuf->b);
|
||||
len += curlx_dyn_len(&cwbuf->b);
|
||||
cwbuf = cwbuf->next;
|
||||
}
|
||||
return len;
|
||||
@@ -198,7 +199,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
||||
const char *buf, size_t blen,
|
||||
size_t *pconsumed)
|
||||
{
|
||||
curl_write_callback wcb;
|
||||
curl_write_callback wcb = NULL;
|
||||
void *wcb_data;
|
||||
size_t max_write, min_write;
|
||||
size_t wlen, nwritten;
|
||||
@@ -220,9 +221,9 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
||||
break;
|
||||
wlen = max_write ? CURLMIN(blen, max_write) : blen;
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
nwritten = wcb((char *)buf, 1, wlen, wcb_data);
|
||||
nwritten = wcb((char *)CURL_UNCONST(buf), 1, wlen, wcb_data);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
|
||||
CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
|
||||
wlen, (otype == CW_OUT_BODY) ? "body" : "header",
|
||||
nwritten);
|
||||
if(CURL_WRITEFUNC_PAUSE == nwritten) {
|
||||
@@ -236,7 +237,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
||||
/* mark the connection as RECV paused */
|
||||
data->req.keepon |= KEEP_RECV_PAUSE;
|
||||
ctx->paused = TRUE;
|
||||
CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
|
||||
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
|
||||
break;
|
||||
}
|
||||
else if(CURL_WRITEFUNC_ERROR == nwritten) {
|
||||
@@ -262,23 +263,24 @@ static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx,
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(Curl_dyn_len(&cwbuf->b)) {
|
||||
if(curlx_dyn_len(&cwbuf->b)) {
|
||||
size_t consumed;
|
||||
|
||||
result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all,
|
||||
Curl_dyn_ptr(&cwbuf->b),
|
||||
Curl_dyn_len(&cwbuf->b),
|
||||
curlx_dyn_ptr(&cwbuf->b),
|
||||
curlx_dyn_len(&cwbuf->b),
|
||||
&consumed);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(consumed) {
|
||||
if(consumed == Curl_dyn_len(&cwbuf->b)) {
|
||||
Curl_dyn_free(&cwbuf->b);
|
||||
if(consumed == curlx_dyn_len(&cwbuf->b)) {
|
||||
curlx_dyn_free(&cwbuf->b);
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(consumed < Curl_dyn_len(&cwbuf->b));
|
||||
result = Curl_dyn_tail(&cwbuf->b, Curl_dyn_len(&cwbuf->b) - consumed);
|
||||
DEBUGASSERT(consumed < curlx_dyn_len(&cwbuf->b));
|
||||
result = curlx_dyn_tail(&cwbuf->b,
|
||||
curlx_dyn_len(&cwbuf->b) - consumed);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
@@ -318,7 +320,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
|
||||
result = cw_out_buf_flush(ctx, data, cwbuf, flush_all);
|
||||
if(result)
|
||||
return result;
|
||||
if(!Curl_dyn_len(&cwbuf->b)) {
|
||||
if(!curlx_dyn_len(&cwbuf->b)) {
|
||||
cw_out_buf_free(cwbuf);
|
||||
*pcwbuf = NULL;
|
||||
}
|
||||
@@ -326,11 +328,16 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
|
||||
}
|
||||
|
||||
static CURLcode cw_out_append(struct cw_out_ctx *ctx,
|
||||
struct Curl_easy *data,
|
||||
cw_out_type otype,
|
||||
const char *buf, size_t blen)
|
||||
{
|
||||
if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER)
|
||||
CURL_TRC_WRITE(data, "[OUT] paused, buffering %zu more bytes (%zu/%d)",
|
||||
blen, cw_out_bufs_len(ctx), DYN_PAUSE_BUFFER);
|
||||
if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER) {
|
||||
failf(data, "pause buffer not large enough -> CURLE_TOO_LARGE");
|
||||
return CURLE_TOO_LARGE;
|
||||
}
|
||||
|
||||
/* if we do not have a buffer, or it is of another type, make a new one.
|
||||
* And for CW_OUT_HDS always make a new one, so we "replay" headers
|
||||
@@ -343,7 +350,7 @@ static CURLcode cw_out_append(struct cw_out_ctx *ctx,
|
||||
ctx->buf = cwbuf;
|
||||
}
|
||||
DEBUGASSERT(ctx->buf && (ctx->buf->type == otype));
|
||||
return Curl_dyn_addn(&ctx->buf->b, buf, blen);
|
||||
return curlx_dyn_addn(&ctx->buf->b, buf, blen);
|
||||
}
|
||||
|
||||
static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
|
||||
@@ -364,7 +371,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
|
||||
|
||||
if(ctx->buf) {
|
||||
/* still have buffered data, append and flush */
|
||||
result = cw_out_append(ctx, otype, buf, blen);
|
||||
result = cw_out_append(ctx, data, otype, buf, blen);
|
||||
if(result)
|
||||
return result;
|
||||
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
|
||||
@@ -380,7 +387,8 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
|
||||
return result;
|
||||
if(consumed < blen) {
|
||||
/* did not write all, append the rest */
|
||||
result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
|
||||
result = cw_out_append(ctx, data, otype,
|
||||
buf + consumed, blen - consumed);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
@@ -430,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;
|
||||
}
|
||||
|
||||
@@ -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
242
lib/cw-pause.c
Normal 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;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user