diff options
author | Brad King <brad.king@kitware.com> | 2023-08-01 17:58:24 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2023-08-01 17:58:24 (GMT) |
commit | 188c065e5a447e4c659426e0c27051928c8adb6e (patch) | |
tree | 91af173dfc4e42b50510e998778aa4886d68faeb /Utilities/cmcurl | |
parent | 1345c21275574dd66f7adadc9123682488856ba1 (diff) | |
parent | e2ab2da70a2b390eb9067d45dfa47023b00c5cd7 (diff) | |
download | CMake-188c065e5a447e4c659426e0c27051928c8adb6e.zip CMake-188c065e5a447e4c659426e0c27051928c8adb6e.tar.gz CMake-188c065e5a447e4c659426e0c27051928c8adb6e.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2023-07-26 (50490c06)
Diffstat (limited to 'Utilities/cmcurl')
92 files changed, 2461 insertions, 1710 deletions
diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake index ff0d49e..ae92e41 100644 --- a/Utilities/cmcurl/CMake/FindNGTCP2.cmake +++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake @@ -31,7 +31,7 @@ Find the ngtcp2 library This module accepts optional COMPONENTS to control the crypto library (these are mutually exclusive):: - OpenSSL: Use libngtcp2_crypto_openssl + OpenSSL: Use libngtcp2_crypto_quictls GnuTLS: Use libngtcp2_crypto_gnutls Result Variables @@ -71,7 +71,7 @@ endif() if(NGTCP2_FIND_COMPONENTS) set(NGTCP2_CRYPTO_BACKEND "") foreach(component IN LISTS NGTCP2_FIND_COMPONENTS) - if(component MATCHES "^(BoringSSL|OpenSSL|wolfSSL|GnuTLS)") + if(component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)") if(NGTCP2_CRYPTO_BACKEND) message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected") endif() diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 82f9b0b..ced5af4 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -242,6 +242,8 @@ endif() include_directories(${CURL_SOURCE_DIR}/include) +set(CMAKE_UNITY_BUILD_BATCH_SIZE 0) + option(CURL_WERROR "Turn compiler warnings into errors" OFF) option(PICKY_COMPILER "Enable picky compiler options" ON) option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) @@ -689,7 +691,7 @@ endif() option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF) set(HAVE_BROTLI OFF) if(CURL_BROTLI) - find_package(Brotli QUIET) + find_package(Brotli REQUIRED) if(BROTLI_FOUND) set(HAVE_BROTLI ON) list(APPEND CURL_LIBS ${BROTLI_LIBRARIES}) @@ -768,7 +770,7 @@ if(USE_NGTCP2) elseif(HAVE_BORINGSSL) find_package(NGTCP2 REQUIRED BoringSSL) else() - find_package(NGTCP2 REQUIRED OpenSSL) + find_package(NGTCP2 REQUIRED quictls) endif() CheckQuicSupportInOpenSSL() elseif(USE_GNUTLS) @@ -839,9 +841,7 @@ if(NOT CURL_DISABLE_LDAP) endif() # Now that we know, we're not using windows LDAP... - if(USE_WIN32_LDAP) - check_include_file_concat("winldap.h" HAVE_WINLDAP_H) - else() + if(NOT USE_WIN32_LDAP) # Check for LDAP set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h index cae9b1c..b668dc0 100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@ -93,7 +93,7 @@ defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \ (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \ - defined(__sun__) || defined(__serenity__) + defined(__sun__) || defined(__serenity__) || defined(__vxworks__) #include <sys/select.h> #endif @@ -781,7 +781,7 @@ typedef enum { CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ CURLPROXY_HTTPS = 2, /* HTTPS but stick to HTTP/1 added in 7.52.0 */ - CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.1.0 */ + CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ @@ -2113,7 +2113,7 @@ typedef enum { CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289), /* allow RCPT TO command to fail for some recipients */ - CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290), + CURLOPT(CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOPTTYPE_LONG, 290), /* the private SSL-certificate as a "blob" */ CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291), @@ -2207,6 +2207,9 @@ typedef enum { /* Can leak things, gonna exit() soon */ CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), + /* set a specific client IP for HAProxy PROXY protocol header? */ + CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2235,6 +2238,9 @@ typedef enum { /* */ #define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT +/* Added in 8.2.0 */ +#define CURLOPT_MAIL_RCPT_ALLLOWFAILS CURLOPT_MAIL_RCPT_ALLOWFAILS + #else /* This is set if CURL_NO_OLDIES is defined at compile-time */ #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ @@ -2918,7 +2924,9 @@ typedef enum { CURLINFO_REFERER = CURLINFO_STRING + 60, CURLINFO_CAINFO = CURLINFO_STRING + 61, CURLINFO_CAPATH = CURLINFO_STRING + 62, - CURLINFO_LASTONE = 62 + CURLINFO_XFER_ID = CURLINFO_OFF_T + 63, + CURLINFO_CONN_ID = CURLINFO_OFF_T + 64, + CURLINFO_LASTONE = 64 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h index 5588fa5..4c39a6d 100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -32,13 +32,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.1.2" +#define LIBCURL_VERSION "8.2.1" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 1 -#define LIBCURL_VERSION_PATCH 2 +#define LIBCURL_VERSION_MINOR 2 +#define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will @@ -59,7 +59,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x080102 +#define LIBCURL_VERSION_NUM 0x080201 /* * This is the date and time when the full source package was created. The diff --git a/Utilities/cmcurl/include/curl/system.h b/Utilities/cmcurl/include/curl/system.h index def7739..b2640c8 100644 --- a/Utilities/cmcurl/include/curl/system.h +++ b/Utilities/cmcurl/include/curl/system.h @@ -237,33 +237,28 @@ # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__MVS__) -# if defined(__IBMC__) || defined(__IBMCPP__) -# if defined(_ILP32) -# elif defined(_LP64) -# endif -# if defined(_LONG_LONG) -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL -# elif defined(_LP64) -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# else -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL -# endif -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_SYS_SOCKET_H 1 +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__370__) # if defined(__IBMC__) || defined(__IBMCPP__) diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h index bc8d7a7..b880f3d 100644 --- a/Utilities/cmcurl/include/curl/typecheck-gcc.h +++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h @@ -280,6 +280,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ (option) == CURLOPT_FTPPORT || \ (option) == CURLOPT_HSTS || \ + (option) == CURLOPT_HAPROXY_CLIENT_IP || \ (option) == CURLOPT_INTERFACE || \ (option) == CURLOPT_ISSUERCERT || \ (option) == CURLOPT_KEYPASSWD || \ diff --git a/Utilities/cmcurl/include/curl/websockets.h b/Utilities/cmcurl/include/curl/websockets.h index fd6a916..6ef6a2b 100644 --- a/Utilities/cmcurl/include/curl/websockets.h +++ b/Utilities/cmcurl/include/curl/websockets.h @@ -54,13 +54,13 @@ struct curl_ws_frame { */ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, size_t *recv, - struct curl_ws_frame **metap); + const struct curl_ws_frame **metap); -/* sendflags for curl_ws_send() */ +/* flags for curl_ws_send() */ #define CURLWS_PONG (1<<6) /* - * NAME curl_easy_send() + * NAME curl_ws_send() * * DESCRIPTION * @@ -69,13 +69,13 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, */ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, size_t buflen, size_t *sent, - curl_off_t framesize, - unsigned int sendflags); + curl_off_t fragsize, + unsigned int flags); /* bits for the CURLOPT_WS_OPTIONS bitmask: */ #define CURLWS_RAW_MODE (1<<0) -CURL_EXTERN struct curl_ws_frame *curl_ws_meta(CURL *curl); +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl); #ifdef __cplusplus } diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index ba75420..20249fe 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -90,15 +90,30 @@ add_library( ) add_library( + curlu # special libcurlu library just for unittests + STATIC + EXCLUDE_FROM_ALL + ${HHEADERS} ${CSOURCES} +) +target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB) + +add_library( ${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_NAME} ) +if(ENABLE_CURLDEBUG) + # We must compile memdebug.c separately to avoid memdebug.h redefinitions + # being applied to memdebug.c itself. + set_source_files_properties(memdebug.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) +endif() + if(NOT BUILD_SHARED_LIBS) set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB) endif() target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS}) +target_link_libraries(curlu PRIVATE ${CURL_LIBS}) if(0) # This code not needed for building within CMake. transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake") diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index f815170..cc7d287 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -72,6 +72,7 @@ LIB_VTLS_HFILES = \ vtls/openssl.h \ vtls/rustls.h \ vtls/schannel.h \ + vtls/schannel_int.h \ vtls/sectransp.h \ vtls/vtls.h \ vtls/vtls_int.h \ @@ -179,6 +180,7 @@ LIB_CFILES = \ krb5.c \ ldap.c \ llist.c \ + macos.c \ md4.c \ md5.c \ memdebug.c \ @@ -315,6 +317,7 @@ LIB_HFILES = \ inet_ntop.h \ inet_pton.h \ llist.h \ + macos.h \ memdebug.h \ mime.h \ mqtt.h \ diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c index f812baf..11009d5 100644 --- a/Utilities/cmcurl/lib/altsvc.c +++ b/Utilities/cmcurl/lib/altsvc.c @@ -424,7 +424,7 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, #ifdef DEBUGBUILD /* to play well with debug builds, we can *set* a fixed time this will return */ -static time_t debugtime(void *unused) +static time_t altsvc_debugtime(void *unused) { char *timestr = getenv("CURL_TIME"); (void)unused; @@ -434,7 +434,8 @@ static time_t debugtime(void *unused) } return time(NULL); } -#define time(x) debugtime(x) +#undef time +#define time(x) altsvc_debugtime(x) #endif #define ISNEWLINE(x) (((x) == '\n') || (x) == '\r') diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c index b0a9500..139309b 100644 --- a/Utilities/cmcurl/lib/amigaos.c +++ b/Utilities/cmcurl/lib/amigaos.c @@ -178,6 +178,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, #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) { diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c index 971300e..9d495d4 100644 --- a/Utilities/cmcurl/lib/base64.c +++ b/Utilities/cmcurl/lib/base64.c @@ -43,7 +43,7 @@ /* ---- Base64 Encoding/Decoding Table --- */ /* Padding character string starts at offset 64. */ -static const char base64[]= +static const char base64encdec[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; /* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648 @@ -120,7 +120,7 @@ CURLcode Curl_base64_decode(const char *src, /* replaces { unsigned char c; - const unsigned char *p = (const unsigned char *)base64; + const unsigned char *p = (const unsigned char *)base64encdec; for(c = 0; *p; c++, p++) lookup[*p] = c; } @@ -264,7 +264,7 @@ static CURLcode base64_encode(const char *table64, CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { - return base64_encode(base64, inputbuff, insize, outptr, outlen); + return base64_encode(base64encdec, inputbuff, insize, outptr, outlen); } /* diff --git a/Utilities/cmcurl/lib/bufq.c b/Utilities/cmcurl/lib/bufq.c index 30598cf..1555449 100644 --- a/Utilities/cmcurl/lib/bufq.c +++ b/Utilities/cmcurl/lib/bufq.c @@ -418,7 +418,8 @@ ssize_t Curl_bufq_write(struct bufq *q, break; } n = chunk_append(tail, buf, len); - DEBUGASSERT(n); + if(!n) + break; nwritten += n; buf += n; len -= n; @@ -528,6 +529,14 @@ ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, } break; } + if(!chunk_written) { + if(!nwritten) { + /* treat as blocked */ + *err = CURLE_AGAIN; + nwritten = -1; + } + break; + } Curl_bufq_skip(q, (size_t)chunk_written); nwritten += chunk_written; } @@ -551,7 +560,8 @@ ssize_t Curl_bufq_write_pass(struct bufq *q, /* real error, fail */ return -1; } - /* would block */ + /* would block, bufq is full, give up */ + break; } } @@ -562,16 +572,25 @@ ssize_t Curl_bufq_write_pass(struct bufq *q, /* real error, fail */ return -1; } - /* no room in bufq, bail out */ - goto out; + /* no room in bufq */ + break; } + /* edge case of writer returning 0 (and len is >0) + * break or we might enter an infinite loop here */ + if(n == 0) + break; + /* Maybe only part of `data` has been added, continue to loop */ buf += (size_t)n; len -= (size_t)n; nwritten += (size_t)n; } -out: + if(!nwritten && len) { + *err = CURLE_AGAIN; + return -1; + } + *err = CURLE_OK; return nwritten; } diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c index 756aebe..c29983c 100644 --- a/Utilities/cmcurl/lib/c-hyper.c +++ b/Utilities/cmcurl/lib/c-hyper.c @@ -71,9 +71,11 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx, DEBUGASSERT(conn); (void)ctx; + DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen)); result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread); if(result == CURLE_AGAIN) { /* would block, register interest */ + DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen)); if(data->hyp.read_waker) hyper_waker_free(data->hyp.read_waker); data->hyp.read_waker = hyper_context_waker(ctx); @@ -87,6 +89,7 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx, failf(data, "Curl_read failed"); return HYPER_IO_ERROR; } + DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread)); return (size_t)nread; } @@ -98,8 +101,12 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx, CURLcode result; ssize_t nwrote; + DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen)); result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote); + if(!result && !nwrote) + result = CURLE_AGAIN; if(result == CURLE_AGAIN) { + DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen)); /* would block, register interest */ if(data->hyp.write_waker) hyper_waker_free(data->hyp.write_waker); @@ -114,6 +121,7 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx, failf(data, "Curl_write failed"); return HYPER_IO_ERROR; } + DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote)); return (size_t)nwrote; } @@ -433,8 +441,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, break; } else if(t != HYPER_TASK_RESPONSE) { - *didwhat = KEEP_RECV; - break; + continue; } /* HYPER_TASK_RESPONSE */ diff --git a/Utilities/cmcurl/lib/cf-h1-proxy.c b/Utilities/cmcurl/lib/cf-h1-proxy.c index b42c4e6..c9b157c 100644 --- a/Utilities/cmcurl/lib/cf-h1-proxy.c +++ b/Utilities/cmcurl/lib/cf-h1-proxy.c @@ -54,16 +54,16 @@ typedef enum { - TUNNEL_INIT, /* init/default/no tunnel state */ - TUNNEL_CONNECT, /* CONNECT request is being send */ - TUNNEL_RECEIVE, /* CONNECT answer is being received */ - TUNNEL_RESPONSE, /* CONNECT response received completely */ - TUNNEL_ESTABLISHED, - TUNNEL_FAILED -} tunnel_state; + 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 tunnel_state { +struct h1_tunnel_state { int sockindex; const char *hostname; int remote_port; @@ -78,23 +78,23 @@ struct tunnel_state { KEEPON_IGNORE } keepon; curl_off_t cl; /* size of content to read and ignore */ - tunnel_state tunnel_state; + h1_tunnel_state tunnel_state; BIT(chunked_encoding); BIT(close_connection); }; -static bool tunnel_is_established(struct tunnel_state *ts) +static bool tunnel_is_established(struct h1_tunnel_state *ts) { - return ts && (ts->tunnel_state == TUNNEL_ESTABLISHED); + return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED); } -static bool tunnel_is_failed(struct tunnel_state *ts) +static bool tunnel_is_failed(struct h1_tunnel_state *ts) { - return ts && (ts->tunnel_state == TUNNEL_FAILED); + return ts && (ts->tunnel_state == H1_TUNNEL_FAILED); } -static CURLcode tunnel_reinit(struct tunnel_state *ts, +static CURLcode tunnel_reinit(struct h1_tunnel_state *ts, struct connectdata *conn, struct Curl_easy *data) { @@ -102,7 +102,7 @@ static CURLcode tunnel_reinit(struct tunnel_state *ts, DEBUGASSERT(ts); Curl_dyn_reset(&ts->rcvbuf); Curl_dyn_reset(&ts->req); - ts->tunnel_state = TUNNEL_INIT; + ts->tunnel_state = H1_TUNNEL_INIT; ts->keepon = KEEPON_CONNECT; ts->cl = 0; ts->close_connection = FALSE; @@ -124,12 +124,12 @@ static CURLcode tunnel_reinit(struct tunnel_state *ts, return CURLE_OK; } -static CURLcode tunnel_init(struct tunnel_state **pts, +static CURLcode tunnel_init(struct h1_tunnel_state **pts, struct Curl_easy *data, struct connectdata *conn, int sockindex) { - struct tunnel_state *ts; + struct h1_tunnel_state *ts; CURLcode result; if(conn->handler->flags & PROTOPT_NOTCPPROXY) { @@ -157,16 +157,16 @@ static CURLcode tunnel_init(struct tunnel_state **pts, return tunnel_reinit(ts, conn, data); } -static void tunnel_go_state(struct Curl_cfilter *cf, - struct tunnel_state *ts, - tunnel_state new_state, - struct Curl_easy *data) +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; /* leaving this one */ switch(ts->tunnel_state) { - case TUNNEL_CONNECT: + case H1_TUNNEL_CONNECT: data->req.ignorebody = FALSE; break; default: @@ -174,36 +174,36 @@ static void tunnel_go_state(struct Curl_cfilter *cf, } /* entering this one */ switch(new_state) { - case TUNNEL_INIT: + case H1_TUNNEL_INIT: DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'")); tunnel_reinit(ts, cf->conn, data); break; - case TUNNEL_CONNECT: + case H1_TUNNEL_CONNECT: DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'")); - ts->tunnel_state = TUNNEL_CONNECT; + ts->tunnel_state = H1_TUNNEL_CONNECT; ts->keepon = KEEPON_CONNECT; Curl_dyn_reset(&ts->rcvbuf); break; - case TUNNEL_RECEIVE: + case H1_TUNNEL_RECEIVE: DEBUGF(LOG_CF(data, cf, "new tunnel state 'receive'")); - ts->tunnel_state = TUNNEL_RECEIVE; + ts->tunnel_state = H1_TUNNEL_RECEIVE; break; - case TUNNEL_RESPONSE: + case H1_TUNNEL_RESPONSE: DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'")); - ts->tunnel_state = TUNNEL_RESPONSE; + ts->tunnel_state = H1_TUNNEL_RESPONSE; break; - case TUNNEL_ESTABLISHED: + case H1_TUNNEL_ESTABLISHED: DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'")); infof(data, "CONNECT phase completed"); data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; /* FALLTHROUGH */ - case TUNNEL_FAILED: - if(new_state == TUNNEL_FAILED) + case H1_TUNNEL_FAILED: + if(new_state == H1_TUNNEL_FAILED) DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'")); ts->tunnel_state = new_state; Curl_dyn_reset(&ts->rcvbuf); @@ -225,9 +225,9 @@ static void tunnel_go_state(struct Curl_cfilter *cf, static void tunnel_free(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct tunnel_state *ts = cf->ctx; + struct h1_tunnel_state *ts = cf->ctx; if(ts) { - tunnel_go_state(cf, ts, TUNNEL_FAILED, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); Curl_dyn_free(&ts->rcvbuf); Curl_dyn_free(&ts->req); free(ts); @@ -270,7 +270,7 @@ static CURLcode CONNECT_host(struct Curl_easy *data, #ifndef USE_HYPER static CURLcode start_CONNECT(struct Curl_cfilter *cf, struct Curl_easy *data, - struct tunnel_state *ts) + struct h1_tunnel_state *ts) { struct connectdata *conn = cf->conn; char *hostheader = NULL; @@ -351,7 +351,7 @@ out: static CURLcode send_CONNECT(struct Curl_easy *data, struct connectdata *conn, - struct tunnel_state *ts, + struct h1_tunnel_state *ts, bool *done) { struct SingleRequest *k = &data->req; @@ -399,7 +399,7 @@ out: static CURLcode on_resp_header(struct Curl_cfilter *cf, struct Curl_easy *data, - struct tunnel_state *ts, + struct h1_tunnel_state *ts, const char *header) { CURLcode result = CURLE_OK; @@ -475,7 +475,7 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf, static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, struct Curl_easy *data, - struct tunnel_state *ts, + struct h1_tunnel_state *ts, bool *done) { CURLcode result = CURLE_OK; @@ -671,7 +671,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, /* The Hyper version of CONNECT */ static CURLcode start_CONNECT(struct Curl_cfilter *cf, struct Curl_easy *data, - struct tunnel_state *ts) + struct h1_tunnel_state *ts) { struct connectdata *conn = cf->conn; struct hyptransfer *h = &data->hyp; @@ -882,7 +882,7 @@ error: static CURLcode send_CONNECT(struct Curl_easy *data, struct connectdata *conn, - struct tunnel_state *ts, + struct h1_tunnel_state *ts, bool *done) { struct hyptransfer *h = &data->hyp; @@ -919,7 +919,7 @@ error: static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, struct Curl_easy *data, - struct tunnel_state *ts, + struct h1_tunnel_state *ts, bool *done) { struct hyptransfer *h = &data->hyp; @@ -949,9 +949,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, #endif /* USE_HYPER */ -static CURLcode CONNECT(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct tunnel_state *ts) +static CURLcode H1_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) { struct connectdata *conn = cf->conn; CURLcode result; @@ -973,25 +973,25 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, } switch(ts->tunnel_state) { - case TUNNEL_INIT: + case H1_TUNNEL_INIT: /* Prepare the CONNECT request and make a first attempt to send. */ DEBUGF(LOG_CF(data, cf, "CONNECT start")); result = start_CONNECT(cf, data, ts); if(result) goto out; - tunnel_go_state(cf, ts, TUNNEL_CONNECT, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data); /* FALLTHROUGH */ - case TUNNEL_CONNECT: + case H1_TUNNEL_CONNECT: /* see that the request is completely sent */ DEBUGF(LOG_CF(data, cf, "CONNECT send")); result = send_CONNECT(data, cf->conn, ts, &done); if(result || !done) goto out; - tunnel_go_state(cf, ts, TUNNEL_RECEIVE, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data); /* FALLTHROUGH */ - case TUNNEL_RECEIVE: + case H1_TUNNEL_RECEIVE: /* read what is there */ DEBUGF(LOG_CF(data, cf, "CONNECT receive")); result = recv_CONNECT_resp(cf, data, ts, &done); @@ -1003,10 +1003,10 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, if(result || !done) goto out; /* got it */ - tunnel_go_state(cf, ts, TUNNEL_RESPONSE, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data); /* FALLTHROUGH */ - case TUNNEL_RESPONSE: + case H1_TUNNEL_RESPONSE: DEBUGF(LOG_CF(data, cf, "CONNECT response")); if(data->req.newurl) { /* not the "final" response, we need to do a follow up request. @@ -1028,7 +1028,7 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, } else { /* staying on this connection, reset state */ - tunnel_go_state(cf, ts, TUNNEL_INIT, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_INIT, data); } } break; @@ -1039,25 +1039,25 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, } while(data->req.newurl); - DEBUGASSERT(ts->tunnel_state == TUNNEL_RESPONSE); + 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 re-use */ streamclose(conn, "proxy CONNECT failure"); - tunnel_go_state(cf, ts, TUNNEL_FAILED, data); + 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! */ - tunnel_go_state(cf, ts, TUNNEL_ESTABLISHED, data); + 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) - tunnel_go_state(cf, ts, TUNNEL_FAILED, data); + h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); return result; } @@ -1066,7 +1066,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, bool blocking, bool *done) { CURLcode result; - struct tunnel_state *ts = cf->ctx; + struct h1_tunnel_state *ts = cf->ctx; if(cf->connected) { *done = TRUE; @@ -1074,7 +1074,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, } DEBUGF(LOG_CF(data, cf, "connect")); - result = cf->next->cft->connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); if(result || !*done) return result; @@ -1089,7 +1089,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, /* TODO: can we do blocking? */ /* We want "seamless" operations through HTTP proxy tunnel */ - result = CONNECT(cf, data, ts); + result = H1_CONNECT(cf, data, ts); if(result) goto out; Curl_safefree(data->state.aptr.proxyuserpwd); @@ -1107,7 +1107,7 @@ static int cf_h1_proxy_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *socks) { - struct tunnel_state *ts = cf->ctx; + struct h1_tunnel_state *ts = cf->ctx; int fds; fds = cf->next->cft->get_select_socks(cf->next, data, socks); @@ -1143,10 +1143,10 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "close")); cf->connected = FALSE; if(cf->ctx) { - tunnel_go_state(cf, cf->ctx, TUNNEL_INIT, data); + h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data); } if(cf->next) - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); } diff --git a/Utilities/cmcurl/lib/cf-h2-proxy.c b/Utilities/cmcurl/lib/cf-h2-proxy.c index 8e76ff8..f6acfc5 100644 --- a/Utilities/cmcurl/lib/cf-h2-proxy.c +++ b/Utilities/cmcurl/lib/cf-h2-proxy.c @@ -44,26 +44,25 @@ #include "curl_memory.h" #include "memdebug.h" -#define H2_NW_CHUNK_SIZE (128*1024) -#define H2_NW_RECV_CHUNKS 1 -#define H2_NW_SEND_CHUNKS 1 +#define H2_CHUNK_SIZE (16*1024) -#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */ +#define PROXY_HTTP2_HUGE_WINDOW_SIZE (100 * 1024 * 1024) +#define H2_TUNNEL_WINDOW_SIZE (10 * 1024 * 1024) + +#define PROXY_H2_NW_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE) +#define PROXY_H2_NW_SEND_CHUNKS 1 + +#define H2_TUNNEL_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE) +#define H2_TUNNEL_SEND_CHUNKS ((128 * 1024) / H2_CHUNK_SIZE) -#define H2_TUNNEL_WINDOW_SIZE (1024 * 1024) -#define H2_TUNNEL_CHUNK_SIZE (32 * 1024) -#define H2_TUNNEL_RECV_CHUNKS \ - (H2_TUNNEL_WINDOW_SIZE / H2_TUNNEL_CHUNK_SIZE) -#define H2_TUNNEL_SEND_CHUNKS \ - (H2_TUNNEL_WINDOW_SIZE / H2_TUNNEL_CHUNK_SIZE) typedef enum { - TUNNEL_INIT, /* init/default/no tunnel state */ - TUNNEL_CONNECT, /* CONNECT request is being send */ - TUNNEL_RESPONSE, /* CONNECT response received completely */ - TUNNEL_ESTABLISHED, - TUNNEL_FAILED -} tunnel_state; + H2_TUNNEL_INIT, /* init/default/no tunnel state */ + H2_TUNNEL_CONNECT, /* CONNECT request is being send */ + H2_TUNNEL_RESPONSE, /* CONNECT response received completely */ + H2_TUNNEL_ESTABLISHED, + H2_TUNNEL_FAILED +} h2_tunnel_state; struct tunnel_stream { struct http_resp *resp; @@ -72,10 +71,11 @@ struct tunnel_stream { char *authority; int32_t stream_id; uint32_t error; - tunnel_state state; - bool has_final_response; - bool closed; - bool reset; + size_t upload_blocked_len; + h2_tunnel_state state; + BIT(has_final_response); + BIT(closed); + BIT(reset); }; static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, @@ -85,11 +85,11 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, int port; bool ipv6_ip = cf->conn->bits.ipv6_ip; - ts->state = TUNNEL_INIT; + ts->state = H2_TUNNEL_INIT; ts->stream_id = -1; - Curl_bufq_init2(&ts->recvbuf, H2_TUNNEL_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS, + Curl_bufq_init2(&ts->recvbuf, H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); - Curl_bufq_init(&ts->sendbuf, H2_TUNNEL_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS); + Curl_bufq_init(&ts->sendbuf, H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS); if(cf->conn->bits.conn_to_host) hostname = cf->conn->conn_to_host.name; @@ -123,13 +123,13 @@ static void tunnel_stream_clear(struct tunnel_stream *ts) Curl_bufq_free(&ts->sendbuf); Curl_safefree(ts->authority); memset(ts, 0, sizeof(*ts)); - ts->state = TUNNEL_INIT; + ts->state = H2_TUNNEL_INIT; } -static void tunnel_go_state(struct Curl_cfilter *cf, - struct tunnel_stream *ts, - tunnel_state new_state, - struct Curl_easy *data) +static void h2_tunnel_go_state(struct Curl_cfilter *cf, + struct tunnel_stream *ts, + h2_tunnel_state new_state, + struct Curl_easy *data) { (void)cf; @@ -137,7 +137,7 @@ static void tunnel_go_state(struct Curl_cfilter *cf, return; /* leaving this one */ switch(ts->state) { - case TUNNEL_CONNECT: + case H2_TUNNEL_CONNECT: data->req.ignorebody = FALSE; break; default: @@ -145,29 +145,29 @@ static void tunnel_go_state(struct Curl_cfilter *cf, } /* entering this one */ switch(new_state) { - case TUNNEL_INIT: + case H2_TUNNEL_INIT: DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'")); tunnel_stream_clear(ts); break; - case TUNNEL_CONNECT: + case H2_TUNNEL_CONNECT: DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'")); - ts->state = TUNNEL_CONNECT; + ts->state = H2_TUNNEL_CONNECT; break; - case TUNNEL_RESPONSE: + case H2_TUNNEL_RESPONSE: DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'")); - ts->state = TUNNEL_RESPONSE; + ts->state = H2_TUNNEL_RESPONSE; break; - case TUNNEL_ESTABLISHED: + case H2_TUNNEL_ESTABLISHED: DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'")); infof(data, "CONNECT phase completed"); data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; /* FALLTHROUGH */ - case TUNNEL_FAILED: - if(new_state == TUNNEL_FAILED) + case H2_TUNNEL_FAILED: + if(new_state == H2_TUNNEL_FAILED) DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'")); ts->state = new_state; /* If a proxy-authorization header was used for the proxy, then we should @@ -191,9 +191,11 @@ struct cf_h2_proxy_ctx { int32_t last_stream_id; BIT(conn_closed); BIT(goaway); + BIT(nw_out_blocked); }; /* How to access `call_data` from a cf_h2 filter */ +#undef CF_CTX_CALL_DATA #define CF_CTX_CALL_DATA(cf) \ ((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data @@ -219,35 +221,54 @@ static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx) } } -static ssize_t nw_in_reader(void *reader_ctx, - unsigned char *buf, size_t buflen, - CURLcode *err) +static void drain_tunnel(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *tunnel) +{ + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len) + bits |= CURL_CSELECT_OUT; + if(data->state.dselect_bits != bits) { + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] DRAIN dselect_bits=%x", + tunnel->stream_id, bits)); + data->state.dselect_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static ssize_t proxy_nw_in_reader(void *reader_ctx, + unsigned char *buf, size_t buflen, + CURLcode *err) { struct Curl_cfilter *cf = reader_ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); - DEBUGF(LOG_CF(data, cf, "nw_in recv(len=%zu) -> %zd, %d", + DEBUGF(LOG_CF(data, cf, "nw_in_reader(len=%zu) -> %zd, %d", buflen, nread, *err)); return nread; } -static ssize_t nw_out_writer(void *writer_ctx, - const unsigned char *buf, size_t buflen, - CURLcode *err) +static ssize_t proxy_h2_nw_out_writer(void *writer_ctx, + const unsigned char *buf, size_t buflen, + CURLcode *err) { struct Curl_cfilter *cf = writer_ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, err); - DEBUGF(LOG_CF(data, cf, "nw_out send(len=%zu) -> %zd", buflen, nwritten)); + DEBUGF(LOG_CF(data, cf, "nw_out_writer(len=%zu) -> %zd, %d", + buflen, nwritten, *err)); return nwritten; } -static int h2_client_new(struct Curl_cfilter *cf, - nghttp2_session_callbacks *cbs) +static int proxy_h2_client_new(struct Curl_cfilter *cf, + nghttp2_session_callbacks *cbs) { struct cf_h2_proxy_ctx *ctx = cf->ctx; nghttp2_option *o; @@ -271,15 +292,18 @@ static int h2_client_new(struct Curl_cfilter *cf, static ssize_t on_session_send(nghttp2_session *h2, const uint8_t *buf, size_t blen, int flags, void *userp); -static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, - void *userp); -static int on_stream_close(nghttp2_session *session, int32_t stream_id, - uint32_t error_code, void *userp); -static int on_header(nghttp2_session *session, const nghttp2_frame *frame, - const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen, - uint8_t flags, - void *userp); +static int proxy_h2_on_frame_recv(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp); +static int proxy_h2_on_stream_close(nghttp2_session *session, + int32_t stream_id, + uint32_t error_code, void *userp); +static int proxy_h2_on_header(nghttp2_session *session, + const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp); static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *mem, size_t len, void *userp); @@ -298,8 +322,8 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf, DEBUGASSERT(!ctx->h2); memset(&ctx->tunnel, 0, sizeof(ctx->tunnel)); - Curl_bufq_init(&ctx->inbufq, H2_NW_CHUNK_SIZE, H2_NW_RECV_CHUNKS); - Curl_bufq_init(&ctx->outbufq, H2_NW_CHUNK_SIZE, H2_NW_SEND_CHUNKS); + Curl_bufq_init(&ctx->inbufq, H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS); + Curl_bufq_init(&ctx->outbufq, H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS); if(tunnel_stream_init(cf, &ctx->tunnel)) goto out; @@ -311,14 +335,16 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf, } nghttp2_session_callbacks_set_send_callback(cbs, on_session_send); - nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv); + nghttp2_session_callbacks_set_on_frame_recv_callback( + cbs, proxy_h2_on_frame_recv); nghttp2_session_callbacks_set_on_data_chunk_recv_callback( cbs, tunnel_recv_callback); - nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close); - nghttp2_session_callbacks_set_on_header_callback(cbs, on_header); + nghttp2_session_callbacks_set_on_stream_close_callback( + cbs, proxy_h2_on_stream_close); + nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header); /* The nghttp2 session is not yet setup, do it */ - rc = h2_client_new(cf, cbs); + rc = proxy_h2_client_new(cf, cbs); if(rc) { failf(data, "Couldn't initialize nghttp2"); goto out; @@ -343,7 +369,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf, } rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, - HTTP2_HUGE_WINDOW_SIZE); + PROXY_HTTP2_HUGE_WINDOW_SIZE); if(rc) { failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", nghttp2_strerror(rc), rc); @@ -362,27 +388,35 @@ out: return result; } -static CURLcode nw_out_flush(struct Curl_cfilter *cf, - struct Curl_easy *data) +static int should_close_session(struct cf_h2_proxy_ctx *ctx) +{ + return !nghttp2_session_want_read(ctx->h2) && + !nghttp2_session_want_write(ctx->h2); +} + +static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - size_t buflen = Curl_bufq_len(&ctx->outbufq); ssize_t nwritten; CURLcode result; (void)data; - if(!buflen) + if(Curl_bufq_is_empty(&ctx->outbufq)) return CURLE_OK; - DEBUGF(LOG_CF(data, cf, "h2 conn flush %zu bytes", buflen)); - nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); + nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf, + &result); if(nwritten < 0) { + if(result == CURLE_AGAIN) { + DEBUGF(LOG_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", + Curl_bufq_len(&ctx->outbufq))); + ctx->nw_out_blocked = 1; + } return result; } - if((size_t)nwritten < buflen) { - return CURLE_AGAIN; - } - return CURLE_OK; + DEBUGF(LOG_CF(data, cf, "nw send buffer flushed")); + return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN; } /* @@ -390,9 +424,9 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf, * This function returns 0 if it succeeds, or -1 and error code will * be assigned to *err. */ -static int h2_process_pending_input(struct Curl_cfilter *cf, - struct Curl_easy *data, - CURLcode *err) +static int proxy_h2_process_pending_input(struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLcode *err) { struct cf_h2_proxy_ctx *ctx = cf->ctx; const unsigned char *buf; @@ -422,19 +456,11 @@ static int h2_process_pending_input(struct Curl_cfilter *cf, } } - if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { - /* No more requests are allowed in the current session, so - the connection may not be reused. This is set when a - GOAWAY frame has been received or when the limit of stream - identifiers has been reached. */ - connclose(cf->conn, "http/2: No new requests allowed"); - } - return 0; } -static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_h2_proxy_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -442,9 +468,9 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, /* Process network input buffer fist */ if(!Curl_bufq_is_empty(&ctx->inbufq)) { - DEBUGF(LOG_CF(data, cf, "Process %zd bytes in connection buffer", + DEBUGF(LOG_CF(data, cf, "Process %zu bytes in connection buffer", Curl_bufq_len(&ctx->inbufq))); - if(h2_process_pending_input(cf, data, &result) < 0) + if(proxy_h2_process_pending_input(cf, data, &result) < 0) return result; } @@ -455,8 +481,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */ !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) { - nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); - DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d", + nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); + DEBUGF(LOG_CF(data, cf, "read %zu bytes nw data -> %zd, %d", Curl_bufq_len(&ctx->inbufq), nread, result)); if(nread < 0) { if(result != CURLE_AGAIN) { @@ -470,7 +496,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, break; } - if(h2_process_pending_input(cf, data, &result)) + if(proxy_h2_process_pending_input(cf, data, &result)) return result; } @@ -481,25 +507,22 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, return CURLE_OK; } -/* - * Check if there's been an update in the priority / - * dependency settings and if so it submits a PRIORITY frame with the updated - * info. - * Flush any out data pending in the network buffer. - */ -static CURLcode h2_progress_egress(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode proxy_h2_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_h2_proxy_ctx *ctx = cf->ctx; int rv = 0; - rv = nghttp2_session_send(ctx->h2); + ctx->nw_out_blocked = 0; + while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) + rv = nghttp2_session_send(ctx->h2); + if(nghttp2_is_fatal(rv)) { DEBUGF(LOG_CF(data, cf, "nghttp2_session_send error (%s)%d", nghttp2_strerror(rv), rv)); return CURLE_SEND_ERROR; } - return nw_out_flush(cf, data); + return proxy_h2_nw_out_flush(cf, data); } static ssize_t on_session_send(nghttp2_session *h2, @@ -517,7 +540,7 @@ static ssize_t on_session_send(nghttp2_session *h2, DEBUGASSERT(data); nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, - nw_out_writer, cf, &result); + proxy_h2_nw_out_writer, cf, &result); if(nwritten < 0) { if(result == CURLE_AGAIN) { return NGHTTP2_ERR_WOULDBLOCK; @@ -532,8 +555,9 @@ static ssize_t on_session_send(nghttp2_session *h2, return nwritten; } -static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, - void *userp) +static int proxy_h2_on_frame_recv(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) { struct Curl_cfilter *cf = userp; struct cf_h2_proxy_ctx *ctx = cf->ctx; @@ -616,11 +640,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, return 0; } -static int on_header(nghttp2_session *session, const nghttp2_frame *frame, - const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen, - uint8_t flags, - void *userp) +static int proxy_h2_on_header(nghttp2_session *session, + const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp) { struct Curl_cfilter *cf = userp; struct cf_h2_proxy_ctx *ctx = cf->ctx; @@ -752,8 +777,9 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, return 0; } -static int on_stream_close(nghttp2_session *session, int32_t stream_id, - uint32_t error_code, void *userp) +static int proxy_h2_on_stream_close(nghttp2_session *session, + int32_t stream_id, + uint32_t error_code, void *userp) { struct Curl_cfilter *cf = userp; struct cf_h2_proxy_ctx *ctx = cf->ctx; @@ -765,7 +791,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, if(stream_id != ctx->tunnel.stream_id) return 0; - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] on_stream_close, %s (err %d)", + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] proxy_h2_on_stream_close, %s (err %d)", stream_id, nghttp2_http2_strerror(error_code), error_code)); ctx->tunnel.closed = TRUE; ctx->tunnel.error = error_code; @@ -773,15 +799,15 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, return 0; } -static CURLcode h2_submit(int32_t *pstream_id, - struct Curl_cfilter *cf, - struct Curl_easy *data, - nghttp2_session *h2, - struct httpreq *req, - const nghttp2_priority_spec *pri_spec, - void *stream_user_data, - nghttp2_data_source_read_callback read_callback, - void *read_ctx) +static CURLcode proxy_h2_submit(int32_t *pstream_id, + struct Curl_cfilter *cf, + struct Curl_easy *data, + nghttp2_session *h2, + struct httpreq *req, + const nghttp2_priority_spec *pri_spec, + void *stream_user_data, + nghttp2_data_source_read_callback read_callback, + void *read_ctx) { struct dynhds h2_headers; nghttp2_nv *nva = NULL; @@ -881,8 +907,8 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf, if(result) goto out; - result = h2_submit(&ts->stream_id, cf, data, ctx->h2, req, - NULL, ts, tunnel_send_callback, cf); + result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req, + NULL, ts, tunnel_send_callback, cf); if(result) { DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u", nghttp2_strerror(ts->stream_id), ts->stream_id)); @@ -907,7 +933,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf, DEBUGASSERT(ts->resp); if(ts->resp->status/100 == 2) { infof(data, "CONNECT tunnel established, response %d", ts->resp->status); - tunnel_go_state(cf, ts, TUNNEL_ESTABLISHED, data); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data); return CURLE_OK; } @@ -928,7 +954,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf, if(data->req.newurl) { /* Inidicator that we should try again */ Curl_safefree(data->req.newurl); - tunnel_go_state(cf, ts, TUNNEL_INIT, data); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data); return CURLE_OK; } } @@ -937,9 +963,9 @@ static CURLcode inspect_response(struct Curl_cfilter *cf, return CURLE_RECV_ERROR; } -static CURLcode CONNECT(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct tunnel_stream *ts) +static CURLcode H2_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct tunnel_stream *ts) { struct cf_h2_proxy_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -948,27 +974,27 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, DEBUGASSERT(ts->authority); do { switch(ts->state) { - case TUNNEL_INIT: + case H2_TUNNEL_INIT: /* Prepare the CONNECT request and make a first attempt to send. */ DEBUGF(LOG_CF(data, cf, "CONNECT start for %s", ts->authority)); result = submit_CONNECT(cf, data, ts); if(result) goto out; - tunnel_go_state(cf, ts, TUNNEL_CONNECT, data); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data); /* FALLTHROUGH */ - case TUNNEL_CONNECT: + case H2_TUNNEL_CONNECT: /* see that the request is completely sent */ - result = h2_progress_ingress(cf, data); + result = proxy_h2_progress_ingress(cf, data); if(!result) - result = h2_progress_egress(cf, data); - if(result) { - tunnel_go_state(cf, ts, TUNNEL_FAILED, data); + result = proxy_h2_progress_egress(cf, data); + if(result && result != CURLE_AGAIN) { + h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data); break; } if(ts->has_final_response) { - tunnel_go_state(cf, ts, TUNNEL_RESPONSE, data); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data); } else { result = CURLE_OK; @@ -976,28 +1002,28 @@ static CURLcode CONNECT(struct Curl_cfilter *cf, } /* FALLTHROUGH */ - case TUNNEL_RESPONSE: + case H2_TUNNEL_RESPONSE: DEBUGASSERT(ts->has_final_response); result = inspect_response(cf, data, ts); if(result) goto out; break; - case TUNNEL_ESTABLISHED: + case H2_TUNNEL_ESTABLISHED: return CURLE_OK; - case TUNNEL_FAILED: + case H2_TUNNEL_FAILED: return CURLE_RECV_ERROR; default: break; } - } while(ts->state == TUNNEL_INIT); + } while(ts->state == H2_TUNNEL_INIT); out: if(result || ctx->tunnel.closed) - tunnel_go_state(cf, ts, TUNNEL_FAILED, data); + h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data); return result; } @@ -1043,10 +1069,10 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf, /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ - result = CONNECT(cf, data, ts); + result = H2_CONNECT(cf, data, ts); out: - *done = (result == CURLE_OK) && (ts->state == TUNNEL_ESTABLISHED); + *done = (result == CURLE_OK) && (ts->state == H2_TUNNEL_ESTABLISHED); cf->connected = *done; CF_DATA_RESTORE(cf, save); return result; @@ -1082,7 +1108,7 @@ static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf, { struct cf_h2_proxy_ctx *ctx = cf->ctx; if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) || - (ctx && ctx->tunnel.state == TUNNEL_ESTABLISHED && + (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED && !Curl_bufq_is_empty(&ctx->tunnel.recvbuf))) return TRUE; return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE; @@ -1188,14 +1214,14 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf, struct cf_call_data save; CURLcode result; - if(ctx->tunnel.state != TUNNEL_ESTABLISHED) { + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { *err = CURLE_RECV_ERROR; return -1; } CF_DATA_SAVE(save, cf, data); if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) { - *err = h2_progress_ingress(cf, data); + *err = proxy_h2_progress_ingress(cf, data); if(*err) goto out; } @@ -1208,13 +1234,19 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf, nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread); } - result = h2_progress_egress(cf, data); - if(result) { + result = proxy_h2_progress_egress(cf, data); + if(result && result != CURLE_AGAIN) { *err = result; nread = -1; } out: + if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) && + (nread >= 0 || *err == CURLE_AGAIN)) { + /* data pending and no fatal error to report. Need to trigger + * draining to avoid stalling when no socket events happen. */ + drain_tunnel(cf, data, &ctx->tunnel); + } DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv(len=%zu) -> %zd %d", ctx->tunnel.stream_id, len, nread, *err)); CF_DATA_RESTORE(cf, save); @@ -1223,93 +1255,188 @@ out: static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *mem, size_t len, CURLcode *err) + const void *buf, size_t len, CURLcode *err) { struct cf_h2_proxy_ctx *ctx = cf->ctx; struct cf_call_data save; - ssize_t nwritten = -1; - const unsigned char *buf = mem; - size_t start_len = len; int rv; + ssize_t nwritten; + CURLcode result; + int blocked = 0; - if(ctx->tunnel.state != TUNNEL_ESTABLISHED) { + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { *err = CURLE_SEND_ERROR; return -1; } CF_DATA_SAVE(save, cf, data); - while(len) { + if(ctx->tunnel.closed) { + nwritten = -1; + *err = CURLE_SEND_ERROR; + goto out; + } + else if(ctx->tunnel.upload_blocked_len) { + /* the data in `buf` has alread been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len); + if(len < ctx->tunnel.upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happend. We are not prepared to handle that. */ + failf(data, "HTTP/2 proxy, send again with decreased length"); + *err = CURLE_HTTP2; + nwritten = -1; + goto out; + } + nwritten = (ssize_t)ctx->tunnel.upload_blocked_len; + ctx->tunnel.upload_blocked_len = 0; + } + else { nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err); - if(nwritten <= 0) { - if(*err && *err != CURLE_AGAIN) { - DEBUGF(LOG_CF(data, cf, "error adding data to tunnel sendbuf: %d", - *err)); - nwritten = -1; + if(nwritten < 0) { + if(*err != CURLE_AGAIN) goto out; - } - /* blocked */ nwritten = 0; } - else { - DEBUGASSERT((size_t)nwritten <= len); - buf += (size_t)nwritten; - len -= (size_t)nwritten; - } + } - /* resume the tunnel stream and let the h2 session send, which - * triggers reading from tunnel.sendbuf */ + if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { + /* req body data is buffered, resume the potentially suspended stream */ rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; nwritten = -1; goto out; } - *err = h2_progress_egress(cf, data); - if(*err) { - nwritten = -1; - goto out; - } - - if(!nwritten && Curl_bufq_is_full(&ctx->tunnel.sendbuf)) { - size_t rwin; - /* we could not add to the buffer and after session processing, - * it is still full. */ - rwin = nghttp2_session_get_stream_remote_window_size( - ctx->h2, ctx->tunnel.stream_id); - DEBUGF(LOG_CF(data, cf, "cf_send: tunnel win %u/%zu", - nghttp2_session_get_remote_window_size(ctx->h2), rwin)); - if(rwin == 0) { - /* We cannot upload more as the stream's remote window size - * is 0. We need to receive WIN_UPDATEs before we can continue. - */ - data->req.keepon |= KEEP_SEND_HOLD; - DEBUGF(LOG_CF(data, cf, "pausing send as remote flow " - "window is exhausted")); - } - break; - } } - nwritten = start_len - len; - if(nwritten > 0) { - *err = CURLE_OK; + /* Call the nghttp2 send loop and flush to write ALL buffered data, + * headers and/or request body completely out to the network */ + result = proxy_h2_progress_egress(cf, data); + if(result == CURLE_AGAIN) { + blocked = 1; } - else if(ctx->tunnel.closed) { + else if(result) { + *err = result; nwritten = -1; - *err = CURLE_SEND_ERROR; + goto out; } - else { - nwritten = -1; + else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { + /* although we wrote everything that nghttp2 wants to send now, + * there is data left in our stream send buffer unwritten. This may + * be due to the stream's HTTP/2 flow window being exhausted. */ + blocked = 1; + } + + if(blocked) { + /* Unable to send all data, due to connection blocked or H2 window + * exhaustion. Data is left in our stream buffer, or nghttp2's internal + * frame buffer or our network out buffer. */ + size_t rwin = nghttp2_session_get_stream_remote_window_size( + ctx->h2, ctx->tunnel.stream_id); + if(rwin == 0) { + /* H2 flow window exhaustion. + * FIXME: there is no way to HOLD all transfers that use this + * proxy connection AND to UNHOLD all of them again when the + * window increases. + * We *could* iterate over all data on this conn maybe? */ + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] remote flow " + "window is exhausted", ctx->tunnel.stream_id)); + } + + /* Whatever the cause, we need to return CURL_EAGAIN for this call. + * We have unwritten state that needs us being invoked again and EAGAIN + * is the only way to ensure that. */ + ctx->tunnel.upload_blocked_len = nwritten; + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) BLOCK: win %u/%zu " + "blocked_len=%zu", + ctx->tunnel.stream_id, len, + nghttp2_session_get_remote_window_size(ctx->h2), rwin, + nwritten)); *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(should_close_session(ctx)) { + /* nghttp2 thinks this session is done. If the stream has not been + * closed, this is an error state for out transfer */ + if(ctx->tunnel.closed) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + } + else { + DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); + *err = CURLE_HTTP2; + nwritten = -1; + } } out: - DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) -> %zd, %d ", - start_len, nwritten, *err)); + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, " + "h2 windows %d-%d (stream-conn), " + "buffers %zu-%zu (stream-conn)", + ctx->tunnel.stream_id, len, nwritten, *err, + nghttp2_session_get_stream_remote_window_size( + ctx->h2, ctx->tunnel.stream_id), + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&ctx->tunnel.sendbuf), + Curl_bufq_len(&ctx->outbufq))); CF_DATA_RESTORE(cf, save); return nwritten; } +static bool proxy_h2_connisalive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + bool alive = TRUE; + + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + CURLcode result; + ssize_t nread = -1; + + *input_pending = FALSE; + nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); + if(nread != -1) { + if(proxy_h2_process_pending_input(cf, data, &result) < 0) + /* immediate error, considered dead */ + alive = FALSE; + else { + alive = !should_close_session(ctx); + } + } + else if(result != CURLE_AGAIN) { + /* the read failed so let's say this is dead anyway */ + alive = FALSE; + } + } + + return alive; +} + +static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_h2_proxy_ctx *ctx = cf->ctx; + CURLcode result; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending)); + DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d", + result, *input_pending)); + CF_DATA_RESTORE(cf, save); + return result; +} + struct Curl_cftype Curl_cft_h2_proxy = { "H2-PROXY", CF_TYPE_IP_CONNECT, @@ -1323,7 +1450,7 @@ struct Curl_cftype Curl_cft_h2_proxy = { cf_h2_proxy_send, cf_h2_proxy_recv, Curl_cf_def_cntrl, - Curl_cf_def_conn_is_alive, + cf_h2_proxy_is_alive, Curl_cf_def_conn_keep_alive, Curl_cf_def_query, }; diff --git a/Utilities/cmcurl/lib/cf-haproxy.c b/Utilities/cmcurl/lib/cf-haproxy.c index 86d7fd1..ec0100c 100644 --- a/Utilities/cmcurl/lib/cf-haproxy.c +++ b/Utilities/cmcurl/lib/cf-haproxy.c @@ -71,6 +71,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, struct cf_haproxy_ctx *ctx = cf->ctx; CURLcode result; const char *tcp_version; + const char *client_ip; DEBUGASSERT(ctx); DEBUGASSERT(ctx->state == HAPROXY_INIT); @@ -82,11 +83,15 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, #endif /* USE_UNIX_SOCKETS */ /* Emit the correct prefix for IPv6 */ tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4"; + if(data->set.str[STRING_HAPROXY_CLIENT_IP]) + client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP]; + else + client_ip = data->info.conn_primary_ip; result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n", tcp_version, data->info.conn_local_ip, - data->info.conn_primary_ip, + client_ip, data->info.conn_local_port, data->info.conn_primary_port); @@ -110,7 +115,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, return CURLE_OK; } - result = cf->next->cft->connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); if(result || !*done) return result; @@ -163,7 +168,7 @@ static void cf_haproxy_close(struct Curl_cfilter *cf, cf->connected = FALSE; cf_haproxy_ctx_reset(cf->ctx); if(cf->next) - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); } static int cf_haproxy_get_select_socks(struct Curl_cfilter *cf, diff --git a/Utilities/cmcurl/lib/cf-https-connect.c b/Utilities/cmcurl/lib/cf-https-connect.c index d03cd1e..4e4d4b1 100644 --- a/Utilities/cmcurl/lib/cf-https-connect.c +++ b/Utilities/cmcurl/lib/cf-https-connect.c @@ -376,9 +376,9 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf, || cf_hc_baller_data_pending(&ctx->h21_baller, data); } -static struct curltime get_max_baller_time(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query) +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 Curl_cfilter *cfb; @@ -408,12 +408,12 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf, switch(query) { case CF_QUERY_TIMER_CONNECT: { struct curltime *when = pres2; - *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); + *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 = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); + *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); return CURLE_OK; } default: @@ -432,7 +432,7 @@ static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data) cf->connected = FALSE; if(cf->next) { - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); Curl_conn_cf_discard_chain(&cf->next, data); } } diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c index 960979b..5729fe0 100644 --- a/Utilities/cmcurl/lib/cf-socket.c +++ b/Utilities/cmcurl/lib/cf-socket.c @@ -871,7 +871,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data) /* this is our local socket, we did never publish it */ DEBUGF(LOG_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T ", not active)", ctx->sock)); - sclose(ctx->sock); + socket_close(data, cf->conn, !ctx->accepted, ctx->sock); ctx->sock = CURL_SOCKET_BAD; } Curl_bufq_reset(&ctx->recvbuf); @@ -901,22 +901,26 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf, struct cf_socket_ctx *ctx = cf->ctx; #ifdef HAVE_GETSOCKNAME - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssloc; - curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage); + if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) { + /* TFTP does not connect, so it cannot get the IP like this */ - memset(&ssloc, 0, sizeof(ssloc)); - if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) { - int error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return CURLE_FAILED_INIT; - } - if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, - ctx->l_ip, &ctx->l_port)) { - failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return CURLE_FAILED_INIT; + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssloc; + curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage); + + memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) { + int error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return CURLE_FAILED_INIT; + } + if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, + ctx->l_ip, &ctx->l_port)) { + failf(data, "ssloc inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return CURLE_FAILED_INIT; + } } #else (void)data; @@ -1356,26 +1360,31 @@ out: static void conn_set_primary_ip(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_socket_ctx *ctx = cf->ctx; #ifdef HAVE_GETPEERNAME - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssrem; - curl_socklen_t plen; - int port; + struct cf_socket_ctx *ctx = cf->ctx; + if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) { + /* TFTP does not connect the endpoint: getpeername() failed with errno + 107: Transport endpoint is not connected */ - plen = sizeof(ssrem); - memset(&ssrem, 0, plen); - if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } - if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, - cf->conn->primary_ip, &port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + curl_socklen_t plen; + int port; + + plen = sizeof(ssrem); + memset(&ssrem, 0, plen); + if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + cf->conn->primary_ip, &port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } } #else cf->conn->primary_ip[0] = 0; diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c index 291c823..216d0b4 100644 --- a/Utilities/cmcurl/lib/cfilters.c +++ b/Utilities/cmcurl/lib/cfilters.c @@ -50,7 +50,7 @@ void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data) { cf->connected = FALSE; if(cf->next) - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); } #endif @@ -161,7 +161,7 @@ void Curl_conn_close(struct Curl_easy *data, int index) /* it is valid to call that without filters being present */ cf = data->conn->cfilter[index]; if(cf) { - cf->cft->close(cf, data); + cf->cft->do_close(cf, data); } } @@ -179,7 +179,7 @@ ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf, if(cf) { return cf->cft->do_recv(cf, data, buf, len, code); } - failf(data, CMSGI(data->conn, num, "recv: no filter connected")); + failf(data, "recv: no filter connected"); *code = CURLE_FAILED_INIT; return -1; } @@ -198,7 +198,7 @@ ssize_t Curl_conn_send(struct Curl_easy *data, int num, if(cf) { return cf->cft->do_send(cf, data, mem, len, code); } - failf(data, CMSGI(data->conn, num, "send: no filter connected")); + failf(data, "send: no filter connected"); DEBUGASSERT(0); *code = CURLE_FAILED_INIT; return -1; @@ -293,14 +293,14 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, bool blocking, bool *done) { if(cf) - return cf->cft->connect(cf, data, blocking, done); + return cf->cft->do_connect(cf, data, blocking, done); return CURLE_FAILED_INIT; } void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) { if(cf) - cf->cft->close(cf, data); + cf->cft->do_close(cf, data); } int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf, @@ -348,7 +348,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, *done = cf->connected; if(!*done) { - result = cf->cft->connect(cf, data, blocking, done); + result = cf->cft->do_connect(cf, data, blocking, done); if(!result && *done) { Curl_conn_ev_update_info(data, data->conn); conn_report_connect_stats(data, data->conn); diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h index 70dcbe7..2c65264 100644 --- a/Utilities/cmcurl/lib/cfilters.h +++ b/Utilities/cmcurl/lib/cfilters.h @@ -168,8 +168,8 @@ struct Curl_cftype { 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 *connect; /* establish connection */ - Curl_cft_close *close; /* close conn */ + Curl_cft_connect *do_connect; /* establish connection */ + Curl_cft_close *do_close; /* close conn */ Curl_cft_get_host *get_host; /* host filter talks to */ Curl_cft_get_select_socks *get_select_socks;/* sockets to select on */ Curl_cft_data_pending *has_data_pending;/* conn has data pending */ diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h index 959767d..c60f844 100644 --- a/Utilities/cmcurl/lib/conncache.h +++ b/Utilities/cmcurl/lib/conncache.h @@ -39,7 +39,8 @@ struct connectdata; struct conncache { struct Curl_hash hash; size_t num_conn; - long next_connection_id; + curl_off_t next_connection_id; + curl_off_t next_easy_id; struct curltime last_cleanup; /* handle used for closing cached connections */ struct Curl_easy *closure_handle; diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index ed55121..dc93533 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -253,7 +253,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, } struct connfind { - long id_tofind; + curl_off_t id_tofind; struct connectdata *found; }; @@ -937,7 +937,7 @@ static void cf_he_close(struct Curl_cfilter *cf, ctx->state = SCFST_INIT; if(cf->next) { - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); Curl_conn_cf_discard_chain(&cf->next, data); } } @@ -1291,7 +1291,7 @@ static void cf_setup_close(struct Curl_cfilter *cf, ctx->state = CF_SETUP_INIT; if(cf->next) { - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); Curl_conn_cf_discard_chain(&cf->next, data); } } diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 0303efb..4345a84 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -123,8 +123,9 @@ static void freecookie(struct Cookie *co) free(co); } -static bool tailmatch(const char *cookie_domain, size_t cookie_domain_len, - const char *hostname) +static bool cookie_tailmatch(const char *cookie_domain, + size_t cookie_domain_len, + const char *hostname) { size_t hostname_len = strlen(hostname); @@ -696,7 +697,7 @@ Curl_cookie_add(struct Curl_easy *data, if(!domain || (is_ip && !strncmp(valuep, domain, vlen) && (vlen == strlen(domain))) - || (!is_ip && tailmatch(valuep, vlen, domain))) { + || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) { strstore(&co->domain, valuep, vlen); if(!co->domain) { badcookie = TRUE; @@ -1431,7 +1432,7 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, /* now check if the domain is correct */ if(!co->domain || (co->tailmatch && !is_ip && - tailmatch(co->domain, strlen(co->domain), host)) || + cookie_tailmatch(co->domain, strlen(co->domain), host)) || ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* * the right part of the host matches the domain stuff in the diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index 6e2458d..4ab8242 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -443,6 +443,9 @@ /* 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 + /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 @@ -572,9 +575,6 @@ /* Define to 1 if you have the windows.h header file. */ #cmakedefine HAVE_WINDOWS_H 1 -/* Define to 1 if you have the winldap.h header file. */ -#cmakedefine HAVE_WINLDAP_H 1 - /* Define to 1 if you have the winsock2.h header file. */ #cmakedefine HAVE_WINSOCK2_H 1 diff --git a/Utilities/cmcurl/lib/curl_log.c b/Utilities/cmcurl/lib/curl_log.c index 71024cf..782c35a 100644 --- a/Utilities/cmcurl/lib/curl_log.c +++ b/Utilities/cmcurl/lib/curl_log.c @@ -130,13 +130,11 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf, const char *fmt, ...) { DEBUGASSERT(cf); - if(data && Curl_log_cf_is_debug(cf)) { + if(data && Curl_log_cf_is_debug(cf, data)) { va_list ap; int len; char buffer[MAXINFO + 2]; - len = msnprintf(buffer, MAXINFO, "[CONN-%ld%s-%s] ", - cf->conn->connection_id, cf->sockindex? "/2" : "", - cf->cft->name); + len = msnprintf(buffer, MAXINFO, "[%s] ", cf->cft->name); va_start(ap, fmt); len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap); va_end(ap); diff --git a/Utilities/cmcurl/lib/curl_log.h b/Utilities/cmcurl/lib/curl_log.h index ad6143f..ebfa5a0 100644 --- a/Utilities/cmcurl/lib/curl_log.h +++ b/Utilities/cmcurl/lib/curl_log.h @@ -74,7 +74,7 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type, defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #define LOG_CF(data, cf, ...) \ - do { if(Curl_log_cf_is_debug(cf)) \ + do { if(Curl_log_cf_is_debug(cf, data)) \ Curl_log_cf_debug(data, cf, __VA_ARGS__); } while(0) #else #define LOG_CF Curl_log_cf_debug @@ -90,8 +90,10 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf, const char *fmt, ...); #endif -#define Curl_log_cf_is_debug(cf) \ - ((cf) && (cf)->cft->log_level >= CURL_LOG_DEBUG) +#define Curl_log_cf_is_debug(cf, data) \ + ((data) && (data)->set.verbose && \ + (cf) && (cf)->cft->log_level >= CURL_LOG_DEBUG) + #else /* !DEBUGBUILD */ @@ -110,29 +112,10 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf, const char *fmt, ...); #endif -#define Curl_log_cf_is_debug(x) ((void)(x), FALSE) +#define Curl_log_cf_is_debug(x,y) ((void)(x), (void)(y), FALSE) #endif /* !DEBUGBUILD */ -#define LOG_CF_IS_DEBUG(x) Curl_log_cf_is_debug(x) - -/* Macros intended for DEBUGF logging, use like: - * DEBUGF(infof(data, CFMSG(cf, "this filter %s rocks"), "very much")); - * and it will output: - * [CONN-1-0][CF-SSL] this filter very much rocks - * on connection #1 with sockindex 0 for filter of type "SSL". */ -#define DMSG(d,msg) \ - "[CONN-%ld] "msg, (d)->conn->connection_id -#define DMSGI(d,i,msg) \ - "[CONN-%ld-%d] "msg, (d)->conn->connection_id, (i) -#define CMSG(c,msg) \ - "[CONN-%ld] "msg, (c)->connection_id -#define CMSGI(c,i,msg) \ - "[CONN-%ld-%d] "msg, (c)->connection_id, (i) -#define CFMSG(cf,msg) \ - "[CONN-%ld-%d][CF-%s] "msg, (cf)->conn->connection_id, \ - (cf)->sockindex, (cf)->cft->name - - +#define LOG_CF_IS_DEBUG(cf, data) Curl_log_cf_is_debug(cf, data) #endif /* HEADER_CURL_LOG_H */ diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h index 1a21c5a..b8c46d7 100644 --- a/Utilities/cmcurl/lib/curl_memory.h +++ b/Utilities/cmcurl/lib/curl_memory.h @@ -55,9 +55,65 @@ */ #ifdef HEADER_CURL_MEMDEBUG_H -#error "Header memdebug.h shall not be included before curl_memory.h" +/* cleanup after memdebug.h */ + +#ifdef MEMDEBUG_NODEFINES +#ifdef CURLDEBUG + +#undef strdup +#undef malloc +#undef calloc +#undef realloc +#undef free +#undef send +#undef recv + +#ifdef WIN32 +# ifdef UNICODE +# undef wcsdup +# undef _wcsdup +# undef _tcsdup +# else +# undef _tcsdup +# endif +#endif + +#undef socket +#undef accept +#ifdef HAVE_SOCKETPAIR +#undef socketpair #endif +#ifdef HAVE_GETADDRINFO +#if defined(getaddrinfo) && defined(__osf__) +#undef ogetaddrinfo +#else +#undef getaddrinfo +#endif +#endif /* HAVE_GETADDRINFO */ + +#ifdef HAVE_FREEADDRINFO +#undef freeaddrinfo +#endif /* HAVE_FREEADDRINFO */ + +/* sclose is probably already defined, redefine it! */ +#undef sclose +#undef fopen +#undef fdopen +#undef fclose + +#endif /* MEMDEBUG_NODEFINES */ +#endif /* CURLDEBUG */ + +#undef HEADER_CURL_MEMDEBUG_H +#endif /* HEADER_CURL_MEMDEBUG_H */ + +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + +#undef fake_sclose + #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ /* * The following memory function replacement typedef's are COPIED from diff --git a/Utilities/cmcurl/lib/curl_printf.h b/Utilities/cmcurl/lib/curl_printf.h index 6d3d492..46ef344 100644 --- a/Utilities/cmcurl/lib/curl_printf.h +++ b/Utilities/cmcurl/lib/curl_printf.h @@ -37,6 +37,7 @@ # undef vprintf # undef vfprintf # undef vsnprintf +# undef mvsnprintf # undef aprintf # undef vaprintf # define printf curl_mprintf diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 119fb9b..1cb0e54 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -221,12 +221,12 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, } /* - * state() + * sasl_state() * * This is the ONLY way to change SASL state! */ -static void state(struct SASL *sasl, struct Curl_easy *data, - saslstate newstate) +static void sasl_state(struct SASL *sasl, struct Curl_easy *data, + saslstate newstate) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ @@ -508,7 +508,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, if(!result) { *progress = SASL_INPROGRESS; - state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1); + sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1); } } @@ -548,14 +548,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, if(code != sasl->params->finalcode) result = CURLE_LOGIN_DENIED; *progress = SASL_DONE; - state(sasl, data, SASL_STOP); + 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; - state(sasl, data, SASL_STOP); + sasl_state(sasl, data, SASL_STOP); return CURLE_LOGIN_DENIED; } @@ -698,7 +698,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, if(code == sasl->params->finalcode) { /* Final response was received so we are done */ *progress = SASL_DONE; - state(sasl, data, SASL_STOP); + sasl_state(sasl, data, SASL_STOP); return result; } else if(code == sasl->params->contcode) { @@ -708,7 +708,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, } else { *progress = SASL_DONE; - state(sasl, data, SASL_STOP); + sasl_state(sasl, data, SASL_STOP); return CURLE_LOGIN_DENIED; } @@ -745,7 +745,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, Curl_bufref_free(&resp); - state(sasl, data, newstate); + sasl_state(sasl, data, newstate); return result; } diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index 9043d97..e395be5 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -262,7 +262,7 @@ #if defined(__APPLE__) && !defined(USE_ARES) #include <TargetConditionals.h> #define USE_RESOLVE_ON_IPS 1 -# if defined(TARGET_OS_OSX) && TARGET_OS_OSX +# if !defined(TARGET_OS_OSX) || TARGET_OS_OSX # define CURL_OSX_CALL_COPYPROXIES 1 # endif #endif @@ -302,6 +302,7 @@ # if defined(HAVE_PROTO_BSDSOCKET_H) && \ (!defined(__amigaos4__) || defined(USE_AMISSL)) /* use bsdsocket.library directly, instead of libc networking functions */ +# define _SYS_MBUF_H /* m_len define clashes with curl */ # include <proto/bsdsocket.h> # ifdef __amigaos4__ int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds, diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h index dde7229..c1ed059 100644 --- a/Utilities/cmcurl/lib/curl_setup_once.h +++ b/Utilities/cmcurl/lib/curl_setup_once.h @@ -77,6 +77,12 @@ # endif #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 diff --git a/Utilities/cmcurl/lib/dynbuf.h b/Utilities/cmcurl/lib/dynbuf.h index 57ad62b..6291eab 100644 --- a/Utilities/cmcurl/lib/dynbuf.h +++ b/Utilities/cmcurl/lib/dynbuf.h @@ -81,8 +81,6 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save); #define DYN_PAUSE_BUFFER (64 * 1024 * 1024) #define DYN_HAXPROXY 2048 #define DYN_HTTP_REQUEST (1024*1024) -#define DYN_H2_HEADERS (128*1024) -#define DYN_H2_TRAILERS (128*1024) #define DYN_APRINTF 8000000 #define DYN_RTSP_REQ_HEADER (64*1024) #define DYN_TRAILERS (64*1024) diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index d36cc03..d034629 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -63,6 +63,7 @@ #include "slist.h" #include "mime.h" #include "amigaos.h" +#include "macos.h" #include "warnless.h" #include "sigpipe.h" #include "vssh/ssh.h" @@ -83,7 +84,7 @@ /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; -static long init_flags; +static long easy_init_flags; #ifdef GLOBAL_INIT_IS_THREADSAFE @@ -181,6 +182,11 @@ static CURLcode global_init(long flags, bool memoryfuncs) } #endif + if(Curl_macos_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n")); + goto fail; + } + if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); goto fail; @@ -199,7 +205,7 @@ static CURLcode global_init(long flags, bool memoryfuncs) } #endif - init_flags = flags; + easy_init_flags = flags; #ifdef DEBUGBUILD if(getenv("CURL_GLOBAL_INIT")) @@ -274,7 +280,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, /** * curl_global_cleanup() globally cleanups curl, uses the value of - * "init_flags" to determine what needs to be cleaned up and what doesn't. + * "easy_init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) { @@ -294,7 +300,7 @@ void curl_global_cleanup(void) Curl_resolver_global_cleanup(); #ifdef WIN32 - Curl_win32_cleanup(init_flags); + Curl_win32_cleanup(easy_init_flags); #endif Curl_amiga_cleanup(); @@ -308,7 +314,7 @@ void curl_global_cleanup(void) free(leakpointer); #endif - init_flags = 0; + easy_init_flags = 0; global_init_unlock(); } @@ -893,6 +899,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) /* the connection cache is setup on demand */ outcurl->state.conn_cache = NULL; outcurl->state.lastconnect_id = -1; + outcurl->state.recent_conn_id = -1; + outcurl->id = -1; outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; diff --git a/Utilities/cmcurl/lib/easy_lock.h b/Utilities/cmcurl/lib/easy_lock.h index 5fa9477..6399a39 100644 --- a/Utilities/cmcurl/lib/easy_lock.h +++ b/Utilities/cmcurl/lib/easy_lock.h @@ -1,3 +1,5 @@ +#ifndef HEADER_CURL_EASY_LOCK_H +#define HEADER_CURL_EASY_LOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -103,3 +105,5 @@ static inline void curl_simple_lock_unlock(curl_simple_lock *lock) #undef GLOBAL_INIT_IS_THREADSAFE #endif + +#endif /* HEADER_CURL_EASY_LOCK_H */ diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c index a9c1efd..e69c658 100644 --- a/Utilities/cmcurl/lib/easyoptions.c +++ b/Utilities/cmcurl/lib/easyoptions.c @@ -120,6 +120,7 @@ struct curl_easyoption Curl_easyopts[] = { {"HAPPY_EYEBALLS_TIMEOUT_MS", CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOT_LONG, 0}, {"HAPROXYPROTOCOL", CURLOPT_HAPROXYPROTOCOL, CURLOT_LONG, 0}, + {"HAPROXY_CLIENT_IP", CURLOPT_HAPROXY_CLIENT_IP, CURLOT_STRING, 0}, {"HEADER", CURLOPT_HEADER, CURLOT_LONG, 0}, {"HEADERDATA", CURLOPT_HEADERDATA, CURLOT_CBPTR, 0}, {"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0}, @@ -164,7 +165,9 @@ struct curl_easyoption Curl_easyopts[] = { {"MAIL_AUTH", CURLOPT_MAIL_AUTH, CURLOT_STRING, 0}, {"MAIL_FROM", CURLOPT_MAIL_FROM, CURLOT_STRING, 0}, {"MAIL_RCPT", CURLOPT_MAIL_RCPT, CURLOT_SLIST, 0}, - {"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOT_LONG, 0}, + {"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, + CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"MAIL_RCPT_ALLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOT_LONG, 0}, {"MAXAGE_CONN", CURLOPT_MAXAGE_CONN, CURLOT_LONG, 0}, {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0}, {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0}, @@ -370,6 +373,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (322 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (323 + 1)); } #endif diff --git a/Utilities/cmcurl/lib/fopen.c b/Utilities/cmcurl/lib/fopen.c index f710dbf..b6e3cad 100644 --- a/Utilities/cmcurl/lib/fopen.c +++ b/Utilities/cmcurl/lib/fopen.c @@ -56,13 +56,13 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, int fd = -1; *tempname = NULL; - if(stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode)) { - /* a non-regular file, fallback to direct fopen() */ - *fh = fopen(filename, FOPEN_WRITETEXT); - if(*fh) - return CURLE_OK; + *fh = fopen(filename, FOPEN_WRITETEXT); + if(!*fh) goto fail; - } + if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) + return CURLE_OK; + fclose(*fh); + *fh = NULL; result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix)); if(result) @@ -85,7 +85,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, if((fstat(fd, &nsb) != -1) && (nsb.st_uid == sb.st_uid) && (nsb.st_gid == sb.st_gid)) { /* if the user and group are the same, clone the original mode */ - if(fchmod(fd, sb.st_mode) == -1) + if(fchmod(fd, (mode_t)sb.st_mode) == -1) goto fail; } } diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 4f50cb4..a1cfa65 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -93,14 +93,14 @@ /* Local API functions */ #ifndef DEBUGBUILD -static void _state(struct Curl_easy *data, - ftpstate newstate); -#define state(x,y) _state(x,y) +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate); +#define ftp_state(x,y) _ftp_state(x,y) #else -static void _state(struct Curl_easy *data, - ftpstate newstate, - int lineno); -#define state(x,y) _state(x,y,__LINE__) +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate, + int lineno); +#define ftp_state(x,y) _ftp_state(x,y,__LINE__) #endif static CURLcode ftp_sendquote(struct Curl_easy *data, @@ -463,7 +463,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data) } conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OK; } @@ -591,7 +591,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data, * generically is a good idea. */ infof(data, "We got a 421 - timeout"); - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OPERATION_TIMEDOUT; } @@ -750,10 +750,10 @@ static const char * const ftp_state_names[]={ #endif /* This is the ONLY way to change FTP state! */ -static void _state(struct Curl_easy *data, - ftpstate newstate +static void _ftp_state(struct Curl_easy *data, + ftpstate newstate #ifdef DEBUGBUILD - , int lineno + , int lineno #endif ) { @@ -784,7 +784,7 @@ static CURLcode ftp_state_user(struct Curl_easy *data, if(!result) { struct ftp_conn *ftpc = &conn->proto.ftpc; ftpc->ftp_trying_alternative = FALSE; - state(data, FTP_USER); + ftp_state(data, FTP_USER); } return result; } @@ -794,7 +794,7 @@ static CURLcode ftp_state_pwd(struct Curl_easy *data, { CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD"); if(!result) - state(data, FTP_PWD); + ftp_state(data, FTP_PWD); return result; } @@ -872,7 +872,7 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data, for all upcoming ones in the ftp->dirs[] array */ result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath); if(!result) - state(data, FTP_CWD); + ftp_state(data, FTP_CWD); } else { if(ftpc->dirdepth) { @@ -882,7 +882,7 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]); if(!result) - state(data, FTP_CWD); + ftp_state(data, FTP_CWD); } else { /* No CWD necessary */ @@ -1261,11 +1261,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, if(result) goto out; portsock = CURL_SOCKET_BAD; /* now held in filter */ - state(data, FTP_PORT); + ftp_state(data, FTP_PORT); out: if(result) { - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); } if(portsock != CURL_SOCKET_BAD) Curl_socket_close(data, conn, portsock); @@ -1307,7 +1307,7 @@ static CURLcode ftp_state_use_pasv(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]); if(!result) { ftpc->count1 = modeoff; - state(data, FTP_PASV); + ftp_state(data, FTP_PASV); infof(data, "Connect data stream passively"); } return result; @@ -1330,7 +1330,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data) /* doesn't transfer any data */ /* still possibly do PRE QUOTE jobs */ - state(data, FTP_RETR_PREQUOTE); + ftp_state(data, FTP_RETR_PREQUOTE); result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE); } else if(data->set.ftp_use_port) { @@ -1355,7 +1355,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data) result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s", conn->proto.ftpc.file); if(!result) - state(data, FTP_PRET); + ftp_state(data, FTP_PRET); } else result = ftp_state_use_pasv(data, conn); @@ -1377,7 +1377,7 @@ static CURLcode ftp_state_rest(struct Curl_easy *data, whether it supports range */ result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0); if(!result) - state(data, FTP_REST); + ftp_state(data, FTP_REST); } else result = ftp_state_prepare_transfer(data); @@ -1398,7 +1398,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data, /* we know ftpc->file is a valid pointer to a file name */ result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); if(!result) - state(data, FTP_SIZE); + ftp_state(data, FTP_SIZE); } else result = ftp_state_rest(data, conn); @@ -1466,7 +1466,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data) free(cmd); if(!result) - state(data, FTP_LIST); + ftp_state(data, FTP_LIST); return result; } @@ -1530,7 +1530,7 @@ static CURLcode ftp_state_mdtm(struct Curl_easy *data) result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file); if(!result) - state(data, FTP_MDTM); + ftp_state(data, FTP_MDTM); } else result = ftp_state_type(data); @@ -1569,7 +1569,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data, /* Got no given size to start from, figure it out */ result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); if(!result) - state(data, FTP_STOR_SIZE); + ftp_state(data, FTP_STOR_SIZE); return result; } @@ -1624,7 +1624,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data, * ftp_done() because we didn't transfer anything! */ ftp->transfer = PPTRANSFER_NONE; - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OK; } } @@ -1634,7 +1634,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s", ftpc->file); if(!result) - state(data, FTP_STOR); + ftp_state(data, FTP_STOR); return result; } @@ -1695,7 +1695,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); if(result) return result; - state(data, instate); + ftp_state(data, instate); quote = TRUE; } } @@ -1709,7 +1709,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, break; case FTP_RETR_PREQUOTE: if(ftp->transfer != PPTRANSFER_BODY) - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); else { if(ftpc->known_filesize != -1) { Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); @@ -1731,12 +1731,12 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, */ result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); if(!result) - state(data, FTP_RETR); + ftp_state(data, FTP_RETR); } else { result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); if(!result) - state(data, FTP_RETR_SIZE); + ftp_state(data, FTP_RETR_SIZE); } } } @@ -1780,7 +1780,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data, if(!result) { conn->proto.ftpc.count1++; /* remain in/go to the FTP_PASV state */ - state(data, FTP_PASV); + ftp_state(data, FTP_PASV); } return result; } @@ -2005,7 +2005,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; conn->bits.do_more = TRUE; - state(data, FTP_STOP); /* this phase is completed */ + ftp_state(data, FTP_STOP); /* this phase is completed */ return result; } @@ -2039,7 +2039,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data, } else { infof(data, "Connect data stream actively"); - state(data, FTP_STOP); /* end of DO phase */ + ftp_state(data, FTP_STOP); /* end of DO phase */ result = ftp_dophase_done(data, FALSE); } @@ -2151,7 +2151,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, infof(data, "The requested document is not new enough"); ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ data->info.timecond = TRUE; - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OK; } break; @@ -2160,7 +2160,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, infof(data, "The requested document is not old enough"); ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ data->info.timecond = TRUE; - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OK; } break; @@ -2268,7 +2268,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data, /* Set ->transfer so that we won't get any error in ftp_done() * because we didn't transfer the any file */ ftp->transfer = PPTRANSFER_NONE; - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return CURLE_OK; } @@ -2279,13 +2279,13 @@ static CURLcode ftp_state_retr(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, data->state.resume_from); if(!result) - state(data, FTP_RETR_REST); + ftp_state(data, FTP_RETR_REST); } else { /* no resume */ result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); if(!result) - state(data, FTP_RETR); + ftp_state(data, FTP_RETR); } return result; @@ -2385,7 +2385,7 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data, else { result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); if(!result) - state(data, FTP_RETR); + ftp_state(data, FTP_RETR); } break; } @@ -2401,7 +2401,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data, if(ftpcode >= 400) { failf(data, "Failed FTP upload: %0d", ftpcode); - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); /* oops, we never close the sockets! */ return CURLE_UPLOAD_FAILED; } @@ -2412,7 +2412,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data, if(data->set.ftp_use_port) { bool connected; - state(data, FTP_STOP); /* no longer in STOR state */ + ftp_state(data, FTP_STOP); /* no longer in STOR state */ result = AllowServerConnect(data, &connected); if(result) @@ -2535,7 +2535,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, if(!connected) { struct ftp_conn *ftpc = &conn->proto.ftpc; infof(data, "Data conn was not available immediately"); - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); ftpc->wait_data_conn = TRUE; } } @@ -2546,7 +2546,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, if((instate == FTP_LIST) && (ftpcode == 450)) { /* simply no matching files in the dir listing */ ftp->transfer = PPTRANSFER_NONE; /* don't download anything */ - state(data, FTP_STOP); /* this phase is over */ + ftp_state(data, FTP_STOP); /* this phase is over */ } else { failf(data, "RETR response: %03d", ftpcode); @@ -2582,7 +2582,7 @@ static CURLcode ftp_state_loggedin(struct Curl_easy *data) */ result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0); if(!result) - state(data, FTP_PBSZ); + ftp_state(data, FTP_PBSZ); } else { result = ftp_state_pwd(data, conn); @@ -2605,7 +2605,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", conn->passwd?conn->passwd:""); if(!result) - state(data, FTP_PASS); + ftp_state(data, FTP_PASS); } else if(ftpcode/100 == 2) { /* 230 User ... logged in. @@ -2617,7 +2617,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); if(!result) - state(data, FTP_ACCT); + ftp_state(data, FTP_ACCT); } else { failf(data, "ACCT requested but none available"); @@ -2638,7 +2638,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); if(!result) { ftpc->ftp_trying_alternative = TRUE; - state(data, FTP_USER); + ftp_state(data, FTP_USER); } } else { @@ -2741,7 +2741,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); if(!result) - state(data, FTP_AUTH); + ftp_state(data, FTP_AUTH); } else result = ftp_state_user(data, conn); @@ -2808,7 +2808,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, Curl_pp_sendf(data, &ftpc->pp, "PROT %c", data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); if(!result) - state(data, FTP_PROT); + ftp_state(data, FTP_PROT); break; case FTP_PROT: @@ -2827,7 +2827,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, */ result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); if(!result) - state(data, FTP_CCC); + ftp_state(data, FTP_CCC); } else result = ftp_state_pwd(data, conn); @@ -2919,7 +2919,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, infof(data, "Entry path is '%s'", ftpc->entrypath); /* also save it where getinfo can access it: */ data->state.most_recent_ftp_entrypath = ftpc->entrypath; - state(data, FTP_SYST); + ftp_state(data, FTP_SYST); break; } @@ -2935,7 +2935,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, infof(data, "Failed to figure out path"); } } - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE")); break; @@ -2970,7 +2970,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, /* remember target server OS */ Curl_safefree(ftpc->server_os); ftpc->server_os = os; - state(data, FTP_NAMEFMT); + ftp_state(data, FTP_NAMEFMT); break; } /* Nothing special for the target server. */ @@ -2982,7 +2982,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, /* Cannot identify server OS. Continue anyway and cross fingers. */ } - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE")); break; @@ -2993,7 +2993,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, break; } - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE")); break; @@ -3026,7 +3026,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]); if(!result) - state(data, FTP_MKD); + ftp_state(data, FTP_MKD); } else { /* return failure */ @@ -3055,7 +3055,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, result = CURLE_REMOTE_ACCESS_DENIED; } else { - state(data, FTP_CWD); + ftp_state(data, FTP_CWD); /* send CWD */ result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); @@ -3114,7 +3114,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, /* fallthrough, just stop! */ default: /* internal error */ - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); break; } } /* if(ftpcode) */ @@ -3191,7 +3191,7 @@ static CURLcode ftp_connect(struct Curl_easy *data, /* When we connect, we start in the state where we await the 220 response */ - state(data, FTP_WAIT220); + ftp_state(data, FTP_WAIT220); result = ftp_multi_statemach(data, done); @@ -3516,13 +3516,13 @@ static CURLcode ftp_nb_type(struct Curl_easy *data, char want = (char)(ascii?'A':'I'); if(ftpc->transfertype == want) { - state(data, newstate); + ftp_state(data, newstate); return ftp_state_type_resp(data, 200, newstate); } result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want); if(!result) { - state(data, newstate); + ftp_state(data, newstate); /* keep track of our current transfer type */ ftpc->transfertype = want; @@ -4040,11 +4040,11 @@ static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn) curl_easy_strerror(result)); conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "QUIT command failed"); /* mark for connection closure */ - state(data, FTP_STOP); + ftp_state(data, FTP_STOP); return result; } - state(data, FTP_QUIT); + ftp_state(data, FTP_QUIT); result = ftp_block_statemach(data, conn); } diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c index 826ffd0..f1574e0 100644 --- a/Utilities/cmcurl/lib/getinfo.c +++ b/Utilities/cmcurl/lib/getinfo.c @@ -415,6 +415,13 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, case CURLINFO_RETRY_AFTER: *param_offt = data->info.retry_after; break; + case CURLINFO_XFER_ID: + *param_offt = data->id; + break; + case CURLINFO_CONN_ID: + *param_offt = data->conn? + data->conn->connection_id : data->state.recent_conn_id; + break; default: return CURLE_UNKNOWN_OPTION; } diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index d721403..1a289de 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -67,10 +67,6 @@ #include "curl_memory.h" #include "memdebug.h" -#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES) -#include <SystemConfiguration/SCDynamicStoreCopySpecific.h> -#endif - #if defined(CURLRES_SYNCH) && \ defined(HAVE_ALARM) && \ defined(SIGALRM) && \ @@ -561,6 +557,7 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name) static struct Curl_addrinfo *get_localhost(int port, const char *name) { struct Curl_addrinfo *ca; + struct Curl_addrinfo *ca6; const size_t ss_size = sizeof(struct sockaddr_in); const size_t hostlen = strlen(name); struct sockaddr_in sa; @@ -587,8 +584,12 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name) memcpy(ca->ai_addr, &sa, ss_size); ca->ai_canonname = (char *)ca->ai_addr + ss_size; strcpy(ca->ai_canonname, name); - ca->ai_next = get_localhost6(port, name); - return ca; + + ca6 = get_localhost6(port, name); + if(!ca6) + return ca; + ca6->ai_next = ca; + return ca6; } #ifdef ENABLE_IPV6 @@ -743,23 +744,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, return CURLRESOLV_ERROR; } -#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES) - { - /* - * The automagic conversion from IPv4 literals to IPv6 literals only - * works if the SCDynamicStoreCopyProxies system function gets called - * first. As Curl currently doesn't support system-wide HTTP proxies, we - * therefore don't use any value this function might return. - * - * This function is only available on a macOS and is not needed for - * IPv4-only builds, hence the conditions above. - */ - CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); - if(dict) - CFRelease(dict); - } -#endif - #ifndef USE_RESOLVE_ON_IPS /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c index 53c01fc..7ecf004 100644 --- a/Utilities/cmcurl/lib/hsts.c +++ b/Utilities/cmcurl/lib/hsts.c @@ -57,7 +57,7 @@ /* to play well with debug builds, we can *set* a fixed time this will return */ time_t deltatime; /* allow for "adjustments" for unit test purposes */ -static time_t debugtime(void *unused) +static time_t hsts_debugtime(void *unused) { char *timestr = getenv("CURL_TIME"); (void)unused; @@ -70,7 +70,8 @@ static time_t debugtime(void *unused) } return time(NULL); } -#define time(x) debugtime(x) +#undef time +#define time(x) hsts_debugtime(x) #endif struct hsts *Curl_hsts_init(void) diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index 219dcc2..e611d27 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -1308,7 +1308,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in, || IS_HTTPS_PROXY(conn->http_proxy.proxytype) #endif ) - && conn->httpversion != 20) { + && conn->httpversion < 20) { /* Make sure this doesn't send more body bytes than what the max send speed says. The request bytes do not count to the max speed. */ @@ -2667,11 +2667,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, #ifndef USE_HYPER /* With Hyper the body is always passed on separately */ if(data->set.postfields) { - - /* In HTTP2, we send request body in DATA frame regardless of - its size. */ - if(conn->httpversion < 20 && - !data->state.expect100header && + if(!data->state.expect100header && (http->postsize < MAX_INITIAL_POST_SIZE)) { /* if we don't use expect: 100 AND postsize is less than MAX_INITIAL_POST_SIZE @@ -2832,16 +2828,18 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, } if(co) { struct Cookie *store = co; + size_t clen = 8; /* hold the size of the generated Cookie: header */ /* now loop through all cookies that matched */ while(co) { if(co->value) { - if(0 == count) { + size_t add; + if(!count) { result = Curl_dyn_addn(r, STRCONST("Cookie: ")); if(result) break; } - if((Curl_dyn_len(r) + strlen(co->name) + strlen(co->value) + 1) >= - MAX_COOKIE_HEADER_LEN) { + add = strlen(co->name) + strlen(co->value) + 1; + if(clen + add >= MAX_COOKIE_HEADER_LEN) { infof(data, "Restricted outgoing cookies due to header size, " "'%s' not sent", co->name); linecap = TRUE; @@ -2851,6 +2849,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, co->name, co->value); if(result) break; + clen += add + (count ? 2 : 0); count++; } co = co->next; /* next cookie please */ @@ -3381,6 +3380,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) } } + if(data->req.upload_done) + Curl_conn_ev_data_done_send(data); + if((conn->httpversion >= 20) && data->req.upload_chunky) /* upload_chunky was set above to set up the request in a chunky fashion, but is disabled here again to avoid that the chunked encoded version is @@ -4569,8 +4571,8 @@ CURLcode Curl_http_req_make(struct httpreq **preq, if(!req->path) goto out; } - Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS); - Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS); + Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); result = CURLE_OK; out: @@ -4727,8 +4729,8 @@ CURLcode Curl_http_req_make2(struct httpreq **preq, if(result) goto out; - Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS); - Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS); + Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); result = CURLE_OK; out: @@ -4858,8 +4860,8 @@ CURLcode Curl_http_resp_make(struct http_resp **presp, if(!resp->description) goto out; } - Curl_dynhds_init(&resp->headers, 0, DYN_H2_HEADERS); - Curl_dynhds_init(&resp->trailers, 0, DYN_H2_TRAILERS); + Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST); + Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST); result = CURLE_OK; out: diff --git a/Utilities/cmcurl/lib/http1.c b/Utilities/cmcurl/lib/http1.c index 46fe855..a442d3e 100644 --- a/Utilities/cmcurl/lib/http1.c +++ b/Utilities/cmcurl/lib/http1.c @@ -38,124 +38,97 @@ #include "memdebug.h" -#define MAX_URL_LEN (4*1024) +#define H1_MAX_URL_LEN (8*1024) void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len) { memset(parser, 0, sizeof(*parser)); parser->max_line_len = max_line_len; - Curl_bufq_init(&parser->scratch, max_line_len, 1); + Curl_dyn_init(&parser->scratch, max_line_len); } void Curl_h1_req_parse_free(struct h1_req_parser *parser) { if(parser) { Curl_http_req_free(parser->req); - Curl_bufq_free(&parser->scratch); + Curl_dyn_free(&parser->scratch); parser->req = NULL; parser->done = FALSE; } } +static CURLcode trim_line(struct h1_req_parser *parser, int options) +{ + DEBUGASSERT(parser->line); + if(parser->line_len) { + if(parser->line[parser->line_len - 1] == '\n') + --parser->line_len; + if(parser->line_len) { + if(parser->line[parser->line_len - 1] == '\r') + --parser->line_len; + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + } + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + } + else if(options & H1_PARSE_OPT_STRICT) + return CURLE_URL_MALFORMAT; + + if(parser->line_len > parser->max_line_len) { + return CURLE_URL_MALFORMAT; + } + return CURLE_OK; +} + static ssize_t detect_line(struct h1_req_parser *parser, - const char *buf, const size_t buflen, int options, + const char *buf, const size_t buflen, CURLcode *err) { const char *line_end; - size_t len; DEBUGASSERT(!parser->line); line_end = memchr(buf, '\n', buflen); if(!line_end) { - *err = (buflen > parser->max_line_len)? CURLE_URL_MALFORMAT : CURLE_AGAIN; + *err = CURLE_AGAIN; return -1; } - len = line_end - buf + 1; - if(len > parser->max_line_len) { - *err = CURLE_URL_MALFORMAT; - return -1; - } - - if(options & H1_PARSE_OPT_STRICT) { - if((len == 1) || (buf[len - 2] != '\r')) { - *err = CURLE_URL_MALFORMAT; - return -1; - } - parser->line = buf; - parser->line_len = len - 2; - } - else { - parser->line = buf; - parser->line_len = len - (((len == 1) || (buf[len - 2] != '\r'))? 1 : 2); - } + parser->line = buf; + parser->line_len = line_end - buf + 1; *err = CURLE_OK; - return (ssize_t)len; + return (ssize_t)parser->line_len; } static ssize_t next_line(struct h1_req_parser *parser, const char *buf, const size_t buflen, int options, CURLcode *err) { - ssize_t nread = 0, n; + ssize_t nread = 0; if(parser->line) { - if(parser->scratch_skip) { - /* last line was from scratch. Remove it now, since we are done - * with it and look for the next one. */ - Curl_bufq_skip_and_shift(&parser->scratch, parser->scratch_skip); - parser->scratch_skip = 0; - } parser->line = NULL; parser->line_len = 0; + Curl_dyn_reset(&parser->scratch); } - if(Curl_bufq_is_empty(&parser->scratch)) { - nread = detect_line(parser, buf, buflen, options, err); - if(nread < 0) { - if(*err != CURLE_AGAIN) + nread = detect_line(parser, buf, buflen, err); + if(nread >= 0) { + if(Curl_dyn_len(&parser->scratch)) { + /* append detected line to scratch to have the complete line */ + *err = Curl_dyn_addn(&parser->scratch, parser->line, parser->line_len); + if(*err) return -1; - /* not a complete line, add to scratch for later revisit */ - nread = Curl_bufq_write(&parser->scratch, - (const unsigned char *)buf, buflen, err); - return nread; + parser->line = Curl_dyn_ptr(&parser->scratch); + parser->line_len = Curl_dyn_len(&parser->scratch); } - /* found one */ + *err = trim_line(parser, options); + if(*err) + return -1; } - else { - const char *sbuf; - size_t sbuflen; - - /* scratch contains bytes from last attempt, add more to it */ - if(buflen) { - const char *line_end; - size_t add_len; - ssize_t pos; - - line_end = memchr(buf, '\n', buflen); - pos = line_end? (line_end - buf + 1) : -1; - add_len = (pos >= 0)? (size_t)pos : buflen; - nread = Curl_bufq_write(&parser->scratch, - (const unsigned char *)buf, add_len, err); - if(nread < 0) { - /* Unable to add anything to scratch is an error, since we should - * have seen a line there then before. */ - if(*err == CURLE_AGAIN) - *err = CURLE_URL_MALFORMAT; - return -1; - } - } - - if(Curl_bufq_peek(&parser->scratch, - (const unsigned char **)&sbuf, &sbuflen)) { - n = detect_line(parser, sbuf, sbuflen, options, err); - if(n < 0 && *err != CURLE_AGAIN) - return -1; /* real error */ - parser->scratch_skip = (size_t)n; - } - else { - /* we SHOULD be able to peek at scratch data */ - DEBUGASSERT(0); - } + else if(*err == CURLE_AGAIN) { + /* no line end in `buf`, add it to our scratch */ + *err = Curl_dyn_addn(&parser->scratch, (const unsigned char *)buf, buflen); + nread = (*err)? -1 : (ssize_t)buflen; } return nread; } @@ -231,7 +204,7 @@ static CURLcode start_req(struct h1_req_parser *parser, else { /* origin-form OR absolute-form */ CURLUcode uc; - char tmp[MAX_URL_LEN]; + char tmp[H1_MAX_URL_LEN]; /* default, unless we see an absolute URL */ path = target; @@ -328,7 +301,7 @@ ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser, goto out; } parser->done = TRUE; - Curl_bufq_free(&parser->scratch); + Curl_dyn_reset(&parser->scratch); /* last chance adjustments */ } else { diff --git a/Utilities/cmcurl/lib/http1.h b/Utilities/cmcurl/lib/http1.h index 93111ef..b1eaa96 100644 --- a/Utilities/cmcurl/lib/http1.h +++ b/Utilities/cmcurl/lib/http1.h @@ -33,11 +33,11 @@ #define H1_PARSE_OPT_NONE (0) #define H1_PARSE_OPT_STRICT (1 << 0) -#define H1_PARSE_DEFAULT_MAX_LINE_LEN (8 * 1024) +#define H1_PARSE_DEFAULT_MAX_LINE_LEN DYN_HTTP_REQUEST struct h1_req_parser { struct httpreq *req; - struct bufq scratch; + struct dynbuf scratch; size_t scratch_skip; const char *line; size_t max_line_len; diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index 191d8cd..6c09ec1 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -134,9 +134,11 @@ struct cf_h2_ctx { BIT(conn_closed); BIT(goaway); BIT(enable_push); + BIT(nw_out_blocked); }; /* How to access `call_data` from a cf_h2 filter */ +#undef CF_CTX_CALL_DATA #define CF_CTX_CALL_DATA(cf) \ ((struct cf_h2_ctx *)(cf)->ctx)->call_data @@ -175,6 +177,7 @@ struct stream_ctx { struct bufq sendbuf; /* request buffer */ struct dynhds resp_trailers; /* response trailer fields */ size_t resp_hds_len; /* amount of response header bytes in recvbuf */ + size_t upload_blocked_len; curl_off_t upload_left; /* number of request bytes left to upload */ char **push_headers; /* allocated array */ @@ -183,6 +186,7 @@ struct stream_ctx { int status_code; /* HTTP response status code */ uint32_t error; /* stream error code */ + uint32_t local_window_size; /* the local recv window size */ bool closed; /* TRUE on stream close */ bool reset; /* TRUE on stream reset */ bool close_handled; /* TRUE if stream closure is handled by libcurl */ @@ -209,9 +213,12 @@ static void drain_stream(struct Curl_cfilter *cf, (void)cf; bits = CURL_CSELECT_IN; - if(!stream->send_closed && stream->upload_left) + if(!stream->send_closed && + (stream->upload_left || stream->upload_blocked_len)) bits |= CURL_CSELECT_OUT; if(data->state.dselect_bits != bits) { + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] DRAIN dselect_bits=%x", + stream->id, bits)); data->state.dselect_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } @@ -245,13 +252,14 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf, H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); - Curl_dynhds_init(&stream->resp_trailers, 0, DYN_H2_TRAILERS); + Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST); stream->resp_hds_len = 0; stream->bodystarted = FALSE; stream->status_code = -1; stream->closed = FALSE; stream->close_handled = FALSE; stream->error = NGHTTP2_NO_ERROR; + stream->local_window_size = H2_STREAM_WINDOW_SIZE; stream->upload_left = 0; H2_STREAM_LCTX(data) = stream; @@ -580,7 +588,6 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, ssize_t nread = -1; *input_pending = FALSE; - Curl_attach_connection(data, cf->conn); nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); if(nread != -1) { DEBUGF(LOG_CF(data, cf, "%zd bytes stray data read before trying " @@ -592,11 +599,10 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, alive = !should_close_session(ctx); } } - else { + else if(result != CURLE_AGAIN) { /* the read failed so let's say this is dead anyway */ alive = FALSE; } - Curl_detach_connection(data); } return alive; @@ -644,13 +650,17 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf, if(Curl_bufq_is_empty(&ctx->outbufq)) return CURLE_OK; - DEBUGF(LOG_CF(data, cf, "h2 conn flush %zu bytes", - Curl_bufq_len(&ctx->outbufq))); nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); - if(nwritten < 0 && result != CURLE_AGAIN) { + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + DEBUGF(LOG_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", + Curl_bufq_len(&ctx->outbufq))); + ctx->nw_out_blocked = 1; + } return result; } - return CURLE_OK; + DEBUGF(LOG_CF(data, cf, "nw send buffer flushed")); + return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN; } /* @@ -676,15 +686,17 @@ static ssize_t send_callback(nghttp2_session *h2, nw_out_writer, cf, &result); if(nwritten < 0) { if(result == CURLE_AGAIN) { + ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; } failf(data, "Failed sending HTTP2 data"); return NGHTTP2_ERR_CALLBACK_FAILURE; } - if(!nwritten) + if(!nwritten) { + ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; - + } return nwritten; } @@ -964,6 +976,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, struct stream_ctx *stream = H2_STREAM_CTX(data); int32_t stream_id = frame->hd.stream_id; CURLcode result; + size_t rbuflen; int rv; if(!stream) { @@ -973,10 +986,10 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, switch(frame->hd.type) { case NGHTTP2_DATA: + rbuflen = Curl_bufq_len(&stream->recvbuf); DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[DATA len=%zu pad=%zu], " "buffered=%zu, window=%d/%d", - stream_id, frame->hd.length, frame->data.padlen, - Curl_bufq_len(&stream->recvbuf), + stream_id, frame->hd.length, frame->data.padlen, rbuflen, nghttp2_session_get_stream_effective_recv_data_length( ctx->h2, stream->id), nghttp2_session_get_stream_effective_local_window_size( @@ -993,6 +1006,20 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { drain_stream(cf, data, stream); } + else if(rbuflen > stream->local_window_size) { + int32_t wsize = nghttp2_session_get_stream_local_window_size( + ctx->h2, stream->id); + if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) { + /* H2 flow control is not absolute, as the server might not have the + * same view, yet. When we recieve more than we want, we enforce + * the local window size again to make nghttp2 send WINDOW_UPATEs + * accordingly. */ + nghttp2_session_set_local_window_size(ctx->h2, + NGHTTP2_FLAG_NONE, + stream->id, + stream->local_window_size); + } + } break; case NGHTTP2_HEADERS: DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[HEADERS]", stream_id)); @@ -1095,6 +1122,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, ctx->max_concurrent_streams)); multi_connchanged(data->multi); } + /* Since the initial stream window is 64K, a request might be on HOLD, + * due to exhaustion. The (initial) SETTINGS may announce a much larger + * window and *assume* that we treat this like a WINDOW_UPDATE. Some + * servers send an explicit WINDOW_UPDATE, but not all seem to do that. + * To be safe, we UNHOLD a stream in order not to stall. */ + if((data->req.keepon & KEEP_SEND_HOLD) && + (data->req.keepon & KEEP_SEND)) { + struct stream_ctx *stream = H2_STREAM_CTX(data); + data->req.keepon &= ~KEEP_SEND_HOLD; + if(stream) { + drain_stream(cf, data, stream); + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] un-holding after SETTINGS", + stream_id)); + } + } break; } case NGHTTP2_GOAWAY: @@ -1448,8 +1490,8 @@ static ssize_t req_body_read_callback(nghttp2_session *session, if(nread > 0 && stream->upload_left != -1) stream->upload_left -= nread; - DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] req_body_read(len=%zu) left=%zd" - " -> %zd, %d", + DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] req_body_read(len=%zu) left=%" + CURL_FORMAT_CURL_OFF_T " -> %zd, %d", stream_id, length, stream->upload_left, nread, result)); if(stream->upload_left == 0) @@ -1555,11 +1597,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, *err = CURLE_SEND_ERROR; /* trigger Curl_retry_request() later */ return -1; } - else if(stream->reset) { - failf(data, "HTTP/2 stream %u was reset", stream->id); - *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; - return -1; - } else if(stream->error != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", stream->id, nghttp2_http2_strerror(stream->error), @@ -1567,6 +1604,11 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, *err = CURLE_HTTP2_STREAM; return -1; } + else if(stream->reset) { + failf(data, "HTTP/2 stream %u was reset", stream->id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + return -1; + } if(!stream->bodystarted) { failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " @@ -1659,9 +1701,10 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, struct stream_ctx *stream = H2_STREAM_CTX(data); int rv = 0; - if((sweight_wanted(data) != sweight_in_effect(data)) || - (data->set.priority.exclusive != data->state.priority.exclusive) || - (data->set.priority.parent != data->state.priority.parent) ) { + if(stream && stream->id > 0 && + ((sweight_wanted(data) != sweight_in_effect(data)) || + (data->set.priority.exclusive != data->state.priority.exclusive) || + (data->set.priority.parent != data->state.priority.parent)) ) { /* send new weight and/or dependency */ nghttp2_priority_spec pri_spec; @@ -1675,7 +1718,8 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, goto out; } - while(!rv && nghttp2_session_want_write(ctx->h2)) + ctx->nw_out_blocked = 0; + while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) rv = nghttp2_session_send(ctx->h2); out: @@ -1739,7 +1783,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, /* Process network input buffer fist */ if(!Curl_bufq_is_empty(&ctx->inbufq)) { - DEBUGF(LOG_CF(data, cf, "Process %zd bytes in connection buffer", + DEBUGF(LOG_CF(data, cf, "Process %zu bytes in connection buffer", Curl_bufq_len(&ctx->inbufq))); if(h2_process_pending_input(cf, data, &result) < 0) return result; @@ -1760,7 +1804,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, } nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); - /* DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d", + /* DEBUGF(LOG_CF(data, cf, "read %zu bytes nw data -> %zd, %d", Curl_bufq_len(&ctx->inbufq), nread, result)); */ if(nread < 0) { if(result != CURLE_AGAIN) { @@ -1836,7 +1880,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, out: result = h2_progress_egress(cf, data); - if(result) { + if(result && result != CURLE_AGAIN) { *err = result; nread = -1; } @@ -1864,7 +1908,8 @@ static ssize_t h2_submit(struct stream_ctx **pstream, struct h1_req_parser h1; struct dynhds h2_headers; nghttp2_nv *nva = NULL; - size_t nheader, i; + const void *body = NULL; + size_t nheader, bodylen, i; nghttp2_data_provider data_prd; int32_t stream_id; nghttp2_priority_spec pri_spec; @@ -1929,8 +1974,8 @@ static ssize_t h2_submit(struct stream_ctx **pstream, h2_pri_spec(data, &pri_spec); - DEBUGF(LOG_CF(data, cf, "send request allowed %d (easy handle %p)", - nghttp2_session_check_request_allowed(ctx->h2), (void *)data)); + DEBUGF(LOG_CF(data, cf, "send request allowed %d", + nghttp2_session_check_request_allowed(ctx->h2))); switch(data->state.httpreq) { case HTTPREQ_POST: @@ -1966,9 +2011,35 @@ static ssize_t h2_submit(struct stream_ctx **pstream, DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) submit %s", stream_id, len, data->state.url)); - infof(data, "Using Stream ID: %u (easy handle %p)", - stream_id, (void *)data); + infof(data, "Using Stream ID: %u", stream_id); stream->id = stream_id; + stream->local_window_size = H2_STREAM_WINDOW_SIZE; + if(data->set.max_recv_speed) { + /* We are asked to only receive `max_recv_speed` bytes per second. + * Let's limit our stream window size around that, otherwise the server + * will send in large bursts only. We make the window 50% larger to + * allow for data in flight and avoid stalling. */ + curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1); + n += CURLMAX((n/2), 1); + if(n < (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) && + n < (UINT_MAX / H2_CHUNK_SIZE)) { + stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE; + } + } + + body = (const char *)buf + nwritten; + bodylen = len - nwritten; + + if(bodylen) { + /* We have request body to send in DATA frame */ + ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err); + if(n < 0) { + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + nwritten += n; + } out: DEBUGF(LOG_CF(data, cf, "[h2sid=%d] submit -> %zd, %d", @@ -1982,17 +2053,13 @@ out: static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { - /* - * Currently, we send request in this function, but this function is also - * used to send request body. It would be nice to add dedicated function for - * request. - */ struct cf_h2_ctx *ctx = cf->ctx; struct stream_ctx *stream = H2_STREAM_CTX(data); struct cf_call_data save; int rv; ssize_t nwritten; CURLcode result; + int blocked = 0; CF_DATA_SAVE(save, cf, data); @@ -2007,18 +2074,35 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, nwritten = http2_handle_stream_close(cf, data, stream, err); goto out; } - /* If stream_id != -1, we have dispatched request HEADERS, and now - are going to send or sending request body in DATA frame */ - nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); - if(nwritten < 0) { - if(*err != CURLE_AGAIN) + else if(stream->upload_blocked_len) { + /* the data in `buf` has alread been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happend. We are not prepared to handle that. */ + failf(data, "HTTP/2 send again with decreased length"); + *err = CURLE_HTTP2; + nwritten = -1; goto out; - nwritten = 0; + } + nwritten = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + } + else { + /* If stream_id != -1, we have dispatched request HEADERS and + * optionally request body, and now are going to send or sending + * more request body in DATA frame */ + nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); + if(nwritten < 0) { + if(*err != CURLE_AGAIN) + goto out; + nwritten = 0; + } } - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] bufq_write(len=%zu) -> %zd, %d", - stream->id, len, nwritten, *err)); if(!Curl_bufq_is_empty(&stream->sendbuf)) { + /* req body data is buffered, resume the potentially suspended stream */ rv = nghttp2_session_resume_data(ctx->h2, stream->id); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; @@ -2026,104 +2110,99 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; } } - - result = h2_progress_ingress(cf, data); - if(result) { - *err = result; - nwritten = -1; - goto out; - } - - result = h2_progress_egress(cf, data); - if(result) { - *err = result; - nwritten = -1; - goto out; - } - - if(should_close_session(ctx)) { - if(stream->closed) { - nwritten = http2_handle_stream_close(cf, data, stream, err); - } - else { - DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); - *err = CURLE_HTTP2; - nwritten = -1; - } - goto out; - } - - if(!nwritten) { - size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2, - stream->id); - DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send: win %u/%zu", - stream->id, - nghttp2_session_get_remote_window_size(ctx->h2), rwin)); - if(rwin == 0) { - /* We cannot upload more as the stream's remote window size - * is 0. We need to receive WIN_UPDATEs before we can continue. - */ - data->req.keepon |= KEEP_SEND_HOLD; - DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow " - "window is exhausted", stream->id)); - } - nwritten = -1; - *err = CURLE_AGAIN; - } - /* handled writing BODY for open stream. */ - goto out; } else { nwritten = h2_submit(&stream, cf, data, buf, len, err); if(nwritten < 0) { goto out; } + DEBUGASSERT(stream); + } - result = h2_progress_ingress(cf, data); - if(result) { - *err = result; - nwritten = -1; - goto out; + /* Call the nghttp2 send loop and flush to write ALL buffered data, + * headers and/or request body completely out to the network */ + result = h2_progress_egress(cf, data); + /* if the stream has been closed in egress handling (nghttp2 does that + * when it does not like the headers, for example */ + if(stream && stream->closed) { + nwritten = http2_handle_stream_close(cf, data, stream, err); + goto out; + } + else if(result == CURLE_AGAIN) { + blocked = 1; + } + else if(result) { + *err = result; + nwritten = -1; + goto out; + } + else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) { + /* although we wrote everything that nghttp2 wants to send now, + * there is data left in our stream send buffer unwritten. This may + * be due to the stream's HTTP/2 flow window being exhausted. */ + blocked = 1; + } + + if(stream && blocked) { + /* Unable to send all data, due to connection blocked or H2 window + * exhaustion. Data is left in our stream buffer, or nghttp2's internal + * frame buffer or our network out buffer. */ + size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2, + stream->id); + if(rwin == 0) { + /* H2 flow window exhaustion. We need to HOLD upload until we get + * a WINDOW_UPDATE from the server. */ + data->req.keepon |= KEEP_SEND_HOLD; + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow " + "window is exhausted", stream->id)); + } + + /* Whatever the cause, we need to return CURL_EAGAIN for this call. + * We have unwritten state that needs us being invoked again and EAGAIN + * is the only way to ensure that. */ + stream->upload_blocked_len = nwritten; + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) BLOCK: win %u/%zu " + "blocked_len=%zu", + stream->id, len, + nghttp2_session_get_remote_window_size(ctx->h2), rwin, + nwritten)); + *err = CURLE_AGAIN; + nwritten = -1; + goto out; + } + else if(should_close_session(ctx)) { + /* nghttp2 thinks this session is done. If the stream has not been + * closed, this is an error state for out transfer */ + if(stream->closed) { + nwritten = http2_handle_stream_close(cf, data, stream, err); } - - result = h2_progress_egress(cf, data); - if(result) { - *err = result; + else { + DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); + *err = CURLE_HTTP2; nwritten = -1; - goto out; - } - - if(should_close_session(ctx)) { - if(stream->closed) { - nwritten = http2_handle_stream_close(cf, data, stream, err); - } - else { - DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); - *err = CURLE_HTTP2; - nwritten = -1; - } - goto out; } } out: if(stream) { DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, " - "buffered=%zu, upload_left=%zu, stream-window=%d, " - "connection-window=%d", + "upload_left=%" CURL_FORMAT_CURL_OFF_T ", " + "h2 windows %d-%d (stream-conn), " + "buffers %zu-%zu (stream-conn)", stream->id, len, nwritten, *err, - Curl_bufq_len(&stream->sendbuf), (ssize_t)stream->upload_left, nghttp2_session_get_stream_remote_window_size( ctx->h2, stream->id), - nghttp2_session_get_remote_window_size(ctx->h2))); - drain_stream(cf, data, stream); + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&stream->sendbuf), + Curl_bufq_len(&ctx->outbufq))); } else { DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, " - "connection-window=%d", + "connection-window=%d, nw_send_buffer(%zu)", len, nwritten, *err, - nghttp2_session_get_remote_window_size(ctx->h2))); + nghttp2_session_get_remote_window_size(ctx->h2), + Curl_bufq_len(&ctx->outbufq))); } CF_DATA_RESTORE(cf, save); return nwritten; @@ -2241,8 +2320,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf, DEBUGASSERT(data); if(ctx && ctx->h2 && stream) { - uint32_t window = !pause * H2_STREAM_WINDOW_SIZE; - CURLcode result; + uint32_t window = pause? 0 : stream->local_window_size; int rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, @@ -2257,10 +2335,8 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf, if(!pause) drain_stream(cf, data, stream); - /* make sure the window update gets sent */ - result = h2_progress_egress(cf, data); - if(result) - return result; + /* attempt to send the window update */ + (void)h2_progress_egress(cf, data); if(!pause) { /* Unpausing a h2 transfer, requires it to be run again. The server @@ -2510,7 +2586,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data, CURLcode result; DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex)); - DEBUGF(infof(data, DMSGI(data, sockindex, "switching to HTTP/2"))); + DEBUGF(infof(data, "switching to HTTP/2")); result = http2_cfilter_add(&cf, data, conn, sockindex); if(result) @@ -2569,7 +2645,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, CURLcode result; DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex)); - DEBUGF(infof(data, DMSGI(data, sockindex, "upgrading to HTTP/2"))); + DEBUGF(infof(data, "upgrading to HTTP/2")); DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); result = http2_cfilter_add(&cf, data, conn, sockindex); diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index add376b..4fd998a 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -71,7 +71,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "connect")); connect_sub: - result = cf->next->cft->connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); if(result || !*done) return result; @@ -181,7 +181,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf, ctx->cf_protocol = NULL; } if(cf->next) - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); } diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index ed197c9..045fe24 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -385,11 +385,11 @@ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out) /*********************************************************************** * - * state() + * imap_state() * * This is the ONLY way to change IMAP state! */ -static void state(struct Curl_easy *data, imapstate newstate) +static void imap_state(struct Curl_easy *data, imapstate newstate) { struct imap_conn *imapc = &data->conn->proto.imapc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -441,7 +441,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data, result = imap_sendf(data, "CAPABILITY"); if(!result) - state(data, IMAP_CAPABILITY); + imap_state(data, IMAP_CAPABILITY); return result; } @@ -458,7 +458,7 @@ static CURLcode imap_perform_starttls(struct Curl_easy *data) CURLcode result = imap_sendf(data, "STARTTLS"); if(!result) - state(data, IMAP_STARTTLS); + imap_state(data, IMAP_STARTTLS); return result; } @@ -487,7 +487,7 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data, if(!result) { imapc->ssldone = ssldone; if(imapc->state != IMAP_UPGRADETLS) - state(data, IMAP_UPGRADETLS); + imap_state(data, IMAP_UPGRADETLS); if(imapc->ssldone) { imap_to_imaps(conn); @@ -514,7 +514,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data, /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!data->state.aptr.user) { - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -531,7 +531,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data, free(passwd); if(!result) - state(data, IMAP_LOGIN); + imap_state(data, IMAP_LOGIN); return result; } @@ -615,7 +615,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data, with and end the connect phase if we don't */ if(imapc->preauth || !Curl_sasl_can_authenticate(&imapc->sasl, data)) { - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -624,7 +624,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data, if(!result) { if(progress == SASL_INPROGRESS) - state(data, IMAP_AUTHENTICATE); + imap_state(data, IMAP_AUTHENTICATE); else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = imap_perform_login(data, conn); @@ -667,7 +667,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data) } if(!result) - state(data, IMAP_LIST); + imap_state(data, IMAP_LIST); return result; } @@ -707,7 +707,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data) free(mailbox); if(!result) - state(data, IMAP_SELECT); + imap_state(data, IMAP_SELECT); return result; } @@ -749,7 +749,7 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data) return CURLE_URL_MALFORMAT; } if(!result) - state(data, IMAP_FETCH); + imap_state(data, IMAP_FETCH); return result; } @@ -820,7 +820,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data) free(mailbox); if(!result) - state(data, IMAP_APPEND); + imap_state(data, IMAP_APPEND); return result; } @@ -846,7 +846,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data) result = imap_sendf(data, "SEARCH %s", imap->query); if(!result) - state(data, IMAP_SEARCH); + imap_state(data, IMAP_SEARCH); return result; } @@ -863,7 +863,7 @@ static CURLcode imap_perform_logout(struct Curl_easy *data) CURLcode result = imap_sendf(data, "LOGOUT"); if(!result) - state(data, IMAP_LOGOUT); + imap_state(data, IMAP_LOGOUT); return result; } @@ -1017,7 +1017,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data, if(!result) switch(progress) { case SASL_DONE: - state(data, IMAP_STOP); /* Authenticated */ + imap_state(data, IMAP_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) @@ -1049,7 +1049,7 @@ static CURLcode imap_state_login_resp(struct Curl_easy *data, } else /* End of connect phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -1075,7 +1075,7 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data, result = CURLE_QUOTE_ERROR; else /* End of DO phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -1143,7 +1143,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, if(imapcode != '*') { Curl_pgrsSetDownloadSize(data, -1); - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return CURLE_REMOTE_FILE_NOT_FOUND; } @@ -1178,7 +1178,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, if(!chunk) { /* no size, we're done with the data */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return CURLE_OK; } result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk); @@ -1224,7 +1224,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, } /* End of DO phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -1242,7 +1242,7 @@ static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data, result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -1265,7 +1265,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode, Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* End of DO phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); } return result; @@ -1284,7 +1284,7 @@ static CURLcode imap_state_append_final_resp(struct Curl_easy *data, result = CURLE_UPLOAD_FAILED; else /* End of DONE phase */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); return result; } @@ -1372,7 +1372,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data, /* fallthrough, just stop! */ default: /* internal error */ - state(data, IMAP_STOP); + imap_state(data, IMAP_STOP); break; } } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp)); @@ -1475,7 +1475,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) return result; /* Start off waiting for the server greeting response */ - state(data, IMAP_SERVERGREET); + imap_state(data, IMAP_SERVERGREET); /* Start off with an response id of '*' */ strcpy(imapc->resptag, "*"); @@ -1516,12 +1516,12 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status, /* Handle responses after FETCH or APPEND transfer has finished */ if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE) - state(data, IMAP_FETCH_FINAL); + imap_state(data, IMAP_FETCH_FINAL); else { /* End the APPEND command first by sending an empty line */ result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", ""); if(!result) - state(data, IMAP_APPEND_FINAL); + imap_state(data, IMAP_APPEND_FINAL); } /* Run the state-machine */ @@ -1777,7 +1777,7 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) /* Calculate the tag based on the connection ID and command ID */ msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", - 'A' + curlx_sltosi(data->conn->connection_id % 26), + 'A' + curlx_sltosi((long)(data->conn->connection_id % 26)), ++imapc->cmdid); /* start with a blank buffer */ @@ -1925,6 +1925,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; const char *ptr = conn->options; + bool prefer_login = false; while(!result && ptr && *ptr) { const char *key = ptr; @@ -1938,26 +1939,39 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strncasecompare(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=+LOGIN", 11)) { + /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */ + prefer_login = true; + imapc->sasl.prefmech = SASL_AUTH_NONE; + } + else if(strncasecompare(key, "AUTH=", 5)) { + prefer_login = false; result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); - else + } + else { + prefer_login = false; result = CURLE_URL_MALFORMAT; + } if(*ptr == ';') ptr++; } - switch(imapc->sasl.prefmech) { - case SASL_AUTH_NONE: - imapc->preftype = IMAP_TYPE_NONE; - break; - case SASL_AUTH_DEFAULT: - imapc->preftype = IMAP_TYPE_ANY; - break; - default: - imapc->preftype = IMAP_TYPE_SASL; - break; + if(prefer_login) + imapc->preftype = IMAP_TYPE_CLEARTEXT; + else { + switch(imapc->sasl.prefmech) { + case SASL_AUTH_NONE: + imapc->preftype = IMAP_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + imapc->preftype = IMAP_TYPE_ANY; + break; + default: + imapc->preftype = IMAP_TYPE_SASL; + break; + } } return result; diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c index a71779a..c2ba815 100644 --- a/Utilities/cmcurl/lib/krb5.c +++ b/Utilities/cmcurl/lib/krb5.c @@ -261,7 +261,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) } /* We pass NULL as |output_name_type| to avoid a leak. */ gss_display_name(&min, gssname, &output_buffer, NULL); - infof(data, "Trying against %s", output_buffer.value); + infof(data, "Trying against %s", (char *)output_buffer.value); gssresp = GSS_C_NO_BUFFER; *context = GSS_C_NO_CONTEXT; diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index 4c88b0a..6b30ffb 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -50,6 +50,14 @@ #endif #ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4201) +# endif +# include <subauth.h> /* for [P]UNICODE_STRING */ +# ifdef _MSC_VER +# pragma warning(pop) +# endif # include <winldap.h> # ifndef LDAP_VENDOR_NAME # error Your Platform SDK is NOT sufficient for LDAP support! \ diff --git a/Utilities/cmcurl/lib/macos.c b/Utilities/cmcurl/lib/macos.c new file mode 100644 index 0000000..5fe4e0b --- /dev/null +++ b/Utilities/cmcurl/lib/macos.c @@ -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" + +#if defined(__APPLE__) + +#if !defined(TARGET_OS_OSX) || TARGET_OS_OSX + +#include <curl/curl.h> + +#include "macos.h" + +#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES) +#include <SystemConfiguration/SCDynamicStoreCopySpecific.h> +#endif + +CURLcode Curl_macos_init(void) +{ +#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES) + { + /* + * The automagic conversion from IPv4 literals to IPv6 literals only + * works if the SCDynamicStoreCopyProxies system function gets called + * first. As Curl currently doesn't support system-wide HTTP proxies, we + * therefore don't use any value this function might return. + * + * This function is only available on a macOS and is not needed for + * IPv4-only builds, hence the conditions above. + */ + CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); + if(dict) + CFRelease(dict); + } +#endif + return CURLE_OK; +} + +#endif /* TARGET_OS_OSX */ + +#endif /* __APPLE__ */ diff --git a/Utilities/cmcurl/lib/macos.h b/Utilities/cmcurl/lib/macos.h new file mode 100644 index 0000000..3388acd --- /dev/null +++ b/Utilities/cmcurl/lib/macos.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_MACOS_H +#define HEADER_CURL_MACOS_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(__APPLE__) && (!defined(TARGET_OS_OSX) || TARGET_OS_OSX) + +CURLcode Curl_macos_init(void); + +#else + +#define Curl_macos_init() CURLE_OK + +#endif + +#endif /* HEADER_CURL_MACOS_H */ diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c index 39aac8f..0a57e1e 100644 --- a/Utilities/cmcurl/lib/mime.c +++ b/Utilities/cmcurl/lib/mime.c @@ -84,7 +84,7 @@ static const struct mime_encoder encoders[] = { }; /* Base64 encoding table */ -static const char base64[] = +static const char base64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Quoted-printable character class table. @@ -469,10 +469,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, i = st->buf[st->bufbeg++] & 0xFF; i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); - *ptr++ = base64[(i >> 18) & 0x3F]; - *ptr++ = base64[(i >> 12) & 0x3F]; - *ptr++ = base64[(i >> 6) & 0x3F]; - *ptr++ = base64[i & 0x3F]; + *ptr++ = base64enc[(i >> 18) & 0x3F]; + *ptr++ = base64enc[(i >> 12) & 0x3F]; + *ptr++ = base64enc[(i >> 6) & 0x3F]; + *ptr++ = base64enc[i & 0x3F]; cursize += 4; st->pos += 4; size -= 4; @@ -496,10 +496,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; i |= (st->buf[st->bufbeg] & 0xFF) << 16; - ptr[0] = base64[(i >> 18) & 0x3F]; - ptr[1] = base64[(i >> 12) & 0x3F]; + ptr[0] = base64enc[(i >> 18) & 0x3F]; + ptr[1] = base64enc[(i >> 12) & 0x3F]; if(++st->bufbeg != st->bufend) { - ptr[2] = base64[(i >> 6) & 0x3F]; + ptr[2] = base64enc[(i >> 6) & 0x3F]; st->bufbeg++; } cursize += 4; diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c index dbe7239..799a21a 100644 --- a/Utilities/cmcurl/lib/mqtt.c +++ b/Utilities/cmcurl/lib/mqtt.c @@ -636,7 +636,7 @@ MQTT_SUBACK_COMING: /* -- switched state -- */ remlen = mq->remaining_length; - infof(data, "Remaining length: %zd bytes", remlen); + infof(data, "Remaining length: %zu bytes", remlen); if(data->set.max_filesize && (curl_off_t)remlen > data->set.max_filesize) { failf(data, "Maximum file size exceeded"); diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index d1d32b7..50bf15a 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -112,7 +112,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, static void process_pending_handles(struct Curl_multi *multi); #ifdef DEBUGBUILD -static const char * const statename[]={ +static const char * const multi_statename[]={ "INIT", "PENDING", "CONNECT", @@ -194,15 +194,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) if(data->mstate >= MSTATE_PENDING && data->mstate < MSTATE_COMPLETED) { - long connection_id = -5000; - - if(data->conn) - connection_id = data->conn->connection_id; - infof(data, - "STATE: %s => %s handle %p; line %d (connection #%ld)", - statename[oldstate], statename[data->mstate], - (void *)data, lineno, connection_id); + "STATE: %s => %s handle %p; line %d", + multi_statename[oldstate], multi_statename[data->mstate], + (void *)data, lineno); } #endif @@ -464,6 +459,20 @@ struct Curl_multi *curl_multi_init(void) CURL_DNS_HASH_SIZE); } +#ifdef DEBUGBUILD +static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data) +{ + if(!multi->warned) { + infof(data, "!!! WARNING !!!"); + infof(data, "This is a debug build of libcurl, " + "do not use in production."); + multi->warned = true; + } +} +#else +#define multi_warn_debug(x,y) Curl_nop_stmt +#endif + /* returns TRUE if the easy handle is supposed to be present in the main link list */ static bool in_main_list(struct Curl_easy *data) @@ -623,8 +632,14 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->set.server_response_timeout; data->state.conn_cache->closure_handle->set.no_signal = data->set.no_signal; + data->id = data->state.conn_cache->next_easy_id++; + if(data->state.conn_cache->next_easy_id <= 0) + data->state.conn_cache->next_easy_id = 0; CONNCACHE_UNLOCK(data); + multi_warn_debug(multi, data); + infof(data, "processing: %s", data->state.url); + return CURLM_OK; } @@ -742,6 +757,7 @@ static CURLcode multi_done(struct Curl_easy *data, but currently we have no such detail knowledge. */ + data->state.recent_conn_id = conn->connection_id; if((data->set.reuse_forbid #if defined(USE_NTLM) && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || @@ -753,8 +769,9 @@ static CURLcode multi_done(struct Curl_easy *data, #endif ) || conn->bits.close || (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) { - DEBUGF(infof(data, "multi_done, not re-using connection=%ld, forbid=%d" - ", close=%d, premature=%d, conn_multiplex=%d", + DEBUGF(infof(data, "multi_done, not re-using connection=%" + CURL_FORMAT_CURL_OFF_T ", forbid=%d" + ", close=%d, premature=%d, conn_multiplex=%d", conn->connection_id, data->set.reuse_forbid, conn->bits.close, premature, Curl_conn_is_multiplex(conn, FIRSTSOCKET))); @@ -774,15 +791,16 @@ static CURLcode multi_done(struct Curl_easy *data, conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->host.dispname; /* create string before returning the connection */ - long connection_id = conn->connection_id; + curl_off_t connection_id = conn->connection_id; msnprintf(buffer, sizeof(buffer), - "Connection #%ld to host %s left intact", + "Connection #%" CURL_FORMAT_CURL_OFF_T " to host %s left intact", connection_id, host); /* the connection is no longer in use by this transfer */ CONNCACHE_UNLOCK(data); if(Curl_conncache_return_conn(data, conn)) { /* remember the most recently used connection */ data->state.lastconnect_id = connection_id; + data->state.recent_conn_id = connection_id; infof(data, "%s", buffer); } else @@ -1895,14 +1913,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, MSTATE_COMPLETED); } -#ifdef DEBUGBUILD - if(!multi->warned) { - infof(data, "!!! WARNING !!!"); - infof(data, "This is a debug build of libcurl, " - "do not use in production."); - multi->warned = true; - } -#endif + multi_warn_debug(multi, data); do { /* A "stream" here is a logical stream if the protocol can handle that @@ -3690,7 +3701,7 @@ void Curl_expire_clear(struct Curl_easy *data) } #ifdef DEBUGBUILD - infof(data, "Expire cleared (transfer %p)", data); + infof(data, "Expire cleared"); #endif nowp->tv_sec = 0; nowp->tv_usec = 0; @@ -3798,7 +3809,7 @@ void Curl_multi_dump(struct Curl_multi *multi) /* only display handles that are not completed */ fprintf(stderr, "handle %p, state %s, %d sockets\n", (void *)data, - statename[data->mstate], data->numsocks); + multi_statename[data->mstate], data->numsocks); for(i = 0; i < data->numsocks; i++) { curl_socket_t s = data->sockets[i]; struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index 0de34cc..ddb98bf 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -282,11 +282,11 @@ static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out) /*********************************************************************** * - * state() + * pop3_state() * * This is the ONLY way to change POP3 state! */ -static void state(struct Curl_easy *data, pop3state newstate) +static void pop3_state(struct Curl_easy *data, pop3state newstate) { struct pop3_conn *pop3c = &data->conn->proto.pop3c; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -335,7 +335,7 @@ static CURLcode pop3_perform_capa(struct Curl_easy *data, result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA"); if(!result) - state(data, POP3_CAPA); + pop3_state(data, POP3_CAPA); return result; } @@ -353,7 +353,7 @@ static CURLcode pop3_perform_starttls(struct Curl_easy *data, CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS"); if(!result) - state(data, POP3_STARTTLS); + pop3_state(data, POP3_STARTTLS); return result; } @@ -383,7 +383,7 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data, if(!result) { pop3c->ssldone = ssldone; if(pop3c->state != POP3_UPGRADETLS) - state(data, POP3_UPGRADETLS); + pop3_state(data, POP3_UPGRADETLS); if(pop3c->ssldone) { pop3_to_pop3s(conn); @@ -408,7 +408,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data, /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!data->state.aptr.user) { - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -417,7 +417,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data, result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s", conn->user ? conn->user : ""); if(!result) - state(data, POP3_USER); + pop3_state(data, POP3_USER); return result; } @@ -442,7 +442,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data, /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!data->state.aptr.user) { - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -468,7 +468,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data, result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret); if(!result) - state(data, POP3_APOP); + pop3_state(data, POP3_APOP); return result; } @@ -552,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data, /* Check we have enough data to authenticate with and end the connect phase if we don't */ if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) { - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -562,7 +562,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data, if(!result) if(progress == SASL_INPROGRESS) - state(data, POP3_AUTH); + pop3_state(data, POP3_AUTH); } if(!result && progress == SASL_IDLE) { @@ -620,7 +620,7 @@ static CURLcode pop3_perform_command(struct Curl_easy *data) pop3->custom : command)); if(!result) - state(data, POP3_COMMAND); + pop3_state(data, POP3_COMMAND); return result; } @@ -638,7 +638,7 @@ static CURLcode pop3_perform_quit(struct Curl_easy *data, CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT"); if(!result) - state(data, POP3_QUIT); + pop3_state(data, POP3_QUIT); return result; } @@ -831,7 +831,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data, if(!result) switch(progress) { case SASL_DONE: - state(data, POP3_STOP); /* Authenticated */ + pop3_state(data, POP3_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ #ifndef CURL_DISABLE_CRYPTO_AUTH @@ -869,7 +869,7 @@ static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code, } else /* End of connect phase */ - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -892,7 +892,7 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code, result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s", conn->passwd ? conn->passwd : ""); if(!result) - state(data, POP3_PASS); + pop3_state(data, POP3_PASS); return result; } @@ -910,7 +910,7 @@ static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code, } else /* End of connect phase */ - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -929,7 +929,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ if(pop3code != '+') { - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return CURLE_WEIRD_SERVER_REPLY; } @@ -967,7 +967,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, } /* End of DO phase */ - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); return result; } @@ -1037,12 +1037,12 @@ static CURLcode pop3_statemachine(struct Curl_easy *data, break; case POP3_QUIT: - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); break; default: /* internal error */ - state(data, POP3_STOP); + pop3_state(data, POP3_STOP); break; } } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); @@ -1143,7 +1143,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done) return result; /* Start off waiting for the server greeting response */ - state(data, POP3_SERVERGREET); + pop3_state(data, POP3_SERVERGREET); result = pop3_multi_statemach(data, done); diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c index 81ee864..437fa74 100644 --- a/Utilities/cmcurl/lib/sendf.c +++ b/Utilities/cmcurl/lib/sendf.c @@ -419,8 +419,6 @@ CURLcode Curl_read(struct Curl_easy *data, /* transfer */ *n += nread; result = CURLE_OK; out: - /* DEBUGF(infof(data, "Curl_read(handle=%p) -> %d, nread=%ld", - data, result, nread)); */ return result; } diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c index 0c3b963..b05162a 100644 --- a/Utilities/cmcurl/lib/setopt.c +++ b/Utilities/cmcurl/lib/setopt.c @@ -1867,6 +1867,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) */ data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_HAPROXY_CLIENT_IP: + /* + * Set the client IP to send through HAProxy PROXY protocol + */ + result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], + va_arg(param, char *)); + /* We enable implicitly the HAProxy protocol if we use this flag. */ + data->set.haproxyprotocol = TRUE; + break; #endif case CURLOPT_INTERFACE: /* @@ -2711,7 +2720,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* Set the list of mail recipients */ data->set.mail_rcpt = va_arg(param, struct curl_slist *); break; - case CURLOPT_MAIL_RCPT_ALLLOWFAILS: + case CURLOPT_MAIL_RCPT_ALLOWFAILS: /* allow RCPT TO command to fail for some recipients */ data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE; break; diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c index d682221..bc4e883 100644 --- a/Utilities/cmcurl/lib/smb.c +++ b/Utilities/cmcurl/lib/smb.c @@ -27,8 +27,6 @@ #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) -#define BUILDING_CURL_SMB_C - #ifdef WIN32 #define getpid GetCurrentProcessId #endif @@ -50,6 +48,199 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Definitions for SMB protocol data structures + */ +#if defined(_MSC_VER) || defined(__ILEC400__) +# define PACK +# pragma pack(push) +# pragma pack(1) +#elif defined(__GNUC__) +# define PACK __attribute__((packed)) +#else +# define PACK +#endif + +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_READ_ANDX 0x2e +#define SMB_COM_WRITE_ANDX 0x2f +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SETUP_ANDX 0x73 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_CREATE_ANDX 0xa2 +#define SMB_COM_NO_ANDX_COMMAND 0xff + +#define SMB_WC_CLOSE 0x03 +#define SMB_WC_READ_ANDX 0x0c +#define SMB_WC_WRITE_ANDX 0x0e +#define SMB_WC_SETUP_ANDX 0x0d +#define SMB_WC_TREE_CONNECT_ANDX 0x04 +#define SMB_WC_NT_CREATE_ANDX 0x18 + +#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 +#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 +#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 +#define SMB_FLAGS2_IS_LONG_NAME 0x0040 +#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 + +#define SMB_CAP_LARGE_FILES 0x08 +#define SMB_GENERIC_WRITE 0x40000000 +#define SMB_GENERIC_READ 0x80000000 +#define SMB_FILE_SHARE_ALL 0x07 +#define SMB_FILE_OPEN 0x01 +#define SMB_FILE_OVERWRITE_IF 0x05 + +#define SMB_ERR_NOACCESS 0x00050001 + +struct smb_header { + unsigned char nbt_type; + unsigned char nbt_flags; + unsigned short nbt_length; + unsigned char magic[4]; + unsigned char command; + unsigned int status; + unsigned char flags; + unsigned short flags2; + unsigned short pid_high; + unsigned char signature[8]; + unsigned short pad; + unsigned short tid; + unsigned short pid; + unsigned short uid; + unsigned short mid; +} PACK; + +struct smb_negotiate_response { + struct smb_header h; + unsigned char word_count; + unsigned short dialect_index; + unsigned char security_mode; + unsigned short max_mpx_count; + unsigned short max_number_vcs; + unsigned int max_buffer_size; + unsigned int max_raw_size; + unsigned int session_key; + unsigned int capabilities; + unsigned int system_time_low; + unsigned int system_time_high; + unsigned short server_time_zone; + unsigned char encryption_key_length; + unsigned short byte_count; + char bytes[1]; +} PACK; + +struct andx { + unsigned char command; + unsigned char pad; + unsigned short offset; +} PACK; + +struct smb_setup { + unsigned char word_count; + struct andx andx; + unsigned short max_buffer_size; + unsigned short max_mpx_count; + unsigned short vc_number; + unsigned int session_key; + unsigned short lengths[2]; + unsigned int pad; + unsigned int capabilities; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_tree_connect { + unsigned char word_count; + struct andx andx; + unsigned short flags; + unsigned short pw_len; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create { + unsigned char word_count; + struct andx andx; + unsigned char pad; + unsigned short name_length; + unsigned int flags; + unsigned int root_fid; + unsigned int access; + curl_off_t allocation_size; + unsigned int ext_file_attributes; + unsigned int share_access; + unsigned int create_disposition; + unsigned int create_options; + unsigned int impersonation_level; + unsigned char security_flags; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create_response { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned char op_lock_level; + unsigned short fid; + unsigned int create_disposition; + + curl_off_t create_time; + curl_off_t last_access_time; + curl_off_t last_write_time; + curl_off_t last_change_time; + unsigned int ext_file_attributes; + curl_off_t allocation_size; + curl_off_t end_of_file; +} PACK; + +struct smb_read { + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned short max_bytes; + unsigned short min_bytes; + unsigned int timeout; + unsigned short remaining; + unsigned int offset_high; + unsigned short byte_count; +} PACK; + +struct smb_write { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned int timeout; + unsigned short write_mode; + unsigned short remaining; + unsigned short pad; + unsigned short data_length; + unsigned short data_offset; + unsigned int offset_high; + unsigned short byte_count; + unsigned char pad2; +} PACK; + +struct smb_close { + unsigned char word_count; + unsigned short fid; + unsigned int last_mtime; + unsigned short byte_count; +} PACK; + +struct smb_tree_disconnect { + unsigned char word_count; + unsigned short byte_count; +} PACK; + +#if defined(_MSC_VER) || defined(__ILEC400__) +# pragma pack(pop) +#endif + /* Local API functions */ static CURLcode smb_setup_connection(struct Curl_easy *data, struct connectdata *conn); diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h index c35f3e9..437f4a5 100644 --- a/Utilities/cmcurl/lib/smb.h +++ b/Utilities/cmcurl/lib/smb.h @@ -48,203 +48,6 @@ struct smb_conn { size_t got; }; -/* - * Definitions for SMB protocol data structures - */ -#ifdef BUILDING_CURL_SMB_C - -#if defined(_MSC_VER) || defined(__ILEC400__) -# define PACK -# pragma pack(push) -# pragma pack(1) -#elif defined(__GNUC__) -# define PACK __attribute__((packed)) -#else -# define PACK -#endif - -#define SMB_COM_CLOSE 0x04 -#define SMB_COM_READ_ANDX 0x2e -#define SMB_COM_WRITE_ANDX 0x2f -#define SMB_COM_TREE_DISCONNECT 0x71 -#define SMB_COM_NEGOTIATE 0x72 -#define SMB_COM_SETUP_ANDX 0x73 -#define SMB_COM_TREE_CONNECT_ANDX 0x75 -#define SMB_COM_NT_CREATE_ANDX 0xa2 -#define SMB_COM_NO_ANDX_COMMAND 0xff - -#define SMB_WC_CLOSE 0x03 -#define SMB_WC_READ_ANDX 0x0c -#define SMB_WC_WRITE_ANDX 0x0e -#define SMB_WC_SETUP_ANDX 0x0d -#define SMB_WC_TREE_CONNECT_ANDX 0x04 -#define SMB_WC_NT_CREATE_ANDX 0x18 - -#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 -#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 -#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 -#define SMB_FLAGS2_IS_LONG_NAME 0x0040 -#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 - -#define SMB_CAP_LARGE_FILES 0x08 -#define SMB_GENERIC_WRITE 0x40000000 -#define SMB_GENERIC_READ 0x80000000 -#define SMB_FILE_SHARE_ALL 0x07 -#define SMB_FILE_OPEN 0x01 -#define SMB_FILE_OVERWRITE_IF 0x05 - -#define SMB_ERR_NOACCESS 0x00050001 - -struct smb_header { - unsigned char nbt_type; - unsigned char nbt_flags; - unsigned short nbt_length; - unsigned char magic[4]; - unsigned char command; - unsigned int status; - unsigned char flags; - unsigned short flags2; - unsigned short pid_high; - unsigned char signature[8]; - unsigned short pad; - unsigned short tid; - unsigned short pid; - unsigned short uid; - unsigned short mid; -} PACK; - -struct smb_negotiate_response { - struct smb_header h; - unsigned char word_count; - unsigned short dialect_index; - unsigned char security_mode; - unsigned short max_mpx_count; - unsigned short max_number_vcs; - unsigned int max_buffer_size; - unsigned int max_raw_size; - unsigned int session_key; - unsigned int capabilities; - unsigned int system_time_low; - unsigned int system_time_high; - unsigned short server_time_zone; - unsigned char encryption_key_length; - unsigned short byte_count; - char bytes[1]; -} PACK; - -struct andx { - unsigned char command; - unsigned char pad; - unsigned short offset; -} PACK; - -struct smb_setup { - unsigned char word_count; - struct andx andx; - unsigned short max_buffer_size; - unsigned short max_mpx_count; - unsigned short vc_number; - unsigned int session_key; - unsigned short lengths[2]; - unsigned int pad; - unsigned int capabilities; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_tree_connect { - unsigned char word_count; - struct andx andx; - unsigned short flags; - unsigned short pw_len; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_nt_create { - unsigned char word_count; - struct andx andx; - unsigned char pad; - unsigned short name_length; - unsigned int flags; - unsigned int root_fid; - unsigned int access; - curl_off_t allocation_size; - unsigned int ext_file_attributes; - unsigned int share_access; - unsigned int create_disposition; - unsigned int create_options; - unsigned int impersonation_level; - unsigned char security_flags; - unsigned short byte_count; - char bytes[1024]; -} PACK; - -struct smb_nt_create_response { - struct smb_header h; - unsigned char word_count; - struct andx andx; - unsigned char op_lock_level; - unsigned short fid; - unsigned int create_disposition; - - curl_off_t create_time; - curl_off_t last_access_time; - curl_off_t last_write_time; - curl_off_t last_change_time; - unsigned int ext_file_attributes; - curl_off_t allocation_size; - curl_off_t end_of_file; -} PACK; - -struct smb_read { - unsigned char word_count; - struct andx andx; - unsigned short fid; - unsigned int offset; - unsigned short max_bytes; - unsigned short min_bytes; - unsigned int timeout; - unsigned short remaining; - unsigned int offset_high; - unsigned short byte_count; -} PACK; - -struct smb_write { - struct smb_header h; - unsigned char word_count; - struct andx andx; - unsigned short fid; - unsigned int offset; - unsigned int timeout; - unsigned short write_mode; - unsigned short remaining; - unsigned short pad; - unsigned short data_length; - unsigned short data_offset; - unsigned int offset_high; - unsigned short byte_count; - unsigned char pad2; -} PACK; - -struct smb_close { - unsigned char word_count; - unsigned short fid; - unsigned int last_mtime; - unsigned short byte_count; -} PACK; - -struct smb_tree_disconnect { - unsigned char word_count; - unsigned short byte_count; -} PACK; - -#if defined(_MSC_VER) || defined(__ILEC400__) -# pragma pack(pop) -#endif - -#endif /* BUILDING_CURL_SMB_C */ - #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ (SIZEOF_CURL_OFF_T > 4) diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index c182cac..afcdd10 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -281,11 +281,11 @@ static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out) /*********************************************************************** * - * state() + * smtp_state() * * This is the ONLY way to change SMTP state! */ -static void state(struct Curl_easy *data, smtpstate newstate) +static void smtp_state(struct Curl_easy *data, smtpstate newstate) { struct smtp_conn *smtpc = &data->conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -338,7 +338,7 @@ static CURLcode smtp_perform_ehlo(struct Curl_easy *data) result = Curl_pp_sendf(data, &smtpc->pp, "EHLO %s", smtpc->domain); if(!result) - state(data, SMTP_EHLO); + smtp_state(data, SMTP_EHLO); return result; } @@ -362,7 +362,7 @@ static CURLcode smtp_perform_helo(struct Curl_easy *data, result = Curl_pp_sendf(data, &smtpc->pp, "HELO %s", smtpc->domain); if(!result) - state(data, SMTP_HELO); + smtp_state(data, SMTP_HELO); return result; } @@ -381,7 +381,7 @@ static CURLcode smtp_perform_starttls(struct Curl_easy *data, "%s", "STARTTLS"); if(!result) - state(data, SMTP_STARTTLS); + smtp_state(data, SMTP_STARTTLS); return result; } @@ -410,7 +410,7 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data) if(!result) { smtpc->ssldone = ssldone; if(smtpc->state != SMTP_UPGRADETLS) - state(data, SMTP_UPGRADETLS); + smtp_state(data, SMTP_UPGRADETLS); if(smtpc->ssldone) { smtp_to_smtps(conn); @@ -499,7 +499,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data) server supports authentication, and end the connect phase if not */ if(!smtpc->auth_supported || !Curl_sasl_can_authenticate(&smtpc->sasl, data)) { - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); return result; } @@ -508,7 +508,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data) if(!result) { if(progress == SASL_INPROGRESS) - state(data, SMTP_AUTH); + smtp_state(data, SMTP_AUTH); else { /* Other mechanisms not supported */ infof(data, "No known authentication mechanisms supported"); @@ -586,7 +586,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data) smtp->custom : "HELP"); if(!result) - state(data, SMTP_COMMAND); + smtp_state(data, SMTP_COMMAND); return result; } @@ -771,7 +771,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data) free(size); if(!result) - state(data, SMTP_MAIL); + smtp_state(data, SMTP_MAIL); return result; } @@ -812,7 +812,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data) free(address); if(!result) - state(data, SMTP_RCPT); + smtp_state(data, SMTP_RCPT); return result; } @@ -830,7 +830,7 @@ static CURLcode smtp_perform_quit(struct Curl_easy *data, CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "QUIT"); if(!result) - state(data, SMTP_QUIT); + smtp_state(data, SMTP_QUIT); return result; } @@ -996,7 +996,7 @@ static CURLcode smtp_state_helo_resp(struct Curl_easy *data, int smtpcode, } else /* End of connect phase */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); return result; } @@ -1017,7 +1017,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data, if(!result) switch(progress) { case SASL_DONE: - state(data, SMTP_STOP); /* Authenticated */ + smtp_state(data, SMTP_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ failf(data, "Authentication cancelled"); @@ -1064,11 +1064,11 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode, } else /* End of DO phase */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); } else /* End of DO phase */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); } } @@ -1145,7 +1145,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data, result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "DATA"); if(!result) - state(data, SMTP_DATA); + smtp_state(data, SMTP_DATA); } } } @@ -1172,7 +1172,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode, Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* End of DO phase */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); } return result; @@ -1192,7 +1192,7 @@ static CURLcode smtp_state_postdata_resp(struct Curl_easy *data, result = CURLE_WEIRD_SERVER_REPLY; /* End of DONE phase */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); return result; } @@ -1274,7 +1274,7 @@ static CURLcode smtp_statemachine(struct Curl_easy *data, /* fallthrough, just stop! */ default: /* internal error */ - state(data, SMTP_STOP); + smtp_state(data, SMTP_STOP); break; } } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); @@ -1379,7 +1379,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done) return result; /* Start off waiting for the server greeting response */ - state(data, SMTP_SERVERGREET); + smtp_state(data, SMTP_SERVERGREET); result = smtp_multi_statemach(data, done); @@ -1461,7 +1461,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status, free(eob); } - state(data, SMTP_POSTDATA); + smtp_state(data, SMTP_POSTDATA); /* Run the state-machine */ result = smtp_block_statemach(data, conn, FALSE); diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index 53d798a..c492d66 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -161,7 +161,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data, enum connect_t oldstate = sx->state; #ifdef DEBUG_AND_VERBOSE /* synced with the state list in urldata.h */ - static const char * const statename[] = { + static const char * const socks_statename[] = { "INIT", "SOCKS_INIT", "SOCKS_SEND", @@ -193,7 +193,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data, #ifdef DEBUG_AND_VERBOSE infof(data, "SXSTATE: %s => %s; line %d", - statename[oldstate], statename[sx->state], + socks_statename[oldstate], socks_statename[sx->state], lineno); #endif } @@ -567,7 +567,6 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, */ struct connectdata *conn = cf->conn; unsigned char *socksreq = (unsigned char *)data->state.buffer; - char dest[256] = "unknown"; /* printable hostname:port */ int idx; CURLcode result; CURLproxycode presult; @@ -820,8 +819,8 @@ CONNECT_REQ_INIT: /* FALLTHROUGH */ CONNECT_RESOLVED: case CONNECT_RESOLVED: { + char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */ struct Curl_addrinfo *hp = NULL; - size_t destlen; if(dns) hp = dns->addr; if(!hp) { @@ -831,8 +830,6 @@ CONNECT_RESOLVED: } Curl_printable_address(hp, dest, sizeof(dest)); - destlen = strlen(dest); - msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", sx->remote_port); len = 0; socksreq[len++] = 5; /* version (SOCKS5) */ @@ -848,7 +845,8 @@ CONNECT_RESOLVED: socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; } - infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)", dest); + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); } #ifdef ENABLE_IPV6 else if(hp->ai_family == AF_INET6) { @@ -862,7 +860,8 @@ CONNECT_RESOLVED: ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; } - infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)", dest); + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); } #endif else { @@ -1115,7 +1114,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, return CURLE_OK; } - result = cf->next->cft->connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); if(result || !*done) return result; @@ -1193,7 +1192,7 @@ static void socks_proxy_cf_close(struct Curl_cfilter *cf, DEBUGASSERT(cf->next); cf->connected = FALSE; socks_proxy_cf_free(cf); - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); } static void socks_proxy_cf_destroy(struct Curl_cfilter *cf, diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index 643e43d..1d7a592 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -1534,7 +1534,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } while(keepon) { - DEBUGF(infof(data, "telnet_do(handle=%p), poll %d fds", data, poll_cnt)); + DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt)); switch(Curl_poll(pfd, poll_cnt, interval_ms)) { case -1: /* error, stop reading */ keepon = FALSE; @@ -1558,8 +1558,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) * in a clean way? Seems to be timing related, happens more * on slow debug build */ if(data->state.os_errno == ECONNRESET) { - DEBUGF(infof(data, "telnet_do(handle=%p), unexpected ECONNRESET" - " on recv", data)); + DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv")); } break; } diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c index dca1c6f..2de79be 100644 --- a/Utilities/cmcurl/lib/timeval.c +++ b/Utilities/cmcurl/lib/timeval.c @@ -58,7 +58,8 @@ struct curltime Curl_now(void) return now; } -#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) +#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \ + defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) struct curltime Curl_now(void) { @@ -87,6 +88,19 @@ struct curltime Curl_now(void) have_clock_gettime = TRUE; #endif +#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW + if( +#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ + (HAVE_BUILTIN_AVAILABLE == 1) + have_clock_gettime && +#endif + (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) { + cnow.tv_sec = tsnow.tv_sec; + cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); + } + else +#endif + if( #if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ (HAVE_BUILTIN_AVAILABLE == 1) diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index d2ff0c2..b678004 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -428,6 +428,8 @@ static CURLcode readwrite_data(struct Curl_easy *data, size_t excess = 0; /* excess bytes read */ bool readmore = FALSE; /* used by RTP to signal for more data */ int maxloops = 100; + curl_off_t max_recv = data->set.max_recv_speed? + data->set.max_recv_speed : CURL_OFF_T_MAX; char *buf = data->state.buffer; DEBUGASSERT(buf); @@ -472,7 +474,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, else { /* read nothing but since we wanted nothing we consider this an OK situation to proceed from */ - DEBUGF(infof(data, DMSG(data, "readwrite_data: we're done"))); + DEBUGF(infof(data, "readwrite_data: we're done")); nread = 0; } @@ -666,6 +668,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, } k->bytecount += nread; + max_recv -= nread; Curl_pgrsSetDownloadCounter(data, k->bytecount); @@ -749,9 +752,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, break; } - } while(data_pending(data) && maxloops--); + } while((max_recv > 0) && data_pending(data) && maxloops--); - if(maxloops <= 0) { + if(maxloops <= 0 || max_recv <= 0) { /* we mark it as read-again-please */ data->state.dselect_bits = CURL_CSELECT_IN; *comeback = TRUE; @@ -768,7 +771,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, out: if(result) - DEBUGF(infof(data, DMSG(data, "readwrite_data() -> %d"), result)); + DEBUGF(infof(data, "readwrite_data() -> %d", result)); return result; } @@ -1233,7 +1236,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE; out: if(result) - DEBUGF(infof(data, DMSG(data, "Curl_readwrite() -> %d"), result)); + DEBUGF(infof(data, "Curl_readwrite() -> %d", result)); return result; } @@ -1551,10 +1554,11 @@ CURLcode Curl_follow(struct Curl_easy *data, if((type != FOLLOW_RETRY) && (data->req.httpcode != 401) && (data->req.httpcode != 407) && - Curl_is_absolute_url(newurl, NULL, 0, FALSE)) + Curl_is_absolute_url(newurl, NULL, 0, FALSE)) { /* If this is not redirect due to a 401 or 407 response and an absolute URL: don't allow a custom port number */ disallowport = TRUE; + } DEBUGASSERT(data->state.uh); uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 0fb6268..e3e7f45 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -659,6 +659,9 @@ CURLcode Curl_open(struct Curl_easy **curl) /* most recent connection is not yet defined */ data->state.lastconnect_id = -1; + data->state.recent_conn_id = -1; + /* and not assigned an id yet */ + data->id = -1; data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ @@ -680,7 +683,7 @@ CURLcode Curl_open(struct Curl_easy **curl) static void conn_shutdown(struct Curl_easy *data) { DEBUGASSERT(data); - infof(data, "Closing connection %ld", data->conn->connection_id); + infof(data, "Closing connection"); /* possible left-overs from the async name resolvers */ Curl_resolver_cancel(data); @@ -763,7 +766,8 @@ void Curl_disconnect(struct Curl_easy *data, /* the transfer must be detached from the connection */ DEBUGASSERT(!data->conn); - DEBUGF(infof(data, "Curl_disconnect(conn #%ld, dead=%d)", + DEBUGF(infof(data, "Curl_disconnect(conn #%" + CURL_FORMAT_CURL_OFF_T ", dead=%d)", conn->connection_id, dead_connection)); /* * If this connection isn't marked to force-close, leave it open if there @@ -937,6 +941,7 @@ static bool extract_if_dead(struct connectdata *conn, else { bool input_pending; + Curl_attach_connection(data, conn); dead = !Curl_conn_is_alive(data, conn, &input_pending); if(input_pending) { /* For reuse, we want a "clean" connection state. The includes @@ -949,10 +954,12 @@ static bool extract_if_dead(struct connectdata *conn, */ dead = TRUE; } + Curl_detach_connection(data); } if(dead) { - infof(data, "Connection %ld seems to be dead", conn->connection_id); + infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead", + conn->connection_id); Curl_conncache_remove_conn(data, conn, FALSE); return TRUE; } @@ -1147,8 +1154,8 @@ ConnectionExists(struct Curl_easy *data, /* primary_ip[0] is NUL only if the resolving of the name hasn't completed yet and until then we don't re-use this connection */ if(!check->primary_ip[0]) { - infof(data, - "Connection #%ld is still name resolving, can't reuse", + infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T " is still " + "name resolving, can't reuse", check->connection_id); continue; } @@ -1158,8 +1165,8 @@ ConnectionExists(struct Curl_easy *data, if(!Curl_conn_is_connected(check, FIRSTSOCKET)) { foundPendingCandidate = TRUE; /* Don't pick a connection that hasn't connected yet */ - infof(data, "Connection #%ld isn't open enough, can't reuse", - check->connection_id); + infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T + "isn't open enough, can't reuse", check->connection_id); continue; } @@ -1335,8 +1342,8 @@ ConnectionExists(struct Curl_easy *data, if(!Curl_ssl_config_matches(&needle->ssl_config, &check->ssl_config)) { DEBUGF(infof(data, - "Connection #%ld has different SSL parameters, " - "can't reuse", + "Connection #%" CURL_FORMAT_CURL_OFF_T + " has different SSL parameters, can't reuse", check->connection_id)); continue; } @@ -1477,14 +1484,14 @@ void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn) { if(data->set.verbose) - infof(data, "Connected to %s (%s) port %u (#%ld)", + infof(data, "Connected to %s (%s) port %u", #ifndef CURL_DISABLE_PROXY conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : #endif conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->host.dispname, - conn->primary_ip, conn->port, conn->connection_id); + conn->primary_ip, conn->port); } #endif @@ -1857,7 +1864,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, * User name and password set with their own options override the * credentials possibly set in the URL. */ - if(!data->state.aptr.passwd) { + if(!data->set.str[STRING_PASSWORD]) { uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0); if(!uc) { char *decoded; @@ -3678,15 +3685,14 @@ static CURLcode create_conn(struct Curl_easy *data, *in_connect = conn; #ifndef CURL_DISABLE_PROXY - infof(data, "Re-using existing connection #%ld with %s %s", - conn->connection_id, + infof(data, "Re-using existing connection with %s %s", conn->bits.proxy?"proxy":"host", conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : conn->http_proxy.host.name ? conn->http_proxy.host.dispname : conn->host.dispname); #else - infof(data, "Re-using existing connection #%ld with host %s", - conn->connection_id, conn->host.dispname); + infof(data, "Re-using existing connection with host %s", + conn->host.dispname); #endif } else { diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c index a4530f9..e0c5476 100644 --- a/Utilities/cmcurl/lib/urlapi.c +++ b/Utilities/cmcurl/lib/urlapi.c @@ -201,7 +201,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url, size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, bool guess_scheme) { - int i; + int i = 0; DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN)); (void)buflen; /* only used in debug-builds */ if(buf) @@ -210,17 +210,18 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url)) return 0; #endif - for(i = 0; i < MAX_SCHEME_LEN; ++i) { - char s = url[i]; - if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) { - /* RFC 3986 3.1 explains: - scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - */ - } - else { - break; + if(ISALPHA(url[0])) + for(i = 1; i < MAX_SCHEME_LEN; ++i) { + char s = url[i]; + if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) { + /* RFC 3986 3.1 explains: + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ + } + else { + break; + } } - } if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) { /* If this does not guess scheme, the scheme always ends with the colon so that this also detects data: URLs etc. In guessing mode, data: could @@ -1546,7 +1547,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, } } - url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s", scheme, u->user ? u->user : "", u->password ? ":": "", @@ -1557,7 +1558,6 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, allochost ? allochost : u->host, port ? ":": "", port ? port : "", - (u->path && (u->path[0] != '/')) ? "/": "", u->path ? u->path : "/", (u->query && u->query[0]) ? "?": "", (u->query && u->query[0]) ? u->query : "", @@ -1639,8 +1639,10 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0; bool plusencode = FALSE; bool urlskipslash = FALSE; + bool leadingslash = FALSE; bool appendquery = FALSE; bool equalsencode = FALSE; + size_t nalloc; if(!u) return CURLUE_BAD_HANDLE; @@ -1693,6 +1695,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_OK; } + nalloc = strlen(part); + if(nalloc > CURL_MAX_INPUT_LENGTH) + /* excessive input length */ + return CURLUE_MALFORMED_INPUT; + switch(what) { case CURLUPART_SCHEME: { size_t plen = strlen(part); @@ -1706,13 +1713,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_UNSUPPORTED_SCHEME; storep = &u->scheme; urlencode = FALSE; /* never */ - /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ - while(plen--) { - if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.')) - s++; /* fine */ - else - return CURLUE_BAD_SCHEME; + if(ISALPHA(*s)) { + /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ + while(--plen) { + if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.')) + s++; /* fine */ + else + return CURLUE_BAD_SCHEME; + } } + else + return CURLUE_BAD_SCHEME; break; } case CURLUPART_USER: @@ -1746,6 +1757,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, break; case CURLUPART_PATH: urlskipslash = TRUE; + leadingslash = TRUE; /* enforce */ storep = &u->path; break; case CURLUPART_QUERY: @@ -1794,18 +1806,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, } DEBUGASSERT(storep); { - const char *newp = part; - size_t nalloc = strlen(part); - - if(nalloc > CURL_MAX_INPUT_LENGTH) - /* excessive input length */ - return CURLUE_MALFORMED_INPUT; + const char *newp; + struct dynbuf enc; + Curl_dyn_init(&enc, nalloc * 3 + 1 + leadingslash); + if(leadingslash && (part[0] != '/')) { + CURLcode result = Curl_dyn_addn(&enc, "/", 1); + if(result) + return CURLUE_OUT_OF_MEMORY; + } if(urlencode) { const unsigned char *i; - struct dynbuf enc; - - Curl_dyn_init(&enc, nalloc * 3 + 1); for(i = (const unsigned char *)part; *i; i++) { CURLcode result; @@ -1833,14 +1844,13 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_OUT_OF_MEMORY; } } - newp = Curl_dyn_ptr(&enc); } else { char *p; - newp = strdup(part); - if(!newp) + CURLcode result = Curl_dyn_add(&enc, part); + if(result) return CURLUE_OUT_OF_MEMORY; - p = (char *)newp; + p = Curl_dyn_ptr(&enc); while(*p) { /* make sure percent encoded are lower case */ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) && @@ -1853,6 +1863,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, p++; } } + newp = Curl_dyn_ptr(&enc); if(appendquery) { /* Append the 'newp' string onto the old query. Add a '&' separator if @@ -1861,24 +1872,24 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, size_t querylen = u->query ? strlen(u->query) : 0; bool addamperand = querylen && (u->query[querylen -1] != '&'); if(querylen) { - struct dynbuf enc; - Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + struct dynbuf qbuf; + Curl_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH); - if(Curl_dyn_addn(&enc, u->query, querylen)) /* add original query */ + if(Curl_dyn_addn(&qbuf, u->query, querylen)) /* add original query */ goto nomem; if(addamperand) { - if(Curl_dyn_addn(&enc, "&", 1)) + if(Curl_dyn_addn(&qbuf, "&", 1)) goto nomem; } - if(Curl_dyn_add(&enc, newp)) + if(Curl_dyn_add(&qbuf, newp)) goto nomem; - free((char *)newp); + Curl_dyn_free(&enc); free(*storep); - *storep = Curl_dyn_ptr(&enc); + *storep = Curl_dyn_ptr(&qbuf); return CURLUE_OK; nomem: - free((char *)newp); + Curl_dyn_free(&enc); return CURLUE_OUT_OF_MEMORY; } } @@ -1890,7 +1901,7 @@ nomem: } else { if(!n || hostname_check(u, (char *)newp, n)) { - free((char *)newp); + Curl_dyn_free(&enc); return CURLUE_BAD_HOSTNAME; } } diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index f02e665..c45913b 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -882,8 +882,8 @@ struct connectdata { #define CONN_INUSE(c) ((c)->easyq.size) /**** Fields set when inited and not modified again */ - long connection_id; /* Contains a unique number to make it easier to - track the connections in the log output */ + curl_off_t connection_id; /* Contains a unique number to make it easier to + track the connections in the log output */ /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in @@ -1294,7 +1294,9 @@ struct UrlState { /* buffers to store authentication data in, as parsed from input options */ struct curltime keeps_speed; /* for the progress meter really */ - long lastconnect_id; /* The last connection, -1 if undefined */ + curl_off_t lastconnect_id; /* The last connection, -1 if undefined */ + curl_off_t recent_conn_id; /* The most recent connection used, might no + * longer exist */ struct dynbuf headerb; /* buffer to store headers in */ char *buffer; /* download buffer */ @@ -1563,6 +1565,7 @@ enum dupstring { STRING_DNS_LOCAL_IP6, STRING_SSL_EC_CURVES, STRING_AWS_SIGV4, /* Parameters for V4 signature */ + STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */ /* -- end of null-terminated strings -- */ @@ -1902,6 +1905,13 @@ struct Curl_easy { /* First a simple identifier to easier detect if a user mix up this easy handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */ unsigned int magic; + /* once an easy handle is tied to a connection cache + a non-negative number to distinguish this transfer from + other using the same cache. For easier tracking + in log output. + This may wrap around after LONG_MAX to 0 again, so it + has no uniqueness guarantuee for very large processings. */ + curl_off_t id; /* first, two fields for the linked list of these */ struct Curl_easy *next; diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 5800ad3..f99dd38 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -300,7 +300,7 @@ char *curl_version(void) protocol line has its own #if line to make things easier on the eye. */ -static const char * const protocols[] = { +static const char * const supported_protocols[] = { #ifndef CURL_DISABLE_DICT "dict", #endif @@ -535,7 +535,7 @@ static curl_version_info_data version_info = { NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ NULL, /* zlib_version */ - protocols, + supported_protocols, NULL, /* c-ares version */ 0, /* c-ares version numerical */ NULL, /* libidn version */ diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c index 1738867..02b5334 100644 --- a/Utilities/cmcurl/lib/vquic/curl_msh3.c +++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c @@ -123,6 +123,7 @@ struct cf_msh3_ctx { }; /* How to access `call_data` from a cf_msh3 filter */ +#undef CF_CTX_CALL_DATA #define CF_CTX_CALL_DATA(cf) \ ((struct cf_msh3_ctx *)(cf)->ctx)->call_data @@ -172,7 +173,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, msh3_lock_initialize(&stream->recv_lock); Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE, H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); - DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data)); + DEBUGF(LOG_CF(data, cf, "data setup")); return CURLE_OK; } @@ -645,7 +646,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, } else { /* request is open */ - DEBUGF(LOG_CF(data, cf, "req: send %zd body bytes", len)); + DEBUGF(LOG_CF(data, cf, "req: send %zu body bytes", len)); if(len > 0xFFFFFFFF) { len = 0xFFFFFFFF; } diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c index 7627940..a430aa1 100644 --- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c +++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c @@ -33,7 +33,7 @@ #ifdef OPENSSL_IS_BORINGSSL #include <ngtcp2/ngtcp2_crypto_boringssl.h> #else -#include <ngtcp2/ngtcp2_crypto_openssl.h> +#include <ngtcp2/ngtcp2_crypto_quictls.h> #endif #include "vtls/openssl.h" #elif defined(USE_GNUTLS) @@ -165,17 +165,19 @@ struct cf_ngtcp2_ctx { }; /* How to access `call_data` from a cf_ngtcp2 filter */ +#undef CF_CTX_CALL_DATA #define CF_CTX_CALL_DATA(cf) \ ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data /** * All about the H3 internals of a stream */ -struct stream_ctx { +struct h3_stream_ctx { int64_t id; /* HTTP/3 protocol identifier */ struct bufq sendbuf; /* h3 request body */ struct bufq recvbuf; /* h3 response body */ size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */ + size_t upload_blocked_len; /* the amount written last and EGAINed */ size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */ uint64_t error3; /* HTTP/3 stream error code */ curl_off_t upload_left; /* number of request bytes left to upload */ @@ -186,18 +188,18 @@ struct stream_ctx { bool send_closed; /* stream is local closed */ }; -#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \ - ((struct HTTP *)(d)->req.p.http)->h3_ctx \ - : NULL)) -#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx -#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ - H3_STREAM_CTX(d)->id : -2) +#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \ + ((struct HTTP *)(d)->req.p.http)->h3_ctx \ + : NULL)) +#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx +#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \ + H3_STREAM_CTX(d)->id : -2) static CURLcode h3_data_setup(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); if(!data || !data->req.p.http) { failf(data, "initialization failure, transfer not http initialized"); @@ -223,13 +225,13 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, stream->recv_buf_nonflow = 0; H3_STREAM_LCTX(data) = stream; - DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data)); + DEBUGF(LOG_CF(data, cf, "data setup")); return CURLE_OK; } static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); (void)cf; if(stream) { @@ -246,10 +248,37 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) the maximum packet burst to MAX_PKT_BURST packets. */ #define MAX_PKT_BURST 10 -static CURLcode cf_process_ingress(struct Curl_cfilter *cf, - struct Curl_easy *data); -static CURLcode cf_flush_egress(struct Curl_cfilter *cf, - struct Curl_easy *data); +struct pkt_io_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + ngtcp2_tstamp ts; + size_t pkt_count; + ngtcp2_path_storage ps; +}; + +static ngtcp2_tstamp timestamp(void) +{ + struct curltime ct = Curl_now(); + return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS; +} + +static void pktx_init(struct pkt_io_ctx *pktx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + pktx->cf = cf; + pktx->data = data; + pktx->ts = timestamp(); + pktx->pkt_count = 0; + ngtcp2_path_storage_zero(&pktx->ps); +} + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx); +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx); static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, uint64_t datalen, void *user_data, void *stream_user_data); @@ -261,12 +290,6 @@ static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) return ctx->qconn; } -static ngtcp2_tstamp timestamp(void) -{ - struct curltime ct = Curl_now(); - return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS; -} - #ifdef DEBUG_NGTCP2 static void quic_printf(void *user_data, const char *fmt, ...) { @@ -300,7 +323,8 @@ static void qlog_callback(void *user_data, uint32_t flags, } static void quic_settings(struct cf_ngtcp2_ctx *ctx, - struct Curl_easy *data) + struct Curl_easy *data, + struct pkt_io_ctx *pktx) { ngtcp2_settings *s = &ctx->settings; ngtcp2_transport_params *t = &ctx->transport_params; @@ -314,7 +338,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, #endif (void)data; - s->initial_ts = timestamp(); + s->initial_ts = pktx->ts; s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT; s->max_window = 100 * ctx->max_stream_window; s->max_stream_window = ctx->max_stream_window; @@ -327,7 +351,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, t->initial_max_streams_uni = QUIC_MAX_STREAMS; t->max_idle_timeout = QUIC_IDLE_TIMEOUT; if(ctx->qlogfd != -1) { - s->qlog.write = qlog_callback; + s->qlog_write = qlog_callback; } } @@ -383,8 +407,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, goto out; } #else - if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) { - failf(data, "ngtcp2_crypto_openssl_configure_client_context failed"); + if(ngtcp2_crypto_quictls_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_quictls_configure_client_context failed"); goto out; } #endif @@ -686,7 +710,7 @@ static void report_consumed_data(struct Curl_cfilter *cf, struct Curl_easy *data, size_t consumed) { - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); struct cf_ngtcp2_ctx *ctx = cf->ctx; if(!stream) @@ -902,13 +926,13 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, return 0; } -static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level, +static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level, void *user_data) { struct Curl_cfilter *cf = user_data; (void)tconn; - if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) { + if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) { return 0; } @@ -962,6 +986,61 @@ static ngtcp2_callbacks ng_callbacks = { NULL, /* early_data_rejected */ }; +/** + * Connection maintenance like timeouts on packet ACKs etc. are done by us, not + * the OS like for TCP. POLL events on the socket therefore are not + * sufficient. + * ngtcp2 tells us when it wants to be invoked again. We handle that via + * the `Curl_expire()` mechanisms. + */ +static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct pkt_io_ctx local_pktx; + ngtcp2_tstamp expiry; + + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx->ts = timestamp(); + } + + expiry = ngtcp2_conn_get_expiry(ctx->qconn); + if(expiry != UINT64_MAX) { + if(expiry <= pktx->ts) { + CURLcode result; + int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts); + if(rv) { + failf(data, "ngtcp2_conn_handle_expiry returned error: %s", + ngtcp2_strerror(rv)); + ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0); + return CURLE_SEND_ERROR; + } + result = cf_progress_ingress(cf, data, pktx); + if(result) + return result; + result = cf_progress_egress(cf, data, pktx); + if(result) + return result; + /* ask again, things might have changed */ + expiry = ngtcp2_conn_get_expiry(ctx->qconn); + } + + if(expiry > pktx->ts) { + ngtcp2_duration timeout = expiry - pktx->ts; + if(timeout % NGTCP2_MILLISECONDS) { + timeout += NGTCP2_MILLISECONDS; + } + Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); + } + } + return CURLE_OK; +} + static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *socks) @@ -969,7 +1048,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf, struct cf_ngtcp2_ctx *ctx = cf->ctx; struct SingleRequest *k = &data->req; int rv = GETSOCK_BLANK; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); struct cf_call_data save; CF_DATA_SAVE(save, cf, data); @@ -991,15 +1070,15 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf, return rv; } -static void drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data) +static void h3_drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) { - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); unsigned char bits; (void)cf; bits = CURL_CSELECT_IN; - if(stream && !stream->send_closed && stream->upload_left) + if(stream && stream->upload_left && !stream->send_closed) bits |= CURL_CSELECT_OUT; if(data->state.dselect_bits != bits) { data->state.dselect_bits = bits; @@ -1013,7 +1092,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, { struct Curl_cfilter *cf = user_data; struct Curl_easy *data = stream_user_data; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); (void)conn; (void)stream_id; (void)app_error_code; @@ -1031,7 +1110,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, stream->reset = TRUE; stream->send_closed = TRUE; } - drain_stream(cf, data); + h3_drain_stream(cf, data); return 0; } @@ -1045,7 +1124,7 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf, const void *mem, size_t memlen, bool flow) { - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); CURLcode result = CURLE_OK; ssize_t nwritten; @@ -1085,7 +1164,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, (void)stream3_id; result = write_resp_raw(cf, data, buf, buflen, TRUE); - drain_stream(cf, data); + h3_drain_stream(cf, data); return result? -1 : 0; } @@ -1110,7 +1189,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, { struct Curl_cfilter *cf = user_data; struct Curl_easy *data = stream_user_data; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); CURLcode result = CURLE_OK; (void)conn; (void)stream_id; @@ -1130,7 +1209,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, if(stream->status_code / 100 != 1) { stream->resp_hds_complete = TRUE; } - drain_stream(cf, data); + h3_drain_stream(cf, data); return 0; } @@ -1143,7 +1222,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name); nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value); struct Curl_easy *data = stream_user_data; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); CURLcode result = CURLE_OK; (void)conn; (void)stream_id; @@ -1207,7 +1286,8 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, (void)conn; (void)stream_user_data; - rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, stream_id, app_error_code); + rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id, + app_error_code); if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1225,7 +1305,7 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id, (void)conn; (void)data; - rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, stream_id, + rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id, app_error_code); DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] reset -> %d", stream_id, rv)); if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { @@ -1249,7 +1329,8 @@ static nghttp3_callbacks ngh3_callbacks = { cb_h3_stop_sending, NULL, /* end_stream */ cb_h3_reset_stream, - NULL /* shutdown */ + NULL, /* shutdown */ + NULL /* recv_settings */ }; static int init_ngh3_conn(struct Curl_cfilter *cf) @@ -1314,7 +1395,7 @@ fail: static ssize_t recv_closed_stream(struct Curl_cfilter *cf, struct Curl_easy *data, - struct stream_ctx *stream, + struct h3_stream_ctx *stream, CURLcode *err) { ssize_t nread = -1; @@ -1364,9 +1445,10 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char *buf, size_t len, CURLcode *err) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); ssize_t nread = -1; struct cf_call_data save; + struct pkt_io_ctx pktx; (void)ctx; @@ -1377,6 +1459,8 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(ctx->h3conn); *err = CURLE_OK; + pktx_init(&pktx, cf, data); + if(!stream) { *err = CURLE_RECV_ERROR; goto out; @@ -1392,7 +1476,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, report_consumed_data(cf, data, nread); } - if(cf_process_ingress(cf, data)) { + if(cf_progress_ingress(cf, data, &pktx)) { *err = CURLE_RECV_ERROR; nread = -1; goto out; @@ -1410,7 +1494,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } if(nread > 0) { - drain_stream(cf, data); + h3_drain_stream(cf, data); } else { if(stream->closed) { @@ -1422,10 +1506,17 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } out: - if(cf_flush_egress(cf, data)) { + if(cf_progress_egress(cf, data, &pktx)) { *err = CURLE_SEND_ERROR; nread = -1; } + else { + CURLcode result2 = check_and_set_expiry(cf, data, &pktx); + if(result2) { + *err = result2; + nread = -1; + } + } DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_recv(len=%zu) -> %zd, %d", stream? stream->id : -1, len, nread, *err)); CF_DATA_RESTORE(cf, save); @@ -1438,7 +1529,7 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, { struct Curl_cfilter *cf = user_data; struct Curl_easy *data = stream_user_data; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); size_t skiplen; (void)cf; @@ -1454,10 +1545,8 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, Curl_bufq_skip(&stream->sendbuf, skiplen); stream->sendbuf_len_in_flight -= skiplen; - /* `sendbuf` *might* now have more room. If so, resume this - * possibly paused stream. And also tell our transfer engine that - * it may continue KEEP_SEND if told to PAUSE. */ - if(!Curl_bufq_is_full(&stream->sendbuf)) { + /* Everything ACKed, we resume upload processing */ + if(!stream->sendbuf_len_in_flight) { int rv = nghttp3_conn_resume_stream(conn, stream_id); if(rv) { return NGTCP2_ERR_CALLBACK_FAILURE; @@ -1465,7 +1554,7 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, if((data->req.keepon & KEEP_SEND_HOLD) && (data->req.keepon & KEEP_SEND)) { data->req.keepon &= ~KEEP_SEND_HOLD; - drain_stream(cf, data); + h3_drain_stream(cf, data); DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] unpausing acks", stream_id)); } @@ -1481,7 +1570,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, { struct Curl_cfilter *cf = user_data; struct Curl_easy *data = stream_user_data; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); ssize_t nwritten = 0; size_t nvecs = 0; (void)cf; @@ -1530,8 +1619,10 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, } DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] read req body -> " - "%d vecs%s with %zu (buffered=%zu, left=%zd)", stream->id, - (int)nvecs, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", + "%d vecs%s with %zu (buffered=%zu, left=%" + CURL_FORMAT_CURL_OFF_T ")", + stream->id, (int)nvecs, + *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", nwritten, Curl_bufq_len(&stream->sendbuf), stream->upload_left)); return (nghttp3_ssize)nvecs; @@ -1547,7 +1638,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, CURLcode *err) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = NULL; + struct h3_stream_ctx *stream = NULL; struct h1_req_parser h1; struct dynhds h2_headers; size_t nheader; @@ -1614,16 +1705,19 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, else /* data sending without specifying the data amount up front */ stream->upload_left = -1; /* unknown */ - reader.read_data = cb_h3_read_req_body; - preader = &reader; break; default: /* there is not request body */ stream->upload_left = 0; /* no request body */ - preader = NULL; break; } + stream->send_closed = (stream->upload_left == 0); + if(!stream->send_closed) { + reader.read_data = cb_h3_read_req_body; + preader = &reader; + } + rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id, nva, nheader, preader, data); if(rc) { @@ -1642,8 +1736,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, goto out; } - infof(data, "Using HTTP/3 Stream ID: %" PRId64 " (easy handle %p)", - stream->id, (void *)data); + infof(data, "Using HTTP/3 Stream ID: %" PRId64, stream->id); DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] opened for %s", stream->id, data->state.url)); @@ -1658,20 +1751,23 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); ssize_t sent = 0; struct cf_call_data save; + struct pkt_io_ctx pktx; + CURLcode result; CF_DATA_SAVE(save, cf, data); DEBUGASSERT(cf->connected); DEBUGASSERT(ctx->qconn); DEBUGASSERT(ctx->h3conn); + pktx_init(&pktx, cf, data); *err = CURLE_OK; - if(stream && stream->closed) { - *err = CURLE_HTTP3; + result = cf_progress_ingress(cf, data, &pktx); + if(result) { + *err = result; sent = -1; - goto out; } if(!stream || stream->id < 0) { @@ -1681,32 +1777,66 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; } } + else if(stream->upload_blocked_len) { + /* the data in `buf` has alread been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/3 send again with decreased length"); + *err = CURLE_HTTP3; + sent = -1; + goto out; + } + sent = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + } + else if(stream->closed) { + *err = CURLE_HTTP3; + sent = -1; + goto out; + } else { sent = Curl_bufq_write(&stream->sendbuf, buf, len, err); DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send, add to " "sendbuf(len=%zu) -> %zd, %d", stream->id, len, sent, *err)); if(sent < 0) { - if(*err == CURLE_AGAIN) { - /* Can't add more to the send buf, needs to drain first. - * Pause the sending to avoid a busy loop. */ - data->req.keepon |= KEEP_SEND_HOLD; - DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] pause send", - stream->id)); - } goto out; } (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); } - if(cf_flush_egress(cf, data)) { - *err = CURLE_SEND_ERROR; + result = cf_progress_egress(cf, data, &pktx); + if(result) { + *err = result; sent = -1; - goto out; + } + + if(stream && sent > 0 && stream->sendbuf_len_in_flight) { + /* We have unacknowledged DATA and cannot report success to our + * caller. Instead we EAGAIN and remember how much we have already + * "written" into our various internal connection buffers. + * We put the stream upload on HOLD, until this gets ACKed. */ + stream->upload_blocked_len = sent; + DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu), " + "%zu bytes in flight -> EGAIN", stream->id, len, + stream->sendbuf_len_in_flight)); + *err = CURLE_AGAIN; + sent = -1; + data->req.keepon |= KEEP_SEND_HOLD; } out: + result = check_and_set_expiry(cf, data, &pktx); + if(result) { + *err = result; + sent = -1; + } + DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu) -> %zd, %d", + stream? stream->id : -1, len, sent, *err)); CF_DATA_RESTORE(cf, save); return sent; } @@ -1763,34 +1893,27 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf, return result; } -struct recv_ctx { - struct Curl_cfilter *cf; - struct Curl_easy *data; - ngtcp2_tstamp ts; - size_t pkt_count; -}; - static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, struct sockaddr_storage *remote_addr, socklen_t remote_addrlen, int ecn, void *userp) { - struct recv_ctx *r = userp; - struct cf_ngtcp2_ctx *ctx = r->cf->ctx; + struct pkt_io_ctx *pktx = userp; + struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; ngtcp2_pkt_info pi; ngtcp2_path path; int rv; - ++r->pkt_count; + ++pktx->pkt_count; ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, ctx->q.local_addrlen); ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, remote_addrlen); pi.ecn = (uint32_t)ecn; - rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, r->ts); + rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); if(rv) { - DEBUGF(LOG_CF(r->data, r->cf, "ingress, read_pkt -> %s", + DEBUGF(LOG_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s", ngtcp2_strerror(rv))); if(!ctx->last_error.error_code) { if(rv == NGTCP2_ERR_CRYPTO) { @@ -1813,41 +1936,40 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, return CURLE_OK; } -static CURLcode cf_process_ingress(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct recv_ctx rctx; + struct pkt_io_ctx local_pktx; size_t pkts_chunk = 128, i; size_t pkts_max = 10 * pkts_chunk; - CURLcode result; + CURLcode result = CURLE_OK; - rctx.cf = cf; - rctx.data = data; - rctx.ts = timestamp(); - rctx.pkt_count = 0; + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx->ts = timestamp(); + } for(i = 0; i < pkts_max; i += pkts_chunk) { - rctx.pkt_count = 0; + pktx->pkt_count = 0; result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk, - recv_pkt, &rctx); + recv_pkt, pktx); if(result) /* error */ break; - if(rctx.pkt_count < pkts_chunk) /* got less than we could */ + if(pktx->pkt_count < pkts_chunk) /* got less than we could */ break; /* give egress a chance before we receive more */ - result = cf_flush_egress(cf, data); + result = cf_progress_egress(cf, data, pktx); + if(result) /* error */ + break; } return result; } -struct read_ctx { - struct Curl_cfilter *cf; - struct Curl_easy *data; - ngtcp2_tstamp ts; - ngtcp2_path_storage *ps; -}; - /** * Read a network packet to send from ngtcp2 into `buf`. * Return number of bytes written or -1 with *err set. @@ -1856,7 +1978,7 @@ static ssize_t read_pkt_to_send(void *userp, unsigned char *buf, size_t buflen, CURLcode *err) { - struct read_ctx *x = userp; + struct pkt_io_ctx *x = userp; struct cf_ngtcp2_ctx *ctx = x->cf->ctx; nghttp3_vec vec[16]; nghttp3_ssize veccnt; @@ -1896,7 +2018,7 @@ static ssize_t read_pkt_to_send(void *userp, flags = NGTCP2_WRITE_STREAM_FLAG_MORE | (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); - n = ngtcp2_conn_writev_stream(ctx->qconn, x->ps? &x->ps->path : NULL, + n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path, NULL, buf, buflen, &ndatalen, flags, stream_id, (const ngtcp2_vec *)vec, veccnt, x->ts); @@ -1955,28 +2077,25 @@ out: return nwritten; } -static CURLcode cf_flush_egress(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - int rv; ssize_t nread; size_t max_payload_size, path_max_payload_size, max_pktcnt; size_t pktcnt = 0; size_t gsolen = 0; /* this disables gso until we have a clue */ - ngtcp2_path_storage ps; - ngtcp2_tstamp ts = timestamp(); - ngtcp2_tstamp expiry; - ngtcp2_duration timeout; CURLcode curlcode; - struct read_ctx readx; + struct pkt_io_ctx local_pktx; - rv = ngtcp2_conn_handle_expiry(ctx->qconn, ts); - if(rv) { - failf(data, "ngtcp2_conn_handle_expiry returned error: %s", - ngtcp2_strerror(rv)); - ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0); - return CURLE_SEND_ERROR; + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx->ts = timestamp(); + ngtcp2_path_storage_zero(&pktx->ps); } curlcode = vquic_flush(cf, data, &ctx->q); @@ -1988,8 +2107,6 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, return curlcode; } - ngtcp2_path_storage_zero(&ps); - /* In UDP, there is a maximum theoretical packet paload length and * a minimum payload length that is "guarantueed" to work. * To detect if this minimum payload can be increased, ngtcp2 sends @@ -2008,15 +2125,10 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, max_pktcnt = CURLMIN(MAX_PKT_BURST, ctx->q.sendbuf.chunk_size / max_payload_size); - readx.cf = cf; - readx.data = data; - readx.ts = ts; - readx.ps = &ps; - for(;;) { /* add the next packet to send, if any, to our buffer */ nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, - read_pkt_to_send, &readx, &curlcode); + read_pkt_to_send, pktx, &curlcode); /* DEBUGF(LOG_CF(data, cf, "sip packet(maxlen=%zu) -> %zd, %d", max_payload_size, nread, curlcode)); */ if(nread < 0) { @@ -2076,21 +2188,6 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, } out: - /* non-errored exit. check when we should run again. */ - expiry = ngtcp2_conn_get_expiry(ctx->qconn); - if(expiry != UINT64_MAX) { - if(expiry <= ts) { - timeout = 0; - } - else { - timeout = expiry - ts; - if(timeout % NGTCP2_MILLISECONDS) { - timeout += NGTCP2_MILLISECONDS; - } - } - Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); - } - return CURLE_OK; } @@ -2101,7 +2198,7 @@ out: static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { - const struct stream_ctx *stream = H3_STREAM_CTX(data); + const struct h3_stream_ctx *stream = H3_STREAM_CTX(data); (void)cf; return stream && !Curl_bufq_is_empty(&stream->recvbuf); } @@ -2113,7 +2210,7 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge * the streams windows. As we do in HTTP/2. */ if(!pause) { - drain_stream(cf, data); + h3_drain_stream(cf, data); Curl_expire(data, 0, EXPIRE_RUN_NOW); } return CURLE_OK; @@ -2141,7 +2238,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, break; } case CF_CTRL_DATA_DONE_SEND: { - struct stream_ctx *stream = H3_STREAM_CTX(data); + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); if(stream && !stream->send_closed) { stream->send_closed = TRUE; stream->upload_left = Curl_bufq_len(&stream->sendbuf); @@ -2150,11 +2247,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, break; } case CF_CTRL_DATA_IDLE: - if(timestamp() >= ngtcp2_conn_get_expiry(ctx->qconn)) { - if(cf_flush_egress(cf, data)) { - result = CURLE_SEND_ERROR; - } - } + result = check_and_set_expiry(cf, data, NULL); break; default: break; @@ -2250,7 +2343,8 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) * Might be called twice for happy eyeballs. */ static CURLcode cf_connect_start(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + struct pkt_io_ctx *pktx) { struct cf_ngtcp2_ctx *ctx = cf->ctx; int rc; @@ -2294,7 +2388,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd); ctx->qlogfd = qfd; /* -1 if failure above */ - quic_settings(ctx, data); + quic_settings(ctx, data, pktx); result = vquic_ctx_init(&ctx->q); if(result) @@ -2344,6 +2438,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, CURLcode result = CURLE_OK; struct cf_call_data save; struct curltime now; + struct pkt_io_ctx pktx; if(cf->connected) { *done = TRUE; @@ -2359,6 +2454,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, *done = FALSE; now = Curl_now(); + pktx_init(&pktx, cf, data); CF_DATA_SAVE(save, cf, data); @@ -2370,19 +2466,19 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(!ctx->qconn) { ctx->started_at = now; - result = cf_connect_start(cf, data); + result = cf_connect_start(cf, data, &pktx); if(result) goto out; - result = cf_flush_egress(cf, data); + result = cf_progress_egress(cf, data, &pktx); /* we do not expect to be able to recv anything yet */ goto out; } - result = cf_process_ingress(cf, data); + result = cf_progress_ingress(cf, data, &pktx); if(result) goto out; - result = cf_flush_egress(cf, data); + result = cf_progress_egress(cf, data, &pktx); if(result) goto out; @@ -2402,7 +2498,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, out: if(result == CURLE_RECV_ERROR && ctx->qconn && - ngtcp2_conn_is_in_draining_period(ctx->qconn)) { + ngtcp2_conn_in_draining_period(ctx->qconn)) { /* When a QUIC server instance is shutting down, it may send us a * CONNECTION_CLOSE right away. Our connection then enters the DRAINING * state. @@ -2439,6 +2535,9 @@ out: r_ip, r_port, curl_easy_strerror(result)); } #endif + if(!result && ctx->qconn) { + result = check_and_set_expiry(cf, data, &pktx); + } DEBUGF(LOG_CF(data, cf, "connect -> %d, done=%d", result, *done)); CF_DATA_RESTORE(cf, save); return result; @@ -2510,13 +2609,11 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, not in use by any other transfer, there shouldn't be any data here, only "protocol frames" */ *input_pending = FALSE; - Curl_attach_connection(data, cf->conn); - if(cf_process_ingress(cf, data)) + if(cf_progress_ingress(cf, data, NULL)) alive = FALSE; else { alive = TRUE; } - Curl_detach_connection(data); } return alive; diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c index 3a4f9f9..39cc16e 100644 --- a/Utilities/cmcurl/lib/vquic/curl_quiche.c +++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c @@ -277,7 +277,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, stream->id = -1; Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); - DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data)); + DEBUGF(LOG_CF(data, cf, "data setup")); return CURLE_OK; } @@ -329,7 +329,7 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf, else { DEBUGASSERT(data->multi); for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { - if(H3_STREAM_ID(sdata) == stream3_id) { + if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) { return sdata; } } @@ -425,12 +425,8 @@ static ssize_t stream_resp_read(void *reader_ctx, *err = CURLE_OK; return nread; } - else if(nread < 0) { - *err = CURLE_AGAIN; - return -1; - } else { - *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + *err = CURLE_AGAIN; return -1; } } @@ -461,8 +457,8 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf, if(nwritten < 0 && result != CURLE_AGAIN) { DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] recv_body error %zd", stream->id, nwritten)); - failf(data, "Error %zd in HTTP/3 response body for stream[%"PRId64"]", - nwritten, stream->id); + failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]", + result, stream->id); stream->closed = TRUE; stream->reset = TRUE; stream->send_closed = TRUE; @@ -595,8 +591,13 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf, "for [h3sid=%"PRId64"] -> %d", stream? stream->id : -1, cf_ev_name(ev), stream3_id, result)); - quiche_h3_event_free(ev); - return result; + if(data == sdata) { + /* Only report this error to the caller if it is about the + * transfer we were called with. Otherwise we fail a transfer + * due to a problem in another one. */ + quiche_h3_event_free(ev); + return result; + } } quiche_h3_event_free(ev); } @@ -649,7 +650,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, } } else if((size_t)nread < pktlen) { - DEBUGF(LOG_CF(r->data, r->cf, "ingress, quiche only read %zd/%zd bytes", + DEBUGF(LOG_CF(r->data, r->cf, "ingress, quiche only read %zd/%zu bytes", nread, pktlen)); } @@ -826,7 +827,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, if(!stream) { *err = CURLE_RECV_ERROR; - goto out; + return -1; } if(!Curl_bufq_is_empty(&stream->recvbuf)) { @@ -883,8 +884,10 @@ out: } if(nread > 0) ctx->data_recvd += nread; - DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] cf_recv(total=%zd) -> %zd, %d", - stream->id, ctx->data_recvd, nread, *err)); + DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] cf_recv(total=%" + CURL_FORMAT_CURL_OFF_T ") -> %zd, %d", + stream ? stream->id : (int64_t)0, + ctx->data_recvd, nread, *err)); return nread; } @@ -909,8 +912,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, if(!stream) { *err = h3_data_setup(cf, data); if(*err) { - nwritten = -1; - goto out; + return -1; } stream = H3_STREAM_CTX(data); DEBUGASSERT(stream); @@ -995,8 +997,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, stream->closed = FALSE; stream->reset = FALSE; - infof(data, "Using HTTP/3 Stream ID: %" PRId64 " (easy handle %p)", - stream3_id, (void *)data); + infof(data, "Using HTTP/3 Stream ID: %" PRId64, stream3_id); DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] opened for %s", stream3_id, data->state.url)); @@ -1068,7 +1069,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, stream->send_closed = TRUE; DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] send body(len=%zu, " - "left=%zd) -> %zd", + "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd", stream->id, len, stream->upload_left, nwritten)); *err = CURLE_OK; } @@ -1151,10 +1152,8 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, (void)arg1; (void)arg2; switch(event) { - case CF_CTRL_DATA_SETUP: { - result = h3_data_setup(cf, data); + case CF_CTRL_DATA_SETUP: break; - } case CF_CTRL_DATA_PAUSE: result = h3_data_pause(cf, data, (arg1 != 0)); break; @@ -1343,11 +1342,6 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, } #endif - /* we do not get a setup event for the initial transfer */ - result = h3_data_setup(cf, data); - if(result) - return result; - result = cf_flush_egress(cf, data); if(result) return result; @@ -1555,13 +1549,11 @@ static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf, not in use by any other transfer, there shouldn't be any data here, only "protocol frames" */ *input_pending = FALSE; - Curl_attach_connection(data, cf->conn); if(cf_process_ingress(cf, data)) alive = FALSE; else { alive = TRUE; } - Curl_detach_connection(data); } return alive; diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c index f850029..399de0b 100644 --- a/Utilities/cmcurl/lib/vquic/vquic.c +++ b/Utilities/cmcurl/lib/vquic/vquic.c @@ -362,7 +362,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, } out: - DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d", + DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", pkts, total_nread, result)); return result; } @@ -425,7 +425,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, } out: - DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d", + DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", pkts, total_nread, result)); return result; } @@ -482,7 +482,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, } out: - DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d", + DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", pkts, total_nread, result)); return result; } diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c index 14c2784..98fce51 100644 --- a/Utilities/cmcurl/lib/vssh/libssh2.c +++ b/Utilities/cmcurl/lib/vssh/libssh2.c @@ -100,11 +100,9 @@ /* Local functions: */ static const char *sftp_libssh2_strerror(unsigned long err); -#ifdef CURL_LIBSSH2_DEBUG static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); -#endif static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data); static CURLcode ssh_connect(struct Curl_easy *data, bool *done); static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done); @@ -284,8 +282,6 @@ static CURLcode libssh2_session_error_to_CURLE(int err) return CURLE_SSH; } -#ifdef CURL_LIBSSH2_DEBUG - static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) { (void)abstract; /* arg not used */ @@ -305,8 +301,6 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free) free(ptr); } -#endif - /* * SSH State machine related code */ @@ -895,6 +889,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data) } if(found) { + int rc; infof(data, "Found host %s in %s", conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); @@ -944,9 +939,15 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data) } infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method); - result = libssh2_session_error_to_CURLE( - libssh2_session_method_pref( - sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method)); + rc = libssh2_session_method_pref(sshc->ssh_session, + LIBSSH2_METHOD_HOSTKEY, hostkey_method); + if(rc) { + char *errmsg = NULL; + int errlen; + libssh2_session_last_error(sshc->ssh_session, &errmsg, &errlen, 0); + failf(data, "libssh2: %s", errmsg); + result = libssh2_session_error_to_CURLE(rc); + } } else { infof(data, "Did not find host %s in %s", @@ -3268,13 +3269,12 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) sock = conn->sock[FIRSTSOCKET]; #endif /* CURL_LIBSSH2_DEBUG */ -#ifdef CURL_LIBSSH2_DEBUG + /* libcurl MUST to set custom memory functions so that the kbd_callback + funciton's memory allocations can be properled freed */ sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, my_libssh2_free, my_libssh2_realloc, data); -#else - sshc->ssh_session = libssh2_session_init_ex(NULL, NULL, NULL, data); -#endif + if(!sshc->ssh_session) { failf(data, "Failure initialising ssh session"); return CURLE_FAILED_INIT; diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c index 780b612..b47c231 100644 --- a/Utilities/cmcurl/lib/vssh/wolfssh.c +++ b/Utilities/cmcurl/lib/vssh/wolfssh.c @@ -277,7 +277,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, return -1; } DEBUGASSERT(rc == (int)len); - infof(data, "sent %zd bytes SFTP from offset %zd", + infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T, len, sshc->offset); sshc->offset += len; return (ssize_t)rc; diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c index 2b666ca..6ed453b 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.c +++ b/Utilities/cmcurl/lib/vtls/bearssl.c @@ -52,7 +52,7 @@ struct x509_context { int cert_num; }; -struct ssl_backend_data { +struct bearssl_ssl_backend_data { br_ssl_client_context ctx; struct x509_context x509; unsigned char buf[BR_SSL_BUFSIZE_BIDI]; @@ -574,7 +574,8 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; @@ -751,7 +752,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf, unsigned target) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; unsigned state; unsigned char *buf; size_t len; @@ -820,7 +822,8 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; CURLcode ret; DEBUGASSERT(backend); @@ -842,7 +845,8 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); CURLcode ret; @@ -889,7 +893,8 @@ static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; unsigned char *app; size_t applen; @@ -923,7 +928,8 @@ static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char *buf, size_t len, CURLcode *err) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; unsigned char *app; size_t applen; @@ -1050,10 +1056,12 @@ static bool bearssl_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct bearssl_ssl_backend_data *backend; (void)data; DEBUGASSERT(ctx && ctx->backend); - return br_ssl_engine_current_state(&ctx->backend->ctx.eng) & BR_SSL_RECVAPP; + backend = (struct bearssl_ssl_backend_data *)ctx->backend; + return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; } static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM, @@ -1101,7 +1109,8 @@ static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf, static void *bearssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); return &backend->ctx; } @@ -1109,7 +1118,8 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl, static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct bearssl_ssl_backend_data *backend = + (struct bearssl_ssl_backend_data *)connssl->backend; size_t i; DEBUGASSERT(backend); @@ -1147,7 +1157,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input, const struct Curl_ssl Curl_ssl_bearssl = { { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */ SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct bearssl_ssl_backend_data), Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 749dc91..c128293 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -103,14 +103,14 @@ #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) #define CURL_GSKPROTO_LAST 5 -struct ssl_backend_data { +struct gskit_ssl_backend_data { gsk_handle handle; int iocport; int localfd; int remotefd; }; -#define BACKEND connssl->backend +#define BACKEND ((struct gskit_ssl_backend_data *)connssl->backend) /* Supported ciphers. */ struct gskit_cipher { @@ -518,6 +518,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data, struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next); struct ssl_connect_data *connssl_next = cf_ssl_next? cf_ssl_next->ctx : NULL; + struct gskit_ssl_backend_data *backend_next; struct pollfd fds[2]; int n; int m; @@ -531,6 +532,8 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data, return 0; /* No SSL over SSL: OK. */ DEBUGASSERT(connssl_next->backend); + backend_next = (struct gskit_ssl_backend_data *)connssl_next->backend; + n = 1; fds[0].fd = BACKEND->remotefd; fds[1].fd = Curl_conn_cf_get_socket(cf, data); @@ -550,8 +553,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data, if(fds[0].revents & POLLOUT) { /* Try getting data from HTTPS proxy and pipe it upstream. */ n = 0; - i = gsk_secure_soc_read(connssl_next->backend->handle, - buf, sizeof(buf), &n); + i = gsk_secure_soc_read(backend_next->handle, buf, sizeof(buf), &n); switch(i) { case GSK_OK: if(n) { @@ -575,7 +577,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data, if(n < 0) return -1; if(n) { - i = gsk_secure_soc_write(connssl_next->backend->handle, buf, n, &m); + i = gsk_secure_soc_write(backend_next->handle, buf, n, &m); if(i != GSK_OK || n != m) return -1; ret = 1; @@ -1294,7 +1296,7 @@ const struct Curl_ssl Curl_ssl_gskit = { SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY, - sizeof(struct ssl_backend_data), + sizeof(struct gskit_ssl_backend_data), gskit_init, /* init */ gskit_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index 3d1906e..f6f1e10 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -76,7 +76,7 @@ static bool gtls_inited = FALSE; # include <gnutls/ocsp.h> -struct ssl_backend_data { +struct gtls_ssl_backend_data { struct gtls_instance gtls; }; @@ -91,7 +91,9 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen) DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); if(nwritten < 0) { - gnutls_transport_set_errno(connssl->backend->gtls.session, + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_transport_set_errno(backend->gtls.session, (CURLE_AGAIN == result)? EAGAIN : EINVAL); nwritten = -1; } @@ -109,7 +111,9 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen) DEBUGASSERT(data); nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); if(nread < 0) { - gnutls_transport_set_errno(connssl->backend->gtls.session, + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; + gnutls_transport_set_errno(backend->gtls.session, (CURLE_AGAIN == result)? EAGAIN : EINVAL); nread = -1; } @@ -212,7 +216,8 @@ static CURLcode handshake(struct Curl_cfilter *cf, bool nonblocking) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; gnutls_session_t session; curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); @@ -679,7 +684,8 @@ static CURLcode gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); long * const pverifyresult = &ssl_config->certverifyresult; @@ -1346,7 +1352,8 @@ gtls_connect_common(struct Curl_cfilter *cf, /* Finish connecting once the handshake is done */ if(ssl_connect_1 == connssl->connecting_state) { - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; gnutls_session_t session; DEBUGASSERT(backend); session = backend->gtls.session; @@ -1390,11 +1397,13 @@ static bool gtls_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct gtls_ssl_backend_data *backend; (void)data; DEBUGASSERT(ctx && ctx->backend); - if(ctx->backend->gtls.session && - 0 != gnutls_record_check_pending(ctx->backend->gtls.session)) + backend = (struct gtls_ssl_backend_data *)ctx->backend; + if(backend->gtls.session && + 0 != gnutls_record_check_pending(backend->gtls.session)) return TRUE; return FALSE; } @@ -1406,7 +1415,8 @@ static ssize_t gtls_send(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; ssize_t rc; (void)data; @@ -1428,7 +1438,8 @@ static void gtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; (void) data; DEBUGASSERT(backend); @@ -1463,7 +1474,8 @@ static int gtls_shutdown(struct Curl_cfilter *cf, { struct ssl_connect_data *connssl = cf->ctx; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; int retval = 0; DEBUGASSERT(backend); @@ -1541,7 +1553,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; ssize_t ret; (void)data; @@ -1620,7 +1633,8 @@ static bool gtls_cert_status_request(void) static void *gtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct gtls_ssl_backend_data *backend = + (struct gtls_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return backend->gtls.session; @@ -1634,7 +1648,7 @@ const struct Curl_ssl Curl_ssl_gnutls = { SSLSUPP_PINNEDPUBKEY | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct gtls_ssl_backend_data), gtls_init, /* init */ gtls_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index d95888c..8d0fa39 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -81,7 +81,7 @@ # endif #endif -struct ssl_backend_data { +struct mbed_ssl_backend_data { mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_context entropy; mbedtls_ssl_context ssl; @@ -255,7 +255,8 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); #if MBEDTLS_VERSION_NUMBER >= 0x03000000 int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3; @@ -307,7 +308,8 @@ static CURLcode mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); @@ -697,7 +699,8 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { int ret; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); const mbedtls_x509_crt *peercert; const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? @@ -860,7 +863,8 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -915,7 +919,8 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; int ret = -1; (void)data; @@ -939,7 +944,8 @@ static void mbedtls_close_all(struct Curl_easy *data) static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; char buf[32]; (void)data; @@ -968,7 +974,8 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; int ret = -1; ssize_t len = -1; @@ -1204,10 +1211,12 @@ static bool mbedtls_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct mbed_ssl_backend_data *backend; (void)data; DEBUGASSERT(ctx && ctx->backend); - return mbedtls_ssl_get_bytes_avail(&ctx->backend->ssl) != 0; + backend = (struct mbed_ssl_backend_data *)ctx->backend; + return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0; } static CURLcode mbedtls_sha256sum(const unsigned char *input, @@ -1234,7 +1243,8 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input, static void *mbedtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct mbed_ssl_backend_data *backend = + (struct mbed_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return &backend->ssl; @@ -1249,7 +1259,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = { SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct mbed_ssl_backend_data), mbedtls_init, /* init */ mbedtls_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index 5e5dbb7..322f507 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -81,7 +81,7 @@ /* enough to fit the string "PEM Token #[0|1]" */ #define SLOTSIZE 13 -struct ssl_backend_data { +struct nss_ssl_backend_data { PRFileDesc *handle; char *client_nickname; struct Curl_easy *data; @@ -489,7 +489,8 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl, const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -806,7 +807,9 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, struct Curl_cfilter *cf = (struct Curl_cfilter *)arg; struct ssl_connect_data *connssl = cf->ctx; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - struct Curl_easy *data = connssl->backend->data; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = backend->data; DEBUGASSERT(data); #ifdef SSL_ENABLE_OCSP_STAPLING @@ -851,7 +854,9 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) { struct Curl_cfilter *cf = (struct Curl_cfilter *)arg; struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->backend->data; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = backend->data; unsigned int buflenmax = 50; unsigned char buf[50]; unsigned int buflen; @@ -1055,7 +1060,9 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) { struct Curl_cfilter *cf = (struct Curl_cfilter *)arg; struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->backend->data; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = backend->data; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config; PRErrorCode err = PR_GetError(); @@ -1117,7 +1124,8 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; struct Curl_easy *data = NULL; CERTCertificate *cert; @@ -1173,7 +1181,8 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; struct Curl_easy *data = NULL; const char *nickname = NULL; static const char pem_slotname[] = "PEM Token #1"; @@ -1538,7 +1547,8 @@ static void nss_cleanup(void) static void close_one(struct ssl_connect_data *connssl) { /* before the cleanup, check whether we are using a client certificate */ - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; bool client_cert = true; DEBUGASSERT(backend); @@ -1580,7 +1590,8 @@ static void close_one(struct ssl_connect_data *connssl) static void nss_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; (void)data; DEBUGASSERT(backend); @@ -1796,7 +1807,8 @@ static CURLcode nss_fail_connect(struct Curl_cfilter *cf, CURLcode curlerr) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -1826,7 +1838,8 @@ static CURLcode nss_set_blocking(struct Curl_cfilter *cf, { struct ssl_connect_data *connssl = cf->ctx; PRSocketOptionData sock_opt; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -1849,7 +1862,8 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, PRBool ssl_cbc_random_iv; curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next); @@ -2031,14 +2045,16 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, /* Is there an SSL filter "in front" of us or are we writing directly * to the socket? */ if(connssl_next) { + struct nss_ssl_backend_data *backend_next = + (struct nss_ssl_backend_data *)connssl_next->backend; /* The filter should be connected by now, with full handshake */ - DEBUGASSERT(connssl_next->backend->handle); + DEBUGASSERT(backend_next->handle); DEBUGASSERT(ssl_connection_complete == connssl_next->state); /* We tell our NSS instance to use do IO with the 'next' NSS * instance. This NSS instance will take ownership of the next * one, including its destruction. We therefore need to `disown` * the next filter's handle, once import succeeds. */ - nspr_io = connssl_next->backend->handle; + nspr_io = backend->handle; second_layer = TRUE; } else { @@ -2077,8 +2093,11 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, PR_Close(model); /* We don't need this any more */ model = NULL; - if(connssl_next) /* steal the NSS handle we just imported successfully */ - connssl_next->backend->handle = NULL; + if(connssl_next) { /* steal the NSS handle we just imported successfully */ + struct nss_ssl_backend_data *backend_next = + (struct nss_ssl_backend_data *)connssl_next->backend; + backend_next->handle = NULL; + } /* This is the password associated with the cert that we're using */ if(ssl_config->key_passwd) { @@ -2154,7 +2173,8 @@ static CURLcode nss_do_connect(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); CURLcode result = CURLE_SSL_CONNECT_ERROR; @@ -2299,7 +2319,8 @@ static ssize_t nss_send(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; ssize_t rc; (void)data; @@ -2337,7 +2358,9 @@ static bool nss_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - PRFileDesc *fd = connssl->backend->handle->lower; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; + PRFileDesc *fd = backend->handle->lower; char buf; (void) data; @@ -2353,7 +2376,8 @@ static ssize_t nss_recv(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; ssize_t nread; (void)data; @@ -2455,7 +2479,8 @@ static bool nss_false_start(void) static void *nss_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return backend->handle; @@ -2465,9 +2490,11 @@ static bool nss_attach_data(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; - if(!connssl->backend->data) - connssl->backend->data = data; + if(!backend->data) + backend->data = data; return TRUE; } @@ -2475,9 +2502,11 @@ static void nss_detach_data(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; + struct nss_ssl_backend_data *backend = + (struct nss_ssl_backend_data *)connssl->backend; - if(connssl->backend->data == data) - connssl->backend->data = NULL; + if(backend->data == data) + backend->data = NULL; } const struct Curl_ssl Curl_ssl_nss = { @@ -2488,7 +2517,7 @@ const struct Curl_ssl Curl_ssl_nss = { SSLSUPP_PINNEDPUBKEY | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct nss_ssl_backend_data), nss_init, /* init */ nss_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index 1c6c786..e6dd398 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -296,7 +296,7 @@ typedef unsigned long sslerr_t; #define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L) #endif /* !LIBRESSL_VERSION_NUMBER */ -struct ssl_backend_data { +struct ossl_ssl_backend_data { /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; @@ -722,6 +722,8 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result = CURLE_SEND_ERROR; @@ -731,7 +733,7 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen) DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d", blen, (int)nwritten, result)); BIO_clear_retry_flags(bio); - connssl->backend->io_result = result; + backend->io_result = result; if(nwritten < 0) { if(CURLE_AGAIN == result) BIO_set_retry_write(bio); @@ -743,6 +745,8 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result = CURLE_RECV_ERROR; @@ -756,7 +760,7 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d", blen, (int)nread, result)); BIO_clear_retry_flags(bio); - connssl->backend->io_result = result; + backend->io_result = result; if(nread < 0) { if(CURLE_AGAIN == result) BIO_set_retry_read(bio); @@ -764,13 +768,13 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) /* Before returning server replies to the SSL instance, we need * to have setup the x509 store or verification will fail. */ - if(!connssl->backend->x509_store_setup) { - result = Curl_ssl_setup_x509_store(cf, data, connssl->backend->ctx); + if(!backend->x509_store_setup) { + result = Curl_ssl_setup_x509_store(cf, data, backend->ctx); if(result) { - connssl->backend->io_result = result; + backend->io_result = result; return -1; } - connssl->backend->x509_store_setup = TRUE; + backend->x509_store_setup = TRUE; } return (int)nread; @@ -1885,7 +1889,8 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data) static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; (void)data; DEBUGASSERT(backend); @@ -1931,7 +1936,8 @@ static int ossl_shutdown(struct Curl_cfilter *cf, int buffsize; int err; bool done = FALSE; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; int loop = 10; DEBUGASSERT(backend); @@ -2329,7 +2335,8 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; X509 *cert; OCSP_CERTID *id = NULL; int cert_status, crl_reason; @@ -2729,7 +2736,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, #ifdef HAS_MODERN_SET_PROTO_VER static CURLcode -set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) +ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); /* first, TLS min version... */ @@ -2826,9 +2833,9 @@ typedef long ctx_option_t; #if !defined(HAS_MODERN_SET_PROTO_VER) static CURLcode -set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, - struct Curl_cfilter *cf, - struct Curl_easy *data) +ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, + struct Curl_cfilter *cf, + struct Curl_easy *data) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); long ssl_version = conn_config->version; @@ -2841,8 +2848,10 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, #ifdef TLS1_3_VERSION { struct ssl_connect_data *connssl = cf->ctx; - DEBUGASSERT(connssl->backend); - SSL_CTX_set_max_proto_version(connssl->backend->ctx, TLS1_3_VERSION); + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; + DEBUGASSERT(backend); + SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION); *ctx_options |= SSL_OP_NO_TLSv1_2; } #else @@ -3447,7 +3456,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, const char * const ssl_cert_type = ssl_config->cert_type; const bool verifypeer = conn_config->verifypeer; char error_buffer[256]; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); DEBUGASSERT(backend); @@ -3589,9 +3599,9 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, ctx_options |= SSL_OP_NO_SSLv3; #if HAS_MODERN_SET_PROTO_VER /* 1.1.0 */ - result = set_ssl_version_min_max(cf, backend->ctx); + result = ossl_set_ssl_version_min_max(cf, backend->ctx); #else - result = set_ssl_version_min_max_legacy(&ctx_options, cf, data); + result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data); #endif if(result != CURLE_OK) return result; @@ -3820,7 +3830,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, { int err; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state @@ -3983,8 +3994,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL */ -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, - const char *pinnedpubkey) +static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, + const char *pinnedpubkey) { /* Scratch */ int len1 = 0, len2 = 0; @@ -4062,7 +4073,8 @@ static CURLcode servercert(struct Curl_cfilter *cf, char buffer[2048]; const char *ptr; BIO *mem = BIO_new(BIO_s_mem()); - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -4077,7 +4089,7 @@ static CURLcode servercert(struct Curl_cfilter *cf, if(data->set.ssl.certinfo) /* asked to gather certificate info */ - (void)Curl_ossl_certchain(data, connssl->backend->handle); + (void)Curl_ossl_certchain(data, backend->handle); backend->server_cert = SSL_get1_peer_certificate(backend->handle); if(!backend->server_cert) { @@ -4245,7 +4257,7 @@ static CURLcode servercert(struct Curl_cfilter *cf, data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(!result && ptr) { - result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr); + result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key"); } @@ -4414,11 +4426,13 @@ static CURLcode ossl_connect(struct Curl_cfilter *cf, static bool ossl_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { - struct ssl_connect_data *ctx = cf->ctx; + struct ssl_connect_data *connssl = cf->ctx; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; (void)data; - DEBUGASSERT(ctx && ctx->backend); - if(ctx->backend->handle && SSL_pending(ctx->backend->handle)) + DEBUGASSERT(connssl && backend); + if(backend->handle && SSL_pending(backend->handle)) return TRUE; return FALSE; } @@ -4437,7 +4451,8 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, int memlen; int rc; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; (void)data; DEBUGASSERT(backend); @@ -4533,7 +4548,8 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf, int buffsize; struct connectdata *conn = cf->conn; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; (void)data; DEBUGASSERT(backend); @@ -4756,7 +4772,8 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl, CURLINFO info) { /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ - struct ssl_backend_data *backend = connssl->backend; + struct ossl_ssl_backend_data *backend = + (struct ossl_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); return info == CURLINFO_TLS_SESSION ? (void *)backend->ctx : (void *)backend->handle; @@ -4789,7 +4806,7 @@ const struct Curl_ssl Curl_ssl_openssl = { #endif SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct ossl_ssl_backend_data), ossl_init, /* init */ ossl_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c index 097c58c..76d3e24 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.c +++ b/Utilities/cmcurl/lib/vtls/rustls.c @@ -40,7 +40,7 @@ #include "strerror.h" #include "multiif.h" -struct ssl_backend_data +struct rustls_ssl_backend_data { const struct rustls_client_config *config; struct rustls_connection *conn; @@ -67,10 +67,12 @@ static bool cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct rustls_ssl_backend_data *backend; (void)data; DEBUGASSERT(ctx && ctx->backend); - return ctx->backend->data_pending; + backend = (struct rustls_ssl_backend_data *)ctx->backend; + return backend->data_pending; } static CURLcode @@ -136,7 +138,8 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, struct Curl_easy *data, CURLcode *err) { struct ssl_connect_data *const connssl = cf->ctx; - struct ssl_backend_data *const backend = connssl->backend; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; struct io_ctx io_ctx; size_t tls_bytes_read = 0; rustls_io_result io_error; @@ -191,7 +194,8 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char *plainbuf, size_t plainlen, CURLcode *err) { struct ssl_connect_data *const connssl = cf->ctx; - struct ssl_backend_data *const backend = connssl->backend; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; size_t n = 0; size_t plain_bytes_copied = 0; @@ -283,7 +287,8 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *plainbuf, size_t plainlen, CURLcode *err) { struct ssl_connect_data *const connssl = cf->ctx; - struct ssl_backend_data *const backend = connssl->backend; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; struct io_ctx io_ctx; size_t plainwritten = 0; @@ -373,7 +378,7 @@ cr_hostname_is_ip(const char *hostname) static CURLcode cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, - struct ssl_backend_data *const backend) + struct rustls_ssl_backend_data *const backend) { struct ssl_connect_data *connssl = cf->ctx; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); @@ -491,7 +496,8 @@ cr_connect_nonblocking(struct Curl_cfilter *cf, { struct ssl_connect_data *const connssl = cf->ctx; curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - struct ssl_backend_data *const backend = connssl->backend; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; CURLcode tmperr = CURLE_OK; int result; @@ -504,7 +510,8 @@ cr_connect_nonblocking(struct Curl_cfilter *cf, DEBUGASSERT(backend); if(ssl_connection_none == connssl->state) { - result = cr_init_backend(cf, data, connssl->backend); + result = cr_init_backend(cf, data, + (struct rustls_ssl_backend_data *)connssl->backend); if(result != CURLE_OK) { return result; } @@ -594,7 +601,8 @@ cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, { struct ssl_connect_data *const connssl = cf->ctx; curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - struct ssl_backend_data *const backend = connssl->backend; + struct rustls_ssl_backend_data *const backend = + (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; (void)data; @@ -617,7 +625,8 @@ static void * cr_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct rustls_ssl_backend_data *backend = + (struct rustls_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); return &backend->conn; } @@ -626,7 +635,8 @@ static void cr_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct rustls_ssl_backend_data *backend = + (struct rustls_ssl_backend_data *)connssl->backend; CURLcode tmperr = CURLE_OK; ssize_t n = 0; @@ -659,7 +669,7 @@ const struct Curl_ssl Curl_ssl_rustls = { SSLSUPP_CAINFO_BLOB | /* supports */ SSLSUPP_TLS13_CIPHERSUITES | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct rustls_ssl_backend_data), Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index 513811d..5dcf5ba 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -33,13 +33,12 @@ #ifdef USE_SCHANNEL -#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS - #ifndef USE_WINDOWS_SSPI # error "Can't compile SCHANNEL support without SSPI." #endif #include "schannel.h" +#include "schannel_int.h" #include "vtls.h" #include "vtls_int.h" #include "strcase.h" @@ -186,9 +185,9 @@ #define PKCS12_NO_PERSIST_KEY 0x00008000 #endif -static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char *pinnedpubkey); +static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *pinnedpubkey); static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, void *BufDataPtr, unsigned long BufByteSize) @@ -207,9 +206,9 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, } static CURLcode -set_ssl_version_min_max(DWORD *enabled_protocols, - struct Curl_cfilter *cf, - struct Curl_easy *data) +schannel_set_ssl_version_min_max(DWORD *enabled_protocols, + struct Curl_cfilter *cf, + struct Curl_easy *data) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); long ssl_version = conn_config->version; @@ -500,7 +499,8 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, DWORD flags = 0; DWORD enabled_protocols = 0; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)(connssl->backend); DEBUGASSERT(backend); @@ -563,7 +563,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { - result = set_ssl_version_min_max(&enabled_protocols, cf, data); + result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data); if(result != CURLE_OK) return result; break; @@ -1075,7 +1075,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { ssize_t written = -1; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); SecBuffer outbuf; @@ -1349,7 +1350,8 @@ static CURLcode schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); int i; ssize_t nread = -1, written = -1; @@ -1607,7 +1609,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(pubkey_ptr) { - result = pkp_pin_peer_pubkey(cf, data, pubkey_ptr); + result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr); if(result) { failf(data, "SSL: public key does not match pinned public key"); return result; @@ -1686,7 +1688,8 @@ static CURLcode schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); CURLcode result = CURLE_OK; SECURITY_STATUS sspi_status = SEC_E_OK; @@ -1931,7 +1934,8 @@ schannel_connect_common(struct Curl_cfilter *cf, * Available on Windows 7 or later. */ { - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); cf->conn->sslContext = &backend->ctxt->ctxt_handle; } @@ -1960,7 +1964,8 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -2110,7 +2115,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* we want the length of the encrypted buffer to be at least large enough that it can hold all the bytes requested and some TLS record overhead. */ size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); @@ -2443,12 +2449,13 @@ static bool schannel_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { const struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; (void)data; DEBUGASSERT(backend); - if(connssl->backend->ctxt) /* SSL/TLS is in use */ + if(backend->ctxt) /* SSL/TLS is in use */ return (backend->decdata_offset > 0 || (backend->encdata_offset > 0 && !backend->encdata_is_incomplete)); else @@ -2486,12 +2493,13 @@ static int schannel_shutdown(struct Curl_cfilter *cf, * Shutting Down an Schannel Connection */ struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; DEBUGASSERT(data); DEBUGASSERT(backend); - if(connssl->backend->ctxt) { + if(backend->ctxt) { infof(data, "schannel: shutting down SSL/TLS connection with %s port %d", connssl->hostname, connssl->port); } @@ -2611,12 +2619,13 @@ static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM, return Curl_win32_random(entropy, length); } -static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char *pinnedpubkey) +static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *pinnedpubkey) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; CERT_CONTEXT *pCertContextServer = NULL; /* Result is returned to caller */ @@ -2742,7 +2751,8 @@ static CURLcode schannel_sha256sum(const unsigned char *input, static void *schannel_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return &backend->ctxt->ctxt_handle; @@ -2759,7 +2769,7 @@ const struct Curl_ssl Curl_ssl_schannel = { SSLSUPP_TLS13_CIPHERSUITES | SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct schannel_ssl_backend_data), schannel_init, /* init */ schannel_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h index 7fae39f..b8cb494 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.h +++ b/Utilities/cmcurl/lib/vtls/schannel.h @@ -28,8 +28,6 @@ #ifdef USE_SCHANNEL -#define SCHANNEL_USE_BLACKLISTS 1 - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4201) @@ -81,119 +79,5 @@ extern const struct Curl_ssl Curl_ssl_schannel; CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, struct Curl_easy *data); -/* structs to expose only in schannel.c and schannel_verify.c */ -#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS - -#ifdef __MINGW32__ -#ifdef __MINGW64_VERSION_MAJOR -#define HAS_MANUAL_VERIFY_API -#endif -#else -#ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN -#define HAS_MANUAL_VERIFY_API -#endif -#endif - -#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ - && !defined(DISABLE_SCHANNEL_CLIENT_CERT) -#define HAS_CLIENT_CERT_PATH -#endif - -#ifndef SCH_CREDENTIALS_VERSION - -#define SCH_CREDENTIALS_VERSION 0x00000005 - -typedef enum _eTlsAlgorithmUsage -{ - TlsParametersCngAlgUsageKeyExchange, - TlsParametersCngAlgUsageSignature, - TlsParametersCngAlgUsageCipher, - TlsParametersCngAlgUsageDigest, - TlsParametersCngAlgUsageCertSig -} eTlsAlgorithmUsage; - -typedef struct _CRYPTO_SETTINGS -{ - eTlsAlgorithmUsage eAlgorithmUsage; - UNICODE_STRING strCngAlgId; - DWORD cChainingModes; - PUNICODE_STRING rgstrChainingModes; - DWORD dwMinBitLength; - DWORD dwMaxBitLength; -} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; - -typedef struct _TLS_PARAMETERS -{ - DWORD cAlpnIds; - PUNICODE_STRING rgstrAlpnIds; - DWORD grbitDisabledProtocols; - DWORD cDisabledCrypto; - PCRYPTO_SETTINGS pDisabledCrypto; - DWORD dwFlags; -} TLS_PARAMETERS, * PTLS_PARAMETERS; - -typedef struct _SCH_CREDENTIALS -{ - DWORD dwVersion; - DWORD dwCredFormat; - DWORD cCreds; - PCCERT_CONTEXT* paCred; - HCERTSTORE hRootStore; - - DWORD cMappers; - struct _HMAPPER **aphMappers; - - DWORD dwSessionLifespan; - DWORD dwFlags; - DWORD cTlsParameters; - PTLS_PARAMETERS pTlsParameters; -} SCH_CREDENTIALS, * PSCH_CREDENTIALS; - -#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16 -#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16 -#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16 -#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16 - -#endif - -struct Curl_schannel_cred { - CredHandle cred_handle; - TimeStamp time_stamp; - TCHAR *sni_hostname; -#ifdef HAS_CLIENT_CERT_PATH - HCERTSTORE client_cert_store; -#endif - int refcount; -}; - -struct Curl_schannel_ctxt { - CtxtHandle ctxt_handle; - TimeStamp time_stamp; -}; - -struct ssl_backend_data { - struct Curl_schannel_cred *cred; - struct Curl_schannel_ctxt *ctxt; - SecPkgContext_StreamSizes stream_sizes; - size_t encdata_length, decdata_length; - size_t encdata_offset, decdata_offset; - unsigned char *encdata_buffer, *decdata_buffer; - /* encdata_is_incomplete: if encdata contains only a partial record that - can't be decrypted without another recv() (that is, status is - SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds - more bytes into encdata then set this back to false. */ - bool encdata_is_incomplete; - unsigned long req_flags, ret_flags; - CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ - bool recv_sspi_close_notify; /* true if connection closed by close_notify */ - bool recv_connection_closed; /* true if connection closed, regardless how */ - bool recv_renegotiating; /* true if recv is doing renegotiation */ - bool use_alpn; /* true if ALPN is used for this connection */ -#ifdef HAS_MANUAL_VERIFY_API - bool use_manual_cred_validation; /* true if manual cred validation is used */ -#endif -}; -#endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */ - #endif /* USE_SCHANNEL */ #endif /* HEADER_CURL_SCHANNEL_H */ diff --git a/Utilities/cmcurl/lib/vtls/schannel_int.h b/Utilities/cmcurl/lib/vtls/schannel_int.h new file mode 100644 index 0000000..d8b6cce --- /dev/null +++ b/Utilities/cmcurl/lib/vtls/schannel_int.h @@ -0,0 +1,142 @@ +#ifndef HEADER_CURL_SCHANNEL_INT_H +#define HEADER_CURL_SCHANNEL_INT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>, et al. + * 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_SCHANNEL + +#ifdef __MINGW32__ +#ifdef __MINGW64_VERSION_MAJOR +#define HAS_MANUAL_VERIFY_API +#endif +#else +#ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN +#define HAS_MANUAL_VERIFY_API +#endif +#endif + +#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ + && !defined(DISABLE_SCHANNEL_CLIENT_CERT) +#define HAS_CLIENT_CERT_PATH +#endif + +#ifndef SCH_CREDENTIALS_VERSION + +#define SCH_CREDENTIALS_VERSION 0x00000005 + +typedef enum _eTlsAlgorithmUsage +{ + TlsParametersCngAlgUsageKeyExchange, + TlsParametersCngAlgUsageSignature, + TlsParametersCngAlgUsageCipher, + TlsParametersCngAlgUsageDigest, + TlsParametersCngAlgUsageCertSig +} eTlsAlgorithmUsage; + +typedef struct _CRYPTO_SETTINGS +{ + eTlsAlgorithmUsage eAlgorithmUsage; + UNICODE_STRING strCngAlgId; + DWORD cChainingModes; + PUNICODE_STRING rgstrChainingModes; + DWORD dwMinBitLength; + DWORD dwMaxBitLength; +} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; + +typedef struct _TLS_PARAMETERS +{ + DWORD cAlpnIds; + PUNICODE_STRING rgstrAlpnIds; + DWORD grbitDisabledProtocols; + DWORD cDisabledCrypto; + PCRYPTO_SETTINGS pDisabledCrypto; + DWORD dwFlags; +} TLS_PARAMETERS, * PTLS_PARAMETERS; + +typedef struct _SCH_CREDENTIALS +{ + DWORD dwVersion; + DWORD dwCredFormat; + DWORD cCreds; + PCCERT_CONTEXT* paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD cTlsParameters; + PTLS_PARAMETERS pTlsParameters; +} SCH_CREDENTIALS, * PSCH_CREDENTIALS; + +#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16 +#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16 +#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16 +#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16 + +#endif /* SCH_CREDENTIALS_VERSION */ + +struct Curl_schannel_cred { + CredHandle cred_handle; + TimeStamp time_stamp; + TCHAR *sni_hostname; +#ifdef HAS_CLIENT_CERT_PATH + HCERTSTORE client_cert_store; +#endif + int refcount; +}; + +struct Curl_schannel_ctxt { + CtxtHandle ctxt_handle; + TimeStamp time_stamp; +}; + +struct schannel_ssl_backend_data { + struct Curl_schannel_cred *cred; + struct Curl_schannel_ctxt *ctxt; + SecPkgContext_StreamSizes stream_sizes; + size_t encdata_length, decdata_length; + size_t encdata_offset, decdata_offset; + unsigned char *encdata_buffer, *decdata_buffer; + /* encdata_is_incomplete: if encdata contains only a partial record that + can't be decrypted without another recv() (that is, status is + SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds + more bytes into encdata then set this back to false. */ + bool encdata_is_incomplete; + unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ + bool recv_renegotiating; /* true if recv is doing renegotiation */ + bool use_alpn; /* true if ALPN is used for this connection */ +#ifdef HAS_MANUAL_VERIFY_API + bool use_manual_cred_validation; /* true if manual cred validation is used */ +#endif +}; + +#endif /* USE_SCHANNEL */ +#endif /* HEADER_CURL_SCHANNEL_INT_H */ diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c index d75ee8d..c582ee4 100644 --- a/Utilities/cmcurl/lib/vtls/schannel_verify.c +++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c @@ -36,8 +36,8 @@ # error "Can't compile SCHANNEL support without SSPI." #endif -#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS #include "schannel.h" +#include "schannel_int.h" #ifdef HAS_MANUAL_VERIFY_API @@ -54,7 +54,7 @@ #include "curl_memory.h" #include "memdebug.h" -#define BACKEND connssl->backend +#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend) #define MAX_CAFILE_SIZE 1048576 /* 1 MiB */ #define BEGIN_CERT "-----BEGIN CERTIFICATE-----" diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index c9f02f2..32bb3a5 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -146,7 +146,7 @@ #define ioErr -36 #define paramErr -50 -struct ssl_backend_data { +struct st_ssl_backend_data { SSLContextRef ssl_ctx; bool ssl_direction; /* true if writing, false if reading */ size_t ssl_write_buffered_length; @@ -836,7 +836,8 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection, { struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result; @@ -859,6 +860,9 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection, } nread = 0; } + else if(nread == 0) { + rtn = errSSLClosedGraceful; + } else if((size_t)nread < *dataLength) { rtn = errSSLWouldBlock; } @@ -872,7 +876,8 @@ static OSStatus bio_cf_out_write(SSLConnectionRef connection, { struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result; @@ -1338,7 +1343,8 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); long ssl_version = conn_config->version; long ssl_version_max = conn_config->version_max; @@ -1633,7 +1639,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); const struct curl_blob *ssl_cablob = conn_config->ca_info_blob; @@ -2515,7 +2522,8 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); OSStatus err; SSLCipherSuite cipher; @@ -2896,7 +2904,8 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf, CURLcode result = ssl_config->certinfo ? CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; CFArrayRef server_certs = NULL; SecCertificateRef server_cert; OSStatus err; @@ -3139,7 +3148,8 @@ static CURLcode sectransp_connect(struct Curl_cfilter *cf, static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; (void) data; @@ -3166,7 +3176,8 @@ static int sectransp_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; ssize_t nread; int what; int rc; @@ -3244,7 +3255,8 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { const struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; OSStatus err; size_t buffer; @@ -3308,7 +3320,8 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; size_t processed = 0UL; OSStatus err; @@ -3376,7 +3389,8 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); size_t processed = 0UL; OSStatus err; @@ -3434,7 +3448,8 @@ again: static void *sectransp_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct st_ssl_backend_data *backend = + (struct st_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return backend->ssl_ctx; @@ -3450,7 +3465,7 @@ const struct Curl_ssl Curl_ssl_sectransp = { #endif /* SECTRANSP_PINNEDPUBKEY */ SSLSUPP_HTTPS_PROXY, - sizeof(struct ssl_backend_data), + sizeof(struct st_ssl_backend_data), Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index a4ff7d6..510bcfe 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -453,7 +453,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, } } - DEBUGF(infof(data, DMSG(data, "%s Session ID in cache for %s %s://%s:%d"), + DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d", no_match? "Didn't find": "Found", Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host", cf->conn->handler->scheme, connssl->hostname, connssl->port)); @@ -601,8 +601,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf, if(added) *added = TRUE; - DEBUGF(infof(data, DMSG(data, "Added Session ID to cache for %s://%s:%d" - " [%s]"), store->scheme, store->name, store->remote_port, + DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]", + store->scheme, store->name, store->remote_port, Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server")); return CURLE_OK; } @@ -893,8 +893,8 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { CURLcode encode; - size_t encodedlen, pinkeylen; - char *encoded, *pinkeycopy, *begin_pos, *end_pos; + size_t encodedlen = 0, pinkeylen; + char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos; unsigned char *sha256sumdigest; if(!Curl_ssl->sha256sum) { @@ -907,14 +907,12 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, if(!sha256sumdigest) return CURLE_OUT_OF_MEMORY; encode = Curl_ssl->sha256sum(pubkey, pubkeylen, - sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); + sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); - if(encode != CURLE_OK) - return encode; - - encode = Curl_base64_encode((char *)sha256sumdigest, - CURL_SHA256_DIGEST_LENGTH, &encoded, - &encodedlen); + if(!encode) + encode = Curl_base64_encode((char *)sha256sumdigest, + CURL_SHA256_DIGEST_LENGTH, &encoded, + &encodedlen); Curl_safefree(sha256sumdigest); if(encode) @@ -1506,7 +1504,7 @@ static void ssl_cf_close(struct Curl_cfilter *cf, CF_DATA_SAVE(save, cf, data); cf_close(cf, data); - cf->next->cft->close(cf->next, data); + cf->next->cft->do_close(cf->next, data); CF_DATA_RESTORE(cf, save); } @@ -1530,7 +1528,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, DEBUGASSERT(connssl); DEBUGASSERT(cf->conn->host.name); - result = cf->next->cft->connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, blocking, done); if(result || !*done) goto out; @@ -1594,6 +1592,7 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, ssize_t nread; CF_DATA_SAVE(save, cf, data); + *err = CURLE_OK; nread = Curl_ssl->recv_plain(cf, data, buf, len, err); if(nread > 0) { DEBUGASSERT((size_t)nread <= len); diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h index ed49339..fe0115c 100644 --- a/Utilities/cmcurl/lib/vtls/vtls_int.h +++ b/Utilities/cmcurl/lib/vtls/vtls_int.h @@ -73,7 +73,7 @@ struct ssl_connect_data { char *hostname; /* hostname for verification */ char *dispname; /* display version of hostname */ const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ - struct ssl_backend_data *backend; /* vtls backend specific props */ + void *backend; /* vtls backend specific props */ struct cf_call_data call_data; /* data handle used in current call */ struct curltime handshake_done; /* time when handshake finished */ int port; /* remote port at origin */ @@ -81,6 +81,7 @@ struct ssl_connect_data { }; +#undef CF_CTX_CALL_DATA #define CF_CTX_CALL_DATA(cf) \ ((struct ssl_connect_data *)(cf)->ctx)->call_data diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index 2928728..6cfc201 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/lib/vtls/wolfssl.c @@ -91,7 +91,7 @@ #undef USE_BIO_CHAIN #endif -struct ssl_backend_data { +struct wolfssl_ssl_backend_data { SSL_CTX* ctx; SSL* handle; CURLcode io_result; /* result of last BIO cfilter operation */ @@ -281,13 +281,15 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result = CURLE_OK; DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); - connssl->backend->io_result = result; + backend->io_result = result; DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d", blen, nwritten, result)); wolfSSL_BIO_clear_retry_flags(bio); @@ -300,6 +302,8 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result = CURLE_OK; @@ -310,7 +314,7 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); - connssl->backend->io_result = result; + backend->io_result = result; DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result)); wolfSSL_BIO_clear_retry_flags(bio); @@ -352,8 +356,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { char *ciphers, *curves; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); SSL_METHOD* req_method = NULL; #ifdef HAVE_LIBOQS @@ -366,6 +372,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #else #define use_sni(x) Curl_nop_stmt #endif + bool imported_ca_info_blob = false; DEBUGASSERT(backend); @@ -410,8 +417,13 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #endif break; case CURL_SSLVERSION_TLSv1_2: +#ifndef WOLFSSL_NO_TLS12 req_method = TLSv1_2_client_method(); use_sni(TRUE); +#else + failf(data, "wolfSSL does not support TLS 1.2"); + return CURLE_NOT_BUILT_IN; +#endif break; case CURL_SSLVERSION_TLSv1_3: #ifdef WOLFSSL_TLS13 @@ -494,13 +506,28 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } } } + + if(ca_info_blob) { + if(wolfSSL_CTX_load_verify_buffer( + backend->ctx, ca_info_blob->data, ca_info_blob->len, + SSL_FILETYPE_PEM + ) != SSL_SUCCESS) { + failf(data, "error importing CA certificate blob"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + imported_ca_info_blob = true; + infof(data, "successfully imported CA certificate blob"); + } + } + #ifndef NO_FILESYSTEM /* load trusted cacert */ if(conn_config->CAfile) { if(1 != SSL_CTX_load_verify_locations(backend->ctx, conn_config->CAfile, conn_config->CApath)) { - if(conn_config->verifypeer) { + if(conn_config->verifypeer && !imported_ca_info_blob) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:" " CAfile: %s CApath: %s", @@ -699,7 +726,8 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { int ret = -1; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: @@ -892,7 +920,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -950,7 +979,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; int rc; @@ -992,7 +1022,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; (void) data; @@ -1019,7 +1050,8 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; int nread; @@ -1108,11 +1140,14 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; (void)data; DEBUGASSERT(ctx && ctx->backend); - if(ctx->backend->handle) /* SSL is in use */ - return (0 != SSL_pending(ctx->backend->handle)) ? TRUE : FALSE; + + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; + if(backend->handle) /* SSL is in use */ + return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE; else return FALSE; } @@ -1126,15 +1161,17 @@ static int wolfssl_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; int retval = 0; (void)data; DEBUGASSERT(ctx && ctx->backend); - if(ctx->backend->handle) { + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; + if(backend->handle) { ERR_clear_error(); - SSL_free(ctx->backend->handle); - ctx->backend->handle = NULL; + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -1305,7 +1342,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ static void *wolfssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return backend->handle; @@ -1320,9 +1358,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = { #ifdef USE_BIO_CHAIN SSLSUPP_HTTPS_PROXY | #endif + SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX, - sizeof(struct ssl_backend_data), + sizeof(struct wolfssl_ssl_backend_data), wolfssl_init, /* init */ wolfssl_cleanup, /* cleanup */ diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c index 10c91fb..65c5ec5 100644 --- a/Utilities/cmcurl/lib/warnless.c +++ b/Utilities/cmcurl/lib/warnless.c @@ -35,10 +35,13 @@ #endif /* __INTEL_COMPILER && __unix__ */ -#define BUILDING_WARNLESS_C 1 - #include "warnless.h" +#ifdef WIN32 +#undef read +#undef write +#endif + #include <limits.h> #define CURL_MASK_UCHAR ((unsigned char)~0) @@ -376,6 +379,9 @@ ssize_t curlx_write(int fd, const void *buf, size_t count) return (ssize_t)write(fd, buf, curlx_uztoui(count)); } +/* Ensure that warnless.h continues to have an effect in "unity" builds. */ +#undef HEADER_CURL_WARNLESS_H + #endif /* WIN32 */ #if defined(__INTEL_COMPILER) && defined(__unix__) diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h index 99b2433..2a53016 100644 --- a/Utilities/cmcurl/lib/warnless.h +++ b/Utilities/cmcurl/lib/warnless.h @@ -75,12 +75,10 @@ ssize_t curlx_read(int fd, void *buf, size_t count); ssize_t curlx_write(int fd, const void *buf, size_t count); -#ifndef BUILDING_WARNLESS_C -# undef read -# define read(fd, buf, count) curlx_read(fd, buf, count) -# undef write -# define write(fd, buf, count) curlx_write(fd, buf, count) -#endif +#undef read +#define read(fd, buf, count) curlx_read(fd, buf, count) +#undef write +#define write(fd, buf, count) curlx_write(fd, buf, count) #endif /* WIN32 */ diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c index c60bbc9..3c1964b 100644 --- a/Utilities/cmcurl/lib/ws.c +++ b/Utilities/cmcurl/lib/ws.c @@ -126,8 +126,9 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data, dec->head_len, dec->head_total); } else { - infof(data, "WS-DEC: %s [%s%s payload=%zd/%zd]", msg, - ws_frame_name_of_op(dec->head[0]), + infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "]", + msg, ws_frame_name_of_op(dec->head[0]), (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL", dec->payload_offset, dec->payload_len); } @@ -272,7 +273,8 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, Curl_bufq_skip(inraw, (size_t)nwritten); dec->payload_offset += (curl_off_t)nwritten; remain = dec->payload_len - dec->payload_offset; - /* infof(data, "WS-DEC: passed %zd bytes payload, %zd remain", + /* infof(data, "WS-DEC: passed %zd bytes payload, %" + CURL_FORMAT_CURL_OFF_T " remain", nwritten, remain); */ } @@ -351,8 +353,9 @@ static void update_meta(struct websocket *ws, static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data, const char *msg) { - infof(data, "WS-ENC: %s [%s%s%s payload=%zd/%zd]", msg, - ws_frame_name_of_op(enc->firstbyte), + infof(data, "WS-ENC: %s [%s%s%s payload=%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "]", + msg, ws_frame_name_of_op(enc->firstbyte), (enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ? " CONT" : "", (enc->firstbyte & WSBIT_FIN)? "" : " NON-FIN", @@ -839,7 +842,7 @@ static ssize_t nw_in_recv(void *reader_ctx, CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, size_t buflen, size_t *nread, - struct curl_ws_frame **metap) + const struct curl_ws_frame **metap) { struct connectdata *conn = data->conn; struct websocket *ws; @@ -921,7 +924,8 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, ctx.payload_len, ctx.bufidx); *metap = &ws->frame; *nread = ws->frame.len; - /* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %zd, %zd left)", + /* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %" + CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)", buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */ return CURLE_OK; } @@ -966,10 +970,10 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, return CURLE_OK; } -CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, +CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer, size_t buflen, size_t *sent, - curl_off_t totalsize, - unsigned int sendflags) + curl_off_t fragsize, + unsigned int flags) { struct websocket *ws; ssize_t nwritten, n; @@ -987,14 +991,13 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, return CURLE_SEND_ERROR; } if(!data->conn->proto.ws) { - failf(data, "Not a websocket transfer on connection #%ld", - data->conn->connection_id); + failf(data, "Not a websocket transfer"); return CURLE_SEND_ERROR; } ws = data->conn->proto.ws; if(data->set.ws_raw_mode) { - if(totalsize || sendflags) + if(fragsize || flags) return CURLE_BAD_FUNCTION_ARGUMENT; if(!buflen) /* nothing to do */ @@ -1027,23 +1030,24 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, if(space < 14) return CURLE_AGAIN; - if(sendflags & CURLWS_OFFSET) { - if(totalsize) { - /* a frame series 'totalsize' bytes big, this is the first */ - n = ws_enc_write_head(data, &ws->enc, sendflags, totalsize, + if(flags & CURLWS_OFFSET) { + if(fragsize) { + /* a frame series 'fragsize' bytes big, this is the first */ + n = ws_enc_write_head(data, &ws->enc, flags, fragsize, &ws->sendbuf, &result); if(n < 0) return result; } else { if((curl_off_t)buflen > ws->enc.payload_remain) { - infof(data, "WS: unaligned frame size (sending %zu instead of %zd)", + infof(data, "WS: unaligned frame size (sending %zu instead of %" + CURL_FORMAT_CURL_OFF_T ")", buflen, ws->enc.payload_remain); } } } else if(!ws->enc.payload_remain) { - n = ws_enc_write_head(data, &ws->enc, sendflags, (curl_off_t)buflen, + n = ws_enc_write_head(data, &ws->enc, flags, (curl_off_t)buflen, &ws->sendbuf, &result); if(n < 0) return result; @@ -1082,7 +1086,7 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data, return CURLE_OK; } -CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) { /* we only return something for websocket, called from within the callback when not using raw mode */ @@ -1096,7 +1100,7 @@ CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, size_t *nread, - struct curl_ws_frame **metap) + const struct curl_ws_frame **metap) { (void)curl; (void)buffer; @@ -1108,19 +1112,19 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, size_t buflen, size_t *sent, - curl_off_t framesize, - unsigned int sendflags) + curl_off_t fragsize, + unsigned int flags) { (void)curl; (void)buffer; (void)buflen; (void)sent; - (void)framesize; - (void)sendflags; + (void)fragsize; + (void)flags; return CURLE_NOT_BUILT_IN; } -CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) { (void)data; return NULL; |