Update networking layer w/ CURL and emscripten impl
This commit is contained in:
+328
@@ -0,0 +1,328 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# 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
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
set(LIBCURL_OUTPUT_NAME "${LIB_NAME}" CACHE STRING "Basename of the curl library")
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_DEBUG_MACROS} "BUILDING_LIBCURL")
|
||||
|
||||
configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
|
||||
|
||||
# Get CSOURCES, HHEADERS, LIB_RCFILES variables
|
||||
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
|
||||
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
|
||||
|
||||
list(APPEND HHEADERS "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
|
||||
|
||||
# The rest of the build
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
"${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
|
||||
)
|
||||
|
||||
if(CURL_BUILD_TESTING)
|
||||
# special libcurlu library just for unittests
|
||||
add_library(curlu STATIC EXCLUDE_FROM_ALL ${HHEADERS} ${CSOURCES})
|
||||
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.
|
||||
set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0 C_CLANG_TIDY "")
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos"
|
||||
${CSOURCES} > "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
|
||||
DEPENDS "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos" ${CSOURCES}
|
||||
VERBATIM)
|
||||
add_custom_target(curlu-unitprotos DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h")
|
||||
endif()
|
||||
|
||||
## Library definition
|
||||
|
||||
if(NOT DEFINED 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()
|
||||
|
||||
# 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
|
||||
# objects to generate both static and shared target.
|
||||
if(NOT DEFINED SHARE_LIB_OBJECT)
|
||||
# Enable it by default on platforms where PIC is the default for both shared
|
||||
# and static and there is a way to tell the linker which libcurl symbols it
|
||||
# should export (vs. marking these symbols exportable at compile-time).
|
||||
if(WIN32)
|
||||
set(SHARE_LIB_OBJECT ON)
|
||||
else()
|
||||
# On other platforms, make it an option disabled by default
|
||||
set(SHARE_LIB_OBJECT OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
|
||||
set(LIB_OBJECT "libcurl_object")
|
||||
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.
|
||||
# Except with symbol hiding disabled or debug mode enabled, when we export
|
||||
# _all_ symbols from libcurl DLL, without using libcurl.def.
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
|
||||
endif()
|
||||
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
|
||||
set_target_properties(${LIB_OBJECT} PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
if(CURL_HIDES_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
|
||||
endif()
|
||||
if(CURL_HAS_LTO)
|
||||
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()
|
||||
if(CURL_CODE_COVERAGE)
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS})
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS})
|
||||
endif()
|
||||
|
||||
target_include_directories(${LIB_OBJECT} INTERFACE
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
|
||||
|
||||
set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
|
||||
else()
|
||||
set(LIB_SOURCE ${HHEADERS} ${CSOURCES})
|
||||
endif()
|
||||
|
||||
# We want it to be called libcurl on all platforms
|
||||
if(BUILD_STATIC_LIBS)
|
||||
list(APPEND libcurl_export ${LIB_STATIC})
|
||||
add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
|
||||
add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
|
||||
if(WIN32)
|
||||
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
|
||||
endif()
|
||||
target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
|
||||
# Remove the "lib" prefix since the library is already named "libcurl".
|
||||
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_LINK_DIRECTORIES "${CURL_LIBDIRS}")
|
||||
if(CURL_HIDES_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
|
||||
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
|
||||
endif()
|
||||
if(CURL_HAS_LTO)
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set_target_properties(${LIB_STATIC} PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
|
||||
else()
|
||||
set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(CURL_CODE_COVERAGE)
|
||||
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS})
|
||||
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS})
|
||||
endif()
|
||||
|
||||
target_include_directories(${LIB_STATIC} INTERFACE
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
|
||||
endif()
|
||||
|
||||
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)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES ${LIB_RCFILES})
|
||||
if(CURL_HIDES_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${PROJECT_SOURCE_DIR}/lib/libcurl.def")
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
|
||||
# Remove the "lib" prefix since the library is already named "libcurl".
|
||||
set_target_properties(${LIB_SHARED} PROPERTIES
|
||||
PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
|
||||
IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
if(CURL_HIDES_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
|
||||
endif()
|
||||
if(CURL_HAS_LTO)
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set_target_properties(${LIB_SHARED} PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
|
||||
else()
|
||||
set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(CURL_CODE_COVERAGE)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS})
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS})
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS})
|
||||
else()
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_include_directories(${LIB_SHARED} INTERFACE
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
|
||||
|
||||
if(CMAKE_DLL_NAME_WITH_SOVERSION OR
|
||||
CYGWIN OR
|
||||
APPLE OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "OHOS" OR # OpenHarmony
|
||||
CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
|
||||
# FreeBSD comes with the a.out and ELF flavours but a.out was supported
|
||||
# up to v3.x and ELF from v3.x. I cannot imagine someone running CMake
|
||||
# on those ancient systems.
|
||||
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
set(_soversion_default TRUE)
|
||||
else()
|
||||
set(_soversion_default FALSE)
|
||||
endif()
|
||||
|
||||
option(CURL_LIBCURL_SOVERSION "Enable libcurl SOVERSION" ${_soversion_default})
|
||||
option(CURL_LIBCURL_VERSIONED_SYMBOLS "Enable libcurl versioned symbols" OFF)
|
||||
|
||||
if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
|
||||
# Get VERSIONCHANGE, VERSIONADD, VERSIONDEL, VERSIONINFO variables
|
||||
curl_transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
|
||||
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
|
||||
|
||||
math(EXPR _cmakesoname "${VERSIONCHANGE} - ${VERSIONDEL}")
|
||||
set(_cmakeversion "${_cmakesoname}.${VERSIONDEL}.${VERSIONADD}")
|
||||
endif()
|
||||
|
||||
if(CURL_LIBCURL_SOVERSION)
|
||||
set_target_properties(${LIB_SHARED} PROPERTIES
|
||||
VERSION "${_cmakeversion}" SOVERSION "${_cmakesoname}")
|
||||
endif()
|
||||
|
||||
## Versioned symbols
|
||||
|
||||
if(CURL_LIBCURL_VERSIONED_SYMBOLS)
|
||||
if(NOT DEFINED CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX)
|
||||
# Default to prefixes used by autotools
|
||||
if(CURL_WITH_MULTI_SSL)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MULTISSL_")
|
||||
elseif(CURL_USE_OPENSSL)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "OPENSSL_")
|
||||
elseif(CURL_USE_MBEDTLS)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MBEDTLS_")
|
||||
elseif(CURL_USE_WOLFSSL)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "WOLFSSL_")
|
||||
elseif(CURL_USE_GNUTLS)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "GNUTLS_")
|
||||
elseif(CURL_USE_RUSTLS)
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "RUSTLS_")
|
||||
endif()
|
||||
endif()
|
||||
# Generate version script for the linker, for versioned symbols.
|
||||
# Consumed variables:
|
||||
# CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX
|
||||
# CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME
|
||||
set(CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME ${_cmakesoname})
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/libcurl.vers.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers" @ONLY)
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCSourceCompiles)
|
||||
cmake_push_check_state()
|
||||
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)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}")
|
||||
else()
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Versioned symbols requested, but not supported by the toolchain.")
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
|
||||
add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})
|
||||
|
||||
if(CURL_ENABLE_EXPORT_TARGET)
|
||||
if(BUILD_STATIC_LIBS)
|
||||
install(TARGETS ${LIB_STATIC}
|
||||
EXPORT ${TARGETS_EXPORT_NAME}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(TARGETS ${LIB_SHARED}
|
||||
EXPORT ${TARGETS_EXPORT_NAME}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
export(TARGETS ${libcurl_export}
|
||||
FILE "${PROJECT_BINARY_DIR}/libcurl-target.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
endif()
|
||||
Vendored
+191
@@ -0,0 +1,191 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# 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
|
||||
#
|
||||
###########################################################################
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
# Get CSOURCES, HHEADERS, LIB_RCFILES variables
|
||||
include Makefile.inc
|
||||
|
||||
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
|
||||
|
||||
EXTRA_DIST = config-mac.h config-os400.h config-plan9.h config-riscos.h \
|
||||
config-win32.h curl_config.h.in $(LIB_RCFILES) libcurl.def \
|
||||
$(CMAKE_DIST) Makefile.soname optiontable.pl
|
||||
|
||||
lib_LTLIBRARIES = libcurl.la
|
||||
|
||||
if BUILD_UNITTESTS
|
||||
noinst_LTLIBRARIES = libcurlu.la
|
||||
|
||||
# generate a file with "private" prototypes for unit testing
|
||||
UNITPROTOS = unitprotos.h
|
||||
|
||||
else
|
||||
noinst_LTLIBRARIES =
|
||||
endif
|
||||
|
||||
# This might hold -Werror
|
||||
CFLAGS += @CURL_CFLAG_EXTRAS@
|
||||
|
||||
# Specify our include paths here, and do it relative to $(top_srcdir) and
|
||||
# $(top_builddir), to ensure that these paths which belong to the library
|
||||
# being currently built and tested are searched before the library which
|
||||
# might possibly already be installed in the system.
|
||||
#
|
||||
# $(top_srcdir)/include is for libcurl's external include files
|
||||
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
|
||||
# $(srcdir) for the generated unity source to find included sources
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/lib \
|
||||
-I$(srcdir)
|
||||
|
||||
# Prevent LIBS from being used for all link targets
|
||||
LIBS = $(BLANK_AT_MAKETIME)
|
||||
|
||||
AM_LDFLAGS =
|
||||
AM_CFLAGS =
|
||||
if DEBUGBUILD
|
||||
AM_CPPFLAGS += -DDEBUGBUILD
|
||||
endif
|
||||
if CURLDEBUG
|
||||
AM_CPPFLAGS += -DCURLDEBUG
|
||||
endif
|
||||
AM_CPPFLAGS += -DBUILDING_LIBCURL
|
||||
|
||||
if DOING_NATIVE_WINDOWS
|
||||
CSOURCES += dllmain.c
|
||||
endif
|
||||
|
||||
if USE_UNITY
|
||||
libcurl_unity.c: $(top_srcdir)/scripts/mk-unity.pl $(CSOURCES)
|
||||
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(CSOURCES) > libcurl_unity.c
|
||||
|
||||
nodist_libcurl_la_SOURCES = libcurl_unity.c
|
||||
libcurl_la_SOURCES =
|
||||
nodist_libcurlu_la_SOURCES = libcurl_unity.c
|
||||
libcurlu_la_SOURCES =
|
||||
CLEANFILES = libcurl_unity.c
|
||||
else
|
||||
libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS)
|
||||
libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
|
||||
CLEANFILES =
|
||||
endif
|
||||
|
||||
CLEANFILES += $(UNITPROTOS)
|
||||
|
||||
libcurl_la_CPPFLAGS_EXTRA =
|
||||
libcurl_la_LDFLAGS_EXTRA =
|
||||
libcurl_la_CFLAGS_EXTRA =
|
||||
|
||||
if CURL_LT_SHLIB_USE_VERSION_INFO
|
||||
# Get VERSIONCHANGE, VERSIONADD, VERSIONDEL, VERSIONINFO variables
|
||||
include Makefile.soname
|
||||
libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO)
|
||||
endif
|
||||
|
||||
if CURL_LT_SHLIB_USE_NO_UNDEFINED
|
||||
libcurl_la_LDFLAGS_EXTRA += -no-undefined
|
||||
endif
|
||||
|
||||
if CURL_LT_SHLIB_USE_MIMPURE_TEXT
|
||||
libcurl_la_LDFLAGS_EXTRA += -mimpure-text
|
||||
endif
|
||||
|
||||
if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS
|
||||
libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers
|
||||
else
|
||||
# if symbol-hiding is enabled, hide them!
|
||||
if DOING_CURL_SYMBOL_HIDING
|
||||
libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*'
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_CPPFLAG_CURL_STATICLIB
|
||||
libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB
|
||||
else
|
||||
if HAVE_WINDRES
|
||||
libcurl_la_SOURCES += $(LIB_RCFILES)
|
||||
$(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h
|
||||
endif
|
||||
endif
|
||||
|
||||
if DOING_CURL_SYMBOL_HIDING
|
||||
libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS
|
||||
libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING)
|
||||
endif
|
||||
|
||||
libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA)
|
||||
libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_PC_LIBS_PRIVATE)
|
||||
libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA)
|
||||
|
||||
libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS
|
||||
libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_PC_LIBS_PRIVATE)
|
||||
libcurlu_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
CHECKSRC = $(CS_$(V))
|
||||
CS_0 = @echo " RUN " $@;
|
||||
CS_1 =
|
||||
CS_ = $(CS_0)
|
||||
|
||||
checksrc:
|
||||
$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
|
||||
$(CSOURCES) $(HHEADERS))
|
||||
|
||||
if NOT_CURL_CI
|
||||
if DEBUGBUILD
|
||||
# for debug builds, we scan the sources on all regular make invokes
|
||||
CHECKSOURCES = checksrc
|
||||
endif
|
||||
endif
|
||||
|
||||
all-local: $(CHECKSOURCES)
|
||||
|
||||
UNIT_V = $(UNITV_$(V))
|
||||
UNITV_0 = @echo " UNITPR " $@;
|
||||
UNITV_1 =
|
||||
UNITV_ = $(UNITV_0)
|
||||
|
||||
# UNITPROTOS depends on every C file in the lib/ dir
|
||||
$(UNITPROTOS): $(CSOURCES)
|
||||
$(UNIT_V)(cd $(srcdir) && @PERL@ ../scripts/extract-unit-protos $(CSOURCES) > $(top_builddir)/lib/$(UNITPROTOS))
|
||||
|
||||
# disable the tests that are mostly causing false positives
|
||||
TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet
|
||||
if CURL_WERROR
|
||||
TIDYFLAGS += --warnings-as-errors=*
|
||||
endif
|
||||
|
||||
TIDY := clang-tidy
|
||||
|
||||
tidy:
|
||||
(_csources=`echo ' $(CSOURCES)' | sed -E -e 's/ +$$//' -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \
|
||||
$(TIDY) $$_csources $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H)
|
||||
|
||||
optiontable:
|
||||
@PERL@ $(srcdir)/optiontable.pl < $(top_srcdir)/include/curl/curl.h > $(srcdir)/easyoptions.c
|
||||
|
||||
if HAVE_WINDRES
|
||||
.rc.lo:
|
||||
$(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@
|
||||
endif
|
||||
Vendored
+5948
File diff suppressed because it is too large
Load Diff
+409
@@ -0,0 +1,409 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# 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
|
||||
#
|
||||
###########################################################################
|
||||
# Shared between CMakeLists.txt and Makefile.am
|
||||
|
||||
LIB_CURLX_CFILES = \
|
||||
curlx/base64.c \
|
||||
curlx/dynbuf.c \
|
||||
curlx/fopen.c \
|
||||
curlx/inet_ntop.c \
|
||||
curlx/inet_pton.c \
|
||||
curlx/multibyte.c \
|
||||
curlx/nonblock.c \
|
||||
curlx/strerr.c \
|
||||
curlx/strparse.c \
|
||||
curlx/timediff.c \
|
||||
curlx/timeval.c \
|
||||
curlx/version_win32.c \
|
||||
curlx/wait.c \
|
||||
curlx/warnless.c \
|
||||
curlx/winapi.c
|
||||
|
||||
LIB_CURLX_HFILES = \
|
||||
curlx/binmode.h \
|
||||
curlx/base64.h \
|
||||
curlx/curlx.h \
|
||||
curlx/dynbuf.h \
|
||||
curlx/fopen.h \
|
||||
curlx/inet_ntop.h \
|
||||
curlx/inet_pton.h \
|
||||
curlx/multibyte.h \
|
||||
curlx/nonblock.h \
|
||||
curlx/strerr.h \
|
||||
curlx/strparse.h \
|
||||
curlx/timediff.h \
|
||||
curlx/timeval.h \
|
||||
curlx/version_win32.h \
|
||||
curlx/wait.h \
|
||||
curlx/warnless.h \
|
||||
curlx/winapi.h
|
||||
|
||||
LIB_VAUTH_CFILES = \
|
||||
vauth/cleartext.c \
|
||||
vauth/cram.c \
|
||||
vauth/digest.c \
|
||||
vauth/digest_sspi.c \
|
||||
vauth/gsasl.c \
|
||||
vauth/krb5_gssapi.c \
|
||||
vauth/krb5_sspi.c \
|
||||
vauth/ntlm.c \
|
||||
vauth/ntlm_sspi.c \
|
||||
vauth/oauth2.c \
|
||||
vauth/spnego_gssapi.c \
|
||||
vauth/spnego_sspi.c \
|
||||
vauth/vauth.c
|
||||
|
||||
LIB_VAUTH_HFILES = \
|
||||
vauth/digest.h \
|
||||
vauth/vauth.h
|
||||
|
||||
LIB_VTLS_CFILES = \
|
||||
vtls/apple.c \
|
||||
vtls/cipher_suite.c \
|
||||
vtls/gtls.c \
|
||||
vtls/hostcheck.c \
|
||||
vtls/keylog.c \
|
||||
vtls/mbedtls.c \
|
||||
vtls/mbedtls_threadlock.c \
|
||||
vtls/openssl.c \
|
||||
vtls/rustls.c \
|
||||
vtls/schannel.c \
|
||||
vtls/schannel_verify.c \
|
||||
vtls/vtls.c \
|
||||
vtls/vtls_scache.c \
|
||||
vtls/vtls_spack.c \
|
||||
vtls/wolfssl.c \
|
||||
vtls/x509asn1.c
|
||||
|
||||
LIB_VTLS_HFILES = \
|
||||
vtls/apple.h \
|
||||
vtls/cipher_suite.h \
|
||||
vtls/gtls.h \
|
||||
vtls/hostcheck.h \
|
||||
vtls/keylog.h \
|
||||
vtls/mbedtls.h \
|
||||
vtls/mbedtls_threadlock.h \
|
||||
vtls/openssl.h \
|
||||
vtls/rustls.h \
|
||||
vtls/schannel.h \
|
||||
vtls/schannel_int.h \
|
||||
vtls/vtls.h \
|
||||
vtls/vtls_int.h \
|
||||
vtls/vtls_scache.h \
|
||||
vtls/vtls_spack.h \
|
||||
vtls/wolfssl.h \
|
||||
vtls/x509asn1.h
|
||||
|
||||
LIB_VQUIC_CFILES = \
|
||||
vquic/curl_ngtcp2.c \
|
||||
vquic/curl_osslq.c \
|
||||
vquic/curl_quiche.c \
|
||||
vquic/vquic.c \
|
||||
vquic/vquic-tls.c
|
||||
|
||||
LIB_VQUIC_HFILES = \
|
||||
vquic/curl_ngtcp2.h \
|
||||
vquic/curl_osslq.h \
|
||||
vquic/curl_quiche.h \
|
||||
vquic/vquic.h \
|
||||
vquic/vquic_int.h \
|
||||
vquic/vquic-tls.h
|
||||
|
||||
LIB_VSSH_CFILES = \
|
||||
vssh/libssh.c \
|
||||
vssh/libssh2.c \
|
||||
vssh/curl_path.c
|
||||
|
||||
LIB_VSSH_HFILES = \
|
||||
vssh/curl_path.h \
|
||||
vssh/ssh.h
|
||||
|
||||
LIB_CFILES = \
|
||||
altsvc.c \
|
||||
amigaos.c \
|
||||
asyn-ares.c \
|
||||
asyn-base.c \
|
||||
asyn-thrdd.c \
|
||||
bufq.c \
|
||||
bufref.c \
|
||||
cf-h1-proxy.c \
|
||||
cf-h2-proxy.c \
|
||||
cf-haproxy.c \
|
||||
cf-https-connect.c \
|
||||
cf-ip-happy.c \
|
||||
cf-socket.c \
|
||||
cfilters.c \
|
||||
conncache.c \
|
||||
connect.c \
|
||||
content_encoding.c \
|
||||
cookie.c \
|
||||
cshutdn.c \
|
||||
curl_addrinfo.c \
|
||||
curl_endian.c \
|
||||
curl_fnmatch.c \
|
||||
curl_fopen.c \
|
||||
curl_get_line.c \
|
||||
curl_gethostname.c \
|
||||
curl_gssapi.c \
|
||||
curl_memrchr.c \
|
||||
curl_ntlm_core.c \
|
||||
curl_range.c \
|
||||
curl_rtmp.c \
|
||||
curl_sasl.c \
|
||||
curl_sha512_256.c \
|
||||
curl_sspi.c \
|
||||
curl_threads.c \
|
||||
curl_trc.c \
|
||||
cw-out.c \
|
||||
cw-pause.c \
|
||||
dict.c \
|
||||
doh.c \
|
||||
dynhds.c \
|
||||
easy.c \
|
||||
easygetopt.c \
|
||||
easyoptions.c \
|
||||
escape.c \
|
||||
fake_addrinfo.c \
|
||||
file.c \
|
||||
fileinfo.c \
|
||||
formdata.c \
|
||||
ftp.c \
|
||||
ftplistparser.c \
|
||||
getenv.c \
|
||||
getinfo.c \
|
||||
gopher.c \
|
||||
hash.c \
|
||||
headers.c \
|
||||
hmac.c \
|
||||
hostip.c \
|
||||
hostip4.c \
|
||||
hostip6.c \
|
||||
hsts.c \
|
||||
http.c \
|
||||
http1.c \
|
||||
http2.c \
|
||||
http_aws_sigv4.c \
|
||||
http_chunks.c \
|
||||
http_digest.c \
|
||||
http_negotiate.c \
|
||||
http_ntlm.c \
|
||||
http_proxy.c \
|
||||
httpsrr.c \
|
||||
idn.c \
|
||||
if2ip.c \
|
||||
imap.c \
|
||||
ldap.c \
|
||||
llist.c \
|
||||
macos.c \
|
||||
md4.c \
|
||||
md5.c \
|
||||
memdebug.c \
|
||||
mime.c \
|
||||
mprintf.c \
|
||||
mqtt.c \
|
||||
multi.c \
|
||||
multi_ev.c \
|
||||
multi_ntfy.c \
|
||||
netrc.c \
|
||||
noproxy.c \
|
||||
openldap.c \
|
||||
parsedate.c \
|
||||
pingpong.c \
|
||||
pop3.c \
|
||||
progress.c \
|
||||
psl.c \
|
||||
rand.c \
|
||||
rename.c \
|
||||
request.c \
|
||||
rtsp.c \
|
||||
select.c \
|
||||
sendf.c \
|
||||
setopt.c \
|
||||
sha256.c \
|
||||
share.c \
|
||||
slist.c \
|
||||
smb.c \
|
||||
smtp.c \
|
||||
socketpair.c \
|
||||
socks.c \
|
||||
socks_gssapi.c \
|
||||
socks_sspi.c \
|
||||
speedcheck.c \
|
||||
splay.c \
|
||||
strcase.c \
|
||||
strdup.c \
|
||||
strequal.c \
|
||||
strerror.c \
|
||||
system_win32.c \
|
||||
telnet.c \
|
||||
tftp.c \
|
||||
transfer.c \
|
||||
uint-bset.c \
|
||||
uint-hash.c \
|
||||
uint-spbset.c \
|
||||
uint-table.c \
|
||||
url.c \
|
||||
urlapi.c \
|
||||
version.c \
|
||||
ws.c
|
||||
|
||||
LIB_HFILES = \
|
||||
altsvc.h \
|
||||
amigaos.h \
|
||||
arpa_telnet.h \
|
||||
asyn.h \
|
||||
bufq.h \
|
||||
bufref.h \
|
||||
cf-h1-proxy.h \
|
||||
cf-h2-proxy.h \
|
||||
cf-haproxy.h \
|
||||
cf-https-connect.h \
|
||||
cf-ip-happy.h \
|
||||
cf-socket.h \
|
||||
cfilters.h \
|
||||
conncache.h \
|
||||
cshutdn.h \
|
||||
connect.h \
|
||||
content_encoding.h \
|
||||
cookie.h \
|
||||
curl_addrinfo.h \
|
||||
curl_ctype.h \
|
||||
curl_endian.h \
|
||||
curl_fnmatch.h \
|
||||
curl_fopen.h \
|
||||
curl_get_line.h \
|
||||
curl_gethostname.h \
|
||||
curl_gssapi.h \
|
||||
curl_hmac.h \
|
||||
curl_ldap.h \
|
||||
curl_md4.h \
|
||||
curl_md5.h \
|
||||
curl_mem_undef.h \
|
||||
curl_memory.h \
|
||||
curl_memrchr.h \
|
||||
curl_ntlm_core.h \
|
||||
curl_printf.h \
|
||||
curl_range.h \
|
||||
curl_rtmp.h \
|
||||
curl_sasl.h \
|
||||
curl_setup.h \
|
||||
curl_setup_once.h \
|
||||
curl_sha256.h \
|
||||
curl_sha512_256.h \
|
||||
curl_sspi.h \
|
||||
curl_threads.h \
|
||||
curl_trc.h \
|
||||
cw-out.h \
|
||||
cw-pause.h \
|
||||
dict.h \
|
||||
doh.h \
|
||||
dynhds.h \
|
||||
easy_lock.h \
|
||||
easyif.h \
|
||||
easyoptions.h \
|
||||
escape.h \
|
||||
fake_addrinfo.h \
|
||||
file.h \
|
||||
fileinfo.h \
|
||||
formdata.h \
|
||||
ftp.h \
|
||||
ftplistparser.h \
|
||||
functypes.h \
|
||||
getinfo.h \
|
||||
gopher.h \
|
||||
hash.h \
|
||||
headers.h \
|
||||
hostip.h \
|
||||
hsts.h \
|
||||
http.h \
|
||||
http1.h \
|
||||
http2.h \
|
||||
http_aws_sigv4.h \
|
||||
http_chunks.h \
|
||||
http_digest.h \
|
||||
http_negotiate.h \
|
||||
http_ntlm.h \
|
||||
http_proxy.h \
|
||||
httpsrr.h \
|
||||
idn.h \
|
||||
if2ip.h \
|
||||
imap.h \
|
||||
llist.h \
|
||||
macos.h \
|
||||
memdebug.h \
|
||||
mime.h \
|
||||
mqtt.h \
|
||||
multihandle.h \
|
||||
multi_ev.h \
|
||||
multi_ntfy.h \
|
||||
multiif.h \
|
||||
netrc.h \
|
||||
noproxy.h \
|
||||
parsedate.h \
|
||||
pingpong.h \
|
||||
pop3.h \
|
||||
progress.h \
|
||||
psl.h \
|
||||
rand.h \
|
||||
rename.h \
|
||||
request.h \
|
||||
rtsp.h \
|
||||
select.h \
|
||||
sendf.h \
|
||||
setopt.h \
|
||||
setup-os400.h \
|
||||
setup-vms.h \
|
||||
setup-win32.h \
|
||||
share.h \
|
||||
sigpipe.h \
|
||||
slist.h \
|
||||
smb.h \
|
||||
smtp.h \
|
||||
sockaddr.h \
|
||||
socketpair.h \
|
||||
socks.h \
|
||||
speedcheck.h \
|
||||
splay.h \
|
||||
strcase.h \
|
||||
strdup.h \
|
||||
strerror.h \
|
||||
system_win32.h \
|
||||
telnet.h \
|
||||
tftp.h \
|
||||
transfer.h \
|
||||
uint-bset.h \
|
||||
uint-hash.h \
|
||||
uint-spbset.h \
|
||||
uint-table.h \
|
||||
url.h \
|
||||
urlapi-int.h \
|
||||
urldata.h \
|
||||
ws.h
|
||||
|
||||
LIB_RCFILES = libcurl.rc
|
||||
|
||||
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
|
||||
$(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) $(LIB_CURLX_CFILES)
|
||||
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
|
||||
$(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) $(LIB_CURLX_HFILES)
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# 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
|
||||
#
|
||||
###########################################################################
|
||||
# Shared between CMakeLists.txt and Makefile.am
|
||||
|
||||
# Keep in sync with CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME in configure.ac
|
||||
VERSIONCHANGE=12
|
||||
VERSIONADD=0
|
||||
VERSIONDEL=8
|
||||
|
||||
# libtool version:
|
||||
VERSIONINFO=-version-info $(VERSIONCHANGE):$(VERSIONADD):$(VERSIONDEL)
|
||||
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
||||
# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
|
||||
# 1.
|
||||
#
|
||||
# Here's the simplified rule guide on how to change -version-info:
|
||||
# (current version is C:R:A)
|
||||
#
|
||||
# 1. if there are only source changes, use C:R+1:A
|
||||
# 2. if interfaces were added use C+1:0:A+1
|
||||
# 3. if interfaces were removed, then use C+1:0:0
|
||||
#
|
||||
# For the full guide on libcurl ABI rules, see docs/libcurl/ABI
|
||||
Vendored
+674
@@ -0,0 +1,674 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
/*
|
||||
* The Alt-Svc: header is defined in RFC 7838:
|
||||
* https://datatracker.ietf.org/doc/html/rfc7838
|
||||
*/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
#include "altsvc.h"
|
||||
#include "curl_fopen.h"
|
||||
#include "curl_get_line.h"
|
||||
#include "parsedate.h"
|
||||
#include "sendf.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "rename.h"
|
||||
#include "strdup.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "connect.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define MAX_ALTSVC_LINE 4095
|
||||
#define MAX_ALTSVC_DATELEN 256
|
||||
#define MAX_ALTSVC_HOSTLEN 2048
|
||||
#define MAX_ALTSVC_ALPNLEN 10
|
||||
|
||||
#define H3VERSION "h3"
|
||||
|
||||
/* Given the ALPN ID, return the name */
|
||||
const char *Curl_alpnid2str(enum alpnid id)
|
||||
{
|
||||
switch(id) {
|
||||
case ALPN_h1:
|
||||
return "h1";
|
||||
case ALPN_h2:
|
||||
return "h2";
|
||||
case ALPN_h3:
|
||||
return H3VERSION;
|
||||
default:
|
||||
return ""; /* bad */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void altsvc_free(struct altsvc *as)
|
||||
{
|
||||
free(as->src.host);
|
||||
free(as->dst.host);
|
||||
free(as);
|
||||
}
|
||||
|
||||
static struct altsvc *altsvc_createid(const char *srchost,
|
||||
size_t hlen,
|
||||
const char *dsthost,
|
||||
size_t dlen, /* dsthost length */
|
||||
enum alpnid srcalpnid,
|
||||
enum alpnid dstalpnid,
|
||||
size_t srcport,
|
||||
size_t dstport)
|
||||
{
|
||||
struct altsvc *as = calloc(1, sizeof(struct altsvc));
|
||||
if(!as)
|
||||
return NULL;
|
||||
DEBUGASSERT(hlen);
|
||||
DEBUGASSERT(dlen);
|
||||
if(!hlen || !dlen)
|
||||
/* bad input */
|
||||
goto error;
|
||||
if((hlen > 2) && srchost[0] == '[') {
|
||||
/* IPv6 address, strip off brackets */
|
||||
srchost++;
|
||||
hlen -= 2;
|
||||
}
|
||||
else if(srchost[hlen - 1] == '.') {
|
||||
/* strip off trailing dot */
|
||||
hlen--;
|
||||
if(!hlen)
|
||||
goto error;
|
||||
}
|
||||
if((dlen > 2) && dsthost[0] == '[') {
|
||||
/* IPv6 address, strip off brackets */
|
||||
dsthost++;
|
||||
dlen -= 2;
|
||||
}
|
||||
|
||||
as->src.host = Curl_memdup0(srchost, hlen);
|
||||
if(!as->src.host)
|
||||
goto error;
|
||||
|
||||
as->dst.host = Curl_memdup0(dsthost, dlen);
|
||||
if(!as->dst.host)
|
||||
goto error;
|
||||
|
||||
as->src.alpnid = srcalpnid;
|
||||
as->dst.alpnid = dstalpnid;
|
||||
as->src.port = (unsigned short)srcport;
|
||||
as->dst.port = (unsigned short)dstport;
|
||||
|
||||
return as;
|
||||
error:
|
||||
altsvc_free(as);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct altsvc *altsvc_create(struct Curl_str *srchost,
|
||||
struct Curl_str *dsthost,
|
||||
struct Curl_str *srcalpn,
|
||||
struct Curl_str *dstalpn,
|
||||
size_t srcport,
|
||||
size_t dstport)
|
||||
{
|
||||
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(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, const char *line)
|
||||
{
|
||||
/* Example line:
|
||||
h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
|
||||
*/
|
||||
struct Curl_str srchost;
|
||||
struct Curl_str dsthost;
|
||||
struct Curl_str srcalpn;
|
||||
struct Curl_str dstalpn;
|
||||
struct Curl_str date;
|
||||
curl_off_t srcport;
|
||||
curl_off_t dstport;
|
||||
curl_off_t persist;
|
||||
curl_off_t prio;
|
||||
|
||||
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 = 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;
|
||||
Curl_getdate_capped(dbuf, &expires);
|
||||
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 */
|
||||
as->persist = persist ? 1 : 0;
|
||||
Curl_llist_append(&asi->list, as, &as->node);
|
||||
}
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load alt-svc entries from the given file. The text based line-oriented file
|
||||
* format is documented here: https://curl.se/docs/alt-svc.html
|
||||
*
|
||||
* This function only returns error on major problems that prevent alt-svc
|
||||
* handling to work completely. It will ignore individual syntactical errors
|
||||
* etc.
|
||||
*/
|
||||
static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
FILE *fp;
|
||||
|
||||
/* we need a private copy of the filename so that the altsvc cache file
|
||||
name survives an easy handle reset */
|
||||
free(asi->filename);
|
||||
asi->filename = strdup(file);
|
||||
if(!asi->filename)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
fp = curlx_fopen(file, FOPEN_READTEXT);
|
||||
if(fp) {
|
||||
bool eof = FALSE;
|
||||
struct dynbuf buf;
|
||||
curlx_dyn_init(&buf, MAX_ALTSVC_LINE);
|
||||
do {
|
||||
result = Curl_get_line(&buf, fp, &eof);
|
||||
if(!result) {
|
||||
const char *lineptr = curlx_dyn_ptr(&buf);
|
||||
curlx_str_passblanks(&lineptr);
|
||||
if(curlx_str_single(&lineptr, '#'))
|
||||
altsvc_add(asi, lineptr);
|
||||
}
|
||||
} while(!result && !eof);
|
||||
curlx_dyn_free(&buf); /* free the line buffer */
|
||||
curlx_fclose(fp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write this single altsvc entry to a single output line
|
||||
*/
|
||||
|
||||
static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
|
||||
{
|
||||
struct tm stamp;
|
||||
const char *dst6_pre = "";
|
||||
const char *dst6_post = "";
|
||||
const char *src6_pre = "";
|
||||
const char *src6_post = "";
|
||||
CURLcode result = Curl_gmtime(as->expires, &stamp);
|
||||
if(result)
|
||||
return result;
|
||||
#ifdef USE_IPV6
|
||||
else {
|
||||
char ipv6_unused[16];
|
||||
if(curlx_inet_pton(AF_INET6, as->dst.host, ipv6_unused) == 1) {
|
||||
dst6_pre = "[";
|
||||
dst6_post = "]";
|
||||
}
|
||||
if(curlx_inet_pton(AF_INET6, as->src.host, ipv6_unused) == 1) {
|
||||
src6_pre = "[";
|
||||
src6_post = "]";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
curl_mfprintf(fp,
|
||||
"%s %s%s%s %u "
|
||||
"%s %s%s%s %u "
|
||||
"\"%d%02d%02d "
|
||||
"%02d:%02d:%02d\" "
|
||||
"%u %u\n",
|
||||
Curl_alpnid2str(as->src.alpnid),
|
||||
src6_pre, as->src.host, src6_post,
|
||||
as->src.port,
|
||||
|
||||
Curl_alpnid2str(as->dst.alpnid),
|
||||
dst6_pre, as->dst.host, dst6_post,
|
||||
as->dst.port,
|
||||
|
||||
stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
|
||||
stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
|
||||
as->persist, as->prio);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* ---- library-wide functions below ---- */
|
||||
|
||||
/*
|
||||
* Curl_altsvc_init() creates a new altsvc cache.
|
||||
* It returns the new instance or NULL if something goes wrong.
|
||||
*/
|
||||
struct altsvcinfo *Curl_altsvc_init(void)
|
||||
{
|
||||
struct altsvcinfo *asi = calloc(1, sizeof(struct altsvcinfo));
|
||||
if(!asi)
|
||||
return NULL;
|
||||
Curl_llist_init(&asi->list, NULL);
|
||||
|
||||
/* set default behavior */
|
||||
asi->flags = CURLALTSVC_H1
|
||||
#ifdef USE_HTTP2
|
||||
| CURLALTSVC_H2
|
||||
#endif
|
||||
#ifdef USE_HTTP3
|
||||
| CURLALTSVC_H3
|
||||
#endif
|
||||
;
|
||||
return asi;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_altsvc_load() loads alt-svc from file.
|
||||
*/
|
||||
CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
|
||||
{
|
||||
DEBUGASSERT(asi);
|
||||
return altsvc_load(asi, file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_altsvc_ctrl() passes on the external bitmask.
|
||||
*/
|
||||
CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
|
||||
{
|
||||
DEBUGASSERT(asi);
|
||||
asi->flags = ctrl;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
|
||||
* resources.
|
||||
*/
|
||||
void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
|
||||
{
|
||||
if(*altsvcp) {
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
struct altsvcinfo *altsvc = *altsvcp;
|
||||
for(e = Curl_llist_head(&altsvc->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
altsvc_free(as);
|
||||
}
|
||||
free(altsvc->filename);
|
||||
free(altsvc);
|
||||
*altsvcp = NULL; /* clear the pointer */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_altsvc_save() writes the altsvc cache to a file.
|
||||
*/
|
||||
CURLcode Curl_altsvc_save(struct Curl_easy *data,
|
||||
struct altsvcinfo *altsvc, const char *file)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
FILE *out;
|
||||
char *tempstore = NULL;
|
||||
|
||||
if(!altsvc)
|
||||
/* no cache activated */
|
||||
return CURLE_OK;
|
||||
|
||||
/* if not new name is given, use the one we stored from the load */
|
||||
if(!file && altsvc->filename)
|
||||
file = altsvc->filename;
|
||||
|
||||
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
|
||||
/* marked as read-only, no file or zero length filename */
|
||||
return CURLE_OK;
|
||||
|
||||
result = Curl_fopen(data, file, &out, &tempstore);
|
||||
if(!result) {
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
|
||||
"# This file was generated by libcurl! Edit at your own risk.\n",
|
||||
out);
|
||||
for(e = Curl_llist_head(&altsvc->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
result = altsvc_out(as, out);
|
||||
if(result)
|
||||
break;
|
||||
}
|
||||
curlx_fclose(out);
|
||||
if(!result && tempstore && Curl_rename(tempstore, file))
|
||||
result = CURLE_WRITE_ERROR;
|
||||
|
||||
if(result && tempstore)
|
||||
unlink(tempstore);
|
||||
}
|
||||
free(tempstore);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* hostcompare() returns true if 'host' matches 'check'. The first host
|
||||
* argument may have a trailing dot present that will be ignored.
|
||||
*/
|
||||
static bool hostcompare(const char *host, const char *check)
|
||||
{
|
||||
size_t hlen = strlen(host);
|
||||
size_t clen = strlen(check);
|
||||
|
||||
if(hlen && (host[hlen - 1] == '.'))
|
||||
hlen--;
|
||||
if(hlen != clen)
|
||||
/* they cannot match if they have different lengths */
|
||||
return FALSE;
|
||||
return curl_strnequal(host, check, hlen);
|
||||
}
|
||||
|
||||
/* altsvc_flush() removes all alternatives for this source origin from the
|
||||
list */
|
||||
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
|
||||
const char *srchost, unsigned short srcport)
|
||||
{
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
for(e = Curl_llist_head(&asi->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
if((srcalpnid == as->src.alpnid) &&
|
||||
(srcport == as->src.port) &&
|
||||
hostcompare(srchost, as->src.host)) {
|
||||
Curl_node_remove(e);
|
||||
altsvc_free(as);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
const char *timestr = getenv("CURL_TIME");
|
||||
(void)unused;
|
||||
if(timestr) {
|
||||
curl_off_t val;
|
||||
curlx_str_number(×tr, &val, TIME_T_MAX);
|
||||
return (time_t)val;
|
||||
}
|
||||
return time(NULL);
|
||||
}
|
||||
#undef time
|
||||
#define time(x) altsvc_debugtime(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Curl_altsvc_parse() takes an incoming alt-svc response header and stores
|
||||
* the data correctly in the cache.
|
||||
*
|
||||
* 'value' points to the header *value*. That is contents to the right of the
|
||||
* header name.
|
||||
*
|
||||
* Currently this function rejects invalid data without returning an error.
|
||||
* Invalid hostname, port number will result in the specific alternative
|
||||
* being rejected. Unknown protocols are skipped.
|
||||
*/
|
||||
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
||||
struct altsvcinfo *asi, const char *value,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
unsigned short srcport)
|
||||
{
|
||||
const char *p = value;
|
||||
struct altsvc *as;
|
||||
unsigned short dstport = srcport; /* the same by default */
|
||||
size_t entries = 0;
|
||||
struct Curl_str alpn;
|
||||
const char *sp;
|
||||
time_t maxage = 24 * 3600; /* default is 24 hours */
|
||||
bool persist = FALSE;
|
||||
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||||
(void)data;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(asi);
|
||||
|
||||
/* initial check for "clear" */
|
||||
if(!curlx_str_cspn(&p, &alpn, ";\n\r")) {
|
||||
curlx_str_trimblanks(&alpn);
|
||||
/* "clear" is a magic keyword */
|
||||
if(curlx_str_casecompare(&alpn, "clear")) {
|
||||
/* Flush cached alternatives for this source origin */
|
||||
altsvc_flush(asi, srcalpnid, srchost, srcport);
|
||||
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(!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 */
|
||||
if(curlx_str_single(&p, '[')) {
|
||||
if(curlx_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
|
||||
infof(data, "Bad alt-svc hostname, ignoring.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* 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
|
||||
/* no destination name, use source host */
|
||||
curlx_str_assign(&dsthost, srchost, strlen(srchost));
|
||||
|
||||
if(curlx_str_number(&p, &port, 0xffff)) {
|
||||
infof(data, "Unknown alt-svc port number, ignoring.");
|
||||
break;
|
||||
}
|
||||
|
||||
dstport = (unsigned short)port;
|
||||
|
||||
if(curlx_str_single(&p, '\"'))
|
||||
break;
|
||||
|
||||
if(dstalpnid) {
|
||||
if(!entries++)
|
||||
/* Flush cached alternatives for this source origin, if any - when
|
||||
this is the first entry of the line. */
|
||||
altsvc_flush(asi, srcalpnid, srchost, srcport);
|
||||
|
||||
as = altsvc_createid(srchost, strlen(srchost),
|
||||
curlx_str(&dsthost),
|
||||
curlx_strlen(&dsthost),
|
||||
srcalpnid, dstalpnid,
|
||||
srcport, dstport);
|
||||
if(as) {
|
||||
time_t secs = time(NULL);
|
||||
/* The expires time also needs to take the Age: value (if any)
|
||||
into account. [See RFC 7838 section 3.1] */
|
||||
if(maxage > (TIME_T_MAX - secs))
|
||||
as->expires = TIME_T_MAX;
|
||||
else
|
||||
as->expires = maxage + secs;
|
||||
as->persist = persist;
|
||||
Curl_llist_append(&asi->list, as, &as->node);
|
||||
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(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(1);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE on a match
|
||||
*/
|
||||
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
int srcport,
|
||||
struct altsvc **dstentry,
|
||||
const int versions) /* one or more bits */
|
||||
{
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
time_t now = time(NULL);
|
||||
DEBUGASSERT(asi);
|
||||
DEBUGASSERT(srchost);
|
||||
DEBUGASSERT(dstentry);
|
||||
|
||||
for(e = Curl_llist_head(&asi->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
if(as->expires < now) {
|
||||
/* an expired entry, remove */
|
||||
Curl_node_remove(e);
|
||||
altsvc_free(as);
|
||||
continue;
|
||||
}
|
||||
if((as->src.alpnid == srcalpnid) &&
|
||||
hostcompare(srchost, as->src.host) &&
|
||||
(as->src.port == srcport) &&
|
||||
(versions & (int)as->dst.alpnid)) {
|
||||
/* match */
|
||||
*dstentry = as;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if defined(DEBUGBUILD) || defined(UNITTESTS)
|
||||
#undef time
|
||||
#endif
|
||||
|
||||
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
|
||||
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
#ifndef HEADER_CURL_ALTSVC_H
|
||||
#define HEADER_CURL_ALTSVC_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
|
||||
#include <curl/curl.h>
|
||||
#include "llist.h"
|
||||
|
||||
struct althost {
|
||||
char *host;
|
||||
unsigned short port;
|
||||
enum alpnid alpnid;
|
||||
};
|
||||
|
||||
struct altsvc {
|
||||
struct althost src;
|
||||
struct althost dst;
|
||||
time_t expires;
|
||||
struct Curl_llist_node node;
|
||||
unsigned int prio;
|
||||
BIT(persist);
|
||||
};
|
||||
|
||||
struct altsvcinfo {
|
||||
char *filename;
|
||||
struct Curl_llist list; /* list of entries */
|
||||
long flags; /* the publicly set bitmask */
|
||||
};
|
||||
|
||||
const char *Curl_alpnid2str(enum alpnid id);
|
||||
struct altsvcinfo *Curl_altsvc_init(void);
|
||||
CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file);
|
||||
CURLcode Curl_altsvc_save(struct Curl_easy *data,
|
||||
struct altsvcinfo *asi, const char *file);
|
||||
CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl);
|
||||
void Curl_altsvc_cleanup(struct altsvcinfo **altsvc);
|
||||
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
||||
struct altsvcinfo *altsvc, const char *value,
|
||||
enum alpnid srcalpn, const char *srchost,
|
||||
unsigned short srcport);
|
||||
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
int srcport,
|
||||
struct altsvc **dstentry,
|
||||
const int versions); /* CURLALTSVC_H* bits */
|
||||
#else
|
||||
/* disabled */
|
||||
#define Curl_altsvc_save(a,b,c)
|
||||
#define Curl_altsvc_cleanup(x)
|
||||
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
|
||||
#endif /* HEADER_CURL_ALTSVC_H */
|
||||
Vendored
+247
@@ -0,0 +1,247 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 __AMIGA__
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "hostip.h"
|
||||
#include "amigaos.h"
|
||||
|
||||
#ifdef HAVE_PROTO_BSDSOCKET_H
|
||||
# if defined(__amigaos4__)
|
||||
# include <bsdsocket/socketbasetags.h>
|
||||
# elif !defined(USE_AMISSL)
|
||||
# include <amitcp/socketbasetags.h>
|
||||
# endif
|
||||
# ifdef __libnix__
|
||||
# include <stabs.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The last #include files should be: */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef HAVE_PROTO_BSDSOCKET_H
|
||||
|
||||
#ifdef __amigaos4__
|
||||
/*
|
||||
* AmigaOS 4.x specific code
|
||||
*/
|
||||
|
||||
/*
|
||||
* hostip4.c - Curl_ipv4_resolve_r() replacement code
|
||||
*
|
||||
* Logic that needs to be considered are the following build cases:
|
||||
* - newlib networking
|
||||
* - clib2 networking
|
||||
* - direct bsdsocket.library networking (usually AmiSSL builds)
|
||||
* Each with the threaded resolver enabled or not.
|
||||
*
|
||||
* With the threaded resolver enabled, try to use gethostbyname_r() where
|
||||
* available, otherwise (re)open bsdsocket.library and fallback to
|
||||
* gethostbyname().
|
||||
*/
|
||||
|
||||
#include <proto/bsdsocket.h>
|
||||
|
||||
static struct SocketIFace *__CurlISocket = NULL;
|
||||
static uint32 SocketFeatures = 0;
|
||||
|
||||
#define HAVE_BSDSOCKET_GETHOSTBYNAME_R 0x01
|
||||
#define HAVE_BSDSOCKET_GETADDRINFO 0x02
|
||||
|
||||
CURLcode Curl_amiga_init(void)
|
||||
{
|
||||
struct SocketIFace *ISocket;
|
||||
struct Library *base = OpenLibrary("bsdsocket.library", 4);
|
||||
|
||||
if(base) {
|
||||
ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
|
||||
if(ISocket) {
|
||||
ULONG enabled = 0;
|
||||
|
||||
SocketBaseTags(SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES), TRUE,
|
||||
SBTM_GETREF(SBTC_HAVE_GETHOSTADDR_R_API), (ULONG)&enabled,
|
||||
TAG_DONE);
|
||||
|
||||
if(enabled) {
|
||||
SocketFeatures |= HAVE_BSDSOCKET_GETHOSTBYNAME_R;
|
||||
}
|
||||
|
||||
__CurlISocket = ISocket;
|
||||
|
||||
atexit(Curl_amiga_cleanup);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
CloseLibrary(base);
|
||||
}
|
||||
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
void Curl_amiga_cleanup(void)
|
||||
{
|
||||
if(__CurlISocket) {
|
||||
struct Library *base = __CurlISocket->Data.LibBase;
|
||||
DropInterface((struct Interface *)__CurlISocket);
|
||||
CloseLibrary(base);
|
||||
__CurlISocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CURLRES_AMIGA
|
||||
/*
|
||||
* Because we need to handle the different cases in hostip4.c at runtime,
|
||||
* not at compile-time, based on what was detected in Curl_amiga_init(),
|
||||
* we replace it completely with our own as to not complicate the baseline
|
||||
* code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()
|
||||
* allocates memory also.
|
||||
*/
|
||||
|
||||
struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
||||
int port)
|
||||
{
|
||||
struct Curl_addrinfo *ai = NULL;
|
||||
struct hostent *h;
|
||||
struct SocketIFace *ISocket = __CurlISocket;
|
||||
|
||||
if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) {
|
||||
LONG h_errnop = 0;
|
||||
struct hostent *buf;
|
||||
|
||||
buf = calloc(1, CURL_HOSTENT_SIZE);
|
||||
if(buf) {
|
||||
h = gethostbyname_r((STRPTR)hostname, buf,
|
||||
(char *)buf + sizeof(struct hostent),
|
||||
CURL_HOSTENT_SIZE - sizeof(struct hostent),
|
||||
&h_errnop);
|
||||
if(h) {
|
||||
ai = Curl_he2ai(h, port);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef CURLRES_THREADED
|
||||
/* gethostbyname() is not thread safe, so we need to reopen bsdsocket
|
||||
* on the thread's context
|
||||
*/
|
||||
struct Library *base = OpenLibrary("bsdsocket.library", 4);
|
||||
if(base) {
|
||||
ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
|
||||
if(ISocket) {
|
||||
h = gethostbyname((STRPTR)hostname);
|
||||
if(h) {
|
||||
ai = Curl_he2ai(h, port);
|
||||
}
|
||||
DropInterface((struct Interface *)ISocket);
|
||||
}
|
||||
CloseLibrary(base);
|
||||
}
|
||||
#else
|
||||
/* not using threaded resolver - safe to use this as-is */
|
||||
h = gethostbyname(hostname);
|
||||
if(h) {
|
||||
ai = Curl_he2ai(h, port);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
#endif /* CURLRES_AMIGA */
|
||||
|
||||
#ifdef USE_AMISSL
|
||||
#include <signal.h>
|
||||
int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, struct timeval *timeout)
|
||||
{
|
||||
int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0);
|
||||
/* Ensure Ctrl-C signal is actioned */
|
||||
if((r == -1) && (SOCKERRNO == SOCKEINTR))
|
||||
raise(SIGINT);
|
||||
return r;
|
||||
}
|
||||
#endif /* USE_AMISSL */
|
||||
|
||||
#elif !defined(USE_AMISSL) /* __amigaos4__ */
|
||||
/*
|
||||
* Amiga OS3 specific code
|
||||
*/
|
||||
|
||||
struct Library *SocketBase = NULL;
|
||||
|
||||
#ifdef __libnix__
|
||||
void __request(const char *msg);
|
||||
#define CURL_AMIGA_REQUEST(msg) __request(msg)
|
||||
#else
|
||||
#define CURL_AMIGA_REQUEST(msg) Printf((const unsigned char *)(msg "\n\a"), 0)
|
||||
#endif
|
||||
|
||||
void Curl_amiga_cleanup(void)
|
||||
{
|
||||
if(SocketBase) {
|
||||
CloseLibrary(SocketBase);
|
||||
SocketBase = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_amiga_init(void)
|
||||
{
|
||||
if(!SocketBase)
|
||||
SocketBase = OpenLibrary((const unsigned char *)"bsdsocket.library", 4);
|
||||
|
||||
if(!SocketBase) {
|
||||
CURL_AMIGA_REQUEST("No TCP/IP Stack running!");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG)&errno,
|
||||
SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG)"curl",
|
||||
TAG_DONE)) {
|
||||
CURL_AMIGA_REQUEST("SocketBaseTags ERROR");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
#ifndef __libnix__
|
||||
atexit(Curl_amiga_cleanup);
|
||||
#endif
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifdef __libnix__
|
||||
ADD2EXIT(Curl_amiga_cleanup, -50);
|
||||
#endif
|
||||
|
||||
#endif /* !USE_AMISSL */
|
||||
|
||||
#endif /* HAVE_PROTO_BSDSOCKET_H */
|
||||
|
||||
#endif /* __AMIGA__ */
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
#ifndef HEADER_CURL_AMIGAOS_H
|
||||
#define HEADER_CURL_AMIGAOS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if defined(__AMIGA__) && defined(HAVE_PROTO_BSDSOCKET_H) && \
|
||||
(!defined(USE_AMISSL) || defined(__amigaos4__))
|
||||
|
||||
CURLcode Curl_amiga_init(void);
|
||||
void Curl_amiga_cleanup(void);
|
||||
|
||||
#else
|
||||
|
||||
#define Curl_amiga_init() CURLE_OK
|
||||
#define Curl_amiga_cleanup() Curl_nop_stmt
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_AMIGAOS_H */
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#ifndef HEADER_CURL_ARPA_TELNET_H
|
||||
#define HEADER_CURL_ARPA_TELNET_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
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifndef CURL_DISABLE_TELNET
|
||||
/*
|
||||
* Telnet option defines. Add more here if in need.
|
||||
*/
|
||||
#define CURL_TELOPT_BINARY 0 /* binary 8bit data */
|
||||
#define CURL_TELOPT_ECHO 1 /* just echo! */
|
||||
#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */
|
||||
#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */
|
||||
#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */
|
||||
#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */
|
||||
#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
|
||||
|
||||
#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
|
||||
#define CURL_NEW_ENV_VAR 0
|
||||
#define CURL_NEW_ENV_VALUE 1
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
/*
|
||||
* The telnet options represented as strings
|
||||
*/
|
||||
static const char * const telnetoptions[]=
|
||||
{
|
||||
"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD",
|
||||
"NAME", "STATUS", "TIMING MARK", "RCTE",
|
||||
"NAOL", "NAOP", "NAOCRD", "NAOHTS",
|
||||
"NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD",
|
||||
"NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
|
||||
"DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION",
|
||||
"TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING",
|
||||
"TTYLOC", "3270 REGIME", "X3 PAD", "NAWS",
|
||||
"TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
|
||||
"OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
|
||||
};
|
||||
#define CURL_TELOPT(x) telnetoptions[x]
|
||||
#else
|
||||
#define CURL_TELOPT(x) ""
|
||||
#endif
|
||||
|
||||
#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
|
||||
|
||||
#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
|
||||
|
||||
#define CURL_NTELOPTS 40
|
||||
|
||||
/*
|
||||
* First some defines
|
||||
*/
|
||||
#define CURL_xEOF 236 /* End Of File */
|
||||
#define CURL_SE 240 /* Sub negotiation End */
|
||||
#define CURL_NOP 241 /* No OPeration */
|
||||
#define CURL_DM 242 /* Data Mark */
|
||||
#define CURL_GA 249 /* Go Ahead, reverse the line */
|
||||
#define CURL_SB 250 /* SuBnegotiation */
|
||||
#define CURL_WILL 251 /* Our side WILL use this option */
|
||||
#define CURL_WONT 252 /* Our side will not use this option */
|
||||
#define CURL_DO 253 /* DO use this option! */
|
||||
#define CURL_DONT 254 /* DON'T use this option! */
|
||||
#define CURL_IAC 255 /* Interpret As Command */
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
/*
|
||||
* Then those numbers represented as strings:
|
||||
*/
|
||||
static const char * const telnetcmds[]=
|
||||
{
|
||||
"EOF", "SUSP", "ABORT", "EOR", "SE",
|
||||
"NOP", "DMARK", "BRK", "IP", "AO",
|
||||
"AYT", "EC", "EL", "GA", "SB",
|
||||
"WILL", "WONT", "DO", "DONT", "IAC"
|
||||
};
|
||||
#endif
|
||||
|
||||
#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
|
||||
#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
|
||||
|
||||
#define CURL_TELQUAL_IS 0
|
||||
#define CURL_TELQUAL_SEND 1
|
||||
#define CURL_TELQUAL_INFO 2
|
||||
#define CURL_TELQUAL_NAME 3
|
||||
|
||||
#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
|
||||
((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
|
||||
#else
|
||||
#define CURL_TELCMD(x) ""
|
||||
#endif
|
||||
|
||||
#endif /* CURL_DISABLE_TELNET */
|
||||
|
||||
#endif /* HEADER_CURL_ARPA_TELNET_H */
|
||||
Vendored
+986
@@ -0,0 +1,986 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 CURLRES_ARES
|
||||
|
||||
/***********************************************************************
|
||||
* Only for ares-enabled builds
|
||||
* And only for functions that fulfill the asynch resolver backend API
|
||||
* as defined in asyn.h, nothing else belongs in this file!
|
||||
**********************************************************************/
|
||||
|
||||
#include <limits.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
|
||||
|
||||
#include "urldata.h"
|
||||
#include "cfilters.h"
|
||||
#include "sendf.h"
|
||||
#include "hostip.h"
|
||||
#include "hash.h"
|
||||
#include "share.h"
|
||||
#include "url.h"
|
||||
#include "multiif.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "connect.h"
|
||||
#include "select.h"
|
||||
#include "progress.h"
|
||||
#include "curlx/timediff.h"
|
||||
#include "httpsrr.h"
|
||||
|
||||
#include <ares.h>
|
||||
#include <ares_version.h> /* really old c-ares did not include this by
|
||||
itself */
|
||||
|
||||
#if ARES_VERSION >= 0x010601
|
||||
/* IPv6 supported since 1.6.1 */
|
||||
#define HAVE_CARES_IPV6 1
|
||||
#endif
|
||||
|
||||
#if ARES_VERSION >= 0x010704
|
||||
#define HAVE_CARES_SERVERS_CSV 1
|
||||
#define HAVE_CARES_LOCAL_DEV 1
|
||||
#define HAVE_CARES_SET_LOCAL 1
|
||||
#endif
|
||||
|
||||
#if ARES_VERSION >= 0x010b00
|
||||
#define HAVE_CARES_PORTS_CSV 1
|
||||
#endif
|
||||
|
||||
#if ARES_VERSION >= 0x011000
|
||||
/* 1.16.0 or later has ares_getaddrinfo */
|
||||
#define HAVE_CARES_GETADDRINFO 1
|
||||
#else
|
||||
/* How long we are willing to wait for additional parallel responses after
|
||||
obtaining a "definitive" one. For old c-ares without getaddrinfo.
|
||||
|
||||
This is intended to equal the c-ares default timeout. cURL always uses that
|
||||
default value. Unfortunately, c-ares does not expose its default timeout in
|
||||
its API, but it is officially documented as 5 seconds.
|
||||
|
||||
See query_completed_cb() for an explanation of how this is used.
|
||||
*/
|
||||
#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
|
||||
#endif
|
||||
|
||||
#ifdef USE_HTTPSRR
|
||||
#if ARES_VERSION < 0x011c00
|
||||
#error "requires c-ares 1.28.0 or newer for HTTPSRR"
|
||||
#endif
|
||||
#define HTTPSRR_WORKS
|
||||
#endif
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define CARES_TIMEOUT_PER_ATTEMPT 2000
|
||||
|
||||
static int ares_ver = 0;
|
||||
|
||||
static CURLcode async_ares_set_dns_servers(struct Curl_easy *data,
|
||||
bool reset_on_null);
|
||||
|
||||
/*
|
||||
* Curl_async_global_init() - the generic low-level asynchronous name
|
||||
* resolve API. Called from curl_global_init() to initialize global resolver
|
||||
* environment. Initializes ares library.
|
||||
*/
|
||||
int Curl_async_global_init(void)
|
||||
{
|
||||
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
|
||||
if(ares_library_init(ARES_LIB_INIT_ALL)) {
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#endif
|
||||
ares_version(&ares_ver);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_global_cleanup()
|
||||
*
|
||||
* Called from curl_global_cleanup() to destroy global resolver environment.
|
||||
* Deinitializes ares library.
|
||||
*/
|
||||
void Curl_async_global_cleanup(void)
|
||||
{
|
||||
#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
|
||||
ares_library_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void sock_state_cb(void *data, ares_socket_t socket_fd,
|
||||
int readable, int writable)
|
||||
{
|
||||
struct Curl_easy *easy = data;
|
||||
if(!readable && !writable) {
|
||||
DEBUGASSERT(easy);
|
||||
Curl_multi_will_close(easy, socket_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode async_ares_init(struct Curl_easy *data)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
int status;
|
||||
struct ares_options options;
|
||||
int optmask = ARES_OPT_SOCK_STATE_CB;
|
||||
CURLcode rc = CURLE_OK;
|
||||
|
||||
options.sock_state_cb = sock_state_cb;
|
||||
options.sock_state_cb_data = data;
|
||||
|
||||
DEBUGASSERT(!ares->channel);
|
||||
/*
|
||||
if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s)
|
||||
|
||||
if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need
|
||||
to set the timeout value;
|
||||
|
||||
if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to
|
||||
overwrite c-ares' timeout.
|
||||
*/
|
||||
DEBUGASSERT(ares_ver);
|
||||
if(ares_ver < 0x011400) {
|
||||
options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
|
||||
optmask |= ARES_OPT_TIMEOUTMS;
|
||||
}
|
||||
|
||||
status = ares_init_options(&ares->channel, &options, optmask);
|
||||
if(status != ARES_SUCCESS) {
|
||||
ares->channel = NULL;
|
||||
rc = (status == ARES_ENOMEM) ?
|
||||
CURLE_OUT_OF_MEMORY : CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = async_ares_set_dns_servers(data, FALSE);
|
||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||
goto out;
|
||||
|
||||
rc = Curl_async_ares_set_dns_interface(data);
|
||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||
goto out;
|
||||
|
||||
rc = Curl_async_ares_set_dns_local_ip4(data);
|
||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||
goto out;
|
||||
|
||||
rc = Curl_async_ares_set_dns_local_ip6(data);
|
||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||
goto out;
|
||||
|
||||
rc = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(rc && ares->channel) {
|
||||
ares_destroy(ares->channel);
|
||||
ares->channel = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static CURLcode async_ares_init_lazy(struct Curl_easy *data)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
if(!ares->channel)
|
||||
return async_ares_init(data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
CURLcode result = CURLE_OK;
|
||||
if(!ares->channel) {
|
||||
result = async_ares_init(data);
|
||||
}
|
||||
*impl = ares->channel;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* async_ares_cleanup() cleans up async resolver data.
|
||||
*/
|
||||
static void async_ares_cleanup(struct Curl_easy *data)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
if(ares->temp_ai) {
|
||||
Curl_freeaddrinfo(ares->temp_ai);
|
||||
ares->temp_ai = NULL;
|
||||
}
|
||||
#ifdef USE_HTTPSRR
|
||||
Curl_httpsrr_cleanup(&ares->hinfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Curl_async_ares_shutdown(struct Curl_easy *data)
|
||||
{
|
||||
/* c-ares has a method to "cancel" operations on a channel, but
|
||||
* as reported in #18216, this does not totally reset the channel
|
||||
* and ares may get stuck.
|
||||
* We need to destroy the channel and on demand create a new
|
||||
* one to avoid that. */
|
||||
Curl_async_ares_destroy(data);
|
||||
}
|
||||
|
||||
void Curl_async_ares_destroy(struct Curl_easy *data)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
if(ares->channel) {
|
||||
ares_destroy(ares->channel);
|
||||
ares->channel = NULL;
|
||||
}
|
||||
async_ares_cleanup(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_pollset() is called when someone from the outside world
|
||||
* (using curl_multi_fdset()) wants to get our fd_set setup.
|
||||
*/
|
||||
|
||||
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
if(ares->channel)
|
||||
return Curl_ares_pollset(data, ares->channel, ps);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Returns normal CURLcode errors.
|
||||
*/
|
||||
CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **dns)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(dns);
|
||||
*dns = NULL;
|
||||
|
||||
if(data->state.async.done) {
|
||||
*dns = data->state.async.dns;
|
||||
return ares->result;
|
||||
}
|
||||
|
||||
if(Curl_ares_perform(ares->channel, 0) < 0) {
|
||||
result = CURLE_UNRECOVERABLE_POLL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CARES_GETADDRINFO
|
||||
/* Now that we have checked for any last minute results above, see if there
|
||||
are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
|
||||
expires. */
|
||||
if(ares->num_pending
|
||||
/* This is only set to non-zero if the timer was started. */
|
||||
&& (ares->happy_eyeballs_dns_time.tv_sec
|
||||
|| ares->happy_eyeballs_dns_time.tv_usec)
|
||||
&& (curlx_timediff(curlx_now(), ares->happy_eyeballs_dns_time)
|
||||
>= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
|
||||
/* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
|
||||
running. */
|
||||
memset(&ares->happy_eyeballs_dns_time, 0,
|
||||
sizeof(ares->happy_eyeballs_dns_time));
|
||||
|
||||
/* Cancel the raw c-ares request, which will fire query_completed_cb() with
|
||||
ARES_ECANCELLED synchronously for all pending responses. This will
|
||||
leave us with res->num_pending == 0, which is perfect for the next
|
||||
block. */
|
||||
ares_cancel(ares->channel);
|
||||
DEBUGASSERT(ares->num_pending == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!ares->num_pending) {
|
||||
/* all c-ares operations done, what is the result to report? */
|
||||
Curl_resolv_unlink(data, &data->state.async.dns);
|
||||
data->state.async.done = TRUE;
|
||||
result = ares->result;
|
||||
if(ares->ares_status == ARES_SUCCESS && !result) {
|
||||
data->state.async.dns =
|
||||
Curl_dnscache_mk_entry(data, ares->temp_ai,
|
||||
data->state.async.hostname, 0,
|
||||
data->state.async.port, FALSE);
|
||||
ares->temp_ai = NULL; /* temp_ai now owned by entry */
|
||||
#ifdef HTTPSRR_WORKS
|
||||
if(data->state.async.dns) {
|
||||
struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->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 we have not found anything, report the proper
|
||||
* CURLE_COULDNT_RESOLVE_* code */
|
||||
if(!result && !data->state.async.dns) {
|
||||
const char *msg = NULL;
|
||||
if(ares->ares_status != ARES_SUCCESS)
|
||||
msg = ares_strerror(ares->ares_status);
|
||||
result = Curl_resolver_error(data, msg);
|
||||
}
|
||||
|
||||
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_ares_cleanup(data);
|
||||
}
|
||||
|
||||
out:
|
||||
ares->result = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_await()
|
||||
*
|
||||
* Waits for a resolve to finish. This function should be avoided since using
|
||||
* this risk getting the multi interface to "hang".
|
||||
*
|
||||
* 'entry' MUST be non-NULL.
|
||||
*
|
||||
* Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
|
||||
* CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
|
||||
*/
|
||||
CURLcode Curl_async_await(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **entry)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
CURLcode result = CURLE_OK;
|
||||
timediff_t timeout;
|
||||
struct curltime now = curlx_now();
|
||||
|
||||
DEBUGASSERT(entry);
|
||||
*entry = NULL; /* clear on entry */
|
||||
|
||||
timeout = Curl_timeleft(data, &now, TRUE);
|
||||
if(timeout < 0) {
|
||||
/* already expired! */
|
||||
connclose(data->conn, "Timed out before name resolve started");
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
if(!timeout)
|
||||
timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
|
||||
|
||||
/* Wait for the name resolve query to complete. */
|
||||
while(!result) {
|
||||
struct timeval *tvp, tv, store;
|
||||
int itimeout;
|
||||
timediff_t timeout_ms;
|
||||
|
||||
#if TIMEDIFF_T_MAX > INT_MAX
|
||||
itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
|
||||
#else
|
||||
itimeout = (int)timeout;
|
||||
#endif
|
||||
|
||||
store.tv_sec = itimeout/1000;
|
||||
store.tv_usec = (itimeout%1000)*1000;
|
||||
|
||||
tvp = ares_timeout(ares->channel, &store, &tv);
|
||||
|
||||
/* use the timeout period ares returned to us above if less than one
|
||||
second is left, otherwise just use 1000ms to make sure the progress
|
||||
callback gets called frequent enough */
|
||||
if(!tvp->tv_sec)
|
||||
timeout_ms = (timediff_t)(tvp->tv_usec/1000);
|
||||
else
|
||||
timeout_ms = 1000;
|
||||
|
||||
if(Curl_ares_perform(ares->channel, timeout_ms) < 0)
|
||||
return CURLE_UNRECOVERABLE_POLL;
|
||||
|
||||
result = Curl_async_is_resolved(data, entry);
|
||||
if(result || data->state.async.done)
|
||||
break;
|
||||
|
||||
if(Curl_pgrsUpdate(data))
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
else {
|
||||
struct curltime now2 = curlx_now();
|
||||
timediff_t timediff = curlx_timediff(now2, now); /* spent time */
|
||||
if(timediff <= 0)
|
||||
timeout -= 1; /* always deduct at least 1 */
|
||||
else if(timediff > timeout)
|
||||
timeout = -1;
|
||||
else
|
||||
timeout -= timediff;
|
||||
now = now2; /* for next loop */
|
||||
}
|
||||
if(timeout < 0)
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
/* Operation complete, if the lookup was successful we now have the entry
|
||||
in the cache. */
|
||||
data->state.async.done = TRUE;
|
||||
*entry = data->state.async.dns;
|
||||
|
||||
if(result)
|
||||
ares_cancel(ares->channel);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CARES_GETADDRINFO
|
||||
|
||||
/* Connects results to the list */
|
||||
static void async_addr_concat(struct Curl_addrinfo **pbase,
|
||||
struct Curl_addrinfo *ai)
|
||||
{
|
||||
if(!ai)
|
||||
return;
|
||||
|
||||
/* When adding `ai` to an existing address list, we prefer ipv6
|
||||
* to be in front. */
|
||||
#ifdef USE_IPV6 /* CURLRES_IPV6 */
|
||||
if(*pbase && (*pbase)->ai_family == PF_INET6) {
|
||||
/* ipv6 already in front, append `ai` */
|
||||
struct Curl_addrinfo *tail = *pbase;
|
||||
while(tail->ai_next)
|
||||
tail = tail->ai_next;
|
||||
tail->ai_next = ai;
|
||||
}
|
||||
else
|
||||
#endif /* CURLRES_IPV6 */
|
||||
{
|
||||
/* prepend to the (possibly) existing list. */
|
||||
struct Curl_addrinfo *tail = ai;
|
||||
while(tail->ai_next)
|
||||
tail = tail->ai_next;
|
||||
tail->ai_next = *pbase;
|
||||
*pbase = ai;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ares_query_completed_cb() is the callback that ares will call when
|
||||
* the host query initiated by ares_gethostbyname() from
|
||||
* Curl_async_getaddrinfo(), when using ares, is completed either
|
||||
* successfully or with failure.
|
||||
*/
|
||||
static void async_ares_hostbyname_cb(void *user_data,
|
||||
int status,
|
||||
int timeouts,
|
||||
struct hostent *hostent)
|
||||
{
|
||||
struct Curl_easy *data = (struct Curl_easy *)user_data;
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
|
||||
(void)timeouts; /* ignored */
|
||||
|
||||
if(ARES_EDESTRUCTION == status)
|
||||
return;
|
||||
|
||||
if(ARES_SUCCESS == status) {
|
||||
ares->ares_status = status; /* one success overrules any error */
|
||||
async_addr_concat(&ares->temp_ai,
|
||||
Curl_he2ai(hostent, data->state.async.port));
|
||||
}
|
||||
else if(ares->ares_status != ARES_SUCCESS) {
|
||||
/* no success so far, remember last error */
|
||||
ares->ares_status = status;
|
||||
}
|
||||
|
||||
ares->num_pending--;
|
||||
|
||||
CURL_TRC_DNS(data, "ares: hostbyname done, status=%d, pending=%d, "
|
||||
"addr=%sfound",
|
||||
status, ares->num_pending, ares->temp_ai ? "" : "not ");
|
||||
/* If there are responses still pending, we presume they must be the
|
||||
complementary IPv4 or IPv6 lookups that we started in parallel in
|
||||
Curl_async_getaddrinfo() (for Happy Eyeballs). If we have got a
|
||||
"definitive" response from one of a set of parallel queries, we need to
|
||||
think about how long we are willing to wait for more responses. */
|
||||
if(ares->num_pending
|
||||
/* Only these c-ares status values count as "definitive" for these
|
||||
purposes. For example, ARES_ENODATA is what we expect when there is
|
||||
no IPv6 entry for a domain name, and that is not a reason to get more
|
||||
aggressive in our timeouts for the other response. Other errors are
|
||||
either a result of bad input (which should affect all parallel
|
||||
requests), local or network conditions, non-definitive server
|
||||
responses, or us cancelling the request. */
|
||||
&& (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
|
||||
/* Right now, there can only be up to two parallel queries, so do not
|
||||
bother handling any other cases. */
|
||||
DEBUGASSERT(ares->num_pending == 1);
|
||||
|
||||
/* it is possible that one of these parallel queries could succeed
|
||||
quickly, but the other could always fail or timeout (when we are
|
||||
talking to a pool of DNS servers that can only successfully resolve
|
||||
IPv4 address, for example).
|
||||
|
||||
it is also possible that the other request could always just take
|
||||
longer because it needs more time or only the second DNS server can
|
||||
fulfill it successfully. But, to align with the philosophy of Happy
|
||||
Eyeballs, we do not want to wait _too_ long or users will think
|
||||
requests are slow when IPv6 lookups do not actually work (but IPv4
|
||||
ones do).
|
||||
|
||||
So, now that we have a usable answer (some IPv4 addresses, some IPv6
|
||||
addresses, or "no such domain"), we start a timeout for the remaining
|
||||
pending responses. Even though it is typical that this resolved
|
||||
request came back quickly, that needn't be the case. It might be that
|
||||
this completing request did not get a result from the first DNS
|
||||
server or even the first round of the whole DNS server pool. So it
|
||||
could already be quite some time after we issued the DNS queries in
|
||||
the first place. Without modifying c-ares, we cannot know exactly
|
||||
where in its retry cycle we are. We could guess based on how much
|
||||
time has gone by, but it does not really matter. Happy Eyeballs tells
|
||||
us that, given usable information in hand, we simply do not want to
|
||||
wait "too much longer" after we get a result.
|
||||
|
||||
We simply wait an additional amount of time equal to the default
|
||||
c-ares query timeout. That is enough time for a typical parallel
|
||||
response to arrive without being "too long". Even on a network
|
||||
where one of the two types of queries is failing or timing out
|
||||
constantly, this will usually mean we wait a total of the default
|
||||
c-ares timeout (5 seconds) plus the round trip time for the successful
|
||||
request, which seems bearable. The downside is that c-ares might race
|
||||
with us to issue one more retry just before we give up, but it seems
|
||||
better to "waste" that request instead of trying to guess the perfect
|
||||
timeout to prevent it. After all, we do not even know where in the
|
||||
c-ares retry cycle each request is.
|
||||
*/
|
||||
ares->happy_eyeballs_dns_time = curlx_now();
|
||||
Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
|
||||
EXPIRE_HAPPY_EYEBALLS_DNS);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* c-ares 1.16.0 or later */
|
||||
|
||||
/*
|
||||
* async_ares_node2addr() converts an address list provided by c-ares
|
||||
* to an internal libcurl compatible list.
|
||||
*/
|
||||
static struct Curl_addrinfo *
|
||||
async_ares_node2addr(struct ares_addrinfo_node *node)
|
||||
{
|
||||
/* traverse the ares_addrinfo_node list */
|
||||
struct ares_addrinfo_node *ai;
|
||||
struct Curl_addrinfo *cafirst = NULL;
|
||||
struct Curl_addrinfo *calast = NULL;
|
||||
int error = 0;
|
||||
|
||||
for(ai = node; ai != NULL; ai = ai->ai_next) {
|
||||
size_t ss_size;
|
||||
struct Curl_addrinfo *ca;
|
||||
/* ignore elements with unsupported address family, */
|
||||
/* settle family-specific sockaddr structure size. */
|
||||
if(ai->ai_family == AF_INET)
|
||||
ss_size = sizeof(struct sockaddr_in);
|
||||
#ifdef USE_IPV6
|
||||
else if(ai->ai_family == AF_INET6)
|
||||
ss_size = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
else
|
||||
continue;
|
||||
|
||||
/* ignore elements without required address info */
|
||||
if(!ai->ai_addr || !(ai->ai_addrlen > 0))
|
||||
continue;
|
||||
|
||||
/* ignore elements with bogus address size */
|
||||
if((size_t)ai->ai_addrlen < ss_size)
|
||||
continue;
|
||||
|
||||
ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
|
||||
if(!ca) {
|
||||
error = EAI_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy each structure member individually, member ordering, */
|
||||
/* size, or padding might be different for each platform. */
|
||||
|
||||
ca->ai_flags = ai->ai_flags;
|
||||
ca->ai_family = ai->ai_family;
|
||||
ca->ai_socktype = ai->ai_socktype;
|
||||
ca->ai_protocol = ai->ai_protocol;
|
||||
ca->ai_addrlen = (curl_socklen_t)ss_size;
|
||||
ca->ai_addr = NULL;
|
||||
ca->ai_canonname = NULL;
|
||||
ca->ai_next = NULL;
|
||||
|
||||
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
|
||||
memcpy(ca->ai_addr, ai->ai_addr, ss_size);
|
||||
|
||||
/* if the return list is empty, this becomes the first element */
|
||||
if(!cafirst)
|
||||
cafirst = ca;
|
||||
|
||||
/* add this element last in the return list */
|
||||
if(calast)
|
||||
calast->ai_next = ca;
|
||||
calast = ca;
|
||||
}
|
||||
|
||||
/* if we failed, destroy the Curl_addrinfo list */
|
||||
if(error) {
|
||||
Curl_freeaddrinfo(cafirst);
|
||||
cafirst = NULL;
|
||||
}
|
||||
|
||||
return cafirst;
|
||||
}
|
||||
|
||||
static void async_ares_addrinfo_cb(void *user_data, int status, int timeouts,
|
||||
struct ares_addrinfo *ares_ai)
|
||||
{
|
||||
struct Curl_easy *data = (struct Curl_easy *)user_data;
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
(void)timeouts;
|
||||
if(ares->ares_status != ARES_SUCCESS) /* do not overwrite success */
|
||||
ares->ares_status = status;
|
||||
if(status == ARES_SUCCESS) {
|
||||
ares->temp_ai = async_ares_node2addr(ares_ai->nodes);
|
||||
ares_freeaddrinfo(ares_ai);
|
||||
}
|
||||
ares->num_pending--;
|
||||
CURL_TRC_DNS(data, "ares: addrinfo done, query status=%d, "
|
||||
"overall status=%d, pending=%d, addr=%sfound",
|
||||
status, ares->ares_status, ares->num_pending,
|
||||
ares->temp_ai ? "" : "not ");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_HTTPSRR
|
||||
static void async_ares_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_ares_ctx *ares = &data->state.async.ares;
|
||||
|
||||
(void)timeouts;
|
||||
--ares->num_pending;
|
||||
CURL_TRC_DNS(data, "ares: httpsrr done, status=%d, pending=%d, "
|
||||
"dnsres=%sfound",
|
||||
status, ares->num_pending,
|
||||
(dnsrec &&
|
||||
ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER)) ?
|
||||
"" : "not ");
|
||||
if((ARES_SUCCESS != status) || !dnsrec)
|
||||
return;
|
||||
ares->result = Curl_httpsrr_from_ares(data, dnsrec, &ares->hinfo);
|
||||
}
|
||||
#endif /* USE_HTTPSRR */
|
||||
|
||||
/*
|
||||
* Curl_async_getaddrinfo() - when using ares
|
||||
*
|
||||
* Returns name information about the given hostname and port number. If
|
||||
* successful, the 'hostent' is returned and the fourth argument will point to
|
||||
* memory we need to free after use. That memory *MUST* be freed with
|
||||
* Curl_freeaddrinfo(), nothing else.
|
||||
*/
|
||||
struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
int port,
|
||||
int ip_version,
|
||||
int *waitp)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
#ifdef USE_HTTPSRR
|
||||
char *rrname = NULL;
|
||||
#endif
|
||||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
if(async_ares_init_lazy(data))
|
||||
return NULL;
|
||||
|
||||
data->state.async.done = FALSE; /* not done */
|
||||
data->state.async.dns = NULL; /* clear */
|
||||
data->state.async.port = port;
|
||||
data->state.async.ip_version = ip_version;
|
||||
data->state.async.hostname = strdup(hostname);
|
||||
if(!data->state.async.hostname)
|
||||
return NULL;
|
||||
#ifdef USE_HTTPSRR
|
||||
if(port != 443) {
|
||||
rrname = curl_maprintf("_%d_.https.%s", port, hostname);
|
||||
if(!rrname) {
|
||||
free(data->state.async.hostname);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initial status - failed */
|
||||
ares->ares_status = ARES_ENOTFOUND;
|
||||
ares->result = CURLE_OK;
|
||||
|
||||
#if !defined(CURL_DISABLE_VERBOSE_STRINGS) && \
|
||||
ARES_VERSION >= 0x011800 /* >= v1.24.0 */
|
||||
if(CURL_TRC_DNS_is_verbose(data)) {
|
||||
char *csv = ares_get_servers_csv(ares->channel);
|
||||
CURL_TRC_DNS(data, "asyn-ares: servers=%s", csv);
|
||||
ares_free_string(csv);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CARES_GETADDRINFO
|
||||
{
|
||||
struct ares_addrinfo_hints hints;
|
||||
char service[12];
|
||||
int pf = PF_INET;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
#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;
|
||||
}
|
||||
#endif /* CURLRES_IPV6 */
|
||||
CURL_TRC_DNS(data, "asyn-ares: fire off getaddrinfo for %s",
|
||||
(pf == PF_UNSPEC) ? "A+AAAA" :
|
||||
((pf == PF_INET) ? "A" : "AAAA"));
|
||||
hints.ai_family = pf;
|
||||
hints.ai_socktype =
|
||||
(Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
|
||||
SOCK_STREAM : SOCK_DGRAM;
|
||||
/* Since the service is a numerical one, set the hint flags
|
||||
* accordingly to save a call to getservbyname in inside C-Ares
|
||||
*/
|
||||
hints.ai_flags = ARES_AI_NUMERICSERV;
|
||||
curl_msnprintf(service, sizeof(service), "%d", port);
|
||||
ares->num_pending = 1;
|
||||
ares_getaddrinfo(ares->channel, data->state.async.hostname,
|
||||
service, &hints, async_ares_addrinfo_cb, data);
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef HAVE_CARES_IPV6
|
||||
if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
CURL_TRC_DNS(data, "asyn-ares: fire off query for A");
|
||||
ares_gethostbyname(ares->channel, data->state.async.hostname, PF_INET,
|
||||
async_ares_hostbyname_cb, data);
|
||||
CURL_TRC_DNS(data, "asyn-ares: fire off query for AAAA");
|
||||
ares->num_pending = 2;
|
||||
ares_gethostbyname(ares->channel, data->state.async.hostname, PF_INET6,
|
||||
async_ares_hostbyname_cb, data);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* areschannel is already setup in the Curl_open() function */
|
||||
CURL_TRC_DNS(data, "asyn-ares: fire off query for A");
|
||||
ares->num_pending = 1;
|
||||
ares_gethostbyname(ares->channel, data->state.async.hostname, PF_INET,
|
||||
async_ares_hostbyname_cb, data);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_HTTPSRR
|
||||
{
|
||||
CURL_TRC_DNS(data, "asyn-ares: fire off query for HTTPSRR: %s",
|
||||
rrname ? rrname : data->state.async.hostname);
|
||||
memset(&ares->hinfo, 0, sizeof(ares->hinfo));
|
||||
ares->hinfo.port = -1;
|
||||
ares->hinfo.rrname = rrname;
|
||||
ares->num_pending++; /* one more */
|
||||
ares_query_dnsrec(ares->channel,
|
||||
rrname ? rrname : data->state.async.hostname,
|
||||
ARES_CLASS_IN, ARES_REC_TYPE_HTTPS,
|
||||
async_ares_rr_done, data, NULL);
|
||||
}
|
||||
#endif
|
||||
*waitp = 1; /* expect asynchronous response */
|
||||
|
||||
return NULL; /* no struct yet */
|
||||
}
|
||||
|
||||
/* Set what DNS server are is to use. This is called in 2 situations:
|
||||
* 1. when the application does 'CURLOPT_DNS_SERVERS' and passing NULL
|
||||
* means any previous set value should be unset. Which means
|
||||
* we need to destroy and create the are channel anew, if there is one.
|
||||
* 2. When we lazy init the ares channel and NULL means that there
|
||||
* are no preferences and we do not reset any existing channel. */
|
||||
static CURLcode async_ares_set_dns_servers(struct Curl_easy *data,
|
||||
bool reset_on_null)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
CURLcode result = CURLE_NOT_BUILT_IN;
|
||||
const char *servers = data->set.str[STRING_DNS_SERVERS];
|
||||
int ares_result = ARES_SUCCESS;
|
||||
|
||||
#if defined(CURLDEBUG) && defined(HAVE_CARES_SERVERS_CSV)
|
||||
if(getenv("CURL_DNS_SERVER"))
|
||||
servers = getenv("CURL_DNS_SERVER");
|
||||
#endif
|
||||
|
||||
if(!servers) {
|
||||
if(reset_on_null) {
|
||||
Curl_async_destroy(data);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CARES_SERVERS_CSV
|
||||
/* if channel is not there, this is just a parameter check */
|
||||
if(ares->channel)
|
||||
#ifdef HAVE_CARES_PORTS_CSV
|
||||
ares_result = ares_set_servers_ports_csv(ares->channel, servers);
|
||||
#else
|
||||
ares_result = ares_set_servers_csv(ares->channel, servers);
|
||||
#endif
|
||||
switch(ares_result) {
|
||||
case ARES_SUCCESS:
|
||||
result = CURLE_OK;
|
||||
break;
|
||||
case ARES_ENOMEM:
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
case ARES_ENOTINITIALIZED:
|
||||
case ARES_ENODATA:
|
||||
case ARES_EBADSTR:
|
||||
default:
|
||||
DEBUGF(infof(data, "bad servers set"));
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
break;
|
||||
}
|
||||
#else /* too old c-ares version! */
|
||||
(void)data;
|
||||
(void)(ares_result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_async_ares_set_dns_servers(struct Curl_easy *data)
|
||||
{
|
||||
return async_ares_set_dns_servers(data, TRUE);
|
||||
}
|
||||
|
||||
CURLcode Curl_async_ares_set_dns_interface(struct Curl_easy *data)
|
||||
{
|
||||
#ifdef HAVE_CARES_LOCAL_DEV
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
const char *interf = data->set.str[STRING_DNS_INTERFACE];
|
||||
|
||||
if(!interf)
|
||||
interf = "";
|
||||
|
||||
/* if channel is not there, this is just a parameter check */
|
||||
if(ares->channel)
|
||||
ares_set_local_dev(ares->channel, interf);
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
(void)interf;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_async_ares_set_dns_local_ip4(struct Curl_easy *data)
|
||||
{
|
||||
#ifdef HAVE_CARES_SET_LOCAL
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
struct in_addr a4;
|
||||
const char *local_ip4 = data->set.str[STRING_DNS_LOCAL_IP4];
|
||||
|
||||
if((!local_ip4) || (local_ip4[0] == 0)) {
|
||||
a4.s_addr = 0; /* disabled: do not bind to a specific address */
|
||||
}
|
||||
else {
|
||||
if(curlx_inet_pton(AF_INET, local_ip4, &a4) != 1) {
|
||||
DEBUGF(infof(data, "bad DNS IPv4 address"));
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* if channel is not there yet, this is just a parameter check */
|
||||
if(ares->channel)
|
||||
ares_set_local_ip4(ares->channel, ntohl(a4.s_addr));
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
(void)local_ip4;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data)
|
||||
{
|
||||
#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
unsigned char a6[INET6_ADDRSTRLEN];
|
||||
const char *local_ip6 = data->set.str[STRING_DNS_LOCAL_IP6];
|
||||
|
||||
if((!local_ip6) || (local_ip6[0] == 0)) {
|
||||
/* disabled: do not bind to a specific address */
|
||||
memset(a6, 0, sizeof(a6));
|
||||
}
|
||||
else {
|
||||
if(curlx_inet_pton(AF_INET6, local_ip6, a6) != 1) {
|
||||
DEBUGF(infof(data, "bad DNS IPv6 address"));
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* if channel is not there, this is just a parameter check */
|
||||
if(ares->channel)
|
||||
ares_set_local_ip6(ares->channel, a6);
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CURLRES_ARES */
|
||||
Vendored
+222
@@ -0,0 +1,222 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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_pollset() 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
|
||||
*/
|
||||
|
||||
|
||||
CURLcode Curl_ares_pollset(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
|
||||
struct timeval timebuf;
|
||||
curl_socket_t sockets[16]; /* ARES documented limit */
|
||||
unsigned int bitmap, i;
|
||||
struct timeval *timeout;
|
||||
timediff_t milli;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(channel);
|
||||
if(!channel)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
bitmap = ares_getsock(channel, (ares_socket_t *)sockets,
|
||||
CURL_ARRAYSIZE(sockets));
|
||||
for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) {
|
||||
int flags = 0;
|
||||
if(ARES_GETSOCK_READABLE(bitmap, i))
|
||||
flags |= CURL_POLL_IN;
|
||||
if(ARES_GETSOCK_WRITABLE(bitmap, i))
|
||||
flags |= CURL_POLL_OUT;
|
||||
if(!flags)
|
||||
break;
|
||||
result = Curl_pollset_change(data, ps, sockets[i], flags, 0);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
timeout = ares_timeout(channel, &maxtime, &timebuf);
|
||||
if(!timeout)
|
||||
timeout = &maxtime;
|
||||
milli = curlx_tvtoms(timeout);
|
||||
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
+797
@@ -0,0 +1,797 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "cfilters.h"
|
||||
#include "sendf.h"
|
||||
#include "hostip.h"
|
||||
#include "hash.h"
|
||||
#include "share.h"
|
||||
#include "url.h"
|
||||
#include "multiif.h"
|
||||
#include "curl_threads.h"
|
||||
#include "select.h"
|
||||
|
||||
#ifdef USE_ARES
|
||||
#include <ares.h>
|
||||
#ifdef USE_HTTPSRR
|
||||
#define USE_HTTPSRR_ARES /* the combo */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#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 *);
|
||||
static void async_thrdd_shutdown(struct Curl_easy *);
|
||||
|
||||
CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl)
|
||||
{
|
||||
(void)data;
|
||||
*impl = NULL;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Give up reference to add_ctx */
|
||||
static void addr_ctx_unlink(struct async_thrdd_addr_ctx **paddr_ctx,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct async_thrdd_addr_ctx *addr_ctx = *paddr_ctx;
|
||||
bool destroy;
|
||||
|
||||
(void)data;
|
||||
if(!addr_ctx)
|
||||
return;
|
||||
|
||||
Curl_mutex_acquire(&addr_ctx->mutx);
|
||||
if(!data) /* called by resolving thread */
|
||||
addr_ctx->thrd_done = TRUE;
|
||||
|
||||
DEBUGASSERT(addr_ctx->ref_count);
|
||||
--addr_ctx->ref_count;
|
||||
destroy = !addr_ctx->ref_count;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
|
||||
if(destroy) {
|
||||
Curl_mutex_destroy(&addr_ctx->mutx);
|
||||
free(addr_ctx->hostname);
|
||||
if(addr_ctx->res)
|
||||
Curl_freeaddrinfo(addr_ctx->res);
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
#ifndef USE_EVENTFD
|
||||
wakeup_close(addr_ctx->sock_pair[1]);
|
||||
#endif
|
||||
wakeup_close(addr_ctx->sock_pair[0]);
|
||||
#endif
|
||||
free(addr_ctx);
|
||||
}
|
||||
*paddr_ctx = NULL;
|
||||
}
|
||||
|
||||
/* Initialize context for threaded resolver */
|
||||
static struct async_thrdd_addr_ctx *
|
||||
addr_ctx_create(struct Curl_easy *data,
|
||||
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;
|
||||
addr_ctx->ref_count = 1;
|
||||
|
||||
#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 = 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
return addr_ctx;
|
||||
|
||||
err_exit:
|
||||
addr_ctx_unlink(&addr_ctx, data);
|
||||
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 CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg)
|
||||
{
|
||||
struct async_thrdd_addr_ctx *addr_ctx = arg;
|
||||
bool do_abort;
|
||||
|
||||
Curl_mutex_acquire(&addr_ctx->mutx);
|
||||
do_abort = addr_ctx->do_abort;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
|
||||
if(!do_abort) {
|
||||
char service[12];
|
||||
int rc;
|
||||
|
||||
curl_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);
|
||||
do_abort = addr_ctx->do_abort;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
if(!do_abort) {
|
||||
#ifdef USE_EVENTFD
|
||||
const uint64_t buf[1] = { 1 };
|
||||
#else
|
||||
const char buf[1] = { 1 };
|
||||
#endif
|
||||
/* Thread is done, notify transfer */
|
||||
if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) {
|
||||
/* update sock_error to errno */
|
||||
addr_ctx->sock_error = SOCKERRNO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
addr_ctx_unlink(&addr_ctx, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* HAVE_GETADDRINFO */
|
||||
|
||||
/*
|
||||
* gethostbyname_thread() resolves a name and then exits.
|
||||
*/
|
||||
static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg)
|
||||
{
|
||||
struct async_thrdd_addr_ctx *addr_ctx = arg;
|
||||
bool do_abort;
|
||||
|
||||
Curl_mutex_acquire(&addr_ctx->mutx);
|
||||
do_abort = addr_ctx->do_abort;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
|
||||
if(!do_abort) {
|
||||
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);
|
||||
do_abort = addr_ctx->do_abort;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
if(!do_abort) {
|
||||
#ifdef USE_EVENTFD
|
||||
const uint64_t buf[1] = { 1 };
|
||||
#else
|
||||
const char buf[1] = { 1 };
|
||||
#endif
|
||||
/* Thread is done, notify transfer */
|
||||
if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) {
|
||||
/* update sock_error to errno */
|
||||
addr_ctx->sock_error = SOCKERRNO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
addr_ctx_unlink(&addr_ctx, NULL);
|
||||
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(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null)) {
|
||||
bool done;
|
||||
|
||||
Curl_mutex_acquire(&addr->mutx);
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
if(!addr->do_abort)
|
||||
Curl_multi_will_close(data, addr->sock_pair[0]);
|
||||
#endif
|
||||
addr->do_abort = TRUE;
|
||||
done = addr->thrd_done;
|
||||
Curl_mutex_release(&addr->mutx);
|
||||
|
||||
if(done) {
|
||||
Curl_thread_join(&addr->thread_hnd);
|
||||
CURL_TRC_DNS(data, "async_thrdd_destroy, thread joined");
|
||||
}
|
||||
else {
|
||||
/* thread is still running. Detach it. */
|
||||
Curl_thread_destroy(&addr->thread_hnd);
|
||||
CURL_TRC_DNS(data, "async_thrdd_destroy, thread detached");
|
||||
}
|
||||
}
|
||||
/* release our reference to the shared context */
|
||||
addr_ctx_unlink(&thrdd->addr, data);
|
||||
}
|
||||
|
||||
#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, int port)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
int status;
|
||||
char *rrname = NULL;
|
||||
|
||||
DEBUGASSERT(!thrdd->rr.channel);
|
||||
if(port != 443) {
|
||||
rrname = curl_maprintf("_%d_.https.%s", port, data->conn->host.name);
|
||||
if(!rrname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
status = ares_init_options(&thrdd->rr.channel, NULL, 0);
|
||||
if(status != ARES_SUCCESS) {
|
||||
thrdd->rr.channel = NULL;
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#ifdef CURLDEBUG
|
||||
if(getenv("CURL_DNS_SERVER")) {
|
||||
const char *servers = getenv("CURL_DNS_SERVER");
|
||||
status = ares_set_servers_ports_csv(thrdd->rr.channel, servers);
|
||||
if(status)
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo));
|
||||
thrdd->rr.hinfo.port = -1;
|
||||
thrdd->rr.hinfo.rrname = rrname;
|
||||
ares_query_dnsrec(thrdd->rr.channel,
|
||||
rrname ? rrname : data->conn->host.name, ARES_CLASS_IN,
|
||||
ARES_REC_TYPE_HTTPS,
|
||||
async_thrdd_rr_done, data, NULL);
|
||||
CURL_TRC_DNS(data, "Issued HTTPS-RR request for %s", data->conn->host.name);
|
||||
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;
|
||||
free(data->state.async.hostname);
|
||||
data->state.async.hostname = strdup(hostname);
|
||||
if(!data->state.async.hostname)
|
||||
goto err_exit;
|
||||
|
||||
addr_ctx = addr_ctx_create(data, hostname, port, hints);
|
||||
if(!addr_ctx)
|
||||
goto err_exit;
|
||||
thrdd->addr = addr_ctx;
|
||||
|
||||
/* passing addr_ctx to the thread adds a reference */
|
||||
addr_ctx->ref_count = 2;
|
||||
addr_ctx->start = curlx_now();
|
||||
|
||||
#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 */
|
||||
addr_ctx->ref_count = 1;
|
||||
addr_ctx->thrd_done = TRUE;
|
||||
err = errno;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
if(async_rr_start(data, port))
|
||||
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;
|
||||
}
|
||||
|
||||
static void async_thrdd_shutdown(struct Curl_easy *data)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_addr_ctx *addr_ctx = thrdd->addr;
|
||||
bool done;
|
||||
|
||||
if(!addr_ctx)
|
||||
return;
|
||||
if(addr_ctx->thread_hnd == curl_thread_t_null)
|
||||
return;
|
||||
|
||||
Curl_mutex_acquire(&addr_ctx->mutx);
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
if(!addr_ctx->do_abort)
|
||||
Curl_multi_will_close(data, addr_ctx->sock_pair[0]);
|
||||
#endif
|
||||
addr_ctx->do_abort = TRUE;
|
||||
done = addr_ctx->thrd_done;
|
||||
Curl_mutex_release(&addr_ctx->mutx);
|
||||
|
||||
/* Wait for the thread to terminate if it is already marked done. If it is
|
||||
not done yet we cannot do anything here. We had tried pthread_cancel but
|
||||
it caused hanging and resource leaks (#18532). */
|
||||
if(done && (addr_ctx->thread_hnd != curl_thread_t_null)) {
|
||||
Curl_thread_join(&addr_ctx->thread_hnd);
|
||||
CURL_TRC_DNS(data, "async_thrdd_shutdown, thread joined");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* '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;
|
||||
|
||||
if(addr_ctx->thread_hnd != curl_thread_t_null) {
|
||||
/* not interested in result? cancel, if still running... */
|
||||
if(!entry)
|
||||
async_thrdd_shutdown(data);
|
||||
|
||||
if(addr_ctx->thread_hnd != curl_thread_t_null) {
|
||||
CURL_TRC_DNS(data, "resolve, wait for thread to finish");
|
||||
if(!Curl_thread_join(&addr_ctx->thread_hnd)) {
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(entry)
|
||||
result = Curl_async_is_resolved(data, entry);
|
||||
}
|
||||
|
||||
data->state.async.done = TRUE;
|
||||
if(entry)
|
||||
*entry = data->state.async.dns;
|
||||
|
||||
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)
|
||||
{
|
||||
async_thrdd_shutdown(data);
|
||||
}
|
||||
|
||||
void Curl_async_thrdd_destroy(struct Curl_easy *data)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
|
||||
if(thrdd->addr && !data->set.quick_exit) {
|
||||
(void)asyn_thrdd_await(data, thrdd->addr, NULL);
|
||||
}
|
||||
async_thrdd_destroy(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->thrd_done;
|
||||
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);
|
||||
Curl_expire_done(data, EXPIRE_ASYNC_NAME);
|
||||
|
||||
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, NULL);
|
||||
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_shutdown(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;
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
CURLcode result = CURLE_OK;
|
||||
bool thrd_done;
|
||||
|
||||
#if !defined(USE_HTTPSRR_ARES) && defined(CURL_DISABLE_SOCKETPAIR)
|
||||
(void)ps;
|
||||
#endif
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
if(thrdd->rr.channel) {
|
||||
result = Curl_ares_pollset(data, thrdd->rr.channel, ps);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
if(!thrdd->addr)
|
||||
return result;
|
||||
|
||||
Curl_mutex_acquire(&thrdd->addr->mutx);
|
||||
thrd_done = thrdd->addr->thrd_done;
|
||||
Curl_mutex_release(&thrdd->addr->mutx);
|
||||
|
||||
if(!thrd_done) {
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
/* return read fd to client for polling the DNS resolution status */
|
||||
result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#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 =
|
||||
(Curl_conn_get_transport(data, data->conn) == 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 */
|
||||
Vendored
+278
@@ -0,0 +1,278 @@
|
||||
#ifndef HEADER_CURL_ASYN_H
|
||||
#define HEADER_CURL_ASYN_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"
|
||||
|
||||
struct Curl_easy;
|
||||
struct Curl_dns_entry;
|
||||
|
||||
#ifdef CURLRES_ASYNCH
|
||||
|
||||
#include "curl_addrinfo.h"
|
||||
#include "httpsrr.h"
|
||||
|
||||
struct addrinfo;
|
||||
struct hostent;
|
||||
struct connectdata;
|
||||
struct easy_pollset;
|
||||
|
||||
#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
|
||||
#error cannot have both CURLRES_ARES and CURLRES_THREADED defined
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This header defines all functions in the internal asynch resolver interface.
|
||||
* All asynch resolvers need to provide these functions.
|
||||
* asyn-ares.c and asyn-thread.c are the current implementations of asynch
|
||||
* resolver backends.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_async_global_init(void);
|
||||
|
||||
/*
|
||||
* Curl_async_global_cleanup()
|
||||
* Called from curl_global_cleanup() to destroy global resolver environment.
|
||||
*/
|
||||
void Curl_async_global_cleanup(void);
|
||||
|
||||
/*
|
||||
* Curl_async_get_impl()
|
||||
* Get the resolver implementation instance (c-ares channel) or NULL
|
||||
* for passing to application callback.
|
||||
*/
|
||||
CURLcode Curl_async_get_impl(struct Curl_easy *easy, void **impl);
|
||||
|
||||
/* Curl_async_pollset()
|
||||
*
|
||||
* This function is called from the Curl_multi_pollset() 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.
|
||||
*/
|
||||
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* take too long.
|
||||
*
|
||||
* Returns normal CURLcode errors.
|
||||
*/
|
||||
CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **dns);
|
||||
|
||||
/*
|
||||
* Curl_async_await()
|
||||
*
|
||||
* Waits for a resolve to finish. This function should be avoided since using
|
||||
* this risk getting the multi interface to "hang".
|
||||
*
|
||||
* 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_async_await(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **dnsentry);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* memory we need to free after use. That memory *MUST* be freed with
|
||||
* Curl_freeaddrinfo(), nothing else.
|
||||
*
|
||||
* Each resolver backend must of course make sure to return data in the
|
||||
* correct format to comply with this.
|
||||
*/
|
||||
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>
|
||||
|
||||
CURLcode Curl_ares_pollset(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
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 ares_status; /* ARES_SUCCESS, ARES_ENOTFOUND, etc. */
|
||||
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;
|
||||
BIT(thrd_done);
|
||||
BIT(do_abort);
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* convert these functions if an asynch resolver is not used */
|
||||
#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 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 *****************/
|
||||
#endif /* HEADER_CURL_ASYN_H */
|
||||
Vendored
+624
@@ -0,0 +1,624 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "bufq.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
static bool chunk_is_empty(const struct buf_chunk *chunk)
|
||||
{
|
||||
return chunk->r_offset >= chunk->w_offset;
|
||||
}
|
||||
|
||||
static bool chunk_is_full(const struct buf_chunk *chunk)
|
||||
{
|
||||
return chunk->w_offset >= chunk->dlen;
|
||||
}
|
||||
|
||||
static size_t chunk_len(const struct buf_chunk *chunk)
|
||||
{
|
||||
return chunk->w_offset - chunk->r_offset;
|
||||
}
|
||||
|
||||
static void chunk_reset(struct buf_chunk *chunk)
|
||||
{
|
||||
chunk->next = NULL;
|
||||
chunk->r_offset = chunk->w_offset = 0;
|
||||
}
|
||||
|
||||
static size_t chunk_append(struct buf_chunk *chunk,
|
||||
const unsigned char *buf, size_t len)
|
||||
{
|
||||
unsigned char *p = &chunk->x.data[chunk->w_offset];
|
||||
size_t n = chunk->dlen - chunk->w_offset;
|
||||
DEBUGASSERT(chunk->dlen >= chunk->w_offset);
|
||||
if(n) {
|
||||
n = CURLMIN(n, len);
|
||||
memcpy(p, buf, n);
|
||||
chunk->w_offset += n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static size_t chunk_read(struct buf_chunk *chunk,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
unsigned char *p = &chunk->x.data[chunk->r_offset];
|
||||
size_t n = chunk->w_offset - chunk->r_offset;
|
||||
DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
|
||||
if(!n) {
|
||||
return 0;
|
||||
}
|
||||
else if(n <= len) {
|
||||
memcpy(buf, p, n);
|
||||
chunk->r_offset = chunk->w_offset = 0;
|
||||
return n;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, p, len);
|
||||
chunk->r_offset += len;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
|
||||
Curl_bufq_reader *reader,
|
||||
void *reader_ctx, size_t *pnread)
|
||||
{
|
||||
unsigned char *p = &chunk->x.data[chunk->w_offset];
|
||||
size_t n = chunk->dlen - chunk->w_offset; /* free amount */
|
||||
CURLcode result;
|
||||
|
||||
*pnread = 0;
|
||||
DEBUGASSERT(chunk->dlen >= chunk->w_offset);
|
||||
if(!n)
|
||||
return CURLE_AGAIN;
|
||||
if(max_len && n > max_len)
|
||||
n = max_len;
|
||||
result = reader(reader_ctx, p, n, pnread);
|
||||
if(!result) {
|
||||
DEBUGASSERT(*pnread <= n);
|
||||
chunk->w_offset += *pnread;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void chunk_peek(const struct buf_chunk *chunk,
|
||||
const unsigned char **pbuf, size_t *plen)
|
||||
{
|
||||
DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
|
||||
*pbuf = &chunk->x.data[chunk->r_offset];
|
||||
*plen = chunk->w_offset - chunk->r_offset;
|
||||
}
|
||||
|
||||
static void chunk_peek_at(const struct buf_chunk *chunk, size_t offset,
|
||||
const unsigned char **pbuf, size_t *plen)
|
||||
{
|
||||
offset += chunk->r_offset;
|
||||
DEBUGASSERT(chunk->w_offset >= offset);
|
||||
*pbuf = &chunk->x.data[offset];
|
||||
*plen = chunk->w_offset - offset;
|
||||
}
|
||||
|
||||
static size_t chunk_skip(struct buf_chunk *chunk, size_t amount)
|
||||
{
|
||||
size_t n = chunk->w_offset - chunk->r_offset;
|
||||
DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
|
||||
if(n) {
|
||||
n = CURLMIN(n, amount);
|
||||
chunk->r_offset += n;
|
||||
if(chunk->r_offset == chunk->w_offset)
|
||||
chunk->r_offset = chunk->w_offset = 0;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void chunk_list_free(struct buf_chunk **anchor)
|
||||
{
|
||||
struct buf_chunk *chunk;
|
||||
while(*anchor) {
|
||||
chunk = *anchor;
|
||||
*anchor = chunk->next;
|
||||
free(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Curl_bufcp_init(struct bufc_pool *pool,
|
||||
size_t chunk_size, size_t spare_max)
|
||||
{
|
||||
DEBUGASSERT(chunk_size > 0);
|
||||
DEBUGASSERT(spare_max > 0);
|
||||
memset(pool, 0, sizeof(*pool));
|
||||
pool->chunk_size = chunk_size;
|
||||
pool->spare_max = spare_max;
|
||||
}
|
||||
|
||||
static CURLcode bufcp_take(struct bufc_pool *pool,
|
||||
struct buf_chunk **pchunk)
|
||||
{
|
||||
struct buf_chunk *chunk = NULL;
|
||||
|
||||
if(pool->spare) {
|
||||
chunk = pool->spare;
|
||||
pool->spare = chunk->next;
|
||||
--pool->spare_count;
|
||||
chunk_reset(chunk);
|
||||
*pchunk = chunk;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Check for integer overflow before allocation */
|
||||
if(pool->chunk_size > SIZE_MAX - sizeof(*chunk)) {
|
||||
*pchunk = NULL;
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
chunk = calloc(1, sizeof(*chunk) + pool->chunk_size);
|
||||
if(!chunk) {
|
||||
*pchunk = NULL;
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
chunk->dlen = pool->chunk_size;
|
||||
*pchunk = chunk;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void bufcp_put(struct bufc_pool *pool,
|
||||
struct buf_chunk *chunk)
|
||||
{
|
||||
if(pool->spare_count >= pool->spare_max) {
|
||||
free(chunk);
|
||||
}
|
||||
else {
|
||||
chunk_reset(chunk);
|
||||
chunk->next = pool->spare;
|
||||
pool->spare = chunk;
|
||||
++pool->spare_count;
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_bufcp_free(struct bufc_pool *pool)
|
||||
{
|
||||
chunk_list_free(&pool->spare);
|
||||
pool->spare_count = 0;
|
||||
}
|
||||
|
||||
static void bufq_init(struct bufq *q, struct bufc_pool *pool,
|
||||
size_t chunk_size, size_t max_chunks, int opts)
|
||||
{
|
||||
DEBUGASSERT(chunk_size > 0);
|
||||
DEBUGASSERT(max_chunks > 0);
|
||||
memset(q, 0, sizeof(*q));
|
||||
q->chunk_size = chunk_size;
|
||||
q->max_chunks = max_chunks;
|
||||
q->pool = pool;
|
||||
q->opts = opts;
|
||||
}
|
||||
|
||||
void Curl_bufq_init2(struct bufq *q, size_t chunk_size, size_t max_chunks,
|
||||
int opts)
|
||||
{
|
||||
bufq_init(q, NULL, chunk_size, max_chunks, opts);
|
||||
}
|
||||
|
||||
void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks)
|
||||
{
|
||||
bufq_init(q, NULL, chunk_size, max_chunks, BUFQ_OPT_NONE);
|
||||
}
|
||||
|
||||
void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool,
|
||||
size_t max_chunks, int opts)
|
||||
{
|
||||
bufq_init(q, pool, pool->chunk_size, max_chunks, opts);
|
||||
}
|
||||
|
||||
void Curl_bufq_free(struct bufq *q)
|
||||
{
|
||||
chunk_list_free(&q->head);
|
||||
chunk_list_free(&q->spare);
|
||||
q->tail = NULL;
|
||||
q->chunk_count = 0;
|
||||
}
|
||||
|
||||
void Curl_bufq_reset(struct bufq *q)
|
||||
{
|
||||
struct buf_chunk *chunk;
|
||||
while(q->head) {
|
||||
chunk = q->head;
|
||||
q->head = chunk->next;
|
||||
chunk->next = q->spare;
|
||||
q->spare = chunk;
|
||||
}
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
size_t Curl_bufq_len(const struct bufq *q)
|
||||
{
|
||||
const struct buf_chunk *chunk = q->head;
|
||||
size_t len = 0;
|
||||
while(chunk) {
|
||||
len += chunk_len(chunk);
|
||||
chunk = chunk->next;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool Curl_bufq_is_empty(const struct bufq *q)
|
||||
{
|
||||
return !q->head || chunk_is_empty(q->head);
|
||||
}
|
||||
|
||||
bool Curl_bufq_is_full(const struct bufq *q)
|
||||
{
|
||||
if(!q->tail || q->spare)
|
||||
return FALSE;
|
||||
if(q->chunk_count < q->max_chunks)
|
||||
return FALSE;
|
||||
if(q->chunk_count > q->max_chunks)
|
||||
return TRUE;
|
||||
/* we have no spares and cannot make more, is the tail full? */
|
||||
return chunk_is_full(q->tail);
|
||||
}
|
||||
|
||||
static struct buf_chunk *get_spare(struct bufq *q)
|
||||
{
|
||||
struct buf_chunk *chunk = NULL;
|
||||
|
||||
if(q->spare) {
|
||||
chunk = q->spare;
|
||||
q->spare = chunk->next;
|
||||
chunk_reset(chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if(q->chunk_count >= q->max_chunks && (!(q->opts & BUFQ_OPT_SOFT_LIMIT)))
|
||||
return NULL;
|
||||
|
||||
if(q->pool) {
|
||||
if(bufcp_take(q->pool, &chunk))
|
||||
return NULL;
|
||||
++q->chunk_count;
|
||||
return chunk;
|
||||
}
|
||||
else {
|
||||
/* Check for integer overflow before allocation */
|
||||
if(q->chunk_size > SIZE_MAX - sizeof(*chunk)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk = calloc(1, sizeof(*chunk) + q->chunk_size);
|
||||
if(!chunk)
|
||||
return NULL;
|
||||
chunk->dlen = q->chunk_size;
|
||||
++q->chunk_count;
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
|
||||
static void prune_head(struct bufq *q)
|
||||
{
|
||||
struct buf_chunk *chunk;
|
||||
|
||||
while(q->head && chunk_is_empty(q->head)) {
|
||||
chunk = q->head;
|
||||
q->head = chunk->next;
|
||||
if(q->tail == chunk)
|
||||
q->tail = q->head;
|
||||
if(q->pool) {
|
||||
bufcp_put(q->pool, chunk);
|
||||
--q->chunk_count;
|
||||
}
|
||||
else if((q->chunk_count > q->max_chunks) ||
|
||||
(q->opts & BUFQ_OPT_NO_SPARES)) {
|
||||
/* SOFT_LIMIT allowed us more than max. free spares until
|
||||
* we are at max again. Or free them if we are configured
|
||||
* to not use spares. */
|
||||
free(chunk);
|
||||
--q->chunk_count;
|
||||
}
|
||||
else {
|
||||
chunk->next = q->spare;
|
||||
q->spare = chunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct buf_chunk *get_non_full_tail(struct bufq *q)
|
||||
{
|
||||
struct buf_chunk *chunk;
|
||||
|
||||
if(q->tail && !chunk_is_full(q->tail))
|
||||
return q->tail;
|
||||
chunk = get_spare(q);
|
||||
if(chunk) {
|
||||
/* new tail, and possibly new head */
|
||||
if(q->tail) {
|
||||
q->tail->next = chunk;
|
||||
q->tail = chunk;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(!q->head);
|
||||
q->head = q->tail = chunk;
|
||||
}
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_write(struct bufq *q,
|
||||
const unsigned char *buf, size_t len,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
struct buf_chunk *tail;
|
||||
size_t n;
|
||||
|
||||
DEBUGASSERT(q->max_chunks > 0);
|
||||
*pnwritten = 0;
|
||||
while(len) {
|
||||
tail = get_non_full_tail(q);
|
||||
if(!tail) {
|
||||
if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT))
|
||||
/* should have gotten a tail, but did not */
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
n = chunk_append(tail, buf, len);
|
||||
if(!n)
|
||||
break;
|
||||
*pnwritten += n;
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
return (!*pnwritten && len) ? CURLE_AGAIN : CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_cwrite(struct bufq *q,
|
||||
const char *buf, size_t len,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
return Curl_bufq_write(q, (const unsigned char *)buf, len, pnwritten);
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
|
||||
size_t *pnread)
|
||||
{
|
||||
*pnread = 0;
|
||||
while(len && q->head) {
|
||||
size_t n = chunk_read(q->head, buf, len);
|
||||
if(n) {
|
||||
*pnread += n;
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
prune_head(q);
|
||||
}
|
||||
return (!*pnread) ? CURLE_AGAIN : CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
|
||||
size_t *pnread)
|
||||
{
|
||||
return Curl_bufq_read(q, (unsigned char *)buf, len, pnread);
|
||||
}
|
||||
|
||||
bool Curl_bufq_peek(struct bufq *q,
|
||||
const unsigned char **pbuf, size_t *plen)
|
||||
{
|
||||
if(q->head && chunk_is_empty(q->head)) {
|
||||
prune_head(q);
|
||||
}
|
||||
if(q->head && !chunk_is_empty(q->head)) {
|
||||
chunk_peek(q->head, pbuf, plen);
|
||||
return TRUE;
|
||||
}
|
||||
*pbuf = NULL;
|
||||
*plen = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
|
||||
const unsigned char **pbuf, size_t *plen)
|
||||
{
|
||||
struct buf_chunk *c = q->head;
|
||||
size_t clen;
|
||||
|
||||
while(c) {
|
||||
clen = chunk_len(c);
|
||||
if(!clen)
|
||||
break;
|
||||
if(offset >= clen) {
|
||||
offset -= clen;
|
||||
c = c->next;
|
||||
continue;
|
||||
}
|
||||
chunk_peek_at(c, offset, pbuf, plen);
|
||||
return TRUE;
|
||||
}
|
||||
*pbuf = NULL;
|
||||
*plen = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Curl_bufq_skip(struct bufq *q, size_t amount)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
while(amount && q->head) {
|
||||
n = chunk_skip(q->head, amount);
|
||||
amount -= n;
|
||||
prune_head(q);
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
|
||||
void *writer_ctx, size_t *pwritten)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t blen;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
*pwritten = 0;
|
||||
while(Curl_bufq_peek(q, &buf, &blen)) {
|
||||
size_t chunk_written;
|
||||
|
||||
result = writer(writer_ctx, buf, blen, &chunk_written);
|
||||
if(result) {
|
||||
if((result == CURLE_AGAIN) && *pwritten) {
|
||||
/* blocked on subsequent write, report success */
|
||||
result = CURLE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!chunk_written) {
|
||||
if(!*pwritten) {
|
||||
/* treat as blocked */
|
||||
result = CURLE_AGAIN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*pwritten += chunk_written;
|
||||
Curl_bufq_skip(q, chunk_written);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_write_pass(struct bufq *q,
|
||||
const unsigned char *buf, size_t len,
|
||||
Curl_bufq_writer *writer, void *writer_ctx,
|
||||
size_t *pwritten)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t n;
|
||||
|
||||
*pwritten = 0;
|
||||
while(len) {
|
||||
if(Curl_bufq_is_full(q)) {
|
||||
/* try to make room in case we are full */
|
||||
result = Curl_bufq_pass(q, writer, writer_ctx, &n);
|
||||
if(result) {
|
||||
if(result != CURLE_AGAIN) {
|
||||
/* real error, fail */
|
||||
return result;
|
||||
}
|
||||
/* would block, bufq is full, give up */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to bufq as much as there is room for */
|
||||
result = Curl_bufq_write(q, buf, len, &n);
|
||||
if(result) {
|
||||
if(result != CURLE_AGAIN)
|
||||
/* real error, fail */
|
||||
return result;
|
||||
/* result == CURLE_AGAIN */
|
||||
if(*pwritten)
|
||||
/* we did write successfully before */
|
||||
result = CURLE_OK;
|
||||
return result;
|
||||
}
|
||||
else if(n == 0)
|
||||
/* edge case of writer returning 0 (and len is >0)
|
||||
* break or we might enter an infinite loop here */
|
||||
break;
|
||||
|
||||
/* Track what we added to bufq */
|
||||
buf += n;
|
||||
len -= n;
|
||||
*pwritten += n;
|
||||
}
|
||||
|
||||
return (!*pwritten && len) ? CURLE_AGAIN : CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
|
||||
Curl_bufq_reader *reader, void *reader_ctx,
|
||||
size_t *pnread)
|
||||
{
|
||||
struct buf_chunk *tail = NULL;
|
||||
|
||||
*pnread = 0;
|
||||
tail = get_non_full_tail(q);
|
||||
if(!tail) {
|
||||
if(q->chunk_count < q->max_chunks)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
/* full, blocked */
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
|
||||
return chunk_slurpn(tail, max_len, reader, reader_ctx, pnread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read up to `max_len` bytes and append it to the end of the buffer queue.
|
||||
* if `max_len` is 0, no limit is imposed and the call behaves exactly
|
||||
* the same as `Curl_bufq_slurp()`.
|
||||
* Returns the total amount of buf read (may be 0) in `pnread` or error
|
||||
* Note that even in case of an error chunks may have been read and
|
||||
* the buffer queue will have different length than before.
|
||||
*/
|
||||
static CURLcode bufq_slurpn(struct bufq *q, size_t max_len,
|
||||
Curl_bufq_reader *reader, void *reader_ctx,
|
||||
size_t *pnread)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
*pnread = 0;
|
||||
while(1) {
|
||||
size_t n;
|
||||
result = Curl_bufq_sipn(q, max_len, reader, reader_ctx, &n);
|
||||
if(result) {
|
||||
if(!*pnread || result != CURLE_AGAIN) {
|
||||
/* blocked on first read or real error, fail */
|
||||
return result;
|
||||
}
|
||||
result = CURLE_OK;
|
||||
break;
|
||||
}
|
||||
else if(n == 0) {
|
||||
/* eof, result remains CURLE_OK */
|
||||
break;
|
||||
}
|
||||
*pnread += n;
|
||||
if(max_len) {
|
||||
DEBUGASSERT(n <= max_len);
|
||||
max_len -= n;
|
||||
if(!max_len)
|
||||
break;
|
||||
}
|
||||
/* give up slurping when we get less bytes than we asked for */
|
||||
if(q->tail && !chunk_is_full(q->tail))
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
|
||||
void *reader_ctx, size_t *pnread)
|
||||
{
|
||||
return bufq_slurpn(q, 0, reader, reader_ctx, pnread);
|
||||
}
|
||||
Vendored
+260
@@ -0,0 +1,260 @@
|
||||
#ifndef HEADER_CURL_BUFQ_H
|
||||
#define HEADER_CURL_BUFQ_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"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
/**
|
||||
* A chunk of bytes for reading and writing.
|
||||
* The size is fixed a creation with read and write offset
|
||||
* for where unread content is.
|
||||
*/
|
||||
struct buf_chunk {
|
||||
struct buf_chunk *next; /* to keep it in a list */
|
||||
size_t dlen; /* the amount of allocated x.data[] */
|
||||
size_t r_offset; /* first unread bytes */
|
||||
size_t w_offset; /* one after last written byte */
|
||||
union {
|
||||
unsigned char data[1]; /* the buffer for `dlen` bytes */
|
||||
void *dummy; /* alignment */
|
||||
} x;
|
||||
};
|
||||
|
||||
/**
|
||||
* A pool for providing/keeping a number of chunks of the same size
|
||||
*
|
||||
* The same pool can be shared by many `bufq` instances. However, a pool
|
||||
* is not thread safe. All bufqs using it are supposed to operate in the
|
||||
* same thread.
|
||||
*/
|
||||
struct bufc_pool {
|
||||
struct buf_chunk *spare; /* list of available spare chunks */
|
||||
size_t chunk_size; /* the size of chunks in this pool */
|
||||
size_t spare_count; /* current number of spare chunks in list */
|
||||
size_t spare_max; /* max number of spares to keep */
|
||||
};
|
||||
|
||||
void Curl_bufcp_init(struct bufc_pool *pool,
|
||||
size_t chunk_size, size_t spare_max);
|
||||
|
||||
void Curl_bufcp_free(struct bufc_pool *pool);
|
||||
|
||||
/**
|
||||
* A queue of byte chunks for reading and writing.
|
||||
* Reading is done from `head`, writing is done to `tail`.
|
||||
*
|
||||
* `bufq`s can be empty or full or neither. Its `len` is the number
|
||||
* of bytes that can be read. For an empty bufq, `len` will be 0.
|
||||
*
|
||||
* By default, a bufq can hold up to `max_chunks * chunk_size` number
|
||||
* of bytes. When `max_chunks` are used (in the `head` list) and the
|
||||
* `tail` chunk is full, the bufq will report that it is full.
|
||||
*
|
||||
* On a full bufq, `len` may be less than the maximum number of bytes,
|
||||
* e.g. when the head chunk is partially read. `len` may also become
|
||||
* larger than the max when option `BUFQ_OPT_SOFT_LIMIT` is used.
|
||||
*
|
||||
* By default, writing to a full bufq will return (-1, CURLE_AGAIN). Same
|
||||
* as reading from an empty bufq.
|
||||
* With `BUFQ_OPT_SOFT_LIMIT` set, a bufq will allow writing becond this
|
||||
* limit and use more than `max_chunks`. However it will report that it
|
||||
* is full nevertheless. This is provided for situation where writes
|
||||
* preferably never fail (except for memory exhaustion).
|
||||
*
|
||||
* By default and without a pool, a bufq will keep chunks that read
|
||||
* empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
|
||||
* disable that and free chunks once they become empty.
|
||||
*
|
||||
* When providing a pool to a bufq, all chunk creation and spare handling
|
||||
* will be delegated to that pool.
|
||||
*/
|
||||
struct bufq {
|
||||
struct buf_chunk *head; /* chunk with bytes to read from */
|
||||
struct buf_chunk *tail; /* chunk to write to */
|
||||
struct buf_chunk *spare; /* list of free chunks, unless `pool` */
|
||||
struct bufc_pool *pool; /* optional pool for free chunks */
|
||||
size_t chunk_count; /* current number of chunks in `head+spare` */
|
||||
size_t max_chunks; /* max `head` chunks to use */
|
||||
size_t chunk_size; /* size of chunks to manage */
|
||||
int opts; /* options for handling queue, see below */
|
||||
};
|
||||
|
||||
/**
|
||||
* Default behaviour: chunk limit is "hard", meaning attempts to write
|
||||
* more bytes than can be hold in `max_chunks` is refused and will return
|
||||
* -1, CURLE_AGAIN. */
|
||||
#define BUFQ_OPT_NONE (0)
|
||||
/**
|
||||
* Make `max_chunks` a "soft" limit. A bufq will report that it is "full"
|
||||
* when `max_chunks` are used, but allows writing beyond this limit.
|
||||
*/
|
||||
#define BUFQ_OPT_SOFT_LIMIT (1 << 0)
|
||||
/**
|
||||
* Do not keep spare chunks.
|
||||
*/
|
||||
#define BUFQ_OPT_NO_SPARES (1 << 1)
|
||||
|
||||
/**
|
||||
* Initialize a buffer queue that can hold up to `max_chunks` buffers
|
||||
* each of size `chunk_size`. The bufq will not allow writing of
|
||||
* more bytes than can be held in `max_chunks`.
|
||||
*/
|
||||
void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks);
|
||||
|
||||
/**
|
||||
* Initialize a buffer queue that can hold up to `max_chunks` buffers
|
||||
* each of size `chunk_size` with the given options. See `BUFQ_OPT_*`.
|
||||
*/
|
||||
void Curl_bufq_init2(struct bufq *q, size_t chunk_size,
|
||||
size_t max_chunks, int opts);
|
||||
|
||||
void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool,
|
||||
size_t max_chunks, int opts);
|
||||
|
||||
/**
|
||||
* Reset the buffer queue to be empty. Will keep any allocated buffer
|
||||
* chunks around.
|
||||
*/
|
||||
void Curl_bufq_reset(struct bufq *q);
|
||||
|
||||
/**
|
||||
* Free all resources held by the buffer queue.
|
||||
*/
|
||||
void Curl_bufq_free(struct bufq *q);
|
||||
|
||||
/**
|
||||
* Return the total amount of data in the queue.
|
||||
*/
|
||||
size_t Curl_bufq_len(const struct bufq *q);
|
||||
|
||||
/**
|
||||
* Returns TRUE iff there is no data in the buffer queue.
|
||||
*/
|
||||
bool Curl_bufq_is_empty(const struct bufq *q);
|
||||
|
||||
/**
|
||||
* Returns TRUE iff there is no space left in the buffer queue.
|
||||
*/
|
||||
bool Curl_bufq_is_full(const struct bufq *q);
|
||||
|
||||
/**
|
||||
* Write buf to the end of the buffer queue. The buf is copied
|
||||
* and the amount of copied bytes is returned.
|
||||
* CURLE_AGAIN is returned if the buffer queue is full.
|
||||
*/
|
||||
CURLcode Curl_bufq_write(struct bufq *q,
|
||||
const unsigned char *buf, size_t len,
|
||||
size_t *pnwritten);
|
||||
|
||||
CURLcode Curl_bufq_cwrite(struct bufq *q,
|
||||
const char *buf, size_t len,
|
||||
size_t *pnwritten);
|
||||
|
||||
/**
|
||||
* Read buf from the start of the buffer queue. The buf is copied
|
||||
* and the amount of copied bytes is returned.
|
||||
*/
|
||||
CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
|
||||
size_t *pnread);
|
||||
|
||||
CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
|
||||
size_t *pnread);
|
||||
|
||||
/**
|
||||
* Peek at the head chunk in the buffer queue. Returns a pointer to
|
||||
* the chunk buf (at the current offset) and its length. Does not
|
||||
* modify the buffer queue.
|
||||
* Returns TRUE iff bytes are available. Sets `pbuf` to NULL and `plen`
|
||||
* to 0 when no bytes are available.
|
||||
* Repeated calls return the same information until the buffer queue
|
||||
* is modified, see `Curl_bufq_skip()``
|
||||
*/
|
||||
bool Curl_bufq_peek(struct bufq *q,
|
||||
const unsigned char **pbuf, size_t *plen);
|
||||
|
||||
bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
|
||||
const unsigned char **pbuf, size_t *plen);
|
||||
|
||||
/**
|
||||
* Tell the buffer queue to discard `amount` buf bytes at the head
|
||||
* of the queue. Skipping more buf than is currently buffered will
|
||||
* just empty the queue.
|
||||
*/
|
||||
void Curl_bufq_skip(struct bufq *q, size_t amount);
|
||||
|
||||
typedef CURLcode Curl_bufq_writer(void *writer_ctx,
|
||||
const unsigned char *buf, size_t len,
|
||||
size_t *pwritten);
|
||||
/**
|
||||
* Passes the chunks in the buffer queue to the writer and returns
|
||||
* the amount of buf written. A writer may return -1 and CURLE_AGAIN
|
||||
* to indicate blocking at which point the queue will stop and return
|
||||
* the amount of buf passed so far.
|
||||
* -1 is returned on any other errors reported by the writer.
|
||||
* Note that in case of a -1 chunks may have been written and
|
||||
* the buffer queue will have different length than before.
|
||||
*/
|
||||
CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
|
||||
void *writer_ctx, size_t *pwritten);
|
||||
|
||||
typedef CURLcode Curl_bufq_reader(void *reader_ctx,
|
||||
unsigned char *buf, size_t len,
|
||||
size_t *pnread);
|
||||
|
||||
/**
|
||||
* Read bytes and append them to the end of the buffer queue until the
|
||||
* reader returns blocking or the queue is full. A reader returns
|
||||
* CURLE_AGAIN to indicate blocking.
|
||||
* Returns the total amount of buf read (may be 0) in `pnread` on success.
|
||||
* Note that in case of an error chunks may have been read and
|
||||
* the buffer queue will have different length than before.
|
||||
*/
|
||||
CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
|
||||
void *reader_ctx, size_t *pnread);
|
||||
|
||||
/**
|
||||
* Read *once* up to `max_len` bytes and append it to the buffer.
|
||||
* if `max_len` is 0, no limit is imposed besides the chunk space.
|
||||
* Returns the total amount of buf read (may be 0) or -1 on other
|
||||
* reader errors.
|
||||
*/
|
||||
CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
|
||||
Curl_bufq_reader *reader, void *reader_ctx,
|
||||
size_t *pnread);
|
||||
|
||||
/**
|
||||
* Write buf to the end of the buffer queue.
|
||||
* Will write bufq content or passed `buf` directly using the `writer`
|
||||
* callback when it sees fit. 'buf' might get passed directly
|
||||
* on or is placed into the buffer, depending on `len` and current
|
||||
* amount buffered, chunk size, etc.
|
||||
*/
|
||||
CURLcode Curl_bufq_write_pass(struct bufq *q,
|
||||
const unsigned char *buf, size_t len,
|
||||
Curl_bufq_writer *writer, void *writer_ctx,
|
||||
size_t *pwritten);
|
||||
|
||||
#endif /* HEADER_CURL_BUFQ_H */
|
||||
Vendored
+129
@@ -0,0 +1,129 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
#include "urldata.h"
|
||||
#include "bufref.h"
|
||||
#include "strdup.h"
|
||||
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
#define SIGNATURE 0x5c48e9b2 /* Random pattern. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Init a bufref struct.
|
||||
*/
|
||||
void Curl_bufref_init(struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
br->dtor = NULL;
|
||||
br->ptr = NULL;
|
||||
br->len = 0;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
br->signature = SIGNATURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the buffer and re-init the necessary fields. It does not touch the
|
||||
* 'signature' field and thus this buffer reference can be reused.
|
||||
*/
|
||||
|
||||
void Curl_bufref_free(struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
if(br->ptr && br->dtor)
|
||||
br->dtor(CURL_UNCONST(br->ptr));
|
||||
|
||||
br->dtor = NULL;
|
||||
br->ptr = NULL;
|
||||
br->len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the buffer reference to new values. The previously referenced buffer
|
||||
* is released before assignment.
|
||||
*/
|
||||
void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
|
||||
void (*dtor)(void *))
|
||||
{
|
||||
DEBUGASSERT(ptr || !len);
|
||||
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
Curl_bufref_free(br);
|
||||
br->ptr = (const unsigned char *) ptr;
|
||||
br->len = len;
|
||||
br->dtor = dtor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to the referenced buffer.
|
||||
*/
|
||||
const unsigned char *Curl_bufref_ptr(const struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
return br->ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the length of the referenced buffer data.
|
||||
*/
|
||||
size_t Curl_bufref_len(const struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
return br->len;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
|
||||
{
|
||||
unsigned char *cpy = NULL;
|
||||
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
DEBUGASSERT(ptr || !len);
|
||||
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
if(ptr) {
|
||||
cpy = Curl_memdup0(ptr, len);
|
||||
if(!cpy)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
Curl_bufref_set(br, cpy, len, curl_free);
|
||||
return CURLE_OK;
|
||||
}
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
#ifndef HEADER_CURL_BUFREF_H
|
||||
#define HEADER_CURL_BUFREF_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Generic buffer reference.
|
||||
*/
|
||||
struct bufref {
|
||||
void (*dtor)(void *); /* Associated destructor. */
|
||||
const unsigned char *ptr; /* Referenced data buffer. */
|
||||
size_t len; /* The data size in bytes. */
|
||||
#ifdef DEBUGBUILD
|
||||
int signature; /* Detect API use mistakes. */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
void Curl_bufref_init(struct bufref *br);
|
||||
void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
|
||||
void (*dtor)(void *));
|
||||
const unsigned char *Curl_bufref_ptr(const struct bufref *br);
|
||||
size_t Curl_bufref_len(const struct bufref *br);
|
||||
CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len);
|
||||
void Curl_bufref_free(struct bufref *br);
|
||||
|
||||
#endif
|
||||
+764
@@ -0,0 +1,764 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
#include "curlx/dynbuf.h"
|
||||
#include "sendf.h"
|
||||
#include "http.h"
|
||||
#include "http1.h"
|
||||
#include "http_proxy.h"
|
||||
#include "url.h"
|
||||
#include "select.h"
|
||||
#include "progress.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-h1-proxy.h"
|
||||
#include "connect.h"
|
||||
#include "curl_trc.h"
|
||||
#include "strcase.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "transfer.h"
|
||||
#include "multiif.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
H1_TUNNEL_INIT, /* init/default/no tunnel state */
|
||||
H1_TUNNEL_CONNECT, /* CONNECT request is being send */
|
||||
H1_TUNNEL_RECEIVE, /* CONNECT answer is being received */
|
||||
H1_TUNNEL_RESPONSE, /* CONNECT response received completely */
|
||||
H1_TUNNEL_ESTABLISHED,
|
||||
H1_TUNNEL_FAILED
|
||||
} h1_tunnel_state;
|
||||
|
||||
/* struct for HTTP CONNECT tunneling */
|
||||
struct h1_tunnel_state {
|
||||
struct dynbuf rcvbuf;
|
||||
struct dynbuf request_data;
|
||||
size_t nsent;
|
||||
size_t headerlines;
|
||||
struct Curl_chunker ch;
|
||||
enum keeponval {
|
||||
KEEPON_DONE,
|
||||
KEEPON_CONNECT,
|
||||
KEEPON_IGNORE
|
||||
} keepon;
|
||||
curl_off_t cl; /* size of content to read and ignore */
|
||||
h1_tunnel_state tunnel_state;
|
||||
BIT(chunked_encoding);
|
||||
BIT(close_connection);
|
||||
};
|
||||
|
||||
|
||||
static bool tunnel_is_established(struct h1_tunnel_state *ts)
|
||||
{
|
||||
return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED);
|
||||
}
|
||||
|
||||
static bool tunnel_is_failed(struct h1_tunnel_state *ts)
|
||||
{
|
||||
return ts && (ts->tunnel_state == H1_TUNNEL_FAILED);
|
||||
}
|
||||
|
||||
static CURLcode tunnel_reinit(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
(void)data;
|
||||
(void)cf;
|
||||
DEBUGASSERT(ts);
|
||||
curlx_dyn_reset(&ts->rcvbuf);
|
||||
curlx_dyn_reset(&ts->request_data);
|
||||
ts->tunnel_state = H1_TUNNEL_INIT;
|
||||
ts->keepon = KEEPON_CONNECT;
|
||||
ts->cl = 0;
|
||||
ts->close_connection = FALSE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode tunnel_init(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state **pts)
|
||||
{
|
||||
struct h1_tunnel_state *ts;
|
||||
|
||||
if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
|
||||
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
ts = calloc(1, sizeof(*ts));
|
||||
if(!ts)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
infof(data, "allocate connect buffer");
|
||||
|
||||
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;
|
||||
connkeep(cf->conn, "HTTP proxy CONNECT");
|
||||
return tunnel_reinit(cf, data, ts);
|
||||
}
|
||||
|
||||
static void h1_tunnel_go_state(struct Curl_cfilter *cf,
|
||||
struct h1_tunnel_state *ts,
|
||||
h1_tunnel_state new_state,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(ts->tunnel_state == new_state)
|
||||
return;
|
||||
/* entering this one */
|
||||
switch(new_state) {
|
||||
case H1_TUNNEL_INIT:
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'init'");
|
||||
tunnel_reinit(cf, data, ts);
|
||||
break;
|
||||
|
||||
case H1_TUNNEL_CONNECT:
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'connect'");
|
||||
ts->tunnel_state = H1_TUNNEL_CONNECT;
|
||||
ts->keepon = KEEPON_CONNECT;
|
||||
curlx_dyn_reset(&ts->rcvbuf);
|
||||
break;
|
||||
|
||||
case H1_TUNNEL_RECEIVE:
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'receive'");
|
||||
ts->tunnel_state = H1_TUNNEL_RECEIVE;
|
||||
break;
|
||||
|
||||
case H1_TUNNEL_RESPONSE:
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'response'");
|
||||
ts->tunnel_state = H1_TUNNEL_RESPONSE;
|
||||
break;
|
||||
|
||||
case H1_TUNNEL_ESTABLISHED:
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'established'");
|
||||
infof(data, "CONNECT phase completed");
|
||||
data->state.authproxy.done = TRUE;
|
||||
data->state.authproxy.multipass = FALSE;
|
||||
FALLTHROUGH();
|
||||
case H1_TUNNEL_FAILED:
|
||||
if(new_state == H1_TUNNEL_FAILED)
|
||||
CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
|
||||
ts->tunnel_state = new_state;
|
||||
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 */
|
||||
/* If a proxy-authorization header was used for the proxy, then we should
|
||||
make sure that it is not accidentally used for the document request
|
||||
after we have connected. So let's free and clear it here. */
|
||||
Curl_safefree(data->state.aptr.proxyuserpwd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_free(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(cf) {
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
if(ts) {
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
curlx_dyn_free(&ts->rcvbuf);
|
||||
curlx_dyn_free(&ts->request_data);
|
||||
Curl_httpchunk_free(data, &ts->ch);
|
||||
free(ts);
|
||||
cf->ctx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool tunnel_want_send(struct h1_tunnel_state *ts)
|
||||
{
|
||||
return ts->tunnel_state == H1_TUNNEL_CONNECT;
|
||||
}
|
||||
|
||||
static CURLcode start_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
struct httpreq *req = NULL;
|
||||
int http_minor;
|
||||
CURLcode result;
|
||||
|
||||
/* This only happens if we have looped here due to authentication
|
||||
reasons, and we do not really use the newly cloned URL here
|
||||
then. Just free() it. */
|
||||
Curl_safefree(data->req.newurl);
|
||||
|
||||
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
infof(data, "Establish HTTP proxy tunnel to %s", req->authority);
|
||||
|
||||
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;
|
||||
|
||||
result = Curl_h1_req_write_head(req, http_minor, &ts->request_data);
|
||||
if(!result)
|
||||
result = Curl_creader_set_null(data);
|
||||
|
||||
out:
|
||||
if(result)
|
||||
failf(data, "Failed sending CONNECT to proxy");
|
||||
if(req)
|
||||
Curl_http_req_free(req);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode send_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
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;
|
||||
size_t nwritten;
|
||||
|
||||
if(blen <= ts->nsent)
|
||||
goto out; /* we are done */
|
||||
|
||||
blen -= ts->nsent;
|
||||
buf += ts->nsent;
|
||||
|
||||
result = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &nwritten);
|
||||
if(result) {
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(blen >= nwritten);
|
||||
ts->nsent += nwritten;
|
||||
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten);
|
||||
|
||||
out:
|
||||
if(result)
|
||||
failf(data, "Failed sending CONNECT to proxy");
|
||||
*done = (!result && (ts->nsent >= request_len));
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode on_resp_header(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts,
|
||||
const char *header)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
(void)cf;
|
||||
|
||||
if((checkprefix("WWW-Authenticate:", header) &&
|
||||
(401 == k->httpcode)) ||
|
||||
(checkprefix("Proxy-authenticate:", header) &&
|
||||
(407 == k->httpcode))) {
|
||||
|
||||
bool proxy = (k->httpcode == 407);
|
||||
char *auth = Curl_copy_header_value(header);
|
||||
if(!auth)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
CURL_TRC_CF(data, cf, "CONNECT: fwd auth header '%s'", header);
|
||||
result = Curl_http_input_auth(data, proxy, auth);
|
||||
|
||||
free(auth);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
else if(checkprefix("Content-Length:", header)) {
|
||||
if(k->httpcode/100 == 2) {
|
||||
/* A client MUST ignore any Content-Length or Transfer-Encoding
|
||||
header fields received in a successful response to CONNECT.
|
||||
"Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
|
||||
infof(data, "Ignoring Content-Length in CONNECT %03d response",
|
||||
k->httpcode);
|
||||
}
|
||||
else {
|
||||
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,
|
||||
STRCONST("Connection:"), STRCONST("close")))
|
||||
ts->close_connection = TRUE;
|
||||
else if(checkprefix("Transfer-Encoding:", header)) {
|
||||
if(k->httpcode/100 == 2) {
|
||||
/* A client MUST ignore any Content-Length or Transfer-Encoding
|
||||
header fields received in a successful response to CONNECT.
|
||||
"Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
|
||||
infof(data, "Ignoring Transfer-Encoding in "
|
||||
"CONNECT %03d response", k->httpcode);
|
||||
}
|
||||
else if(Curl_compareheader(header,
|
||||
STRCONST("Transfer-Encoding:"),
|
||||
STRCONST("chunked"))) {
|
||||
infof(data, "CONNECT responded chunked");
|
||||
ts->chunked_encoding = TRUE;
|
||||
/* reset our chunky engine */
|
||||
Curl_httpchunk_reset(data, &ts->ch, TRUE);
|
||||
}
|
||||
}
|
||||
else if(Curl_compareheader(header,
|
||||
STRCONST("Proxy-Connection:"),
|
||||
STRCONST("close")))
|
||||
ts->close_connection = TRUE;
|
||||
else if(!strncmp(header, "HTTP/1.", 7) &&
|
||||
((header[7] == '0') || (header[7] == '1')) &&
|
||||
(header[8] == ' ') &&
|
||||
ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) &&
|
||||
!ISDIGIT(header[12])) {
|
||||
/* store the HTTP code from the proxy */
|
||||
data->info.httpproxycode = k->httpcode = (header[9] - '0') * 100 +
|
||||
(header[10] - '0') * 10 + (header[11] - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
char *linep;
|
||||
size_t line_len;
|
||||
int error, writetype;
|
||||
|
||||
#define SELECT_OK 0
|
||||
#define SELECT_ERROR 1
|
||||
|
||||
error = SELECT_OK;
|
||||
*done = FALSE;
|
||||
|
||||
while(ts->keepon) {
|
||||
size_t nread;
|
||||
char byte;
|
||||
|
||||
/* Read one byte at a time to avoid a race condition. Wait at most one
|
||||
second before looping to ensure continuous pgrsUpdates. */
|
||||
result = Curl_conn_recv(data, cf->sockindex, &byte, 1, &nread);
|
||||
if(result == CURLE_AGAIN)
|
||||
/* socket buffer drained, return */
|
||||
return CURLE_OK;
|
||||
|
||||
if(Curl_pgrsUpdate(data))
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
|
||||
if(result) {
|
||||
ts->keepon = KEEPON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!nread) {
|
||||
if(data->set.proxyauth && data->state.authproxy.avail &&
|
||||
data->state.aptr.proxyuserpwd) {
|
||||
/* proxy auth was requested and there was proxy auth available,
|
||||
then deem this as "mere" proxy disconnect */
|
||||
ts->close_connection = TRUE;
|
||||
infof(data, "Proxy CONNECT connection closed");
|
||||
}
|
||||
else {
|
||||
error = SELECT_ERROR;
|
||||
failf(data, "Proxy CONNECT aborted");
|
||||
}
|
||||
ts->keepon = KEEPON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(ts->keepon == KEEPON_IGNORE) {
|
||||
/* This means we are currently ignoring a response-body */
|
||||
|
||||
if(ts->cl) {
|
||||
/* A Content-Length based body: simply count down the counter
|
||||
and make sure to break out of the loop when we are done! */
|
||||
ts->cl--;
|
||||
if(ts->cl <= 0) {
|
||||
ts->keepon = KEEPON_DONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(ts->chunked_encoding) {
|
||||
/* chunked-encoded body, so we need to do the chunked dance
|
||||
properly to know when the end of the body is reached */
|
||||
size_t consumed = 0;
|
||||
|
||||
/* now parse the chunked piece of data so that we can
|
||||
properly tell when the stream ends */
|
||||
result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
|
||||
if(result)
|
||||
return result;
|
||||
if(Curl_httpchunk_is_done(data, &ts->ch)) {
|
||||
/* we are done reading chunks! */
|
||||
infof(data, "chunk reading DONE");
|
||||
ts->keepon = KEEPON_DONE;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(curlx_dyn_addn(&ts->rcvbuf, &byte, 1)) {
|
||||
failf(data, "CONNECT response too large");
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
|
||||
/* if this is not the end of a header line then continue */
|
||||
if(byte != 0x0a)
|
||||
continue;
|
||||
|
||||
ts->headerlines++;
|
||||
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);
|
||||
|
||||
/* send the header to the callback */
|
||||
writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
|
||||
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
|
||||
result = Curl_client_write(data, writetype, linep, line_len);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_bump_headersize(data, line_len, TRUE);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Newlines are CRLF, so the CR is ignored as the line is not
|
||||
really terminated until the LF comes. Treat a following CR
|
||||
as end-of-headers as well.*/
|
||||
|
||||
if(('\r' == linep[0]) ||
|
||||
('\n' == linep[0])) {
|
||||
/* end of response-headers from the proxy */
|
||||
|
||||
if((407 == k->httpcode) && !data->state.authproblem) {
|
||||
/* If we get a 407 response code with content length
|
||||
when we have no auth problem, we must ignore the
|
||||
whole response-body */
|
||||
ts->keepon = KEEPON_IGNORE;
|
||||
|
||||
if(ts->cl) {
|
||||
infof(data, "Ignore %" FMT_OFF_T " bytes of response-body", ts->cl);
|
||||
}
|
||||
else if(ts->chunked_encoding) {
|
||||
infof(data, "Ignore chunked response-body");
|
||||
}
|
||||
else {
|
||||
/* without content-length or chunked encoding, we
|
||||
cannot keep the connection alive since the close is
|
||||
the end signal so we bail out at once instead */
|
||||
CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
|
||||
ts->keepon = KEEPON_DONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ts->keepon = KEEPON_DONE;
|
||||
}
|
||||
|
||||
DEBUGASSERT(ts->keepon == KEEPON_IGNORE
|
||||
|| ts->keepon == KEEPON_DONE);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = on_resp_header(cf, data, ts, linep);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
curlx_dyn_reset(&ts->rcvbuf);
|
||||
} /* while there is buffer left and loop is requested */
|
||||
|
||||
if(error)
|
||||
result = CURLE_RECV_ERROR;
|
||||
*done = (ts->keepon == KEEPON_DONE);
|
||||
if(!result && *done && data->info.httpproxycode/100 != 2) {
|
||||
/* Deal with the possibly already received authenticate
|
||||
headers. 'newurl' is set to a new URL if we must loop. */
|
||||
result = Curl_http_auth_act(data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
struct connectdata *conn = cf->conn;
|
||||
CURLcode result;
|
||||
bool done;
|
||||
|
||||
if(tunnel_is_established(ts))
|
||||
return CURLE_OK;
|
||||
if(tunnel_is_failed(ts))
|
||||
return CURLE_RECV_ERROR; /* Need a cfilter close and new bootstrap */
|
||||
|
||||
do {
|
||||
timediff_t check;
|
||||
|
||||
check = Curl_timeleft(data, NULL, TRUE);
|
||||
if(check <= 0) {
|
||||
failf(data, "Proxy CONNECT aborted due to timeout");
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch(ts->tunnel_state) {
|
||||
case H1_TUNNEL_INIT:
|
||||
/* Prepare the CONNECT request and make a first attempt to send. */
|
||||
CURL_TRC_CF(data, cf, "CONNECT start");
|
||||
result = start_CONNECT(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data);
|
||||
FALLTHROUGH();
|
||||
|
||||
case H1_TUNNEL_CONNECT:
|
||||
/* see that the request is completely sent */
|
||||
CURL_TRC_CF(data, cf, "CONNECT send");
|
||||
result = send_CONNECT(cf, data, ts, &done);
|
||||
if(result || !done)
|
||||
goto out;
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data);
|
||||
FALLTHROUGH();
|
||||
|
||||
case H1_TUNNEL_RECEIVE:
|
||||
/* read what is there */
|
||||
CURL_TRC_CF(data, cf, "CONNECT receive");
|
||||
result = recv_CONNECT_resp(cf, data, ts, &done);
|
||||
if(Curl_pgrsUpdate(data)) {
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
goto out;
|
||||
}
|
||||
/* error or not complete yet. return for more multi-multi */
|
||||
if(result || !done)
|
||||
goto out;
|
||||
/* got it */
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data);
|
||||
FALLTHROUGH();
|
||||
|
||||
case H1_TUNNEL_RESPONSE:
|
||||
CURL_TRC_CF(data, cf, "CONNECT response");
|
||||
if(data->req.newurl) {
|
||||
/* not the "final" response, we need to do a follow up request.
|
||||
* If the other side indicated a connection close, or if someone
|
||||
* else told us to close this connection, do so now.
|
||||
*/
|
||||
Curl_req_soft_reset(&data->req, data);
|
||||
if(ts->close_connection || conn->bits.close) {
|
||||
/* Close this filter and the sub-chain, re-connect the
|
||||
* sub-chain and continue. Closing this filter will
|
||||
* reset our tunnel state. To avoid recursion, we return
|
||||
* and expect to be called again.
|
||||
*/
|
||||
CURL_TRC_CF(data, cf, "CONNECT need to close+open");
|
||||
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, &done);
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
/* staying on this connection, reset state */
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_INIT, data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while(data->req.newurl);
|
||||
|
||||
DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
|
||||
if(data->info.httpproxycode/100 != 2) {
|
||||
/* a non-2xx response and we have no next URL to try. */
|
||||
Curl_safefree(data->req.newurl);
|
||||
/* failure, close this connection to avoid reuse */
|
||||
streamclose(conn, "proxy CONNECT failure");
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
/* 2xx response, SUCCESS! */
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data);
|
||||
infof(data, "CONNECT tunnel established, response %d",
|
||||
data->info.httpproxycode);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(result)
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "connect");
|
||||
result = cf->next->cft->do_connect(cf->next, data, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
*done = FALSE;
|
||||
if(!ts) {
|
||||
result = tunnel_init(cf, data, &ts);
|
||||
if(result)
|
||||
return result;
|
||||
cf->ctx = ts;
|
||||
}
|
||||
|
||||
/* We want "seamless" operations through HTTP proxy tunnel */
|
||||
|
||||
result = H1_CONNECT(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_safefree(data->state.aptr.proxyuserpwd);
|
||||
|
||||
out:
|
||||
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
|
||||
if(*done) {
|
||||
cf->connected = TRUE;
|
||||
/* The real request will follow the CONNECT, reset request partially */
|
||||
Curl_req_soft_reset(&data->req, data);
|
||||
Curl_client_reset(data);
|
||||
Curl_pgrsSetUploadCounter(data, 0);
|
||||
Curl_pgrsSetDownloadCounter(data, 0);
|
||||
|
||||
tunnel_free(cf, data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(!cf->connected) {
|
||||
/* If we are not connected, but the filter "below" is
|
||||
* and not waiting on something, we are tunneling. */
|
||||
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
|
||||
if(ts) {
|
||||
/* when we have sent a CONNECT to a proxy, we should rather either
|
||||
wait for the socket to become readable to be able to get the
|
||||
response headers or if we are still sending the request, wait
|
||||
for write. */
|
||||
if(tunnel_want_send(ts))
|
||||
result = Curl_pollset_set_out_only(data, ps, sock);
|
||||
else
|
||||
result = Curl_pollset_set_in_only(data, ps, sock);
|
||||
}
|
||||
else
|
||||
result = Curl_pollset_set_out_only(data, ps, sock);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
tunnel_free(cf, data);
|
||||
}
|
||||
|
||||
static void cf_h1_proxy_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
if(cf) {
|
||||
cf->connected = FALSE;
|
||||
if(cf->ctx) {
|
||||
h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
|
||||
}
|
||||
if(cf->next)
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Curl_cftype Curl_cft_h1_proxy = {
|
||||
"H1-PROXY",
|
||||
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
|
||||
0,
|
||||
cf_h1_proxy_destroy,
|
||||
cf_h1_proxy_connect,
|
||||
cf_h1_proxy_close,
|
||||
Curl_cf_def_shutdown,
|
||||
cf_h1_proxy_adjust_pollset,
|
||||
Curl_cf_def_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_http_proxy_query,
|
||||
};
|
||||
|
||||
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, NULL);
|
||||
if(!result)
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !CURL_DISABLE_PROXY && ! CURL_DISABLE_HTTP */
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_H1_PROXY_H
|
||||
#define HEADER_CURL_H1_PROXY_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||
|
||||
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_h1_proxy;
|
||||
|
||||
|
||||
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
|
||||
|
||||
#endif /* HEADER_CURL_H1_PROXY_H */
|
||||
+1624
File diff suppressed because it is too large
Load Diff
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_H2_PROXY_H
|
||||
#define HEADER_CURL_H2_PROXY_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY)
|
||||
|
||||
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_h2_proxy;
|
||||
|
||||
#endif /* USE_NGHTTP2 && !CURL_DISABLE_PROXY */
|
||||
|
||||
#endif /* HEADER_CURL_H2_PROXY_H */
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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"
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-haproxy.h"
|
||||
#include "curl_trc.h"
|
||||
#include "multiif.h"
|
||||
#include "select.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
HAPROXY_INIT, /* init/default/no tunnel state */
|
||||
HAPROXY_SEND, /* data_out being sent */
|
||||
HAPROXY_DONE /* all work done */
|
||||
} haproxy_state;
|
||||
|
||||
struct cf_haproxy_ctx {
|
||||
int state;
|
||||
struct dynbuf data_out;
|
||||
};
|
||||
|
||||
static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
|
||||
{
|
||||
DEBUGASSERT(ctx);
|
||||
ctx->state = HAPROXY_INIT;
|
||||
curlx_dyn_reset(&ctx->data_out);
|
||||
}
|
||||
|
||||
static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
curlx_dyn_free(&ctx->data_out);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_haproxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
const char *client_ip;
|
||||
struct ip_quadruple ipquad;
|
||||
bool is_ipv6;
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
DEBUGASSERT(ctx->state == HAPROXY_INIT);
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(cf->conn->unix_domain_socket)
|
||||
/* the buffer is large enough to hold this! */
|
||||
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);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Emit the correct prefix for IPv6 */
|
||||
if(data->set.str[STRING_HAPROXY_CLIENT_IP])
|
||||
client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
|
||||
else
|
||||
client_ip = ipquad.local_ip;
|
||||
|
||||
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
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_haproxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
size_t len;
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
result = cf->next->cft->do_connect(cf->next, data, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
switch(ctx->state) {
|
||||
case HAPROXY_INIT:
|
||||
result = cf_haproxy_date_out_set(cf, data);
|
||||
if(result)
|
||||
goto out;
|
||||
ctx->state = HAPROXY_SEND;
|
||||
FALLTHROUGH();
|
||||
case HAPROXY_SEND:
|
||||
len = curlx_dyn_len(&ctx->data_out);
|
||||
if(len > 0) {
|
||||
size_t nwritten;
|
||||
result = Curl_conn_cf_send(cf->next, data,
|
||||
curlx_dyn_ptr(&ctx->data_out), len, FALSE,
|
||||
&nwritten);
|
||||
if(result) {
|
||||
if(result != CURLE_AGAIN)
|
||||
goto out;
|
||||
result = CURLE_OK;
|
||||
nwritten = 0;
|
||||
}
|
||||
curlx_dyn_tail(&ctx->data_out, len - nwritten);
|
||||
if(curlx_dyn_len(&ctx->data_out) > 0) {
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ctx->state = HAPROXY_DONE;
|
||||
FALLTHROUGH();
|
||||
default:
|
||||
curlx_dyn_free(&ctx->data_out);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
*done = (!result) && (ctx->state == HAPROXY_DONE);
|
||||
cf->connected = *done;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cf_haproxy_destroy(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
(void)data;
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
cf_haproxy_ctx_free(cf->ctx);
|
||||
}
|
||||
|
||||
static void cf_haproxy_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
cf->connected = FALSE;
|
||||
cf_haproxy_ctx_reset(cf->ctx);
|
||||
if(cf->next)
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
if(cf->next->connected && !cf->connected) {
|
||||
/* If we are not connected, but the filter "below" is
|
||||
* and not waiting on something, we are sending. */
|
||||
return Curl_pollset_set_out_only(
|
||||
data, ps, Curl_conn_cf_get_socket(cf, data));
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_haproxy = {
|
||||
"HAPROXY",
|
||||
CF_TYPE_PROXY,
|
||||
0,
|
||||
cf_haproxy_destroy,
|
||||
cf_haproxy_connect,
|
||||
cf_haproxy_close,
|
||||
Curl_cf_def_shutdown,
|
||||
cf_haproxy_adjust_pollset,
|
||||
Curl_cf_def_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_def_query,
|
||||
};
|
||||
|
||||
static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
struct cf_haproxy_ctx *ctx;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
ctx->state = HAPROXY_INIT;
|
||||
curlx_dyn_init(&ctx->data_out, DYN_HAXPROXY);
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
ctx = NULL;
|
||||
|
||||
out:
|
||||
cf_haproxy_ctx_free(ctx);
|
||||
*pcf = result ? NULL : cf;
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_haproxy_create(&cf, data);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_CF_HAPROXY_H
|
||||
#define HEADER_CURL_CF_HAPROXY_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"
|
||||
#include "urldata.h"
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_haproxy;
|
||||
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
|
||||
#endif /* HEADER_CURL_CF_HAPROXY_H */
|
||||
+752
@@ -0,0 +1,752 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
#include "urldata.h"
|
||||
#include <curl/curl.h>
|
||||
#include "curl_trc.h"
|
||||
#include "cfilters.h"
|
||||
#include "connect.h"
|
||||
#include "hostip.h"
|
||||
#include "multiif.h"
|
||||
#include "cf-https-connect.h"
|
||||
#include "http2.h"
|
||||
#include "select.h"
|
||||
#include "vquic/vquic.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
typedef enum {
|
||||
CF_HC_INIT,
|
||||
CF_HC_CONNECT,
|
||||
CF_HC_SUCCESS,
|
||||
CF_HC_FAILURE
|
||||
} cf_hc_state;
|
||||
|
||||
struct cf_hc_baller {
|
||||
const char *name;
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
struct curltime started;
|
||||
int reply_ms;
|
||||
unsigned char transport;
|
||||
enum alpnid alpn_id;
|
||||
BIT(shutdown);
|
||||
};
|
||||
|
||||
static void cf_hc_baller_reset(struct cf_hc_baller *b,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(b->cf) {
|
||||
Curl_conn_cf_close(b->cf, data);
|
||||
Curl_conn_cf_discard_chain(&b->cf, data);
|
||||
b->cf = NULL;
|
||||
}
|
||||
b->result = CURLE_OK;
|
||||
b->reply_ms = -1;
|
||||
}
|
||||
|
||||
static bool cf_hc_baller_is_active(struct cf_hc_baller *b)
|
||||
{
|
||||
return b->cf && !b->result;
|
||||
}
|
||||
|
||||
static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
|
||||
{
|
||||
return !!b->cf;
|
||||
}
|
||||
|
||||
static int cf_hc_baller_reply_ms(struct cf_hc_baller *b,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(b->cf && (b->reply_ms < 0))
|
||||
b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS,
|
||||
&b->reply_ms, NULL);
|
||||
return b->reply_ms;
|
||||
}
|
||||
|
||||
static bool cf_hc_baller_data_pending(struct cf_hc_baller *b,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data);
|
||||
}
|
||||
|
||||
static bool cf_hc_baller_needs_flush(struct cf_hc_baller *b,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
return b->cf && !b->result && Curl_conn_cf_needs_flush(b->cf, data);
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
|
||||
struct Curl_easy *data,
|
||||
int event, int arg1, void *arg2)
|
||||
{
|
||||
if(b->cf && !b->result)
|
||||
return Curl_conn_cf_cntrl(b->cf, data, FALSE, event, arg1, arg2);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
struct cf_hc_ctx {
|
||||
cf_hc_state state;
|
||||
struct curltime started; /* when connect started */
|
||||
CURLcode result; /* overall result */
|
||||
struct cf_hc_baller ballers[2];
|
||||
size_t baller_count;
|
||||
timediff_t soft_eyeballs_timeout_ms;
|
||||
timediff_t hard_eyeballs_timeout_ms;
|
||||
};
|
||||
|
||||
static void cf_hc_baller_assign(struct cf_hc_baller *b,
|
||||
enum alpnid alpn_id,
|
||||
unsigned char def_transport)
|
||||
{
|
||||
b->alpn_id = alpn_id;
|
||||
b->transport = def_transport;
|
||||
switch(b->alpn_id) {
|
||||
case ALPN_h3:
|
||||
b->name = "h3";
|
||||
b->transport = TRNSPRT_QUIC;
|
||||
break;
|
||||
case ALPN_h2:
|
||||
b->name = "h2";
|
||||
break;
|
||||
case ALPN_h1:
|
||||
b->name = "h1";
|
||||
break;
|
||||
default:
|
||||
b->result = CURLE_FAILED_INIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_hc_baller_init(struct cf_hc_baller *b,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int transport)
|
||||
{
|
||||
struct Curl_cfilter *save = cf->next;
|
||||
|
||||
cf->next = NULL;
|
||||
b->started = curlx_now();
|
||||
switch(b->alpn_id) {
|
||||
case ALPN_h3:
|
||||
transport = TRNSPRT_QUIC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(!b->result)
|
||||
b->result = Curl_cf_setup_insert_after(cf, data, transport,
|
||||
CURL_CF_SSL_ENABLE);
|
||||
b->cf = cf->next;
|
||||
cf->next = save;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct Curl_cfilter *save = cf->next;
|
||||
|
||||
cf->next = b->cf;
|
||||
b->result = Curl_conn_cf_connect(cf->next, data, done);
|
||||
b->cf = cf->next; /* it might mutate */
|
||||
cf->next = save;
|
||||
return b->result;
|
||||
}
|
||||
|
||||
static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
|
||||
if(ctx) {
|
||||
for(i = 0; i < ctx->baller_count; ++i)
|
||||
cf_hc_baller_reset(&ctx->ballers[i], 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 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode baller_connected(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_hc_baller *winner)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
int reply_ms;
|
||||
size_t i;
|
||||
|
||||
DEBUGASSERT(winner->cf);
|
||||
for(i = 0; i < ctx->baller_count; ++i)
|
||||
if(winner != &ctx->ballers[i])
|
||||
cf_hc_baller_reset(&ctx->ballers[i], data);
|
||||
|
||||
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)curlx_timediff(curlx_now(),
|
||||
winner->started), reply_ms);
|
||||
else
|
||||
CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
|
||||
winner->name, (int)curlx_timediff(curlx_now(),
|
||||
winner->started));
|
||||
|
||||
/* install the winning filter below this one. */
|
||||
cf->next = winner->cf;
|
||||
winner->cf = NULL;
|
||||
|
||||
#ifdef USE_NGHTTP2
|
||||
{
|
||||
/* Using nghttp2, we add the filter "below" us, so when the conn
|
||||
* closes, we tear it down for a fresh reconnect */
|
||||
const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data);
|
||||
if(alpn && !strcmp("h2", alpn)) {
|
||||
result = Curl_http2_switch_at(cf, data);
|
||||
if(result) {
|
||||
ctx->state = CF_HC_FAILURE;
|
||||
ctx->result = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx->state = CF_HC_SUCCESS;
|
||||
cf->connected = TRUE;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool time_to_start_next(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
size_t idx, struct curltime now)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
timediff_t elapsed_ms;
|
||||
size_t i;
|
||||
|
||||
if(idx >= ctx->baller_count)
|
||||
return FALSE;
|
||||
if(cf_hc_baller_has_started(&ctx->ballers[idx]))
|
||||
return FALSE;
|
||||
for(i = 0; i < idx; i++) {
|
||||
if(!ctx->ballers[i].result)
|
||||
break;
|
||||
}
|
||||
if(i == idx) {
|
||||
CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
|
||||
ctx->ballers[idx].name);
|
||||
return TRUE;
|
||||
}
|
||||
elapsed_ms = curlx_timediff(now, ctx->started);
|
||||
if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
|
||||
CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, "
|
||||
"starting %s",
|
||||
ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
|
||||
if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
|
||||
CURL_TRC_CF(data, cf, "soft timeout of %" FMT_TIMEDIFF_T "ms reached, "
|
||||
"%s has not seen any data, starting %s",
|
||||
ctx->soft_eyeballs_timeout_ms,
|
||||
ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
|
||||
return TRUE;
|
||||
}
|
||||
/* set the effective hard timeout again */
|
||||
Curl_expire(data, ctx->hard_eyeballs_timeout_ms - elapsed_ms,
|
||||
EXPIRE_ALPN_EYEBALLS);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
struct curltime now;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t i, failed_ballers;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
*done = FALSE;
|
||||
now = curlx_now();
|
||||
switch(ctx->state) {
|
||||
case CF_HC_INIT:
|
||||
DEBUGASSERT(!cf->next);
|
||||
for(i = 0; i < ctx->baller_count; i++)
|
||||
DEBUGASSERT(!ctx->ballers[i].cf);
|
||||
CURL_TRC_CF(data, cf, "connect, init");
|
||||
ctx->started = now;
|
||||
cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
|
||||
if(ctx->baller_count > 1) {
|
||||
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
|
||||
CURL_TRC_CF(data, cf, "set next attempt to start in %" FMT_TIMEDIFF_T
|
||||
"ms", ctx->soft_eyeballs_timeout_ms);
|
||||
}
|
||||
ctx->state = CF_HC_CONNECT;
|
||||
FALLTHROUGH();
|
||||
|
||||
case CF_HC_CONNECT:
|
||||
if(cf_hc_baller_is_active(&ctx->ballers[0])) {
|
||||
result = cf_hc_baller_connect(&ctx->ballers[0], cf, data, done);
|
||||
if(!result && *done) {
|
||||
result = baller_connected(cf, data, &ctx->ballers[0]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(time_to_start_next(cf, data, 1, now)) {
|
||||
cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
|
||||
}
|
||||
|
||||
if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
|
||||
CURL_TRC_CF(data, cf, "connect, check %s", ctx->ballers[1].name);
|
||||
result = cf_hc_baller_connect(&ctx->ballers[1], cf, data, done);
|
||||
if(!result && *done) {
|
||||
result = baller_connected(cf, data, &ctx->ballers[1]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
failed_ballers = 0;
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
if(ctx->ballers[i].result)
|
||||
++failed_ballers;
|
||||
}
|
||||
|
||||
if(failed_ballers == ctx->baller_count) {
|
||||
/* all have failed. we give up */
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->state = CF_HC_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
result = CURLE_OK;
|
||||
*done = FALSE;
|
||||
break;
|
||||
|
||||
case CF_HC_FAILURE:
|
||||
result = ctx->result;
|
||||
cf->connected = FALSE;
|
||||
*done = FALSE;
|
||||
break;
|
||||
|
||||
case CF_HC_SUCCESS:
|
||||
result = CURLE_OK;
|
||||
cf->connected = TRUE;
|
||||
*done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, bool *done)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* shutdown all ballers that have not done so already. If one fails,
|
||||
* continue shutting down others until all are shutdown. */
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
struct cf_hc_baller *b = &ctx->ballers[i];
|
||||
bool bdone = FALSE;
|
||||
if(!cf_hc_baller_is_active(b) || b->shutdown)
|
||||
continue;
|
||||
b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
|
||||
if(b->result || bdone)
|
||||
b->shutdown = TRUE; /* treat a failed shutdown as done */
|
||||
}
|
||||
|
||||
*done = TRUE;
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
if(!ctx->ballers[i].shutdown)
|
||||
*done = FALSE;
|
||||
}
|
||||
if(*done) {
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
if(ctx->ballers[i].result)
|
||||
result = ctx->ballers[i].result;
|
||||
}
|
||||
}
|
||||
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
if(!cf->connected) {
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
|
||||
for(i = 0; (i < ctx->baller_count) && !result; i++) {
|
||||
struct cf_hc_baller *b = &ctx->ballers[i];
|
||||
if(!cf_hc_baller_is_active(b))
|
||||
continue;
|
||||
result = Curl_conn_cf_adjust_pollset(b->cf, data, ps);
|
||||
}
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool cf_hc_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
|
||||
if(cf->connected)
|
||||
return cf->next->cft->has_data_pending(cf->next, data);
|
||||
|
||||
for(i = 0; i < ctx->baller_count; i++)
|
||||
if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
struct curltime t, tmax;
|
||||
size_t i;
|
||||
|
||||
memset(&tmax, 0, sizeof(tmax));
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
struct Curl_cfilter *cfb = ctx->ballers[i].cf;
|
||||
memset(&t, 0, sizeof(t));
|
||||
if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
|
||||
if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0)
|
||||
tmax = t;
|
||||
}
|
||||
}
|
||||
return tmax;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
|
||||
if(!cf->connected) {
|
||||
switch(query) {
|
||||
case CF_QUERY_TIMER_CONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
case CF_QUERY_TIMER_APPCONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
case CF_QUERY_NEED_FLUSH: {
|
||||
for(i = 0; i < ctx->baller_count; i++)
|
||||
if(cf_hc_baller_needs_flush(&ctx->ballers[i], data)) {
|
||||
*pres1 = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cf->next ?
|
||||
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
|
||||
CURLE_UNKNOWN_OPTION;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int event, int arg1, void *arg2)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t i;
|
||||
|
||||
if(!cf->connected) {
|
||||
for(i = 0; i < ctx->baller_count; i++) {
|
||||
result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2);
|
||||
if(result && (result != CURLE_AGAIN))
|
||||
goto out;
|
||||
}
|
||||
result = CURLE_OK;
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
cf_hc_reset(cf, data);
|
||||
cf->connected = FALSE;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
|
||||
(void)data;
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
cf_hc_reset(cf, data);
|
||||
Curl_safefree(ctx);
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_http_connect = {
|
||||
"HTTPS-CONNECT",
|
||||
0,
|
||||
CURL_LOG_LVL_NONE,
|
||||
cf_hc_destroy,
|
||||
cf_hc_connect,
|
||||
cf_hc_close,
|
||||
cf_hc_shutdown,
|
||||
cf_hc_adjust_pollset,
|
||||
cf_hc_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
cf_hc_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
cf_hc_query,
|
||||
};
|
||||
|
||||
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
enum alpnid *alpnids, size_t alpn_count,
|
||||
unsigned char def_transport)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
struct cf_hc_ctx *ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t i;
|
||||
|
||||
DEBUGASSERT(alpnids);
|
||||
DEBUGASSERT(alpn_count);
|
||||
DEBUGASSERT(alpn_count <= CURL_ARRAYSIZE(ctx->ballers));
|
||||
if(!alpn_count || (alpn_count > CURL_ARRAYSIZE(ctx->ballers))) {
|
||||
failf(data, "https-connect filter create with unsupported %zu ALPN ids",
|
||||
alpn_count);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
for(i = 0; i < alpn_count; ++i)
|
||||
cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport);
|
||||
for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
|
||||
ctx->ballers[i].alpn_id = ALPN_none;
|
||||
ctx->baller_count = alpn_count;
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
ctx = NULL;
|
||||
cf_hc_reset(cf, data);
|
||||
|
||||
out:
|
||||
*pcf = result ? NULL : cf;
|
||||
free(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_http_connect_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
enum alpnid *alpn_ids, size_t alpn_count,
|
||||
unsigned char def_transport)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
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)
|
||||
{
|
||||
enum alpnid alpn_ids[2];
|
||||
size_t alpn_count = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct Curl_cfilter cf_fake, *cf = NULL;
|
||||
|
||||
(void)sockindex;
|
||||
/* 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) {
|
||||
#ifdef USE_HTTPSRR
|
||||
/* 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, conn->transport_wanted))
|
||||
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;
|
||||
}
|
||||
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 < 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, conn->transport_wanted);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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,
|
||||
alpn_ids, alpn_count,
|
||||
conn->transport_wanted);
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !CURL_DISABLE_HTTP */
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#ifndef HEADER_CURL_CF_HTTP_H
|
||||
#define HEADER_CURL_CF_HTTP_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"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
struct Curl_cfilter;
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
struct Curl_cftype;
|
||||
struct Curl_dns_entry;
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http_connect;
|
||||
|
||||
CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool try_h3, bool try_h21);
|
||||
|
||||
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
|
||||
#endif /* !CURL_DISABLE_HTTP */
|
||||
#endif /* HEADER_CURL_CF_HTTP_H */
|
||||
+983
@@ -0,0 +1,983 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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> /* <netinet/tcp.h> may need it */
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h> /* for sockaddr_un */
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TCP_H
|
||||
#include <linux/tcp.h>
|
||||
#elif defined(HAVE_NETINET_TCP_H)
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.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
|
||||
|
||||
#include "urldata.h"
|
||||
#include "connect.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-ip-happy.h"
|
||||
#include "curl_trc.h"
|
||||
#include "multiif.h"
|
||||
#include "progress.h"
|
||||
#include "select.h"
|
||||
#include "vquic/vquic.h" /* for quic cfilters */
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
struct transport_provider {
|
||||
int transport;
|
||||
cf_ip_connect_create *cf_create;
|
||||
};
|
||||
|
||||
static
|
||||
#ifndef UNITTESTS
|
||||
const
|
||||
#endif
|
||||
struct transport_provider transport_providers[] = {
|
||||
{ TRNSPRT_TCP, Curl_cf_tcp_create },
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
|
||||
{ TRNSPRT_QUIC, Curl_cf_quic_create },
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_TFTP
|
||||
{ TRNSPRT_UDP, Curl_cf_udp_create },
|
||||
#endif
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
{ TRNSPRT_UNIX, Curl_cf_unix_create },
|
||||
#endif
|
||||
};
|
||||
|
||||
static cf_ip_connect_create *get_cf_create(int transport)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
|
||||
if(transport == transport_providers[i].transport)
|
||||
return transport_providers[i].cf_create;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef UNITTESTS
|
||||
/* used by unit2600.c */
|
||||
void Curl_debug_set_transport_provider(int transport,
|
||||
cf_ip_connect_create *cf_create)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
|
||||
if(transport == transport_providers[i].transport) {
|
||||
transport_providers[i].cf_create = cf_create;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* UNITTESTS */
|
||||
|
||||
|
||||
struct cf_ai_iter {
|
||||
const struct Curl_addrinfo *head;
|
||||
const struct Curl_addrinfo *last;
|
||||
int ai_family;
|
||||
int n;
|
||||
};
|
||||
|
||||
static void cf_ai_iter_init(struct cf_ai_iter *iter,
|
||||
const struct Curl_addrinfo *list,
|
||||
int ai_family)
|
||||
{
|
||||
iter->head = list;
|
||||
iter->ai_family = ai_family;
|
||||
iter->last = NULL;
|
||||
iter->n = -1;
|
||||
}
|
||||
|
||||
static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter)
|
||||
{
|
||||
const struct Curl_addrinfo *addr;
|
||||
if(iter->n < 0) {
|
||||
iter->n++;
|
||||
for(addr = iter->head; addr; addr = addr->ai_next) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
break;
|
||||
}
|
||||
iter->last = addr;
|
||||
}
|
||||
else if(iter->last) {
|
||||
iter->n++;
|
||||
for(addr = iter->last->ai_next; addr; addr = addr->ai_next) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
break;
|
||||
}
|
||||
iter->last = addr;
|
||||
}
|
||||
return iter->last;
|
||||
}
|
||||
|
||||
static bool cf_ai_iter_has_more(struct cf_ai_iter *iter)
|
||||
{
|
||||
const struct Curl_addrinfo *addr = iter->last ? iter->last->ai_next :
|
||||
((iter->n < 0) ? iter->head : NULL);
|
||||
while(addr) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
return TRUE;
|
||||
addr = addr->ai_next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct cf_ip_attempt {
|
||||
struct cf_ip_attempt *next;
|
||||
const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */
|
||||
struct Curl_cfilter *cf; /* current sub-cfilter connecting */
|
||||
cf_ip_connect_create *cf_create;
|
||||
struct curltime started; /* start of current attempt */
|
||||
CURLcode result;
|
||||
int ai_family;
|
||||
int transport;
|
||||
int error;
|
||||
BIT(connected); /* cf has connected */
|
||||
BIT(shutdown); /* cf has shutdown */
|
||||
BIT(inconclusive); /* connect was not a hard failure, we
|
||||
* might talk to a restarting server */
|
||||
};
|
||||
|
||||
static void cf_ip_attempt_free(struct cf_ip_attempt *a,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(a) {
|
||||
if(a->cf)
|
||||
Curl_conn_cf_discard_chain(&a->cf, data);
|
||||
free(a);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_addrinfo *addr,
|
||||
int ai_family,
|
||||
int transport,
|
||||
cf_ip_connect_create *cf_create)
|
||||
{
|
||||
struct Curl_cfilter *wcf;
|
||||
struct cf_ip_attempt *a;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
*pa = NULL;
|
||||
a = calloc(1, sizeof(*a));
|
||||
if(!a)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
a->addr = addr;
|
||||
a->ai_family = ai_family;
|
||||
a->transport = transport;
|
||||
a->result = CURLE_OK;
|
||||
a->cf_create = cf_create;
|
||||
*pa = a;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, a->addr, transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* the new filter might have sub-filters */
|
||||
for(wcf = a->cf; wcf; wcf = wcf->next) {
|
||||
wcf->conn = cf->conn;
|
||||
wcf->sockindex = cf->sockindex;
|
||||
}
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
cf_ip_attempt_free(a, data);
|
||||
*pa = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_attempt_connect(struct cf_ip_attempt *a,
|
||||
struct Curl_easy *data,
|
||||
bool *connected)
|
||||
{
|
||||
*connected = a->connected;
|
||||
if(!a->result && !*connected) {
|
||||
/* evaluate again */
|
||||
a->result = Curl_conn_cf_connect(a->cf, data, connected);
|
||||
|
||||
if(!a->result) {
|
||||
if(*connected) {
|
||||
a->connected = TRUE;
|
||||
}
|
||||
}
|
||||
else if(a->result == CURLE_WEIRD_SERVER_REPLY)
|
||||
a->inconclusive = TRUE;
|
||||
}
|
||||
return a->result;
|
||||
}
|
||||
|
||||
struct cf_ip_ballers {
|
||||
struct cf_ip_attempt *running;
|
||||
struct cf_ip_attempt *winner;
|
||||
struct cf_ai_iter addr_iter;
|
||||
#ifdef USE_IPV6
|
||||
struct cf_ai_iter ipv6_iter;
|
||||
#endif
|
||||
cf_ip_connect_create *cf_create; /* for creating cf */
|
||||
struct curltime started;
|
||||
struct curltime last_attempt_started;
|
||||
timediff_t attempt_delay_ms;
|
||||
int last_attempt_ai_family;
|
||||
int transport;
|
||||
};
|
||||
|
||||
static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_cfilter *cf_prev = a->cf;
|
||||
struct Curl_cfilter *wcf;
|
||||
CURLcode result;
|
||||
|
||||
/* When restarting, we tear down and existing filter *after* we
|
||||
* started up the new one. This gives us a new socket number and
|
||||
* probably a new local port. Which may prevent confusion. */
|
||||
a->result = CURLE_OK;
|
||||
a->connected = FALSE;
|
||||
a->inconclusive = FALSE;
|
||||
a->cf = NULL;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, a->addr, a->transport);
|
||||
if(!result) {
|
||||
bool dummy;
|
||||
/* the new filter might have sub-filters */
|
||||
for(wcf = a->cf; wcf; wcf = wcf->next) {
|
||||
wcf->conn = cf->conn;
|
||||
wcf->sockindex = cf->sockindex;
|
||||
}
|
||||
a->result = cf_ip_attempt_connect(a, data, &dummy);
|
||||
}
|
||||
if(cf_prev)
|
||||
Curl_conn_cf_discard_chain(&cf_prev, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_ip_ballers *bs)
|
||||
{
|
||||
(void)cf;
|
||||
while(bs->running) {
|
||||
struct cf_ip_attempt *a = bs->running;
|
||||
bs->running = a->next;
|
||||
cf_ip_attempt_free(a, data);
|
||||
}
|
||||
cf_ip_attempt_free(bs->winner, data);
|
||||
bs->winner = NULL;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
|
||||
const struct Curl_addrinfo *addr_list,
|
||||
cf_ip_connect_create *cf_create,
|
||||
int transport,
|
||||
timediff_t attempt_delay_ms)
|
||||
{
|
||||
memset(bs, 0, sizeof(*bs));
|
||||
bs->cf_create = cf_create;
|
||||
bs->transport = transport;
|
||||
bs->attempt_delay_ms = attempt_delay_ms;
|
||||
bs->last_attempt_ai_family = AF_INET; /* so AF_INET6 is next */
|
||||
|
||||
if(transport == TRNSPRT_UNIX) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_UNIX);
|
||||
#else
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
else { /* TCP/UDP/QUIC */
|
||||
#ifdef USE_IPV6
|
||||
if(ip_version == CURL_IPRESOLVE_V6)
|
||||
cf_ai_iter_init(&bs->addr_iter, NULL, AF_INET);
|
||||
else
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET);
|
||||
|
||||
if(ip_version == CURL_IPRESOLVE_V4)
|
||||
cf_ai_iter_init(&bs->ipv6_iter, NULL, AF_INET6);
|
||||
else
|
||||
cf_ai_iter_init(&bs->ipv6_iter, addr_list, AF_INET6);
|
||||
#else
|
||||
(void)ip_version;
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET);
|
||||
#endif
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *connected)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct cf_ip_attempt *a = NULL, **panchor;
|
||||
bool do_more;
|
||||
struct curltime now;
|
||||
timediff_t next_expire_ms;
|
||||
int i, inconclusive, ongoing;
|
||||
|
||||
if(bs->winner)
|
||||
return CURLE_OK;
|
||||
|
||||
evaluate:
|
||||
now = curlx_now();
|
||||
ongoing = inconclusive = 0;
|
||||
|
||||
/* check if a running baller connects now */
|
||||
i = -1;
|
||||
for(panchor = &bs->running; *panchor; panchor = &((*panchor)->next)) {
|
||||
++i;
|
||||
a = *panchor;
|
||||
a->result = cf_ip_attempt_connect(a, data, connected);
|
||||
if(!a->result) {
|
||||
if(*connected) {
|
||||
/* connected, declare the winner, remove from running,
|
||||
* clear remaining running list. */
|
||||
CURL_TRC_CF(data, cf, "connect attempt #%d successful", i);
|
||||
bs->winner = a;
|
||||
*panchor = a->next;
|
||||
a->next = NULL;
|
||||
while(bs->running) {
|
||||
a = bs->running;
|
||||
bs->running = a->next;
|
||||
cf_ip_attempt_free(a, data);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
/* still running */
|
||||
++ongoing;
|
||||
}
|
||||
else if(a->inconclusive) /* failed, but inconclusive */
|
||||
++inconclusive;
|
||||
}
|
||||
if(bs->running)
|
||||
CURL_TRC_CF(data, cf, "checked connect attempts: "
|
||||
"%d ongoing, %d inconclusive", ongoing, inconclusive);
|
||||
|
||||
/* no attempt connected yet, start another one? */
|
||||
if(!ongoing) {
|
||||
if(!bs->started.tv_sec && !bs->started.tv_usec)
|
||||
bs->started = now;
|
||||
do_more = TRUE;
|
||||
}
|
||||
else {
|
||||
bool more_possible = cf_ai_iter_has_more(&bs->addr_iter);
|
||||
#ifdef USE_IPV6
|
||||
if(!more_possible)
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter);
|
||||
#endif
|
||||
do_more = more_possible &&
|
||||
(curlx_timediff(now, bs->last_attempt_started) >=
|
||||
bs->attempt_delay_ms);
|
||||
if(do_more)
|
||||
CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, "
|
||||
"start next attempt");
|
||||
}
|
||||
|
||||
if(do_more) {
|
||||
/* start the next attempt if there is another ip address to try.
|
||||
* Alternate between address families when possible. */
|
||||
const struct Curl_addrinfo *addr = NULL;
|
||||
int ai_family = 0;
|
||||
#ifdef USE_IPV6
|
||||
if((bs->last_attempt_ai_family == AF_INET) ||
|
||||
!cf_ai_iter_has_more(&bs->addr_iter)) {
|
||||
addr = cf_ai_iter_next(&bs->ipv6_iter);
|
||||
ai_family = bs->ipv6_iter.ai_family;
|
||||
}
|
||||
#endif
|
||||
if(!addr) {
|
||||
addr = cf_ai_iter_next(&bs->addr_iter);
|
||||
ai_family = bs->addr_iter.ai_family;
|
||||
}
|
||||
|
||||
if(addr) { /* try another address */
|
||||
result = cf_ip_attempt_new(&a, cf, data, addr, ai_family,
|
||||
bs->transport, bs->cf_create);
|
||||
CURL_TRC_CF(data, cf, "starting %s attempt for ipv%s -> %d",
|
||||
bs->running ? "next" : "first",
|
||||
(ai_family == AF_INET) ? "4" : "6", result);
|
||||
if(result)
|
||||
goto out;
|
||||
DEBUGASSERT(a);
|
||||
|
||||
/* append to running list */
|
||||
panchor = &bs->running;
|
||||
while(*panchor)
|
||||
panchor = &((*panchor)->next);
|
||||
*panchor = a;
|
||||
bs->last_attempt_started = now;
|
||||
bs->last_attempt_ai_family = ai_family;
|
||||
/* and run everything again */
|
||||
goto evaluate;
|
||||
}
|
||||
else if(inconclusive) {
|
||||
/* tried all addresses, no success but some where inconclusive.
|
||||
* Let's restart the inconclusive ones. */
|
||||
timediff_t since_ms = curlx_timediff(now, bs->last_attempt_started);
|
||||
timediff_t delay_ms = bs->attempt_delay_ms - since_ms;
|
||||
if(delay_ms <= 0) {
|
||||
CURL_TRC_CF(data, cf, "all attempts inconclusive, restarting one");
|
||||
i = -1;
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
++i;
|
||||
if(!a->inconclusive)
|
||||
continue;
|
||||
result = cf_ip_attempt_restart(a, cf, data);
|
||||
CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, result);
|
||||
if(result) /* serious failure */
|
||||
goto out;
|
||||
bs->last_attempt_started = now;
|
||||
goto evaluate;
|
||||
}
|
||||
DEBUGASSERT(0); /* should not come here */
|
||||
}
|
||||
else {
|
||||
/* let's wait some more before restarting */
|
||||
infof(data, "connect attempts inconclusive, retrying "
|
||||
"in %" FMT_TIMEDIFF_T "ms", delay_ms);
|
||||
Curl_expire(data, delay_ms, EXPIRE_HAPPY_EYEBALLS);
|
||||
}
|
||||
/* attempt timeout for restart has not expired yet */
|
||||
goto out;
|
||||
}
|
||||
else if(!ongoing) {
|
||||
/* no more addresses, no inconclusive attempts */
|
||||
CURL_TRC_CF(data, cf, "no more attempts to try");
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
i = 0;
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
CURL_TRC_CF(data, cf, "baller %d: result=%d", i, a->result);
|
||||
if(a->result)
|
||||
result = a->result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if(!result) {
|
||||
bool more_possible;
|
||||
|
||||
/* when do we need to be called again? */
|
||||
next_expire_ms = Curl_timeleft(data, &now, TRUE);
|
||||
if(next_expire_ms <= 0) {
|
||||
failf(data, "Connection timeout after %" FMT_OFF_T " ms",
|
||||
curlx_timediff(now, data->progress.t_startsingle));
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
more_possible = cf_ai_iter_has_more(&bs->addr_iter);
|
||||
#ifdef USE_IPV6
|
||||
if(!more_possible)
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter);
|
||||
#endif
|
||||
if(more_possible) {
|
||||
timediff_t expire_ms, elapsed_ms;
|
||||
elapsed_ms = curlx_timediff(now, bs->last_attempt_started);
|
||||
expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0);
|
||||
next_expire_ms = CURLMIN(next_expire_ms, expire_ms);
|
||||
if(next_expire_ms <= 0) {
|
||||
CURL_TRC_CF(data, cf, "HAPPY_EYBALLS timeout due, re-evaluate");
|
||||
goto evaluate;
|
||||
}
|
||||
CURL_TRC_CF(data, cf, "next HAPPY_EYBALLS timeout in %" FMT_TIMEDIFF_T
|
||||
"ms", next_expire_ms);
|
||||
Curl_expire(data, next_expire_ms, EXPIRE_HAPPY_EYEBALLS);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_shutdown(struct cf_ip_ballers *bs,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_ip_attempt *a;
|
||||
|
||||
/* shutdown all ballers that have not done so already. If one fails,
|
||||
* continue shutting down others until all are shutdown. */
|
||||
*done = TRUE;
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
bool bdone = FALSE;
|
||||
if(a->shutdown)
|
||||
continue;
|
||||
a->result = a->cf->cft->do_shutdown(a->cf, data, &bdone);
|
||||
if(a->result || bdone)
|
||||
a->shutdown = TRUE; /* treat a failed shutdown as done */
|
||||
else
|
||||
*done = FALSE;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_pollset(struct cf_ip_ballers *bs,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
struct cf_ip_attempt *a;
|
||||
CURLcode result = CURLE_OK;
|
||||
for(a = bs->running; a && !result; a = a->next) {
|
||||
if(a->result)
|
||||
continue;
|
||||
result = Curl_conn_cf_adjust_pollset(a->cf, data, ps);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool cf_ip_ballers_pending(struct cf_ip_ballers *bs,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_attempt *a;
|
||||
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
if(a->result)
|
||||
continue;
|
||||
if(a->cf->cft->has_data_pending(a->cf, data))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct curltime cf_ip_ballers_max_time(struct cf_ip_ballers *bs,
|
||||
struct Curl_easy *data,
|
||||
int query)
|
||||
{
|
||||
struct curltime t, tmax;
|
||||
struct cf_ip_attempt *a;
|
||||
|
||||
memset(&tmax, 0, sizeof(tmax));
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
memset(&t, 0, sizeof(t));
|
||||
if(!a->cf->cft->query(a->cf, data, query, NULL, &t)) {
|
||||
if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0)
|
||||
tmax = t;
|
||||
}
|
||||
}
|
||||
return tmax;
|
||||
}
|
||||
|
||||
static int cf_ip_ballers_min_reply_ms(struct cf_ip_ballers *bs,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
int reply_ms = -1, breply_ms;
|
||||
struct cf_ip_attempt *a;
|
||||
|
||||
for(a = bs->running; a; a = a->next) {
|
||||
if(!a->cf->cft->query(a->cf, data, CF_QUERY_CONNECT_REPLY_MS,
|
||||
&breply_ms, NULL)) {
|
||||
if(breply_ms >= 0 && (reply_ms < 0 || breply_ms < reply_ms))
|
||||
reply_ms = breply_ms;
|
||||
}
|
||||
}
|
||||
return reply_ms;
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
SCFST_INIT,
|
||||
SCFST_WAITING,
|
||||
SCFST_DONE
|
||||
} cf_connect_state;
|
||||
|
||||
struct cf_ip_happy_ctx {
|
||||
int transport;
|
||||
cf_ip_connect_create *cf_create;
|
||||
cf_connect_state state;
|
||||
struct cf_ip_ballers ballers;
|
||||
struct curltime started;
|
||||
};
|
||||
|
||||
|
||||
static CURLcode is_connected(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *connected)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
struct connectdata *conn = cf->conn;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_ip_ballers_run(&ctx->ballers, cf, data, connected);
|
||||
|
||||
if(!result)
|
||||
return CURLE_OK;
|
||||
|
||||
{
|
||||
const char *hostname, *proxy_name = NULL;
|
||||
char viamsg[160];
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->bits.socksproxy)
|
||||
proxy_name = conn->socks_proxy.host.name;
|
||||
else if(conn->bits.httpproxy)
|
||||
proxy_name = conn->http_proxy.host.name;
|
||||
#endif
|
||||
hostname = conn->bits.conn_to_host ? conn->conn_to_host.name :
|
||||
conn->host.name;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(conn->unix_domain_socket)
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), "over %s",
|
||||
conn->unix_domain_socket);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int port;
|
||||
if(cf->sockindex == SECONDARYSOCKET)
|
||||
port = conn->secondary_port;
|
||||
else if(cf->conn->bits.conn_to_port)
|
||||
port = conn->conn_to_port;
|
||||
else
|
||||
port = conn->remote_port;
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), "port %u", port);
|
||||
}
|
||||
|
||||
failf(data, "Failed to connect to %s %s %s%s%safter "
|
||||
"%" FMT_TIMEDIFF_T " ms: %s",
|
||||
hostname, viamsg,
|
||||
proxy_name ? "via " : "",
|
||||
proxy_name ? proxy_name : "",
|
||||
proxy_name ? " " : "",
|
||||
curlx_timediff(curlx_now(), data->progress.t_startsingle),
|
||||
curl_easy_strerror(result));
|
||||
}
|
||||
|
||||
#ifdef SOCKETIMEDOUT
|
||||
if(SOCKETIMEDOUT == data->state.os_errno)
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the given host with timeout, proxy or remote does not matter.
|
||||
* There might be more than one IP address to try out.
|
||||
*/
|
||||
static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
|
||||
|
||||
if(!dns)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(Curl_timeleft(data, NULL, TRUE) < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
failf(data, "Connection time-out");
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "init ip ballers for transport %d", ctx->transport);
|
||||
ctx->started = curlx_now();
|
||||
return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version,
|
||||
dns->addr, ctx->cf_create, ctx->transport,
|
||||
data->set.happy_eyeballs_timeout);
|
||||
}
|
||||
|
||||
static void cf_ip_happy_ctx_clear(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
DEBUGASSERT(data);
|
||||
cf_ip_ballers_clear(cf, data, &ctx->ballers);
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
result = cf_ip_ballers_shutdown(&ctx->ballers, data, done);
|
||||
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(!cf->connected) {
|
||||
result = cf_ip_ballers_pollset(&ctx->ballers, data, ps);
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
*done = FALSE;
|
||||
|
||||
switch(ctx->state) {
|
||||
case SCFST_INIT:
|
||||
DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
|
||||
DEBUGASSERT(!cf->connected);
|
||||
result = start_connect(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = SCFST_WAITING;
|
||||
FALLTHROUGH();
|
||||
case SCFST_WAITING:
|
||||
result = is_connected(cf, data, done);
|
||||
if(!result && *done) {
|
||||
DEBUGASSERT(ctx->ballers.winner);
|
||||
DEBUGASSERT(ctx->ballers.winner->cf);
|
||||
DEBUGASSERT(ctx->ballers.winner->cf->connected);
|
||||
/* we have a winner. Install and activate it.
|
||||
* close/free all others. */
|
||||
ctx->state = SCFST_DONE;
|
||||
cf->connected = TRUE;
|
||||
cf->next = ctx->ballers.winner->cf;
|
||||
ctx->ballers.winner->cf = NULL;
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
|
||||
|
||||
if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
|
||||
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
if(Curl_trc_cf_is_verbose(cf, data)) {
|
||||
struct ip_quadruple ipquad;
|
||||
bool is_ipv6;
|
||||
if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
|
||||
const char *host;
|
||||
int port;
|
||||
Curl_conn_get_current_host(data, cf->sockindex, &host, &port);
|
||||
CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
|
||||
host, ipquad.remote_ip, ipquad.remote_port);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
data->info.numconnects++; /* to track the # of connections made */
|
||||
}
|
||||
break;
|
||||
case SCFST_DONE:
|
||||
*done = TRUE;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cf_ip_happy_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
cf->connected = FALSE;
|
||||
ctx->state = SCFST_INIT;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool cf_ip_happy_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
if(!cf->connected) {
|
||||
return cf_ip_ballers_pending(&ctx->ballers, data);
|
||||
}
|
||||
return cf->next->cft->has_data_pending(cf->next, data);
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_happy_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
if(!cf->connected) {
|
||||
switch(query) {
|
||||
case CF_QUERY_CONNECT_REPLY_MS: {
|
||||
*pres1 = cf_ip_ballers_min_reply_ms(&ctx->ballers, data);
|
||||
CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1);
|
||||
return CURLE_OK;
|
||||
}
|
||||
case CF_QUERY_TIMER_CONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = cf_ip_ballers_max_time(&ctx->ballers, data,
|
||||
CF_QUERY_TIMER_CONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
case CF_QUERY_TIMER_APPCONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = cf_ip_ballers_max_time(&ctx->ballers, data,
|
||||
CF_QUERY_TIMER_APPCONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cf->next ?
|
||||
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
|
||||
CURLE_UNKNOWN_OPTION;
|
||||
}
|
||||
|
||||
static void cf_ip_happy_destroy(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
if(ctx) {
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
}
|
||||
/* release any resources held in state */
|
||||
Curl_safefree(ctx);
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_ip_happy = {
|
||||
"HAPPY-EYEBALLS",
|
||||
0,
|
||||
CURL_LOG_LVL_NONE,
|
||||
cf_ip_happy_destroy,
|
||||
cf_ip_happy_connect,
|
||||
cf_ip_happy_close,
|
||||
cf_ip_happy_shutdown,
|
||||
cf_ip_happy_adjust_pollset,
|
||||
cf_ip_happy_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
cf_ip_happy_query,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an IP happy eyeball connection filter that uses the, once resolved,
|
||||
* address information to connect on ip families based on connection
|
||||
* configuration.
|
||||
* @param pcf output, the created cfilter
|
||||
* @param data easy handle used in creation
|
||||
* @param conn connection the filter is created for
|
||||
* @param cf_create method to create the sub-filters performing the
|
||||
* actual connects.
|
||||
*/
|
||||
static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
cf_ip_connect_create *cf_create,
|
||||
int transport)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = NULL;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
(void)conn;
|
||||
*pcf = NULL;
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
ctx->transport = transport;
|
||||
ctx->cf_create = cf_create;
|
||||
|
||||
result = Curl_cf_create(pcf, &Curl_cft_ip_happy, ctx);
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
Curl_safefree(*pcf);
|
||||
free(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
int transport)
|
||||
{
|
||||
cf_ip_connect_create *cf_create;
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
/* Need to be first */
|
||||
DEBUGASSERT(cf_at);
|
||||
cf_create = get_cf_create(transport);
|
||||
if(!cf_create) {
|
||||
CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport);
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
result = cf_ip_happy_create(&cf, data, cf_at->conn, cf_create, transport);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
return CURLE_OK;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
#ifndef HEADER_CURL_IP_HAPPY_H
|
||||
#define HEADER_CURL_IP_HAPPY_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"
|
||||
|
||||
#include "curlx/nonblock.h" /* for curlx_nonblock() */
|
||||
#include "sockaddr.h"
|
||||
|
||||
/**
|
||||
* Create a cfilter for making an "ip" connection to the
|
||||
* given address, using parameters from `conn`. The "ip" connection
|
||||
* can be a TCP socket, a UDP socket or even a QUIC connection.
|
||||
*
|
||||
* It MUST use only the supplied `ai` for its connection attempt.
|
||||
*
|
||||
* Such a filter may be used in "happy eyeball" scenarios, and its
|
||||
* `connect` implementation needs to support non-blocking. Once connected,
|
||||
* it MAY be installed in the connection filter chain to serve transfers.
|
||||
*/
|
||||
typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
int transport);
|
||||
|
||||
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
int transport);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_ip_happy;
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void Curl_debug_set_transport_provider(int transport,
|
||||
cf_ip_connect_create *cf_create);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_IP_HAPPY_H */
|
||||
Vendored
+2281
File diff suppressed because it is too large
Load Diff
Vendored
+168
@@ -0,0 +1,168 @@
|
||||
#ifndef HEADER_CURL_CF_SOCKET_H
|
||||
#define HEADER_CURL_CF_SOCKET_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"
|
||||
|
||||
#include "curlx/nonblock.h" /* for curlx_nonblock() */
|
||||
#include "sockaddr.h"
|
||||
|
||||
struct Curl_addrinfo;
|
||||
struct Curl_cfilter;
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
struct Curl_sockaddr_ex;
|
||||
struct ip_quadruple;
|
||||
|
||||
/*
|
||||
* The Curl_sockaddr_ex structure is basically libcurl's external API
|
||||
* curl_sockaddr structure with enough space available to directly hold any
|
||||
* protocol-specific address structures. The variable declared here will be
|
||||
* used to pass / receive data to/from the fopensocket callback if this has
|
||||
* been set, before that, it is initialized from parameters.
|
||||
*/
|
||||
struct Curl_sockaddr_ex {
|
||||
int family;
|
||||
int socktype;
|
||||
int protocol;
|
||||
unsigned int addrlen;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct Curl_sockaddr_storage buf;
|
||||
} addr;
|
||||
};
|
||||
#define curl_sa_addr addr.sa
|
||||
#define curl_sa_addrbuf addr.buf
|
||||
|
||||
/*
|
||||
* Parse interface option, and return the interface name and the host part.
|
||||
*/
|
||||
CURLcode Curl_parse_interface(const char *input,
|
||||
char **dev, char **iface, char **host);
|
||||
|
||||
/*
|
||||
* Create a socket based on info from 'conn' and 'ai'.
|
||||
*
|
||||
* Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
|
||||
* socket callback is set, used that!
|
||||
*
|
||||
*/
|
||||
CURLcode Curl_socket_open(struct Curl_easy *data,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
int transport,
|
||||
curl_socket_t *sockfd);
|
||||
|
||||
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
|
||||
curl_socket_t sock);
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
/* When you run a program that uses the Windows Sockets API, you may
|
||||
experience slow performance when you copy data to a TCP server.
|
||||
|
||||
https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api
|
||||
|
||||
Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
|
||||
Buffer Size
|
||||
|
||||
*/
|
||||
void Curl_sndbuf_init(curl_socket_t sockfd);
|
||||
#else
|
||||
#define Curl_sndbuf_init(y) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a cfilter that opens a TCP socket to the given address
|
||||
* when calling its `connect` implementation.
|
||||
* The filter will not touch any connection/data flags and can be
|
||||
* used in happy eyeballing. Once selected for use, its `_active()`
|
||||
* method needs to be called.
|
||||
*/
|
||||
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
int transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that opens a UDP socket to the given address
|
||||
* when calling its `connect` implementation.
|
||||
* The filter will not touch any connection/data flags and can be
|
||||
* used in happy eyeballing. Once selected for use, its `_active()`
|
||||
* method needs to be called.
|
||||
*/
|
||||
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
int transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that opens a UNIX socket to the given address
|
||||
* when calling its `connect` implementation.
|
||||
* The filter will not touch any connection/data flags and can be
|
||||
* used in happy eyeballing. Once selected for use, its `_active()`
|
||||
* method needs to be called.
|
||||
*/
|
||||
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
int transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that keeps a listening socket.
|
||||
*/
|
||||
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
curl_socket_t *s);
|
||||
|
||||
/**
|
||||
* Return TRUE iff the last filter at `sockindex` was set via
|
||||
* Curl_conn_tcp_listen_set().
|
||||
*/
|
||||
bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
|
||||
int sockindex);
|
||||
|
||||
/**
|
||||
* Peek at the socket and remote ip/port the socket filter is using.
|
||||
* The filter owns all returned values.
|
||||
* @param psock pointer to hold socket descriptor or NULL
|
||||
* @param paddr pointer to hold addr reference or NULL
|
||||
* @param pip pointer to get IP quadruple or NULL
|
||||
* Returns error if the filter is of invalid type.
|
||||
*/
|
||||
CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
curl_socket_t *psock,
|
||||
const struct Curl_sockaddr_ex **paddr,
|
||||
struct ip_quadruple *pip) WARN_UNUSED_RESULT;
|
||||
|
||||
extern struct Curl_cftype Curl_cft_tcp;
|
||||
extern struct Curl_cftype Curl_cft_udp;
|
||||
extern struct Curl_cftype Curl_cft_unix;
|
||||
extern struct Curl_cftype Curl_cft_tcp_accept;
|
||||
|
||||
#endif /* HEADER_CURL_CF_SOCKET_H */
|
||||
Vendored
+1139
File diff suppressed because it is too large
Load Diff
Vendored
+694
@@ -0,0 +1,694 @@
|
||||
#ifndef HEADER_CURL_CFILTERS_H
|
||||
#define HEADER_CURL_CFILTERS_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 "curlx/timediff.h"
|
||||
|
||||
struct bufq;
|
||||
struct Curl_cfilter;
|
||||
struct Curl_easy;
|
||||
struct Curl_dns_entry;
|
||||
struct connectdata;
|
||||
struct ip_quadruple;
|
||||
struct curl_tlssessioninfo;
|
||||
|
||||
/* Callback to destroy resources held by this filter instance.
|
||||
* Implementations MUST NOT chain calls to cf->next.
|
||||
*/
|
||||
typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/* Callback to close the connection immediately. */
|
||||
typedef void Curl_cft_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/* Callback to close the connection filter gracefully, non-blocking.
|
||||
* Implementations MUST NOT chain calls to cf->next.
|
||||
*/
|
||||
typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done);
|
||||
|
||||
typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done);
|
||||
|
||||
struct easy_pollset;
|
||||
|
||||
/* Passing in an easy_pollset for monitoring of sockets, let
|
||||
* filters add or remove sockets actions (CURL_POLL_OUT, CURL_POLL_IN).
|
||||
* This may add a socket or, in case no actions remain, remove
|
||||
* a socket from the set.
|
||||
*
|
||||
* Filter implementations need to call filters "below" *after* they have
|
||||
* made their adjustments. This allows lower filters to override "upper"
|
||||
* actions. If a "lower" filter is unable to write, it needs to be able
|
||||
* to disallow POLL_OUT.
|
||||
*
|
||||
* A filter without own restrictions/preferences should not modify
|
||||
* the pollset. Filters, whose filter "below" is not connected, should
|
||||
* also do no adjustments.
|
||||
*
|
||||
* Examples: a TLS handshake, while ongoing, might remove POLL_IN when it
|
||||
* needs to write, or vice versa. An HTTP/2 filter might remove POLL_OUT when
|
||||
* a stream window is exhausted and a WINDOW_UPDATE needs to be received first
|
||||
* and add instead POLL_IN.
|
||||
*
|
||||
* @param cf the filter to ask
|
||||
* @param data the easy handle the pollset is about
|
||||
* @param ps the pollset (inout) for the easy handle
|
||||
*/
|
||||
typedef CURLcode Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data);
|
||||
|
||||
typedef CURLcode Curl_cft_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, /* transfer */
|
||||
const void *buf, /* data to write */
|
||||
size_t len, /* amount to write */
|
||||
bool eos, /* last chunk */
|
||||
size_t *pnwritten); /* how much sent */
|
||||
|
||||
typedef CURLcode Curl_cft_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, /* transfer */
|
||||
char *buf, /* store data here */
|
||||
size_t len, /* amount to read */
|
||||
size_t *pnread); /* how much received */
|
||||
|
||||
typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *input_pending);
|
||||
|
||||
typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Events/controls for connection filters, their arguments and
|
||||
* return code handling. Filter callbacks are invoked "top down".
|
||||
* Return code handling:
|
||||
* "first fail" meaning that the first filter returning != CURLE_OK, will
|
||||
* abort further event distribution and determine the result.
|
||||
* "ignored" meaning return values are ignored and the event is distributed
|
||||
* to all filters in the chain. Overall result is always CURLE_OK.
|
||||
*/
|
||||
/* data event arg1 arg2 return */
|
||||
#define CF_CTRL_DATA_SETUP 4 /* 0 NULL first fail */
|
||||
/* unused now 5 */
|
||||
#define CF_CTRL_DATA_PAUSE 6 /* on/off NULL first fail */
|
||||
#define CF_CTRL_DATA_DONE 7 /* premature NULL ignored */
|
||||
#define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */
|
||||
/* update conn info at connection and data */
|
||||
#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */
|
||||
#define CF_CTRL_FORGET_SOCKET (256+1) /* 0 NULL ignored */
|
||||
#define CF_CTRL_FLUSH (256+2) /* 0 NULL first fail */
|
||||
|
||||
/**
|
||||
* Handle event/control for the filter.
|
||||
* Implementations MUST NOT chain calls to cf->next.
|
||||
*/
|
||||
typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int event, int arg1, void *arg2);
|
||||
|
||||
|
||||
/**
|
||||
* Queries to ask via a `Curl_cft_query *query` method on a cfilter chain.
|
||||
* - MAX_CONCURRENT: the maximum number of parallel transfers the filter
|
||||
* chain expects to handle at the same time.
|
||||
* default: 1 if no filter overrides.
|
||||
* - CONNECT_REPLY_MS: milliseconds until the first indication of a server
|
||||
* response was received on a connect. For TCP, this
|
||||
* reflects the time until the socket connected. On UDP
|
||||
* this gives the time the first bytes from the server
|
||||
* were received.
|
||||
* -1 if not determined yet.
|
||||
* - CF_QUERY_SOCKET: the socket used by the filter chain
|
||||
* - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data
|
||||
* - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
|
||||
* ip quadruple
|
||||
* - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to
|
||||
* - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the
|
||||
* internal from the SSL secured connection when
|
||||
* available.
|
||||
* - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX
|
||||
* when available, or the same internal pointer
|
||||
* when the TLS stack does not differentiate.
|
||||
* - CF_QUERY_ALPN_NEGOTIATED: The ALPN selected by the server as
|
||||
null-terminated string or NULL if none
|
||||
selected/handshake not done. Implemented by filter
|
||||
types CF_TYPE_SSL or CF_TYPE_IP_CONNECT.
|
||||
*/
|
||||
/* query res1 res2 */
|
||||
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
|
||||
#define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */
|
||||
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
|
||||
#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
|
||||
#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
|
||||
#define CF_QUERY_STREAM_ERROR 6 /* error code - */
|
||||
#define CF_QUERY_NEED_FLUSH 7 /* TRUE/FALSE - */
|
||||
#define CF_QUERY_IP_INFO 8 /* TRUE/FALSE struct ip_quadruple */
|
||||
#define CF_QUERY_HTTP_VERSION 9 /* number (10/11/20/30) - */
|
||||
/* pass in a `const struct Curl_sockaddr_ex **` as `pres2`. Gets set
|
||||
* to NULL when not connected. */
|
||||
#define CF_QUERY_REMOTE_ADDR 10 /* - `Curl_sockaddr_ex *` */
|
||||
#define CF_QUERY_HOST_PORT 11 /* port const char * */
|
||||
#define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */
|
||||
#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */
|
||||
#define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */
|
||||
#define CF_QUERY_ALPN_NEGOTIATED 15 /* - const char * */
|
||||
|
||||
/**
|
||||
* Query the cfilter for properties. Filters ignorant of a query will
|
||||
* pass it "down" the filter chain.
|
||||
*/
|
||||
typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2);
|
||||
|
||||
/**
|
||||
* Type flags for connection filters. A filter can have none, one or
|
||||
* many of those. Use to evaluate state/capabilities of a filter chain.
|
||||
*
|
||||
* CF_TYPE_IP_CONNECT: provides an IP connection or sth equivalent, like
|
||||
* a CONNECT tunnel, a UNIX domain socket, a QUIC
|
||||
* connection, etc.
|
||||
* CF_TYPE_SSL: provide SSL/TLS
|
||||
* CF_TYPE_MULTIPLEX: provides multiplexing of easy handles
|
||||
* CF_TYPE_PROXY provides proxying
|
||||
* CF_TYPE_HTTP implement a version of the HTTP protocol
|
||||
*/
|
||||
#define CF_TYPE_IP_CONNECT (1 << 0)
|
||||
#define CF_TYPE_SSL (1 << 1)
|
||||
#define CF_TYPE_MULTIPLEX (1 << 2)
|
||||
#define CF_TYPE_PROXY (1 << 3)
|
||||
#define CF_TYPE_HTTP (1 << 4)
|
||||
|
||||
/* A connection filter type, e.g. specific implementation. */
|
||||
struct Curl_cftype {
|
||||
const char *name; /* name of the filter type */
|
||||
int flags; /* flags of filter type */
|
||||
int log_level; /* log level for such filters */
|
||||
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
|
||||
Curl_cft_connect *do_connect; /* establish connection */
|
||||
Curl_cft_close *do_close; /* close conn */
|
||||
Curl_cft_shutdown *do_shutdown; /* shutdown conn */
|
||||
Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
|
||||
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
|
||||
Curl_cft_send *do_send; /* send data */
|
||||
Curl_cft_recv *do_recv; /* receive data */
|
||||
Curl_cft_cntrl *cntrl; /* events/control */
|
||||
Curl_cft_conn_is_alive *is_alive; /* FALSE if conn is dead, Jim! */
|
||||
Curl_cft_conn_keep_alive *keep_alive; /* try to keep it alive */
|
||||
Curl_cft_query *query; /* query filter chain */
|
||||
};
|
||||
|
||||
/* A connection filter instance, e.g. registered at a connection */
|
||||
struct Curl_cfilter {
|
||||
const struct Curl_cftype *cft; /* the type providing implementation */
|
||||
struct Curl_cfilter *next; /* next filter in chain */
|
||||
void *ctx; /* filter type specific settings */
|
||||
struct connectdata *conn; /* the connection this filter belongs to */
|
||||
int sockindex; /* the index the filter is installed at */
|
||||
BIT(connected); /* != 0 iff this filter is connected */
|
||||
BIT(shutdown); /* != 0 iff this filter has shut down */
|
||||
};
|
||||
|
||||
/* Default implementations for the type functions, implementing nop. */
|
||||
void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/* Default implementations for the type functions, implementing pass-through
|
||||
* the filter chain. */
|
||||
CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data);
|
||||
CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, bool eos,
|
||||
size_t *pnwritten);
|
||||
CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, size_t *pnread);
|
||||
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
|
||||
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);
|
||||
CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2);
|
||||
CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, bool *done);
|
||||
|
||||
/**
|
||||
* Create a new filter instance, unattached to the filter chain.
|
||||
* Use Curl_conn_cf_add() to add it to the chain.
|
||||
* @param pcf on success holds the created instance
|
||||
* @param cft the filter type
|
||||
* @param ctx the type specific context to use
|
||||
*/
|
||||
CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
|
||||
const struct Curl_cftype *cft,
|
||||
void *ctx);
|
||||
|
||||
/**
|
||||
* Add a filter instance to the `sockindex` filter chain at connection
|
||||
* `conn`. The filter must not already be attached. It is inserted at
|
||||
* the start of the chain (top).
|
||||
*/
|
||||
void Curl_conn_cf_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
struct Curl_cfilter *cf);
|
||||
|
||||
/**
|
||||
* Insert a filter (chain) after `cf_at`.
|
||||
* `cf_new` must not already be attached.
|
||||
*/
|
||||
void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_cfilter *cf_new);
|
||||
|
||||
/**
|
||||
* Extract filter `*pcf` from its connection filter chain.
|
||||
* Destroy `*pcf`, even if it was not part of the chain and NULL it.
|
||||
* Returns TRUE of cf has been part of chain.
|
||||
*/
|
||||
bool Curl_conn_cf_discard(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Discard all cfilters starting with `*pcf` and clearing it afterwards.
|
||||
*/
|
||||
void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Remove and destroy all filters at chain `sockindex` on connection `conn`.
|
||||
*/
|
||||
void Curl_conn_cf_discard_all(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
|
||||
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done);
|
||||
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
|
||||
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, bool eos,
|
||||
size_t *pnwritten);
|
||||
CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, size_t *pnread);
|
||||
CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool ignore_result,
|
||||
int event, int arg1, void *arg2);
|
||||
|
||||
/**
|
||||
* Get the socket used by the filter chain starting at `cf`.
|
||||
* Returns CURL_SOCKET_BAD if not available.
|
||||
*/
|
||||
curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *is_ipv6, struct ip_quadruple *ipquad);
|
||||
|
||||
bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
#define CURL_CF_SSL_DEFAULT -1
|
||||
#define CURL_CF_SSL_DISABLE 0
|
||||
#define CURL_CF_SSL_ENABLE 1
|
||||
|
||||
/**
|
||||
* Bring the filter chain at `sockindex` for connection `data->conn` into
|
||||
* connected state. Which will set `*done` to TRUE.
|
||||
* This can be called on an already connected chain with no side effects.
|
||||
* When not `blocking`, calls may return without error and `*done != TRUE`,
|
||||
* while the individual filters negotiated the connection.
|
||||
*/
|
||||
CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
|
||||
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.
|
||||
*/
|
||||
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex);
|
||||
|
||||
/**
|
||||
* Determine if we have reached the remote host on IP level, e.g.
|
||||
* have a TCP connection. This turns TRUE before a possible SSL
|
||||
* handshake has been started/done.
|
||||
*/
|
||||
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Determine if the connection is using SSL to the remote host
|
||||
* (or will be once connected). This will return FALSE, if SSL
|
||||
* is only used in proxying and not for the tunnel itself.
|
||||
*/
|
||||
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
|
||||
|
||||
/*
|
||||
* Fill `info` with information about the TLS instance securing
|
||||
* the connection when available, otherwise e.g. when
|
||||
* Curl_conn_is_ssl() is FALSE, return FALSE.
|
||||
*/
|
||||
bool Curl_conn_get_ssl_info(struct Curl_easy *data,
|
||||
struct connectdata *conn, int sockindex,
|
||||
struct curl_tlssessioninfo *info);
|
||||
|
||||
CURLcode Curl_conn_get_ip_info(struct Curl_easy *data,
|
||||
struct connectdata *conn, int sockindex,
|
||||
bool *is_ipv6, struct ip_quadruple *ipquad);
|
||||
|
||||
/**
|
||||
* Connection provides multiplexing of easy handles at `socketindex`.
|
||||
*/
|
||||
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
struct connectdata *conn);
|
||||
|
||||
/* Get the TRNSPRT_* the connection is using */
|
||||
unsigned char Curl_conn_get_transport(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
|
||||
/* Get the negotiated ALPN protocol or NULL if none in play */
|
||||
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
|
||||
/**
|
||||
* Close the filter chain at `sockindex` for connection `data->conn`.
|
||||
* Filters remain in place and may be connected again afterwards.
|
||||
*/
|
||||
void Curl_conn_close(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Shutdown the connection at `sockindex` non-blocking, using timeout
|
||||
* from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
|
||||
* Will return CURLE_OK and *done == FALSE if not finished.
|
||||
*/
|
||||
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);
|
||||
|
||||
/**
|
||||
* Return if data is pending in some connection filter at chain
|
||||
* `sockindex` for connection `data->conn`.
|
||||
*/
|
||||
bool Curl_conn_data_pending(struct Curl_easy *data,
|
||||
int sockindex);
|
||||
|
||||
/**
|
||||
* Return TRUE if any of the connection filters at chain `sockindex`
|
||||
* have data still to send.
|
||||
*/
|
||||
bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Flush any pending data on the connection filters at chain `sockindex`.
|
||||
*/
|
||||
CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Return the socket used on data's connection for FIRSTSOCKET,
|
||||
* querying filters if the whole chain has not connected yet.
|
||||
* Returns CURL_SOCKET_BAD if not available.
|
||||
*/
|
||||
curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data);
|
||||
|
||||
/* Return a pointer to the connected socket address or NULL. */
|
||||
const struct Curl_sockaddr_ex *
|
||||
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Tell filters to forget about the socket at sockindex.
|
||||
*/
|
||||
void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/**
|
||||
* Adjust the pollset for the filter chain starting at `cf`.
|
||||
*/
|
||||
CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
/**
|
||||
* Adjust pollset from filters installed at transfer's connection.
|
||||
*/
|
||||
CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
/**
|
||||
* Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
|
||||
* Returns 0 on timeout, negative on error or number of sockets
|
||||
* with requested poll events.
|
||||
*/
|
||||
int Curl_conn_cf_poll(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
timediff_t timeout_ms);
|
||||
|
||||
/**
|
||||
* Receive data through the filter chain at `sockindex` for connection
|
||||
* `data->conn`. Copy at most `len` bytes into `buf`. Return the
|
||||
* actual number of bytes copied in `*pnread`or an error.
|
||||
*/
|
||||
CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
|
||||
size_t len, size_t *pnread);
|
||||
|
||||
/**
|
||||
* Send `len` bytes of data from `buf` through the filter chain `sockindex`
|
||||
* at connection `data->conn`. Return the actual number of bytes written
|
||||
* in `*pnwritten` or on error.
|
||||
*/
|
||||
CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
|
||||
const void *buf, size_t len, bool eos,
|
||||
size_t *pnwritten);
|
||||
|
||||
/**
|
||||
* Receive bytes from connection filter `cf` into `bufq`.
|
||||
* Convenience wrapper around `Curl_bufq_sipn()`,
|
||||
* so users do not have to implement a callback.
|
||||
*/
|
||||
CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct bufq *bufq,
|
||||
size_t maxlen,
|
||||
size_t *pnread);
|
||||
|
||||
/**
|
||||
* Send bytes in `bufq` using connection filter `cf`.
|
||||
* A convenience wrapper around `Curl_bufq_write_pass()`,
|
||||
* so users do not have to implement a callback.
|
||||
*/
|
||||
CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct bufq *bufq,
|
||||
const unsigned char *buf, size_t blen,
|
||||
size_t *pnwritten);
|
||||
|
||||
/**
|
||||
* Notify connection filters that they need to setup data for
|
||||
* a transfer.
|
||||
*/
|
||||
CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Notify connection filters that the transfer represented by `data`
|
||||
* is done with sending data (e.g. has uploaded everything).
|
||||
*/
|
||||
void Curl_conn_ev_data_done_send(struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Notify connection filters that the transfer represented by `data`
|
||||
* is finished - eventually premature, e.g. before being complete.
|
||||
*/
|
||||
void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature);
|
||||
|
||||
/**
|
||||
* Notify connection filters that the transfer of data is paused/unpaused.
|
||||
*/
|
||||
CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause);
|
||||
|
||||
/**
|
||||
* Check if FIRSTSOCKET's cfilter chain deems connection alive.
|
||||
*/
|
||||
bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
|
||||
bool *input_pending);
|
||||
|
||||
/**
|
||||
* Try to upkeep the connection filters at sockindex.
|
||||
*/
|
||||
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the remote hostname and port that the connection is currently
|
||||
* talking to (or will talk to).
|
||||
* Once connected or before connect starts,
|
||||
* it is `conn->host.name` and `conn->remote_port`.
|
||||
* During connect, when tunneling proxies are involved (http or socks),
|
||||
* it will be the name and port the proxy currently negotiates with.
|
||||
*/
|
||||
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
|
||||
const char **phost, int *pport);
|
||||
|
||||
/**
|
||||
* Get the maximum number of parallel transfers the connection
|
||||
* expects to be able to handle at `sockindex`.
|
||||
*/
|
||||
size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
/**
|
||||
* Get the underlying error code for a transfer stream or 0 if not known.
|
||||
*/
|
||||
int Curl_conn_get_stream_error(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
/**
|
||||
* Get the index of the given socket in the connection's sockets.
|
||||
* Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
|
||||
* correct socket index.
|
||||
*/
|
||||
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
|
||||
|
||||
/*
|
||||
* Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
|
||||
* Will return CURLE_AGAIN iff blocked on receiving.
|
||||
*/
|
||||
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
|
||||
char *buf, size_t buffersize,
|
||||
size_t *pnread);
|
||||
|
||||
/*
|
||||
* Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
|
||||
* Will return CURLE_AGAIN iff blocked on sending.
|
||||
*/
|
||||
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
|
||||
const void *buf, size_t blen, bool eos,
|
||||
size_t *pnwritten);
|
||||
|
||||
|
||||
/**
|
||||
* Types and macros used to keep the current easy handle in filter calls,
|
||||
* allowing for nested invocations. See #10336.
|
||||
*
|
||||
* `cf_call_data` is intended to be a member of the cfilter's `ctx` type.
|
||||
* A filter defines the macro `CF_CTX_CALL_DATA` to give access to that.
|
||||
*
|
||||
* With all values 0, the default, this indicates that there is no cfilter
|
||||
* call with `data` ongoing.
|
||||
* Macro `CF_DATA_SAVE` preserves the current `cf_call_data` in a local
|
||||
* variable and sets the `data` given, incrementing the `depth` counter.
|
||||
*
|
||||
* Macro `CF_DATA_RESTORE` restores the old values from the local variable,
|
||||
* while checking that `depth` values are as expected (debug build), catching
|
||||
* cases where a "lower" RESTORE was not called.
|
||||
*
|
||||
* Finally, macro `CF_DATA_CURRENT` gives the easy handle of the current
|
||||
* invocation.
|
||||
*/
|
||||
struct cf_call_data {
|
||||
struct Curl_easy *data;
|
||||
#ifdef DEBUGBUILD
|
||||
int depth;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* define to access the `struct cf_call_data for a cfilter. Normally
|
||||
* a member in the cfilter's `ctx`.
|
||||
*
|
||||
* #define CF_CTX_CALL_DATA(cf) -> struct cf_call_data instance
|
||||
*/
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
#define CF_DATA_SAVE(save, cf, data) \
|
||||
do { \
|
||||
(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 *)CURL_UNCONST(data); \
|
||||
} while(0)
|
||||
|
||||
#define CF_DATA_RESTORE(cf, save) \
|
||||
do { \
|
||||
DEBUGASSERT(CF_CTX_CALL_DATA(cf).depth == (save).depth + 1); \
|
||||
DEBUGASSERT((save).data == NULL || (save).depth > 0); \
|
||||
CF_CTX_CALL_DATA(cf) = (save); \
|
||||
} while(0)
|
||||
|
||||
#else /* DEBUGBUILD */
|
||||
|
||||
#define CF_DATA_SAVE(save, cf, data) \
|
||||
do { \
|
||||
(save) = CF_CTX_CALL_DATA(cf); \
|
||||
CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
|
||||
} while(0)
|
||||
|
||||
#define CF_DATA_RESTORE(cf, save) \
|
||||
do { \
|
||||
CF_CTX_CALL_DATA(cf) = (save); \
|
||||
} while(0)
|
||||
|
||||
#endif /* !DEBUGBUILD */
|
||||
|
||||
#define CF_DATA_CURRENT(cf) \
|
||||
((cf)? (CF_CTX_CALL_DATA(cf).data) : NULL)
|
||||
|
||||
#endif /* HEADER_CURL_CFILTERS_H */
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
#ifndef HEADER_CURL_CONFIG_MAC_H
|
||||
#define HEADER_CURL_CONFIG_MAC_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* =================================================================== */
|
||||
/* Hand crafted config file for Mac OS 9 */
|
||||
/* =================================================================== */
|
||||
/* On macOS you must run configure to generate curl_config.h file */
|
||||
/* =================================================================== */
|
||||
|
||||
#ifndef CURL_OS
|
||||
#define CURL_OS "mac"
|
||||
#endif
|
||||
|
||||
#include <ConditionalMacros.h>
|
||||
#if TYPE_LONGLONG
|
||||
#define HAVE_LONGLONG 1
|
||||
#endif
|
||||
|
||||
/* Define if you want the built-in manual */
|
||||
#define USE_MANUAL 1
|
||||
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
#define HAVE_NETDB_H 1
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_NET_IF_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
#define HAVE_FCNTL_H 1
|
||||
#define HAVE_UTIME_H 1
|
||||
#define HAVE_SYS_UTIME_H 1
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
#define HAVE_ALARM 1
|
||||
#define HAVE_FTRUNCATE 1
|
||||
#define HAVE_UTIME 1
|
||||
#define HAVE_SELECT 1
|
||||
#define HAVE_SOCKET 1
|
||||
#define HAVE_STRUCT_TIMEVAL 1
|
||||
|
||||
#define HAVE_SIGACTION 1
|
||||
|
||||
#define CURL_DISABLE_LDAP 1
|
||||
|
||||
#define HAVE_IOCTL_FIONBIO 1
|
||||
|
||||
#define SIZEOF_INT 4
|
||||
#define SIZEOF_LONG 4
|
||||
#define SIZEOF_SIZE_T 4
|
||||
#ifdef HAVE_LONGLONG
|
||||
#define SIZEOF_CURL_OFF_T 8
|
||||
#else
|
||||
#define SIZEOF_CURL_OFF_T 4
|
||||
#endif
|
||||
|
||||
#define HAVE_RECV 1
|
||||
#define RECV_TYPE_ARG1 int
|
||||
#define RECV_TYPE_ARG2 void *
|
||||
#define RECV_TYPE_ARG3 size_t
|
||||
#define RECV_TYPE_ARG4 int
|
||||
#define RECV_TYPE_RETV ssize_t
|
||||
|
||||
#define HAVE_SEND 1
|
||||
#define SEND_TYPE_ARG1 int
|
||||
#define SEND_QUAL_ARG2 const
|
||||
#define SEND_TYPE_ARG2 void *
|
||||
#define SEND_TYPE_ARG3 size_t
|
||||
#define SEND_TYPE_ARG4 int
|
||||
#define SEND_TYPE_RETV ssize_t
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG_MAC_H */
|
||||
+295
@@ -0,0 +1,295 @@
|
||||
#ifndef HEADER_CURL_CONFIG_OS400_H
|
||||
#define HEADER_CURL_CONFIG_OS400_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* ================================================================ */
|
||||
/* Hand crafted config file for OS/400 */
|
||||
/* ================================================================ */
|
||||
|
||||
#pragma enum(int)
|
||||
|
||||
/* Define cpu-machine-OS */
|
||||
#ifndef CURL_OS
|
||||
#define CURL_OS "OS/400"
|
||||
#endif
|
||||
|
||||
/* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its
|
||||
* prototype is incompatible with the "standard" one (1st argument is not
|
||||
* const). However, getaddrinfo() is supported (ASCII version defined as
|
||||
* a local wrapper in setup-os400.h) in a threadsafe way: we can then
|
||||
* configure getaddrinfo() as such and get rid of gethostbyname_r() without
|
||||
* loss of threadsafeness. */
|
||||
#undef HAVE_GETHOSTBYNAME_R
|
||||
#undef HAVE_GETHOSTBYNAME_R_3
|
||||
#undef HAVE_GETHOSTBYNAME_R_5
|
||||
#undef HAVE_GETHOSTBYNAME_R_6
|
||||
#define HAVE_GETADDRINFO
|
||||
#define HAVE_GETADDRINFO_THREADSAFE
|
||||
|
||||
/* Define if you need the _REENTRANT define for some functions */
|
||||
#undef NEED_REENTRANT
|
||||
|
||||
/* Define if you want to enable IPv6 support */
|
||||
#define USE_IPV6
|
||||
|
||||
/* Define if struct sockaddr_in6 has the sin6_scope_id member */
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
/* Define this to 'int' if ssize_t is not an available typedefed type */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to 1 if you have the alarm function. */
|
||||
#define HAVE_ALARM 1
|
||||
|
||||
/* Define if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H
|
||||
|
||||
/* Define if you have the `closesocket' function. */
|
||||
#undef HAVE_CLOSESOCKET
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H
|
||||
|
||||
/* Define if you have the `geteuid' function. */
|
||||
#define HAVE_GETEUID
|
||||
|
||||
/* Define if you have the `gethostname' function. */
|
||||
#define HAVE_GETHOSTNAME
|
||||
|
||||
/* Define if you have the `getpass_r' function. */
|
||||
#undef HAVE_GETPASS_R
|
||||
|
||||
/* Define to 1 if you have the getpeername function. */
|
||||
#define HAVE_GETPEERNAME 1
|
||||
|
||||
/* Define if you have the `getpwuid' function. */
|
||||
#define HAVE_GETPWUID
|
||||
|
||||
/* Define to 1 if you have the getsockname function. */
|
||||
#define HAVE_GETSOCKNAME 1
|
||||
|
||||
/* Define if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define if you have the `timeval' struct. */
|
||||
#define HAVE_STRUCT_TIMEVAL
|
||||
|
||||
/* Define if you have the <io.h> header file. */
|
||||
#undef HAVE_IO_H
|
||||
|
||||
/* Define if you have GSS API. */
|
||||
#define HAVE_GSSAPI
|
||||
|
||||
/* Define if you have the GNU gssapi libraries */
|
||||
#undef HAVE_GSSGNU
|
||||
|
||||
/* Define if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H
|
||||
|
||||
/* Define if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H
|
||||
|
||||
/* Define if you have the <net/if.h> header file. */
|
||||
#define HAVE_NET_IF_H
|
||||
|
||||
/* Define if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H
|
||||
|
||||
/* Define if you have the `select' function. */
|
||||
#define HAVE_SELECT
|
||||
|
||||
/* Define if you have the `sigaction' function. */
|
||||
#define HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the `signal' function. */
|
||||
#undef HAVE_SIGNAL
|
||||
|
||||
/* Define if you have the `socket' function. */
|
||||
#define HAVE_SOCKET
|
||||
|
||||
|
||||
/* The following define is needed on OS400 to enable strcmpi(), stricmp() and
|
||||
strdup(). */
|
||||
#define __cplusplus__strings__
|
||||
|
||||
/* Define if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define if you have the `strcmpi' function. */
|
||||
#define HAVE_STRCMPI
|
||||
|
||||
/* Define if you have the `stricmp' function. */
|
||||
#define HAVE_STRICMP
|
||||
|
||||
/* Define if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP
|
||||
|
||||
/* Define if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H
|
||||
|
||||
/* Define if you have the <stropts.h> header file. */
|
||||
#undef HAVE_STROPTS_H
|
||||
|
||||
/* Define if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define if you have the <sys/sockio.h> header file. */
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
/* Define if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define if you have the <sys/un.h> header file. */
|
||||
#define HAVE_SYS_UN_H
|
||||
|
||||
/* Define if you have the <sys/ioctl.h> header file. */
|
||||
#define HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define if you have the <termio.h> header file. */
|
||||
#undef HAVE_TERMIO_H
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* Define if the compiler supports the 'long long' data type. */
|
||||
#define HAVE_LONGLONG
|
||||
|
||||
/* The size of a `long long', as computed by sizeof. */
|
||||
#define SIZEOF_LONG_LONG 8
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#define SIZEOF_LONG 4
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#define SIZEOF_SIZE_T 4
|
||||
|
||||
/* The size of `curl_off_t', as computed by sizeof. */
|
||||
#define SIZEOF_CURL_OFF_T 8
|
||||
|
||||
/* Define this if you have struct sockaddr_storage */
|
||||
#define HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#define _LARGE_FILES
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define if you have a working ioctl FIONBIO function. */
|
||||
#define HAVE_IOCTL_FIONBIO
|
||||
|
||||
/* Define if you have a working ioctl SIOCGIFADDR function. */
|
||||
#define HAVE_IOCTL_SIOCGIFADDR
|
||||
|
||||
/* To disable LDAP */
|
||||
#undef CURL_DISABLE_LDAP
|
||||
|
||||
/* Definition to make a library symbol externally visible. */
|
||||
#define CURL_EXTERN_SYMBOL
|
||||
|
||||
/* Define if you have the ldap_url_parse procedure. */
|
||||
/* #define HAVE_LDAP_URL_PARSE */ /* Disabled because of an IBM bug. */
|
||||
|
||||
/* Define if you have the recv function. */
|
||||
#define HAVE_RECV
|
||||
|
||||
/* Define to the type of arg 1 for recv. */
|
||||
#define RECV_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type of arg 2 for recv. */
|
||||
#define RECV_TYPE_ARG2 char *
|
||||
|
||||
/* Define to the type of arg 3 for recv. */
|
||||
#define RECV_TYPE_ARG3 int
|
||||
|
||||
/* Define to the type of arg 4 for recv. */
|
||||
#define RECV_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for recv. */
|
||||
#define RECV_TYPE_RETV int
|
||||
|
||||
/* Define if you have the send function. */
|
||||
#define HAVE_SEND
|
||||
|
||||
/* Define to the type of arg 1 for send. */
|
||||
#define SEND_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type qualifier of arg 2 for send. */
|
||||
#define SEND_QUAL_ARG2
|
||||
|
||||
/* Define to the type of arg 2 for send. */
|
||||
#define SEND_TYPE_ARG2 char *
|
||||
|
||||
/* Define to the type of arg 3 for send. */
|
||||
#define SEND_TYPE_ARG3 int
|
||||
|
||||
/* Define to the type of arg 4 for send. */
|
||||
#define SEND_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for send. */
|
||||
#define SEND_TYPE_RETV int
|
||||
|
||||
/* Define to use the OS/400 crypto library. */
|
||||
#define USE_OS400CRYPTO
|
||||
|
||||
/* Define to use Unix sockets. */
|
||||
#define USE_UNIX_SOCKETS
|
||||
|
||||
/* Use the system keyring as the default CA bundle. */
|
||||
#define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB"
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ADDITIONAL DEFINITIONS */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* The following must be defined BEFORE system header files inclusion. */
|
||||
|
||||
#define __ptr128 /* No teraspace. */
|
||||
#define qadrt_use_fputc_inline /* Generate fputc() wrapper inline. */
|
||||
#define qadrt_use_fread_inline /* Generate fread() wrapper inline. */
|
||||
#define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG_OS400_H */
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
#ifndef HEADER_CURL_CONFIG_PLAN9_H
|
||||
#define HEADER_CURL_CONFIG_PLAN9_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define BUILDING_LIBCURL 1
|
||||
#define CURL_CA_BUNDLE "/sys/lib/tls/ca.pem"
|
||||
#define CURL_CA_PATH "/sys/lib/tls"
|
||||
#define CURL_STATICLIB 1
|
||||
#define USE_IPV6 1
|
||||
#define CURL_DISABLE_LDAP 1
|
||||
|
||||
#define NEED_REENTRANT 1
|
||||
#ifndef CURL_OS
|
||||
#define CURL_OS "plan9"
|
||||
#endif
|
||||
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
#ifdef _BITS64
|
||||
#error not implement
|
||||
#else
|
||||
#define SIZEOF_INT 4
|
||||
#define SIZEOF_LONG 4
|
||||
#define SIZEOF_OFF_T 8
|
||||
#define SIZEOF_CURL_OFF_T 4 /* curl_off_t = timediff_t = int */
|
||||
#define SIZEOF_SIZE_T 4
|
||||
#define SIZEOF_TIME_T 4
|
||||
#endif
|
||||
|
||||
#define HAVE_RECV 1
|
||||
#define RECV_TYPE_ARG1 int
|
||||
#define RECV_TYPE_ARG2 void *
|
||||
#define RECV_TYPE_ARG3 int
|
||||
#define RECV_TYPE_ARG4 int
|
||||
#define RECV_TYPE_RETV int
|
||||
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
#define HAVE_SEND 1
|
||||
#define SEND_TYPE_ARG1 int
|
||||
#define SEND_TYPE_ARG2 void *
|
||||
#define SEND_QUAL_ARG2
|
||||
#define SEND_TYPE_ARG3 int
|
||||
#define SEND_TYPE_ARG4 int
|
||||
#define SEND_TYPE_RETV int
|
||||
|
||||
#define HAVE_ALARM 1
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
#define HAVE_BASENAME 1
|
||||
#define HAVE_BOOL_T 1
|
||||
#define HAVE_FCNTL 1
|
||||
#define HAVE_FCNTL_H 1
|
||||
#define HAVE_FREEADDRINFO 1
|
||||
#define HAVE_FTRUNCATE 1
|
||||
#define HAVE_GETADDRINFO 1
|
||||
#define HAVE_GETEUID 1
|
||||
#define HAVE_GETHOSTNAME 1
|
||||
#define HAVE_GETPPID 1
|
||||
#define HAVE_GETPWUID 1
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
#define HAVE_GMTIME_R 1
|
||||
#define HAVE_INET_NTOP 1
|
||||
#define HAVE_INET_PTON 1
|
||||
#define HAVE_LIBGEN_H 1
|
||||
#define HAVE_LIBZ 1
|
||||
#define HAVE_LOCALE_H 1
|
||||
#define HAVE_LONGLONG 1
|
||||
#define HAVE_NETDB_H 1
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
#define HAVE_NETINET_TCP_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
#define USE_OPENSSL 1
|
||||
|
||||
#define HAVE_PIPE 1
|
||||
#define HAVE_POLL 1
|
||||
#define HAVE_POLL_H 1
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SETLOCALE 1
|
||||
|
||||
#define HAVE_SIGACTION 1
|
||||
#define HAVE_SIGNAL 1
|
||||
#define HAVE_SIGSETJMP 1
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
#define HAVE_SOCKET 1
|
||||
#define HAVE_STDBOOL_H 1
|
||||
#define HAVE_STRCASECMP 1
|
||||
#define HAVE_STRDUP 1
|
||||
#define HAVE_STRUCT_TIMEVAL 1
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_RESOURCE_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_SYS_UN_H 1
|
||||
#define HAVE_TERMIOS_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_UTIME 1
|
||||
#define HAVE_UTIME_H 1
|
||||
|
||||
#define HAVE_POSIX_STRERROR_R 1
|
||||
#define HAVE_STRERROR_R 1
|
||||
#define USE_MANUAL 1
|
||||
|
||||
#define __attribute__(x)
|
||||
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG_PLAN9_H */
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
#ifndef HEADER_CURL_CONFIG_RISCOS_H
|
||||
#define HEADER_CURL_CONFIG_RISCOS_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* ================================================================ */
|
||||
/* Hand crafted config file for RISC OS */
|
||||
/* ================================================================ */
|
||||
|
||||
/* Define cpu-machine-OS */
|
||||
#ifndef CURL_OS
|
||||
#define CURL_OS "ARM-RISC OS"
|
||||
#endif
|
||||
|
||||
/* Define if you want the built-in manual */
|
||||
#define USE_MANUAL
|
||||
|
||||
/* Define if you have the gethostbyname_r() function with 3 arguments */
|
||||
#undef HAVE_GETHOSTBYNAME_R_3
|
||||
|
||||
/* Define if you have the gethostbyname_r() function with 5 arguments */
|
||||
#undef HAVE_GETHOSTBYNAME_R_5
|
||||
|
||||
/* Define if you have the gethostbyname_r() function with 6 arguments */
|
||||
#undef HAVE_GETHOSTBYNAME_R_6
|
||||
|
||||
/* Define if you need the _REENTRANT define for some functions */
|
||||
#undef NEED_REENTRANT
|
||||
|
||||
/* Define if you want to enable IPv6 support */
|
||||
#undef USE_IPV6
|
||||
|
||||
/* Define if struct sockaddr_in6 has the sin6_scope_id member */
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
/* Define this to 'int' if ssize_t is not an available typedefed type */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define if you have the alarm function. */
|
||||
#define HAVE_ALARM
|
||||
|
||||
/* Define if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H
|
||||
|
||||
/* Define if you have the `closesocket' function. */
|
||||
#undef HAVE_CLOSESOCKET
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H
|
||||
|
||||
/* Define if you have the `ftruncate' function. */
|
||||
#define HAVE_FTRUNCATE
|
||||
|
||||
/* Define if getaddrinfo exists and works */
|
||||
#define HAVE_GETADDRINFO
|
||||
|
||||
/* Define if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define if you have the `gethostbyname_r' function. */
|
||||
#undef HAVE_GETHOSTBYNAME_R
|
||||
|
||||
/* Define if you have the `gethostname' function. */
|
||||
#define HAVE_GETHOSTNAME
|
||||
|
||||
/* Define if you have the `getpass_r' function. */
|
||||
#undef HAVE_GETPASS_R
|
||||
|
||||
/* Define if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define if you have the `timeval' struct. */
|
||||
#define HAVE_STRUCT_TIMEVAL
|
||||
|
||||
/* Define if you have the <io.h> header file. */
|
||||
#undef HAVE_IO_H
|
||||
|
||||
/* Define if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H
|
||||
|
||||
/* Define if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H
|
||||
|
||||
/* Define if you have the <net/if.h> header file. */
|
||||
#define HAVE_NET_IF_H
|
||||
|
||||
/* Define if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define if you have the `select' function. */
|
||||
#define HAVE_SELECT
|
||||
|
||||
/* Define if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the `signal' function. */
|
||||
#define HAVE_SIGNAL
|
||||
|
||||
/* Define if you have the `socket' function. */
|
||||
#define HAVE_SOCKET
|
||||
|
||||
/* Define if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define if you have the `strcmpi' function. */
|
||||
#undef HAVE_STRCMPI
|
||||
|
||||
/* Define if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP
|
||||
|
||||
/* Define if you have the `stricmp' function. */
|
||||
#define HAVE_STRICMP
|
||||
|
||||
/* Define if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define if you have the <sys/sockio.h> header file. */
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
/* Define if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define if you have the <termios.h> header file. */
|
||||
#define HAVE_TERMIOS_H
|
||||
|
||||
/* Define if you have the <termio.h> header file. */
|
||||
#undef HAVE_TERMIO_H
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#define SIZEOF_SIZE_T 4
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define if you have a working ioctl FIONBIO function. */
|
||||
#define HAVE_IOCTL_FIONBIO
|
||||
|
||||
/* to disable LDAP */
|
||||
#define CURL_DISABLE_LDAP
|
||||
|
||||
/* Define if you have the recv function. */
|
||||
#define HAVE_RECV 1
|
||||
|
||||
/* Define to the type of arg 1 for recv. */
|
||||
#define RECV_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type of arg 2 for recv. */
|
||||
#define RECV_TYPE_ARG2 void *
|
||||
|
||||
/* Define to the type of arg 3 for recv. */
|
||||
#define RECV_TYPE_ARG3 size_t
|
||||
|
||||
/* Define to the type of arg 4 for recv. */
|
||||
#define RECV_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for recv. */
|
||||
#define RECV_TYPE_RETV ssize_t
|
||||
|
||||
/* Define if you have the send function. */
|
||||
#define HAVE_SEND 1
|
||||
|
||||
/* Define to the type of arg 1 for send. */
|
||||
#define SEND_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type qualifier of arg 2 for send. */
|
||||
#define SEND_QUAL_ARG2 const
|
||||
|
||||
/* Define to the type of arg 2 for send. */
|
||||
#define SEND_TYPE_ARG2 void *
|
||||
|
||||
/* Define to the type of arg 3 for send. */
|
||||
#define SEND_TYPE_ARG3 size_t
|
||||
|
||||
/* Define to the type of arg 4 for send. */
|
||||
#define SEND_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for send. */
|
||||
#define SEND_TYPE_RETV ssize_t
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG_RISCOS_H */
|
||||
+493
@@ -0,0 +1,493 @@
|
||||
#ifndef HEADER_CURL_CONFIG_WIN32_H
|
||||
#define HEADER_CURL_CONFIG_WIN32_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* ================================================================ */
|
||||
/* Hand crafted config file for Windows */
|
||||
/* ================================================================ */
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
/* Define some minimum and default build targets for Visual Studio */
|
||||
#ifdef _MSC_VER
|
||||
/* VS2012 default target settings and minimum build target check. */
|
||||
# if _MSC_VER >= 1700
|
||||
/* The minimum and default build targets for VS2012 are Vista and 8,
|
||||
respectively, unless Update 1 is installed and the v110_xp toolset
|
||||
is chosen. */
|
||||
# ifdef _USING_V110_SDK71_
|
||||
# define VS2012_MIN_TARGET 0x0501 /* XP */
|
||||
# define VS2012_DEF_TARGET 0x0501 /* XP */
|
||||
# else
|
||||
# define VS2012_MIN_TARGET 0x0600 /* Vista */
|
||||
# define VS2012_DEF_TARGET 0x0602 /* 8 */
|
||||
# endif
|
||||
|
||||
# ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT VS2012_DEF_TARGET
|
||||
# endif
|
||||
# ifndef WINVER
|
||||
# define WINVER VS2012_DEF_TARGET
|
||||
# endif
|
||||
# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET)
|
||||
# ifdef _USING_V110_SDK71_
|
||||
# error VS2012 does not support build targets prior to Windows XP
|
||||
# else
|
||||
# error VS2012 does not support build targets prior to Windows Vista
|
||||
# endif
|
||||
# endif
|
||||
/* Default target settings and minimum build target check for
|
||||
VS2008 and VS2010 */
|
||||
# else
|
||||
# define VS2008_MIN_TARGET 0x0501 /* XP */
|
||||
/* VS2008 default build target is Windows Vista (0x0600).
|
||||
We override default target to be Windows XP. */
|
||||
# define VS2008_DEF_TARGET 0x0501 /* XP */
|
||||
|
||||
# ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT VS2008_DEF_TARGET
|
||||
# endif
|
||||
# ifndef WINVER
|
||||
# define WINVER VS2008_DEF_TARGET
|
||||
# endif
|
||||
# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
|
||||
# error VS2008 does not support build targets prior to Windows XP
|
||||
# endif
|
||||
# endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#endif /* UNDER_CE */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* HEADER FILES */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have the <arpa/inet.h> header file. */
|
||||
/* #define HAVE_ARPA_INET_H 1 */
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1 /* exists on __MINGW32CE__ */
|
||||
|
||||
/* Define if you have the <io.h> header file. */
|
||||
#define HAVE_IO_H 1 /* exists on __MINGW32CE__ */
|
||||
|
||||
/* Define if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
#endif
|
||||
|
||||
/* Define if you have the <netdb.h> header file. */
|
||||
/* #define HAVE_NETDB_H 1 */
|
||||
|
||||
/* Define if you have the <netinet/in.h> header file. */
|
||||
/* #define HAVE_NETINET_IN_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#ifndef UNDER_CE
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
|
||||
#define HAVE_STDBOOL_H 1 /* exists on __MINGW32CE__ */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(__MINGW32__)
|
||||
#define HAVE_STDINT_H 1
|
||||
#endif
|
||||
|
||||
/* Define if you have the <sys/param.h> header file. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#endif
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
/* #define HAVE_SYS_SELECT_H 1 */
|
||||
|
||||
/* Define if you have the <sys/sockio.h> header file. */
|
||||
/* #define HAVE_SYS_SOCKIO_H 1 */
|
||||
|
||||
/* Define if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define if you have the <sys/utime.h> header file. */
|
||||
#define HAVE_SYS_UTIME_H 1
|
||||
|
||||
/* Define if you have the <termio.h> header file. */
|
||||
/* #define HAVE_TERMIO_H 1 */
|
||||
|
||||
/* Define if you have the <termios.h> header file. */
|
||||
/* #define HAVE_TERMIOS_H 1 */
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_UNISTD_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_LIBGEN_H 1
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* OTHER HEADER INFO */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if bool is an available type. */
|
||||
#ifndef UNDER_CE
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
|
||||
#define HAVE_BOOL_T 1 /* exists on __MINGW32CE__ */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* FUNCTIONS */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have the closesocket function. */
|
||||
#define HAVE_CLOSESOCKET 1
|
||||
|
||||
/* Define if you have the ftruncate function. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_FTRUNCATE 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `getpeername' function. */
|
||||
#define HAVE_GETPEERNAME 1
|
||||
|
||||
/* Define to 1 if you have the getsockname function. */
|
||||
#define HAVE_GETSOCKNAME 1
|
||||
|
||||
/* Define if you have the gethostname function. */
|
||||
#define HAVE_GETHOSTNAME 1
|
||||
|
||||
/* Define if you have the gettimeofday function. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
#endif
|
||||
|
||||
/* Define if you have the ioctlsocket function. */
|
||||
#define HAVE_IOCTLSOCKET 1
|
||||
|
||||
/* Define if you have a working ioctlsocket FIONBIO function. */
|
||||
#define HAVE_IOCTLSOCKET_FIONBIO 1
|
||||
|
||||
/* Define if you have the select function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
#ifndef UNDER_CE
|
||||
/* Define if you have the setlocale function. */
|
||||
#define HAVE_SETLOCALE 1
|
||||
|
||||
/* Define if you have the setmode function. */
|
||||
#define HAVE_SETMODE 1
|
||||
|
||||
/* Define if you have the _setmode function. */
|
||||
#define HAVE__SETMODE 1
|
||||
#endif
|
||||
|
||||
/* Define if you have the socket function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* Define if you have the strdup function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define if you have the utime function. */
|
||||
#define HAVE_UTIME 1
|
||||
|
||||
/* Define if you have the recv function. */
|
||||
#define HAVE_RECV 1
|
||||
|
||||
/* Define to the type of arg 1 for recv. */
|
||||
#define RECV_TYPE_ARG1 SOCKET
|
||||
|
||||
/* Define to the type of arg 2 for recv. */
|
||||
#define RECV_TYPE_ARG2 char *
|
||||
|
||||
/* Define to the type of arg 3 for recv. */
|
||||
#define RECV_TYPE_ARG3 int
|
||||
|
||||
/* Define to the type of arg 4 for recv. */
|
||||
#define RECV_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for recv. */
|
||||
#define RECV_TYPE_RETV int
|
||||
|
||||
/* Define if you have the send function. */
|
||||
#define HAVE_SEND 1
|
||||
|
||||
/* Define to the type of arg 1 for send. */
|
||||
#define SEND_TYPE_ARG1 SOCKET
|
||||
|
||||
/* Define to the type qualifier of arg 2 for send. */
|
||||
#define SEND_QUAL_ARG2 const
|
||||
|
||||
/* Define to the type of arg 2 for send. */
|
||||
#define SEND_TYPE_ARG2 char *
|
||||
|
||||
/* Define to the type of arg 3 for send. */
|
||||
#define SEND_TYPE_ARG3 int
|
||||
|
||||
/* Define to the type of arg 4 for send. */
|
||||
#define SEND_TYPE_ARG4 int
|
||||
|
||||
/* Define to the function return type for send. */
|
||||
#define SEND_TYPE_RETV int
|
||||
|
||||
/* Define to 1 if you have the snprintf function. */
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || defined(__MINGW32__)
|
||||
#define HAVE_SNPRINTF 1
|
||||
#endif
|
||||
|
||||
/* Must always use local implementations on Windows. */
|
||||
/* Define to 1 if you have an IPv6 capable working inet_ntop function. */
|
||||
/* #undef HAVE_INET_NTOP */
|
||||
/* Define to 1 if you have an IPv6 capable working inet_pton function. */
|
||||
/* #undef HAVE_INET_PTON */
|
||||
|
||||
/* Define to 1 if you have the `basename' function. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_BASENAME 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the signal function. */
|
||||
#ifndef UNDER_CE
|
||||
#define HAVE_SIGNAL 1
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* TYPEDEF REPLACEMENTS */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if ssize_t is not an available 'typedefed' type. */
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
# ifdef __MINGW32__
|
||||
# elif defined(_WIN64)
|
||||
# define _SSIZE_T_DEFINED
|
||||
# define ssize_t __int64
|
||||
# else
|
||||
# define _SSIZE_T_DEFINED
|
||||
# define ssize_t int
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* TYPE SIZES */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define to the size of `int', as computed by sizeof. */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* Define to the size of `long long', as computed by sizeof. */
|
||||
/* #define SIZEOF_LONG_LONG 8 */
|
||||
|
||||
/* Define to the size of `long', as computed by sizeof. */
|
||||
#define SIZEOF_LONG 4
|
||||
|
||||
/* Define to the size of `size_t', as computed by sizeof. */
|
||||
#ifdef _WIN64
|
||||
# define SIZEOF_SIZE_T 8
|
||||
#else
|
||||
# define SIZEOF_SIZE_T 4
|
||||
#endif
|
||||
|
||||
/* Define to the size of `curl_off_t', as computed by sizeof. */
|
||||
#define SIZEOF_CURL_OFF_T 8
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* COMPILER SPECIFIC */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define to nothing if compiler does not support 'const' qualifier. */
|
||||
/* #define const */
|
||||
|
||||
/* Define to nothing if compiler does not support 'volatile' qualifier. */
|
||||
/* #define volatile */
|
||||
|
||||
/* Windows should not have HAVE_GMTIME_R defined */
|
||||
/* #undef HAVE_GMTIME_R */
|
||||
|
||||
/* Define if the compiler supports the 'long long' data type. */
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define HAVE_LONGLONG 1
|
||||
#endif
|
||||
|
||||
/* Default to 64-bit time_t unless _USE_32BIT_TIME_T is defined */
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# ifndef _USE_32BIT_TIME_T
|
||||
# define SIZEOF_TIME_T 8
|
||||
# else
|
||||
# define SIZEOF_TIME_T 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Windows XP is required for freeaddrinfo, getaddrinfo */
|
||||
#ifndef UNDER_CE
|
||||
#define HAVE_FREEADDRINFO 1
|
||||
#define HAVE_GETADDRINFO 1
|
||||
#define HAVE_GETADDRINFO_THREADSAFE 1
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* STRUCT RELATED */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have struct sockaddr_storage. */
|
||||
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
|
||||
|
||||
/* Define if you have struct timeval. */
|
||||
#define HAVE_STRUCT_TIMEVAL 1
|
||||
|
||||
/* Define if struct sockaddr_in6 has the sin6_scope_id member. */
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* LARGE FILE SUPPORT */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# define USE_WIN32_LARGE_FILES
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
# ifdef __MINGW32__
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to the size of `off_t', as computed by sizeof. */
|
||||
#if defined(__MINGW32__) && \
|
||||
defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
# define SIZEOF_OFF_T 8
|
||||
#else
|
||||
# define SIZEOF_OFF_T 4
|
||||
#endif
|
||||
|
||||
#endif /* UNDER_CE */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* DNS RESOLVER SPECIALTY */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS.
|
||||
*/
|
||||
|
||||
/* Define to enable c-ares asynchronous DNS lookups. */
|
||||
/* #define USE_ARES 1 */
|
||||
|
||||
/* Default define to enable threaded asynchronous DNS lookups. */
|
||||
#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \
|
||||
!defined(USE_THREADS_WIN32)
|
||||
# define USE_THREADS_WIN32 1
|
||||
#endif
|
||||
|
||||
#if defined(USE_ARES) && defined(USE_THREADS_WIN32)
|
||||
# error "Only one DNS lookup specialty may be defined at most"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* LDAP SUPPORT */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
#ifdef CURL_HAS_OPENLDAP_LDAPSDK
|
||||
#undef USE_WIN32_LDAP
|
||||
#define HAVE_LDAP_URL_PARSE 1
|
||||
#elif !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
#undef HAVE_LDAP_URL_PARSE
|
||||
#define HAVE_LDAP_SSL 1
|
||||
#define USE_WIN32_LDAP 1
|
||||
#endif
|
||||
|
||||
/* Define to use the Windows crypto library. */
|
||||
#ifndef CURL_WINDOWS_UWP
|
||||
#define USE_WIN32_CRYPTO
|
||||
#endif
|
||||
|
||||
/* Define to use Unix sockets. */
|
||||
#ifndef UNDER_CE
|
||||
#define USE_UNIX_SOCKETS
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ADDITIONAL DEFINITIONS */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define cpu-machine-OS */
|
||||
#ifndef CURL_OS
|
||||
# ifdef UNDER_CE
|
||||
# ifdef _M_ARM
|
||||
# define CURL_OS "arm-pc-win32ce"
|
||||
# else
|
||||
# define CURL_OS "i386-pc-win32ce"
|
||||
# endif
|
||||
# else /* !UNDER_CE */
|
||||
# if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */
|
||||
# define CURL_OS "i386-pc-win32"
|
||||
# elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (VS2005+ or gcc) */
|
||||
# define CURL_OS "x86_64-pc-win32"
|
||||
# elif defined(_M_IA64) || defined(__ia64__) /* Itanium */
|
||||
# define CURL_OS "ia64-pc-win32"
|
||||
# elif defined(_M_ARM_NT) || defined(__arm__) /* ARMv7-Thumb2 */
|
||||
# define CURL_OS "thumbv7a-pc-win32"
|
||||
# elif defined(_M_ARM64) || defined(__aarch64__) /* ARM64 (Windows 10) */
|
||||
# define CURL_OS "aarch64-pc-win32"
|
||||
# else
|
||||
# define CURL_OS "unknown-pc-win32"
|
||||
# endif
|
||||
# endif /* UNDER_CE */
|
||||
#endif /* !CURL_OS */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* Windows CE */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
#ifdef UNDER_CE
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#define CURL_DISABLE_FILE 1
|
||||
#define CURL_DISABLE_TELNET 1
|
||||
#define CURL_DISABLE_LDAP 1
|
||||
|
||||
#ifndef _MSC_VER
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
extern int stat(const char *path, struct stat *buffer);
|
||||
#endif
|
||||
|
||||
#endif /* UNDER_CE */
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG_WIN32_H */
|
||||
Vendored
+928
@@ -0,0 +1,928 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "conncache.h"
|
||||
#include "http_negotiate.h"
|
||||
#include "http_ntlm.h"
|
||||
#include "share.h"
|
||||
#include "sigpipe.h"
|
||||
#include "connect.h"
|
||||
#include "select.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "uint-table.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
#define CPOOL_IS_LOCKED(c) ((c) && (c)->locked)
|
||||
|
||||
#define CPOOL_LOCK(c,d) \
|
||||
do { \
|
||||
if((c)) { \
|
||||
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
|
||||
Curl_share_lock((d), CURL_LOCK_DATA_CONNECT, \
|
||||
CURL_LOCK_ACCESS_SINGLE); \
|
||||
DEBUGASSERT(!(c)->locked); \
|
||||
(c)->locked = TRUE; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CPOOL_UNLOCK(c,d) \
|
||||
do { \
|
||||
if((c)) { \
|
||||
DEBUGASSERT((c)->locked); \
|
||||
(c)->locked = FALSE; \
|
||||
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
|
||||
Curl_share_unlock((d), CURL_LOCK_DATA_CONNECT); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* A list of connections to the same destination. */
|
||||
struct cpool_bundle {
|
||||
struct Curl_llist conns; /* connections in the bundle */
|
||||
size_t dest_len; /* total length of destination, including NUL */
|
||||
char dest[1]; /* destination of bundle, allocated to keep dest_len bytes */
|
||||
};
|
||||
|
||||
|
||||
static void cpool_discard_conn(struct cpool *cpool,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool aborted);
|
||||
|
||||
static struct cpool_bundle *cpool_bundle_create(const char *dest)
|
||||
{
|
||||
struct cpool_bundle *bundle;
|
||||
size_t dest_len = strlen(dest) + 1;
|
||||
|
||||
bundle = calloc(1, sizeof(*bundle) + dest_len - 1);
|
||||
if(!bundle)
|
||||
return NULL;
|
||||
Curl_llist_init(&bundle->conns, NULL);
|
||||
bundle->dest_len = dest_len;
|
||||
memcpy(bundle->dest, dest, bundle->dest_len);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
static void cpool_bundle_destroy(struct cpool_bundle *bundle)
|
||||
{
|
||||
DEBUGASSERT(!Curl_llist_count(&bundle->conns));
|
||||
free(bundle);
|
||||
}
|
||||
|
||||
/* Add a connection to a bundle */
|
||||
static void cpool_bundle_add(struct cpool_bundle *bundle,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
DEBUGASSERT(!Curl_node_llist(&conn->cpool_node));
|
||||
Curl_llist_append(&bundle->conns, conn, &conn->cpool_node);
|
||||
conn->bits.in_cpool = TRUE;
|
||||
}
|
||||
|
||||
/* Remove a connection from a bundle */
|
||||
static void cpool_bundle_remove(struct cpool_bundle *bundle,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
(void)bundle;
|
||||
DEBUGASSERT(Curl_node_llist(&conn->cpool_node) == &bundle->conns);
|
||||
Curl_node_remove(&conn->cpool_node);
|
||||
conn->bits.in_cpool = FALSE;
|
||||
}
|
||||
|
||||
static void cpool_bundle_free_entry(void *freethis)
|
||||
{
|
||||
cpool_bundle_destroy((struct cpool_bundle *)freethis);
|
||||
}
|
||||
|
||||
void Curl_cpool_init(struct cpool *cpool,
|
||||
struct Curl_easy *idata,
|
||||
struct Curl_share *share,
|
||||
size_t size)
|
||||
{
|
||||
Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
|
||||
curlx_str_key_compare, cpool_bundle_free_entry);
|
||||
|
||||
DEBUGASSERT(idata);
|
||||
|
||||
cpool->idata = idata;
|
||||
cpool->share = share;
|
||||
cpool->initialised = TRUE;
|
||||
}
|
||||
|
||||
/* Return the "first" connection in the pool or NULL. */
|
||||
static struct connectdata *cpool_get_first(struct cpool *cpool)
|
||||
{
|
||||
struct Curl_hash_iterator iter;
|
||||
struct Curl_hash_element *he;
|
||||
struct cpool_bundle *bundle;
|
||||
struct Curl_llist_node *conn_node;
|
||||
|
||||
Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
|
||||
for(he = Curl_hash_next_element(&iter); he;
|
||||
he = Curl_hash_next_element(&iter)) {
|
||||
bundle = he->ptr;
|
||||
conn_node = Curl_llist_head(&bundle->conns);
|
||||
if(conn_node)
|
||||
return Curl_node_elem(conn_node);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct cpool_bundle *cpool_find_bundle(struct cpool *cpool,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
return Curl_hash_pick(&cpool->dest2bundle,
|
||||
conn->destination, strlen(conn->destination) + 1);
|
||||
}
|
||||
|
||||
|
||||
static void cpool_remove_bundle(struct cpool *cpool,
|
||||
struct cpool_bundle *bundle)
|
||||
{
|
||||
if(!cpool)
|
||||
return;
|
||||
Curl_hash_delete(&cpool->dest2bundle, bundle->dest, bundle->dest_len);
|
||||
}
|
||||
|
||||
|
||||
static void cpool_remove_conn(struct cpool *cpool,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
struct Curl_llist *list = Curl_node_llist(&conn->cpool_node);
|
||||
DEBUGASSERT(cpool);
|
||||
if(list) {
|
||||
/* The connection is certainly in the pool, but where? */
|
||||
struct cpool_bundle *bundle = cpool_find_bundle(cpool, conn);
|
||||
if(bundle && (list == &bundle->conns)) {
|
||||
cpool_bundle_remove(bundle, conn);
|
||||
if(!Curl_llist_count(&bundle->conns))
|
||||
cpool_remove_bundle(cpool, bundle);
|
||||
conn->bits.in_cpool = FALSE;
|
||||
cpool->num_conn--;
|
||||
}
|
||||
else {
|
||||
/* Should have been in the bundle list */
|
||||
DEBUGASSERT(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_cpool_destroy(struct cpool *cpool)
|
||||
{
|
||||
if(cpool && cpool->initialised && cpool->idata) {
|
||||
struct connectdata *conn;
|
||||
SIGPIPE_VARIABLE(pipe_st);
|
||||
|
||||
CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections",
|
||||
cpool->share ? "[SHARE] " : "", cpool->num_conn);
|
||||
/* Move all connections to the shutdown list */
|
||||
sigpipe_init(&pipe_st);
|
||||
CPOOL_LOCK(cpool, cpool->idata);
|
||||
conn = cpool_get_first(cpool);
|
||||
while(conn) {
|
||||
cpool_remove_conn(cpool, conn);
|
||||
sigpipe_apply(cpool->idata, &pipe_st);
|
||||
connclose(conn, "kill all");
|
||||
cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
|
||||
conn = cpool_get_first(cpool);
|
||||
}
|
||||
CPOOL_UNLOCK(cpool, cpool->idata);
|
||||
sigpipe_restore(&pipe_st);
|
||||
Curl_hash_destroy(&cpool->dest2bundle);
|
||||
}
|
||||
}
|
||||
|
||||
static struct cpool *cpool_get_instance(struct Curl_easy *data)
|
||||
{
|
||||
if(data) {
|
||||
if(CURL_SHARE_KEEP_CONNECT(data->share))
|
||||
return &data->share->cpool;
|
||||
else if(data->multi_easy)
|
||||
return &data->multi_easy->cpool;
|
||||
else if(data->multi)
|
||||
return &data->multi->cpool;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Curl_cpool_xfer_init(struct Curl_easy *data)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
|
||||
DEBUGASSERT(cpool);
|
||||
if(cpool) {
|
||||
CPOOL_LOCK(cpool, data);
|
||||
/* the identifier inside the connection cache */
|
||||
data->id = cpool->next_easy_id++;
|
||||
if(cpool->next_easy_id <= 0)
|
||||
cpool->next_easy_id = 0;
|
||||
data->state.lastconnect_id = -1;
|
||||
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
else {
|
||||
/* We should not get here, but in a non-debug build, do something */
|
||||
data->id = 0;
|
||||
data->state.lastconnect_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static struct cpool_bundle *
|
||||
cpool_add_bundle(struct cpool *cpool, struct connectdata *conn)
|
||||
{
|
||||
struct cpool_bundle *bundle;
|
||||
|
||||
bundle = cpool_bundle_create(conn->destination);
|
||||
if(!bundle)
|
||||
return NULL;
|
||||
|
||||
if(!Curl_hash_add(&cpool->dest2bundle,
|
||||
bundle->dest, bundle->dest_len, bundle)) {
|
||||
cpool_bundle_destroy(bundle);
|
||||
return NULL;
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
static struct connectdata *
|
||||
cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
|
||||
{
|
||||
struct Curl_llist_node *curr;
|
||||
timediff_t highscore = -1;
|
||||
timediff_t score;
|
||||
struct curltime now;
|
||||
struct connectdata *oldest_idle = NULL;
|
||||
struct connectdata *conn;
|
||||
|
||||
now = curlx_now();
|
||||
curr = Curl_llist_head(&bundle->conns);
|
||||
while(curr) {
|
||||
conn = Curl_node_elem(curr);
|
||||
|
||||
if(!CONN_INUSE(conn)) {
|
||||
/* Set higher score for the age passed since the connection was used */
|
||||
score = curlx_timediff(now, conn->lastused);
|
||||
|
||||
if(score > highscore) {
|
||||
highscore = score;
|
||||
oldest_idle = conn;
|
||||
}
|
||||
}
|
||||
curr = Curl_node_next(curr);
|
||||
}
|
||||
return oldest_idle;
|
||||
}
|
||||
|
||||
static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
|
||||
{
|
||||
struct Curl_hash_iterator iter;
|
||||
struct Curl_llist_node *curr;
|
||||
struct Curl_hash_element *he;
|
||||
struct connectdata *oldest_idle = NULL;
|
||||
struct cpool_bundle *bundle;
|
||||
struct curltime now;
|
||||
timediff_t highscore = -1;
|
||||
timediff_t score;
|
||||
|
||||
now = curlx_now();
|
||||
Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
|
||||
|
||||
for(he = Curl_hash_next_element(&iter); he;
|
||||
he = Curl_hash_next_element(&iter)) {
|
||||
struct connectdata *conn;
|
||||
bundle = he->ptr;
|
||||
|
||||
for(curr = Curl_llist_head(&bundle->conns); curr;
|
||||
curr = Curl_node_next(curr)) {
|
||||
conn = Curl_node_elem(curr);
|
||||
if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
|
||||
continue;
|
||||
/* Set higher score for the age passed since the connection was used */
|
||||
score = curlx_timediff(now, conn->lastused);
|
||||
if(score > highscore) {
|
||||
highscore = score;
|
||||
oldest_idle = conn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldest_idle;
|
||||
}
|
||||
|
||||
|
||||
int Curl_cpool_check_limits(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct cpool_bundle *bundle;
|
||||
size_t dest_limit = 0;
|
||||
size_t total_limit = 0;
|
||||
size_t shutdowns;
|
||||
int result = CPOOL_LIMIT_OK;
|
||||
|
||||
if(!cpool)
|
||||
return CPOOL_LIMIT_OK;
|
||||
|
||||
if(cpool->idata->multi) {
|
||||
dest_limit = cpool->idata->multi->max_host_connections;
|
||||
total_limit = cpool->idata->multi->max_total_connections;
|
||||
}
|
||||
|
||||
if(!dest_limit && !total_limit)
|
||||
return CPOOL_LIMIT_OK;
|
||||
|
||||
CPOOL_LOCK(cpool, cpool->idata);
|
||||
if(dest_limit) {
|
||||
size_t live;
|
||||
|
||||
bundle = cpool_find_bundle(cpool, conn);
|
||||
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
|
||||
shutdowns = Curl_cshutdn_dest_count(data, conn->destination);
|
||||
while((live + shutdowns) >= dest_limit) {
|
||||
if(shutdowns) {
|
||||
/* close one connection in shutdown right away, if we can */
|
||||
if(!Curl_cshutdn_close_oldest(data, conn->destination))
|
||||
break;
|
||||
}
|
||||
else if(!bundle)
|
||||
break;
|
||||
else {
|
||||
struct connectdata *oldest_idle = NULL;
|
||||
/* The bundle is full. Extract the oldest connection that may
|
||||
* be removed now, if there is one. */
|
||||
oldest_idle = cpool_bundle_get_oldest_idle(bundle);
|
||||
if(!oldest_idle)
|
||||
break;
|
||||
/* disconnect the old conn and continue */
|
||||
CURL_TRC_M(data, "Discarding connection #%"
|
||||
FMT_OFF_T " from %zu to reach destination "
|
||||
"limit of %zu", oldest_idle->connection_id,
|
||||
Curl_llist_count(&bundle->conns), dest_limit);
|
||||
Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
|
||||
|
||||
/* in case the bundle was destroyed in disconnect, look it up again */
|
||||
bundle = cpool_find_bundle(cpool, conn);
|
||||
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
|
||||
}
|
||||
shutdowns = Curl_cshutdn_dest_count(cpool->idata, conn->destination);
|
||||
}
|
||||
if((live + shutdowns) >= dest_limit) {
|
||||
result = CPOOL_LIMIT_DEST;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(total_limit) {
|
||||
shutdowns = Curl_cshutdn_count(cpool->idata);
|
||||
while((cpool->num_conn + shutdowns) >= total_limit) {
|
||||
if(shutdowns) {
|
||||
/* close one connection in shutdown right away, if we can */
|
||||
if(!Curl_cshutdn_close_oldest(data, NULL))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
|
||||
if(!oldest_idle)
|
||||
break;
|
||||
/* disconnect the old conn and continue */
|
||||
CURL_TRC_M(data, "Discarding connection #%"
|
||||
FMT_OFF_T " from %zu to reach total "
|
||||
"limit of %zu",
|
||||
oldest_idle->connection_id, cpool->num_conn, total_limit);
|
||||
Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
|
||||
}
|
||||
shutdowns = Curl_cshutdn_count(cpool->idata);
|
||||
}
|
||||
if((cpool->num_conn + shutdowns) >= total_limit) {
|
||||
result = CPOOL_LIMIT_TOTAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
CPOOL_UNLOCK(cpool, cpool->idata);
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cpool_add(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct cpool_bundle *bundle = NULL;
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
DEBUGASSERT(conn);
|
||||
|
||||
DEBUGASSERT(cpool);
|
||||
if(!cpool)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
CPOOL_LOCK(cpool, data);
|
||||
bundle = cpool_find_bundle(cpool, conn);
|
||||
if(!bundle) {
|
||||
bundle = cpool_add_bundle(cpool, conn);
|
||||
if(!bundle) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
cpool_bundle_add(bundle, conn);
|
||||
conn->connection_id = cpool->next_connection_id++;
|
||||
cpool->num_conn++;
|
||||
CURL_TRC_M(data, "[CPOOL] added connection %" FMT_OFF_T ". "
|
||||
"The cache now contains %zu members",
|
||||
conn->connection_id, cpool->num_conn);
|
||||
out:
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This function iterates the entire connection pool and calls the function
|
||||
func() with the connection pointer as the first argument and the supplied
|
||||
'param' argument as the other.
|
||||
|
||||
The cpool lock is still held when the callback is called. It needs it,
|
||||
so that it can safely continue traversing the lists once the callback
|
||||
returns.
|
||||
|
||||
Returns TRUE if the loop was aborted due to the callback's return code.
|
||||
|
||||
Return 0 from func() to continue the loop, return 1 to abort it.
|
||||
*/
|
||||
static bool cpool_foreach(struct Curl_easy *data,
|
||||
struct cpool *cpool,
|
||||
void *param,
|
||||
int (*func)(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param))
|
||||
{
|
||||
struct Curl_hash_iterator iter;
|
||||
struct Curl_hash_element *he;
|
||||
|
||||
if(!cpool)
|
||||
return FALSE;
|
||||
|
||||
Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
|
||||
|
||||
he = Curl_hash_next_element(&iter);
|
||||
while(he) {
|
||||
struct Curl_llist_node *curr;
|
||||
struct cpool_bundle *bundle = he->ptr;
|
||||
he = Curl_hash_next_element(&iter);
|
||||
|
||||
curr = Curl_llist_head(&bundle->conns);
|
||||
while(curr) {
|
||||
/* Yes, we need to update curr before calling func(), because func()
|
||||
might decide to remove the connection */
|
||||
struct connectdata *conn = Curl_node_elem(curr);
|
||||
curr = Curl_node_next(curr);
|
||||
|
||||
if(func(data, conn, param) == 1) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* A connection (already in the pool) has become idle. Do any
|
||||
* cleanups in regard to the pool's limits.
|
||||
*
|
||||
* Return TRUE if idle connection kept in pool, FALSE if closed.
|
||||
*/
|
||||
bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
unsigned int maxconnects;
|
||||
struct connectdata *oldest_idle = NULL;
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
bool kept = TRUE;
|
||||
|
||||
if(!data->multi->maxconnects) {
|
||||
unsigned int running = Curl_multi_xfers_running(data->multi);
|
||||
maxconnects = (running <= UINT_MAX / 4) ? running * 4 : UINT_MAX;
|
||||
}
|
||||
else {
|
||||
maxconnects = data->multi->maxconnects;
|
||||
}
|
||||
|
||||
conn->lastused = curlx_now(); /* it was used up until now */
|
||||
if(cpool && maxconnects) {
|
||||
/* may be called form a callback already under lock */
|
||||
bool do_lock = !CPOOL_IS_LOCKED(cpool);
|
||||
if(do_lock)
|
||||
CPOOL_LOCK(cpool, data);
|
||||
if(cpool->num_conn > maxconnects) {
|
||||
infof(data, "Connection pool is full, closing the oldest of %zu/%u",
|
||||
cpool->num_conn, maxconnects);
|
||||
|
||||
oldest_idle = cpool_get_oldest_idle(cpool);
|
||||
kept = (oldest_idle != conn);
|
||||
if(oldest_idle) {
|
||||
Curl_conn_terminate(data, oldest_idle, FALSE);
|
||||
}
|
||||
}
|
||||
if(do_lock)
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
|
||||
return kept;
|
||||
}
|
||||
|
||||
bool Curl_cpool_find(struct Curl_easy *data,
|
||||
const char *destination,
|
||||
Curl_cpool_conn_match_cb *conn_cb,
|
||||
Curl_cpool_done_match_cb *done_cb,
|
||||
void *userdata)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct cpool_bundle *bundle;
|
||||
bool result = FALSE;
|
||||
|
||||
DEBUGASSERT(cpool);
|
||||
DEBUGASSERT(conn_cb);
|
||||
if(!cpool)
|
||||
return FALSE;
|
||||
|
||||
CPOOL_LOCK(cpool, data);
|
||||
bundle = Curl_hash_pick(&cpool->dest2bundle,
|
||||
CURL_UNCONST(destination),
|
||||
strlen(destination) + 1);
|
||||
if(bundle) {
|
||||
struct Curl_llist_node *curr = Curl_llist_head(&bundle->conns);
|
||||
while(curr) {
|
||||
struct connectdata *conn = Curl_node_elem(curr);
|
||||
/* Get next node now. callback might discard current */
|
||||
curr = Curl_node_next(curr);
|
||||
|
||||
if(conn_cb(conn, userdata)) {
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(done_cb) {
|
||||
result = done_cb(result, userdata);
|
||||
}
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cpool_discard_conn(struct cpool *cpool,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool aborted)
|
||||
{
|
||||
bool done = FALSE;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(!data->conn);
|
||||
DEBUGASSERT(cpool);
|
||||
DEBUGASSERT(!conn->bits.in_cpool);
|
||||
|
||||
/*
|
||||
* If this connection is not marked to force-close, leave it open if there
|
||||
* are other users of it
|
||||
*/
|
||||
if(CONN_INUSE(conn) && !aborted) {
|
||||
CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
|
||||
" still in use by %u transfers", conn->connection_id,
|
||||
CONN_ATTACHED(conn));
|
||||
return;
|
||||
}
|
||||
|
||||
/* treat the connection as aborted in CONNECT_ONLY situations, we do
|
||||
* not know what the APP did with it. */
|
||||
if(conn->connect_only)
|
||||
aborted = TRUE;
|
||||
conn->bits.aborted = aborted;
|
||||
|
||||
/* We do not shutdown dead connections. The term 'dead' can be misleading
|
||||
* here, as we also mark errored connections/transfers as 'dead'.
|
||||
* If we do a shutdown for an aborted transfer, the server might think
|
||||
* it was successful otherwise (for example an ftps: upload). This is
|
||||
* not what we want. */
|
||||
if(aborted)
|
||||
done = TRUE;
|
||||
if(!done) {
|
||||
/* Attempt to shutdown the connection right away. */
|
||||
Curl_cshutdn_run_once(cpool->idata, conn, &done);
|
||||
}
|
||||
|
||||
if(done || !data->multi)
|
||||
Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
|
||||
else
|
||||
Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
|
||||
}
|
||||
|
||||
void Curl_conn_terminate(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool aborted)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
bool do_lock;
|
||||
|
||||
DEBUGASSERT(cpool);
|
||||
DEBUGASSERT(data && !data->conn);
|
||||
if(!cpool)
|
||||
return;
|
||||
|
||||
/* If this connection is not marked to force-close, leave it open if there
|
||||
* are other users of it */
|
||||
if(CONN_INUSE(conn) && !aborted) {
|
||||
DEBUGASSERT(0); /* does this ever happen? */
|
||||
DEBUGF(infof(data, "Curl_disconnect when inuse: %u", CONN_ATTACHED(conn)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* This method may be called while we are under lock, e.g. from a
|
||||
* user callback in find. */
|
||||
do_lock = !CPOOL_IS_LOCKED(cpool);
|
||||
if(do_lock)
|
||||
CPOOL_LOCK(cpool, data);
|
||||
|
||||
if(conn->bits.in_cpool) {
|
||||
cpool_remove_conn(cpool, conn);
|
||||
DEBUGASSERT(!conn->bits.in_cpool);
|
||||
}
|
||||
|
||||
/* treat the connection as aborted in CONNECT_ONLY situations,
|
||||
* so no graceful shutdown is attempted. */
|
||||
if(conn->connect_only)
|
||||
aborted = TRUE;
|
||||
|
||||
if(data->multi) {
|
||||
/* Add it to the multi's cpool for shutdown handling */
|
||||
infof(data, "%s connection #%" FMT_OFF_T,
|
||||
aborted ? "closing" : "shutting down", conn->connection_id);
|
||||
cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
|
||||
}
|
||||
else {
|
||||
/* No multi available, terminate */
|
||||
infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
|
||||
Curl_cshutdn_terminate(cpool->idata, conn, !aborted);
|
||||
}
|
||||
|
||||
if(do_lock)
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
|
||||
|
||||
struct cpool_reaper_ctx {
|
||||
struct curltime now;
|
||||
};
|
||||
|
||||
static int cpool_reap_dead_cb(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param)
|
||||
{
|
||||
struct cpool_reaper_ctx *rctx = param;
|
||||
if((!CONN_INUSE(conn) && conn->bits.no_reuse) ||
|
||||
Curl_conn_seems_dead(conn, data, &rctx->now)) {
|
||||
/* stop the iteration here, pass back the connection that was pruned */
|
||||
Curl_conn_terminate(data, conn, FALSE);
|
||||
return 1;
|
||||
}
|
||||
return 0; /* continue iteration */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function scans the data's connection pool for half-open/dead
|
||||
* connections, closes and removes them.
|
||||
* The cleanup is done at most once per second.
|
||||
*
|
||||
* When called, this transfer has no connection attached.
|
||||
*/
|
||||
void Curl_cpool_prune_dead(struct Curl_easy *data)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct cpool_reaper_ctx rctx;
|
||||
timediff_t elapsed;
|
||||
|
||||
if(!cpool)
|
||||
return;
|
||||
|
||||
rctx.now = curlx_now();
|
||||
CPOOL_LOCK(cpool, data);
|
||||
elapsed = curlx_timediff(rctx.now, cpool->last_cleanup);
|
||||
|
||||
if(elapsed >= 1000L) {
|
||||
while(cpool_foreach(data, cpool, &rctx, cpool_reap_dead_cb))
|
||||
;
|
||||
cpool->last_cleanup = rctx.now;
|
||||
}
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
|
||||
static int conn_upkeep(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
void *param)
|
||||
{
|
||||
struct curltime *now = param;
|
||||
Curl_conn_upkeep(data, conn, now);
|
||||
return 0; /* continue iteration */
|
||||
}
|
||||
|
||||
CURLcode Curl_cpool_upkeep(void *data)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct curltime now = curlx_now();
|
||||
|
||||
if(!cpool)
|
||||
return CURLE_OK;
|
||||
|
||||
CPOOL_LOCK(cpool, data);
|
||||
cpool_foreach(data, cpool, &now, conn_upkeep);
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
struct cpool_find_ctx {
|
||||
curl_off_t id;
|
||||
struct connectdata *conn;
|
||||
};
|
||||
|
||||
static int cpool_find_conn(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param)
|
||||
{
|
||||
struct cpool_find_ctx *fctx = param;
|
||||
(void)data;
|
||||
if(conn->connection_id == fctx->id) {
|
||||
fctx->conn = conn;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
|
||||
curl_off_t conn_id)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct cpool_find_ctx fctx;
|
||||
|
||||
if(!cpool)
|
||||
return NULL;
|
||||
fctx.id = conn_id;
|
||||
fctx.conn = NULL;
|
||||
CPOOL_LOCK(cpool, data);
|
||||
cpool_foreach(data, cpool, &fctx, cpool_find_conn);
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
return fctx.conn;
|
||||
}
|
||||
|
||||
struct cpool_do_conn_ctx {
|
||||
curl_off_t id;
|
||||
Curl_cpool_conn_do_cb *cb;
|
||||
void *cbdata;
|
||||
};
|
||||
|
||||
static int cpool_do_conn(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param)
|
||||
{
|
||||
struct cpool_do_conn_ctx *dctx = param;
|
||||
(void)data;
|
||||
if(conn->connection_id == dctx->id) {
|
||||
dctx->cb(conn, data, dctx->cbdata);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
|
||||
Curl_cpool_conn_do_cb *cb, void *cbdata)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
struct cpool_do_conn_ctx dctx;
|
||||
|
||||
if(!cpool)
|
||||
return;
|
||||
dctx.id = conn_id;
|
||||
dctx.cb = cb;
|
||||
dctx.cbdata = cbdata;
|
||||
CPOOL_LOCK(cpool, data);
|
||||
cpool_foreach(data, cpool, &dctx, cpool_do_conn);
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
|
||||
void Curl_cpool_do_locked(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
Curl_cpool_conn_do_cb *cb, void *cbdata)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
if(cpool) {
|
||||
CPOOL_LOCK(cpool, data);
|
||||
cb(conn, data, cbdata);
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
else
|
||||
cb(conn, data, cbdata);
|
||||
}
|
||||
|
||||
static int cpool_mark_stale(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param)
|
||||
{
|
||||
(void)data;
|
||||
(void)param;
|
||||
conn->bits.no_reuse = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpool_reap_no_reuse(struct Curl_easy *data,
|
||||
struct connectdata *conn, void *param)
|
||||
{
|
||||
(void)data;
|
||||
(void)param;
|
||||
if(!CONN_INUSE(conn) && conn->bits.no_reuse) {
|
||||
Curl_conn_terminate(data, conn, FALSE);
|
||||
return 1;
|
||||
}
|
||||
return 0; /* continue iteration */
|
||||
}
|
||||
|
||||
void Curl_cpool_nw_changed(struct Curl_easy *data)
|
||||
{
|
||||
struct cpool *cpool = cpool_get_instance(data);
|
||||
|
||||
if(cpool) {
|
||||
CPOOL_LOCK(cpool, data);
|
||||
cpool_foreach(data, cpool, NULL, cpool_mark_stale);
|
||||
while(cpool_foreach(data, cpool, NULL, cpool_reap_no_reuse))
|
||||
;
|
||||
CPOOL_UNLOCK(cpool, data);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Useful for debugging the connection pool */
|
||||
void Curl_cpool_print(struct cpool *cpool)
|
||||
{
|
||||
struct Curl_hash_iterator iter;
|
||||
struct Curl_llist_node *curr;
|
||||
struct Curl_hash_element *he;
|
||||
|
||||
if(!cpool)
|
||||
return;
|
||||
|
||||
curl_mfprintf(stderr, "=Bundle cache=\n");
|
||||
|
||||
Curl_hash_start_iterate(cpool->dest2bundle, &iter);
|
||||
|
||||
he = Curl_hash_next_element(&iter);
|
||||
while(he) {
|
||||
struct cpool_bundle *bundle;
|
||||
struct connectdata *conn;
|
||||
|
||||
bundle = he->ptr;
|
||||
|
||||
curl_mfprintf(stderr, "%s -", he->key);
|
||||
curr = Curl_llist_head(bundle->conns);
|
||||
while(curr) {
|
||||
conn = Curl_node_elem(curr);
|
||||
|
||||
curl_mfprintf(stderr, " [%p %d]", (void *)conn, conn->refcount);
|
||||
curr = Curl_node_next(curr);
|
||||
}
|
||||
curl_mfprintf(stderr, "\n");
|
||||
|
||||
he = Curl_hash_next_element(&iter);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Vendored
+170
@@ -0,0 +1,170 @@
|
||||
#ifndef HEADER_CURL_CONNCACHE_H
|
||||
#define HEADER_CURL_CONNCACHE_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;
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
struct Curl_hash dest2bundle;
|
||||
size_t num_conn;
|
||||
curl_off_t next_connection_id;
|
||||
curl_off_t next_easy_id;
|
||||
struct curltime last_cleanup;
|
||||
struct 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.
|
||||
* Cannot fail.
|
||||
*/
|
||||
void Curl_cpool_init(struct cpool *cpool,
|
||||
struct Curl_easy *idata,
|
||||
struct Curl_share *share,
|
||||
size_t size);
|
||||
|
||||
/* Destroy all connections and free all members */
|
||||
void Curl_cpool_destroy(struct cpool *connc);
|
||||
|
||||
/* Init the transfer to be used within its connection pool.
|
||||
* Assigns `data->id`. */
|
||||
void Curl_cpool_xfer_init(struct Curl_easy *data);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
* the given connection. Will try to discard the oldest, idle
|
||||
* connections to make space.
|
||||
*/
|
||||
#define CPOOL_LIMIT_OK 0
|
||||
#define CPOOL_LIMIT_DEST 1
|
||||
#define CPOOL_LIMIT_TOTAL 2
|
||||
int Curl_cpool_check_limits(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
|
||||
/* Return of conn is suitable. If so, stops iteration. */
|
||||
typedef bool Curl_cpool_conn_match_cb(struct connectdata *conn,
|
||||
void *userdata);
|
||||
|
||||
/* Act on the result of the find, may override it. */
|
||||
typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
|
||||
|
||||
/**
|
||||
* Find a connection in the pool matching `destination`.
|
||||
* All callbacks are invoked while the pool's lock is held.
|
||||
* @param data current transfer
|
||||
* @param destination match against `conn->destination` in pool
|
||||
* @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,
|
||||
Curl_cpool_conn_match_cb *conn_cb,
|
||||
Curl_cpool_done_match_cb *done_cb,
|
||||
void *userdata);
|
||||
|
||||
/*
|
||||
* A connection (already in the pool) is now idle. Do any
|
||||
* cleanups in regard to the pool's limits.
|
||||
*
|
||||
* Return TRUE if idle connection kept in pool, FALSE if closed.
|
||||
*/
|
||||
bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
|
||||
/**
|
||||
* This function scans the data's connection pool for half-open/dead
|
||||
* connections, closes and removes them.
|
||||
* The cleanup is done at most once per second.
|
||||
*
|
||||
* When called, this transfer has no connection attached.
|
||||
*/
|
||||
void Curl_cpool_prune_dead(struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Perform upkeep actions on connections in the transfer's pool.
|
||||
*/
|
||||
CURLcode Curl_cpool_upkeep(void *data);
|
||||
|
||||
typedef void Curl_cpool_conn_do_cb(struct connectdata *conn,
|
||||
struct Curl_easy *data,
|
||||
void *cbdata);
|
||||
|
||||
/**
|
||||
* Invoke the callback on the pool's connection with the
|
||||
* given connection id (if it exists).
|
||||
*/
|
||||
void Curl_cpool_do_by_id(struct Curl_easy *data,
|
||||
curl_off_t conn_id,
|
||||
Curl_cpool_conn_do_cb *cb, void *cbdata);
|
||||
|
||||
/**
|
||||
* Invoked the callback for the given data + connection under the
|
||||
* connection pool's lock.
|
||||
* The callback is always invoked, even if the transfer has no connection
|
||||
* pool associated.
|
||||
*/
|
||||
void Curl_cpool_do_locked(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
Curl_cpool_conn_do_cb *cb, void *cbdata);
|
||||
|
||||
/* Close all unused connections, prevent reuse of existing ones. */
|
||||
void Curl_cpool_nw_changed(struct Curl_easy *data);
|
||||
|
||||
|
||||
#endif /* HEADER_CURL_CONNCACHE_H */
|
||||
Vendored
+630
@@ -0,0 +1,630 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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> /* <netinet/tcp.h> may need it */
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h> /* for sockaddr_un */
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TCP_H
|
||||
#include <linux/tcp.h>
|
||||
#elif defined(HAVE_NETINET_TCP_H)
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.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
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "if2ip.h"
|
||||
#include "strerror.h"
|
||||
#include "cfilters.h"
|
||||
#include "connect.h"
|
||||
#include "cf-haproxy.h"
|
||||
#include "cf-https-connect.h"
|
||||
#include "cf-ip-happy.h"
|
||||
#include "cf-socket.h"
|
||||
#include "select.h"
|
||||
#include "url.h" /* for Curl_safefree() */
|
||||
#include "multiif.h"
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "curlx/inet_ntop.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "vtls/vtls.h" /* for vtsl cfilters */
|
||||
#include "progress.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multihandle.h"
|
||||
#include "share.h"
|
||||
#include "http_proxy.h"
|
||||
#include "socks.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
|
||||
|
||||
enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
|
||||
{
|
||||
if(len == 2) {
|
||||
if(curl_strnequal(name, "h1", 2))
|
||||
return ALPN_h1;
|
||||
if(curl_strnequal(name, "h2", 2))
|
||||
return ALPN_h2;
|
||||
if(curl_strnequal(name, "h3", 2))
|
||||
return ALPN_h3;
|
||||
}
|
||||
else if(len == 8) {
|
||||
if(curl_strnequal(name, "http/1.1", 8))
|
||||
return ALPN_h1;
|
||||
}
|
||||
return ALPN_none; /* unknown, probably rubbish input */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Curl_timeleft() returns the amount of milliseconds left allowed for the
|
||||
* transfer/connection. If the value is 0, there is no timeout (ie there is
|
||||
* 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 curlx_now()
|
||||
* @param duringconnect TRUE iff connect timeout is also taken into account.
|
||||
* @unittest: 1303
|
||||
*/
|
||||
timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
struct curltime *nowp,
|
||||
bool duringconnect)
|
||||
{
|
||||
timediff_t timeleft_ms = 0;
|
||||
timediff_t ctimeleft_ms = 0;
|
||||
struct curltime now;
|
||||
|
||||
/* The duration of a connect and the total transfer are calculated from two
|
||||
different time-stamps. It can end up with the total timeout being reached
|
||||
before the connect timeout expires and we must acknowledge whichever
|
||||
timeout that is reached first. The total timeout is set per entire
|
||||
operation, while the connect timeout is set per connect. */
|
||||
if((!data->set.timeout || data->set.connect_only) && !duringconnect)
|
||||
return 0; /* no timeout in place or checked, return "no limit" */
|
||||
|
||||
if(!nowp) {
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
|
||||
if(data->set.timeout) {
|
||||
timeleft_ms = data->set.timeout -
|
||||
curlx_timediff(*nowp, data->progress.t_startop);
|
||||
if(!timeleft_ms)
|
||||
timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
|
||||
if(!duringconnect)
|
||||
return timeleft_ms; /* no connect check, this is it */
|
||||
}
|
||||
|
||||
if(duringconnect) {
|
||||
timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
|
||||
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
|
||||
ctimeleft_ms = ctimeout_ms -
|
||||
curlx_timediff(*nowp, data->progress.t_startsingle);
|
||||
if(!ctimeleft_ms)
|
||||
ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
|
||||
if(!timeleft_ms)
|
||||
return ctimeleft_ms; /* no general timeout, this is it */
|
||||
}
|
||||
/* return minimal time left or max amount already expired */
|
||||
return (ctimeleft_ms < timeleft_ms) ? ctimeleft_ms : timeleft_ms;
|
||||
}
|
||||
|
||||
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
|
||||
int timeout_ms, struct curltime *nowp)
|
||||
{
|
||||
struct curltime now;
|
||||
struct connectdata *conn = data->conn;
|
||||
|
||||
DEBUGASSERT(conn);
|
||||
if(!nowp) {
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
conn->shutdown.start[sockindex] = *nowp;
|
||||
conn->shutdown.timeout_ms = (timeout_ms > 0) ?
|
||||
(timediff_t)timeout_ms :
|
||||
((data->set.shutdowntimeout > 0) ?
|
||||
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
||||
/* Set a timer, unless we operate on the admin handle */
|
||||
if(data->mid)
|
||||
Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms,
|
||||
EXPIRE_SHUTDOWN);
|
||||
}
|
||||
|
||||
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
|
||||
struct curltime *nowp)
|
||||
{
|
||||
struct curltime now;
|
||||
timediff_t left_ms;
|
||||
|
||||
if(!conn->shutdown.start[sockindex].tv_sec ||
|
||||
(conn->shutdown.timeout_ms <= 0))
|
||||
return 0; /* not started or no limits */
|
||||
|
||||
if(!nowp) {
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
left_ms = conn->shutdown.timeout_ms -
|
||||
curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
|
||||
return left_ms ? left_ms : -1;
|
||||
}
|
||||
|
||||
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
|
||||
struct curltime *nowp)
|
||||
{
|
||||
timediff_t left_ms = 0, ms;
|
||||
struct curltime now;
|
||||
int i;
|
||||
|
||||
for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
|
||||
if(!conn->shutdown.start[i].tv_sec)
|
||||
continue;
|
||||
if(!nowp) {
|
||||
now = curlx_now();
|
||||
nowp = &now;
|
||||
}
|
||||
ms = Curl_shutdown_timeleft(conn, i, nowp);
|
||||
if(ms && (!left_ms || ms < left_ms))
|
||||
left_ms = ms;
|
||||
}
|
||||
return left_ms;
|
||||
}
|
||||
|
||||
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
|
||||
{
|
||||
struct curltime *pt = &data->conn->shutdown.start[sockindex];
|
||||
memset(pt, 0, sizeof(*pt));
|
||||
}
|
||||
|
||||
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
|
||||
{
|
||||
struct curltime *pt = &data->conn->shutdown.start[sockindex];
|
||||
return (pt->tv_sec > 0) || (pt->tv_usec > 0);
|
||||
}
|
||||
|
||||
/* retrieves ip address and port from a sockaddr structure. note it calls
|
||||
curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
|
||||
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
char *addr, int *port)
|
||||
{
|
||||
struct sockaddr_in *si = NULL;
|
||||
#ifdef USE_IPV6
|
||||
struct sockaddr_in6 *si6 = NULL;
|
||||
#endif
|
||||
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
|
||||
struct sockaddr_un *su = NULL;
|
||||
#else
|
||||
(void)salen;
|
||||
#endif
|
||||
|
||||
switch(sa->sa_family) {
|
||||
case AF_INET:
|
||||
si = (struct sockaddr_in *)(void *) sa;
|
||||
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
|
||||
unsigned short us_port = ntohs(si->sin_port);
|
||||
*port = us_port;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
#ifdef USE_IPV6
|
||||
case AF_INET6:
|
||||
si6 = (struct sockaddr_in6 *)(void *) sa;
|
||||
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
|
||||
MAX_IPADR_LEN)) {
|
||||
unsigned short us_port = ntohs(si6->sin6_port);
|
||||
*port = us_port;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
|
||||
case AF_UNIX:
|
||||
if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
|
||||
su = (struct sockaddr_un*)sa;
|
||||
curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
|
||||
}
|
||||
else
|
||||
addr[0] = 0; /* socket with no name */
|
||||
*port = 0;
|
||||
return TRUE;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
addr[0] = '\0';
|
||||
*port = 0;
|
||||
CURL_SETERRNO(SOCKEAFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to extract socket and connectdata struct for the most recent
|
||||
* transfer on the given Curl_easy.
|
||||
*
|
||||
* The returned socket will be CURL_SOCKET_BAD in case of failure!
|
||||
*/
|
||||
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
|
||||
struct connectdata **connp)
|
||||
{
|
||||
DEBUGASSERT(data);
|
||||
|
||||
/* this works for an easy handle:
|
||||
* - that has been used for curl_easy_perform()
|
||||
* - that is associated with a multi handle, and whose connection
|
||||
* was detached with CURLOPT_CONNECT_ONLY
|
||||
*/
|
||||
if(data->state.lastconnect_id != -1) {
|
||||
struct connectdata *conn;
|
||||
|
||||
conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
|
||||
if(!conn) {
|
||||
data->state.lastconnect_id = -1;
|
||||
return CURL_SOCKET_BAD;
|
||||
}
|
||||
|
||||
if(connp)
|
||||
/* only store this if the caller cares for it */
|
||||
*connp = conn;
|
||||
return conn->sock[FIRSTSOCKET];
|
||||
}
|
||||
return CURL_SOCKET_BAD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_conncontrol() marks streams or connection for closure.
|
||||
*/
|
||||
void Curl_conncontrol(struct connectdata *conn,
|
||||
int ctrl /* see defines in header */
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
, const char *reason
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* close if a connection, or a stream that is not multiplexed. */
|
||||
/* This function will be called both before and after this connection is
|
||||
associated with a transfer. */
|
||||
bool closeit, is_multiplex;
|
||||
DEBUGASSERT(conn);
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
(void)reason; /* useful for debugging */
|
||||
#endif
|
||||
is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
|
||||
closeit = (ctrl == CONNCTRL_CONNECTION) ||
|
||||
((ctrl == CONNCTRL_STREAM) && !is_multiplex);
|
||||
if((ctrl == CONNCTRL_STREAM) && is_multiplex)
|
||||
; /* stream signal on multiplex conn never affects close state */
|
||||
else if((bit)closeit != conn->bits.close) {
|
||||
conn->bits.close = closeit; /* the only place in the source code that
|
||||
should assign this bit */
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
CF_SETUP_INIT,
|
||||
CF_SETUP_CNNCT_EYEBALLS,
|
||||
CF_SETUP_CNNCT_SOCKS,
|
||||
CF_SETUP_CNNCT_HTTP_PROXY,
|
||||
CF_SETUP_CNNCT_HAPROXY,
|
||||
CF_SETUP_CNNCT_SSL,
|
||||
CF_SETUP_DONE
|
||||
} cf_setup_state;
|
||||
|
||||
struct cf_setup_ctx {
|
||||
cf_setup_state state;
|
||||
int ssl_mode;
|
||||
int transport;
|
||||
};
|
||||
|
||||
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
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;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* 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, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
|
||||
result = cf_ip_happy_insert_after(cf, data, ctx->transport);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
|
||||
if(!cf->next || !cf->next->connected)
|
||||
goto connect_sub_chain;
|
||||
}
|
||||
|
||||
/* sub-chain connected, do we need to add more? */
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
|
||||
result = Curl_cf_socks_proxy_insert_after(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = CF_SETUP_CNNCT_SOCKS;
|
||||
if(!cf->next || !cf->next->connected)
|
||||
goto connect_sub_chain;
|
||||
}
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
|
||||
#ifdef USE_SSL
|
||||
if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype)
|
||||
&& !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
|
||||
result = Curl_cf_ssl_proxy_insert_after(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(cf->conn->bits.tunnel_proxy) {
|
||||
result = Curl_cf_http_proxy_insert_after(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_HTTP */
|
||||
ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
|
||||
if(!cf->next || !cf->next->connected)
|
||||
goto connect_sub_chain;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(data->set.haproxyprotocol) {
|
||||
if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
|
||||
failf(data, "haproxy protocol not support with SSL "
|
||||
"encryption in place (QUIC?)");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
result = Curl_cf_haproxy_insert_after(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
ctx->state = CF_SETUP_CNNCT_HAPROXY;
|
||||
if(!cf->next || !cf->next->connected)
|
||||
goto connect_sub_chain;
|
||||
}
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_SSL) {
|
||||
#ifdef USE_SSL
|
||||
if((ctx->ssl_mode == CURL_CF_SSL_ENABLE
|
||||
|| (ctx->ssl_mode != CURL_CF_SSL_DISABLE
|
||||
&& cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */
|
||||
&& !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
|
||||
result = Curl_cf_ssl_insert_after(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
ctx->state = CF_SETUP_CNNCT_SSL;
|
||||
if(!cf->next || !cf->next->connected)
|
||||
goto connect_sub_chain;
|
||||
}
|
||||
|
||||
ctx->state = CF_SETUP_DONE;
|
||||
cf->connected = TRUE;
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cf_setup_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_setup_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
cf->connected = FALSE;
|
||||
ctx->state = CF_SETUP_INIT;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_setup_ctx *ctx = cf->ctx;
|
||||
|
||||
(void)data;
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
Curl_safefree(ctx);
|
||||
}
|
||||
|
||||
|
||||
struct Curl_cftype Curl_cft_setup = {
|
||||
"SETUP",
|
||||
0,
|
||||
CURL_LOG_LVL_NONE,
|
||||
cf_setup_destroy,
|
||||
cf_setup_connect,
|
||||
cf_setup_close,
|
||||
Curl_cf_def_shutdown,
|
||||
Curl_cf_def_adjust_pollset,
|
||||
Curl_cf_def_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_def_query,
|
||||
};
|
||||
|
||||
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
struct cf_setup_ctx *ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
(void)data;
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
ctx->state = CF_SETUP_INIT;
|
||||
ctx->ssl_mode = ssl_mode;
|
||||
ctx->transport = transport;
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
ctx = NULL;
|
||||
|
||||
out:
|
||||
*pcf = result ? NULL : cf;
|
||||
if(ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_setup_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_setup_create(&cf, data, transport, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
int transport,
|
||||
int ssl_mode)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_setup_create(&cf, data, transport, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_conn_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
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;
|
||||
|
||||
#ifndef 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);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_HTTP */
|
||||
|
||||
/* Still no cfilter set, apply default. */
|
||||
if(!conn->cfilter[sockindex]) {
|
||||
result = cf_setup_add(data, conn, sockindex,
|
||||
conn->transport_wanted, ssl_mode);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(conn->cfilter[sockindex]);
|
||||
out:
|
||||
if(result)
|
||||
Curl_resolv_unlink(data, &data->state.dns[sockindex]);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn)
|
||||
{
|
||||
if(!conn->bits.multiplex) {
|
||||
conn->bits.multiplex = TRUE;
|
||||
if(conn->attached_multi) {
|
||||
Curl_multi_connchanged(conn->attached_multi);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+131
@@ -0,0 +1,131 @@
|
||||
#ifndef HEADER_CURL_CONNECT_H
|
||||
#define HEADER_CURL_CONNECT_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"
|
||||
|
||||
#include "curlx/nonblock.h" /* for curlx_nonblock() */
|
||||
#include "sockaddr.h"
|
||||
#include "curlx/timeval.h"
|
||||
|
||||
struct Curl_dns_entry;
|
||||
struct ip_quadruple;
|
||||
|
||||
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 */
|
||||
timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
struct curltime *nowp,
|
||||
bool duringconnect);
|
||||
|
||||
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
|
||||
|
||||
#define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000)
|
||||
|
||||
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
|
||||
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. */
|
||||
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
|
||||
struct curltime *nowp);
|
||||
|
||||
/* return how much time there is left to shutdown the connection.
|
||||
* Returns 0 if there is no limit or shutdown has not started. */
|
||||
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
|
||||
struct curltime *nowp);
|
||||
|
||||
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/* TRUE iff shutdown has been started */
|
||||
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);
|
||||
|
||||
/*
|
||||
* Used to extract socket and connectdata struct for the most recent
|
||||
* transfer on the given Curl_easy.
|
||||
*
|
||||
* The returned socket will be CURL_SOCKET_BAD in case of failure!
|
||||
*/
|
||||
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
|
||||
struct connectdata **connp);
|
||||
|
||||
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
char *addr, int *port);
|
||||
|
||||
/*
|
||||
* Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
|
||||
* argument specifies if it is the end of a connection or a stream.
|
||||
*
|
||||
* For stream-based protocols (such as HTTP/2), a stream close will not cause
|
||||
* a connection close. Other protocols will close the connection for both
|
||||
* cases.
|
||||
*
|
||||
* It sets the bit.close bit to TRUE (with an explanation for debug builds),
|
||||
* when the connection will close.
|
||||
*/
|
||||
|
||||
#define CONNCTRL_KEEP 0 /* undo a marked closure */
|
||||
#define CONNCTRL_CONNECTION 1
|
||||
#define CONNCTRL_STREAM 2
|
||||
|
||||
void Curl_conncontrol(struct connectdata *conn,
|
||||
int closeit
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
, const char *reason
|
||||
#endif
|
||||
);
|
||||
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
|
||||
#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
|
||||
#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
|
||||
#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */
|
||||
#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM)
|
||||
#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
|
||||
#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP)
|
||||
#endif
|
||||
|
||||
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
int transport,
|
||||
int ssl_mode);
|
||||
|
||||
/**
|
||||
* Setup the cfilters at `sockindex` in connection `conn`.
|
||||
* If no filter chain is installed yet, inspects the configuration
|
||||
* in `data` and `conn? to install a suitable filter chain.
|
||||
*/
|
||||
CURLcode Curl_conn_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
struct Curl_dns_entry *dns,
|
||||
int ssl_mode);
|
||||
|
||||
/* Set conn to allow multiplexing. */
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_setup;
|
||||
|
||||
#endif /* HEADER_CURL_CONNECT_H */
|
||||
+860
@@ -0,0 +1,860 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include <curl/curl.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BROTLI
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
/* Ignore -Wvla warnings in brotli headers */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvla"
|
||||
#endif
|
||||
#include <brotli/decode.h>
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ZSTD
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
|
||||
#include "sendf.h"
|
||||
#include "http.h"
|
||||
#include "content_encoding.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define CONTENT_ENCODING_DEFAULT "identity"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
/* 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 < 0x1252)
|
||||
#error "requires zlib 1.2.5.2 or newer"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ZLIB_UNINIT, /* uninitialized */
|
||||
ZLIB_INIT, /* initialized */
|
||||
ZLIB_INFLATING, /* inflating started. */
|
||||
ZLIB_EXTERNAL_TRAILER, /* reading external trailer */
|
||||
ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
|
||||
} zlibInitState;
|
||||
|
||||
/* Deflate and gzip writer. */
|
||||
struct zlib_writer {
|
||||
struct Curl_cwriter super;
|
||||
zlibInitState zlib_init; /* zlib init state */
|
||||
char buffer[DECOMPRESS_BUFFER_SIZE]; /* Put the decompressed data here. */
|
||||
uInt trailerlen; /* Remaining trailer byte count. */
|
||||
z_stream z; /* State structure for zlib. */
|
||||
};
|
||||
|
||||
|
||||
static voidpf
|
||||
zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
|
||||
{
|
||||
(void)opaque;
|
||||
/* not a typo, keep it calloc() */
|
||||
return (voidpf) calloc(items, size);
|
||||
}
|
||||
|
||||
static void
|
||||
zfree_cb(voidpf opaque, voidpf ptr)
|
||||
{
|
||||
(void)opaque;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
process_zlib_error(struct Curl_easy *data, z_stream *z)
|
||||
{
|
||||
if(z->msg)
|
||||
failf(data, "Error while processing content unencoding: %s",
|
||||
z->msg);
|
||||
else
|
||||
failf(data, "Error while processing content unencoding: "
|
||||
"Unknown failure within decompression software.");
|
||||
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
exit_zlib(struct Curl_easy *data,
|
||||
z_stream *z, zlibInitState *zlib_init, CURLcode result)
|
||||
{
|
||||
if(*zlib_init != ZLIB_UNINIT) {
|
||||
if(inflateEnd(z) != Z_OK && result == CURLE_OK)
|
||||
result = process_zlib_error(data, z);
|
||||
*zlib_init = ZLIB_UNINIT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode process_trailer(struct Curl_easy *data,
|
||||
struct zlib_writer *zp)
|
||||
{
|
||||
z_stream *z = &zp->z;
|
||||
CURLcode result = CURLE_OK;
|
||||
uInt len = z->avail_in < zp->trailerlen ? z->avail_in : zp->trailerlen;
|
||||
|
||||
/* Consume expected trailer bytes. Terminate stream if exhausted.
|
||||
Issue an error if unexpected bytes follow. */
|
||||
|
||||
zp->trailerlen -= len;
|
||||
z->avail_in -= len;
|
||||
z->next_in += len;
|
||||
if(z->avail_in)
|
||||
result = CURLE_WRITE_ERROR;
|
||||
if(result || !zp->trailerlen)
|
||||
result = exit_zlib(data, z, &zp->zlib_init, result);
|
||||
else {
|
||||
/* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
|
||||
zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode inflate_stream(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
zlibInitState started)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
uInt nread = z->avail_in;
|
||||
z_const Bytef *orig_in = z->next_in;
|
||||
bool done = FALSE;
|
||||
CURLcode result = CURLE_OK; /* Curl_client_write status */
|
||||
|
||||
/* Check state. */
|
||||
if(zp->zlib_init != ZLIB_INIT &&
|
||||
zp->zlib_init != ZLIB_INFLATING &&
|
||||
zp->zlib_init != ZLIB_INIT_GZIP)
|
||||
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
|
||||
|
||||
/* because the buffer size is fixed, iteratively decompress and transfer to
|
||||
the client via next_write function. */
|
||||
while(!done) {
|
||||
int status; /* zlib status */
|
||||
done = TRUE;
|
||||
|
||||
/* (re)set buffer for decompressed output for every iteration */
|
||||
z->next_out = (Bytef *) zp->buffer;
|
||||
z->avail_out = DECOMPRESS_BUFFER_SIZE;
|
||||
|
||||
status = inflate(z, Z_BLOCK);
|
||||
|
||||
/* Flush output data if some. */
|
||||
if(z->avail_out != DECOMPRESS_BUFFER_SIZE) {
|
||||
if(status == Z_OK || status == Z_STREAM_END) {
|
||||
zp->zlib_init = started; /* Data started. */
|
||||
result = Curl_cwriter_write(data, writer->next, type, zp->buffer,
|
||||
DECOMPRESS_BUFFER_SIZE - z->avail_out);
|
||||
if(result) {
|
||||
exit_zlib(data, z, &zp->zlib_init, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dispatch by inflate() status. */
|
||||
switch(status) {
|
||||
case Z_OK:
|
||||
/* Always loop: there may be unflushed latched data in zlib state. */
|
||||
done = FALSE;
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
/* No more data to flush: just exit loop. */
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
result = process_trailer(data, zp);
|
||||
break;
|
||||
case Z_DATA_ERROR:
|
||||
/* some servers seem to not generate zlib headers, so this is an attempt
|
||||
to fix and continue anyway */
|
||||
if(zp->zlib_init == ZLIB_INIT) {
|
||||
if(inflateReset2(z, -MAX_WBITS) == Z_OK) {
|
||||
z->next_in = orig_in;
|
||||
z->avail_in = nread;
|
||||
zp->zlib_init = ZLIB_INFLATING;
|
||||
zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
|
||||
done = FALSE;
|
||||
break;
|
||||
}
|
||||
zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
|
||||
}
|
||||
result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
|
||||
break;
|
||||
default:
|
||||
result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are about to leave this call so the `nread' data bytes will not be seen
|
||||
again. If we are in a state that would wrongly allow restart in raw mode
|
||||
at the next call, assume output has already started. */
|
||||
if(nread && zp->zlib_init == ZLIB_INIT)
|
||||
zp->zlib_init = started; /* Cannot restart anymore. */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Deflate handler. */
|
||||
static CURLcode deflate_do_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
/* Initialize zlib */
|
||||
z->zalloc = (alloc_func) zalloc_cb;
|
||||
z->zfree = (free_func) zfree_cb;
|
||||
|
||||
if(inflateInit(z) != Z_OK)
|
||||
return process_zlib_error(data, z);
|
||||
zp->zlib_init = ZLIB_INIT;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode deflate_do_write(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
const char *buf, size_t nbytes)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
if(!(type & CLIENTWRITE_BODY) || !nbytes)
|
||||
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
|
||||
|
||||
/* Set the compressed input when this function is called */
|
||||
z->next_in = (z_const Bytef *)buf;
|
||||
z->avail_in = (uInt)nbytes;
|
||||
|
||||
if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
|
||||
return process_trailer(data, zp);
|
||||
|
||||
/* Now uncompress the data */
|
||||
return inflate_stream(data, writer, type, ZLIB_INFLATING);
|
||||
}
|
||||
|
||||
static void deflate_do_close(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
|
||||
}
|
||||
|
||||
static const struct Curl_cwtype deflate_encoding = {
|
||||
"deflate",
|
||||
NULL,
|
||||
deflate_do_init,
|
||||
deflate_do_write,
|
||||
deflate_do_close,
|
||||
sizeof(struct zlib_writer)
|
||||
};
|
||||
|
||||
|
||||
/* Gzip handler. */
|
||||
static CURLcode gzip_do_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
/* Initialize zlib */
|
||||
z->zalloc = (alloc_func) zalloc_cb;
|
||||
z->zfree = (free_func) zfree_cb;
|
||||
|
||||
if(inflateInit2(z, MAX_WBITS + 32) != Z_OK)
|
||||
return process_zlib_error(data, z);
|
||||
|
||||
zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode gzip_do_write(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
const char *buf, size_t nbytes)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
if(!(type & CLIENTWRITE_BODY) || !nbytes)
|
||||
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
|
||||
|
||||
if(zp->zlib_init == ZLIB_INIT_GZIP) {
|
||||
/* Let zlib handle the gzip decompression entirely */
|
||||
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);
|
||||
}
|
||||
|
||||
/* We are running with an old version: return error. */
|
||||
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
|
||||
}
|
||||
|
||||
static void gzip_do_close(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zlib_writer *zp = (struct zlib_writer *) writer;
|
||||
z_stream *z = &zp->z; /* zlib state structure */
|
||||
|
||||
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
|
||||
}
|
||||
|
||||
static const struct Curl_cwtype gzip_encoding = {
|
||||
"gzip",
|
||||
"x-gzip",
|
||||
gzip_do_init,
|
||||
gzip_do_write,
|
||||
gzip_do_close,
|
||||
sizeof(struct zlib_writer)
|
||||
};
|
||||
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
||||
#ifdef HAVE_BROTLI
|
||||
/* Brotli writer. */
|
||||
struct brotli_writer {
|
||||
struct Curl_cwriter super;
|
||||
char buffer[DECOMPRESS_BUFFER_SIZE];
|
||||
BrotliDecoderState *br; /* State structure for brotli. */
|
||||
};
|
||||
|
||||
static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
|
||||
{
|
||||
switch(be) {
|
||||
case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
|
||||
case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
|
||||
#ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY
|
||||
case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
|
||||
#endif
|
||||
#ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET
|
||||
case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
|
||||
#endif
|
||||
case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
|
||||
case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
|
||||
case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
|
||||
case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
|
||||
case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
|
||||
case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
|
||||
static CURLcode brotli_do_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct brotli_writer *bp = (struct brotli_writer *) writer;
|
||||
(void)data;
|
||||
|
||||
bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||
return bp->br ? CURLE_OK : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
static CURLcode brotli_do_write(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
const char *buf, size_t nbytes)
|
||||
{
|
||||
struct brotli_writer *bp = (struct brotli_writer *) writer;
|
||||
const uint8_t *src = (const uint8_t *) buf;
|
||||
uint8_t *dst;
|
||||
size_t dstleft;
|
||||
CURLcode result = CURLE_OK;
|
||||
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
|
||||
|
||||
if(!(type & CLIENTWRITE_BODY) || !nbytes)
|
||||
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
|
||||
|
||||
if(!bp->br)
|
||||
return CURLE_WRITE_ERROR; /* Stream already ended. */
|
||||
|
||||
while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
|
||||
result == CURLE_OK) {
|
||||
dst = (uint8_t *) bp->buffer;
|
||||
dstleft = DECOMPRESS_BUFFER_SIZE;
|
||||
r = BrotliDecoderDecompressStream(bp->br,
|
||||
&nbytes, &src, &dstleft, &dst, NULL);
|
||||
result = Curl_cwriter_write(data, writer->next, type,
|
||||
bp->buffer, DECOMPRESS_BUFFER_SIZE - dstleft);
|
||||
if(result)
|
||||
break;
|
||||
switch(r) {
|
||||
case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
|
||||
case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
|
||||
break;
|
||||
case BROTLI_DECODER_RESULT_SUCCESS:
|
||||
BrotliDecoderDestroyInstance(bp->br);
|
||||
bp->br = NULL;
|
||||
if(nbytes)
|
||||
result = CURLE_WRITE_ERROR;
|
||||
break;
|
||||
default:
|
||||
result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void brotli_do_close(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct brotli_writer *bp = (struct brotli_writer *) writer;
|
||||
(void)data;
|
||||
|
||||
if(bp->br) {
|
||||
BrotliDecoderDestroyInstance(bp->br);
|
||||
bp->br = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct Curl_cwtype brotli_encoding = {
|
||||
"br",
|
||||
NULL,
|
||||
brotli_do_init,
|
||||
brotli_do_write,
|
||||
brotli_do_close,
|
||||
sizeof(struct brotli_writer)
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ZSTD
|
||||
/* Zstd writer. */
|
||||
struct zstd_writer {
|
||||
struct Curl_cwriter super;
|
||||
ZSTD_DStream *zds; /* State structure for zstd. */
|
||||
char buffer[DECOMPRESS_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
#ifdef ZSTD_STATIC_LINKING_ONLY
|
||||
static void *Curl_zstd_alloc(void *opaque, size_t size)
|
||||
{
|
||||
(void)opaque;
|
||||
return Curl_cmalloc(size);
|
||||
}
|
||||
|
||||
static void Curl_zstd_free(void *opaque, void *address)
|
||||
{
|
||||
(void)opaque;
|
||||
Curl_cfree(address);
|
||||
}
|
||||
#endif
|
||||
|
||||
static CURLcode zstd_do_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zstd_writer *zp = (struct zstd_writer *) writer;
|
||||
|
||||
(void)data;
|
||||
|
||||
#ifdef ZSTD_STATIC_LINKING_ONLY
|
||||
zp->zds = ZSTD_createDStream_advanced((ZSTD_customMem) {
|
||||
.customAlloc = Curl_zstd_alloc,
|
||||
.customFree = Curl_zstd_free,
|
||||
.opaque = NULL
|
||||
});
|
||||
#else
|
||||
zp->zds = ZSTD_createDStream();
|
||||
#endif
|
||||
|
||||
return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
static CURLcode zstd_do_write(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
const char *buf, size_t nbytes)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct zstd_writer *zp = (struct zstd_writer *) writer;
|
||||
ZSTD_inBuffer in;
|
||||
ZSTD_outBuffer out;
|
||||
size_t errorCode;
|
||||
|
||||
if(!(type & CLIENTWRITE_BODY) || !nbytes)
|
||||
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
|
||||
|
||||
in.pos = 0;
|
||||
in.src = buf;
|
||||
in.size = nbytes;
|
||||
|
||||
for(;;) {
|
||||
out.pos = 0;
|
||||
out.dst = zp->buffer;
|
||||
out.size = DECOMPRESS_BUFFER_SIZE;
|
||||
|
||||
errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
|
||||
if(ZSTD_isError(errorCode)) {
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
if(out.pos > 0) {
|
||||
result = Curl_cwriter_write(data, writer->next, type,
|
||||
zp->buffer, out.pos);
|
||||
if(result)
|
||||
break;
|
||||
}
|
||||
if((in.pos == nbytes) && (out.pos < out.size))
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void zstd_do_close(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
struct zstd_writer *zp = (struct zstd_writer *) writer;
|
||||
(void)data;
|
||||
|
||||
if(zp->zds) {
|
||||
ZSTD_freeDStream(zp->zds);
|
||||
zp->zds = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct Curl_cwtype zstd_encoding = {
|
||||
"zstd",
|
||||
NULL,
|
||||
zstd_do_init,
|
||||
zstd_do_write,
|
||||
zstd_do_close,
|
||||
sizeof(struct zstd_writer)
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Identity handler. */
|
||||
static const struct Curl_cwtype identity_encoding = {
|
||||
"identity",
|
||||
"none",
|
||||
Curl_cwriter_def_init,
|
||||
Curl_cwriter_def_write,
|
||||
Curl_cwriter_def_close,
|
||||
sizeof(struct Curl_cwriter)
|
||||
};
|
||||
|
||||
/* supported general content decoders. */
|
||||
static const struct Curl_cwtype * const general_unencoders[] = {
|
||||
&identity_encoding,
|
||||
#ifdef HAVE_LIBZ
|
||||
&deflate_encoding,
|
||||
&gzip_encoding,
|
||||
#endif
|
||||
#ifdef HAVE_BROTLI
|
||||
&brotli_encoding,
|
||||
#endif
|
||||
#ifdef HAVE_ZSTD
|
||||
&zstd_encoding,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* supported content decoders only for transfer encodings */
|
||||
static const struct Curl_cwtype * const transfer_unencoders[] = {
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
&Curl_httpchunk_unencoder,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Provide a list of comma-separated names of supported encodings.
|
||||
*/
|
||||
void Curl_all_content_encodings(char *buf, size_t blen)
|
||||
{
|
||||
size_t len = 0;
|
||||
const struct Curl_cwtype * const *cep;
|
||||
const struct Curl_cwtype *ce;
|
||||
|
||||
DEBUGASSERT(buf);
|
||||
DEBUGASSERT(blen);
|
||||
buf[0] = 0;
|
||||
|
||||
for(cep = general_unencoders; *cep; cep++) {
|
||||
ce = *cep;
|
||||
if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT))
|
||||
len += strlen(ce->name) + 2;
|
||||
}
|
||||
|
||||
if(!len) {
|
||||
if(blen >= sizeof(CONTENT_ENCODING_DEFAULT))
|
||||
strcpy(buf, CONTENT_ENCODING_DEFAULT);
|
||||
}
|
||||
else if(blen > len) {
|
||||
char *p = buf;
|
||||
for(cep = general_unencoders; *cep; cep++) {
|
||||
ce = *cep;
|
||||
if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) {
|
||||
strcpy(p, ce->name);
|
||||
p += strlen(p);
|
||||
*p++ = ',';
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
p[-2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Deferred error dummy writer. */
|
||||
static CURLcode error_do_init(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
(void)data;
|
||||
(void)writer;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode error_do_write(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer, int type,
|
||||
const char *buf, size_t nbytes)
|
||||
{
|
||||
(void)writer;
|
||||
(void)buf;
|
||||
(void)nbytes;
|
||||
|
||||
if(!(type & CLIENTWRITE_BODY) || !nbytes)
|
||||
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
|
||||
else {
|
||||
char all[256];
|
||||
(void)Curl_all_content_encodings(all, sizeof(all));
|
||||
failf(data, "Unrecognized content encoding type. "
|
||||
"libcurl understands %s content encodings.", all);
|
||||
}
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
static void error_do_close(struct Curl_easy *data,
|
||||
struct Curl_cwriter *writer)
|
||||
{
|
||||
(void)data;
|
||||
(void)writer;
|
||||
}
|
||||
|
||||
static const struct Curl_cwtype error_writer = {
|
||||
"ce-error",
|
||||
NULL,
|
||||
error_do_init,
|
||||
error_do_write,
|
||||
error_do_close,
|
||||
sizeof(struct Curl_cwriter)
|
||||
};
|
||||
|
||||
/* Find the content encoding by name. */
|
||||
static const struct Curl_cwtype *find_unencode_writer(const char *name,
|
||||
size_t len,
|
||||
Curl_cwriter_phase phase)
|
||||
{
|
||||
const struct Curl_cwtype * const *cep;
|
||||
|
||||
if(phase == CURL_CW_TRANSFER_DECODE) {
|
||||
for(cep = transfer_unencoders; *cep; cep++) {
|
||||
const struct Curl_cwtype *ce = *cep;
|
||||
if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
|
||||
(ce->alias && curl_strnequal(name, ce->alias, len)
|
||||
&& !ce->alias[len]))
|
||||
return ce;
|
||||
}
|
||||
}
|
||||
/* look among the general decoders */
|
||||
for(cep = general_unencoders; *cep; cep++) {
|
||||
const struct Curl_cwtype *ce = *cep;
|
||||
if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
|
||||
(ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len]))
|
||||
return ce;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Setup the unencoding stack from the Content-Encoding header value.
|
||||
* See RFC 7231 section 3.1.2.2. */
|
||||
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
|
||||
const char *enclist, int is_transfer)
|
||||
{
|
||||
Curl_cwriter_phase phase = is_transfer ?
|
||||
CURL_CW_TRANSFER_DECODE : CURL_CW_CONTENT_DECODE;
|
||||
CURLcode result;
|
||||
bool has_chunked = FALSE;
|
||||
|
||||
do {
|
||||
const char *name;
|
||||
size_t namelen;
|
||||
bool is_chunked = FALSE;
|
||||
|
||||
/* Parse a single encoding name. */
|
||||
while(ISBLANK(*enclist) || *enclist == ',')
|
||||
enclist++;
|
||||
|
||||
name = enclist;
|
||||
|
||||
for(namelen = 0; *enclist && *enclist != ','; enclist++)
|
||||
if(*enclist > ' ')
|
||||
namelen = enclist - name + 1;
|
||||
|
||||
if(namelen) {
|
||||
const struct Curl_cwtype *cwt;
|
||||
struct Curl_cwriter *writer;
|
||||
|
||||
CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
|
||||
is_transfer ? "transfer" : "content", (int)namelen, name);
|
||||
is_chunked = (is_transfer && (namelen == 7) &&
|
||||
curl_strnequal(name, "chunked", 7));
|
||||
/* if we skip the decoding in this phase, do not look further.
|
||||
* Exception is "chunked" transfer-encoding which always must happen */
|
||||
if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
|
||||
(!is_transfer && data->set.http_ce_skip)) {
|
||||
bool is_identity = curl_strnequal(name, "identity", 8);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
|
||||
failf(data, "Reject response due to more than %u content encodings",
|
||||
MAX_ENCODE_STACK);
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
cwt = find_unencode_writer(name, namelen, phase);
|
||||
if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
|
||||
/* A 'chunked' transfer encoding has already been added.
|
||||
* Ignore duplicates. See #13451.
|
||||
* Also RFC 9112, ch. 6.1:
|
||||
* "A sender MUST NOT apply the chunked transfer coding more than
|
||||
* once to a message body."
|
||||
*/
|
||||
CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(is_transfer && !is_chunked &&
|
||||
Curl_cwriter_get_by_name(data, "chunked")) {
|
||||
/* RFC 9112, ch. 6.1:
|
||||
* "If any transfer coding other than chunked is applied to a
|
||||
* response's content, the sender MUST either apply chunked as the
|
||||
* final transfer coding or terminate the message by closing the
|
||||
* connection."
|
||||
* "chunked" must be the last added to be the first in its phase,
|
||||
* reject this.
|
||||
*/
|
||||
failf(data, "Reject response due to 'chunked' not being the last "
|
||||
"Transfer-Encoding");
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
if(!cwt)
|
||||
cwt = &error_writer; /* Defer error at use. */
|
||||
|
||||
result = Curl_cwriter_create(&writer, data, cwt, phase);
|
||||
CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
|
||||
is_transfer ? "transfer" : "content", cwt->name, result);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_cwriter_add(data, writer);
|
||||
if(result) {
|
||||
Curl_cwriter_free(data, writer);
|
||||
return result;
|
||||
}
|
||||
if(is_chunked)
|
||||
has_chunked = TRUE;
|
||||
}
|
||||
} while(*enclist);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stubs for builds without HTTP. */
|
||||
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
|
||||
const char *enclist, int is_transfer)
|
||||
{
|
||||
(void)data;
|
||||
(void)enclist;
|
||||
(void)is_transfer;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
void Curl_all_content_encodings(char *buf, size_t blen)
|
||||
{
|
||||
DEBUGASSERT(buf);
|
||||
DEBUGASSERT(blen);
|
||||
if(blen < sizeof(CONTENT_ENCODING_DEFAULT))
|
||||
buf[0] = 0;
|
||||
else
|
||||
strcpy(buf, CONTENT_ENCODING_DEFAULT);
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#ifndef HEADER_CURL_CONTENT_ENCODING_H
|
||||
#define HEADER_CURL_CONTENT_ENCODING_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"
|
||||
|
||||
struct Curl_cwriter;
|
||||
|
||||
void Curl_all_content_encodings(char *buf, size_t blen);
|
||||
|
||||
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
|
||||
const char *enclist, int is_transfer);
|
||||
#endif /* HEADER_CURL_CONTENT_ENCODING_H */
|
||||
Vendored
+1692
File diff suppressed because it is too large
Load Diff
Vendored
+142
@@ -0,0 +1,142 @@
|
||||
#ifndef HEADER_CURL_COOKIE_H
|
||||
#define HEADER_CURL_COOKIE_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"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
struct Cookie {
|
||||
struct Curl_llist_node node; /* for the main cookie list */
|
||||
struct Curl_llist_node getnode; /* for getlist */
|
||||
char *name; /* <this> = value */
|
||||
char *value; /* name = <this> */
|
||||
char *path; /* path = <this> which is in Set-Cookie: */
|
||||
char *spath; /* sanitized cookie path */
|
||||
char *domain; /* domain = <this> */
|
||||
curl_off_t expires; /* expires = <this> */
|
||||
unsigned int creationtime; /* time when the cookie was written */
|
||||
BIT(tailmatch); /* tail-match the domain name */
|
||||
BIT(secure); /* the 'secure' keyword was used */
|
||||
BIT(livecookie); /* updated from a server, not a stored file */
|
||||
BIT(httponly); /* the httponly directive is present */
|
||||
BIT(prefix_secure); /* secure prefix is set */
|
||||
BIT(prefix_host); /* host prefix is set */
|
||||
};
|
||||
|
||||
/*
|
||||
* Available cookie prefixes, as defined in
|
||||
* draft-ietf-httpbis-rfc6265bis-02
|
||||
*/
|
||||
#define COOKIE_PREFIX__SECURE (1<<0)
|
||||
#define COOKIE_PREFIX__HOST (1<<1)
|
||||
|
||||
#define COOKIE_HASH_SIZE 63
|
||||
|
||||
struct CookieInfo {
|
||||
/* linked lists of cookies we know of */
|
||||
struct Curl_llist cookielist[COOKIE_HASH_SIZE];
|
||||
curl_off_t next_expiration; /* the next time at which expiration happens */
|
||||
unsigned int numcookies; /* number of cookies in the "jar" */
|
||||
unsigned int lastct; /* last creation-time used in the jar */
|
||||
BIT(running); /* state info, for cookie adding information */
|
||||
BIT(newsession); /* new session, discard session cookies on load */
|
||||
};
|
||||
|
||||
/* The maximum sizes we accept for cookies. RFC 6265 section 6.1 says
|
||||
"general-use user agents SHOULD provide each of the following minimum
|
||||
capabilities":
|
||||
|
||||
- At least 4096 bytes per cookie (as measured by the sum of the length of
|
||||
the cookie's name, value, and attributes).
|
||||
In the 6265bis draft document section 5.4 it is phrased even stronger: "If
|
||||
the sum of the lengths of the name string and the value string is more than
|
||||
4096 octets, abort these steps and ignore the set-cookie-string entirely."
|
||||
*/
|
||||
|
||||
/** Limits for INCOMING cookies **/
|
||||
|
||||
/* The longest we allow a line to be when reading a cookie from an HTTP header
|
||||
or from a cookie jar */
|
||||
#define MAX_COOKIE_LINE 5000
|
||||
|
||||
/* Maximum length of an incoming cookie name or content we deal with. Longer
|
||||
cookies are ignored. */
|
||||
#define MAX_NAME 4096
|
||||
|
||||
/* Maximum number of Set-Cookie: lines accepted in a single response. If more
|
||||
such header lines are received, they are ignored. This value must be less
|
||||
than 256 since an unsigned char is used to count. */
|
||||
#define MAX_SET_COOKIE_AMOUNT 50
|
||||
|
||||
/** Limits for OUTGOING cookies **/
|
||||
|
||||
/* Maximum size for an outgoing cookie line libcurl will use in an http
|
||||
request. This is the default maximum length used in some versions of Apache
|
||||
httpd. */
|
||||
#define MAX_COOKIE_HEADER_LEN 8190
|
||||
|
||||
/* Maximum number of cookies libcurl will send in a single request, even if
|
||||
there might be more cookies that match. One reason to cap the number is to
|
||||
keep the maximum HTTP request within the maximum allowed size. */
|
||||
#define MAX_COOKIE_SEND_AMOUNT 150
|
||||
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
|
||||
/*
|
||||
* Add a cookie to the internal list of cookies. The domain and path arguments
|
||||
* are only used if the header boolean is TRUE.
|
||||
*/
|
||||
|
||||
bool Curl_secure_context(struct connectdata *conn, const char *host);
|
||||
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
|
||||
struct CookieInfo *c, bool header,
|
||||
bool noexpiry, const char *lineptr,
|
||||
const char *domain, const char *path,
|
||||
bool secure);
|
||||
int Curl_cookie_getlist(struct Curl_easy *data, struct connectdata *conn,
|
||||
const char *host, struct Curl_llist *list);
|
||||
void Curl_cookie_clearall(struct CookieInfo *cookies);
|
||||
void Curl_cookie_clearsess(struct CookieInfo *cookies);
|
||||
|
||||
#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
|
||||
#define Curl_cookie_list(x) NULL
|
||||
#define Curl_cookie_loadfiles(x) Curl_nop_stmt
|
||||
#define Curl_cookie_init(x,y,z,w) NULL
|
||||
#define Curl_cookie_cleanup(x) Curl_nop_stmt
|
||||
#define Curl_flush_cookies(x,y) Curl_nop_stmt
|
||||
#else
|
||||
void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
|
||||
void Curl_cookie_cleanup(struct CookieInfo *c);
|
||||
struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
|
||||
const char *file, struct CookieInfo *inc,
|
||||
bool newsession);
|
||||
struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
|
||||
void Curl_cookie_loadfiles(struct Curl_easy *data);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_COOKIE_H */
|
||||
Vendored
+588
@@ -0,0 +1,588 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "curlx/strparse.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#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) {
|
||||
|
||||
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;
|
||||
struct easy_pollset ps;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
unsigned int i;
|
||||
struct connectdata *conn = Curl_node_elem(e);
|
||||
CURLcode result;
|
||||
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
result = Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
if(result)
|
||||
continue;
|
||||
|
||||
for(i = 0; i < ps.n; i++) {
|
||||
#ifdef __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);
|
||||
#ifdef __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];
|
||||
}
|
||||
}
|
||||
Curl_pollset_cleanup(&ps);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
CURLcode result;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
conn = Curl_node_elem(e);
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
result = Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
if(!result)
|
||||
need += Curl_waitfds_add_ps(cwfds, &ps);
|
||||
}
|
||||
Curl_pollset_cleanup(&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;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
conn = Curl_node_elem(e);
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
result = Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
if(!result)
|
||||
result = Curl_pollfds_add_ps(cpfds, &ps);
|
||||
if(result) {
|
||||
Curl_pollset_cleanup(&ps);
|
||||
Curl_pollfds_cleanup(cpfds);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
Curl_pollset_cleanup(&ps);
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
Vendored
+110
@@ -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 */
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN6_H
|
||||
# include <netinet/in6.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
# include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#ifdef __VMS
|
||||
# include <in.h>
|
||||
# include <inet.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "curl_addrinfo.h"
|
||||
#include "fake_addrinfo.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "curlx/warnless.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* Curl_freeaddrinfo()
|
||||
*
|
||||
* This is used to free a linked list of Curl_addrinfo structs along
|
||||
* with all its associated allocated storage. This function should be
|
||||
* called once for each successful call to Curl_getaddrinfo_ex() or to
|
||||
* any function call which actually allocates a Curl_addrinfo struct.
|
||||
*/
|
||||
|
||||
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
|
||||
defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
|
||||
/* workaround icc 9.1 optimizer issue */
|
||||
# define vqualifier volatile
|
||||
#else
|
||||
# define vqualifier
|
||||
#endif
|
||||
|
||||
void
|
||||
Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
|
||||
{
|
||||
struct Curl_addrinfo *vqualifier canext;
|
||||
struct Curl_addrinfo *ca;
|
||||
|
||||
for(ca = cahead; ca; ca = canext) {
|
||||
canext = ca->ai_next;
|
||||
free(ca);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
/*
|
||||
* Curl_getaddrinfo_ex()
|
||||
*
|
||||
* This is a wrapper function around system's getaddrinfo(), with
|
||||
* the only difference that instead of returning a linked list of
|
||||
* addrinfo structs this one returns a linked list of Curl_addrinfo
|
||||
* ones. The memory allocated by this function *MUST* be free'd with
|
||||
* Curl_freeaddrinfo(). For each successful call to this function
|
||||
* there must be an associated call later to Curl_freeaddrinfo().
|
||||
*
|
||||
* There should be no single call to system's getaddrinfo() in the
|
||||
* whole library, any such call should be 'routed' through this one.
|
||||
*/
|
||||
|
||||
int
|
||||
Curl_getaddrinfo_ex(const char *nodename,
|
||||
const char *servname,
|
||||
const struct addrinfo *hints,
|
||||
struct Curl_addrinfo **result)
|
||||
{
|
||||
const struct addrinfo *ai;
|
||||
struct addrinfo *aihead;
|
||||
struct Curl_addrinfo *cafirst = NULL;
|
||||
struct Curl_addrinfo *calast = NULL;
|
||||
struct Curl_addrinfo *ca;
|
||||
size_t ss_size;
|
||||
int error;
|
||||
|
||||
*result = NULL; /* assume failure */
|
||||
|
||||
error = CURL_GETADDRINFO(nodename, servname, hints, &aihead);
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
/* traverse the addrinfo list */
|
||||
|
||||
for(ai = aihead; ai != NULL; ai = ai->ai_next) {
|
||||
size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0;
|
||||
/* ignore elements with unsupported address family, */
|
||||
/* settle family-specific sockaddr structure size. */
|
||||
if(ai->ai_family == AF_INET)
|
||||
ss_size = sizeof(struct sockaddr_in);
|
||||
#ifdef USE_IPV6
|
||||
else if(ai->ai_family == AF_INET6)
|
||||
ss_size = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
else
|
||||
continue;
|
||||
|
||||
/* ignore elements without required address info */
|
||||
if(!ai->ai_addr || !(ai->ai_addrlen > 0))
|
||||
continue;
|
||||
|
||||
/* ignore elements with bogus address size */
|
||||
if((size_t)ai->ai_addrlen < ss_size)
|
||||
continue;
|
||||
|
||||
ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
|
||||
if(!ca) {
|
||||
error = EAI_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy each structure member individually, member ordering, */
|
||||
/* size, or padding might be different for each platform. */
|
||||
|
||||
ca->ai_flags = ai->ai_flags;
|
||||
ca->ai_family = ai->ai_family;
|
||||
ca->ai_socktype = ai->ai_socktype;
|
||||
ca->ai_protocol = ai->ai_protocol;
|
||||
ca->ai_addrlen = (curl_socklen_t)ss_size;
|
||||
ca->ai_addr = NULL;
|
||||
ca->ai_canonname = NULL;
|
||||
ca->ai_next = NULL;
|
||||
|
||||
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
|
||||
memcpy(ca->ai_addr, ai->ai_addr, ss_size);
|
||||
|
||||
if(namelen) {
|
||||
ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
|
||||
memcpy(ca->ai_canonname, ai->ai_canonname, namelen);
|
||||
}
|
||||
|
||||
/* if the return list is empty, this becomes the first element */
|
||||
if(!cafirst)
|
||||
cafirst = ca;
|
||||
|
||||
/* add this element last in the return list */
|
||||
if(calast)
|
||||
calast->ai_next = ca;
|
||||
calast = ca;
|
||||
|
||||
}
|
||||
|
||||
/* destroy the addrinfo list */
|
||||
if(aihead)
|
||||
CURL_FREEADDRINFO(aihead);
|
||||
|
||||
/* if we failed, also destroy the Curl_addrinfo list */
|
||||
if(error) {
|
||||
Curl_freeaddrinfo(cafirst);
|
||||
cafirst = NULL;
|
||||
}
|
||||
else if(!cafirst) {
|
||||
#ifdef EAI_NONAME
|
||||
/* rfc3493 conformant */
|
||||
error = EAI_NONAME;
|
||||
#else
|
||||
/* rfc3493 obsoleted */
|
||||
error = EAI_NODATA;
|
||||
#endif
|
||||
#ifdef USE_WINSOCK
|
||||
SET_SOCKERRNO(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
*result = cafirst;
|
||||
|
||||
/* This is not a CURLcode */
|
||||
return error;
|
||||
}
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
|
||||
|
||||
/*
|
||||
* Curl_he2ai()
|
||||
*
|
||||
* 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 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
|
||||
* Curl_freeaddrinfo(). For each successful call to this function there
|
||||
* must be an associated call later to Curl_freeaddrinfo().
|
||||
*
|
||||
* Curl_addrinfo defined in "lib/curl_addrinfo.h"
|
||||
*
|
||||
* struct Curl_addrinfo {
|
||||
* int ai_flags;
|
||||
* int ai_family;
|
||||
* int ai_socktype;
|
||||
* int ai_protocol;
|
||||
* curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo *
|
||||
* char *ai_canonname;
|
||||
* struct sockaddr *ai_addr;
|
||||
* struct Curl_addrinfo *ai_next;
|
||||
* };
|
||||
*
|
||||
* hostent defined in <netdb.h>
|
||||
*
|
||||
* struct hostent {
|
||||
* char *h_name;
|
||||
* char **h_aliases;
|
||||
* int h_addrtype;
|
||||
* int h_length;
|
||||
* char **h_addr_list;
|
||||
* };
|
||||
*
|
||||
* for backward compatibility:
|
||||
*
|
||||
* #define h_addr h_addr_list[0]
|
||||
*/
|
||||
|
||||
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
|
||||
struct Curl_addrinfo *
|
||||
Curl_he2ai(const struct hostent *he, int port)
|
||||
{
|
||||
struct Curl_addrinfo *ai;
|
||||
struct Curl_addrinfo *prevai = NULL;
|
||||
struct Curl_addrinfo *firstai = NULL;
|
||||
struct sockaddr_in *addr;
|
||||
#ifdef USE_IPV6
|
||||
struct sockaddr_in6 *addr6;
|
||||
#endif
|
||||
CURLcode result = CURLE_OK;
|
||||
int i;
|
||||
char *curr;
|
||||
|
||||
if(!he)
|
||||
/* no input == no output! */
|
||||
return NULL;
|
||||
|
||||
DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
|
||||
|
||||
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
|
||||
size_t ss_size;
|
||||
size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
|
||||
#ifdef USE_IPV6
|
||||
if(he->h_addrtype == AF_INET6)
|
||||
ss_size = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
#endif
|
||||
ss_size = sizeof(struct sockaddr_in);
|
||||
|
||||
/* allocate memory to hold the struct, the address and the name */
|
||||
ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
|
||||
if(!ai) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
/* put the address after the struct */
|
||||
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
|
||||
/* then put the name after the address */
|
||||
ai->ai_canonname = (char *)ai->ai_addr + ss_size;
|
||||
memcpy(ai->ai_canonname, he->h_name, namelen);
|
||||
|
||||
if(!firstai)
|
||||
/* store the pointer we want to return from this function */
|
||||
firstai = ai;
|
||||
|
||||
if(prevai)
|
||||
/* make the previous entry point to this */
|
||||
prevai->ai_next = ai;
|
||||
|
||||
ai->ai_family = he->h_addrtype;
|
||||
|
||||
/* we return all names as STREAM, so when using this address for TFTP
|
||||
the type must be ignored and conn->socktype be used instead! */
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
|
||||
ai->ai_addrlen = (curl_socklen_t)ss_size;
|
||||
|
||||
/* leave the rest of the struct filled with zero */
|
||||
|
||||
switch(ai->ai_family) {
|
||||
case AF_INET:
|
||||
addr = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
|
||||
addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
|
||||
addr->sin_port = htons((unsigned short)port);
|
||||
break;
|
||||
|
||||
#ifdef USE_IPV6
|
||||
case AF_INET6:
|
||||
addr6 = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
|
||||
addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
|
||||
addr6->sin6_port = htons((unsigned short)port);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
prevai = ai;
|
||||
}
|
||||
|
||||
if(result) {
|
||||
Curl_freeaddrinfo(firstai);
|
||||
firstai = NULL;
|
||||
}
|
||||
|
||||
return firstai;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Curl_ip2addr()
|
||||
*
|
||||
* This function takes an Internet address, in binary form, as input parameter
|
||||
* along with its address family and the string version of the address, and it
|
||||
* returns a Curl_addrinfo chain filled in correctly with information for the
|
||||
* given address/host
|
||||
*/
|
||||
|
||||
struct Curl_addrinfo *
|
||||
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
|
||||
{
|
||||
struct Curl_addrinfo *ai;
|
||||
size_t addrsize;
|
||||
size_t namelen;
|
||||
struct sockaddr_in *addr;
|
||||
#ifdef USE_IPV6
|
||||
struct sockaddr_in6 *addr6;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(inaddr && hostname);
|
||||
|
||||
namelen = strlen(hostname) + 1;
|
||||
|
||||
if(af == AF_INET)
|
||||
addrsize = sizeof(struct sockaddr_in);
|
||||
#ifdef USE_IPV6
|
||||
else if(af == AF_INET6)
|
||||
addrsize = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
else
|
||||
return NULL;
|
||||
|
||||
/* allocate memory to hold the struct, the address and the name */
|
||||
ai = calloc(1, sizeof(struct Curl_addrinfo) + addrsize + namelen);
|
||||
if(!ai)
|
||||
return NULL;
|
||||
/* put the address after the struct */
|
||||
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
|
||||
/* then put the name after the address */
|
||||
ai->ai_canonname = (char *)ai->ai_addr + addrsize;
|
||||
memcpy(ai->ai_canonname, hostname, namelen);
|
||||
ai->ai_family = af;
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
ai->ai_addrlen = (curl_socklen_t)addrsize;
|
||||
/* leave the rest of the struct filled with zero */
|
||||
|
||||
switch(af) {
|
||||
case AF_INET:
|
||||
addr = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr->sin_addr, inaddr, sizeof(struct in_addr));
|
||||
addr->sin_family = (CURL_SA_FAMILY_T)af;
|
||||
addr->sin_port = htons((unsigned short)port);
|
||||
break;
|
||||
|
||||
#ifdef USE_IPV6
|
||||
case AF_INET6:
|
||||
addr6 = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr6->sin6_addr, inaddr, sizeof(struct in6_addr));
|
||||
addr6->sin6_family = (CURL_SA_FAMILY_T)af;
|
||||
addr6->sin6_port = htons((unsigned short)port);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an IPv4 or IPv6 dotted string address, this converts it to a proper
|
||||
* allocated Curl_addrinfo struct and returns it.
|
||||
*/
|
||||
struct Curl_addrinfo *Curl_str2addr(char *address, int port)
|
||||
{
|
||||
struct in_addr in;
|
||||
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(curlx_inet_pton(AF_INET6, address, &in6) > 0)
|
||||
/* This is a dotted IPv6 address ::1-style */
|
||||
return Curl_ip2addr(AF_INET6, &in6, address, port);
|
||||
}
|
||||
#endif
|
||||
return NULL; /* bad input format */
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
/**
|
||||
* Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
|
||||
* struct initialized with this path.
|
||||
* Set '*longpath' to TRUE if the error is a too long path.
|
||||
*/
|
||||
struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
|
||||
bool abstract)
|
||||
{
|
||||
struct Curl_addrinfo *ai;
|
||||
struct sockaddr_un *sa_un;
|
||||
size_t path_len;
|
||||
|
||||
*longpath = FALSE;
|
||||
|
||||
ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un));
|
||||
if(!ai)
|
||||
return NULL;
|
||||
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
|
||||
|
||||
sa_un = (void *) ai->ai_addr;
|
||||
sa_un->sun_family = AF_UNIX;
|
||||
|
||||
/* 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);
|
||||
*longpath = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ai->ai_family = AF_UNIX;
|
||||
ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
|
||||
ai->ai_addrlen = (curl_socklen_t)
|
||||
((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF);
|
||||
|
||||
/* Abstract Unix domain socket have NULL prefix instead of suffix */
|
||||
if(abstract)
|
||||
memcpy(sa_un->sun_path + 1, path, path_len - 1);
|
||||
else
|
||||
memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
|
||||
|
||||
return ai;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
|
||||
defined(HAVE_FREEADDRINFO)
|
||||
/*
|
||||
* curl_dbg_freeaddrinfo()
|
||||
*
|
||||
* This is strictly for memory tracing and are using the same style as the
|
||||
* family otherwise present in memdebug.c. I put these ones here since they
|
||||
* require a bunch of structs I did not want to include in memdebug.c
|
||||
*/
|
||||
|
||||
void
|
||||
curl_dbg_freeaddrinfo(struct addrinfo *freethis,
|
||||
int line, const char *source)
|
||||
{
|
||||
curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
|
||||
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
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
freeaddrinfo(freethis);
|
||||
}
|
||||
#else
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
freeaddrinfo(freethis);
|
||||
#endif
|
||||
}
|
||||
#endif /* CURLDEBUG && HAVE_FREEADDRINFO */
|
||||
|
||||
|
||||
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
|
||||
/*
|
||||
* curl_dbg_getaddrinfo()
|
||||
*
|
||||
* This is strictly for memory tracing and are using the same style as the
|
||||
* family otherwise present in memdebug.c. I put these ones here since they
|
||||
* require a bunch of structs I did not want to include in memdebug.c
|
||||
*/
|
||||
|
||||
int
|
||||
curl_dbg_getaddrinfo(const char *hostname,
|
||||
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
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
res = getaddrinfo(hostname, service, hints, result);
|
||||
#else
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
int res = getaddrinfo(hostname, service, hints, result);
|
||||
#endif
|
||||
if(res == 0)
|
||||
/* success */
|
||||
curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n",
|
||||
source, line, (void *)*result);
|
||||
else
|
||||
curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n",
|
||||
source, line);
|
||||
return res;
|
||||
}
|
||||
#endif /* CURLDEBUG && HAVE_GETADDRINFO */
|
||||
|
||||
#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
|
||||
/*
|
||||
* Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and macOS
|
||||
* 10.11.5.
|
||||
*/
|
||||
void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
|
||||
{
|
||||
struct Curl_addrinfo *ca;
|
||||
struct sockaddr_in *addr;
|
||||
#ifdef USE_IPV6
|
||||
struct sockaddr_in6 *addr6;
|
||||
#endif
|
||||
for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
|
||||
switch(ca->ai_family) {
|
||||
case AF_INET:
|
||||
addr = (void *)ca->ai_addr; /* storage area for this info */
|
||||
addr->sin_port = htons((unsigned short)port);
|
||||
break;
|
||||
|
||||
#ifdef USE_IPV6
|
||||
case AF_INET6:
|
||||
addr6 = (void *)ca->ai_addr; /* storage area for this info */
|
||||
addr6->sin6_port = htons((unsigned short)port);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
#ifndef HEADER_CURL_ADDRINFO_H
|
||||
#define HEADER_CURL_ADDRINFO_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"
|
||||
|
||||
#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>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Curl_addrinfo is our internal struct definition that we use to allow
|
||||
* consistent internal handling of this data. We use this even when the system
|
||||
* provides an addrinfo structure definition. We use this for all sorts of
|
||||
* IPv4 and IPV6 builds.
|
||||
*/
|
||||
|
||||
struct Curl_addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */
|
||||
char *ai_canonname;
|
||||
struct sockaddr *ai_addr;
|
||||
struct Curl_addrinfo *ai_next;
|
||||
};
|
||||
|
||||
void
|
||||
Curl_freeaddrinfo(struct Curl_addrinfo *cahead);
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
int
|
||||
Curl_getaddrinfo_ex(const char *nodename,
|
||||
const char *servname,
|
||||
const struct addrinfo *hints,
|
||||
struct Curl_addrinfo **result);
|
||||
#endif
|
||||
|
||||
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
|
||||
struct Curl_addrinfo *
|
||||
Curl_he2ai(const struct hostent *he, int port);
|
||||
#endif
|
||||
|
||||
struct Curl_addrinfo *
|
||||
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
|
||||
|
||||
struct Curl_addrinfo *Curl_str2addr(char *dotted, int port);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
|
||||
bool abstract);
|
||||
#endif
|
||||
|
||||
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
|
||||
defined(HAVE_FREEADDRINFO)
|
||||
void
|
||||
curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source);
|
||||
#endif
|
||||
|
||||
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
|
||||
int
|
||||
curl_dbg_getaddrinfo(const char *hostname, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **result,
|
||||
int line, const char *source);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
#ifdef USE_RESOLVE_ON_IPS
|
||||
void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port);
|
||||
#else
|
||||
#define Curl_addrinfo_set_port(x,y)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_ADDRINFO_H */
|
||||
+813
@@ -0,0 +1,813 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Location of default ca bundle */
|
||||
#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}"
|
||||
|
||||
/* define "1" to use built-in ca store of TLS backend */
|
||||
#cmakedefine CURL_CA_FALLBACK 1
|
||||
|
||||
/* Location of default ca path */
|
||||
#cmakedefine CURL_CA_PATH "${CURL_CA_PATH}"
|
||||
|
||||
/* Default SSL backend */
|
||||
#cmakedefine CURL_DEFAULT_SSL_BACKEND "${CURL_DEFAULT_SSL_BACKEND}"
|
||||
|
||||
/* disables alt-svc */
|
||||
#cmakedefine CURL_DISABLE_ALTSVC 1
|
||||
|
||||
/* disables cookies support */
|
||||
#cmakedefine CURL_DISABLE_COOKIES 1
|
||||
|
||||
/* disables Basic authentication */
|
||||
#cmakedefine CURL_DISABLE_BASIC_AUTH 1
|
||||
|
||||
/* disables Bearer authentication */
|
||||
#cmakedefine CURL_DISABLE_BEARER_AUTH 1
|
||||
|
||||
/* disables Digest authentication */
|
||||
#cmakedefine CURL_DISABLE_DIGEST_AUTH 1
|
||||
|
||||
/* disables Kerberos authentication */
|
||||
#cmakedefine CURL_DISABLE_KERBEROS_AUTH 1
|
||||
|
||||
/* disables negotiate authentication */
|
||||
#cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1
|
||||
|
||||
/* disables aws-sigv4 */
|
||||
#cmakedefine CURL_DISABLE_AWS 1
|
||||
|
||||
/* disables DICT */
|
||||
#cmakedefine CURL_DISABLE_DICT 1
|
||||
|
||||
/* disables DNS-over-HTTPS */
|
||||
#cmakedefine CURL_DISABLE_DOH 1
|
||||
|
||||
/* disables FILE */
|
||||
#cmakedefine CURL_DISABLE_FILE 1
|
||||
|
||||
/* disables form api */
|
||||
#cmakedefine CURL_DISABLE_FORM_API 1
|
||||
|
||||
/* disables FTP */
|
||||
#cmakedefine CURL_DISABLE_FTP 1
|
||||
|
||||
/* disables curl_easy_options API for existing options to curl_easy_setopt */
|
||||
#cmakedefine CURL_DISABLE_GETOPTIONS 1
|
||||
|
||||
/* disables GOPHER */
|
||||
#cmakedefine CURL_DISABLE_GOPHER 1
|
||||
|
||||
/* disables headers-api support */
|
||||
#cmakedefine CURL_DISABLE_HEADERS_API 1
|
||||
|
||||
/* disables HSTS support */
|
||||
#cmakedefine CURL_DISABLE_HSTS 1
|
||||
|
||||
/* disables HTTP */
|
||||
#cmakedefine CURL_DISABLE_HTTP 1
|
||||
|
||||
/* disabled all HTTP authentication methods */
|
||||
#cmakedefine CURL_DISABLE_HTTP_AUTH 1
|
||||
|
||||
/* disables IMAP */
|
||||
#cmakedefine CURL_DISABLE_IMAP 1
|
||||
|
||||
/* disables LDAP */
|
||||
#cmakedefine CURL_DISABLE_LDAP 1
|
||||
|
||||
/* disables LDAPS */
|
||||
#cmakedefine CURL_DISABLE_LDAPS 1
|
||||
|
||||
/* disables --libcurl option from the curl tool */
|
||||
#cmakedefine CURL_DISABLE_LIBCURL_OPTION 1
|
||||
|
||||
/* disables MIME support */
|
||||
#cmakedefine CURL_DISABLE_MIME 1
|
||||
|
||||
/* disables local binding support */
|
||||
#cmakedefine CURL_DISABLE_BINDLOCAL 1
|
||||
|
||||
/* disables MQTT */
|
||||
#cmakedefine CURL_DISABLE_MQTT 1
|
||||
|
||||
/* disables netrc parser */
|
||||
#cmakedefine CURL_DISABLE_NETRC 1
|
||||
|
||||
/* disables NTLM support */
|
||||
#cmakedefine CURL_DISABLE_NTLM 1
|
||||
|
||||
/* disables date parsing */
|
||||
#cmakedefine CURL_DISABLE_PARSEDATE 1
|
||||
|
||||
/* disables POP3 */
|
||||
#cmakedefine CURL_DISABLE_POP3 1
|
||||
|
||||
/* disables built-in progress meter */
|
||||
#cmakedefine CURL_DISABLE_PROGRESS_METER 1
|
||||
|
||||
/* disables proxies */
|
||||
#cmakedefine CURL_DISABLE_PROXY 1
|
||||
|
||||
/* disables IPFS from the curl tool */
|
||||
#cmakedefine CURL_DISABLE_IPFS 1
|
||||
|
||||
/* disables RTSP */
|
||||
#cmakedefine CURL_DISABLE_RTSP 1
|
||||
|
||||
/* disables SHA-512/256 hash algorithm */
|
||||
#cmakedefine CURL_DISABLE_SHA512_256 1
|
||||
|
||||
/* disabled shuffle DNS feature */
|
||||
#cmakedefine CURL_DISABLE_SHUFFLE_DNS 1
|
||||
|
||||
/* disables SMB */
|
||||
#cmakedefine CURL_DISABLE_SMB 1
|
||||
|
||||
/* disables SMTP */
|
||||
#cmakedefine CURL_DISABLE_SMTP 1
|
||||
|
||||
/* disabled WebSocket */
|
||||
#cmakedefine CURL_DISABLE_WEBSOCKETS 1
|
||||
|
||||
/* disables use of socketpair for curl_multi_poll */
|
||||
#cmakedefine CURL_DISABLE_SOCKETPAIR 1
|
||||
|
||||
/* disables TELNET */
|
||||
#cmakedefine CURL_DISABLE_TELNET 1
|
||||
|
||||
/* disables TFTP */
|
||||
#cmakedefine CURL_DISABLE_TFTP 1
|
||||
|
||||
/* disables verbose strings */
|
||||
#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
|
||||
|
||||
/* disables unsafe CA bundle search on Windows from the curl tool */
|
||||
#cmakedefine CURL_DISABLE_CA_SEARCH 1
|
||||
|
||||
/* safe CA bundle search (within the curl tool directory) on Windows */
|
||||
#cmakedefine CURL_CA_SEARCH_SAFE 1
|
||||
|
||||
/* to make a symbol visible */
|
||||
#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
|
||||
/* Ensure using CURL_EXTERN_SYMBOL is possible */
|
||||
#ifndef CURL_EXTERN_SYMBOL
|
||||
#define CURL_EXTERN_SYMBOL
|
||||
#endif
|
||||
|
||||
/* Allow SMB to work on Windows */
|
||||
#cmakedefine USE_WIN32_CRYPTO 1
|
||||
|
||||
/* Use Windows LDAP implementation */
|
||||
#cmakedefine USE_WIN32_LDAP 1
|
||||
|
||||
/* Define if you want to enable IPv6 support */
|
||||
#cmakedefine USE_IPV6 1
|
||||
|
||||
/* Define to 1 if you have the alarm function. */
|
||||
#cmakedefine HAVE_ALARM 1
|
||||
|
||||
/* Define to 1 if you have the arc4random function. */
|
||||
#cmakedefine HAVE_ARC4RANDOM 1
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#cmakedefine HAVE_ARPA_INET_H 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* Define to 1 if you have the `basename' function. */
|
||||
#cmakedefine HAVE_BASENAME 1
|
||||
|
||||
/* Define to 1 if bool is an available type. */
|
||||
#cmakedefine HAVE_BOOL_T 1
|
||||
|
||||
/* Define to 1 if you have the __builtin_available function. */
|
||||
#cmakedefine HAVE_BUILTIN_AVAILABLE 1
|
||||
|
||||
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
|
||||
#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
|
||||
|
||||
/* Define to 1 if you have the clock_gettime function and raw monotonic timer.
|
||||
*/
|
||||
#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1
|
||||
|
||||
/* Define to 1 if you have the `closesocket' function. */
|
||||
#cmakedefine HAVE_CLOSESOCKET 1
|
||||
|
||||
/* Define to 1 if you have the `CloseSocket' function. */
|
||||
#cmakedefine HAVE_CLOSESOCKET_CAMEL 1
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#cmakedefine HAVE_DIRENT_H 1
|
||||
|
||||
/* Define to 1 if you have the `opendir' function. */
|
||||
#cmakedefine HAVE_OPENDIR 1
|
||||
|
||||
/* Define to 1 if you have the fcntl function. */
|
||||
#cmakedefine HAVE_FCNTL 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#cmakedefine HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
|
||||
#cmakedefine HAVE_FCNTL_O_NONBLOCK 1
|
||||
|
||||
/* Define to 1 if you have the freeaddrinfo function. */
|
||||
#cmakedefine HAVE_FREEADDRINFO 1
|
||||
|
||||
/* Define to 1 if you have the fseeko function. */
|
||||
#cmakedefine HAVE_FSEEKO 1
|
||||
|
||||
/* Define to 1 if you have the fseeko declaration. */
|
||||
#cmakedefine HAVE_DECL_FSEEKO 1
|
||||
|
||||
/* Define to 1 if you have the ftruncate function. */
|
||||
#cmakedefine HAVE_FTRUNCATE 1
|
||||
|
||||
/* Define to 1 if you have a working getaddrinfo function. */
|
||||
#cmakedefine HAVE_GETADDRINFO 1
|
||||
|
||||
/* Define to 1 if the getaddrinfo function is threadsafe. */
|
||||
#cmakedefine HAVE_GETADDRINFO_THREADSAFE 1
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#cmakedefine HAVE_GETEUID 1
|
||||
|
||||
/* Define to 1 if you have the `getppid' function. */
|
||||
#cmakedefine HAVE_GETPPID 1
|
||||
|
||||
/* Define to 1 if you have the gethostbyname_r function. */
|
||||
#cmakedefine HAVE_GETHOSTBYNAME_R 1
|
||||
|
||||
/* gethostbyname_r() takes 3 args */
|
||||
#cmakedefine HAVE_GETHOSTBYNAME_R_3 1
|
||||
|
||||
/* gethostbyname_r() takes 5 args */
|
||||
#cmakedefine HAVE_GETHOSTBYNAME_R_5 1
|
||||
|
||||
/* gethostbyname_r() takes 6 args */
|
||||
#cmakedefine HAVE_GETHOSTBYNAME_R_6 1
|
||||
|
||||
/* Define to 1 if you have the gethostname function. */
|
||||
#cmakedefine HAVE_GETHOSTNAME 1
|
||||
|
||||
/* Define to 1 if you have a working getifaddrs function. */
|
||||
#cmakedefine HAVE_GETIFADDRS 1
|
||||
|
||||
/* Define to 1 if you have the `getpass_r' function. */
|
||||
#cmakedefine HAVE_GETPASS_R 1
|
||||
|
||||
/* Define to 1 if you have the `getpeername' function. */
|
||||
#cmakedefine HAVE_GETPEERNAME 1
|
||||
|
||||
/* Define to 1 if you have the `getsockname' function. */
|
||||
#cmakedefine HAVE_GETSOCKNAME 1
|
||||
|
||||
/* Define to 1 if you have the `if_nametoindex' function. */
|
||||
#cmakedefine HAVE_IF_NAMETOINDEX 1
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#cmakedefine HAVE_GETPWUID 1
|
||||
|
||||
/* Define to 1 if you have the `getpwuid_r' function. */
|
||||
#cmakedefine HAVE_GETPWUID_R 1
|
||||
|
||||
/* Define to 1 if you have the `getrlimit' function. */
|
||||
#cmakedefine HAVE_GETRLIMIT 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#cmakedefine HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have a working glibc-style strerror_r function. */
|
||||
#cmakedefine HAVE_GLIBC_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have a working gmtime_r function. */
|
||||
#cmakedefine HAVE_GMTIME_R 1
|
||||
|
||||
/* if you have the gssapi libraries */
|
||||
#cmakedefine HAVE_GSSAPI 1
|
||||
|
||||
/* if you have the GNU gssapi libraries */
|
||||
#cmakedefine HAVE_GSSGNU 1
|
||||
|
||||
/* MIT Kerberos version */
|
||||
#cmakedefine CURL_KRB5_VERSION ${CURL_KRB5_VERSION}
|
||||
|
||||
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||
#cmakedefine HAVE_IFADDRS_H 1
|
||||
|
||||
/* Define to 1 if you have an IPv6 capable working inet_ntop function. */
|
||||
#cmakedefine HAVE_INET_NTOP 1
|
||||
|
||||
/* Define to 1 if you have an IPv6 capable working inet_pton function. */
|
||||
#cmakedefine HAVE_INET_PTON 1
|
||||
|
||||
/* Define to 1 if symbol `sa_family_t' exists */
|
||||
#cmakedefine HAVE_SA_FAMILY_T 1
|
||||
|
||||
/* Define to 1 if you have the ioctlsocket function. */
|
||||
#cmakedefine HAVE_IOCTLSOCKET 1
|
||||
|
||||
/* Define to 1 if you have the IoctlSocket camel case function. */
|
||||
#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1
|
||||
|
||||
/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
|
||||
*/
|
||||
#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
|
||||
|
||||
/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
|
||||
#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1
|
||||
|
||||
/* Define to 1 if you have a working ioctl FIONBIO function. */
|
||||
#cmakedefine HAVE_IOCTL_FIONBIO 1
|
||||
|
||||
/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
|
||||
#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#cmakedefine HAVE_IO_H 1
|
||||
|
||||
/* Define to 1 if you have the lber.h header file. */
|
||||
#cmakedefine HAVE_LBER_H 1
|
||||
|
||||
/* Use LDAPS implementation */
|
||||
#cmakedefine HAVE_LDAP_SSL 1
|
||||
|
||||
/* Define to 1 if you have the ldap_ssl.h header file. */
|
||||
#cmakedefine HAVE_LDAP_SSL_H 1
|
||||
|
||||
/* Define to 1 if you have the `ldap_url_parse' function. */
|
||||
#cmakedefine HAVE_LDAP_URL_PARSE 1
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#cmakedefine HAVE_LIBGEN_H 1
|
||||
|
||||
/* Define to 1 if you have the `idn2' library (-lidn2). */
|
||||
#cmakedefine HAVE_LIBIDN2 1
|
||||
|
||||
/* Define to 1 if you have the idn2.h header file. */
|
||||
#cmakedefine HAVE_IDN2_H 1
|
||||
|
||||
/* if zlib is available */
|
||||
#cmakedefine HAVE_LIBZ 1
|
||||
|
||||
/* if brotli is available */
|
||||
#cmakedefine HAVE_BROTLI 1
|
||||
|
||||
/* if zstd is available */
|
||||
#cmakedefine HAVE_ZSTD 1
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#cmakedefine HAVE_LOCALE_H 1
|
||||
|
||||
/* Define to 1 if the compiler supports the 'long long' data type. */
|
||||
#cmakedefine HAVE_LONGLONG 1
|
||||
|
||||
/* Define to 1 if you have the 'suseconds_t' data type. */
|
||||
#cmakedefine HAVE_SUSECONDS_T 1
|
||||
|
||||
/* Define to 1 if you have the MSG_NOSIGNAL flag. */
|
||||
#cmakedefine HAVE_MSG_NOSIGNAL 1
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#cmakedefine HAVE_NETDB_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in6.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_IN6_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_TCP_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/udp.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_UDP_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/tcp.h> header file. */
|
||||
#cmakedefine HAVE_LINUX_TCP_H 1
|
||||
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#cmakedefine HAVE_NET_IF_H 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* If you have poll */
|
||||
#cmakedefine HAVE_POLL 1
|
||||
|
||||
/* If you have realpath */
|
||||
#cmakedefine HAVE_REALPATH 1
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#cmakedefine HAVE_POLL_H 1
|
||||
|
||||
/* Define to 1 if you have a working POSIX-style strerror_r function. */
|
||||
#cmakedefine HAVE_POSIX_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file */
|
||||
#cmakedefine HAVE_PTHREAD_H 1
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#cmakedefine HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if OpenSSL has the `SSL_set0_wbio` function. */
|
||||
#cmakedefine HAVE_SSL_SET0_WBIO 1
|
||||
|
||||
/* Define to 1 if you have the recv function. */
|
||||
#cmakedefine HAVE_RECV 1
|
||||
|
||||
/* Define to 1 if you have the select function. */
|
||||
#cmakedefine HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the sched_yield function. */
|
||||
#cmakedefine HAVE_SCHED_YIELD 1
|
||||
|
||||
/* Define to 1 if you have the send function. */
|
||||
#cmakedefine HAVE_SEND 1
|
||||
|
||||
/* Define to 1 if you have the sendmsg function. */
|
||||
#cmakedefine HAVE_SENDMSG 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* fsetxattr() takes 5 args */
|
||||
#cmakedefine HAVE_FSETXATTR_5 1
|
||||
|
||||
/* fsetxattr() takes 6 args */
|
||||
#cmakedefine HAVE_FSETXATTR_6 1
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#cmakedefine HAVE_SETLOCALE 1
|
||||
|
||||
/* Define to 1 if you have the `setmode' function. */
|
||||
#cmakedefine HAVE_SETMODE 1
|
||||
|
||||
/* Define to 1 if you have the `_setmode' function. */
|
||||
#cmakedefine HAVE__SETMODE 1
|
||||
|
||||
/* Define to 1 if you have the `setrlimit' function. */
|
||||
#cmakedefine HAVE_SETRLIMIT 1
|
||||
|
||||
/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
|
||||
#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
|
||||
|
||||
/* Define to 1 if you have the sigaction function. */
|
||||
#cmakedefine HAVE_SIGACTION 1
|
||||
|
||||
/* Define to 1 if you have the siginterrupt function. */
|
||||
#cmakedefine HAVE_SIGINTERRUPT 1
|
||||
|
||||
/* Define to 1 if you have the signal function. */
|
||||
#cmakedefine HAVE_SIGNAL 1
|
||||
|
||||
/* Define to 1 if you have the sigsetjmp function or macro. */
|
||||
#cmakedefine HAVE_SIGSETJMP 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#cmakedefine HAVE_SNPRINTF 1
|
||||
|
||||
/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
|
||||
#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#cmakedefine HAVE_SOCKET 1
|
||||
|
||||
/* Define to 1 if you have the <proto/bsdsocket.h> header file. */
|
||||
#cmakedefine HAVE_PROTO_BSDSOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the socketpair function. */
|
||||
#cmakedefine HAVE_SOCKETPAIR 1
|
||||
|
||||
/* Define to 1 if you have the <stdatomic.h> header file. */
|
||||
#cmakedefine HAVE_STDATOMIC_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#cmakedefine HAVE_STDBOOL_H 1
|
||||
|
||||
/* Define to 1 if you have the strcasecmp function. */
|
||||
#cmakedefine HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the strcmpi function. */
|
||||
#cmakedefine HAVE_STRCMPI 1
|
||||
|
||||
/* Define to 1 if you have the strdup function. */
|
||||
#cmakedefine HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the strerror_r function. */
|
||||
#cmakedefine HAVE_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have the stricmp function. */
|
||||
#cmakedefine HAVE_STRICMP 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#cmakedefine HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <stropts.h> header file. */
|
||||
#cmakedefine HAVE_STROPTS_H 1
|
||||
|
||||
/* Define to 1 if you have the memrchr function. */
|
||||
#cmakedefine HAVE_MEMRCHR 1
|
||||
|
||||
/* if struct sockaddr_storage is defined */
|
||||
#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1
|
||||
|
||||
/* Define to 1 if you have the timeval struct. */
|
||||
#cmakedefine HAVE_STRUCT_TIMEVAL 1
|
||||
|
||||
/* Define to 1 if you have the <sys/eventfd.h> header file. */
|
||||
#cmakedefine HAVE_SYS_EVENTFD_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/filio.h> header file. */
|
||||
#cmakedefine HAVE_SYS_FILIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#cmakedefine HAVE_SYS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#cmakedefine HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/poll.h> header file. */
|
||||
#cmakedefine HAVE_SYS_POLL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#cmakedefine HAVE_SYS_RESOURCE_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SOCKIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
||||
#cmakedefine HAVE_SYS_UN_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/utime.h> header file. */
|
||||
#cmakedefine HAVE_SYS_UTIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#cmakedefine HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <termio.h> header file. */
|
||||
#cmakedefine HAVE_TERMIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `utime' function. */
|
||||
#cmakedefine HAVE_UTIME 1
|
||||
|
||||
/* Define to 1 if you have the `utimes' function. */
|
||||
#cmakedefine HAVE_UTIMES 1
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#cmakedefine HAVE_UTIME_H 1
|
||||
|
||||
/* Define this symbol if your OS supports changing the contents of argv */
|
||||
#cmakedefine HAVE_WRITABLE_ARGV 1
|
||||
|
||||
/* Define this if time_t is unsigned */
|
||||
#cmakedefine HAVE_TIME_T_UNSIGNED 1
|
||||
|
||||
/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
|
||||
#cmakedefine NEED_REENTRANT 1
|
||||
|
||||
/* cpu-machine-OS */
|
||||
#cmakedefine CURL_OS ${CURL_OS}
|
||||
|
||||
/*
|
||||
Note: SIZEOF_* variables are fetched with CMake through check_type_size().
|
||||
As per CMake documentation on CheckTypeSize, C preprocessor code is
|
||||
generated by CMake into SIZEOF_*_CODE. This is what we use in the
|
||||
following statements.
|
||||
|
||||
Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html
|
||||
*/
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
${SIZEOF_INT_CODE}
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
${SIZEOF_LONG_CODE}
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
${SIZEOF_LONG_LONG_CODE}
|
||||
|
||||
/* The size of `off_t', as computed by sizeof. */
|
||||
${SIZEOF_OFF_T_CODE}
|
||||
|
||||
/* The size of `curl_off_t', as computed by sizeof. */
|
||||
${SIZEOF_CURL_OFF_T_CODE}
|
||||
|
||||
/* The size of `curl_socket_t', as computed by sizeof. */
|
||||
${SIZEOF_CURL_SOCKET_T_CODE}
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
${SIZEOF_SIZE_T_CODE}
|
||||
|
||||
/* The size of `time_t', as computed by sizeof. */
|
||||
${SIZEOF_TIME_T_CODE}
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#cmakedefine STDC_HEADERS 1
|
||||
|
||||
/* Define if you want to enable c-ares support */
|
||||
#cmakedefine USE_ARES 1
|
||||
|
||||
/* Define if you want to enable POSIX threaded DNS lookup */
|
||||
#cmakedefine USE_THREADS_POSIX 1
|
||||
|
||||
/* Define if you want to enable Win32 threaded DNS lookup */
|
||||
#cmakedefine USE_THREADS_WIN32 1
|
||||
|
||||
/* if GnuTLS is enabled */
|
||||
#cmakedefine USE_GNUTLS 1
|
||||
|
||||
/* if SSL session export support is available */
|
||||
#cmakedefine USE_SSLS_EXPORT 1
|
||||
|
||||
/* if mbedTLS is enabled */
|
||||
#cmakedefine USE_MBEDTLS 1
|
||||
|
||||
/* if mbedTLS <4 has the mbedtls_des_crypt_ecb function. */
|
||||
#cmakedefine HAVE_MBEDTLS_DES_CRYPT_ECB 1
|
||||
|
||||
/* if Rustls is enabled */
|
||||
#cmakedefine USE_RUSTLS 1
|
||||
|
||||
/* 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_NEW 1
|
||||
|
||||
/* if wolfSSL has the wolfSSL_BIO_set_shutdown function. */
|
||||
#cmakedefine HAVE_WOLFSSL_BIO_SET_SHUTDOWN 1
|
||||
|
||||
/* if libssh is in use */
|
||||
#cmakedefine USE_LIBSSH 1
|
||||
|
||||
/* if libssh2 is in use */
|
||||
#cmakedefine USE_LIBSSH2 1
|
||||
|
||||
/* if libpsl is in use */
|
||||
#cmakedefine USE_LIBPSL 1
|
||||
|
||||
/* if you want to use OpenLDAP code instead of legacy ldap implementation */
|
||||
#cmakedefine USE_OPENLDAP 1
|
||||
|
||||
/* if OpenSSL is in use */
|
||||
#cmakedefine USE_OPENSSL 1
|
||||
|
||||
/* if AmiSSL is in use */
|
||||
#cmakedefine USE_AMISSL 1
|
||||
|
||||
/* if librtmp/rtmpdump is in use */
|
||||
#cmakedefine USE_LIBRTMP 1
|
||||
|
||||
/* if GSASL is in use */
|
||||
#cmakedefine USE_GSASL 1
|
||||
|
||||
/* if libuv is in use */
|
||||
#cmakedefine USE_LIBUV 1
|
||||
|
||||
/* Define to 1 if you have the <uv.h> header file. */
|
||||
#cmakedefine HAVE_UV_H 1
|
||||
|
||||
/* Define to 1 if you do not want the OpenSSL configuration to be loaded
|
||||
automatically */
|
||||
#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
|
||||
|
||||
/* to enable NGHTTP2 */
|
||||
#cmakedefine USE_NGHTTP2 1
|
||||
|
||||
/* to enable NGTCP2 */
|
||||
#cmakedefine USE_NGTCP2 1
|
||||
|
||||
/* to enable NGHTTP3 */
|
||||
#cmakedefine USE_NGHTTP3 1
|
||||
|
||||
/* to enable quiche */
|
||||
#cmakedefine USE_QUICHE 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* if Unix domain sockets are enabled */
|
||||
#cmakedefine USE_UNIX_SOCKETS 1
|
||||
|
||||
/* Define to 1 if you are building a Windows target with large file support. */
|
||||
#cmakedefine USE_WIN32_LARGE_FILES 1
|
||||
|
||||
/* to enable SSPI support */
|
||||
#cmakedefine USE_WINDOWS_SSPI 1
|
||||
|
||||
/* to enable Windows SSL */
|
||||
#cmakedefine USE_SCHANNEL 1
|
||||
|
||||
/* if Watt-32 is in use */
|
||||
#cmakedefine USE_WATT32 1
|
||||
|
||||
/* enable multiple SSL backends */
|
||||
#cmakedefine CURL_WITH_MULTI_SSL 1
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
|
||||
|
||||
/* the signed version of size_t */
|
||||
#cmakedefine ssize_t ${ssize_t}
|
||||
|
||||
/* Define to 1 if you have the mach_absolute_time function. */
|
||||
#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
|
||||
|
||||
/* to enable Windows IDN */
|
||||
#cmakedefine USE_WIN32_IDN 1
|
||||
|
||||
/* to enable Apple IDN */
|
||||
#cmakedefine USE_APPLE_IDN 1
|
||||
|
||||
/* to enable Apple OS-native certificate verification */
|
||||
#cmakedefine USE_APPLE_SECTRUST 1
|
||||
|
||||
/* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */
|
||||
#cmakedefine HAVE_OPENSSL_SRP 1
|
||||
|
||||
/* Define to 1 if GnuTLS has the gnutls_srp_verifier function. */
|
||||
#cmakedefine HAVE_GNUTLS_SRP 1
|
||||
|
||||
/* Define to 1 to enable TLS-SRP support. */
|
||||
#cmakedefine USE_TLS_SRP 1
|
||||
|
||||
/* Define to 1 to query for HTTPSRR when using DoH */
|
||||
#cmakedefine USE_HTTPSRR 1
|
||||
|
||||
/* if ECH support is available */
|
||||
#cmakedefine USE_ECH 1
|
||||
|
||||
/* Define to 1 if you have the wolfSSL_CTX_GenerateEchConfig function. */
|
||||
#cmakedefine HAVE_WOLFSSL_CTX_GENERATEECHCONFIG 1
|
||||
|
||||
/* Define to 1 if you have the SSL_set1_ech_config_list function. */
|
||||
#cmakedefine HAVE_SSL_SET1_ECH_CONFIG_LIST 1
|
||||
|
||||
/* Define to 1 if OpenSSL has the DES_ecb_encrypt function. */
|
||||
#cmakedefine HAVE_DES_ECB_ENCRYPT 1
|
||||
+944
@@ -0,0 +1,944 @@
|
||||
/* lib/curl_config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* !checksrc! disable COPYRIGHT all */
|
||||
|
||||
/* Location of default ca bundle */
|
||||
#undef CURL_CA_BUNDLE
|
||||
|
||||
/* define "1" to use OpenSSL's built-in CA store */
|
||||
#undef CURL_CA_FALLBACK
|
||||
|
||||
/* Location of default ca path */
|
||||
#undef CURL_CA_PATH
|
||||
|
||||
/* If safe CA bundle search is enabled */
|
||||
#undef CURL_CA_SEARCH_SAFE
|
||||
|
||||
/* Default SSL backend */
|
||||
#undef CURL_DEFAULT_SSL_BACKEND
|
||||
|
||||
/* disable alt-svc */
|
||||
#undef CURL_DISABLE_ALTSVC
|
||||
|
||||
/* to disable AWS sig support */
|
||||
#undef CURL_DISABLE_AWS
|
||||
|
||||
/* to disable basic authentication */
|
||||
#undef CURL_DISABLE_BASIC_AUTH
|
||||
|
||||
/* to disable bearer authentication */
|
||||
#undef CURL_DISABLE_BEARER_AUTH
|
||||
|
||||
/* disable local binding support */
|
||||
#undef CURL_DISABLE_BINDLOCAL
|
||||
|
||||
/* If unsafe CA bundle search in PATH on Windows is disabled */
|
||||
#undef CURL_DISABLE_CA_SEARCH
|
||||
|
||||
/* to disable cookies support */
|
||||
#undef CURL_DISABLE_COOKIES
|
||||
|
||||
/* to disable DICT */
|
||||
#undef CURL_DISABLE_DICT
|
||||
|
||||
/* to disable digest authentication */
|
||||
#undef CURL_DISABLE_DIGEST_AUTH
|
||||
|
||||
/* disable DoH */
|
||||
#undef CURL_DISABLE_DOH
|
||||
|
||||
/* to disable FILE */
|
||||
#undef CURL_DISABLE_FILE
|
||||
|
||||
/* disable form API */
|
||||
#undef CURL_DISABLE_FORM_API
|
||||
|
||||
/* to disable FTP */
|
||||
#undef CURL_DISABLE_FTP
|
||||
|
||||
/* to disable curl_easy_options */
|
||||
#undef CURL_DISABLE_GETOPTIONS
|
||||
|
||||
/* to disable Gopher */
|
||||
#undef CURL_DISABLE_GOPHER
|
||||
|
||||
/* disable headers-api */
|
||||
#undef CURL_DISABLE_HEADERS_API
|
||||
|
||||
/* disable alt-svc */
|
||||
#undef CURL_DISABLE_HSTS
|
||||
|
||||
/* to disable HTTP */
|
||||
#undef CURL_DISABLE_HTTP
|
||||
|
||||
/* disable HTTP authentication */
|
||||
#undef CURL_DISABLE_HTTP_AUTH
|
||||
|
||||
/* to disable IMAP */
|
||||
#undef CURL_DISABLE_IMAP
|
||||
|
||||
/* to disable IPFS */
|
||||
#undef CURL_DISABLE_IPFS
|
||||
|
||||
/* to disable kerberos authentication */
|
||||
#undef CURL_DISABLE_KERBEROS_AUTH
|
||||
|
||||
/* to disable LDAP */
|
||||
#undef CURL_DISABLE_LDAP
|
||||
|
||||
/* to disable LDAPS */
|
||||
#undef CURL_DISABLE_LDAPS
|
||||
|
||||
/* to disable --libcurl C code generation option */
|
||||
#undef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
/* disable mime API */
|
||||
#undef CURL_DISABLE_MIME
|
||||
|
||||
/* to disable MQTT */
|
||||
#undef CURL_DISABLE_MQTT
|
||||
|
||||
/* to disable negotiate authentication */
|
||||
#undef CURL_DISABLE_NEGOTIATE_AUTH
|
||||
|
||||
/* disable netrc parsing */
|
||||
#undef CURL_DISABLE_NETRC
|
||||
|
||||
/* to disable NTLM support */
|
||||
#undef CURL_DISABLE_NTLM
|
||||
|
||||
/* if the OpenSSL configuration won't be loaded automatically */
|
||||
#undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
|
||||
|
||||
/* disable date parsing */
|
||||
#undef CURL_DISABLE_PARSEDATE
|
||||
|
||||
/* to disable POP3 */
|
||||
#undef CURL_DISABLE_POP3
|
||||
|
||||
/* disable progress-meter */
|
||||
#undef CURL_DISABLE_PROGRESS_METER
|
||||
|
||||
/* to disable proxies */
|
||||
#undef CURL_DISABLE_PROXY
|
||||
|
||||
/* to disable RTSP */
|
||||
#undef CURL_DISABLE_RTSP
|
||||
|
||||
/* disable SHA-512/256 hash algorithm */
|
||||
#undef CURL_DISABLE_SHA512_256
|
||||
|
||||
/* disable DNS shuffling */
|
||||
#undef CURL_DISABLE_SHUFFLE_DNS
|
||||
|
||||
/* to disable SMB/CIFS */
|
||||
#undef CURL_DISABLE_SMB
|
||||
|
||||
/* to disable SMTP */
|
||||
#undef CURL_DISABLE_SMTP
|
||||
|
||||
/* to disable socketpair support */
|
||||
#undef CURL_DISABLE_SOCKETPAIR
|
||||
|
||||
/* to disable TELNET */
|
||||
#undef CURL_DISABLE_TELNET
|
||||
|
||||
/* to disable TFTP */
|
||||
#undef CURL_DISABLE_TFTP
|
||||
|
||||
/* to disable verbose strings */
|
||||
#undef CURL_DISABLE_VERBOSE_STRINGS
|
||||
|
||||
/* disable WebSockets */
|
||||
#undef CURL_DISABLE_WEBSOCKETS
|
||||
|
||||
/* Definition to make a library symbol externally visible. */
|
||||
#undef CURL_EXTERN_SYMBOL
|
||||
|
||||
/* MIT Kerberos version */
|
||||
#undef CURL_KRB5_VERSION
|
||||
|
||||
/* cpu-machine-OS */
|
||||
#undef CURL_OS
|
||||
|
||||
/* built with multiple SSL backends */
|
||||
#undef CURL_WITH_MULTI_SSL
|
||||
|
||||
/* Define to the type of arg 2 for gethostname. */
|
||||
#undef GETHOSTNAME_TYPE_ARG2
|
||||
|
||||
/* Define to 1 if you have the `accept4' function. */
|
||||
#undef HAVE_ACCEPT4
|
||||
|
||||
/* Define to 1 if you have the alarm function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have the `arc4random' function. */
|
||||
#undef HAVE_ARC4RANDOM
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have _Atomic support. */
|
||||
#undef HAVE_ATOMIC
|
||||
|
||||
/* Define to 1 if you have the basename function. */
|
||||
#undef HAVE_BASENAME
|
||||
|
||||
/* Define to 1 if bool is an available type. */
|
||||
#undef HAVE_BOOL_T
|
||||
|
||||
/* if BROTLI is in use */
|
||||
#undef HAVE_BROTLI
|
||||
|
||||
/* Define to 1 if you have the <brotli/decode.h> header file. */
|
||||
#undef HAVE_BROTLI_DECODE_H
|
||||
|
||||
/* Define to 1 if you have the __builtin_available function. */
|
||||
#undef HAVE_BUILTIN_AVAILABLE
|
||||
|
||||
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
|
||||
#undef HAVE_CLOCK_GETTIME_MONOTONIC
|
||||
|
||||
/* Define to 1 if you have the clock_gettime function and raw monotonic timer.
|
||||
*/
|
||||
#undef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
|
||||
|
||||
/* Define to 1 if you have the closesocket function. */
|
||||
#undef HAVE_CLOSESOCKET
|
||||
|
||||
/* Define to 1 if you have the CloseSocket camel case function. */
|
||||
#undef HAVE_CLOSESOCKET_CAMEL
|
||||
|
||||
/* Define to 1 if you have the fseeko declaration */
|
||||
#undef HAVE_DECL_FSEEKO
|
||||
|
||||
/* if you have the function DES_ecb_encrypt */
|
||||
#undef HAVE_DES_ECB_ENCRYPT
|
||||
|
||||
/* if you have <dirent.h> */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `eventfd' function. */
|
||||
#undef HAVE_EVENTFD
|
||||
|
||||
/* Define to 1 if you have the fcntl function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
|
||||
#undef HAVE_FCNTL_O_NONBLOCK
|
||||
|
||||
/* Define to 1 if you have the `fnmatch' function. */
|
||||
#undef HAVE_FNMATCH
|
||||
|
||||
/* Define to 1 if you have the freeaddrinfo function. */
|
||||
#undef HAVE_FREEADDRINFO
|
||||
|
||||
/* Define to 1 if you have the `fseeko' function. */
|
||||
#undef HAVE_FSEEKO
|
||||
|
||||
/* Define to 1 if you have the fsetxattr function. */
|
||||
#undef HAVE_FSETXATTR
|
||||
|
||||
/* fsetxattr() takes 5 args */
|
||||
#undef HAVE_FSETXATTR_5
|
||||
|
||||
/* fsetxattr() takes 6 args */
|
||||
#undef HAVE_FSETXATTR_6
|
||||
|
||||
/* Define to 1 if you have the ftruncate function. */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* Define to 1 if you have a working getaddrinfo function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if the getaddrinfo function is threadsafe. */
|
||||
#undef HAVE_GETADDRINFO_THREADSAFE
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define to 1 if you have the gethostbyname_r function. */
|
||||
#undef HAVE_GETHOSTBYNAME_R
|
||||
|
||||
/* gethostbyname_r() takes 3 args */
|
||||
#undef HAVE_GETHOSTBYNAME_R_3
|
||||
|
||||
/* gethostbyname_r() takes 5 args */
|
||||
#undef HAVE_GETHOSTBYNAME_R_5
|
||||
|
||||
/* gethostbyname_r() takes 6 args */
|
||||
#undef HAVE_GETHOSTBYNAME_R_6
|
||||
|
||||
/* Define to 1 if you have the gethostname function. */
|
||||
#undef HAVE_GETHOSTNAME
|
||||
|
||||
/* Define to 1 if you have a working getifaddrs function. */
|
||||
#undef HAVE_GETIFADDRS
|
||||
|
||||
/* Define to 1 if you have the `getpass_r' function. */
|
||||
#undef HAVE_GETPASS_R
|
||||
|
||||
/* Define to 1 if you have the getpeername function. */
|
||||
#undef HAVE_GETPEERNAME
|
||||
|
||||
/* Define to 1 if you have the `getppid' function. */
|
||||
#undef HAVE_GETPPID
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define to 1 if you have the `getpwuid_r' function. */
|
||||
#undef HAVE_GETPWUID_R
|
||||
|
||||
/* Define to 1 if you have the `getrlimit' function. */
|
||||
#undef HAVE_GETRLIMIT
|
||||
|
||||
/* Define to 1 if you have the getsockname function. */
|
||||
#undef HAVE_GETSOCKNAME
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have a working glibc-style strerror_r function. */
|
||||
#undef HAVE_GLIBC_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have a working gmtime_r function. */
|
||||
#undef HAVE_GMTIME_R
|
||||
|
||||
/* if you have the function gnutls_srp_verifier */
|
||||
#undef HAVE_GNUTLS_SRP
|
||||
|
||||
/* Define to 1 if you have the <gsasl.h> header file. */
|
||||
#undef HAVE_GSASL_H
|
||||
|
||||
/* if you have GSS-API libraries */
|
||||
#undef HAVE_GSSAPI
|
||||
|
||||
/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
|
||||
#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
|
||||
|
||||
/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
|
||||
#undef HAVE_GSSAPI_GSSAPI_H
|
||||
|
||||
/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
|
||||
#undef HAVE_GSSAPI_GSSAPI_KRB5_H
|
||||
|
||||
/* if you have GNU GSS */
|
||||
#undef HAVE_GSSGNU
|
||||
|
||||
/* Define to 1 if you have the <idn2.h> header file. */
|
||||
#undef HAVE_IDN2_H
|
||||
|
||||
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||
#undef HAVE_IFADDRS_H
|
||||
|
||||
/* Define to 1 if you have the `if_nametoindex' function. */
|
||||
#undef HAVE_IF_NAMETOINDEX
|
||||
|
||||
/* Define to 1 if you have an IPv6 capable working inet_ntop function. */
|
||||
#undef HAVE_INET_NTOP
|
||||
|
||||
/* Define to 1 if you have an IPv6 capable working inet_pton function. */
|
||||
#undef HAVE_INET_PTON
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the ioctlsocket function. */
|
||||
#undef HAVE_IOCTLSOCKET
|
||||
|
||||
/* Define to 1 if you have the IoctlSocket camel case function. */
|
||||
#undef HAVE_IOCTLSOCKET_CAMEL
|
||||
|
||||
/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
|
||||
*/
|
||||
#undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
|
||||
|
||||
/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
|
||||
#undef HAVE_IOCTLSOCKET_FIONBIO
|
||||
|
||||
/* Define to 1 if you have a working ioctl FIONBIO function. */
|
||||
#undef HAVE_IOCTL_FIONBIO
|
||||
|
||||
/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
|
||||
#undef HAVE_IOCTL_SIOCGIFADDR
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#undef HAVE_IO_H
|
||||
|
||||
/* Define to 1 if you have the lber.h header file. */
|
||||
#undef HAVE_LBER_H
|
||||
|
||||
/* Define to 1 if you have the ldap.h header file. */
|
||||
#undef HAVE_LDAP_H
|
||||
|
||||
/* Define to 1 if you have the `ldap_init_fd' function. */
|
||||
#undef HAVE_LDAP_INIT_FD
|
||||
|
||||
/* Use LDAPS implementation */
|
||||
#undef HAVE_LDAP_SSL
|
||||
|
||||
/* Define to 1 if you have the ldap_ssl.h header file. */
|
||||
#undef HAVE_LDAP_SSL_H
|
||||
|
||||
/* Define to 1 if you have the `ldap_url_parse' function. */
|
||||
#undef HAVE_LDAP_URL_PARSE
|
||||
|
||||
/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */
|
||||
#undef HAVE_LIBBROTLIDEC
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#undef HAVE_LIBGEN_H
|
||||
|
||||
/* Define to 1 if you have the `idn2' library (-lidn2). */
|
||||
#undef HAVE_LIBIDN2
|
||||
|
||||
/* Define to 1 if you have the <libpsl.h> header file. */
|
||||
#undef HAVE_LIBPSL_H
|
||||
|
||||
/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
|
||||
#undef HAVE_LIBRTMP_RTMP_H
|
||||
|
||||
/* Define to 1 if you have the `ssh' library (-lssh). */
|
||||
#undef HAVE_LIBSSH
|
||||
|
||||
/* Define to 1 if you have the `ssh2' library (-lssh2). */
|
||||
#undef HAVE_LIBSSH2
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
#undef HAVE_LIBSSL
|
||||
|
||||
/* if zlib is available */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if you have the `zstd' library (-lzstd). */
|
||||
#undef HAVE_LIBZSTD
|
||||
|
||||
/* Define to 1 if you have the <linux/tcp.h> header file. */
|
||||
#undef HAVE_LINUX_TCP_H
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if the compiler supports the 'long long' data type. */
|
||||
#undef HAVE_LONGLONG
|
||||
|
||||
/* Define to 1 if you have the `mach_absolute_time' function. */
|
||||
#undef HAVE_MACH_ABSOLUTE_TIME
|
||||
|
||||
/* Define to 1 if you have the `mbedtls_des_crypt_ecb' function. */
|
||||
#undef HAVE_MBEDTLS_DES_CRYPT_ECB
|
||||
|
||||
/* Define to 1 if you have the memrchr function or macro. */
|
||||
#undef HAVE_MEMRCHR
|
||||
|
||||
/* Define to 1 if you have the MSG_NOSIGNAL flag. */
|
||||
#undef HAVE_MSG_NOSIGNAL
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in6.h> header file. */
|
||||
#undef HAVE_NETINET_IN6_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#undef HAVE_NETINET_TCP_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/udp.h> header file. */
|
||||
#undef HAVE_NETINET_UDP_H
|
||||
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#undef HAVE_NET_IF_H
|
||||
|
||||
/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
|
||||
#undef HAVE_NGHTTP2_NGHTTP2_H
|
||||
|
||||
/* Define to 1 if you have the <nghttp3/nghttp3.h> header file. */
|
||||
#undef HAVE_NGHTTP3_NGHTTP3_H
|
||||
|
||||
/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto.h> header file. */
|
||||
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_H
|
||||
|
||||
/* Define to 1 if you have the <ngtcp2/ngtcp2.h> header file. */
|
||||
#undef HAVE_NGTCP2_NGTCP2_H
|
||||
|
||||
/* if you have opendir */
|
||||
#undef HAVE_OPENDIR
|
||||
|
||||
/* Define to 1 if you have the <openssl/crypto.h> header file. */
|
||||
#undef HAVE_OPENSSL_CRYPTO_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/err.h> header file. */
|
||||
#undef HAVE_OPENSSL_ERR_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/pem.h> header file. */
|
||||
#undef HAVE_OPENSSL_PEM_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/rsa.h> header file. */
|
||||
#undef HAVE_OPENSSL_RSA_H
|
||||
|
||||
/* if you have the functions SSL_CTX_set_srp_username and
|
||||
SSL_CTX_set_srp_password */
|
||||
#undef HAVE_OPENSSL_SRP
|
||||
|
||||
/* Define to 1 if you have the <openssl/ssl.h> header file. */
|
||||
#undef HAVE_OPENSSL_SSL_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/x509.h> header file. */
|
||||
#undef HAVE_OPENSSL_X509_H
|
||||
|
||||
/* Define to 1 if you have the `pipe' function. */
|
||||
#undef HAVE_PIPE
|
||||
|
||||
/* Define to 1 if you have the `pipe2' function. */
|
||||
#undef HAVE_PIPE2
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#undef HAVE_POLL_H
|
||||
|
||||
/* Define to 1 if you have a working POSIX-style strerror_r function. */
|
||||
#undef HAVE_POSIX_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <proto/bsdsocket.h> header file. */
|
||||
#undef HAVE_PROTO_BSDSOCKET_H
|
||||
|
||||
/* if you have <pthread.h> */
|
||||
#undef HAVE_PTHREAD_H
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define to 1 if you have the `quiche_conn_set_qlog_fd' function. */
|
||||
#undef HAVE_QUICHE_CONN_SET_QLOG_FD
|
||||
|
||||
/* Define to 1 if you have the <quiche.h> header file. */
|
||||
#undef HAVE_QUICHE_H
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
/* Define to 1 if you have the recv function. */
|
||||
#undef HAVE_RECV
|
||||
|
||||
/* Define to 1 if symbol `sa_family_t' exists */
|
||||
#undef HAVE_SA_FAMILY_T
|
||||
|
||||
/* Define to 1 if you have the `sched_yield' function. */
|
||||
#undef HAVE_SCHED_YIELD
|
||||
|
||||
/* Define to 1 if you have the select function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define to 1 if you have the send function. */
|
||||
#undef HAVE_SEND
|
||||
|
||||
/* Define to 1 if you have the `sendmmsg' function. */
|
||||
#undef HAVE_SENDMMSG
|
||||
|
||||
/* Define to 1 if you have the `sendmsg' function. */
|
||||
#undef HAVE_SENDMSG
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* Define to 1 if you have the `setmode' function. */
|
||||
#undef HAVE_SETMODE
|
||||
|
||||
/* Define to 1 if you have the `setrlimit' function. */
|
||||
#undef HAVE_SETRLIMIT
|
||||
|
||||
/* Define to 1 if you have the sigaction function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the siginterrupt function. */
|
||||
#undef HAVE_SIGINTERRUPT
|
||||
|
||||
/* Define to 1 if you have the signal function. */
|
||||
#undef HAVE_SIGNAL
|
||||
|
||||
/* Define to 1 if you have the sigsetjmp function or macro. */
|
||||
#undef HAVE_SIGSETJMP
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
|
||||
#undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
|
||||
/* Define to 1 if you have the socket function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the socketpair function. */
|
||||
#undef HAVE_SOCKETPAIR
|
||||
|
||||
/* Define to 1 if you have the `SSL_set0_wbio' function. */
|
||||
#undef HAVE_SSL_SET0_WBIO
|
||||
|
||||
/* Define to 1 if you have the `SSL_set1_ech_config_list' function. */
|
||||
#undef HAVE_SSL_SET1_ECH_CONFIG_LIST
|
||||
|
||||
/* Define to 1 if you have the `SSL_set_quic_tls_cbs' function. */
|
||||
#undef HAVE_SSL_SET_QUIC_TLS_CBS
|
||||
|
||||
/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function.
|
||||
*/
|
||||
#undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT
|
||||
|
||||
/* Define to 1 if you have the <stdatomic.h> header file. */
|
||||
#undef HAVE_STDATOMIC_H
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the strcasecmp function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the strcmpi function. */
|
||||
#undef HAVE_STRCMPI
|
||||
|
||||
/* Define to 1 if you have the strdup function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the strerror_r function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the stricmp function. */
|
||||
#undef HAVE_STRICMP
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <stropts.h> header file. */
|
||||
#undef HAVE_STROPTS_H
|
||||
|
||||
/* if struct sockaddr_storage is defined */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
|
||||
/* Define to 1 if you have the timeval struct. */
|
||||
#undef HAVE_STRUCT_TIMEVAL
|
||||
|
||||
/* Define to 1 if suseconds_t is an available type. */
|
||||
#undef HAVE_SUSECONDS_T
|
||||
|
||||
/* Define to 1 if you have the <sys/eventfd.h> header file. */
|
||||
#undef HAVE_SYS_EVENTFD_H
|
||||
|
||||
/* Define to 1 if you have the <sys/filio.h> header file. */
|
||||
#undef HAVE_SYS_FILIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/poll.h> header file. */
|
||||
#undef HAVE_SYS_POLL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
||||
#undef HAVE_SYS_UN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utime.h> header file. */
|
||||
#undef HAVE_SYS_UTIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/xattr.h> header file. */
|
||||
#undef HAVE_SYS_XATTR_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <termio.h> header file. */
|
||||
#undef HAVE_TERMIO_H
|
||||
|
||||
/* Define this if time_t is unsigned */
|
||||
#undef HAVE_TIME_T_UNSIGNED
|
||||
|
||||
/* Define to 1 if you have the <unicode/uidna.h> header file. */
|
||||
#undef HAVE_UNICODE_UIDNA_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `utime' function. */
|
||||
#undef HAVE_UTIME
|
||||
|
||||
/* Define to 1 if you have the `utimes' function. */
|
||||
#undef HAVE_UTIMES
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
|
||||
/* Define to 1 if you have the <uv.h> header file. */
|
||||
#undef HAVE_UV_H
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_BIO_new' function. */
|
||||
#undef HAVE_WOLFSSL_BIO_NEW
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_BIO_set_shutdown' function. */
|
||||
#undef HAVE_WOLFSSL_BIO_SET_SHUTDOWN
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_CTX_GenerateEchConfig' function. */
|
||||
#undef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_DES_ecb_encrypt' function. */
|
||||
#undef HAVE_WOLFSSL_DES_ECB_ENCRYPT
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */
|
||||
#undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_set_quic_use_legacy_codepoint'
|
||||
function. */
|
||||
#undef HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT
|
||||
|
||||
/* Define to 1 if you have the `wolfSSL_UseALPN' function. */
|
||||
#undef HAVE_WOLFSSL_USEALPN
|
||||
|
||||
/* Define this symbol if your OS supports changing the contents of argv */
|
||||
#undef HAVE_WRITABLE_ARGV
|
||||
|
||||
/* if libzstd is in use */
|
||||
#undef HAVE_ZSTD
|
||||
|
||||
/* Define to 1 if you have the <zstd.h> header file. */
|
||||
#undef HAVE_ZSTD_H
|
||||
|
||||
/* Define to 1 if you have the `_setmode' function. */
|
||||
#undef HAVE__SETMODE
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to 1 if you need the lber.h header file even with ldap.h */
|
||||
#undef NEED_LBER_H
|
||||
|
||||
/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
|
||||
#undef NEED_REENTRANT
|
||||
|
||||
/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
|
||||
#undef NEED_THREAD_SAFE
|
||||
|
||||
/* openssl with new QUIC API */
|
||||
#undef OPENSSL_QUIC_API2
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Size of curl_off_t in number of bytes */
|
||||
#undef SIZEOF_CURL_OFF_T
|
||||
|
||||
/* Size of curl_socket_t in number of bytes */
|
||||
#undef SIZEOF_CURL_SOCKET_T
|
||||
|
||||
/* Size of int in number of bytes */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* Size of long in number of bytes */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* Size of long long in number of bytes */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* Size of off_t in number of bytes */
|
||||
#undef SIZEOF_OFF_T
|
||||
|
||||
/* Size of size_t in number of bytes */
|
||||
#undef SIZEOF_SIZE_T
|
||||
|
||||
/* Size of time_t in number of bytes */
|
||||
#undef SIZEOF_TIME_T
|
||||
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* if AmiSSL is in use */
|
||||
#undef USE_AMISSL
|
||||
|
||||
/* if AppleIDN */
|
||||
#undef USE_APPLE_IDN
|
||||
|
||||
/* enable Apple OS certificate validation */
|
||||
#undef USE_APPLE_SECTRUST
|
||||
|
||||
/* Define to enable c-ares support */
|
||||
#undef USE_ARES
|
||||
|
||||
/* if ECH support is available */
|
||||
#undef USE_ECH
|
||||
|
||||
/* if GnuTLS is enabled */
|
||||
#undef USE_GNUTLS
|
||||
|
||||
/* GSASL support enabled */
|
||||
#undef USE_GSASL
|
||||
|
||||
/* enable HTTPS RR support */
|
||||
#undef USE_HTTPSRR
|
||||
|
||||
/* Define if you want to enable IPv6 support */
|
||||
#undef USE_IPV6
|
||||
|
||||
/* if libpsl is in use */
|
||||
#undef USE_LIBPSL
|
||||
|
||||
/* if librtmp is in use */
|
||||
#undef USE_LIBRTMP
|
||||
|
||||
/* if libssh is in use */
|
||||
#undef USE_LIBSSH
|
||||
|
||||
/* if libssh2 is in use */
|
||||
#undef USE_LIBSSH2
|
||||
|
||||
/* if libuv is in use */
|
||||
#undef USE_LIBUV
|
||||
|
||||
/* if mbedTLS is enabled */
|
||||
#undef USE_MBEDTLS
|
||||
|
||||
/* if nghttp2 is in use */
|
||||
#undef USE_NGHTTP2
|
||||
|
||||
/* if nghttp3 is in use */
|
||||
#undef USE_NGHTTP3
|
||||
|
||||
/* if ngtcp2 is in use */
|
||||
#undef USE_NGTCP2
|
||||
|
||||
/* Use OpenLDAP-specific code */
|
||||
#undef USE_OPENLDAP
|
||||
|
||||
/* if OpenSSL is in use */
|
||||
#undef USE_OPENSSL
|
||||
|
||||
/* if openssl QUIC is in use */
|
||||
#undef USE_OPENSSL_QUIC
|
||||
|
||||
/* if quiche is in use */
|
||||
#undef USE_QUICHE
|
||||
|
||||
/* if Rustls is enabled */
|
||||
#undef USE_RUSTLS
|
||||
|
||||
/* to enable Windows native SSL/TLS support */
|
||||
#undef USE_SCHANNEL
|
||||
|
||||
/* if SSL session export support is available */
|
||||
#undef USE_SSLS_EXPORT
|
||||
|
||||
/* if you want POSIX threaded DNS lookup */
|
||||
#undef USE_THREADS_POSIX
|
||||
|
||||
/* if you want Win32 threaded DNS lookup */
|
||||
#undef USE_THREADS_WIN32
|
||||
|
||||
/* Use TLS-SRP authentication */
|
||||
#undef USE_TLS_SRP
|
||||
|
||||
/* Use Unix domain sockets */
|
||||
#undef USE_UNIX_SOCKETS
|
||||
|
||||
/* if Watt-32 is in use */
|
||||
#undef USE_WATT32
|
||||
|
||||
/* Define to 1 if you are building a Windows target with crypto API support.
|
||||
*/
|
||||
#undef USE_WIN32_CRYPTO
|
||||
|
||||
/* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */
|
||||
#undef USE_WIN32_IDN
|
||||
|
||||
/* Define to 1 if you are building a Windows target with large file support.
|
||||
*/
|
||||
#undef USE_WIN32_LARGE_FILES
|
||||
|
||||
/* Use Windows LDAP implementation */
|
||||
#undef USE_WIN32_LDAP
|
||||
|
||||
/* to enable SSPI support */
|
||||
#undef USE_WINDOWS_SSPI
|
||||
|
||||
/* if wolfSSL is enabled */
|
||||
#undef USE_WOLFSSL
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to 1 if OS is AIX. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* the signed version of size_t */
|
||||
#undef ssize_t
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#ifndef HEADER_CURL_CTYPE_H
|
||||
#define HEADER_CURL_CTYPE_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define ISLOWHEXALHA(x) (((x) >= 'a') && ((x) <= 'f'))
|
||||
#define ISUPHEXALHA(x) (((x) >= 'A') && ((x) <= 'F'))
|
||||
|
||||
#define ISLOWCNTRL(x) ((unsigned char)(x) <= 0x1f)
|
||||
#define IS7F(x) ((x) == 0x7f)
|
||||
|
||||
#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d))
|
||||
|
||||
#define ISPRINT(x) (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e)))
|
||||
#define ISGRAPH(x) (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e)))
|
||||
#define 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'))
|
||||
#define ISDIGIT(x) (((x) >= '0') && ((x) <= '9'))
|
||||
#define ISBLANK(x) (((x) == ' ') || ((x) == '\t'))
|
||||
#define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d)))
|
||||
#define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \
|
||||
((x) == '~'))
|
||||
#define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x))
|
||||
#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
|
||||
|
||||
#endif /* HEADER_CURL_CTYPE_H */
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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_endian.h"
|
||||
|
||||
/*
|
||||
* Curl_read16_le()
|
||||
*
|
||||
* This function converts a 16-bit integer from the little endian format, as
|
||||
* used in the incoming package to whatever endian format we are using
|
||||
* natively.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* buf [in] - A pointer to a 2 byte buffer.
|
||||
*
|
||||
* Returns the integer.
|
||||
*/
|
||||
unsigned short Curl_read16_le(const unsigned char *buf)
|
||||
{
|
||||
return (unsigned short)(((unsigned short)buf[0]) |
|
||||
((unsigned short)buf[1] << 8));
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_read32_le()
|
||||
*
|
||||
* This function converts a 32-bit integer from the little endian format, as
|
||||
* used in the incoming package to whatever endian format we are using
|
||||
* natively.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* buf [in] - A pointer to a 4 byte buffer.
|
||||
*
|
||||
* Returns the integer.
|
||||
*/
|
||||
unsigned int Curl_read32_le(const unsigned char *buf)
|
||||
{
|
||||
return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
|
||||
((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_read16_be()
|
||||
*
|
||||
* This function converts a 16-bit integer from the big endian format, as
|
||||
* used in the incoming package to whatever endian format we are using
|
||||
* natively.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* buf [in] - A pointer to a 2 byte buffer.
|
||||
*
|
||||
* Returns the integer.
|
||||
*/
|
||||
unsigned short Curl_read16_be(const unsigned char *buf)
|
||||
{
|
||||
return (unsigned short)(((unsigned short)buf[0] << 8) |
|
||||
((unsigned short)buf[1]));
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_ENDIAN_H
|
||||
#define HEADER_CURL_ENDIAN_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Converts a 16-bit integer from little endian */
|
||||
unsigned short Curl_read16_le(const unsigned char *buf);
|
||||
|
||||
/* Converts a 32-bit integer from little endian */
|
||||
unsigned int Curl_read32_le(const unsigned char *buf);
|
||||
|
||||
/* Converts a 16-bit integer from big endian */
|
||||
unsigned short Curl_read16_be(const unsigned char *buf);
|
||||
|
||||
#endif /* HEADER_CURL_ENDIAN_H */
|
||||
+390
@@ -0,0 +1,390 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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"
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "curl_fnmatch.h"
|
||||
#include "curl_memory.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifndef HAVE_FNMATCH
|
||||
|
||||
#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
|
||||
#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
|
||||
|
||||
#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
|
||||
|
||||
#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
|
||||
#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
|
||||
#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
|
||||
#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
|
||||
#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
|
||||
#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
|
||||
#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
|
||||
#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
|
||||
#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
|
||||
#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
|
||||
|
||||
typedef enum {
|
||||
CURLFNM_SCHS_DEFAULT = 0,
|
||||
CURLFNM_SCHS_RIGHTBR,
|
||||
CURLFNM_SCHS_RIGHTBRLEFTBR
|
||||
} setcharset_state;
|
||||
|
||||
typedef enum {
|
||||
CURLFNM_PKW_INIT = 0,
|
||||
CURLFNM_PKW_DDOT
|
||||
} parsekey_state;
|
||||
|
||||
typedef enum {
|
||||
CCLASS_OTHER = 0,
|
||||
CCLASS_DIGIT,
|
||||
CCLASS_UPPER,
|
||||
CCLASS_LOWER
|
||||
} char_class;
|
||||
|
||||
#define SETCHARSET_OK 1
|
||||
#define SETCHARSET_FAIL 0
|
||||
|
||||
static int parsekeyword(const unsigned char **pattern, unsigned char *charset)
|
||||
{
|
||||
parsekey_state state = CURLFNM_PKW_INIT;
|
||||
char keyword[10] = { 0 };
|
||||
size_t i;
|
||||
const unsigned char *p = *pattern;
|
||||
bool found = FALSE;
|
||||
for(i = 0; !found; i++) {
|
||||
char c = (char)*p++;
|
||||
if(i >= sizeof(keyword))
|
||||
return SETCHARSET_FAIL;
|
||||
switch(state) {
|
||||
case CURLFNM_PKW_INIT:
|
||||
if(ISLOWER(c))
|
||||
keyword[i] = c;
|
||||
else if(c == ':')
|
||||
state = CURLFNM_PKW_DDOT;
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
break;
|
||||
case CURLFNM_PKW_DDOT:
|
||||
if(c == ']')
|
||||
found = TRUE;
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
}
|
||||
#undef KEYLEN
|
||||
|
||||
*pattern = p; /* move caller's pattern pointer */
|
||||
if(strcmp(keyword, "digit") == 0)
|
||||
charset[CURLFNM_DIGIT] = 1;
|
||||
else if(strcmp(keyword, "alnum") == 0)
|
||||
charset[CURLFNM_ALNUM] = 1;
|
||||
else if(strcmp(keyword, "alpha") == 0)
|
||||
charset[CURLFNM_ALPHA] = 1;
|
||||
else if(strcmp(keyword, "xdigit") == 0)
|
||||
charset[CURLFNM_XDIGIT] = 1;
|
||||
else if(strcmp(keyword, "print") == 0)
|
||||
charset[CURLFNM_PRINT] = 1;
|
||||
else if(strcmp(keyword, "graph") == 0)
|
||||
charset[CURLFNM_GRAPH] = 1;
|
||||
else if(strcmp(keyword, "space") == 0)
|
||||
charset[CURLFNM_SPACE] = 1;
|
||||
else if(strcmp(keyword, "blank") == 0)
|
||||
charset[CURLFNM_BLANK] = 1;
|
||||
else if(strcmp(keyword, "upper") == 0)
|
||||
charset[CURLFNM_UPPER] = 1;
|
||||
else if(strcmp(keyword, "lower") == 0)
|
||||
charset[CURLFNM_LOWER] = 1;
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
|
||||
/* Return the character class. */
|
||||
static char_class charclass(unsigned char c)
|
||||
{
|
||||
if(ISUPPER(c))
|
||||
return CCLASS_UPPER;
|
||||
if(ISLOWER(c))
|
||||
return CCLASS_LOWER;
|
||||
if(ISDIGIT(c))
|
||||
return CCLASS_DIGIT;
|
||||
return CCLASS_OTHER;
|
||||
}
|
||||
|
||||
/* Include a character or a range in set. */
|
||||
static void setcharorrange(const unsigned char **pp, unsigned char *charset)
|
||||
{
|
||||
const unsigned char *p = (*pp)++;
|
||||
unsigned char c = *p++;
|
||||
|
||||
charset[c] = 1;
|
||||
if(ISALNUM(c) && *p++ == '-') {
|
||||
char_class cc = charclass(c);
|
||||
unsigned char endrange = *p++;
|
||||
|
||||
if(endrange == '\\')
|
||||
endrange = *p++;
|
||||
if(endrange >= c && charclass(endrange) == cc) {
|
||||
while(c++ != endrange)
|
||||
if(charclass(c) == cc) /* Chars in class may be not consecutive. */
|
||||
charset[c] = 1;
|
||||
*pp = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* returns 1 (TRUE) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
|
||||
static int setcharset(const unsigned char **p, unsigned char *charset)
|
||||
{
|
||||
setcharset_state state = CURLFNM_SCHS_DEFAULT;
|
||||
bool something_found = FALSE;
|
||||
unsigned char c;
|
||||
|
||||
memset(charset, 0, CURLFNM_CHSET_SIZE);
|
||||
for(;;) {
|
||||
c = **p;
|
||||
if(!c)
|
||||
return SETCHARSET_FAIL;
|
||||
|
||||
switch(state) {
|
||||
case CURLFNM_SCHS_DEFAULT:
|
||||
if(c == ']') {
|
||||
if(something_found)
|
||||
return SETCHARSET_OK;
|
||||
something_found = TRUE;
|
||||
state = CURLFNM_SCHS_RIGHTBR;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == '[') {
|
||||
const unsigned char *pp = *p + 1;
|
||||
|
||||
if(*pp++ == ':' && parsekeyword(&pp, charset))
|
||||
*p = pp;
|
||||
else {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
something_found = TRUE;
|
||||
}
|
||||
else if(c == '^' || c == '!') {
|
||||
if(!something_found) {
|
||||
if(charset[CURLFNM_NEGATE]) {
|
||||
charset[c] = 1;
|
||||
something_found = TRUE;
|
||||
}
|
||||
else
|
||||
charset[CURLFNM_NEGATE] = 1; /* negate charset */
|
||||
}
|
||||
else
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == '\\') {
|
||||
c = *(++(*p));
|
||||
if(c)
|
||||
setcharorrange(p, charset);
|
||||
else
|
||||
charset['\\'] = 1;
|
||||
something_found = TRUE;
|
||||
}
|
||||
else {
|
||||
setcharorrange(p, charset);
|
||||
something_found = TRUE;
|
||||
}
|
||||
break;
|
||||
case CURLFNM_SCHS_RIGHTBR:
|
||||
if(c == '[') {
|
||||
state = CURLFNM_SCHS_RIGHTBRLEFTBR;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == ']') {
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
else if(ISPRINT(c)) {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
}
|
||||
else
|
||||
/* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
|
||||
* nonsense warning 'statement not reached' at end of the fnc when
|
||||
* compiling on Solaris */
|
||||
goto fail;
|
||||
break;
|
||||
case CURLFNM_SCHS_RIGHTBRLEFTBR:
|
||||
if(c == ']')
|
||||
return SETCHARSET_OK;
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
|
||||
static int loop(const unsigned char *pattern, const unsigned char *string,
|
||||
int maxstars)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)pattern;
|
||||
const unsigned char *s = (const unsigned char *)string;
|
||||
unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
|
||||
|
||||
for(;;) {
|
||||
const unsigned char *pp;
|
||||
|
||||
switch(*p) {
|
||||
case '*':
|
||||
if(!maxstars)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
/* Regroup consecutive stars and question marks. This can be done because
|
||||
'*?*?*' can be expressed as '??*'. */
|
||||
for(;;) {
|
||||
if(*++p == '\0')
|
||||
return CURL_FNMATCH_MATCH;
|
||||
if(*p == '?') {
|
||||
if(!*s++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
}
|
||||
else if(*p != '*')
|
||||
break;
|
||||
}
|
||||
/* Skip string characters until we find a match with pattern suffix. */
|
||||
for(maxstars--; *s; s++) {
|
||||
if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
|
||||
return CURL_FNMATCH_MATCH;
|
||||
}
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
case '?':
|
||||
if(!*s)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
s++;
|
||||
p++;
|
||||
break;
|
||||
case '\0':
|
||||
return *s ? CURL_FNMATCH_NOMATCH : CURL_FNMATCH_MATCH;
|
||||
case '\\':
|
||||
if(p[1])
|
||||
p++;
|
||||
if(*s++ != *p++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
break;
|
||||
case '[':
|
||||
pp = p + 1; /* Copy in case of syntax error in set. */
|
||||
if(setcharset(&pp, charset)) {
|
||||
bool found = FALSE;
|
||||
if(!*s)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
if(charset[(unsigned int)*s])
|
||||
found = TRUE;
|
||||
else if(charset[CURLFNM_ALNUM])
|
||||
found = ISALNUM(*s);
|
||||
else if(charset[CURLFNM_ALPHA])
|
||||
found = ISALPHA(*s);
|
||||
else if(charset[CURLFNM_DIGIT])
|
||||
found = ISDIGIT(*s);
|
||||
else if(charset[CURLFNM_XDIGIT])
|
||||
found = ISXDIGIT(*s);
|
||||
else if(charset[CURLFNM_PRINT])
|
||||
found = ISPRINT(*s);
|
||||
else if(charset[CURLFNM_SPACE])
|
||||
found = ISBLANK(*s);
|
||||
else if(charset[CURLFNM_UPPER])
|
||||
found = ISUPPER(*s);
|
||||
else if(charset[CURLFNM_LOWER])
|
||||
found = ISLOWER(*s);
|
||||
else if(charset[CURLFNM_BLANK])
|
||||
found = ISBLANK(*s);
|
||||
else if(charset[CURLFNM_GRAPH])
|
||||
found = ISGRAPH(*s);
|
||||
|
||||
if(charset[CURLFNM_NEGATE])
|
||||
found = !found;
|
||||
|
||||
if(!found)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
p = pp + 1;
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
/* Syntax error in set; mismatch! */
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
|
||||
default:
|
||||
if(*p++ != *s++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @unittest: 1307
|
||||
*/
|
||||
int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
|
||||
{
|
||||
(void)ptr; /* the argument is specified by the curl_fnmatch_callback
|
||||
prototype, but not used by Curl_fnmatch() */
|
||||
if(!pattern || !string) {
|
||||
return CURL_FNMATCH_FAIL;
|
||||
}
|
||||
return loop((const unsigned char *)pattern,
|
||||
(const unsigned char *)string, 2);
|
||||
}
|
||||
#else
|
||||
#include <fnmatch.h>
|
||||
/*
|
||||
* @unittest: 1307
|
||||
*/
|
||||
int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
|
||||
{
|
||||
(void)ptr; /* the argument is specified by the curl_fnmatch_callback
|
||||
prototype, but not used by Curl_fnmatch() */
|
||||
if(!pattern || !string) {
|
||||
return CURL_FNMATCH_FAIL;
|
||||
}
|
||||
|
||||
switch(fnmatch(pattern, string, 0)) {
|
||||
case 0:
|
||||
return CURL_FNMATCH_MATCH;
|
||||
case FNM_NOMATCH:
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
default:
|
||||
return CURL_FNMATCH_FAIL;
|
||||
}
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* if FTP is disabled */
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
#ifndef HEADER_CURL_FNMATCH_H
|
||||
#define HEADER_CURL_FNMATCH_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define CURL_FNMATCH_MATCH 0
|
||||
#define CURL_FNMATCH_NOMATCH 1
|
||||
#define CURL_FNMATCH_FAIL 2
|
||||
|
||||
/* default pattern matching function
|
||||
* =================================
|
||||
* Implemented with recursive backtracking, if you want to use Curl_fnmatch,
|
||||
* please note that there is not implemented UTF/Unicode support.
|
||||
*
|
||||
* Implemented features:
|
||||
* '?' notation, does not match UTF characters
|
||||
* '*' can also work with UTF string
|
||||
* [a-zA-Z0-9] enumeration support
|
||||
*
|
||||
* keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space
|
||||
* and upper (use as "[[:alnum:]]")
|
||||
*/
|
||||
int Curl_fnmatch(void *ptr, const char *pattern, const char *string);
|
||||
|
||||
#endif /* HEADER_CURL_FNMATCH_H */
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \
|
||||
!defined(CURL_DISABLE_HSTS)
|
||||
|
||||
#include "urldata.h"
|
||||
#include "rand.h"
|
||||
#include "curl_fopen.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
The dirslash() function breaks a null-terminated pathname string into
|
||||
directory and filename components then returns the directory component up
|
||||
to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
|
||||
this instead returns a "" string.
|
||||
|
||||
This function returns a pointer to malloc'ed memory.
|
||||
|
||||
The input path to this function is expected to have a filename part.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PATHSEP "\\"
|
||||
#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
|
||||
#elif defined(MSDOS) || defined(OS2)
|
||||
#define PATHSEP "\\"
|
||||
#define IS_SEP(x) ((x) == '\\')
|
||||
#else
|
||||
#define PATHSEP "/"
|
||||
#define IS_SEP(x) ((x) == '/')
|
||||
#endif
|
||||
|
||||
static char *dirslash(const char *path)
|
||||
{
|
||||
size_t n;
|
||||
struct dynbuf out;
|
||||
DEBUGASSERT(path);
|
||||
curlx_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
|
||||
n = strlen(path);
|
||||
if(n) {
|
||||
/* find the rightmost path separator, if any */
|
||||
while(n && !IS_SEP(path[n-1]))
|
||||
--n;
|
||||
/* skip over all the path separators, if any */
|
||||
while(n && IS_SEP(path[n-1]))
|
||||
--n;
|
||||
}
|
||||
if(curlx_dyn_addn(&out, path, n))
|
||||
return NULL;
|
||||
/* if there was a directory, append a single trailing slash */
|
||||
if(n && curlx_dyn_addn(&out, PATHSEP, 1))
|
||||
return NULL;
|
||||
return curlx_dyn_ptr(&out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_fopen() opens a file for writing with a temp name, to be renamed
|
||||
* to the final name when completed. If there is an existing file using this
|
||||
* name at the time of the open, this function will clone the mode from that
|
||||
* file. if 'tempname' is non-NULL, it needs a rename after the file is
|
||||
* written.
|
||||
*/
|
||||
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
FILE **fh, char **tempname)
|
||||
{
|
||||
CURLcode result = CURLE_WRITE_ERROR;
|
||||
unsigned char randbuf[41];
|
||||
char *tempstore = NULL;
|
||||
struct_stat sb;
|
||||
int fd = -1;
|
||||
char *dir = NULL;
|
||||
*tempname = NULL;
|
||||
|
||||
*fh = curlx_fopen(filename, FOPEN_WRITETEXT);
|
||||
if(!*fh)
|
||||
goto fail;
|
||||
if(
|
||||
#ifdef UNDER_CE
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
stat(filename, &sb) == -1
|
||||
#else
|
||||
fstat(fileno(*fh), &sb) == -1
|
||||
#endif
|
||||
|| !S_ISREG(sb.st_mode)) {
|
||||
return CURLE_OK;
|
||||
}
|
||||
curlx_fclose(*fh);
|
||||
*fh = NULL;
|
||||
|
||||
result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
dir = dirslash(filename);
|
||||
if(dir) {
|
||||
/* The temp filename should not end up too long for the target file
|
||||
system */
|
||||
tempstore = curl_maprintf("%s%s.tmp", dir, randbuf);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
if(!tempstore) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = CURLE_WRITE_ERROR;
|
||||
#if (defined(ANDROID) || defined(__ANDROID__)) && \
|
||||
(defined(__i386__) || defined(__arm__))
|
||||
fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL,
|
||||
(mode_t)(0600 | sb.st_mode));
|
||||
#else
|
||||
fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL,
|
||||
0600 | sb.st_mode);
|
||||
#endif
|
||||
if(fd == -1)
|
||||
goto fail;
|
||||
|
||||
*fh = curlx_fdopen(fd, FOPEN_WRITETEXT);
|
||||
if(!*fh)
|
||||
goto fail;
|
||||
|
||||
*tempname = tempstore;
|
||||
return CURLE_OK;
|
||||
|
||||
fail:
|
||||
if(fd != -1) {
|
||||
close(fd);
|
||||
unlink(tempstore);
|
||||
}
|
||||
|
||||
free(tempstore);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* ! disabled */
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef HEADER_CURL_FOPEN_H
|
||||
#define HEADER_CURL_FOPEN_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 "curlx/fopen.h"
|
||||
|
||||
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
FILE **fh, char **tempname);
|
||||
|
||||
#endif
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \
|
||||
!defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC)
|
||||
|
||||
#include "curl_get_line.h"
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#define appendnl(b) \
|
||||
curlx_dyn_addn(buf, "\n", 1)
|
||||
|
||||
/*
|
||||
* Curl_get_line() returns only complete whole lines that end with newline.
|
||||
* When 'eof' is set TRUE, the last line has been read.
|
||||
*/
|
||||
CURLcode Curl_get_line(struct dynbuf *buf, FILE *input, bool *eof)
|
||||
{
|
||||
CURLcode result;
|
||||
char buffer[128];
|
||||
curlx_dyn_reset(buf);
|
||||
while(1) {
|
||||
size_t rlen;
|
||||
char *b = fgets(buffer, sizeof(buffer), input);
|
||||
|
||||
*eof = feof(input);
|
||||
|
||||
rlen = b ? strlen(b) : 0;
|
||||
if(rlen) {
|
||||
result = curlx_dyn_addn(buf, b, rlen);
|
||||
if(result)
|
||||
/* too long line or out of memory */
|
||||
return result;
|
||||
}
|
||||
/* now check the full line */
|
||||
rlen = curlx_dyn_len(buf);
|
||||
b = curlx_dyn_ptr(buf);
|
||||
if(rlen && (b[rlen-1] == '\n'))
|
||||
/* LF at end of the line */
|
||||
return CURLE_OK; /* all good */
|
||||
if(*eof)
|
||||
/* append a newline */
|
||||
return appendnl(buf);
|
||||
/* otherwise get next line to append */
|
||||
}
|
||||
/* UNREACHABLE */
|
||||
}
|
||||
|
||||
#endif /* if not disabled */
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef HEADER_CURL_GET_LINE_H
|
||||
#define HEADER_CURL_GET_LINE_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 "curlx/dynbuf.h"
|
||||
|
||||
/* Curl_get_line() returns complete lines that end with a newline. */
|
||||
CURLcode Curl_get_line(struct dynbuf *buf, FILE *input, bool *eof);
|
||||
|
||||
#endif /* HEADER_CURL_GET_LINE_H */
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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_gethostname.h"
|
||||
|
||||
/*
|
||||
* Curl_gethostname() is a wrapper around gethostname() which allows
|
||||
* overriding the hostname that the function would normally return.
|
||||
* This capability is used by the test suite to verify exact matching
|
||||
* of NTLM authentication, which exercises libcurl's MD4 and DES code
|
||||
* as well as by the SMTP module when a hostname is not provided.
|
||||
*
|
||||
* For libcurl debug enabled builds hostname overriding takes place
|
||||
* when environment variable CURL_GETHOSTNAME is set, using the value
|
||||
* held by the variable to override returned hostname.
|
||||
*
|
||||
* Note: The function always returns the un-qualified hostname rather
|
||||
* than being provider dependent.
|
||||
*/
|
||||
|
||||
int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
|
||||
{
|
||||
#ifndef HAVE_GETHOSTNAME
|
||||
|
||||
/* Allow compilation and return failure when unavailable */
|
||||
(void)name;
|
||||
(void)namelen;
|
||||
return -1;
|
||||
|
||||
#else
|
||||
int err;
|
||||
char *dot;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
/* Override hostname when environment variable CURL_GETHOSTNAME is set */
|
||||
const char *force_hostname = getenv("CURL_GETHOSTNAME");
|
||||
if(force_hostname) {
|
||||
if(strlen(force_hostname) < (size_t)namelen)
|
||||
strcpy(name, force_hostname);
|
||||
else
|
||||
return 1; /* can't do it */
|
||||
err = 0;
|
||||
}
|
||||
else {
|
||||
name[0] = '\0';
|
||||
err = gethostname(name, namelen);
|
||||
}
|
||||
|
||||
#else /* DEBUGBUILD */
|
||||
|
||||
name[0] = '\0';
|
||||
#ifdef __AMIGA__
|
||||
err = gethostname((unsigned char *)name, namelen);
|
||||
#else
|
||||
err = gethostname(name, namelen);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
name[namelen - 1] = '\0';
|
||||
|
||||
if(err)
|
||||
return err;
|
||||
|
||||
/* Truncate domain, leave only machine name */
|
||||
dot = strchr(name, '.');
|
||||
if(dot)
|
||||
*dot = '\0';
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#ifndef HEADER_CURL_GETHOSTNAME_H
|
||||
#define HEADER_CURL_GETHOSTNAME_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Hostname buffer size */
|
||||
#define HOSTNAME_MAX 1024
|
||||
|
||||
/* This returns the local machine's un-qualified hostname */
|
||||
int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen);
|
||||
|
||||
#endif /* HEADER_CURL_GETHOSTNAME_H */
|
||||
+455
@@ -0,0 +1,455 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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_GSSAPI
|
||||
|
||||
#include "curl_gssapi.h"
|
||||
#include "sendf.h"
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
#if defined(HAVE_GSSGNU) || !defined(_WIN32)
|
||||
/* To avoid memdebug macro replacement, wrap the name in parentheses to call
|
||||
the original version. It is freed via the GSS API gss_release_buffer(). */
|
||||
#define Curl_gss_alloc (malloc)
|
||||
#define Curl_gss_free (free)
|
||||
#define CURL_GSS_STUB
|
||||
/* For correctness this would be required for all platforms, not only Windows,
|
||||
but, as of v1.22.1, MIT Kerberos uses a special allocator only for Windows,
|
||||
and the availability of 'gssapi/gssapi_alloc.h' is difficult to detect,
|
||||
because GSS headers are not versioned, and there is also no other macro to
|
||||
indicate 1.18+ vs. previous versions. On Windows we can use 'GSS_S_BAD_MIC'.
|
||||
*/
|
||||
#elif defined(_WIN32) && defined(GSS_S_BAD_MIC) /* MIT Kerberos 1.15+ */
|
||||
/* MIT Kerberos 1.10+ (Windows), 1.18+ (all platforms), missing from GNU GSS */
|
||||
#include <gssapi/gssapi_alloc.h>
|
||||
#define Curl_gss_alloc gssalloc_malloc
|
||||
#define Curl_gss_free gssalloc_free
|
||||
#define CURL_GSS_STUB
|
||||
#endif
|
||||
#endif /* DEBUGBUILD */
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define CURL_ALIGN8 __attribute__((aligned(8)))
|
||||
#else
|
||||
#define CURL_ALIGN8
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(__APPLE__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
|
||||
6, CURL_UNCONST("\x2b\x06\x01\x05\x05\x02")
|
||||
};
|
||||
gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
|
||||
9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")
|
||||
};
|
||||
|
||||
#ifdef CURL_GSS_STUB
|
||||
enum min_err_code {
|
||||
STUB_GSS_OK = 0,
|
||||
STUB_GSS_NO_MEMORY,
|
||||
STUB_GSS_INVALID_ARGS,
|
||||
STUB_GSS_INVALID_CREDS,
|
||||
STUB_GSS_INVALID_CTX,
|
||||
STUB_GSS_SERVER_ERR,
|
||||
STUB_GSS_NO_MECH,
|
||||
STUB_GSS_LAST
|
||||
};
|
||||
|
||||
/* libcurl is also passing this struct to these functions, which are not yet
|
||||
* stubbed:
|
||||
* gss_inquire_context()
|
||||
* gss_unwrap()
|
||||
* gss_wrap()
|
||||
*/
|
||||
struct stub_gss_ctx_id_t_desc {
|
||||
enum { STUB_GSS_NONE, STUB_GSS_KRB5, STUB_GSS_NTLM1, STUB_GSS_NTLM3 } sent;
|
||||
int have_krb5;
|
||||
int have_ntlm;
|
||||
OM_uint32 flags;
|
||||
char creds[250];
|
||||
};
|
||||
|
||||
static OM_uint32
|
||||
stub_gss_init_sec_context(OM_uint32 *min,
|
||||
gss_cred_id_t initiator_cred_handle,
|
||||
struct stub_gss_ctx_id_t_desc **context,
|
||||
gss_name_t target_name,
|
||||
const gss_OID mech_type,
|
||||
OM_uint32 req_flags,
|
||||
OM_uint32 time_req,
|
||||
const gss_channel_bindings_t input_chan_bindings,
|
||||
gss_buffer_desc *input_token,
|
||||
gss_OID *actual_mech_type,
|
||||
gss_buffer_desc *output_token,
|
||||
OM_uint32 *ret_flags,
|
||||
OM_uint32 *time_rec)
|
||||
{
|
||||
struct stub_gss_ctx_id_t_desc *ctx = NULL;
|
||||
|
||||
/* The token will be encoded in base64 */
|
||||
size_t length = sizeof(ctx->creds) * 3 / 4;
|
||||
size_t used = 0;
|
||||
char *token = NULL;
|
||||
const char *creds = NULL;
|
||||
|
||||
(void)initiator_cred_handle;
|
||||
(void)mech_type;
|
||||
(void)time_req;
|
||||
(void)input_chan_bindings;
|
||||
(void)actual_mech_type;
|
||||
|
||||
if(!min)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
*min = 0;
|
||||
|
||||
if(!context || !target_name || !output_token) {
|
||||
*min = STUB_GSS_INVALID_ARGS;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
creds = getenv("CURL_STUB_GSS_CREDS");
|
||||
if(!creds || strlen(creds) >= sizeof(ctx->creds)) {
|
||||
*min = STUB_GSS_INVALID_CREDS;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
ctx = *context;
|
||||
if(ctx && strcmp(ctx->creds, creds)) {
|
||||
*min = STUB_GSS_INVALID_CREDS;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
output_token->length = 0;
|
||||
output_token->value = NULL;
|
||||
|
||||
if(input_token && input_token->length) {
|
||||
if(!ctx) {
|
||||
*min = STUB_GSS_INVALID_CTX;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* Server response, either D (RA==) or C (Qw==) */
|
||||
if(((char *) input_token->value)[0] == 'D') {
|
||||
/* Done */
|
||||
switch(ctx->sent) {
|
||||
case STUB_GSS_KRB5:
|
||||
case STUB_GSS_NTLM3:
|
||||
if(ret_flags)
|
||||
*ret_flags = ctx->flags;
|
||||
if(time_rec)
|
||||
*time_rec = GSS_C_INDEFINITE;
|
||||
return GSS_S_COMPLETE;
|
||||
default:
|
||||
*min = STUB_GSS_SERVER_ERR;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if(((char *) input_token->value)[0] != 'C') {
|
||||
/* We only support Done or Continue */
|
||||
*min = STUB_GSS_SERVER_ERR;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* Continue */
|
||||
switch(ctx->sent) {
|
||||
case STUB_GSS_KRB5:
|
||||
/* We sent KRB5 and it failed, let's try NTLM */
|
||||
if(ctx->have_ntlm) {
|
||||
ctx->sent = STUB_GSS_NTLM1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
*min = STUB_GSS_SERVER_ERR;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
case STUB_GSS_NTLM1:
|
||||
ctx->sent = STUB_GSS_NTLM3;
|
||||
break;
|
||||
default:
|
||||
*min = STUB_GSS_SERVER_ERR;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(ctx) {
|
||||
*min = STUB_GSS_INVALID_CTX;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
*min = STUB_GSS_NO_MEMORY;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if(strstr(creds, "KRB5"))
|
||||
ctx->have_krb5 = 1;
|
||||
|
||||
if(strstr(creds, "NTLM"))
|
||||
ctx->have_ntlm = 1;
|
||||
|
||||
if(ctx->have_krb5)
|
||||
ctx->sent = STUB_GSS_KRB5;
|
||||
else if(ctx->have_ntlm)
|
||||
ctx->sent = STUB_GSS_NTLM1;
|
||||
else {
|
||||
free(ctx);
|
||||
*min = STUB_GSS_NO_MECH;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
strcpy(ctx->creds, creds);
|
||||
ctx->flags = req_flags;
|
||||
}
|
||||
|
||||
token = Curl_gss_alloc(length);
|
||||
if(!token) {
|
||||
free(ctx);
|
||||
*min = STUB_GSS_NO_MEMORY;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
{
|
||||
gss_buffer_desc target_desc;
|
||||
gss_OID name_type = GSS_C_NO_OID;
|
||||
OM_uint32 minor_status;
|
||||
OM_uint32 major_status;
|
||||
major_status = gss_display_name(&minor_status, target_name,
|
||||
&target_desc, &name_type);
|
||||
if(GSS_ERROR(major_status)) {
|
||||
Curl_gss_free(token);
|
||||
free(ctx);
|
||||
*min = STUB_GSS_NO_MEMORY;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if(strlen(creds) + target_desc.length + 5 >= sizeof(ctx->creds)) {
|
||||
Curl_gss_free(token);
|
||||
free(ctx);
|
||||
*min = STUB_GSS_NO_MEMORY;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* Token format: creds:target:type:padding */
|
||||
used = curl_msnprintf(token, length, "%s:%.*s:%d:", creds,
|
||||
(int)target_desc.length,
|
||||
(const char *)target_desc.value,
|
||||
ctx->sent);
|
||||
|
||||
gss_release_buffer(&minor_status, &target_desc);
|
||||
}
|
||||
|
||||
if(used >= length) {
|
||||
Curl_gss_free(token);
|
||||
free(ctx);
|
||||
*min = STUB_GSS_NO_MEMORY;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* Overwrite null-terminator */
|
||||
memset(token + used, 'A', length - used);
|
||||
|
||||
*context = ctx;
|
||||
|
||||
output_token->value = token;
|
||||
output_token->length = length;
|
||||
|
||||
return GSS_S_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
static OM_uint32
|
||||
stub_gss_delete_sec_context(OM_uint32 *min,
|
||||
struct stub_gss_ctx_id_t_desc **context,
|
||||
gss_buffer_t output_token)
|
||||
{
|
||||
(void)output_token;
|
||||
|
||||
if(!min)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
if(!context) {
|
||||
*min = STUB_GSS_INVALID_CTX;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
if(!*context) {
|
||||
*min = STUB_GSS_INVALID_CTX;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
free(*context);
|
||||
*context = NULL;
|
||||
*min = 0;
|
||||
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
#endif /* CURL_GSS_STUB */
|
||||
|
||||
OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
|
||||
OM_uint32 *minor_status,
|
||||
gss_ctx_id_t *context,
|
||||
gss_name_t target_name,
|
||||
gss_OID mech_type,
|
||||
gss_channel_bindings_t input_chan_bindings,
|
||||
gss_buffer_t input_token,
|
||||
gss_buffer_t output_token,
|
||||
const bool mutual_auth,
|
||||
OM_uint32 *ret_flags)
|
||||
{
|
||||
OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
|
||||
|
||||
if(mutual_auth)
|
||||
req_flags |= GSS_C_MUTUAL_FLAG;
|
||||
|
||||
if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) {
|
||||
#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.8+, missing from GNU GSS */
|
||||
req_flags |= GSS_C_DELEG_POLICY_FLAG;
|
||||
#else
|
||||
infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
|
||||
"compiled in");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
|
||||
req_flags |= GSS_C_DELEG_FLAG;
|
||||
|
||||
#ifdef CURL_GSS_STUB
|
||||
if(getenv("CURL_STUB_GSS_CREDS"))
|
||||
return stub_gss_init_sec_context(minor_status,
|
||||
GSS_C_NO_CREDENTIAL, /* cred_handle */
|
||||
(struct stub_gss_ctx_id_t_desc **)context,
|
||||
target_name,
|
||||
mech_type,
|
||||
req_flags,
|
||||
0, /* time_req */
|
||||
input_chan_bindings,
|
||||
input_token,
|
||||
NULL, /* actual_mech_type */
|
||||
output_token,
|
||||
ret_flags,
|
||||
NULL /* time_rec */);
|
||||
#endif /* CURL_GSS_STUB */
|
||||
|
||||
return gss_init_sec_context(minor_status,
|
||||
GSS_C_NO_CREDENTIAL, /* cred_handle */
|
||||
context,
|
||||
target_name,
|
||||
mech_type,
|
||||
req_flags,
|
||||
0, /* time_req */
|
||||
input_chan_bindings,
|
||||
input_token,
|
||||
NULL, /* actual_mech_type */
|
||||
output_token,
|
||||
ret_flags,
|
||||
NULL /* time_rec */);
|
||||
}
|
||||
|
||||
OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
|
||||
gss_ctx_id_t *context,
|
||||
gss_buffer_t output_token)
|
||||
{
|
||||
#ifdef CURL_GSS_STUB
|
||||
if(getenv("CURL_STUB_GSS_CREDS"))
|
||||
return stub_gss_delete_sec_context(min,
|
||||
(struct stub_gss_ctx_id_t_desc **)context,
|
||||
output_token);
|
||||
#endif /* CURL_GSS_STUB */
|
||||
|
||||
return gss_delete_sec_context(min, context, output_token);
|
||||
}
|
||||
|
||||
#define GSS_LOG_BUFFER_LEN 1024
|
||||
static size_t display_gss_error(OM_uint32 status, int type,
|
||||
char *buf, size_t len) {
|
||||
OM_uint32 maj_stat;
|
||||
OM_uint32 min_stat;
|
||||
OM_uint32 msg_ctx = 0;
|
||||
gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
do {
|
||||
maj_stat = gss_display_status(&min_stat,
|
||||
status,
|
||||
type,
|
||||
GSS_C_NO_OID,
|
||||
&msg_ctx,
|
||||
&status_string);
|
||||
if(maj_stat == GSS_S_COMPLETE && status_string.length > 0) {
|
||||
if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) {
|
||||
len += curl_msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
|
||||
"%.*s. ", (int)status_string.length,
|
||||
(char *)status_string.value);
|
||||
}
|
||||
}
|
||||
gss_release_buffer(&min_stat, &status_string);
|
||||
} while(!GSS_ERROR(maj_stat) && msg_ctx);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_gss_log_error()
|
||||
*
|
||||
* This is used to log a GSS-API error status.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* data [in] - The session handle.
|
||||
* prefix [in] - The prefix of the log message.
|
||||
* major [in] - The major status code.
|
||||
* minor [in] - The minor status code.
|
||||
*/
|
||||
void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
|
||||
OM_uint32 major, OM_uint32 minor)
|
||||
{
|
||||
char buf[GSS_LOG_BUFFER_LEN];
|
||||
size_t len = 0;
|
||||
|
||||
if(major != GSS_S_FAILURE)
|
||||
len = display_gss_error(major, GSS_C_GSS_CODE, buf, len);
|
||||
|
||||
display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
|
||||
|
||||
infof(data, "%s%s", prefix, buf);
|
||||
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||||
(void)data;
|
||||
(void)prefix;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && defined(__APPLE__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_GSSAPI */
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
#ifndef HEADER_CURL_GSSAPI_H
|
||||
#define HEADER_CURL_GSSAPI_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"
|
||||
#include "urldata.h"
|
||||
|
||||
#ifdef HAVE_GSSAPI
|
||||
|
||||
#ifdef GSS_C_CHANNEL_BOUND_FLAG /* MIT Kerberos 1.19+, missing from GNU GSS */
|
||||
#define CURL_GSSAPI_HAS_CHANNEL_BINDING
|
||||
#endif
|
||||
|
||||
extern gss_OID_desc Curl_spnego_mech_oid;
|
||||
extern gss_OID_desc Curl_krb5_mech_oid;
|
||||
|
||||
/* Common method for using GSS-API */
|
||||
OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
|
||||
OM_uint32 *minor_status,
|
||||
gss_ctx_id_t *context,
|
||||
gss_name_t target_name,
|
||||
gss_OID mech_type,
|
||||
gss_channel_bindings_t input_chan_bindings,
|
||||
gss_buffer_t input_token,
|
||||
gss_buffer_t output_token,
|
||||
const bool mutual_auth,
|
||||
OM_uint32 *ret_flags);
|
||||
|
||||
OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
|
||||
gss_ctx_id_t *context_handle,
|
||||
gss_buffer_t output_token);
|
||||
|
||||
/* Helper to log a GSS-API error status */
|
||||
void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
|
||||
OM_uint32 major, OM_uint32 minor);
|
||||
|
||||
/* Define our privacy and integrity protection values */
|
||||
#define GSSAUTH_P_NONE 1
|
||||
#define GSSAUTH_P_INTEGRITY 2
|
||||
#define GSSAUTH_P_PRIVACY 4
|
||||
|
||||
#endif /* HAVE_GSSAPI */
|
||||
#endif /* HEADER_CURL_GSSAPI_H */
|
||||
Vendored
+76
@@ -0,0 +1,76 @@
|
||||
#ifndef HEADER_CURL_HMAC_H
|
||||
#define HEADER_CURL_HMAC_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \
|
||||
!defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
|
||||
defined(USE_LIBSSH2) || defined(USE_SSL)
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#define HMAC_MD5_LENGTH 16
|
||||
|
||||
typedef CURLcode (*HMAC_hinit)(void *context);
|
||||
typedef void (*HMAC_hupdate)(void *context,
|
||||
const unsigned char *data,
|
||||
unsigned int len);
|
||||
typedef void (*HMAC_hfinal)(unsigned char *result, void *context);
|
||||
|
||||
/* Per-hash function HMAC parameters. */
|
||||
struct HMAC_params {
|
||||
HMAC_hinit hinit; /* Initialize context procedure. */
|
||||
HMAC_hupdate hupdate; /* Update context with data. */
|
||||
HMAC_hfinal hfinal; /* Get final result procedure. */
|
||||
unsigned int ctxtsize; /* Context structure size. */
|
||||
unsigned int maxkeylen; /* Maximum key length (bytes). */
|
||||
unsigned int resultlen; /* Result length (bytes). */
|
||||
};
|
||||
|
||||
|
||||
/* HMAC computation context. */
|
||||
struct HMAC_context {
|
||||
const struct HMAC_params *hash; /* Hash function definition. */
|
||||
void *hashctxt1; /* Hash function context 1. */
|
||||
void *hashctxt2; /* Hash function context 2. */
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes. */
|
||||
struct HMAC_context *Curl_HMAC_init(const struct HMAC_params *hashparams,
|
||||
const unsigned char *key,
|
||||
unsigned int keylen);
|
||||
int Curl_HMAC_update(struct HMAC_context *context,
|
||||
const unsigned char *data,
|
||||
unsigned int len);
|
||||
int Curl_HMAC_final(struct HMAC_context *context, unsigned char *result);
|
||||
|
||||
CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
|
||||
const unsigned char *key, const size_t keylen,
|
||||
const unsigned char *data, const size_t datalen,
|
||||
unsigned char *output);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_HMAC_H */
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_LDAP_H
|
||||
#define HEADER_CURL_LDAP_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
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifndef CURL_DISABLE_LDAP
|
||||
extern const struct Curl_handler Curl_handler_ldap;
|
||||
|
||||
#if !defined(CURL_DISABLE_LDAPS) && \
|
||||
((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
|
||||
(!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
|
||||
extern const struct Curl_handler Curl_handler_ldaps;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* HEADER_CURL_LDAP_H */
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_MD4_H
|
||||
#define HEADER_CURL_MD4_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"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef USE_CURL_NTLM_CORE
|
||||
|
||||
#define MD4_DIGEST_LENGTH 16
|
||||
|
||||
CURLcode Curl_md4it(unsigned char *output, const unsigned char *input,
|
||||
const size_t len);
|
||||
|
||||
#endif /* USE_CURL_NTLM_CORE */
|
||||
|
||||
#endif /* HEADER_CURL_MD4_H */
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
#ifndef HEADER_CURL_MD5_H
|
||||
#define HEADER_CURL_MD5_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \
|
||||
!defined(CURL_DISABLE_DIGEST_AUTH)
|
||||
|
||||
#include "curl_hmac.h"
|
||||
|
||||
#define MD5_DIGEST_LEN 16
|
||||
|
||||
typedef CURLcode (*Curl_MD5_init_func)(void *context);
|
||||
typedef void (*Curl_MD5_update_func)(void *context,
|
||||
const unsigned char *data,
|
||||
unsigned int len);
|
||||
typedef void (*Curl_MD5_final_func)(unsigned char *result, void *context);
|
||||
|
||||
struct MD5_params {
|
||||
Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
|
||||
Curl_MD5_update_func md5_update_func; /* Update context with data */
|
||||
Curl_MD5_final_func md5_final_func; /* Get final result procedure */
|
||||
unsigned int md5_ctxtsize; /* Context structure size */
|
||||
unsigned int md5_resultlen; /* Result length (bytes) */
|
||||
};
|
||||
|
||||
struct MD5_context {
|
||||
const struct MD5_params *md5_hash; /* Hash function definition */
|
||||
void *md5_hashctx; /* Hash function context */
|
||||
};
|
||||
|
||||
extern const struct MD5_params Curl_DIGEST_MD5;
|
||||
extern const struct HMAC_params Curl_HMAC_MD5;
|
||||
|
||||
CURLcode Curl_md5it(unsigned char *output, const unsigned char *input,
|
||||
const size_t len);
|
||||
|
||||
struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params);
|
||||
CURLcode Curl_MD5_update(struct MD5_context *context,
|
||||
const unsigned char *data,
|
||||
unsigned int len);
|
||||
CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_MD5_H */
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Unset redefined system symbols. */
|
||||
|
||||
#undef strdup
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
#ifdef _WIN32
|
||||
#undef Curl_tcsdup
|
||||
#endif
|
||||
|
||||
#undef HEADER_CURL_MEMORY_H
|
||||
#undef HEADER_CURL_MEMDEBUG_H
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
#ifndef HEADER_CURL_MEMORY_H
|
||||
#define HEADER_CURL_MEMORY_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Nasty internal details ahead...
|
||||
*
|
||||
* File curl_memory.h must be included by _all_ *.c source files
|
||||
* that use memory related functions strdup, malloc, calloc, realloc
|
||||
* or free, and given source file is used to build libcurl library.
|
||||
* It should be included immediately before memdebug.h as the last files
|
||||
* included to avoid undesired interaction with other memory function
|
||||
* headers in dependent libraries.
|
||||
*
|
||||
* There is nearly no exception to above rule. All libcurl source
|
||||
* files in 'lib' subdirectory as well as those living deep inside
|
||||
* 'packages' subdirectories and linked together in order to build
|
||||
* libcurl library shall follow it.
|
||||
*
|
||||
* File lib/strdup.c is an exception, given that it provides a strdup
|
||||
* clone implementation while using malloc. Extra care needed inside
|
||||
* this one.
|
||||
*
|
||||
* The need for curl_memory.h inclusion is due to libcurl's feature
|
||||
* of allowing library user to provide memory replacement functions,
|
||||
* memory callbacks, at runtime with curl_global_init_mem()
|
||||
*
|
||||
* Any *.c source file used to build libcurl library that does not
|
||||
* include curl_memory.h and uses any memory function of the five
|
||||
* mentioned above will compile without any indication, but it will
|
||||
* trigger weird memory related issues at runtime.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CURLDEBUG
|
||||
|
||||
/*
|
||||
* libcurl's 'memory tracking' system defines strdup, malloc, calloc,
|
||||
* realloc and free, along with others, in memdebug.h in a different
|
||||
* way although still using memory callbacks forward declared above.
|
||||
* When using the 'memory tracking' system (CURLDEBUG defined) we do
|
||||
* not define here the five memory functions given that definitions
|
||||
* from memdebug.h are the ones that shall be used.
|
||||
*/
|
||||
|
||||
#undef strdup
|
||||
#define strdup(ptr) Curl_cstrdup(ptr)
|
||||
#undef malloc
|
||||
#define malloc(size) Curl_cmalloc(size)
|
||||
#undef calloc
|
||||
#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
|
||||
#undef realloc
|
||||
#define realloc(ptr,size) Curl_crealloc(ptr, size)
|
||||
#undef free
|
||||
#define free(ptr) Curl_cfree(ptr)
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef Curl_tcsdup
|
||||
#ifdef UNICODE
|
||||
#define Curl_tcsdup(ptr) Curl_wcsdup(ptr)
|
||||
#else
|
||||
#define Curl_tcsdup(ptr) Curl_cstrdup(ptr)
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* CURLDEBUG */
|
||||
#endif /* HEADER_CURL_MEMORY_H */
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "curl_memrchr.h"
|
||||
#include "curl_memory.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifndef HAVE_MEMRCHR
|
||||
/*
|
||||
* Curl_memrchr()
|
||||
*
|
||||
* Our memrchr() function clone for systems which lack this function. The
|
||||
* memrchr() function is like the memchr() function, except that it searches
|
||||
* backwards from the end of the n bytes pointed to by s instead of forward
|
||||
* from the beginning.
|
||||
*/
|
||||
|
||||
void *
|
||||
Curl_memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
if(n > 0) {
|
||||
const unsigned char *p = s;
|
||||
const unsigned char *q = s;
|
||||
|
||||
p += n - 1;
|
||||
|
||||
while(p >= q) {
|
||||
if(*p == (unsigned char)c)
|
||||
return CURL_UNCONST(p);
|
||||
p--;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_MEMRCHR */
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#ifndef HEADER_CURL_MEMRCHR_H
|
||||
#define HEADER_CURL_MEMRCHR_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"
|
||||
|
||||
#ifdef HAVE_MEMRCHR
|
||||
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#else /* HAVE_MEMRCHR */
|
||||
void *Curl_memrchr(const void *s, int c, size_t n);
|
||||
#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
|
||||
|
||||
#endif /* HAVE_MEMRCHR */
|
||||
|
||||
#endif /* HEADER_CURL_MEMRCHR_H */
|
||||
+679
@@ -0,0 +1,679 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 USE_CURL_NTLM_CORE
|
||||
|
||||
/*
|
||||
* NTLM details:
|
||||
*
|
||||
* https://davenport.sourceforge.net/ntlm.html
|
||||
* https://www.innovation.ch/java/ntlm.html
|
||||
*/
|
||||
|
||||
/* Please keep the SSL backend-specific #if branches in this order:
|
||||
|
||||
1. USE_OPENSSL
|
||||
2. USE_WOLFSSL
|
||||
3. USE_GNUTLS
|
||||
4. USE_MBEDTLS
|
||||
5. USE_OS400CRYPTO
|
||||
6. USE_WIN32_CRYPTO
|
||||
|
||||
This ensures that:
|
||||
- the same SSL branch gets activated throughout this source
|
||||
file even if multiple backends are enabled at the same time.
|
||||
- OpenSSL has higher priority than Windows Crypt, due
|
||||
to issues with the latter supporting NTLM2Session responses
|
||||
in NTLM type-3 messages.
|
||||
*/
|
||||
|
||||
#ifdef USE_MBEDTLS
|
||||
#include <mbedtls/version.h>
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x03020000
|
||||
#error "mbedTLS 3.2.0 or later required"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_OPENSSL) && defined(HAVE_DES_ECB_ENCRYPT)
|
||||
#define USE_OPENSSL_DES
|
||||
#elif defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT)
|
||||
#define USE_OPENSSL_DES
|
||||
#elif defined(USE_MBEDTLS) && defined(HAVE_MBEDTLS_DES_CRYPT_ECB)
|
||||
#define USE_MBEDTLS_DES
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENSSL_DES
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
# include <openssl/des.h>
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/rand.h>
|
||||
# ifdef OPENSSL_IS_AWSLC /* for versions 1.2.0 to 1.30.1 */
|
||||
# define DES_set_key_unchecked (void)DES_set_key
|
||||
# endif
|
||||
# define DESKEY(x) &x
|
||||
#else
|
||||
# include <wolfssl/options.h>
|
||||
# include <wolfssl/openssl/des.h>
|
||||
# include <wolfssl/openssl/ssl.h>
|
||||
# include <wolfssl/openssl/rand.h>
|
||||
# ifdef OPENSSL_COEXIST
|
||||
# define DES_key_schedule WOLFSSL_DES_key_schedule
|
||||
# define DES_cblock WOLFSSL_DES_cblock
|
||||
# define DES_set_odd_parity wolfSSL_DES_set_odd_parity
|
||||
# define DES_set_key wolfSSL_DES_set_key
|
||||
# define DES_set_key_unchecked wolfSSL_DES_set_key_unchecked
|
||||
# define DES_ecb_encrypt wolfSSL_DES_ecb_encrypt
|
||||
# define DESKEY(x) ((WOLFSSL_DES_key_schedule *)(x))
|
||||
# else
|
||||
# define DESKEY(x) &x
|
||||
# endif
|
||||
#endif
|
||||
#define DESKEYARG(x) *x
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
|
||||
# include <nettle/des.h>
|
||||
# define USE_CURL_DES_SET_ODD_PARITY
|
||||
|
||||
#elif defined(USE_MBEDTLS_DES)
|
||||
|
||||
# include <mbedtls/des.h>
|
||||
|
||||
#elif defined(USE_OS400CRYPTO)
|
||||
# include "cipher.mih" /* mih/cipher */
|
||||
# define USE_CURL_DES_SET_ODD_PARITY
|
||||
#elif defined(USE_WIN32_CRYPTO)
|
||||
# include <wincrypt.h>
|
||||
# define USE_CURL_DES_SET_ODD_PARITY
|
||||
#else
|
||||
# error "cannot compile NTLM support without a crypto library with DES."
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
#include "strcase.h"
|
||||
#include "curl_ntlm_core.h"
|
||||
#include "curl_md5.h"
|
||||
#include "curl_hmac.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "curl_endian.h"
|
||||
#include "curl_md4.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef USE_CURL_DES_SET_ODD_PARITY
|
||||
/*
|
||||
* curl_des_set_odd_parity()
|
||||
*
|
||||
* Copyright (C) Steve Holme, <steve_holme@hotmail.com>
|
||||
*
|
||||
* This is used to apply odd parity to the given byte array. It is typically
|
||||
* used by when a cryptography engine does not have its own version.
|
||||
*
|
||||
* The function is a port of the Java based oddParity() function over at:
|
||||
*
|
||||
* https://davenport.sourceforge.net/ntlm.html
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* bytes [in/out] - The data whose parity bits are to be adjusted for
|
||||
* odd parity.
|
||||
* len [out] - The length of the data.
|
||||
*/
|
||||
static void curl_des_set_odd_parity(unsigned char *bytes, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
unsigned char b = bytes[i];
|
||||
|
||||
bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^
|
||||
(b >> 4) ^ (b >> 3) ^ (b >> 2) ^
|
||||
(b >> 1)) & 0x01) == 0;
|
||||
|
||||
if(needs_parity)
|
||||
bytes[i] |= 0x01;
|
||||
else
|
||||
bytes[i] &= 0xfe;
|
||||
}
|
||||
}
|
||||
#endif /* USE_CURL_DES_SET_ODD_PARITY */
|
||||
|
||||
/*
|
||||
* Turns a 56-bit key into being 64-bit wide.
|
||||
*/
|
||||
static void extend_key_56_to_64(const unsigned char *key_56, char *key)
|
||||
{
|
||||
key[0] = (char)key_56[0];
|
||||
key[1] = (char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
|
||||
key[2] = (char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
|
||||
key[3] = (char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
|
||||
key[4] = (char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
|
||||
key[5] = (char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
|
||||
key[6] = (char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
|
||||
key[7] = (char) ((key_56[6] << 1) & 0xFF);
|
||||
}
|
||||
|
||||
#ifdef USE_OPENSSL_DES
|
||||
/*
|
||||
* Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The
|
||||
* key schedule ks is also set.
|
||||
*/
|
||||
static void setup_des_key(const unsigned char *key_56,
|
||||
DES_key_schedule DESKEYARG(ks))
|
||||
{
|
||||
DES_cblock key;
|
||||
|
||||
/* Expand the 56-bit key to 64 bits */
|
||||
extend_key_56_to_64(key_56, (char *) &key);
|
||||
|
||||
/* Set the key parity to odd */
|
||||
DES_set_odd_parity(&key);
|
||||
|
||||
/* Set the key */
|
||||
DES_set_key_unchecked(&key, ks);
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
|
||||
static void setup_des_key(const unsigned char *key_56,
|
||||
struct des_ctx *des)
|
||||
{
|
||||
char key[8];
|
||||
|
||||
/* Expand the 56-bit key to 64 bits */
|
||||
extend_key_56_to_64(key_56, key);
|
||||
|
||||
/* Set the key parity to odd */
|
||||
curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
|
||||
|
||||
/* Set the key */
|
||||
des_set_key(des, (const uint8_t *) key);
|
||||
}
|
||||
|
||||
#elif defined(USE_MBEDTLS_DES)
|
||||
|
||||
static bool encrypt_des(const unsigned char *in, unsigned char *out,
|
||||
const unsigned char *key_56)
|
||||
{
|
||||
mbedtls_des_context ctx;
|
||||
char key[8];
|
||||
|
||||
/* Expand the 56-bit key to 64 bits */
|
||||
extend_key_56_to_64(key_56, key);
|
||||
|
||||
/* Set the key parity to odd */
|
||||
mbedtls_des_key_set_parity((unsigned char *) key);
|
||||
|
||||
/* Perform the encryption */
|
||||
mbedtls_des_init(&ctx);
|
||||
mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
|
||||
return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
|
||||
}
|
||||
|
||||
#elif defined(USE_OS400CRYPTO)
|
||||
|
||||
static bool encrypt_des(const unsigned char *in, unsigned char *out,
|
||||
const unsigned char *key_56)
|
||||
{
|
||||
char key[8];
|
||||
_CIPHER_Control_T ctl;
|
||||
|
||||
/* Setup the cipher control structure */
|
||||
ctl.Func_ID = ENCRYPT_ONLY;
|
||||
ctl.Data_Len = sizeof(key);
|
||||
|
||||
/* Expand the 56-bit key to 64 bits */
|
||||
extend_key_56_to_64(key_56, ctl.Crypto_Key);
|
||||
|
||||
/* Set the key parity to odd */
|
||||
curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len);
|
||||
|
||||
/* Perform the encryption */
|
||||
_CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#elif defined(USE_WIN32_CRYPTO)
|
||||
|
||||
static bool encrypt_des(const unsigned char *in, unsigned char *out,
|
||||
const unsigned char *key_56)
|
||||
{
|
||||
HCRYPTPROV hprov;
|
||||
HCRYPTKEY hkey;
|
||||
struct {
|
||||
BLOBHEADER hdr;
|
||||
unsigned int len;
|
||||
char key[8];
|
||||
} blob;
|
||||
DWORD len = 8;
|
||||
|
||||
/* Acquire the crypto provider */
|
||||
if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
return FALSE;
|
||||
|
||||
/* Setup the key blob structure */
|
||||
memset(&blob, 0, sizeof(blob));
|
||||
blob.hdr.bType = PLAINTEXTKEYBLOB;
|
||||
blob.hdr.bVersion = 2;
|
||||
blob.hdr.aiKeyAlg = CALG_DES;
|
||||
blob.len = sizeof(blob.key);
|
||||
|
||||
/* Expand the 56-bit key to 64 bits */
|
||||
extend_key_56_to_64(key_56, blob.key);
|
||||
|
||||
/* Set the key parity to odd */
|
||||
curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key));
|
||||
|
||||
/* Import the key */
|
||||
if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) {
|
||||
CryptReleaseContext(hprov, 0);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(out, in, 8);
|
||||
|
||||
/* Perform the encryption */
|
||||
CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len);
|
||||
|
||||
CryptDestroyKey(hkey);
|
||||
CryptReleaseContext(hprov, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* USE_WIN32_CRYPTO */
|
||||
|
||||
/*
|
||||
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
|
||||
* 8 byte plaintext is encrypted with each key and the resulting 24
|
||||
* bytes are stored in the results array.
|
||||
*/
|
||||
void Curl_ntlm_core_lm_resp(const unsigned char *keys,
|
||||
const unsigned char *plaintext,
|
||||
unsigned char *results)
|
||||
{
|
||||
#ifdef USE_OPENSSL_DES
|
||||
DES_key_schedule ks;
|
||||
|
||||
setup_des_key(keys, DESKEY(ks));
|
||||
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*)CURL_UNCONST(plaintext),
|
||||
(DES_cblock*)(results + 8), DESKEY(ks), DES_ENCRYPT);
|
||||
|
||||
setup_des_key(keys + 14, DESKEY(ks));
|
||||
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);
|
||||
des_encrypt(&des, 8, results, plaintext);
|
||||
setup_des_key(keys + 7, &des);
|
||||
des_encrypt(&des, 8, results + 8, plaintext);
|
||||
setup_des_key(keys + 14, &des);
|
||||
des_encrypt(&des, 8, results + 16, plaintext);
|
||||
#elif defined(USE_MBEDTLS_DES) || defined(USE_OS400CRYPTO) || \
|
||||
defined(USE_WIN32_CRYPTO)
|
||||
encrypt_des(plaintext, results, keys);
|
||||
encrypt_des(plaintext, results + 8, keys + 7);
|
||||
encrypt_des(plaintext, results + 16, keys + 14);
|
||||
#else
|
||||
(void)keys;
|
||||
(void)plaintext;
|
||||
(void)results;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up lanmanager hashed password
|
||||
*/
|
||||
CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
|
||||
unsigned char *lmbuffer /* 21 bytes */)
|
||||
{
|
||||
unsigned char pw[14];
|
||||
static const unsigned char magic[] = {
|
||||
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
|
||||
};
|
||||
size_t len = CURLMIN(strlen(password), 14);
|
||||
|
||||
Curl_strntoupper((char *)pw, password, len);
|
||||
memset(&pw[len], 0, 14 - len);
|
||||
|
||||
{
|
||||
/* Create LanManager hashed password. */
|
||||
|
||||
#ifdef USE_OPENSSL_DES
|
||||
DES_key_schedule ks;
|
||||
|
||||
setup_des_key(pw, DESKEY(ks));
|
||||
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 *)CURL_UNCONST(magic),
|
||||
(DES_cblock *)(lmbuffer + 8), DESKEY(ks), DES_ENCRYPT);
|
||||
#elif defined(USE_GNUTLS)
|
||||
struct des_ctx des;
|
||||
setup_des_key(pw, &des);
|
||||
des_encrypt(&des, 8, lmbuffer, magic);
|
||||
setup_des_key(pw + 7, &des);
|
||||
des_encrypt(&des, 8, lmbuffer + 8, magic);
|
||||
#elif defined(USE_MBEDTLS_DES) || defined(USE_OS400CRYPTO) || \
|
||||
defined(USE_WIN32_CRYPTO)
|
||||
encrypt_des(magic, lmbuffer, pw);
|
||||
encrypt_des(magic, lmbuffer + 8, pw + 7);
|
||||
#endif
|
||||
|
||||
memset(lmbuffer + 16, 0, 21 - 16);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void ascii_to_unicode_le(unsigned char *dest, const char *src,
|
||||
size_t srclen)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < srclen; i++) {
|
||||
dest[2 * i] = (unsigned char)src[i];
|
||||
dest[2 * i + 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_WINDOWS_SSPI
|
||||
|
||||
static void ascii_uppercase_to_unicode_le(unsigned char *dest,
|
||||
const char *src, size_t srclen)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < srclen; i++) {
|
||||
dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i]));
|
||||
dest[2 * i + 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !USE_WINDOWS_SSPI */
|
||||
|
||||
/*
|
||||
* Set up nt hashed passwords
|
||||
* @unittest: 1600
|
||||
*/
|
||||
CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
|
||||
unsigned char *ntbuffer /* 21 bytes */)
|
||||
{
|
||||
size_t len = strlen(password);
|
||||
unsigned char *pw;
|
||||
CURLcode result;
|
||||
if(len > SIZE_MAX/2) /* avoid integer overflow */
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
pw = len ? malloc(len * 2) : (unsigned char *)strdup("");
|
||||
if(!pw)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
ascii_to_unicode_le(pw, password, len);
|
||||
|
||||
/* Create NT hashed password. */
|
||||
result = Curl_md4it(ntbuffer, pw, 2 * len);
|
||||
if(!result)
|
||||
memset(ntbuffer + 16, 0, 21 - 16);
|
||||
|
||||
free(pw);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef 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;
|
||||
unsigned int dwHighDateTime;
|
||||
};
|
||||
|
||||
/* Convert a time_t to an MS FILETIME (MS-DTYP section 2.3.3). */
|
||||
static void time2filetime(struct ms_filetime *ft, time_t t)
|
||||
{
|
||||
#if SIZEOF_TIME_T > 4
|
||||
t = (t + (curl_off_t)11644473600) * 10000000;
|
||||
ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
|
||||
ft->dwHighDateTime = (unsigned int) (t >> 32);
|
||||
#else
|
||||
unsigned int r, s;
|
||||
unsigned int i;
|
||||
|
||||
ft->dwLowDateTime = (unsigned int)t & 0xFFFFFFFF;
|
||||
ft->dwHighDateTime = 0;
|
||||
|
||||
# ifndef HAVE_TIME_T_UNSIGNED
|
||||
/* Extend sign if needed. */
|
||||
if(ft->dwLowDateTime & 0x80000000)
|
||||
ft->dwHighDateTime = ~(unsigned int)0;
|
||||
# endif
|
||||
|
||||
/* Bias seconds to Jan 1, 1601.
|
||||
134774 days = 11644473600 seconds = 0x2B6109100 */
|
||||
r = ft->dwLowDateTime;
|
||||
ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
|
||||
ft->dwHighDateTime += ft->dwLowDateTime < r ? 0x03 : 0x02;
|
||||
|
||||
/* Convert to tenths of microseconds. */
|
||||
ft->dwHighDateTime *= 10000000;
|
||||
i = 32;
|
||||
do {
|
||||
i -= 8;
|
||||
s = ((ft->dwLowDateTime >> i) & 0xFF) * (10000000 - 1);
|
||||
r = (s << i) & 0xFFFFFFFF;
|
||||
s >>= 1; /* Split shift to avoid width overflow. */
|
||||
s >>= 31 - i;
|
||||
ft->dwLowDateTime = (ft->dwLowDateTime + r) & 0xFFFFFFFF;
|
||||
if(ft->dwLowDateTime < r)
|
||||
s++;
|
||||
ft->dwHighDateTime += s;
|
||||
} while(i);
|
||||
ft->dwHighDateTime &= 0xFFFFFFFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
|
||||
* (uppercase UserName + Domain) as the data
|
||||
*/
|
||||
CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
|
||||
const char *domain, size_t domlen,
|
||||
unsigned char *ntlmhash,
|
||||
unsigned char *ntlmv2hash)
|
||||
{
|
||||
/* Unicode representation */
|
||||
size_t identity_len;
|
||||
unsigned char *identity;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if((userlen > CURL_MAX_INPUT_LENGTH) || (domlen > CURL_MAX_INPUT_LENGTH))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
identity_len = (userlen + domlen) * 2;
|
||||
identity = malloc(identity_len + 1);
|
||||
|
||||
if(!identity)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
ascii_uppercase_to_unicode_le(identity, user, userlen);
|
||||
ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
|
||||
|
||||
result = Curl_hmacit(&Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len,
|
||||
ntlmv2hash);
|
||||
free(identity);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_ntlm_core_mk_ntlmv2_resp()
|
||||
*
|
||||
* This creates the NTLMv2 response as set in the NTLM type-3 message.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* ntlmv2hash [in] - The NTLMv2 hash (16 bytes)
|
||||
* challenge_client [in] - The client nonce (8 bytes)
|
||||
* ntlm [in] - The NTLM data struct being used to read TargetInfo
|
||||
and Server challenge received in the type-2 message
|
||||
* ntresp [out] - The address where a pointer to newly allocated
|
||||
* memory holding the NTLMv2 response.
|
||||
* ntresp_len [out] - The length of the output message.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
|
||||
unsigned char *challenge_client,
|
||||
struct ntlmdata *ntlm,
|
||||
unsigned char **ntresp,
|
||||
unsigned int *ntresp_len)
|
||||
{
|
||||
/* NTLMv2 response structure :
|
||||
------------------------------------------------------------------------------
|
||||
0 HMAC MD5 16 bytes
|
||||
------BLOB--------------------------------------------------------------------
|
||||
16 Signature 0x01010000
|
||||
20 Reserved long (0x00000000)
|
||||
24 Timestamp LE, 64-bit signed value representing the number of
|
||||
tenths of a microsecond since January 1, 1601.
|
||||
32 Client Nonce 8 bytes
|
||||
40 Unknown 4 bytes
|
||||
44 Target Info N bytes (from the type-2 message)
|
||||
44+N Unknown 4 bytes
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned int len = 0;
|
||||
unsigned char *ptr = NULL;
|
||||
unsigned char hmac_output[HMAC_MD5_LENGTH];
|
||||
struct ms_filetime tw;
|
||||
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* Calculate the timestamp */
|
||||
#ifdef DEBUGBUILD
|
||||
char *force_timestamp = getenv("CURL_FORCETIME");
|
||||
if(force_timestamp)
|
||||
time2filetime(&tw, (time_t) 0);
|
||||
else
|
||||
#endif
|
||||
time2filetime(&tw, time(NULL));
|
||||
|
||||
/* Calculate the response len */
|
||||
len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
|
||||
|
||||
/* Allocate the response */
|
||||
ptr = calloc(1, len);
|
||||
if(!ptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Create the BLOB structure */
|
||||
curl_msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
|
||||
"%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
|
||||
"%c%c%c%c" /* Reserved = 0 */
|
||||
"%c%c%c%c%c%c%c%c", /* Timestamp */
|
||||
NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
|
||||
NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
|
||||
0, 0, 0, 0,
|
||||
LONGQUARTET(tw.dwLowDateTime),
|
||||
LONGQUARTET(tw.dwHighDateTime));
|
||||
|
||||
memcpy(ptr + 32, challenge_client, 8);
|
||||
if(ntlm->target_info_len)
|
||||
memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
|
||||
|
||||
/* 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);
|
||||
if(result) {
|
||||
free(ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Concatenate the HMAC MD5 output with the BLOB */
|
||||
memcpy(ptr, hmac_output, HMAC_MD5_LENGTH);
|
||||
|
||||
/* Return the response */
|
||||
*ntresp = ptr;
|
||||
*ntresp_len = len;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_ntlm_core_mk_lmv2_resp()
|
||||
*
|
||||
* This creates the LMv2 response as used in the NTLM type-3 message.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* ntlmv2hash [in] - The NTLMv2 hash (16 bytes)
|
||||
* challenge_client [in] - The client nonce (8 bytes)
|
||||
* challenge_client [in] - The server challenge (8 bytes)
|
||||
* lmresp [out] - The LMv2 response (24 bytes)
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
|
||||
unsigned char *challenge_client,
|
||||
unsigned char *challenge_server,
|
||||
unsigned char *lmresp)
|
||||
{
|
||||
unsigned char data[16];
|
||||
unsigned char hmac_output[16];
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
memcpy(&data[0], challenge_server, 8);
|
||||
memcpy(&data[8], challenge_client, 8);
|
||||
|
||||
result = Curl_hmacit(&Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16,
|
||||
hmac_output);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Concatenate the HMAC MD5 output with the client nonce */
|
||||
memcpy(lmresp, hmac_output, 16);
|
||||
memcpy(lmresp + 16, challenge_client, 8);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !USE_WINDOWS_SSPI */
|
||||
|
||||
#endif /* USE_CURL_NTLM_CORE */
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
#ifndef HEADER_CURL_NTLM_CORE_H
|
||||
#define HEADER_CURL_NTLM_CORE_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"
|
||||
|
||||
#ifdef USE_CURL_NTLM_CORE
|
||||
|
||||
#include "vauth/vauth.h"
|
||||
|
||||
struct ntlmdata;
|
||||
|
||||
/* Helpers to generate function byte arguments in little endian order */
|
||||
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
|
||||
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
|
||||
((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
|
||||
|
||||
void Curl_ntlm_core_lm_resp(const unsigned char *keys,
|
||||
const unsigned char *plaintext,
|
||||
unsigned char *results);
|
||||
|
||||
CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
|
||||
unsigned char *lmbuffer /* 21 bytes */);
|
||||
|
||||
CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
|
||||
unsigned char *ntbuffer /* 21 bytes */);
|
||||
|
||||
#ifndef USE_WINDOWS_SSPI
|
||||
|
||||
CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
|
||||
const unsigned char *data, unsigned int datalen,
|
||||
unsigned char *output);
|
||||
|
||||
CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
|
||||
const char *domain, size_t domlen,
|
||||
unsigned char *ntlmhash,
|
||||
unsigned char *ntlmv2hash);
|
||||
|
||||
CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
|
||||
unsigned char *challenge_client,
|
||||
struct ntlmdata *ntlm,
|
||||
unsigned char **ntresp,
|
||||
unsigned int *ntresp_len);
|
||||
|
||||
CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
|
||||
unsigned char *challenge_client,
|
||||
unsigned char *challenge_server,
|
||||
unsigned char *lmresp);
|
||||
|
||||
#endif /* !USE_WINDOWS_SSPI */
|
||||
|
||||
#endif /* USE_CURL_NTLM_CORE */
|
||||
|
||||
#endif /* HEADER_CURL_NTLM_CORE_H */
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef HEADER_CURL_PRINTF_H
|
||||
#define HEADER_CURL_PRINTF_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#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[];
|
||||
|
||||
#endif /* HEADER_CURL_PRINTF_H */
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "curl_range.h"
|
||||
#include "sendf.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)
|
||||
|
||||
/*
|
||||
Check if this is a range download, and if so, set the internal variables
|
||||
properly.
|
||||
*/
|
||||
CURLcode Curl_range(struct Curl_easy *data)
|
||||
{
|
||||
if(data->state.use_range && data->state.range) {
|
||||
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;
|
||||
|
||||
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(!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));
|
||||
}
|
||||
else {
|
||||
/* X-Y */
|
||||
curl_off_t totalsize;
|
||||
|
||||
/* Ensure the range is sensible - to should follow from. */
|
||||
if(from > to)
|
||||
return CURLE_RANGE_ERROR;
|
||||
|
||||
totalsize = to - from;
|
||||
if(totalsize == CURL_OFF_T_MAX)
|
||||
return CURLE_RANGE_ERROR;
|
||||
|
||||
data->req.maxdownload = totalsize + 1; /* include last byte */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(data, "RANGE from %" FMT_OFF_T
|
||||
" getting %" FMT_OFF_T " bytes",
|
||||
from, data->req.maxdownload));
|
||||
}
|
||||
DEBUGF(infof(data, "range-download from %" FMT_OFF_T
|
||||
" to %" FMT_OFF_T ", totally %" FMT_OFF_T " bytes",
|
||||
from, to, data->req.maxdownload));
|
||||
}
|
||||
else
|
||||
data->req.maxdownload = -1;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef HEADER_CURL_RANGE_H
|
||||
#define HEADER_CURL_RANGE_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"
|
||||
#include "urldata.h"
|
||||
|
||||
CURLcode Curl_range(struct Curl_easy *data);
|
||||
#endif /* HEADER_CURL_RANGE_H */
|
||||
Vendored
+393
@@ -0,0 +1,393 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) Howard Chu, <hyc@highlandsun.com>
|
||||
*
|
||||
* 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 USE_LIBRTMP
|
||||
|
||||
#include "curl_rtmp.h"
|
||||
#include "urldata.h"
|
||||
#include "url.h"
|
||||
#include "curlx/nonblock.h" /* for curlx_nonblock */
|
||||
#include "progress.h" /* for Curl_pgrsSetUploadSize */
|
||||
#include "transfer.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include <curl/curl.h>
|
||||
#include <librtmp/rtmp.h>
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(USE_LWIPSOCK)
|
||||
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
|
||||
#define SET_RCVTIMEO(tv,s) int tv = s*1000
|
||||
#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
|
||||
#define SET_RCVTIMEO(tv,s) int tv = s*1000
|
||||
#else
|
||||
#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
|
||||
#endif
|
||||
|
||||
#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);
|
||||
static CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature);
|
||||
static CURLcode rtmp_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode rtmp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn, bool dead);
|
||||
|
||||
static Curl_recv rtmp_recv;
|
||||
static Curl_send rtmp_send;
|
||||
|
||||
/*
|
||||
* RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
|
||||
*/
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmp = {
|
||||
"rtmp", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMP, /* defport */
|
||||
CURLPROTO_RTMP, /* protocol */
|
||||
CURLPROTO_RTMP, /* family */
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmpt = {
|
||||
"rtmpt", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMPT, /* defport */
|
||||
CURLPROTO_RTMPT, /* protocol */
|
||||
CURLPROTO_RTMPT, /* family */
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmpe = {
|
||||
"rtmpe", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMP, /* defport */
|
||||
CURLPROTO_RTMPE, /* protocol */
|
||||
CURLPROTO_RTMPE, /* family */
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmpte = {
|
||||
"rtmpte", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMPT, /* defport */
|
||||
CURLPROTO_RTMPTE, /* protocol */
|
||||
CURLPROTO_RTMPTE, /* family */
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmps = {
|
||||
"rtmps", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMPS, /* defport */
|
||||
CURLPROTO_RTMPS, /* protocol */
|
||||
CURLPROTO_RTMP, /* family */
|
||||
PROTOPT_NONE /* flags */
|
||||
};
|
||||
|
||||
const struct Curl_handler Curl_handler_rtmpts = {
|
||||
"rtmpts", /* scheme */
|
||||
rtmp_setup_connection, /* setup_connection */
|
||||
rtmp_do, /* do_it */
|
||||
rtmp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
rtmp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_pollset */
|
||||
ZERO_NULL, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_RTMPS, /* defport */
|
||||
CURLPROTO_RTMPTS, /* protocol */
|
||||
CURLPROTO_RTMPT, /* family */
|
||||
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 ||
|
||||
Curl_conn_meta_set(conn, CURL_META_RTMP_CONN, r, rtmp_conn_dtor))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
RTMP_Init(r);
|
||||
RTMP_SetBufferMS(r, DEF_BUFTIME);
|
||||
if(!RTMP_SetupURL(r, data->state.url)) {
|
||||
RTMP_Free(r);
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
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
|
||||
* connect request packet
|
||||
*/
|
||||
if(data->state.upload)
|
||||
r->Link.protocol |= RTMP_FEATURE_WRITE;
|
||||
|
||||
/* For plain streams, use the buffer toggle trick to keep data flowing */
|
||||
if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
|
||||
!(r->Link.protocol & RTMP_FEATURE_HTTP))
|
||||
r->Link.lFlags |= RTMP_LF_BUFX;
|
||||
|
||||
(void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
|
||||
setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
|
||||
(char *)&tv, sizeof(tv));
|
||||
|
||||
if(!RTMP_Connect1(r, NULL))
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
/* Clients must send a periodic BytesReceived report to the server */
|
||||
r->m_bSendCounter = TRUE;
|
||||
|
||||
*done = TRUE;
|
||||
conn->recv[FIRSTSOCKET] = rtmp_recv;
|
||||
conn->send[FIRSTSOCKET] = rtmp_send;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
|
||||
|
||||
if(!r || !RTMP_ConnectStream(r, 0))
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(data->state.upload) {
|
||||
Curl_pgrsSetUploadSize(data, data->state.infilesize);
|
||||
Curl_xfer_setup_send(data, FIRSTSOCKET);
|
||||
}
|
||||
else
|
||||
Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
|
||||
bool premature)
|
||||
{
|
||||
(void)data;
|
||||
(void)status;
|
||||
(void)premature;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool dead_connection)
|
||||
{
|
||||
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
|
||||
(void)data;
|
||||
(void)dead_connection;
|
||||
if(r)
|
||||
Curl_conn_meta_remove(conn, CURL_META_RTMP_CONN);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
|
||||
size_t len, size_t *pnread)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nread;
|
||||
|
||||
(void)sockindex;
|
||||
*pnread = 0;
|
||||
if(!r)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
nread = RTMP_Read(r, buf, curlx_uztosi(len));
|
||||
if(nread < 0) {
|
||||
if(r->m_read.status == RTMP_READ_COMPLETE ||
|
||||
r->m_read.status == RTMP_READ_EOF) {
|
||||
data->req.size = data->req.bytecount;
|
||||
}
|
||||
else
|
||||
result = CURLE_RECV_ERROR;
|
||||
}
|
||||
else
|
||||
*pnread = (size_t)nread;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode rtmp_send(struct Curl_easy *data, int sockindex,
|
||||
const void *buf, size_t len, bool eos,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
|
||||
ssize_t nwritten;
|
||||
|
||||
(void)sockindex;
|
||||
(void)eos;
|
||||
*pnwritten = 0;
|
||||
if(!r)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
nwritten = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
|
||||
if(nwritten < 0)
|
||||
return CURLE_SEND_ERROR;
|
||||
|
||||
*pnwritten = (size_t)nwritten;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void Curl_rtmp_version(char *version, size_t len)
|
||||
{
|
||||
char suff[2];
|
||||
if(RTMP_LIB_VERSION & 0xff) {
|
||||
suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
|
||||
suff[1] = '\0';
|
||||
}
|
||||
else
|
||||
suff[0] = '\0';
|
||||
|
||||
curl_msnprintf(version, len, "librtmp/%d.%d%s",
|
||||
RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
|
||||
suff);
|
||||
}
|
||||
|
||||
#endif /* USE_LIBRTMP */
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef HEADER_CURL_RTMP_H
|
||||
#define HEADER_CURL_RTMP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Howard Chu, <hyc@highlandsun.com>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef USE_LIBRTMP
|
||||
extern const struct Curl_handler Curl_handler_rtmp;
|
||||
extern const struct Curl_handler Curl_handler_rtmpt;
|
||||
extern const struct Curl_handler Curl_handler_rtmpe;
|
||||
extern const struct Curl_handler Curl_handler_rtmpte;
|
||||
extern const struct Curl_handler Curl_handler_rtmps;
|
||||
extern const struct Curl_handler Curl_handler_rtmpts;
|
||||
|
||||
void Curl_rtmp_version(char *version, size_t len);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_RTMP_H */
|
||||
Vendored
+948
@@ -0,0 +1,948 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
* RFC2195 CRAM-MD5 authentication
|
||||
* RFC2617 Basic and Digest Access Authentication
|
||||
* RFC2831 DIGEST-MD5 authentication
|
||||
* RFC4422 Simple Authentication and Security Layer (SASL)
|
||||
* RFC4616 PLAIN authentication
|
||||
* RFC5802 SCRAM-SHA-1 authentication
|
||||
* RFC7677 SCRAM-SHA-256 authentication
|
||||
* RFC6749 OAuth 2.0 Authorization Framework
|
||||
* RFC7628 A Set of SASL Mechanisms for OAuth
|
||||
* Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
|
||||
!defined(CURL_DISABLE_POP3) || \
|
||||
(!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
|
||||
#include "curlx/base64.h"
|
||||
#include "vauth/vauth.h"
|
||||
#include "cfilters.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "curl_hmac.h"
|
||||
#include "curl_sasl.h"
|
||||
#include "curlx/warnless.h"
|
||||
#include "sendf.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/* Supported mechanisms */
|
||||
static const struct {
|
||||
const char *name; /* Name */
|
||||
size_t len; /* Name length */
|
||||
unsigned short bit; /* Flag bit */
|
||||
} mechtable[] = {
|
||||
{ "LOGIN", 5, SASL_MECH_LOGIN },
|
||||
{ "PLAIN", 5, SASL_MECH_PLAIN },
|
||||
{ "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
|
||||
{ "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
|
||||
{ "GSSAPI", 6, SASL_MECH_GSSAPI },
|
||||
{ "EXTERNAL", 8, SASL_MECH_EXTERNAL },
|
||||
{ "NTLM", 4, SASL_MECH_NTLM },
|
||||
{ "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
|
||||
{ "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
|
||||
{ "SCRAM-SHA-1", 11, SASL_MECH_SCRAM_SHA_1 },
|
||||
{ "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
|
||||
{ ZERO_NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Curl_sasl_decode_mech()
|
||||
*
|
||||
* Convert a SASL mechanism name into a token.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* ptr [in] - The mechanism string.
|
||||
* maxlen [in] - Maximum mechanism string length.
|
||||
* len [out] - If not NULL, effective name length.
|
||||
*
|
||||
* Returns the SASL mechanism token or 0 if no match.
|
||||
*/
|
||||
unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
|
||||
size_t *len)
|
||||
{
|
||||
unsigned int i;
|
||||
char c;
|
||||
|
||||
for(i = 0; mechtable[i].name; i++) {
|
||||
if(maxlen >= mechtable[i].len &&
|
||||
!memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
|
||||
if(len)
|
||||
*len = mechtable[i].len;
|
||||
|
||||
if(maxlen == mechtable[i].len)
|
||||
return mechtable[i].bit;
|
||||
|
||||
c = ptr[mechtable[i].len];
|
||||
if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
|
||||
return mechtable[i].bit;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_parse_url_auth_option()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
|
||||
const char *value, size_t len)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t mechlen;
|
||||
|
||||
if(!len)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
|
||||
if(sasl->resetprefs) {
|
||||
sasl->resetprefs = FALSE;
|
||||
sasl->prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
|
||||
if(!strncmp(value, "*", len))
|
||||
sasl->prefmech = SASL_AUTH_DEFAULT;
|
||||
else {
|
||||
unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
|
||||
if(mechbit && mechlen == len)
|
||||
sasl->prefmech |= mechbit;
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_init()
|
||||
*
|
||||
* Initializes the SASL structure.
|
||||
*/
|
||||
void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
|
||||
const struct SASLproto *params)
|
||||
{
|
||||
unsigned long auth = data->set.httpauth;
|
||||
|
||||
sasl->params = params; /* Set protocol dependent parameters */
|
||||
sasl->state = SASL_STOP; /* Not yet running */
|
||||
sasl->curmech = NULL; /* No mechanism yet. */
|
||||
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
|
||||
sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
|
||||
sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
|
||||
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
|
||||
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
|
||||
sasl->force_ir = FALSE; /* Respect external option */
|
||||
|
||||
if(auth != CURLAUTH_BASIC) {
|
||||
unsigned short mechs = SASL_AUTH_NONE;
|
||||
|
||||
/* If some usable http authentication options have been set, determine
|
||||
new defaults from them. */
|
||||
if(auth & CURLAUTH_BASIC)
|
||||
mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
|
||||
if(auth & CURLAUTH_DIGEST)
|
||||
mechs |= SASL_MECH_DIGEST_MD5;
|
||||
if(auth & CURLAUTH_NTLM)
|
||||
mechs |= SASL_MECH_NTLM;
|
||||
if(auth & CURLAUTH_BEARER)
|
||||
mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
|
||||
if(auth & CURLAUTH_GSSAPI)
|
||||
mechs |= SASL_MECH_GSSAPI;
|
||||
|
||||
if(mechs != SASL_AUTH_NONE)
|
||||
sasl->prefmech = mechs;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* sasl_state()
|
||||
*
|
||||
* This is the ONLY way to change SASL state!
|
||||
*/
|
||||
static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
|
||||
saslstate newstate)
|
||||
{
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
/* for debug purposes */
|
||||
static const char * const names[]={
|
||||
"STOP",
|
||||
"PLAIN",
|
||||
"LOGIN",
|
||||
"LOGIN_PASSWD",
|
||||
"EXTERNAL",
|
||||
"CRAMMD5",
|
||||
"DIGESTMD5",
|
||||
"DIGESTMD5_RESP",
|
||||
"NTLM",
|
||||
"NTLM_TYPE2MSG",
|
||||
"GSSAPI",
|
||||
"GSSAPI_TOKEN",
|
||||
"GSSAPI_NO_DATA",
|
||||
"OAUTH2",
|
||||
"OAUTH2_RESP",
|
||||
"GSASL",
|
||||
"CANCEL",
|
||||
"FINAL",
|
||||
/* LAST */
|
||||
};
|
||||
|
||||
if(sasl->state != newstate)
|
||||
infof(data, "SASL %p state change from %s to %s",
|
||||
(void *)sasl, names[sasl->state], names[newstate]);
|
||||
#else
|
||||
(void)data;
|
||||
#endif
|
||||
|
||||
sasl->state = newstate;
|
||||
}
|
||||
|
||||
#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \
|
||||
!defined(CURL_DISABLE_DIGEST_AUTH)
|
||||
/* Get the SASL server message and convert it to binary. */
|
||||
static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
|
||||
struct bufref *out)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
result = sasl->params->getmessage(data, out);
|
||||
if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
|
||||
unsigned char *msg;
|
||||
size_t msglen;
|
||||
const char *serverdata = (const char *) Curl_bufref_ptr(out);
|
||||
|
||||
if(!*serverdata || *serverdata == '=')
|
||||
Curl_bufref_set(out, NULL, 0, NULL);
|
||||
else {
|
||||
result = curlx_base64_decode(serverdata, &msg, &msglen);
|
||||
if(!result)
|
||||
Curl_bufref_set(out, msg, msglen, curl_free);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Encode the outgoing SASL message. */
|
||||
static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(sasl->params->flags & SASL_FLAG_BASE64) {
|
||||
if(!Curl_bufref_ptr(msg)) /* Empty message. */
|
||||
Curl_bufref_set(msg, "", 0, NULL);
|
||||
else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
|
||||
Curl_bufref_set(msg, "=", 1, NULL);
|
||||
else {
|
||||
char *base64;
|
||||
size_t 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);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_can_authenticate()
|
||||
*
|
||||
* Check if we have enough auth data and capabilities to authenticate.
|
||||
*/
|
||||
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
|
||||
{
|
||||
/* Have credentials been provided? */
|
||||
if(data->state.aptr.user)
|
||||
return TRUE;
|
||||
|
||||
/* EXTERNAL can authenticate without a username and/or password */
|
||||
if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct sasl_ctx {
|
||||
struct SASL *sasl;
|
||||
struct connectdata *conn;
|
||||
const char *user;
|
||||
unsigned short enabledmechs;
|
||||
const char *mech;
|
||||
saslstate state1;
|
||||
saslstate state2;
|
||||
struct bufref resp;
|
||||
CURLcode result;
|
||||
};
|
||||
|
||||
static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) {
|
||||
sctx->mech = SASL_MECH_STRING_EXTERNAL;
|
||||
sctx->state1 = SASL_EXTERNAL;
|
||||
sctx->sasl->authused = SASL_MECH_EXTERNAL;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir)
|
||||
Curl_auth_create_external_message(sctx->conn->user, &sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef USE_KERBEROS5
|
||||
static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
if(sctx->user &&
|
||||
(sctx->enabledmechs & SASL_MECH_GSSAPI) &&
|
||||
Curl_auth_is_gssapi_supported() &&
|
||||
Curl_auth_user_contains_domain(sctx->conn->user)) {
|
||||
const char *service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] :
|
||||
sctx->sasl->params->service;
|
||||
|
||||
sctx->sasl->mutual_auth = FALSE;
|
||||
sctx->mech = SASL_MECH_STRING_GSSAPI;
|
||||
sctx->state1 = SASL_GSSAPI;
|
||||
sctx->state2 = SASL_GSSAPI_TOKEN;
|
||||
sctx->sasl->authused = SASL_MECH_GSSAPI;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir) {
|
||||
struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
|
||||
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
|
||||
sctx->conn->passwd,
|
||||
service, sctx->conn->host.name,
|
||||
sctx->sasl->mutual_auth, NULL,
|
||||
krb5, &sctx->resp);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* USE_KERBEROS5 */
|
||||
|
||||
#ifdef USE_GSASL
|
||||
static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
struct gsasldata *gsasl;
|
||||
struct bufref nullmsg;
|
||||
|
||||
if(sctx->user &&
|
||||
(sctx->enabledmechs & (SASL_MECH_SCRAM_SHA_256|SASL_MECH_SCRAM_SHA_1))) {
|
||||
gsasl = Curl_auth_gsasl_get(sctx->conn);
|
||||
if(!gsasl) {
|
||||
sctx->result = CURLE_OUT_OF_MEMORY;
|
||||
return TRUE; /* attempted, but failed */
|
||||
}
|
||||
|
||||
if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
|
||||
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
|
||||
gsasl)) {
|
||||
sctx->mech = SASL_MECH_STRING_SCRAM_SHA_256;
|
||||
sctx->sasl->authused = SASL_MECH_SCRAM_SHA_256;
|
||||
}
|
||||
else if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
|
||||
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
|
||||
gsasl)) {
|
||||
sctx->mech = SASL_MECH_STRING_SCRAM_SHA_1;
|
||||
sctx->sasl->authused = SASL_MECH_SCRAM_SHA_1;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
Curl_bufref_init(&nullmsg);
|
||||
sctx->state1 = SASL_GSASL;
|
||||
sctx->state2 = SASL_GSASL;
|
||||
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user,
|
||||
sctx->conn->passwd, gsasl);
|
||||
if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
|
||||
sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* USE_GSASL */
|
||||
|
||||
#ifndef CURL_DISABLE_DIGEST_AUTH
|
||||
static bool sasl_choose_digest(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
(void)data;
|
||||
if(!sctx->user)
|
||||
return FALSE;
|
||||
else if((sctx->enabledmechs & SASL_MECH_DIGEST_MD5) &&
|
||||
Curl_auth_is_digest_supported()) {
|
||||
sctx->mech = SASL_MECH_STRING_DIGEST_MD5;
|
||||
sctx->state1 = SASL_DIGESTMD5;
|
||||
sctx->sasl->authused = SASL_MECH_DIGEST_MD5;
|
||||
return TRUE;
|
||||
}
|
||||
else if(sctx->enabledmechs & SASL_MECH_CRAM_MD5) {
|
||||
sctx->mech = SASL_MECH_STRING_CRAM_MD5;
|
||||
sctx->state1 = SASL_CRAMMD5;
|
||||
sctx->sasl->authused = SASL_MECH_CRAM_MD5;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_DIGEST_AUTH */
|
||||
|
||||
#ifdef USE_NTLM
|
||||
static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
if(!sctx->user)
|
||||
return FALSE;
|
||||
else if((sctx->enabledmechs & SASL_MECH_NTLM) &&
|
||||
Curl_auth_is_ntlm_supported()) {
|
||||
const char *service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] :
|
||||
sctx->sasl->params->service;
|
||||
const char *hostname;
|
||||
int port;
|
||||
|
||||
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
|
||||
|
||||
sctx->mech = SASL_MECH_STRING_NTLM;
|
||||
sctx->state1 = SASL_NTLM;
|
||||
sctx->state2 = SASL_NTLM_TYPE2MSG;
|
||||
sctx->sasl->authused = SASL_MECH_NTLM;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir) {
|
||||
struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
|
||||
sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_ntlm_type1_message(data,
|
||||
sctx->conn->user,
|
||||
sctx->conn->passwd,
|
||||
service, hostname,
|
||||
ntlm, &sctx->resp);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* USE_NTLM */
|
||||
|
||||
static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
const char *oauth_bearer = data->set.str[STRING_BEARER];
|
||||
|
||||
if(sctx->user && oauth_bearer &&
|
||||
(sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
|
||||
const char *hostname;
|
||||
int port;
|
||||
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
|
||||
|
||||
sctx->mech = SASL_MECH_STRING_OAUTHBEARER;
|
||||
sctx->state1 = SASL_OAUTH2;
|
||||
sctx->state2 = SASL_OAUTH2_RESP;
|
||||
sctx->sasl->authused = SASL_MECH_OAUTHBEARER;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir)
|
||||
sctx->result =
|
||||
Curl_auth_create_oauth_bearer_message(sctx->conn->user,
|
||||
hostname, port,
|
||||
oauth_bearer, &sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
const char *oauth_bearer = data->set.str[STRING_BEARER];
|
||||
|
||||
if(sctx->user && oauth_bearer &&
|
||||
(sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
|
||||
sctx->mech = SASL_MECH_STRING_XOAUTH2;
|
||||
sctx->state1 = SASL_OAUTH2;
|
||||
sctx->sasl->authused = SASL_MECH_XOAUTH2;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir)
|
||||
sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user,
|
||||
oauth_bearer,
|
||||
&sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
if(sctx->user && (sctx->enabledmechs & SASL_MECH_PLAIN)) {
|
||||
sctx->mech = SASL_MECH_STRING_PLAIN;
|
||||
sctx->state1 = SASL_PLAIN;
|
||||
sctx->sasl->authused = SASL_MECH_PLAIN;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir)
|
||||
sctx->result =
|
||||
Curl_auth_create_plain_message(sctx->conn->sasl_authzid,
|
||||
sctx->conn->user, sctx->conn->passwd,
|
||||
&sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
|
||||
{
|
||||
if(sctx->user && (sctx->enabledmechs & SASL_MECH_LOGIN)) {
|
||||
sctx->mech = SASL_MECH_STRING_LOGIN;
|
||||
sctx->state1 = SASL_LOGIN;
|
||||
sctx->state2 = SASL_LOGIN_PASSWD;
|
||||
sctx->sasl->authused = SASL_MECH_LOGIN;
|
||||
|
||||
if(sctx->sasl->force_ir || data->set.sasl_ir)
|
||||
Curl_auth_create_login_message(sctx->conn->user, &sctx->resp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_start()
|
||||
*
|
||||
* Calculate the required login details for SASL authentication.
|
||||
*/
|
||||
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
|
||||
bool force_ir, saslprogress *progress)
|
||||
{
|
||||
struct sasl_ctx sctx;
|
||||
|
||||
sasl->force_ir = force_ir; /* Latch for future use */
|
||||
sasl->authused = 0; /* No mechanism used yet */
|
||||
*progress = SASL_IDLE;
|
||||
|
||||
memset(&sctx, 0, sizeof(sctx));
|
||||
sctx.sasl = sasl;
|
||||
sctx.conn = data->conn;
|
||||
sctx.user = data->state.aptr.user;
|
||||
Curl_bufref_init(&sctx.resp);
|
||||
sctx.enabledmechs = sasl->authmechs & sasl->prefmech;
|
||||
sctx.state1 = SASL_STOP;
|
||||
sctx.state2 = SASL_FINAL;
|
||||
|
||||
/* Calculate the supported authentication mechanism, by decreasing order of
|
||||
security, as well as the initial response where appropriate */
|
||||
if(sasl_choose_external(data, &sctx) ||
|
||||
#ifdef USE_KERBEROS5
|
||||
sasl_choose_krb5(data, &sctx) ||
|
||||
#endif
|
||||
#ifdef USE_GSASL
|
||||
sasl_choose_gsasl(data, &sctx) ||
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_DIGEST_AUTH
|
||||
sasl_choose_digest(data, &sctx) ||
|
||||
#endif
|
||||
#ifdef USE_NTLM
|
||||
sasl_choose_ntlm(data, &sctx) ||
|
||||
#endif
|
||||
sasl_choose_oauth(data, &sctx) ||
|
||||
sasl_choose_oauth2(data, &sctx) ||
|
||||
sasl_choose_plain(data, &sctx) ||
|
||||
sasl_choose_login(data, &sctx)) {
|
||||
/* selected, either we have a mechanism or a failure */
|
||||
DEBUGASSERT(sctx.mech || sctx.result);
|
||||
}
|
||||
|
||||
if(!sctx.result && sctx.mech) {
|
||||
sasl->curmech = sctx.mech;
|
||||
if(Curl_bufref_ptr(&sctx.resp))
|
||||
sctx.result = build_message(sasl, &sctx.resp);
|
||||
|
||||
if(sasl->params->maxirlen &&
|
||||
strlen(sctx.mech) + Curl_bufref_len(&sctx.resp) >
|
||||
sasl->params->maxirlen)
|
||||
Curl_bufref_free(&sctx.resp);
|
||||
|
||||
if(!sctx.result)
|
||||
sctx.result = sasl->params->sendauth(data, sctx.mech, &sctx.resp);
|
||||
|
||||
if(!sctx.result) {
|
||||
*progress = SASL_INPROGRESS;
|
||||
sasl_state(sasl, data, Curl_bufref_ptr(&sctx.resp) ?
|
||||
sctx.state2 : sctx.state1);
|
||||
}
|
||||
}
|
||||
|
||||
Curl_bufref_free(&sctx.resp);
|
||||
return sctx.result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_continue()
|
||||
*
|
||||
* Continue the authentication.
|
||||
*/
|
||||
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
int code, saslprogress *progress)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct connectdata *conn = data->conn;
|
||||
saslstate newstate = SASL_FINAL;
|
||||
struct bufref resp;
|
||||
const char *hostname;
|
||||
int port;
|
||||
#if defined(USE_KERBEROS5) || defined(USE_NTLM) || \
|
||||
!defined(CURL_DISABLE_DIGEST_AUTH)
|
||||
const char *service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] :
|
||||
sasl->params->service;
|
||||
#endif
|
||||
const char *oauth_bearer = data->set.str[STRING_BEARER];
|
||||
struct bufref serverdata;
|
||||
|
||||
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
|
||||
Curl_bufref_init(&serverdata);
|
||||
Curl_bufref_init(&resp);
|
||||
*progress = SASL_INPROGRESS;
|
||||
|
||||
if(sasl->state == SASL_FINAL) {
|
||||
if(code != sasl->params->finalcode)
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
*progress = SASL_DONE;
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
|
||||
code != sasl->params->contcode) {
|
||||
*progress = SASL_DONE;
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
switch(sasl->state) {
|
||||
case SASL_STOP:
|
||||
*progress = SASL_DONE;
|
||||
return result;
|
||||
case SASL_PLAIN:
|
||||
result = Curl_auth_create_plain_message(conn->sasl_authzid,
|
||||
conn->user, conn->passwd, &resp);
|
||||
break;
|
||||
case SASL_LOGIN:
|
||||
Curl_auth_create_login_message(conn->user, &resp);
|
||||
newstate = SASL_LOGIN_PASSWD;
|
||||
break;
|
||||
case SASL_LOGIN_PASSWD:
|
||||
Curl_auth_create_login_message(conn->passwd, &resp);
|
||||
break;
|
||||
case SASL_EXTERNAL:
|
||||
Curl_auth_create_external_message(conn->user, &resp);
|
||||
break;
|
||||
#ifdef USE_GSASL
|
||||
case SASL_GSASL:
|
||||
result = get_server_message(sasl, data, &serverdata);
|
||||
if(!result) {
|
||||
struct gsasldata *gsasl = Curl_auth_gsasl_get(conn);
|
||||
result = !gsasl ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_gsasl_token(data, &serverdata, gsasl, &resp);
|
||||
}
|
||||
if(!result && Curl_bufref_len(&resp) > 0)
|
||||
newstate = SASL_GSASL;
|
||||
break;
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_DIGEST_AUTH
|
||||
case SASL_CRAMMD5:
|
||||
result = get_server_message(sasl, data, &serverdata);
|
||||
if(!result)
|
||||
result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
|
||||
conn->passwd, &resp);
|
||||
break;
|
||||
case SASL_DIGESTMD5:
|
||||
result = get_server_message(sasl, data, &serverdata);
|
||||
if(!result)
|
||||
result = Curl_auth_create_digest_md5_message(data, &serverdata,
|
||||
conn->user, conn->passwd,
|
||||
service, &resp);
|
||||
if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
|
||||
newstate = SASL_DIGESTMD5_RESP;
|
||||
break;
|
||||
case SASL_DIGESTMD5_RESP:
|
||||
/* Keep response NULL to output an empty line. */
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef USE_NTLM
|
||||
case SASL_NTLM: {
|
||||
/* Create the type-1 message */
|
||||
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
|
||||
result = !ntlm ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_ntlm_type1_message(data,
|
||||
conn->user, conn->passwd,
|
||||
service, hostname,
|
||||
ntlm, &resp);
|
||||
newstate = SASL_NTLM_TYPE2MSG;
|
||||
break;
|
||||
}
|
||||
case SASL_NTLM_TYPE2MSG: {
|
||||
/* Decode the type-2 message */
|
||||
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
|
||||
result = !ntlm ? CURLE_FAILED_INIT :
|
||||
get_server_message(sasl, data, &serverdata);
|
||||
if(!result)
|
||||
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
|
||||
if(!result)
|
||||
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
|
||||
conn->passwd, ntlm,
|
||||
&resp);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_KERBEROS5
|
||||
case SASL_GSSAPI: {
|
||||
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
|
||||
result = !krb5 ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd,
|
||||
service, conn->host.name,
|
||||
sasl->mutual_auth, NULL,
|
||||
krb5, &resp);
|
||||
newstate = SASL_GSSAPI_TOKEN;
|
||||
break;
|
||||
}
|
||||
case SASL_GSSAPI_TOKEN:
|
||||
result = get_server_message(sasl, data, &serverdata);
|
||||
if(!result) {
|
||||
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
|
||||
if(!krb5)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
else if(sasl->mutual_auth) {
|
||||
/* Decode the user token challenge and create the optional response
|
||||
message */
|
||||
result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
|
||||
NULL, NULL,
|
||||
sasl->mutual_auth,
|
||||
&serverdata,
|
||||
krb5, &resp);
|
||||
newstate = SASL_GSSAPI_NO_DATA;
|
||||
}
|
||||
else
|
||||
/* Decode the security challenge and create the response message */
|
||||
result = Curl_auth_create_gssapi_security_message(data,
|
||||
conn->sasl_authzid,
|
||||
&serverdata,
|
||||
krb5, &resp);
|
||||
}
|
||||
break;
|
||||
case SASL_GSSAPI_NO_DATA:
|
||||
/* Decode the security challenge and create the response message */
|
||||
result = get_server_message(sasl, data, &serverdata);
|
||||
if(!result) {
|
||||
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
|
||||
if(!krb5)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
else
|
||||
result = Curl_auth_create_gssapi_security_message(data,
|
||||
conn->sasl_authzid,
|
||||
&serverdata,
|
||||
krb5, &resp);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SASL_OAUTH2:
|
||||
/* Create the authorization message */
|
||||
if(sasl->authused == SASL_MECH_OAUTHBEARER) {
|
||||
result = Curl_auth_create_oauth_bearer_message(conn->user,
|
||||
hostname,
|
||||
port,
|
||||
oauth_bearer,
|
||||
&resp);
|
||||
|
||||
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
|
||||
newstate = SASL_OAUTH2_RESP;
|
||||
}
|
||||
else
|
||||
result = Curl_auth_create_xoauth_bearer_message(conn->user,
|
||||
oauth_bearer,
|
||||
&resp);
|
||||
break;
|
||||
|
||||
case SASL_OAUTH2_RESP:
|
||||
/* The continuation is optional so check the response code */
|
||||
if(code == sasl->params->finalcode) {
|
||||
/* Final response was received so we are done */
|
||||
*progress = SASL_DONE;
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return result;
|
||||
}
|
||||
else if(code == sasl->params->contcode) {
|
||||
/* Acknowledge the continuation by sending a 0x01 response. */
|
||||
Curl_bufref_set(&resp, "\x01", 1, NULL);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
*progress = SASL_DONE;
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
case SASL_CANCEL:
|
||||
/* Remove the offending mechanism from the supported list */
|
||||
sasl->authmechs &= (unsigned short)~sasl->authused;
|
||||
sasl->authused = SASL_AUTH_NONE;
|
||||
sasl->curmech = NULL;
|
||||
|
||||
/* Start an alternative SASL authentication */
|
||||
return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
|
||||
default:
|
||||
failf(data, "Unsupported SASL authentication mechanism");
|
||||
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
|
||||
break;
|
||||
}
|
||||
|
||||
Curl_bufref_free(&serverdata);
|
||||
|
||||
switch(result) {
|
||||
case CURLE_BAD_CONTENT_ENCODING:
|
||||
/* Cancel dialog */
|
||||
result = sasl->params->cancelauth(data, sasl->curmech);
|
||||
newstate = SASL_CANCEL;
|
||||
break;
|
||||
case CURLE_OK:
|
||||
result = build_message(sasl, &resp);
|
||||
if(!result)
|
||||
result = sasl->params->contauth(data, sasl->curmech, &resp);
|
||||
break;
|
||||
default:
|
||||
newstate = SASL_STOP; /* Stop on error */
|
||||
*progress = SASL_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
Curl_bufref_free(&resp);
|
||||
|
||||
sasl_state(sasl, data, newstate);
|
||||
|
||||
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 */
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
#ifndef HEADER_CURL_SASL_H
|
||||
#define HEADER_CURL_SASL_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/curl.h>
|
||||
|
||||
#include "bufref.h"
|
||||
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
|
||||
/* Authentication mechanism flags */
|
||||
#define SASL_MECH_LOGIN (1 << 0)
|
||||
#define SASL_MECH_PLAIN (1 << 1)
|
||||
#define SASL_MECH_CRAM_MD5 (1 << 2)
|
||||
#define SASL_MECH_DIGEST_MD5 (1 << 3)
|
||||
#define SASL_MECH_GSSAPI (1 << 4)
|
||||
#define SASL_MECH_EXTERNAL (1 << 5)
|
||||
#define SASL_MECH_NTLM (1 << 6)
|
||||
#define SASL_MECH_XOAUTH2 (1 << 7)
|
||||
#define SASL_MECH_OAUTHBEARER (1 << 8)
|
||||
#define SASL_MECH_SCRAM_SHA_1 (1 << 9)
|
||||
#define SASL_MECH_SCRAM_SHA_256 (1 << 10)
|
||||
|
||||
/* Authentication mechanism values */
|
||||
#define SASL_AUTH_NONE 0
|
||||
#define SASL_AUTH_ANY 0xffff
|
||||
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
|
||||
|
||||
/* Authentication mechanism strings */
|
||||
#define SASL_MECH_STRING_LOGIN "LOGIN"
|
||||
#define SASL_MECH_STRING_PLAIN "PLAIN"
|
||||
#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
|
||||
#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
|
||||
#define SASL_MECH_STRING_GSSAPI "GSSAPI"
|
||||
#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
|
||||
#define SASL_MECH_STRING_NTLM "NTLM"
|
||||
#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
|
||||
#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
|
||||
#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
|
||||
#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
|
||||
|
||||
/* SASL flags */
|
||||
#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */
|
||||
|
||||
/* SASL machine states */
|
||||
typedef enum {
|
||||
SASL_STOP,
|
||||
SASL_PLAIN,
|
||||
SASL_LOGIN,
|
||||
SASL_LOGIN_PASSWD,
|
||||
SASL_EXTERNAL,
|
||||
SASL_CRAMMD5,
|
||||
SASL_DIGESTMD5,
|
||||
SASL_DIGESTMD5_RESP,
|
||||
SASL_NTLM,
|
||||
SASL_NTLM_TYPE2MSG,
|
||||
SASL_GSSAPI,
|
||||
SASL_GSSAPI_TOKEN,
|
||||
SASL_GSSAPI_NO_DATA,
|
||||
SASL_OAUTH2,
|
||||
SASL_OAUTH2_RESP,
|
||||
SASL_GSASL,
|
||||
SASL_CANCEL,
|
||||
SASL_FINAL
|
||||
} saslstate;
|
||||
|
||||
/* Progress indicator */
|
||||
typedef enum {
|
||||
SASL_IDLE,
|
||||
SASL_INPROGRESS,
|
||||
SASL_DONE
|
||||
} saslprogress;
|
||||
|
||||
/* Protocol dependent SASL parameters */
|
||||
struct SASLproto {
|
||||
const char *service; /* The service name */
|
||||
CURLcode (*sendauth)(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *ir);
|
||||
/* Send authentication command */
|
||||
CURLcode (*contauth)(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *contauth);
|
||||
/* Send authentication continuation */
|
||||
CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech);
|
||||
/* Cancel authentication. */
|
||||
CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out);
|
||||
/* Get SASL response message */
|
||||
size_t maxirlen; /* Maximum initial response + mechanism length,
|
||||
or zero if no max. This is normally the max
|
||||
command length - other characters count.
|
||||
This has to be zero for non-base64 protocols. */
|
||||
int contcode; /* Code to receive when continuation is expected */
|
||||
int finalcode; /* Code to receive upon authentication success */
|
||||
unsigned short defmechs; /* Mechanisms enabled by default */
|
||||
unsigned short flags; /* Configuration flags. */
|
||||
};
|
||||
|
||||
/* Per-connection parameters */
|
||||
struct SASL {
|
||||
const struct SASLproto *params; /* Protocol dependent parameters */
|
||||
saslstate state; /* Current machine state */
|
||||
const char *curmech; /* Current mechanism id. */
|
||||
unsigned short authmechs; /* Accepted authentication mechanisms */
|
||||
unsigned short prefmech; /* Preferred authentication mechanism */
|
||||
unsigned short authused; /* Auth mechanism used for the connection */
|
||||
BIT(resetprefs); /* For URL auth option parsing. */
|
||||
BIT(mutual_auth); /* Mutual authentication enabled (GSSAPI only) */
|
||||
BIT(force_ir); /* Protocol always supports initial response */
|
||||
};
|
||||
|
||||
/* This is used to test whether the line starts with the given mechanism */
|
||||
#define sasl_mech_equal(line, wordlen, mech) \
|
||||
(wordlen == (sizeof(mech) - 1) / sizeof(char) && \
|
||||
!memcmp(line, mech, wordlen))
|
||||
|
||||
/* Convert a mechanism name to a token */
|
||||
unsigned short Curl_sasl_decode_mech(const char *ptr,
|
||||
size_t maxlen, size_t *len);
|
||||
|
||||
/* Parse the URL login options */
|
||||
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
|
||||
const char *value, size_t len);
|
||||
|
||||
/* Initializes an SASL structure */
|
||||
void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
|
||||
const struct SASLproto *params);
|
||||
|
||||
/* Check if we have enough auth data and capabilities to authenticate */
|
||||
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data);
|
||||
|
||||
/* Calculate the required login details for SASL authentication */
|
||||
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
|
||||
bool force_ir, saslprogress *progress);
|
||||
|
||||
/* Continue an SASL authentication */
|
||||
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 */
|
||||
+1209
File diff suppressed because it is too large
Load Diff
+374
@@ -0,0 +1,374 @@
|
||||
#ifndef HEADER_CURL_SETUP_ONCE_H
|
||||
#define HEADER_CURL_SETUP_ONCE_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Inclusion of common header files.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if !defined(_WIN32) || defined(__MINGW32__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.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. */
|
||||
# define SCHANNEL_USE_BLACKLISTS 1
|
||||
#endif
|
||||
|
||||
#ifdef __hpux
|
||||
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
|
||||
# ifdef _APP32_64BIT_OFF_T
|
||||
# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
|
||||
# undef _APP32_64BIT_OFF_T
|
||||
# else
|
||||
# undef OLD_APP32_64BIT_OFF_T
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "functypes.h"
|
||||
|
||||
#ifdef __hpux
|
||||
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
|
||||
# ifdef OLD_APP32_64BIT_OFF_T
|
||||
# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
|
||||
# undef OLD_APP32_64BIT_OFF_T
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Definition of timeval struct for platforms that do not have it.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_STRUCT_TIMEVAL
|
||||
struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* If we have the MSG_NOSIGNAL define, make sure we use
|
||||
* it as the fourth argument of function send()
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MSG_NOSIGNAL
|
||||
#define SEND_4TH_ARG MSG_NOSIGNAL
|
||||
#else
|
||||
#define SEND_4TH_ARG 0
|
||||
#endif
|
||||
|
||||
|
||||
#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), \
|
||||
(RECV_TYPE_ARG3)(z))
|
||||
|
||||
#elif defined(HAVE_RECV)
|
||||
/*
|
||||
* The definitions for the return type and arguments types
|
||||
* of functions recv() and send() belong and come from the
|
||||
* configuration file. Do not define them in any other place.
|
||||
*
|
||||
* HAVE_RECV is defined if you have a function named recv()
|
||||
* which is used to read incoming data from sockets. If your
|
||||
* function has another name then do not define HAVE_RECV.
|
||||
*
|
||||
* If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
|
||||
* RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
|
||||
* be defined.
|
||||
*
|
||||
* HAVE_SEND is defined if you have a function named send()
|
||||
* which is used to write outgoing data on a connected socket.
|
||||
* If yours has another name then do not define HAVE_SEND.
|
||||
*
|
||||
* If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
|
||||
* SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
|
||||
* SEND_TYPE_RETV must also be defined.
|
||||
*/
|
||||
|
||||
#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
|
||||
(RECV_TYPE_ARG2)(y), \
|
||||
(RECV_TYPE_ARG3)(z), \
|
||||
(RECV_TYPE_ARG4)(0))
|
||||
#else /* HAVE_RECV */
|
||||
#ifndef sread
|
||||
#error "Missing definition of macro sread!"
|
||||
#endif
|
||||
#endif /* HAVE_RECV */
|
||||
|
||||
|
||||
#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)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)CURL_UNCONST(y), \
|
||||
(SEND_TYPE_ARG3)(z), \
|
||||
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
|
||||
#else /* HAVE_SEND */
|
||||
#ifndef swrite
|
||||
#error "Missing definition of macro swrite!"
|
||||
#endif
|
||||
#endif /* HAVE_SEND */
|
||||
|
||||
|
||||
/*
|
||||
* Function-like macro definition used to close a socket.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CLOSESOCKET
|
||||
# define CURL_SCLOSE(x) closesocket((x))
|
||||
#elif defined(HAVE_CLOSESOCKET_CAMEL)
|
||||
# define CURL_SCLOSE(x) CloseSocket((x))
|
||||
#elif defined(MSDOS) /* Watt-32 */
|
||||
# define CURL_SCLOSE(x) close_s((x))
|
||||
#elif defined(USE_LWIPSOCK)
|
||||
# define CURL_SCLOSE(x) lwip_close((x))
|
||||
#else
|
||||
# define CURL_SCLOSE(x) close((x))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Stack-independent version of fcntl() on sockets:
|
||||
*/
|
||||
#ifdef USE_LWIPSOCK
|
||||
# define sfcntl lwip_fcntl
|
||||
#else
|
||||
# define sfcntl fcntl
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 'bool' stuff compatible with HP-UX headers.
|
||||
*/
|
||||
|
||||
#if defined(__hpux) && !defined(HAVE_BOOL_T)
|
||||
typedef int bool;
|
||||
# define false 0
|
||||
# define true 1
|
||||
# define HAVE_BOOL_T
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
|
||||
* On non-C99 platforms there is no bool, so define an enum for that.
|
||||
* On C99 platforms 'false' and 'true' also exist. Enum uses a
|
||||
* global namespace though, so use bool_false and bool_true.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_BOOL_T
|
||||
typedef enum {
|
||||
bool_false = 0,
|
||||
bool_true = 1
|
||||
} bool;
|
||||
|
||||
/*
|
||||
* Use a define to let 'true' and 'false' use those enums. There
|
||||
* are currently no use of true and false in libcurl proper, but
|
||||
* there are some in the examples. This will cater for any later
|
||||
* code happening to use true and false.
|
||||
*/
|
||||
# define false bool_false
|
||||
# define true bool_true
|
||||
# define HAVE_BOOL_T
|
||||
#endif
|
||||
|
||||
/* the type we use for storing a single boolean bit */
|
||||
#ifdef _MSC_VER
|
||||
typedef bool bit;
|
||||
#define BIT(x) bool x
|
||||
#else
|
||||
typedef unsigned int bit;
|
||||
#define BIT(x) bit x:1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Redefine TRUE and FALSE too, to catch current use. With this
|
||||
* change, 'bool found = 1' will give a warning on MIPSPro, but
|
||||
* 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro,
|
||||
* AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too.
|
||||
*/
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#include "curl_ctype.h"
|
||||
|
||||
|
||||
/*
|
||||
* Macro used to include code only in debug builds.
|
||||
*/
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
#define DEBUGF(x) x
|
||||
#else
|
||||
#define DEBUGF(x) do { } while(0)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Macro used to include assertion code only in debug builds.
|
||||
*/
|
||||
|
||||
#undef DEBUGASSERT
|
||||
#ifdef DEBUGBUILD
|
||||
#define DEBUGASSERT(x) assert(x)
|
||||
#else
|
||||
#define DEBUGASSERT(x) do { } while(0)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
|
||||
* (or equivalent) on this platform to hide platform details to code using it.
|
||||
*/
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
#define SOCKERRNO ((int)WSAGetLastError())
|
||||
#define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
|
||||
#else
|
||||
#define SOCKERRNO (errno)
|
||||
#define SET_SOCKERRNO(x) (errno = (x))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Portable error number symbolic names defined to Winsock error codes.
|
||||
*/
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
#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 SOCKEWOULDBLOCK EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macro argv_item_t hides platform details to code using it.
|
||||
*/
|
||||
|
||||
#ifdef __VMS
|
||||
#define argv_item_t __char_ptr32
|
||||
#elif defined(_UNICODE) && !defined(UNDER_CE)
|
||||
#define argv_item_t wchar_t *
|
||||
#else
|
||||
#define argv_item_t char *
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* We use this ZERO_NULL to avoid picky compiler warnings,
|
||||
* when assigning a NULL pointer to a function pointer var.
|
||||
*/
|
||||
|
||||
#define ZERO_NULL 0
|
||||
|
||||
|
||||
#endif /* HEADER_CURL_SETUP_ONCE_H */
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#ifndef HEADER_CURL_SHA256_H
|
||||
#define HEADER_CURL_SHA256_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
|
||||
defined(USE_LIBSSH2) || defined(USE_SSL)
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "curl_hmac.h"
|
||||
|
||||
extern const struct HMAC_params Curl_HMAC_SHA256;
|
||||
|
||||
#ifndef CURL_SHA256_DIGEST_LENGTH
|
||||
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
|
||||
#endif
|
||||
|
||||
CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
|
||||
const size_t len);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_SHA256_H */
|
||||
+826
@@ -0,0 +1,826 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_DIGEST_AUTH) && !defined(CURL_DISABLE_SHA512_256)
|
||||
|
||||
#include "curl_sha512_256.h"
|
||||
#include "curlx/warnless.h"
|
||||
|
||||
/* The recommended order of the TLS backends:
|
||||
* * OpenSSL
|
||||
* * GnuTLS
|
||||
* * wolfSSL
|
||||
* * Schannel SSPI
|
||||
* * mbedTLS
|
||||
* * Rustls
|
||||
* Skip the backend if it does not support the required algorithm */
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
# include <openssl/opensslv.h>
|
||||
# if (!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10101000L) || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER >= 0x3080000fL)
|
||||
# include <openssl/opensslconf.h>
|
||||
# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512)
|
||||
# include <openssl/evp.h>
|
||||
# define USE_OPENSSL_SHA512_256 1
|
||||
# define HAS_SHA512_256_IMPLEMENTATION 1
|
||||
# ifdef __NetBSD__
|
||||
/* Some NetBSD versions has a bug in SHA-512/256.
|
||||
* See https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039
|
||||
* The problematic versions:
|
||||
* - NetBSD before 9.4
|
||||
* - NetBSD 9 all development versions (9.99.x)
|
||||
* - NetBSD 10 development versions (10.99.x) before 10.99.11
|
||||
* The bug was fixed in NetBSD 9.4 release, NetBSD 10.0 release,
|
||||
* NetBSD 10.99.11 development.
|
||||
* It is safe to apply the workaround even if the bug is not present, as
|
||||
* the workaround just reduces performance slightly. */
|
||||
# include <sys/param.h>
|
||||
# if __NetBSD_Version__ < 904000000 || \
|
||||
(__NetBSD_Version__ >= 999000000 && \
|
||||
__NetBSD_Version__ < 1000000000) || \
|
||||
(__NetBSD_Version__ >= 1099000000 && \
|
||||
__NetBSD_Version__ < 1099001100)
|
||||
# define NEED_NETBSD_SHA512_256_WORKAROUND 1
|
||||
# include <string.h>
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif /* USE_OPENSSL */
|
||||
|
||||
|
||||
#if !defined(HAS_SHA512_256_IMPLEMENTATION) && defined(USE_GNUTLS)
|
||||
# include <nettle/sha.h>
|
||||
# ifdef SHA512_256_DIGEST_SIZE
|
||||
# define USE_GNUTLS_SHA512_256 1
|
||||
# endif
|
||||
#endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */
|
||||
|
||||
#ifdef USE_OPENSSL_SHA512_256
|
||||
|
||||
/* OpenSSL does not provide macros for SHA-512/256 sizes */
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 single processing block in bytes.
|
||||
*/
|
||||
#define CURL_SHA512_256_BLOCK_SIZE 128
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 resulting digest in bytes.
|
||||
* This is the final digest size, not intermediate hash.
|
||||
*/
|
||||
#define CURL_SHA512_256_DIGEST_SIZE CURL_SHA512_256_DIGEST_LENGTH
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef EVP_MD_CTX *Curl_sha512_256_ctx;
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_init(void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
*ctx = EVP_MD_CTX_create();
|
||||
if(!*ctx)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(EVP_DigestInit_ex(*ctx, EVP_sha512_256(), NULL)) {
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(EVP_MD_CTX_size(*ctx) == CURL_SHA512_256_DIGEST_SIZE);
|
||||
/* Check whether the block size is correct */
|
||||
DEBUGASSERT(EVP_MD_CTX_block_size(*ctx) == CURL_SHA512_256_BLOCK_SIZE);
|
||||
|
||||
return CURLE_OK; /* Success */
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
EVP_MD_CTX_destroy(*ctx);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process portion of bytes.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
if(!EVP_DigestUpdate(*ctx, data, length))
|
||||
return CURLE_SSL_CIPHER;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise SHA-512/256 calculation, return digest.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
|
||||
# bytes
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
|
||||
{
|
||||
CURLcode ret;
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
#ifdef NEED_NETBSD_SHA512_256_WORKAROUND
|
||||
/* Use a larger buffer to work around a bug in NetBSD:
|
||||
https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039 */
|
||||
unsigned char tmp_digest[CURL_SHA512_256_DIGEST_SIZE * 2];
|
||||
ret = EVP_DigestFinal_ex(*ctx,
|
||||
tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
|
||||
if(ret == CURLE_OK)
|
||||
memcpy(digest, tmp_digest, CURL_SHA512_256_DIGEST_SIZE);
|
||||
explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
|
||||
#else /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
|
||||
ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
|
||||
#endif /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
|
||||
|
||||
EVP_MD_CTX_destroy(*ctx);
|
||||
*ctx = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS_SHA512_256)
|
||||
|
||||
#define CURL_SHA512_256_BLOCK_SIZE SHA512_256_BLOCK_SIZE
|
||||
#define CURL_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef struct sha512_256_ctx Curl_sha512_256_ctx;
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_init(void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
|
||||
|
||||
sha512_256_init(ctx);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process portion of bytes.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @param length number of bytes in @a data
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
DEBUGASSERT((data != NULL) || (length == 0));
|
||||
|
||||
sha512_256_update(ctx, length, (const uint8_t *)data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise SHA-512/256 calculation, return digest.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
|
||||
# bytes
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_finish(unsigned char *digest,
|
||||
void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
sha512_256_digest(ctx,
|
||||
(size_t)CURL_SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#else /* No system or TLS backend SHA-512/256 implementation available */
|
||||
|
||||
/* ** 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 ** *
|
||||
* ** under curl license. ** *
|
||||
* ** This is a minimal version with minimal optimizations. Performance ** *
|
||||
* ** can be significantly improved. Big-endian store and load macros ** *
|
||||
* ** are obvious targets for optimization. ** */
|
||||
|
||||
#ifdef __GNUC__
|
||||
# if defined(__has_attribute) && defined(__STDC_VERSION__)
|
||||
# if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
|
||||
# define CURL_FORCEINLINE CURL_INLINE __attribute__((always_inline))
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(CURL_FORCEINLINE) && \
|
||||
defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
|
||||
#define CURL_FORCEINLINE __forceinline
|
||||
#endif
|
||||
|
||||
/* Assume that 'CURL_INLINE' keyword works or the
|
||||
* macro was already defined correctly. */
|
||||
#ifndef CURL_FORCEINLINE
|
||||
#define CURL_FORCEINLINE CURL_INLINE
|
||||
#endif
|
||||
|
||||
/* Bits manipulation macros and functions.
|
||||
Can be moved to other headers to reuse. */
|
||||
|
||||
#define CURL_GET_64BIT_BE(ptr) \
|
||||
( ((curl_uint64_t)(((const unsigned char*)(ptr))[0]) << 56) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[1]) << 48) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[2]) << 40) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[3]) << 32) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[4]) << 24) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[5]) << 16) | \
|
||||
((curl_uint64_t)(((const unsigned char*)(ptr))[6]) << 8) | \
|
||||
(curl_uint64_t)(((const unsigned char*)(ptr))[7]) )
|
||||
|
||||
#define CURL_PUT_64BIT_BE(ptr,val) do { \
|
||||
((unsigned char*)(ptr))[7]=(unsigned char)((curl_uint64_t)(val)); \
|
||||
((unsigned char*)(ptr))[6]=(unsigned char)(((curl_uint64_t)(val)) >> 8); \
|
||||
((unsigned char*)(ptr))[5]=(unsigned char)(((curl_uint64_t)(val)) >> 16); \
|
||||
((unsigned char*)(ptr))[4]=(unsigned char)(((curl_uint64_t)(val)) >> 24); \
|
||||
((unsigned char*)(ptr))[3]=(unsigned char)(((curl_uint64_t)(val)) >> 32); \
|
||||
((unsigned char*)(ptr))[2]=(unsigned char)(((curl_uint64_t)(val)) >> 40); \
|
||||
((unsigned char*)(ptr))[1]=(unsigned char)(((curl_uint64_t)(val)) >> 48); \
|
||||
((unsigned char*)(ptr))[0]=(unsigned char)(((curl_uint64_t)(val)) >> 56); \
|
||||
} while(0)
|
||||
|
||||
/* Defined as a function. The macro version may duplicate the binary code
|
||||
* size as each argument is used twice, so if any calculation is used
|
||||
* as an argument, the calculation could be done twice. */
|
||||
static CURL_FORCEINLINE curl_uint64_t Curl_rotr64(curl_uint64_t value,
|
||||
unsigned int bits)
|
||||
{
|
||||
bits %= 64;
|
||||
if(bits == 0)
|
||||
return value;
|
||||
/* Defined in a form which modern compiler could optimize. */
|
||||
return (value >> bits) | (value << (64 - bits));
|
||||
}
|
||||
|
||||
/* SHA-512/256 specific data */
|
||||
|
||||
/**
|
||||
* Number of bits in a single SHA-512/256 word.
|
||||
*/
|
||||
#define SHA512_256_WORD_SIZE_BITS 64
|
||||
|
||||
/**
|
||||
* Number of bytes in a single SHA-512/256 word.
|
||||
*/
|
||||
#define SHA512_256_BYTES_IN_WORD (SHA512_256_WORD_SIZE_BITS / 8)
|
||||
|
||||
/**
|
||||
* Hash is kept internally as 8 64-bit words.
|
||||
* This is the intermediate hash size, used during computing the final digest.
|
||||
*/
|
||||
#define SHA512_256_HASH_SIZE_WORDS 8
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 resulting digest in words.
|
||||
* This is the final digest size, not intermediate hash.
|
||||
*/
|
||||
#define SHA512_256_DIGEST_SIZE_WORDS (SHA512_256_HASH_SIZE_WORDS / 2)
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 resulting digest in bytes
|
||||
* This is the final digest size, not intermediate hash.
|
||||
*/
|
||||
#define CURL_SHA512_256_DIGEST_SIZE \
|
||||
(SHA512_256_DIGEST_SIZE_WORDS * SHA512_256_BYTES_IN_WORD)
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 single processing block in bits.
|
||||
*/
|
||||
#define SHA512_256_BLOCK_SIZE_BITS 1024
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 single processing block in bytes.
|
||||
*/
|
||||
#define CURL_SHA512_256_BLOCK_SIZE (SHA512_256_BLOCK_SIZE_BITS / 8)
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 single processing block in words.
|
||||
*/
|
||||
#define SHA512_256_BLOCK_SIZE_WORDS \
|
||||
(SHA512_256_BLOCK_SIZE_BITS / SHA512_256_WORD_SIZE_BITS)
|
||||
|
||||
/**
|
||||
* SHA-512/256 calculation context
|
||||
*/
|
||||
struct Curl_sha512_256ctx {
|
||||
/**
|
||||
* Intermediate hash value. The variable is properly aligned. Smart
|
||||
* compilers may automatically use fast load/store instruction for big
|
||||
* endian data on little endian machine.
|
||||
*/
|
||||
curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS];
|
||||
/**
|
||||
* SHA-512/256 input data buffer. The buffer is properly aligned. Smart
|
||||
* compilers may automatically use fast load/store instruction for big
|
||||
* endian data on little endian machine.
|
||||
*/
|
||||
curl_uint64_t buffer[SHA512_256_BLOCK_SIZE_WORDS];
|
||||
/**
|
||||
* The number of bytes, lower part
|
||||
*/
|
||||
curl_uint64_t count;
|
||||
/**
|
||||
* The number of bits, high part. Unlike lower part, this counts the number
|
||||
* of bits, not bytes.
|
||||
*/
|
||||
curl_uint64_t count_bits_hi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef struct Curl_sha512_256ctx Curl_sha512_256_ctx;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_init(void *context)
|
||||
{
|
||||
struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
|
||||
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
|
||||
|
||||
DEBUGASSERT(sizeof(curl_uint64_t) == 8);
|
||||
|
||||
/* Initial hash values, see FIPS PUB 180-4 section 5.3.6.2 */
|
||||
/* Values generated by "IV Generation Function" as described in
|
||||
* section 5.3.6 */
|
||||
ctx->H[0] = CURL_UINT64_C(0x22312194FC2BF72C);
|
||||
ctx->H[1] = CURL_UINT64_C(0x9F555FA3C84C64C2);
|
||||
ctx->H[2] = CURL_UINT64_C(0x2393B86B6F53B151);
|
||||
ctx->H[3] = CURL_UINT64_C(0x963877195940EABD);
|
||||
ctx->H[4] = CURL_UINT64_C(0x96283EE2A88EFFE3);
|
||||
ctx->H[5] = CURL_UINT64_C(0xBE5E1E2553863992);
|
||||
ctx->H[6] = CURL_UINT64_C(0x2B0199FC2C85B8AA);
|
||||
ctx->H[7] = CURL_UINT64_C(0x0EB72DDC81C52CA2);
|
||||
|
||||
/* Initialise number of bytes and high part of number of bits. */
|
||||
ctx->count = CURL_UINT64_C(0);
|
||||
ctx->count_bits_hi = CURL_UINT64_C(0);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the SHA-512/256 transformation.
|
||||
* Gets a full 128 bytes block of data and updates hash values;
|
||||
* @param H hash values
|
||||
* @param data the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block
|
||||
*/
|
||||
static
|
||||
void Curl_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
|
||||
const void *data)
|
||||
{
|
||||
/* Working variables,
|
||||
see FIPS PUB 180-4 section 6.7, 6.4. */
|
||||
curl_uint64_t a = H[0];
|
||||
curl_uint64_t b = H[1];
|
||||
curl_uint64_t c = H[2];
|
||||
curl_uint64_t d = H[3];
|
||||
curl_uint64_t e = H[4];
|
||||
curl_uint64_t f = H[5];
|
||||
curl_uint64_t g = H[6];
|
||||
curl_uint64_t h = H[7];
|
||||
|
||||
/* Data buffer, used as a cyclic buffer.
|
||||
See FIPS PUB 180-4 section 5.2.2, 6.7, 6.4. */
|
||||
curl_uint64_t W[16];
|
||||
|
||||
/* 'Ch' and 'Maj' macro functions are defined with widely-used optimization.
|
||||
See FIPS PUB 180-4 formulae 4.8, 4.9. */
|
||||
#define Sha512_Ch(x,y,z) ( (z) ^ ((x) & ((y) ^ (z))) )
|
||||
#define Sha512_Maj(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
|
||||
|
||||
/* Four 'Sigma' macro functions.
|
||||
See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
|
||||
#define SIG0(x) \
|
||||
( Curl_rotr64((x), 28) ^ Curl_rotr64((x), 34) ^ Curl_rotr64((x), 39) )
|
||||
#define SIG1(x) \
|
||||
( Curl_rotr64((x), 14) ^ Curl_rotr64((x), 18) ^ Curl_rotr64((x), 41) )
|
||||
#define sig0(x) \
|
||||
( Curl_rotr64((x), 1) ^ Curl_rotr64((x), 8) ^ ((x) >> 7) )
|
||||
#define sig1(x) \
|
||||
( Curl_rotr64((x), 19) ^ Curl_rotr64((x), 61) ^ ((x) >> 6) )
|
||||
|
||||
if(1) {
|
||||
unsigned int t;
|
||||
/* K constants array.
|
||||
See FIPS PUB 180-4 section 4.2.3 for K values. */
|
||||
static const curl_uint64_t K[80] = {
|
||||
CURL_UINT64_C(0x428a2f98d728ae22), CURL_UINT64_C(0x7137449123ef65cd),
|
||||
CURL_UINT64_C(0xb5c0fbcfec4d3b2f), CURL_UINT64_C(0xe9b5dba58189dbbc),
|
||||
CURL_UINT64_C(0x3956c25bf348b538), CURL_UINT64_C(0x59f111f1b605d019),
|
||||
CURL_UINT64_C(0x923f82a4af194f9b), CURL_UINT64_C(0xab1c5ed5da6d8118),
|
||||
CURL_UINT64_C(0xd807aa98a3030242), CURL_UINT64_C(0x12835b0145706fbe),
|
||||
CURL_UINT64_C(0x243185be4ee4b28c), CURL_UINT64_C(0x550c7dc3d5ffb4e2),
|
||||
CURL_UINT64_C(0x72be5d74f27b896f), CURL_UINT64_C(0x80deb1fe3b1696b1),
|
||||
CURL_UINT64_C(0x9bdc06a725c71235), CURL_UINT64_C(0xc19bf174cf692694),
|
||||
CURL_UINT64_C(0xe49b69c19ef14ad2), CURL_UINT64_C(0xefbe4786384f25e3),
|
||||
CURL_UINT64_C(0x0fc19dc68b8cd5b5), CURL_UINT64_C(0x240ca1cc77ac9c65),
|
||||
CURL_UINT64_C(0x2de92c6f592b0275), CURL_UINT64_C(0x4a7484aa6ea6e483),
|
||||
CURL_UINT64_C(0x5cb0a9dcbd41fbd4), CURL_UINT64_C(0x76f988da831153b5),
|
||||
CURL_UINT64_C(0x983e5152ee66dfab), CURL_UINT64_C(0xa831c66d2db43210),
|
||||
CURL_UINT64_C(0xb00327c898fb213f), CURL_UINT64_C(0xbf597fc7beef0ee4),
|
||||
CURL_UINT64_C(0xc6e00bf33da88fc2), CURL_UINT64_C(0xd5a79147930aa725),
|
||||
CURL_UINT64_C(0x06ca6351e003826f), CURL_UINT64_C(0x142929670a0e6e70),
|
||||
CURL_UINT64_C(0x27b70a8546d22ffc), CURL_UINT64_C(0x2e1b21385c26c926),
|
||||
CURL_UINT64_C(0x4d2c6dfc5ac42aed), CURL_UINT64_C(0x53380d139d95b3df),
|
||||
CURL_UINT64_C(0x650a73548baf63de), CURL_UINT64_C(0x766a0abb3c77b2a8),
|
||||
CURL_UINT64_C(0x81c2c92e47edaee6), CURL_UINT64_C(0x92722c851482353b),
|
||||
CURL_UINT64_C(0xa2bfe8a14cf10364), CURL_UINT64_C(0xa81a664bbc423001),
|
||||
CURL_UINT64_C(0xc24b8b70d0f89791), CURL_UINT64_C(0xc76c51a30654be30),
|
||||
CURL_UINT64_C(0xd192e819d6ef5218), CURL_UINT64_C(0xd69906245565a910),
|
||||
CURL_UINT64_C(0xf40e35855771202a), CURL_UINT64_C(0x106aa07032bbd1b8),
|
||||
CURL_UINT64_C(0x19a4c116b8d2d0c8), CURL_UINT64_C(0x1e376c085141ab53),
|
||||
CURL_UINT64_C(0x2748774cdf8eeb99), CURL_UINT64_C(0x34b0bcb5e19b48a8),
|
||||
CURL_UINT64_C(0x391c0cb3c5c95a63), CURL_UINT64_C(0x4ed8aa4ae3418acb),
|
||||
CURL_UINT64_C(0x5b9cca4f7763e373), CURL_UINT64_C(0x682e6ff3d6b2b8a3),
|
||||
CURL_UINT64_C(0x748f82ee5defb2fc), CURL_UINT64_C(0x78a5636f43172f60),
|
||||
CURL_UINT64_C(0x84c87814a1f0ab72), CURL_UINT64_C(0x8cc702081a6439ec),
|
||||
CURL_UINT64_C(0x90befffa23631e28), CURL_UINT64_C(0xa4506cebde82bde9),
|
||||
CURL_UINT64_C(0xbef9a3f7b2c67915), CURL_UINT64_C(0xc67178f2e372532b),
|
||||
CURL_UINT64_C(0xca273eceea26619c), CURL_UINT64_C(0xd186b8c721c0c207),
|
||||
CURL_UINT64_C(0xeada7dd6cde0eb1e), CURL_UINT64_C(0xf57d4f7fee6ed178),
|
||||
CURL_UINT64_C(0x06f067aa72176fba), CURL_UINT64_C(0x0a637dc5a2c898a6),
|
||||
CURL_UINT64_C(0x113f9804bef90dae), CURL_UINT64_C(0x1b710b35131c471b),
|
||||
CURL_UINT64_C(0x28db77f523047d84), CURL_UINT64_C(0x32caab7b40c72493),
|
||||
CURL_UINT64_C(0x3c9ebe0a15c9bebc), CURL_UINT64_C(0x431d67c49c100d4c),
|
||||
CURL_UINT64_C(0x4cc5d4becb3e42b6), CURL_UINT64_C(0x597f299cfc657e2a),
|
||||
CURL_UINT64_C(0x5fcb6fab3ad6faec), CURL_UINT64_C(0x6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* One step of SHA-512/256 computation,
|
||||
see FIPS PUB 180-4 section 6.4.2 step 3.
|
||||
* Note: this macro updates working variables in-place, without rotation.
|
||||
* Note: the first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in
|
||||
FIPS PUB 180-4 section 6.4.2 step 3.
|
||||
the second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in
|
||||
FIPS PUB 180-4 section 6.4.2 step 3.
|
||||
* Note: 'wt' must be used exactly one time in this macro as macro for
|
||||
'wt' calculation may change other data as well every time when
|
||||
used. */
|
||||
#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do { \
|
||||
(vD) += ((vH) += SIG1((vE)) + Sha512_Ch((vE),(vF),(vG)) + (kt) + (wt)); \
|
||||
(vH) += SIG0((vA)) + Sha512_Maj((vA),(vB),(vC)); } while (0)
|
||||
|
||||
/* One step of SHA-512/256 computation with working variables rotation,
|
||||
see FIPS PUB 180-4 section 6.4.2 step 3. This macro version reassigns
|
||||
all working variables on each step. */
|
||||
#define SHA2STEP64RV(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do { \
|
||||
curl_uint64_t tmp_h_ = (vH); \
|
||||
SHA2STEP64((vA),(vB),(vC),(vD),(vE),(vF),(vG),tmp_h_,(kt),(wt)); \
|
||||
(vH) = (vG); \
|
||||
(vG) = (vF); \
|
||||
(vF) = (vE); \
|
||||
(vE) = (vD); \
|
||||
(vD) = (vC); \
|
||||
(vC) = (vB); \
|
||||
(vB) = (vA); \
|
||||
(vA) = tmp_h_; } while(0)
|
||||
|
||||
/* Get value of W(t) from input data buffer for 0 <= t <= 15,
|
||||
See FIPS PUB 180-4 section 6.2.
|
||||
Input data must be read in big-endian bytes order,
|
||||
see FIPS PUB 180-4 section 3.1.2. */
|
||||
#define SHA512_GET_W_FROM_DATA(buf,t) \
|
||||
CURL_GET_64BIT_BE( \
|
||||
((const unsigned char*) (buf)) + (t) * SHA512_256_BYTES_IN_WORD)
|
||||
|
||||
/* During first 16 steps, before making any calculation on each step, the
|
||||
W element is read from the input data buffer as a big-endian value and
|
||||
stored in the array of W elements. */
|
||||
for(t = 0; t < 16; ++t) {
|
||||
SHA2STEP64RV(a, b, c, d, e, f, g, h, K[t], \
|
||||
W[t] = SHA512_GET_W_FROM_DATA(data, t));
|
||||
}
|
||||
|
||||
/* 'W' generation and assignment for 16 <= t <= 79.
|
||||
See FIPS PUB 180-4 section 6.4.2.
|
||||
As only the last 16 'W' are used in calculations, it is possible to
|
||||
use 16 elements array of W as a cyclic buffer.
|
||||
Note: ((t-16) & 15) have same value as (t & 15) */
|
||||
#define Wgen(w,t) \
|
||||
(curl_uint64_t)( (w)[(t - 16) & 15] + sig1((w)[((t) - 2) & 15]) \
|
||||
+ (w)[((t) - 7) & 15] + sig0((w)[((t) - 15) & 15]) )
|
||||
|
||||
/* During the last 64 steps, before making any calculation on each step,
|
||||
current W element is generated from other W elements of the cyclic
|
||||
buffer and the generated value is stored back in the cyclic buffer. */
|
||||
for(t = 16; t < 80; ++t) {
|
||||
SHA2STEP64RV(a, b, c, d, e, f, g, h, K[t], \
|
||||
W[t & 15] = Wgen(W, t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute and store the intermediate hash.
|
||||
See FIPS PUB 180-4 section 6.4.2 step 4. */
|
||||
H[0] += a;
|
||||
H[1] += b;
|
||||
H[2] += c;
|
||||
H[3] += d;
|
||||
H[4] += e;
|
||||
H[5] += f;
|
||||
H[6] += g;
|
||||
H[7] += h;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process portion of bytes.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @param length number of bytes in @a data
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
unsigned int bytes_have; /**< Number of bytes in the context buffer */
|
||||
struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
|
||||
/* the void pointer here is required to mute Intel compiler warning */
|
||||
void *const ctx_buf = ctx->buffer;
|
||||
|
||||
DEBUGASSERT((data != NULL) || (length == 0));
|
||||
|
||||
if(length == 0)
|
||||
return CURLE_OK; /* Shortcut, do nothing */
|
||||
|
||||
/* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
|
||||
equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
|
||||
bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
|
||||
ctx->count += length;
|
||||
if(length > ctx->count)
|
||||
ctx->count_bits_hi += 1U << 3; /* Value wrap */
|
||||
ctx->count_bits_hi += ctx->count >> 61;
|
||||
ctx->count &= CURL_UINT64_C(0x1FFFFFFFFFFFFFFF);
|
||||
|
||||
if(bytes_have) {
|
||||
unsigned int bytes_left = CURL_SHA512_256_BLOCK_SIZE - bytes_have;
|
||||
if(length >= bytes_left) {
|
||||
/* Combine new data with data in the buffer and process the full
|
||||
block. */
|
||||
memcpy(((unsigned char *) ctx_buf) + bytes_have,
|
||||
data,
|
||||
bytes_left);
|
||||
data += bytes_left;
|
||||
length -= bytes_left;
|
||||
Curl_sha512_256_transform(ctx->H, ctx->buffer);
|
||||
bytes_have = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while(CURL_SHA512_256_BLOCK_SIZE <= length) {
|
||||
/* Process any full blocks of new data directly,
|
||||
without copying to the buffer. */
|
||||
Curl_sha512_256_transform(ctx->H, data);
|
||||
data += CURL_SHA512_256_BLOCK_SIZE;
|
||||
length -= CURL_SHA512_256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if(length) {
|
||||
/* Copy incomplete block of new data (if any)
|
||||
to the buffer. */
|
||||
memcpy(((unsigned char *) ctx_buf) + bytes_have, data, length);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Size of "length" insertion in bits.
|
||||
* See FIPS PUB 180-4 section 5.1.2.
|
||||
*/
|
||||
#define SHA512_256_SIZE_OF_LEN_ADD_BITS 128
|
||||
|
||||
/**
|
||||
* Size of "length" insertion in bytes.
|
||||
*/
|
||||
#define SHA512_256_SIZE_OF_LEN_ADD (SHA512_256_SIZE_OF_LEN_ADD_BITS / 8)
|
||||
|
||||
/**
|
||||
* Finalise SHA-512/256 calculation, return digest.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
|
||||
# bytes
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
|
||||
{
|
||||
struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
|
||||
curl_uint64_t num_bits; /**< Number of processed bits */
|
||||
unsigned int bytes_have; /**< Number of bytes in the context buffer */
|
||||
/* the void pointer here is required to mute Intel compiler warning */
|
||||
void *const ctx_buf = ctx->buffer;
|
||||
|
||||
/* Memorise the number of processed bits.
|
||||
The padding and other data added here during the postprocessing must
|
||||
not change the amount of hashed data. */
|
||||
num_bits = ctx->count << 3;
|
||||
|
||||
/* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
|
||||
equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
|
||||
bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
|
||||
|
||||
/* Input data must be padded with a single bit "1", then with zeros and
|
||||
the finally the length of data in bits must be added as the final bytes
|
||||
of the last block.
|
||||
See FIPS PUB 180-4 section 5.1.2. */
|
||||
|
||||
/* Data is always processed in form of bytes (not by individual bits),
|
||||
therefore position of the first padding bit in byte is always
|
||||
predefined (0x80). */
|
||||
/* Buffer always have space at least for one byte (as full buffers are
|
||||
processed when formed). */
|
||||
((unsigned char *) ctx_buf)[bytes_have++] = 0x80U;
|
||||
|
||||
if(CURL_SHA512_256_BLOCK_SIZE - bytes_have < SHA512_256_SIZE_OF_LEN_ADD) {
|
||||
/* No space in the current block to put the total length of message.
|
||||
Pad the current block with zeros and process it. */
|
||||
if(bytes_have < CURL_SHA512_256_BLOCK_SIZE)
|
||||
memset(((unsigned char *) ctx_buf) + bytes_have, 0,
|
||||
CURL_SHA512_256_BLOCK_SIZE - bytes_have);
|
||||
/* Process the full block. */
|
||||
Curl_sha512_256_transform(ctx->H, ctx->buffer);
|
||||
/* Start the new block. */
|
||||
bytes_have = 0;
|
||||
}
|
||||
|
||||
/* Pad the rest of the buffer with zeros. */
|
||||
memset(((unsigned char *) ctx_buf) + bytes_have, 0,
|
||||
CURL_SHA512_256_BLOCK_SIZE - SHA512_256_SIZE_OF_LEN_ADD - bytes_have);
|
||||
/* Put high part of number of bits in processed message and then lower
|
||||
part of number of bits as big-endian values.
|
||||
See FIPS PUB 180-4 section 5.1.2. */
|
||||
/* Note: the target location is predefined and buffer is always aligned */
|
||||
CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \
|
||||
+ CURL_SHA512_256_BLOCK_SIZE \
|
||||
- SHA512_256_SIZE_OF_LEN_ADD, \
|
||||
ctx->count_bits_hi);
|
||||
CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \
|
||||
+ CURL_SHA512_256_BLOCK_SIZE \
|
||||
- SHA512_256_SIZE_OF_LEN_ADD \
|
||||
+ SHA512_256_BYTES_IN_WORD, \
|
||||
num_bits);
|
||||
/* Process the full final block. */
|
||||
Curl_sha512_256_transform(ctx->H, ctx->buffer);
|
||||
|
||||
/* Put in BE mode the leftmost part of the hash as the final digest.
|
||||
See FIPS PUB 180-4 section 6.7. */
|
||||
|
||||
CURL_PUT_64BIT_BE((digest + 0 * SHA512_256_BYTES_IN_WORD), ctx->H[0]);
|
||||
CURL_PUT_64BIT_BE((digest + 1 * SHA512_256_BYTES_IN_WORD), ctx->H[1]);
|
||||
CURL_PUT_64BIT_BE((digest + 2 * SHA512_256_BYTES_IN_WORD), ctx->H[2]);
|
||||
CURL_PUT_64BIT_BE((digest + 3 * SHA512_256_BYTES_IN_WORD), ctx->H[3]);
|
||||
|
||||
/* Erase potentially sensitive data. */
|
||||
memset(ctx, 0, sizeof(struct Curl_sha512_256ctx));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#endif /* Local SHA-512/256 code */
|
||||
|
||||
|
||||
/**
|
||||
* Compute SHA-512/256 hash for the given data in one function call
|
||||
* @param[out] output the pointer to put the hash
|
||||
* @param[in] input the pointer to the data to process
|
||||
* @param input_size the size of the data pointed by @a input
|
||||
* @return always #CURLE_OK
|
||||
*/
|
||||
CURLcode Curl_sha512_256it(unsigned char *output, const unsigned char *input,
|
||||
size_t input_size)
|
||||
{
|
||||
Curl_sha512_256_ctx ctx;
|
||||
CURLcode res;
|
||||
|
||||
res = Curl_sha512_256_init(&ctx);
|
||||
if(res != CURLE_OK)
|
||||
return res;
|
||||
|
||||
res = Curl_sha512_256_update(&ctx, (const void *) input, input_size);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
(void)Curl_sha512_256_finish(output, &ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
return Curl_sha512_256_finish(output, &ctx);
|
||||
}
|
||||
|
||||
/* Wrapper function, takes 'unsigned int' as length type, returns void */
|
||||
static void Curl_sha512_256_update_i(void *context,
|
||||
const unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
/* Hypothetically the function may fail, but assume it does not */
|
||||
(void)Curl_sha512_256_update(context, data, length);
|
||||
}
|
||||
|
||||
/* Wrapper function, returns void */
|
||||
static void Curl_sha512_256_finish_v(unsigned char *result, void *context)
|
||||
{
|
||||
/* Hypothetically the function may fail, but assume it does not */
|
||||
(void)Curl_sha512_256_finish(result, context);
|
||||
}
|
||||
|
||||
/* Wrapper function, takes 'unsigned int' as length type, returns void */
|
||||
|
||||
const struct HMAC_params Curl_HMAC_SHA512_256[] = {
|
||||
{
|
||||
/* Initialize context procedure. */
|
||||
Curl_sha512_256_init,
|
||||
/* Update context with data. */
|
||||
Curl_sha512_256_update_i,
|
||||
/* Get final result procedure. */
|
||||
Curl_sha512_256_finish_v,
|
||||
/* Context structure size. */
|
||||
sizeof(Curl_sha512_256_ctx),
|
||||
/* Maximum key length (bytes). */
|
||||
CURL_SHA512_256_BLOCK_SIZE,
|
||||
/* Result length (bytes). */
|
||||
CURL_SHA512_256_DIGEST_SIZE
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* !CURL_DISABLE_DIGEST_AUTH && !CURL_DISABLE_SHA512_256 */
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#ifndef HEADER_CURL_SHA512_256_H
|
||||
#define HEADER_CURL_SHA512_256_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#if !defined(CURL_DISABLE_DIGEST_AUTH) && !defined(CURL_DISABLE_SHA512_256)
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "curl_hmac.h"
|
||||
|
||||
#define CURL_HAVE_SHA512_256
|
||||
|
||||
extern const struct HMAC_params Curl_HMAC_SHA512_256[1];
|
||||
|
||||
#define CURL_SHA512_256_DIGEST_LENGTH 32
|
||||
|
||||
CURLcode
|
||||
Curl_sha512_256it(unsigned char *output, const unsigned char *input,
|
||||
size_t input_size);
|
||||
|
||||
#endif /* !CURL_DISABLE_DIGEST_AUTH && !CURL_DISABLE_SHA512_256 */
|
||||
|
||||
#endif /* HEADER_CURL_SHA256_H */
|
||||
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 USE_WINDOWS_SSPI
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "curl_sspi.h"
|
||||
#include "strdup.h"
|
||||
#include "curlx/multibyte.h"
|
||||
#include "system_win32.h"
|
||||
#include "curlx/warnless.h"
|
||||
|
||||
/* The last #include files should be: */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/* Pointer to SSPI dispatch table */
|
||||
PSecurityFunctionTable Curl_pSecFn = NULL;
|
||||
|
||||
/*
|
||||
* Curl_sspi_global_init()
|
||||
*
|
||||
* This is used to load the Security Service Provider Interface (SSPI)
|
||||
* dynamic link library portably across all Windows versions, without
|
||||
* the need to directly link libcurl, nor the application using it, at
|
||||
* build time.
|
||||
*
|
||||
* Once this function has been executed, Windows SSPI functions can be
|
||||
* called through the Security Service Provider Interface dispatch table.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* None.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
CURLcode Curl_sspi_global_init(void)
|
||||
{
|
||||
/* If security interface is not yet initialized try to do this */
|
||||
if(!Curl_pSecFn) {
|
||||
/* Get pointer to Security Service Provider Interface dispatch table */
|
||||
#ifdef __MINGW32CE__
|
||||
Curl_pSecFn = InitSecurityInterfaceW();
|
||||
#else
|
||||
Curl_pSecFn = InitSecurityInterface();
|
||||
#endif
|
||||
if(!Curl_pSecFn)
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sspi_global_cleanup()
|
||||
*
|
||||
* This deinitializes the Security Service Provider Interface from libcurl.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* None.
|
||||
*/
|
||||
void Curl_sspi_global_cleanup(void)
|
||||
{
|
||||
if(Curl_pSecFn) {
|
||||
Curl_pSecFn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_create_sspi_identity()
|
||||
*
|
||||
* This is used to populate an SSPI identity structure based on the supplied
|
||||
* username and password.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* userp [in] - The username in the format User or Domain\User.
|
||||
* passwdp [in] - The user's password.
|
||||
* identity [in/out] - The identity structure.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
|
||||
SEC_WINNT_AUTH_IDENTITY *identity)
|
||||
{
|
||||
xcharp_u useranddomain;
|
||||
xcharp_u user, dup_user;
|
||||
xcharp_u domain, dup_domain;
|
||||
xcharp_u passwd, dup_passwd;
|
||||
size_t domlen = 0;
|
||||
|
||||
domain.const_tchar_ptr = TEXT("");
|
||||
|
||||
/* Initialize the identity */
|
||||
memset(identity, 0, sizeof(*identity));
|
||||
|
||||
useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp);
|
||||
if(!useranddomain.tchar_ptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
|
||||
if(!user.const_tchar_ptr)
|
||||
user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
|
||||
|
||||
if(user.tchar_ptr) {
|
||||
domain.tchar_ptr = useranddomain.tchar_ptr;
|
||||
domlen = user.tchar_ptr - useranddomain.tchar_ptr;
|
||||
user.tchar_ptr++;
|
||||
}
|
||||
else {
|
||||
user.tchar_ptr = useranddomain.tchar_ptr;
|
||||
domain.const_tchar_ptr = TEXT("");
|
||||
domlen = 0;
|
||||
}
|
||||
|
||||
/* Setup the identity's user and length */
|
||||
dup_user.tchar_ptr = Curl_tcsdup(user.tchar_ptr);
|
||||
if(!dup_user.tchar_ptr) {
|
||||
curlx_unicodefree(useranddomain.tchar_ptr);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
identity->User = dup_user.tbyte_ptr;
|
||||
identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
|
||||
dup_user.tchar_ptr = NULL;
|
||||
|
||||
/* Setup the identity's domain and length */
|
||||
dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
|
||||
if(!dup_domain.tchar_ptr) {
|
||||
curlx_unicodefree(useranddomain.tchar_ptr);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
_tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
|
||||
*(dup_domain.tchar_ptr + domlen) = TEXT('\0');
|
||||
identity->Domain = dup_domain.tbyte_ptr;
|
||||
identity->DomainLength = curlx_uztoul(domlen);
|
||||
dup_domain.tchar_ptr = NULL;
|
||||
|
||||
curlx_unicodefree(useranddomain.tchar_ptr);
|
||||
|
||||
/* Setup the identity's password and length */
|
||||
passwd.tchar_ptr = curlx_convert_UTF8_to_tchar(passwdp);
|
||||
if(!passwd.tchar_ptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
dup_passwd.tchar_ptr = Curl_tcsdup(passwd.tchar_ptr);
|
||||
if(!dup_passwd.tchar_ptr) {
|
||||
curlx_unicodefree(passwd.tchar_ptr);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
identity->Password = dup_passwd.tbyte_ptr;
|
||||
identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
|
||||
dup_passwd.tchar_ptr = NULL;
|
||||
|
||||
curlx_unicodefree(passwd.tchar_ptr);
|
||||
|
||||
/* Setup the identity's flags */
|
||||
identity->Flags = (unsigned long)
|
||||
#ifdef UNICODE
|
||||
SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
#else
|
||||
SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
#endif
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sspi_free_identity()
|
||||
*
|
||||
* This is used to free the contents of an SSPI identifier structure.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* identity [in/out] - The identity structure.
|
||||
*/
|
||||
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
|
||||
{
|
||||
if(identity) {
|
||||
Curl_safefree(identity->User);
|
||||
Curl_safefree(identity->Password);
|
||||
Curl_safefree(identity->Domain);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_WINDOWS_SSPI */
|
||||
Vendored
+351
@@ -0,0 +1,351 @@
|
||||
#ifndef HEADER_CURL_SSPI_H
|
||||
#define HEADER_CURL_SSPI_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"
|
||||
|
||||
#ifdef USE_WINDOWS_SSPI
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
/*
|
||||
* When including the following three headers, it is mandatory to define either
|
||||
* SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code.
|
||||
*/
|
||||
|
||||
#undef SECURITY_WIN32
|
||||
#undef SECURITY_KERNEL
|
||||
#define SECURITY_WIN32 1
|
||||
#include <security.h>
|
||||
#include <sspi.h>
|
||||
#include <rpc.h>
|
||||
|
||||
CURLcode Curl_sspi_global_init(void);
|
||||
void Curl_sspi_global_cleanup(void);
|
||||
|
||||
/* This is used to populate the domain in an SSPI identity structure */
|
||||
CURLcode Curl_override_sspi_http_realm(const char *chlg,
|
||||
SEC_WINNT_AUTH_IDENTITY *identity);
|
||||
|
||||
/* This is used to generate an SSPI identity structure */
|
||||
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
|
||||
SEC_WINNT_AUTH_IDENTITY *identity);
|
||||
|
||||
/* This is used to free an SSPI identity structure */
|
||||
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
|
||||
|
||||
/* Forward-declaration of global variables defined in curl_sspi.c */
|
||||
extern PSecurityFunctionTable Curl_pSecFn;
|
||||
|
||||
/* Provide some definitions missing in old headers */
|
||||
#define SP_NAME_DIGEST "WDigest"
|
||||
#define SP_NAME_NTLM "NTLM"
|
||||
#define SP_NAME_NEGOTIATE "Negotiate"
|
||||
#define SP_NAME_KERBEROS "Kerberos"
|
||||
|
||||
/* Offered by mingw-w64 v9+. MS SDK 7.0A+. */
|
||||
#ifndef ISC_REQ_USE_HTTP_STYLE
|
||||
#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__ */
|
||||
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
|
||||
#ifndef SEC_E_INVALID_PARAMETER
|
||||
#define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
|
||||
#endif
|
||||
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
|
||||
#ifndef SEC_E_DELEGATION_POLICY
|
||||
#define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL)
|
||||
#endif
|
||||
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
|
||||
#ifndef SEC_E_POLICY_NLTM_ONLY
|
||||
#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__ */
|
||||
|
||||
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
|
||||
#ifndef SEC_I_SIGNATURE_NEEDED
|
||||
#define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32CE__
|
||||
#ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE
|
||||
#define CRYPT_E_NOT_IN_REVOCATION_DATABASE ((HRESULT)0x80092014L)
|
||||
#endif
|
||||
#endif /* __MINGW32CE__ */
|
||||
|
||||
/*
|
||||
* Definitions required from ntsecapi.h are directly provided below this point
|
||||
* to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
|
||||
*/
|
||||
#define KERB_WRAP_NO_ENCRYPT 0x80000001
|
||||
|
||||
#endif /* USE_WINDOWS_SSPI */
|
||||
|
||||
#endif /* HEADER_CURL_SSPI_H */
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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>
|
||||
|
||||
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "curl_threads.h"
|
||||
#include "curl_memory.h"
|
||||
/* The last #include FILE should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef USE_THREADS_POSIX
|
||||
|
||||
struct Curl_actual_call {
|
||||
unsigned int (*func)(void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void *curl_thread_create_thunk(void *arg)
|
||||
{
|
||||
struct Curl_actual_call *ac = arg;
|
||||
unsigned int (*func)(void *) = ac->func;
|
||||
void *real_arg = ac->arg;
|
||||
|
||||
free(ac);
|
||||
|
||||
(*func)(real_arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
||||
(CURL_STDCALL *func) (void *), void *arg)
|
||||
{
|
||||
curl_thread_t t = malloc(sizeof(pthread_t));
|
||||
struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call));
|
||||
int rc;
|
||||
if(!(ac && t))
|
||||
goto err;
|
||||
|
||||
ac->func = func;
|
||||
ac->arg = arg;
|
||||
|
||||
rc = pthread_create(t, NULL, curl_thread_create_thunk, ac);
|
||||
if(rc) {
|
||||
CURL_SETERRNO(rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
err:
|
||||
free(t);
|
||||
free(ac);
|
||||
return curl_thread_t_null;
|
||||
}
|
||||
|
||||
void Curl_thread_destroy(curl_thread_t *hnd)
|
||||
{
|
||||
if(*hnd != curl_thread_t_null) {
|
||||
pthread_detach(**hnd);
|
||||
free(*hnd);
|
||||
*hnd = curl_thread_t_null;
|
||||
}
|
||||
}
|
||||
|
||||
int Curl_thread_join(curl_thread_t *hnd)
|
||||
{
|
||||
int ret = (pthread_join(**hnd, NULL) == 0);
|
||||
|
||||
free(*hnd);
|
||||
*hnd = curl_thread_t_null;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined(USE_THREADS_WIN32)
|
||||
|
||||
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
||||
(CURL_STDCALL *func) (void *), void *arg)
|
||||
{
|
||||
curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL);
|
||||
if(!t) {
|
||||
DWORD gle = GetLastError();
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
int err = (gle == ERROR_ACCESS_DENIED ||
|
||||
gle == ERROR_NOT_ENOUGH_MEMORY) ?
|
||||
EACCES : EINVAL;
|
||||
CURL_SETERRNO(err);
|
||||
return curl_thread_t_null;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void Curl_thread_destroy(curl_thread_t *hnd)
|
||||
{
|
||||
if(*hnd != curl_thread_t_null) {
|
||||
CloseHandle(*hnd);
|
||||
*hnd = curl_thread_t_null;
|
||||
}
|
||||
}
|
||||
|
||||
int Curl_thread_join(curl_thread_t *hnd)
|
||||
{
|
||||
#ifdef UNDER_CE
|
||||
int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
|
||||
#else
|
||||
int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
|
||||
#endif
|
||||
|
||||
Curl_thread_destroy(hnd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* USE_THREADS_* */
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
#ifndef HEADER_CURL_THREADS_H
|
||||
#define HEADER_CURL_THREADS_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"
|
||||
|
||||
#ifdef USE_THREADS_POSIX
|
||||
# define CURL_THREAD_RETURN_T unsigned int
|
||||
# define CURL_STDCALL
|
||||
# define curl_mutex_t pthread_mutex_t
|
||||
# define curl_thread_t pthread_t *
|
||||
# define curl_thread_t_null (pthread_t *)0
|
||||
# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
|
||||
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
|
||||
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
|
||||
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
|
||||
#elif defined(USE_THREADS_WIN32)
|
||||
# define CURL_THREAD_RETURN_T DWORD
|
||||
# define CURL_STDCALL WINAPI
|
||||
# define curl_mutex_t CRITICAL_SECTION
|
||||
# define curl_thread_t HANDLE
|
||||
# define curl_thread_t_null (HANDLE)0
|
||||
# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA)
|
||||
# define Curl_mutex_init(m) InitializeCriticalSection(m)
|
||||
# else
|
||||
# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1)
|
||||
# endif
|
||||
# define Curl_mutex_acquire(m) EnterCriticalSection(m)
|
||||
# define Curl_mutex_release(m) LeaveCriticalSection(m)
|
||||
# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
|
||||
#endif
|
||||
|
||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
||||
|
||||
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
||||
(CURL_STDCALL *func) (void *), void *arg);
|
||||
|
||||
void Curl_thread_destroy(curl_thread_t *hnd);
|
||||
|
||||
int Curl_thread_join(curl_thread_t *hnd);
|
||||
|
||||
#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
|
||||
|
||||
#endif /* HEADER_CURL_THREADS_H */
|
||||
Vendored
+711
@@ -0,0 +1,711 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "curl_trc.h"
|
||||
#include "urldata.h"
|
||||
#include "easyif.h"
|
||||
#include "cfilters.h"
|
||||
#include "multiif.h"
|
||||
|
||||
#include "cf-socket.h"
|
||||
#include "connect.h"
|
||||
#include "doh.h"
|
||||
#include "http2.h"
|
||||
#include "http_proxy.h"
|
||||
#include "cf-h1-proxy.h"
|
||||
#include "cf-h2-proxy.h"
|
||||
#include "cf-haproxy.h"
|
||||
#include "cf-https-connect.h"
|
||||
#include "cf-ip-happy.h"
|
||||
#include "socks.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "vquic/vquic.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
static void trc_write(struct Curl_easy *data, curl_infotype type,
|
||||
const char *ptr, size_t size)
|
||||
{
|
||||
if(data->set.verbose) {
|
||||
if(data->set.fdebug) {
|
||||
bool inCallback = Curl_is_in_callback(data);
|
||||
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 {
|
||||
static const char s_infotype[CURLINFO_END][3] = {
|
||||
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
case CURLINFO_HEADER_OUT:
|
||||
case CURLINFO_HEADER_IN:
|
||||
fwrite(s_infotype[type], 2, 1, data->set.err);
|
||||
fwrite(ptr, size, 1, data->set.err);
|
||||
break;
|
||||
default: /* nada */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
|
||||
else
|
||||
return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
|
||||
}
|
||||
else if(cid >= 0)
|
||||
return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
|
||||
else {
|
||||
return curl_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 += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
|
||||
(int)size, ptr);
|
||||
len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
(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:
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
if(CURL_TRC_IDS(data)) {
|
||||
len = trc_print_ids(data, buf, TRC_LINE_MAX);
|
||||
fwrite(buf, len, 1, data->set.err);
|
||||
}
|
||||
#endif
|
||||
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.
|
||||
*/
|
||||
void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(data->set.verbose || data->set.errorbuffer) {
|
||||
va_list ap;
|
||||
size_t len;
|
||||
char error[CURL_ERROR_SIZE + 2];
|
||||
va_start(ap, fmt);
|
||||
len = curl_mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
|
||||
|
||||
if(data->set.errorbuffer && !data->state.errorbuf) {
|
||||
strcpy(data->set.errorbuffer, error);
|
||||
data->state.errorbuf = TRUE; /* wrote error string */
|
||||
}
|
||||
error[len++] = '\n';
|
||||
error[len] = '\0';
|
||||
trc_write(data, CURLINFO_TEXT, error, len);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
|
||||
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,
|
||||
const char *opt_id, int opt_id_idx,
|
||||
const char * const fmt, va_list ap)
|
||||
{
|
||||
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 += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
|
||||
if(opt_id) {
|
||||
if(opt_id_idx > 0)
|
||||
len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
|
||||
opt_id, opt_id_idx);
|
||||
else
|
||||
len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
|
||||
}
|
||||
len += curl_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, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_is_verbose(data)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
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,
|
||||
};
|
||||
struct curl_trc_feat Curl_trc_feat_timer = {
|
||||
"TIMER",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
static const char * const Curl_trc_timer_names[]={
|
||||
"100_TIMEOUT",
|
||||
"ASYNC_NAME",
|
||||
"CONNECTTIMEOUT",
|
||||
"DNS_PER_NAME",
|
||||
"DNS_PER_NAME2",
|
||||
"HAPPY_EYEBALLS_DNS",
|
||||
"HAPPY_EYEBALLS",
|
||||
"MULTI_PENDING",
|
||||
"SPEEDCHECK",
|
||||
"TIMEOUT",
|
||||
"TOOFAST",
|
||||
"QUIC",
|
||||
"FTP_ACCEPT",
|
||||
"ALPN_EYEBALLS",
|
||||
"SHUTDOWN",
|
||||
};
|
||||
|
||||
static const char *trc_timer_name(int tid)
|
||||
{
|
||||
if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names)))
|
||||
return Curl_trc_timer_names[(size_t)tid];
|
||||
return "UNKNOWN?";
|
||||
}
|
||||
|
||||
void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)) {
|
||||
const char *tname = trc_timer_name(tid);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_timer, tname, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_trc_easy_timers(struct Curl_easy *data)
|
||||
{
|
||||
if(CURL_TRC_TIMER_is_verbose(data)) {
|
||||
struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
|
||||
if(e) {
|
||||
struct curltime now = curlx_now();
|
||||
while(e) {
|
||||
struct time_node *n = Curl_node_elem(e);
|
||||
e = Curl_node_next(e);
|
||||
CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns",
|
||||
curlx_timediff_us(n->time, now));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
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, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
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, 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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
struct curl_trc_feat Curl_trc_feat_ftp = {
|
||||
"FTP",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
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, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#endif /* !CURL_DISABLE_FTP */
|
||||
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
struct curl_trc_feat Curl_trc_feat_smtp = {
|
||||
"SMTP",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#endif /* !CURL_DISABLE_SMTP */
|
||||
|
||||
#ifdef USE_SSL
|
||||
struct curl_trc_feat Curl_trc_feat_ssls = {
|
||||
"SSLS",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
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, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
struct curl_trc_feat Curl_trc_feat_ws = {
|
||||
"WS",
|
||||
CURL_LOG_LVL_NONE,
|
||||
};
|
||||
|
||||
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
|
||||
|
||||
#define TRC_CT_NONE (0)
|
||||
#define TRC_CT_PROTOCOL (1<<(0))
|
||||
#define TRC_CT_NETWORK (1<<(1))
|
||||
#define TRC_CT_PROXY (1<<(2))
|
||||
#define TRC_CT_INTERNALS (1<<(3))
|
||||
|
||||
struct trc_feat_def {
|
||||
struct curl_trc_feat *feat;
|
||||
unsigned int category;
|
||||
};
|
||||
|
||||
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 },
|
||||
{ &Curl_trc_feat_timer, TRC_CT_NETWORK },
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
{ &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
{ &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
#ifdef USE_SSL
|
||||
{ &Curl_trc_feat_ssls, TRC_CT_NETWORK },
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
{ &Curl_trc_feat_ws, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
};
|
||||
|
||||
struct trc_cft_def {
|
||||
struct Curl_cftype *cft;
|
||||
unsigned int category;
|
||||
};
|
||||
|
||||
static struct trc_cft_def trc_cfts[] = {
|
||||
{ &Curl_cft_tcp, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_udp, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_unix, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_tcp_accept, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_ip_happy, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_setup, TRC_CT_PROTOCOL },
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
|
||||
{ &Curl_cft_nghttp2, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
#ifdef USE_SSL
|
||||
{ &Curl_cft_ssl, TRC_CT_NETWORK },
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
{ &Curl_cft_ssl_proxy, TRC_CT_PROXY },
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
{ &Curl_cft_h1_proxy, TRC_CT_PROXY },
|
||||
#ifdef USE_NGHTTP2
|
||||
{ &Curl_cft_h2_proxy, TRC_CT_PROXY },
|
||||
#endif
|
||||
{ &Curl_cft_http_proxy, TRC_CT_PROXY },
|
||||
#endif /* !CURL_DISABLE_HTTP */
|
||||
{ &Curl_cft_haproxy, TRC_CT_PROXY },
|
||||
{ &Curl_cft_socks_proxy, TRC_CT_PROXY },
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
|
||||
{ &Curl_cft_http3, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
{ &Curl_cft_http_connect, TRC_CT_PROTOCOL },
|
||||
#endif
|
||||
};
|
||||
|
||||
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(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(curlx_str_casecompare(token, trc_feats[i].feat->name)) {
|
||||
trc_feats[i].feat->log_level = lvl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void trc_apply_level_by_category(int category, int lvl)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
|
||||
if(!category || (trc_cfts[i].category & category))
|
||||
trc_cfts[i].cft->log_level = lvl;
|
||||
}
|
||||
for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
|
||||
if(!category || (trc_feats[i].category & category))
|
||||
trc_feats[i].feat->log_level = lvl;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode trc_opt(const char *config)
|
||||
{
|
||||
struct Curl_str out;
|
||||
while(!curlx_str_until(&config, &out, 32, ',')) {
|
||||
int lvl = CURL_LOG_LVL_INFO;
|
||||
const char *token = curlx_str(&out);
|
||||
|
||||
if(*token == '-') {
|
||||
lvl = CURL_LOG_LVL_NONE;
|
||||
curlx_str_nudge(&out, 1);
|
||||
}
|
||||
else if(*token == '+')
|
||||
curlx_str_nudge(&out, 1);
|
||||
|
||||
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;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_trc_opt(const char *config)
|
||||
{
|
||||
CURLcode result = config ? trc_opt(config) : CURLE_OK;
|
||||
#ifdef DEBUGBUILD
|
||||
/* CURL_DEBUG can override anything */
|
||||
if(!result) {
|
||||
const char *dbg_config = getenv("CURL_DEBUG");
|
||||
if(dbg_config)
|
||||
result = trc_opt(dbg_config);
|
||||
}
|
||||
#endif /* DEBUGBUILD */
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_trc_init(void)
|
||||
{
|
||||
#ifdef DEBUGBUILD
|
||||
return Curl_trc_opt(NULL);
|
||||
#else
|
||||
return CURLE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* CURL_DISABLE_VERBOSE_STRINGS */
|
||||
|
||||
CURLcode Curl_trc_init(void)
|
||||
{
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)fmt;
|
||||
}
|
||||
|
||||
void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)cf; (void)fmt;
|
||||
}
|
||||
|
||||
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_timer(struct Curl_easy *data, int tid, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)tid; (void)fmt;
|
||||
}
|
||||
|
||||
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)fmt;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)fmt;
|
||||
}
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)fmt;
|
||||
}
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data; (void)fmt;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SSL
|
||||
void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
|
||||
{
|
||||
(void)data;
|
||||
(void)fmt;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
|
||||
Vendored
+237
@@ -0,0 +1,237 @@
|
||||
#ifndef HEADER_CURL_TRC_H
|
||||
#define HEADER_CURL_TRC_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
struct Curl_easy;
|
||||
struct Curl_cfilter;
|
||||
|
||||
/**
|
||||
* Init logging, return != 0 on failure.
|
||||
*/
|
||||
CURLcode Curl_trc_init(void);
|
||||
|
||||
/**
|
||||
* Configure tracing. May be called several times during global
|
||||
* initialization. Later calls may not take effect.
|
||||
*
|
||||
* Configuration format supported:
|
||||
* - comma-separated list of component names to enable logging on.
|
||||
* E.g. 'http/2,ssl'. Unknown names are ignored. Names are compared
|
||||
* case-insensitive.
|
||||
* - component 'all' applies to all known log components
|
||||
* - prefixing a component with '+' or '-' will en-/disable logging for
|
||||
* that component
|
||||
* Example: 'all,-ssl' would enable logging for all components but the
|
||||
* SSL filters.
|
||||
*
|
||||
* @param config configuration string
|
||||
*/
|
||||
CURLcode Curl_trc_opt(const char *config);
|
||||
|
||||
/* the function used to output verbose information */
|
||||
void Curl_debug(struct Curl_easy *data, curl_infotype type,
|
||||
const char *ptr, size_t size);
|
||||
|
||||
/**
|
||||
* Output a failure message on registered callbacks for transfer.
|
||||
*/
|
||||
void Curl_failf(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
|
||||
#define failf Curl_failf
|
||||
|
||||
#define CURL_LOG_LVL_NONE 0
|
||||
#define CURL_LOG_LVL_INFO 1
|
||||
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define CURL_HAVE_C99
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Output an informational message when transfer's verbose logging is enabled.
|
||||
*/
|
||||
void Curl_infof(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
|
||||
/**
|
||||
* 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, 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);
|
||||
const char *Curl_trc_timer_name(int tid);
|
||||
void Curl_trc_easy_timers(struct Curl_easy *data);
|
||||
|
||||
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);
|
||||
void Curl_trc_timer(struct Curl_easy *data, int tid,
|
||||
const char *fmt, ...) CURL_PRINTF(3, 4);
|
||||
|
||||
struct curl_trc_feat {
|
||||
const char *name;
|
||||
int log_level;
|
||||
};
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
extern struct curl_trc_feat Curl_trc_feat_ftp;
|
||||
void Curl_trc_ftp(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
extern struct curl_trc_feat Curl_trc_feat_smtp;
|
||||
void Curl_trc_smtp(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
#endif
|
||||
#ifdef USE_SSL
|
||||
extern struct curl_trc_feat Curl_trc_feat_ssls;
|
||||
void Curl_trc_ssls(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
extern struct curl_trc_feat Curl_trc_feat_ws;
|
||||
void Curl_trc_ws(struct Curl_easy *data,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
#endif
|
||||
|
||||
#define CURL_TRC_M_is_verbose(data) \
|
||||
Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)
|
||||
#define CURL_TRC_DNS_is_verbose(data) \
|
||||
Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)
|
||||
#define CURL_TRC_TIMER_is_verbose(data) \
|
||||
Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)
|
||||
|
||||
#if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
#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_M_is_verbose(data)) \
|
||||
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)
|
||||
#define CURL_TRC_WRITE(data, ...) \
|
||||
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) \
|
||||
Curl_trc_write(data, __VA_ARGS__); } while(0)
|
||||
#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_DNS_is_verbose(data)) \
|
||||
Curl_trc_dns(data, __VA_ARGS__); } while(0)
|
||||
#define CURL_TRC_TIMER(data, tid, ...) \
|
||||
do { if(CURL_TRC_TIMER_is_verbose(data)) \
|
||||
Curl_trc_timer(data, tid, __VA_ARGS__); } while(0)
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
#define CURL_TRC_FTP(data, ...) \
|
||||
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) \
|
||||
Curl_trc_ftp(data, __VA_ARGS__); } while(0)
|
||||
#endif /* !CURL_DISABLE_FTP */
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
#define CURL_TRC_SMTP(data, ...) \
|
||||
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
|
||||
Curl_trc_smtp(data, __VA_ARGS__); } while(0)
|
||||
#endif /* !CURL_DISABLE_SMTP */
|
||||
#ifdef USE_SSL
|
||||
#define CURL_TRC_SSLS(data, ...) \
|
||||
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) \
|
||||
Curl_trc_ssls(data, __VA_ARGS__); } while(0)
|
||||
#endif /* USE_SSL */
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
#define CURL_TRC_WS(data, ...) \
|
||||
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
|
||||
Curl_trc_ws(data, __VA_ARGS__); } while(0)
|
||||
#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
|
||||
|
||||
#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
|
||||
#define CURL_TRC_TIMER Curl_trc_timer
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
#define CURL_TRC_FTP Curl_trc_ftp
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
#define CURL_TRC_SMTP Curl_trc_smtp
|
||||
#endif
|
||||
#ifdef USE_SSL
|
||||
#define CURL_TRC_SSLS Curl_trc_ssls
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
|
||||
#define CURL_TRC_WS Curl_trc_ws
|
||||
#endif
|
||||
|
||||
#endif /* !CURL_HAVE_C99 */
|
||||
|
||||
#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;
|
||||
extern struct curl_trc_feat Curl_trc_feat_timer;
|
||||
|
||||
#define Curl_trc_is_verbose(data) \
|
||||
((data) && (data)->set.verbose && \
|
||||
(!(data)->state.feat || \
|
||||
((data)->state.feat->log_level >= CURL_LOG_LVL_INFO)))
|
||||
#define Curl_trc_cf_is_verbose(cf, data) \
|
||||
(Curl_trc_is_verbose(data) && \
|
||||
(cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
|
||||
#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))
|
||||
#define CURL_TRC_EASY_TIMERS(data) \
|
||||
do { if(CURL_TRC_TIMER_is_verbose(data)) \
|
||||
Curl_trc_easy_timers(data); } while(0)
|
||||
|
||||
#else /* CURL_DISABLE_VERBOSE_STRINGS */
|
||||
/* All informational messages are not compiled in for size savings */
|
||||
|
||||
#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), "-")
|
||||
#define CURL_TRC_EASY_TIMERS(x) Curl_nop_stmt
|
||||
|
||||
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
|
||||
|
||||
#endif /* HEADER_CURL_TRC_H */
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Base64 encoding/decoding */
|
||||
|
||||
#include "../curl_setup.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "warnless.h"
|
||||
#include "base64.h"
|
||||
|
||||
/* The last 2 #include files should be in this order */
|
||||
#ifdef BUILDING_LIBCURL
|
||||
#include "../curl_memory.h"
|
||||
#endif
|
||||
#include "../memdebug.h"
|
||||
|
||||
/* ---- Base64 Encoding/Decoding Table --- */
|
||||
const char Curl_base64encdec[]=
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
|
||||
section 5 */
|
||||
static const char base64url[]=
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
static const unsigned char decodetable[] =
|
||||
{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255,
|
||||
255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,
|
||||
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51 };
|
||||
/*
|
||||
* curlx_base64_decode()
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* When decoded data length is 0, returns NULL in *outptr.
|
||||
*
|
||||
* @unittest: 1302
|
||||
*/
|
||||
CURLcode curlx_base64_decode(const char *src,
|
||||
unsigned char **outptr, size_t *outlen)
|
||||
{
|
||||
size_t srclen = 0;
|
||||
size_t padding = 0;
|
||||
size_t i;
|
||||
size_t numQuantums;
|
||||
size_t fullQuantums;
|
||||
size_t rawlen = 0;
|
||||
unsigned char *pos;
|
||||
unsigned char *newstr;
|
||||
unsigned char lookup[256];
|
||||
|
||||
*outptr = NULL;
|
||||
*outlen = 0;
|
||||
srclen = strlen(src);
|
||||
|
||||
/* Check the length of the input string is valid */
|
||||
if(!srclen || srclen % 4)
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
|
||||
/* srclen is at least 4 here */
|
||||
while(src[srclen - 1 - padding] == '=') {
|
||||
/* count padding characters */
|
||||
padding++;
|
||||
/* A maximum of two = padding characters is allowed */
|
||||
if(padding > 2)
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
/* Calculate the number of quantums */
|
||||
numQuantums = srclen / 4;
|
||||
fullQuantums = numQuantums - (padding ? 1 : 0);
|
||||
|
||||
/* Calculate the size of the decoded string */
|
||||
rawlen = (numQuantums * 3) - padding;
|
||||
|
||||
/* Allocate our buffer including room for a null-terminator */
|
||||
newstr = malloc(rawlen + 1);
|
||||
if(!newstr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
pos = newstr;
|
||||
|
||||
memset(lookup, 0xff, sizeof(lookup));
|
||||
memcpy(&lookup['+'], decodetable, sizeof(decodetable));
|
||||
|
||||
/* Decode the complete quantums first */
|
||||
for(i = 0; i < fullQuantums; i++) {
|
||||
unsigned char val;
|
||||
unsigned int x = 0;
|
||||
int j;
|
||||
|
||||
for(j = 0; j < 4; j++) {
|
||||
val = lookup[(unsigned char)*src++];
|
||||
if(val == 0xff) /* bad symbol */
|
||||
goto bad;
|
||||
x = (x << 6) | val;
|
||||
}
|
||||
pos[2] = x & 0xff;
|
||||
pos[1] = (x >> 8) & 0xff;
|
||||
pos[0] = (x >> 16) & 0xff;
|
||||
pos += 3;
|
||||
}
|
||||
if(padding) {
|
||||
/* this means either 8 or 16 bits output */
|
||||
unsigned char val;
|
||||
unsigned int x = 0;
|
||||
int j;
|
||||
size_t padc = 0;
|
||||
for(j = 0; j < 4; j++) {
|
||||
if(*src == '=') {
|
||||
x <<= 6;
|
||||
src++;
|
||||
if(++padc > padding)
|
||||
/* this is a badly placed '=' symbol! */
|
||||
goto bad;
|
||||
}
|
||||
else {
|
||||
val = lookup[(unsigned char)*src++];
|
||||
if(val == 0xff) /* bad symbol */
|
||||
goto bad;
|
||||
x = (x << 6) | val;
|
||||
}
|
||||
}
|
||||
if(padding == 1)
|
||||
pos[1] = (x >> 8) & 0xff;
|
||||
pos[0] = (x >> 16) & 0xff;
|
||||
pos += 3 - padding;
|
||||
}
|
||||
|
||||
/* Zero terminate */
|
||||
*pos = '\0';
|
||||
|
||||
/* Return the decoded data */
|
||||
*outptr = newstr;
|
||||
*outlen = rawlen;
|
||||
|
||||
return CURLE_OK;
|
||||
bad:
|
||||
free(newstr);
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
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 = (const unsigned char *)inputbuff;
|
||||
|
||||
*outptr = NULL;
|
||||
*outlen = 0;
|
||||
|
||||
if(!insize)
|
||||
return CURLE_OK;
|
||||
|
||||
/* safety precaution */
|
||||
DEBUGASSERT(insize <= CURL_MAX_BASE64_INPUT);
|
||||
if(insize > CURL_MAX_BASE64_INPUT)
|
||||
return CURLE_TOO_LARGE;
|
||||
|
||||
base64data = output = malloc((insize + 2) / 3 * 4 + 1);
|
||||
if(!output)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
while(insize >= 3) {
|
||||
*output++ = table64[ in[0] >> 2 ];
|
||||
*output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ];
|
||||
*output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ];
|
||||
*output++ = table64[ in[2] & 0x3F ];
|
||||
insize -= 3;
|
||||
in += 3;
|
||||
}
|
||||
if(insize) {
|
||||
/* this is only one or two bytes now */
|
||||
*output++ = table64[ in[0] >> 2 ];
|
||||
if(insize == 1) {
|
||||
*output++ = table64[ ((in[0] & 0x03) << 4) ];
|
||||
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(padbyte)
|
||||
*output++ = padbyte;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zero terminate */
|
||||
*output = '\0';
|
||||
|
||||
/* Return the pointer to the new data (allocated memory) */
|
||||
*outptr = base64data;
|
||||
|
||||
/* Return the length of the new data */
|
||||
*outlen = (size_t)(output - base64data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Returns CURLE_OK on success, otherwise specific error code. Function
|
||||
* output shall not be considered valid unless CURLE_OK is returned.
|
||||
*
|
||||
* @unittest: 1302
|
||||
*/
|
||||
CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
return base64_encode(Curl_base64encdec, '=',
|
||||
inputbuff, insize, outptr, outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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 curlx_base64url_encode(const char *inputbuff, size_t insize,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
return base64_encode(base64url, 0, inputbuff, insize, outptr, outlen);
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
#ifndef HEADER_CURL_BASE64_H
|
||||
#define HEADER_CURL_BASE64_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
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[];
|
||||
|
||||
/* maximum input length acceptable to base64 encode, here to catch and prevent
|
||||
mistakes */
|
||||
#define CURL_MAX_BASE64_INPUT 16000000
|
||||
|
||||
#endif /* HEADER_CURL_BASE64_H */
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_TOOL_BINMODE_H
|
||||
#define HEADER_CURL_TOOL_BINMODE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "../curl_setup.h"
|
||||
|
||||
#if (defined(HAVE_SETMODE) || defined(HAVE__SETMODE)) && defined(O_BINARY)
|
||||
/* Requires io.h and/or fcntl.h when available */
|
||||
#ifdef HAVE__SETMODE
|
||||
# define CURLX_SET_BINMODE(stream) (void)_setmode(fileno(stream), O_BINARY)
|
||||
#else
|
||||
# define CURLX_SET_BINMODE(stream) (void)setmode(fileno(stream), O_BINARY)
|
||||
#endif
|
||||
#else
|
||||
# define CURLX_SET_BINMODE(stream) (void)stream; Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_BINMODE_H */
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
#ifndef HEADER_CURL_CURLX_H
|
||||
#define HEADER_CURL_CURLX_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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Defines protos and includes all header files that provide the curlx_*
|
||||
* functions. The curlx_* functions are not part of the libcurl API, but are
|
||||
* stand-alone functions whose sources can be built and linked by apps if need
|
||||
* be.
|
||||
*/
|
||||
|
||||
#include "binmode.h"
|
||||
/* "binmode.h" provides macro CURLX_SET_BINMODE() */
|
||||
|
||||
#include "nonblock.h"
|
||||
/* "nonblock.h" provides curlx_nonblock() */
|
||||
|
||||
#include "warnless.h"
|
||||
/* "warnless.h" provides functions:
|
||||
|
||||
curlx_ultous()
|
||||
curlx_ultouc()
|
||||
curlx_uztosi()
|
||||
*/
|
||||
|
||||
#include "multibyte.h"
|
||||
/* "multibyte.h" provides these functions and macros:
|
||||
|
||||
curlx_convert_UTF8_to_wchar()
|
||||
curlx_convert_wchar_to_UTF8()
|
||||
curlx_convert_UTF8_to_tchar()
|
||||
curlx_convert_tchar_to_UTF8()
|
||||
curlx_unicodefree()
|
||||
*/
|
||||
|
||||
#include "version_win32.h"
|
||||
/* provides curlx_verify_windows_version() */
|
||||
|
||||
#include "strerr.h"
|
||||
/* The curlx_strerror() function */
|
||||
|
||||
#include "strparse.h"
|
||||
/* The curlx_str_* parsing functions */
|
||||
|
||||
#include "dynbuf.h"
|
||||
/* The curlx_dyn_* functions */
|
||||
|
||||
#include "fopen.h"
|
||||
/* The curlx_f* functions */
|
||||
|
||||
#include "base64.h"
|
||||
#include "timeval.h"
|
||||
#include "timediff.h"
|
||||
|
||||
#include "wait.h"
|
||||
/* for curlx_wait_ms */
|
||||
|
||||
#include "winapi.h"
|
||||
/* for curlx_winapi_strerror */
|
||||
|
||||
#include "inet_pton.h"
|
||||
/* for curlx_inet_pton */
|
||||
|
||||
#include "inet_ntop.h"
|
||||
/* for curlx_inet_ntop */
|
||||
|
||||
#endif /* HEADER_CURL_CURLX_H */
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "dynbuf.h"
|
||||
#include "../curl_printf.h"
|
||||
#ifdef BUILDING_LIBCURL
|
||||
#include "../curl_memory.h"
|
||||
#endif
|
||||
#include "../memdebug.h"
|
||||
|
||||
#define MIN_FIRST_ALLOC 32
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
#define DYNINIT 0xbee51da /* random pattern */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Init a dynbuf struct.
|
||||
*/
|
||||
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;
|
||||
s->toobig = toobig;
|
||||
#ifdef DEBUGBUILD
|
||||
s->init = DYNINIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 curlx_dyn_free(struct dynbuf *s)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
Curl_safefree(s->bufr);
|
||||
s->leng = s->allc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store/append an chunk of memory to the dynbuf.
|
||||
*/
|
||||
static CURLcode dyn_nappend(struct dynbuf *s,
|
||||
const unsigned char *mem, size_t len)
|
||||
{
|
||||
size_t idx = s->leng;
|
||||
size_t a = s->allc;
|
||||
size_t fit = len + idx + 1; /* new string + old string + zero byte */
|
||||
|
||||
/* try to detect if there is rubbish in the struct */
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(s->toobig);
|
||||
DEBUGASSERT(idx < s->toobig);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
DEBUGASSERT(a <= s->toobig);
|
||||
DEBUGASSERT(!len || mem);
|
||||
|
||||
if(fit > s->toobig) {
|
||||
curlx_dyn_free(s);
|
||||
return CURLE_TOO_LARGE;
|
||||
}
|
||||
else if(!a) {
|
||||
DEBUGASSERT(!idx);
|
||||
/* first invoke */
|
||||
if(MIN_FIRST_ALLOC > s->toobig)
|
||||
a = s->toobig;
|
||||
else if(fit < MIN_FIRST_ALLOC)
|
||||
a = MIN_FIRST_ALLOC;
|
||||
else
|
||||
a = fit;
|
||||
}
|
||||
else {
|
||||
while(a < fit)
|
||||
a *= 2;
|
||||
if(a > s->toobig)
|
||||
/* no point in allocating a larger buffer than this is allowed to use */
|
||||
a = s->toobig;
|
||||
}
|
||||
|
||||
if(a != s->allc) {
|
||||
/* this logic is not using Curl_saferealloc() to make the tool not have to
|
||||
include that as well when it uses this code */
|
||||
void *p = realloc(s->bufr, a);
|
||||
if(!p) {
|
||||
curlx_dyn_free(s);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
s->bufr = p;
|
||||
s->allc = a;
|
||||
}
|
||||
|
||||
if(len)
|
||||
memcpy(&s->bufr[idx], mem, len);
|
||||
s->leng = idx + len;
|
||||
s->bufr[s->leng] = 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears the string, keeps the allocation. This can also be called on a
|
||||
* buffer that already was freed.
|
||||
*/
|
||||
void curlx_dyn_reset(struct dynbuf *s)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
if(s->leng)
|
||||
s->bufr[0] = 0;
|
||||
s->leng = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specify the size of the tail to keep (number of bytes from the end of the
|
||||
* buffer). The rest will be dropped.
|
||||
*/
|
||||
CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
if(trail > s->leng)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
else if(trail == s->leng)
|
||||
return CURLE_OK;
|
||||
else if(!trail) {
|
||||
curlx_dyn_reset(s);
|
||||
}
|
||||
else {
|
||||
memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
|
||||
s->leng = trail;
|
||||
s->bufr[s->leng] = 0;
|
||||
}
|
||||
return CURLE_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a buffer with length.
|
||||
*/
|
||||
CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
return dyn_nappend(s, mem, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a null-terminated string at the end.
|
||||
*/
|
||||
CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
|
||||
{
|
||||
size_t n;
|
||||
DEBUGASSERT(str);
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
n = strlen(str);
|
||||
return dyn_nappend(s, (const unsigned char *)str, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a string vprintf()-style
|
||||
*/
|
||||
CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
|
||||
{
|
||||
#ifdef BUILDING_LIBCURL
|
||||
int rc;
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
DEBUGASSERT(fmt);
|
||||
rc = curlx_dyn_vprintf(s, fmt, ap);
|
||||
|
||||
if(!rc)
|
||||
return CURLE_OK;
|
||||
else if(rc == MERR_TOO_LARGE)
|
||||
return CURLE_TOO_LARGE;
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
#else
|
||||
char *str;
|
||||
str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
|
||||
|
||||
if(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 */
|
||||
curlx_dyn_free(s);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a string printf()-style
|
||||
*/
|
||||
CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
|
||||
{
|
||||
CURLcode result;
|
||||
va_list ap;
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
DEBUGASSERT(strcmp(fmt, "%s")); /* use curlx_dyn_add instead */
|
||||
va_start(ap, fmt);
|
||||
result = curlx_dyn_vaddf(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the buffer.
|
||||
*/
|
||||
char *curlx_dyn_ptr(const struct dynbuf *s)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
return s->bufr;
|
||||
}
|
||||
|
||||
char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
|
||||
{
|
||||
char *ptr = s->bufr;
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
*plen = s->leng;
|
||||
s->bufr = NULL;
|
||||
s->leng = 0;
|
||||
s->allc = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an unsigned pointer to the buffer.
|
||||
*/
|
||||
unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
return (unsigned char *)s->bufr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the length of the buffer.
|
||||
*/
|
||||
size_t curlx_dyn_len(const struct dynbuf *s)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
return s->leng;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a new (smaller) length.
|
||||
*/
|
||||
CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
|
||||
{
|
||||
DEBUGASSERT(s);
|
||||
DEBUGASSERT(s->init == DYNINIT);
|
||||
DEBUGASSERT(!s->leng || s->bufr);
|
||||
if(set > s->leng)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
s->leng = set;
|
||||
s->bufr[s->leng] = 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
#ifndef HEADER_CURL_DYNBUF_H
|
||||
#define HEADER_CURL_DYNBUF_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/curl.h>
|
||||
|
||||
struct dynbuf {
|
||||
char *bufr; /* point to a null-terminated allocated buffer */
|
||||
size_t leng; /* number of bytes *EXCLUDING* the null-terminator */
|
||||
size_t allc; /* size of the current allocation */
|
||||
size_t toobig; /* size limit for the buffer */
|
||||
#ifdef DEBUGBUILD
|
||||
int init; /* detect API usage mistakes */
|
||||
#endif
|
||||
};
|
||||
|
||||
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 curlx_dyn_add(struct dynbuf *s, const char *str)
|
||||
WARN_UNUSED_RESULT;
|
||||
CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
|
||||
WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
|
||||
CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
|
||||
WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
|
||||
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 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 *curlx_dyn_take(struct dynbuf *s, size_t *plen);
|
||||
|
||||
/* Dynamic buffer max sizes */
|
||||
#define MAX_DYNBUF_SIZE (SIZE_MAX/2)
|
||||
|
||||
#define DYN_DOH_RESPONSE 3000
|
||||
#define DYN_DOH_CNAME 256
|
||||
#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
|
||||
#define DYN_HAXPROXY 2048
|
||||
#define DYN_HTTP_REQUEST (1024*1024)
|
||||
#define DYN_APRINTF 8000000
|
||||
#define DYN_RTSP_REQ_HEADER (64*1024)
|
||||
#define DYN_TRAILERS (64*1024)
|
||||
#define DYN_PROXY_CONNECT_HEADERS 16384
|
||||
#define DYN_QLOG_NAME 1024
|
||||
#define DYN_H1_TRAILER 4096
|
||||
#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
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* 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 "fopen.h"
|
||||
|
||||
int curlx_fseek(void *stream, curl_off_t offset, int whence)
|
||||
{
|
||||
#if defined(_WIN32) && defined(USE_WIN32_LARGE_FILES)
|
||||
return _fseeki64(stream, (__int64)offset, whence);
|
||||
#elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
|
||||
return fseeko(stream, (off_t)offset, whence);
|
||||
#else
|
||||
if(offset > LONG_MAX)
|
||||
return -1;
|
||||
return fseek(stream, (long)offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
#include "multibyte.h"
|
||||
|
||||
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
|
||||
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
|
||||
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
|
||||
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
|
||||
#endif
|
||||
|
||||
/* Fix excessive paths (paths that exceed MAX_PATH length of 260).
|
||||
*
|
||||
* This is a helper function to fix paths that would exceed the MAX_PATH
|
||||
* limitation check done by Windows APIs. It does so by normalizing the passed
|
||||
* in filename or path 'in' to its full canonical path, and if that path is
|
||||
* longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path.
|
||||
*
|
||||
* For example 'in' filename255chars in current directory C:\foo\bar is
|
||||
* fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows
|
||||
* it is ok to access that filename even though the actual full path is longer
|
||||
* than 260 chars.
|
||||
*
|
||||
* For non-Unicode builds this function may fail sometimes because only the
|
||||
* Unicode versions of some Windows API functions can access paths longer than
|
||||
* MAX_PATH, for example GetFullPathNameW which is used in this function. When
|
||||
* the full path is then converted from Unicode to multibyte that fails if any
|
||||
* directories in the path contain characters not in the current codepage.
|
||||
*/
|
||||
static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
|
||||
{
|
||||
size_t needed, count;
|
||||
const wchar_t *in_w;
|
||||
wchar_t *fbuf = NULL;
|
||||
|
||||
/* MS documented "approximate" limit for the maximum path length */
|
||||
const size_t max_path_len = 32767;
|
||||
|
||||
#ifndef _UNICODE
|
||||
wchar_t *ibuf = NULL;
|
||||
char *obuf = NULL;
|
||||
#endif
|
||||
|
||||
*out = NULL;
|
||||
|
||||
/* skip paths already normalized */
|
||||
if(!_tcsncmp(in, _T("\\\\?\\"), 4))
|
||||
goto cleanup;
|
||||
|
||||
#ifndef _UNICODE
|
||||
/* convert multibyte input to unicode */
|
||||
needed = mbstowcs(NULL, in, 0);
|
||||
if(needed == (size_t)-1 || needed >= max_path_len)
|
||||
goto cleanup;
|
||||
++needed; /* for NUL */
|
||||
ibuf = (malloc)(needed * sizeof(wchar_t));
|
||||
if(!ibuf)
|
||||
goto cleanup;
|
||||
count = mbstowcs(ibuf, in, needed);
|
||||
if(count == (size_t)-1 || count >= needed)
|
||||
goto cleanup;
|
||||
in_w = ibuf;
|
||||
#else
|
||||
in_w = in;
|
||||
#endif
|
||||
|
||||
/* GetFullPathNameW returns the normalized full path in unicode. It converts
|
||||
forward slashes to backslashes, processes .. to remove directory segments,
|
||||
etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */
|
||||
needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
|
||||
if(!needed || needed > max_path_len)
|
||||
goto cleanup;
|
||||
/* skip paths that are not excessive and do not need modification */
|
||||
if(needed <= MAX_PATH)
|
||||
goto cleanup;
|
||||
fbuf = (malloc)(needed * sizeof(wchar_t));
|
||||
if(!fbuf)
|
||||
goto cleanup;
|
||||
count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
|
||||
if(!count || count >= needed)
|
||||
goto cleanup;
|
||||
|
||||
/* prepend \\?\ or \\?\UNC\ to the excessively long path.
|
||||
*
|
||||
* c:\longpath ---> \\?\c:\longpath
|
||||
* \\.\c:\longpath ---> \\?\c:\longpath
|
||||
* \\?\c:\longpath ---> \\?\c:\longpath (unchanged)
|
||||
* \\server\c$\longpath ---> \\?\UNC\server\c$\longpath
|
||||
*
|
||||
* https://learn.microsoft.com/dotnet/standard/io/file-path-formats
|
||||
*/
|
||||
if(!wcsncmp(fbuf, L"\\\\?\\", 4))
|
||||
; /* do nothing */
|
||||
else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
|
||||
fbuf[2] = '?';
|
||||
else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
|
||||
/* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */
|
||||
goto cleanup;
|
||||
}
|
||||
else {
|
||||
wchar_t *temp;
|
||||
|
||||
if(!wcsncmp(fbuf, L"\\\\", 2)) {
|
||||
/* "\\?\UNC\" + full path without "\\" + null */
|
||||
needed = 8 + (count - 2) + 1;
|
||||
if(needed > max_path_len)
|
||||
goto cleanup;
|
||||
|
||||
temp = (malloc)(needed * sizeof(wchar_t));
|
||||
if(!temp)
|
||||
goto cleanup;
|
||||
|
||||
wcsncpy(temp, L"\\\\?\\UNC\\", 8);
|
||||
wcscpy(temp + 8, fbuf + 2);
|
||||
}
|
||||
else {
|
||||
/* "\\?\" + full path + null */
|
||||
needed = 4 + count + 1;
|
||||
if(needed > max_path_len)
|
||||
goto cleanup;
|
||||
|
||||
temp = (malloc)(needed * sizeof(wchar_t));
|
||||
if(!temp)
|
||||
goto cleanup;
|
||||
|
||||
wcsncpy(temp, L"\\\\?\\", 4);
|
||||
wcscpy(temp + 4, fbuf);
|
||||
}
|
||||
|
||||
(free)(fbuf);
|
||||
fbuf = temp;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
/* convert unicode full path to multibyte output */
|
||||
needed = wcstombs(NULL, fbuf, 0);
|
||||
if(needed == (size_t)-1 || needed >= max_path_len)
|
||||
goto cleanup;
|
||||
++needed; /* for NUL */
|
||||
obuf = (malloc)(needed);
|
||||
if(!obuf)
|
||||
goto cleanup;
|
||||
count = wcstombs(obuf, fbuf, needed);
|
||||
if(count == (size_t)-1 || count >= needed)
|
||||
goto cleanup;
|
||||
*out = obuf;
|
||||
obuf = NULL;
|
||||
#else
|
||||
*out = fbuf;
|
||||
fbuf = NULL;
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
(free)(fbuf);
|
||||
#ifndef _UNICODE
|
||||
(free)(ibuf);
|
||||
(free)(obuf);
|
||||
#endif
|
||||
return *out ? true : false;
|
||||
}
|
||||
|
||||
int curlx_win32_open(const char *filename, int oflag, ...)
|
||||
{
|
||||
int pmode = 0;
|
||||
int result = -1;
|
||||
TCHAR *fixed = NULL;
|
||||
const TCHAR *target = NULL;
|
||||
|
||||
#ifdef _UNICODE
|
||||
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
|
||||
#endif
|
||||
|
||||
va_list param;
|
||||
va_start(param, oflag);
|
||||
if(oflag & O_CREAT)
|
||||
pmode = va_arg(param, int);
|
||||
va_end(param);
|
||||
|
||||
#ifdef _UNICODE
|
||||
if(filename_w) {
|
||||
if(fix_excessive_path(filename_w, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = filename_w;
|
||||
result = _wopen(target, oflag, pmode);
|
||||
curlx_unicodefree(filename_w);
|
||||
}
|
||||
else
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
CURL_SETERRNO(EINVAL);
|
||||
#else
|
||||
if(fix_excessive_path(filename, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = filename;
|
||||
result = _open(target, oflag, pmode);
|
||||
#endif
|
||||
|
||||
(free)(fixed);
|
||||
return result;
|
||||
}
|
||||
|
||||
FILE *curlx_win32_fopen(const char *filename, const char *mode)
|
||||
{
|
||||
FILE *result = NULL;
|
||||
TCHAR *fixed = NULL;
|
||||
const TCHAR *target = NULL;
|
||||
|
||||
#ifdef _UNICODE
|
||||
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
|
||||
wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
|
||||
if(filename_w && mode_w) {
|
||||
if(fix_excessive_path(filename_w, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = filename_w;
|
||||
result = _wfopen(target, mode_w);
|
||||
}
|
||||
else
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
CURL_SETERRNO(EINVAL);
|
||||
curlx_unicodefree(filename_w);
|
||||
curlx_unicodefree(mode_w);
|
||||
#else
|
||||
if(fix_excessive_path(filename, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = filename;
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
result = fopen(target, mode);
|
||||
#endif
|
||||
|
||||
(free)(fixed);
|
||||
return result;
|
||||
}
|
||||
|
||||
int curlx_win32_stat(const char *path, struct_stat *buffer)
|
||||
{
|
||||
int result = -1;
|
||||
TCHAR *fixed = NULL;
|
||||
const TCHAR *target = NULL;
|
||||
|
||||
#ifdef _UNICODE
|
||||
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
|
||||
if(path_w) {
|
||||
if(fix_excessive_path(path_w, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = path_w;
|
||||
#ifndef USE_WIN32_LARGE_FILES
|
||||
result = _wstat(target, buffer);
|
||||
#else
|
||||
result = _wstati64(target, buffer);
|
||||
#endif
|
||||
curlx_unicodefree(path_w);
|
||||
}
|
||||
else
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
CURL_SETERRNO(EINVAL);
|
||||
#else
|
||||
if(fix_excessive_path(path, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = path;
|
||||
#ifndef USE_WIN32_LARGE_FILES
|
||||
result = _stat(target, buffer);
|
||||
#else
|
||||
result = _stati64(target, buffer);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
(free)(fixed);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 && !UNDER_CE */
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#ifndef HEADER_CURLX_FOPEN_H
|
||||
#define HEADER_CURLX_FOPEN_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"
|
||||
|
||||
#include "multibyte.h"
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h> /* for open() and attributes */
|
||||
#endif
|
||||
|
||||
int curlx_fseek(void *stream, curl_off_t offset, int whence);
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
FILE *curlx_win32_fopen(const char *filename, const char *mode);
|
||||
int curlx_win32_stat(const char *path, struct_stat *buffer);
|
||||
int curlx_win32_open(const char *filename, int oflag, ...);
|
||||
#define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode)
|
||||
#define curlx_stat(fname, stp) curlx_win32_stat(fname, stp)
|
||||
#define curlx_open curlx_win32_open
|
||||
#else
|
||||
#define CURLX_FOPEN_LOW fopen
|
||||
#define curlx_stat(fname, stp) stat(fname, stp)
|
||||
#define curlx_open open
|
||||
#endif
|
||||
|
||||
#ifdef CURLDEBUG
|
||||
#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
|
||||
#define curlx_fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
|
||||
#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
|
||||
#else
|
||||
#define curlx_fopen CURLX_FOPEN_LOW
|
||||
#define curlx_fdopen fdopen
|
||||
#define curlx_fclose fclose
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURLX_FOPEN_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user