diff options
| author | dartraiden <wowemuh@gmail.com> | 2024-03-27 16:04:05 +0300 |
|---|---|---|
| committer | dartraiden <wowemuh@gmail.com> | 2024-03-27 16:04:05 +0300 |
| commit | 26b7f4e979561aa1f17d6719fc1dad91e1a5d1b4 (patch) | |
| tree | 98aafdc421d93e855ddc886fe56e9e084f992ac8 /libs/libcurl/src/vquic | |
| parent | 9be45ab3f9c03107dfb717798e41dda72576122d (diff) | |
libcurl: update to 8.7.1
Diffstat (limited to 'libs/libcurl/src/vquic')
| -rw-r--r-- | libs/libcurl/src/vquic/curl_msh3.c | 21 | ||||
| -rw-r--r-- | libs/libcurl/src/vquic/curl_ngtcp2.c | 179 | ||||
| -rw-r--r-- | libs/libcurl/src/vquic/curl_osslq.c | 124 | ||||
| -rw-r--r-- | libs/libcurl/src/vquic/curl_quiche.c | 13 | ||||
| -rw-r--r-- | libs/libcurl/src/vquic/vquic-tls.c | 4 | ||||
| -rw-r--r-- | libs/libcurl/src/vquic/vquic.c | 24 |
6 files changed, 151 insertions, 214 deletions
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c index 9835ccc5e1..a5b3e54c3b 100644 --- a/libs/libcurl/src/vquic/curl_msh3.c +++ b/libs/libcurl/src/vquic/curl_msh3.c @@ -722,23 +722,6 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf, return pending;
}
-static void cf_msh3_active(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_msh3_ctx *ctx = cf->ctx;
-
- /* use this socket from now on */
- cf->conn->sock[cf->sockindex] = ctx->sock[SP_LOCAL];
- /* the first socket info gets set at conn and data */
- if(cf->sockindex == FIRSTSOCKET) {
- cf->conn->remote_addr = &ctx->addr;
- #ifdef ENABLE_IPV6
- cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
- #endif
- Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
- }
- ctx->active = TRUE;
-}
-
static CURLcode h3_data_pause(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool pause)
@@ -785,10 +768,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf, }
}
break;
- case CF_CTRL_CONN_INFO_UPDATE:
- CURL_TRC_CF(data, cf, "req: update info");
- cf_msh3_active(cf, data);
- break;
default:
break;
}
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c index d004c9d27f..f4c66c71ac 100644 --- a/libs/libcurl/src/vquic/curl_ngtcp2.c +++ b/libs/libcurl/src/vquic/curl_ngtcp2.c @@ -58,6 +58,7 @@ #include "http1.h"
#include "select.h"
#include "inet_pton.h"
+#include "transfer.h"
#include "vquic.h"
#include "vquic_int.h"
#include "vquic-tls.h"
@@ -145,11 +146,9 @@ struct cf_ngtcp2_ctx { struct h3_stream_ctx {
int64_t id; /* HTTP/3 protocol identifier */
struct bufq sendbuf; /* h3 request body */
- struct bufq recvbuf; /* h3 response body */
struct h1_req_parser h1; /* h1 request parsing */
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 */
int status_code; /* HTTP status code */
@@ -190,11 +189,6 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
stream->sendbuf_len_in_flight = 0;
- /* on recv, we need a flexible buffer limit since we also write
- * headers to it that are not counted against the nghttp3 flow limits. */
- Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
- H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
- stream->recv_buf_nonflow = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
H3_STREAM_LCTX(data) = stream;
@@ -219,7 +213,6 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) }
Curl_bufq_free(&stream->sendbuf);
- Curl_bufq_free(&stream->recvbuf);
Curl_h1_req_parse_free(&stream->h1);
free(stream);
H3_STREAM_LCTX(data) = NULL;
@@ -387,36 +380,6 @@ static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) return 0;
}
-static void report_consumed_data(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- size_t consumed)
-{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
-
- if(!stream)
- return;
- /* the HTTP/1.1 response headers are written to the buffer, but
- * consuming those does not count against flow control. */
- if(stream->recv_buf_nonflow) {
- if(consumed >= stream->recv_buf_nonflow) {
- consumed -= stream->recv_buf_nonflow;
- stream->recv_buf_nonflow = 0;
- }
- else {
- stream->recv_buf_nonflow -= consumed;
- consumed = 0;
- }
- }
- if(consumed > 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
- stream->id, consumed);
- ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id,
- consumed);
- ngtcp2_conn_extend_max_offset(ctx->qconn, consumed);
- }
-}
-
static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
int64_t stream_id, uint64_t offset,
const uint8_t *buf, size_t buflen,
@@ -796,46 +759,18 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, return 0;
}
-/*
- * write_resp_raw() copies response data in raw format to the `data`'s
- * receive buffer. If not enough space is available, it appends to the
- * `data`'s overflow buffer.
- */
-static CURLcode write_resp_raw(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *mem, size_t memlen,
- bool flow)
+static CURLcode write_resp_hds(struct Curl_easy *data,
+ const char *buf, size_t blen)
{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- CURLcode result = CURLE_OK;
- ssize_t nwritten;
-
- (void)cf;
- if(!stream) {
- return CURLE_RECV_ERROR;
- }
- nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
- if(nwritten < 0) {
- return result;
- }
-
- if(!flow)
- stream->recv_buf_nonflow += (size_t)nwritten;
-
- if((size_t)nwritten < memlen) {
- /* This MUST not happen. Our recbuf is dimensioned to hold the
- * full max_stream_window and then some for this very reason. */
- DEBUGASSERT(0);
- return CURLE_RECV_ERROR;
- }
- return result;
+ return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
}
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
- const uint8_t *buf, size_t buflen,
+ const uint8_t *buf, size_t blen,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
@@ -846,14 +781,19 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- result = write_resp_raw(cf, data, buf, buflen, TRUE);
+ result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
if(result) {
CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
- stream->id, buflen, result);
+ stream->id, blen, result);
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, buflen);
- h3_drain_stream(cf, data);
+ if(blen) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
+ stream->id, blen);
+ ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
+ ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
+ }
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen);
return 0;
}
@@ -888,7 +828,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, if(!stream)
return 0;
/* add a CRLF only if we've received some headers */
- result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
+ result = write_resp_hds(data, "\r\n", 2);
if(result) {
return -1;
}
@@ -934,7 +874,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
stream->status_code);
CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
- result = write_resp_raw(cf, data, line, ncopy, FALSE);
+ result = write_resp_hds(data, line, ncopy);
if(result) {
return -1;
}
@@ -944,19 +884,19 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
- result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
+ result = write_resp_hds(data, (const char *)h3name.base, h3name.len);
if(result) {
return -1;
}
- result = write_resp_raw(cf, data, ": ", 2, FALSE);
+ result = write_resp_hds(data, ": ", 2);
if(result) {
return -1;
}
- result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE);
+ result = write_resp_hds(data, (const char *)h3val.base, h3val.len);
if(result) {
return -1;
}
- result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
+ result = write_resp_hds(data, "\r\n", 2);
if(result) {
return -1;
}
@@ -1092,7 +1032,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, if(stream->reset) {
failf(data,
"HTTP/3 stream %" PRId64 " reset by server", stream->id);
- *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
@@ -1112,7 +1052,7 @@ out: /* incoming data frames on the h3 stream */
static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
- char *buf, size_t len, CURLcode *err)
+ char *buf, size_t blen, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
@@ -1121,6 +1061,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, struct pkt_io_ctx pktx;
(void)ctx;
+ (void)buf;
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
@@ -1136,46 +1077,18 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto out;
}
- if(!Curl_bufq_is_empty(&stream->recvbuf)) {
- nread = Curl_bufq_read(&stream->recvbuf,
- (unsigned char *)buf, len, err);
- if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
- "-> %zd, %d", stream->id, len, nread, *err);
- goto out;
- }
- report_consumed_data(cf, data, nread);
- }
-
if(cf_progress_ingress(cf, data, &pktx)) {
*err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
- /* recvbuf had nothing before, maybe after progressing ingress? */
- if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
- nread = Curl_bufq_read(&stream->recvbuf,
- (unsigned char *)buf, len, err);
- if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
- "-> %zd, %d", stream->id, len, nread, *err);
- goto out;
- }
- report_consumed_data(cf, data, nread);
- }
-
- if(nread > 0) {
- h3_drain_stream(cf, data);
- }
- else {
- if(stream->closed) {
- nread = recv_closed_stream(cf, data, stream, err);
- goto out;
- }
- *err = CURLE_AGAIN;
- nread = -1;
+ if(stream->closed) {
+ nread = recv_closed_stream(cf, data, stream, err);
+ goto out;
}
+ *err = CURLE_AGAIN;
+ nread = -1;
out:
if(cf_progress_egress(cf, data, &pktx)) {
@@ -1189,8 +1102,8 @@ out: nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d",
- stream? stream->id : -1, len, nread, *err);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
+ stream? stream->id : -1, blen, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -1593,7 +1506,6 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct pkt_io_ctx local_pktx;
size_t pkts_chunk = 128, i;
- size_t pkts_max = 10 * pkts_chunk;
CURLcode result = CURLE_OK;
if(!pktx) {
@@ -1608,17 +1520,13 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, if(result)
return result;
- for(i = 0; i < pkts_max; i += pkts_chunk) {
+ for(i = 0; i < 4; ++i) {
+ if(i)
+ pktx_update_time(pktx, cf);
pktx->pkt_count = 0;
result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
recv_pkt, pktx);
- if(result) /* error */
- break;
- if(pktx->pkt_count < pkts_chunk) /* got less than we could */
- break;
- /* give egress a chance before we receive more */
- result = cf_progress_egress(cf, data, pktx);
- if(result) /* error */
+ if(result || !pktx->pkt_count) /* error or got nothing */
break;
}
return result;
@@ -1769,7 +1677,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, }
/* In UDP, there is a maximum theoretical packet paload length and
- * a minimum payload length that is "guarantueed" to work.
+ * a minimum payload length that is "guaranteed" to work.
* To detect if this minimum payload can be increased, ngtcp2 sends
* now and then a packet payload larger than the minimum. It that
* is ACKed by the peer, both parties know that it works and
@@ -1857,9 +1765,9 @@ out: static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- const struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
- return stream && !Curl_bufq_is_empty(&stream->recvbuf);
+ (void)data;
+ return FALSE;
}
static CURLcode h3_data_pause(struct Curl_cfilter *cf,
@@ -2070,8 +1978,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result)
return result;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
- &sockaddr, NULL, NULL, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
if(!sockaddr)
return CURLE_QUIC_CONNECT_ERROR;
ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
@@ -2186,13 +2093,11 @@ out: #ifndef CURL_DISABLE_VERBOSE_STRINGS
if(result) {
- const char *r_ip = NULL;
- int r_port = 0;
+ struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
infof(data, "QUIC connect to %s port %u failed: %s",
- r_ip, r_port, curl_easy_strerror(result));
+ ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
}
#endif
if(!result && ctx->qconn) {
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c index 82fda51971..caa78935f1 100644 --- a/libs/libcurl/src/vquic/curl_osslq.c +++ b/libs/libcurl/src/vquic/curl_osslq.c @@ -67,7 +67,7 @@ * Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE (16 * 1024)
-/* The pool keeps spares around and half of a full stream windows
+/* The pool keeps spares around and half of a full stream window
* seems good. More does not seem to improve performance.
* The benefit of the pool is that stream buffer to not keep
* spares. So memory consumption goes down when streams run empty,
@@ -100,7 +100,7 @@ typedef unsigned long sslerr_t; static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct Curl_easy *data);
-static const char *SSL_ERROR_to_str(int err)
+static const char *osslq_SSL_ERROR_to_str(int err)
{
switch(err) {
case SSL_ERROR_NONE:
@@ -139,7 +139,7 @@ static const char *SSL_ERROR_to_str(int err) }
/* Return error string for last OpenSSL error */
-static char *ossl_strerror(unsigned long error, char *buf, size_t size)
+static char *osslq_strerror(unsigned long error, char *buf, size_t size)
{
DEBUGASSERT(size);
*buf = '\0';
@@ -381,8 +381,8 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3, }
static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int detail, CURLcode def_result)
+ struct Curl_easy *data,
+ int detail, CURLcode def_result)
{
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = def_result;
@@ -421,17 +421,17 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, /* If client certificate is required, communicate the
error to client */
result = CURLE_SSL_CLIENTCERT;
- ossl_strerror(errdetail, ebuf, sizeof(ebuf));
+ osslq_strerror(errdetail, ebuf, sizeof(ebuf));
}
#endif
else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) {
ctx->protocol_shutdown = TRUE;
- err_descr = "QUIC connectin has been shut down";
+ err_descr = "QUIC connection has been shut down";
result = def_result;
}
else {
result = def_result;
- ossl_strerror(errdetail, ebuf, sizeof(ebuf));
+ osslq_strerror(errdetail, ebuf, sizeof(ebuf));
}
/* detail is already set to the SSL error above */
@@ -443,16 +443,14 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
char extramsg[80]="";
int sockerr = SOCKERRNO;
- const char *r_ip = NULL;
- int r_port = 0;
+ struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
if(sockerr && detail == SSL_ERROR_SYSCALL)
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, "QUIC connect: %s in connection to %s:%d (%s)",
- extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- ctx->peer.dispname, r_port, r_ip);
+ extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail),
+ ctx->peer.dispname, ip.remote_port, ip.remote_ip);
}
else {
/* Could be a CERT problem */
@@ -976,7 +974,7 @@ static nghttp3_callbacks ngh3_callbacks = { };
static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn,
- void *user_data)
+ void *user_data)
{
struct cf_osslq_h3conn *h3 = &ctx->h3;
CURLcode result;
@@ -1039,7 +1037,6 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, CURLcode result;
int rv;
const struct Curl_sockaddr_ex *peer_addr = NULL;
- int peer_port;
BIO *bio = NULL;
BIO_ADDR *baddr = NULL;
@@ -1061,8 +1058,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, goto out;
result = CURLE_QUIC_CONNECT_ERROR;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
- &peer_addr, NULL, &peer_port, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL);
if(!peer_addr)
goto out;
@@ -1078,7 +1074,20 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, goto out;
}
+ /* Type conversions, see #12861: OpenSSL wants an `int`, but on 64-bit
+ * Win32 systems, Microsoft defines SOCKET as `unsigned long long`.
+ */
+#if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
+ if(ctx->q.sockfd > INT_MAX) {
+ failf(data, "Windows socket identifier larger than MAX_INT, "
+ "unable to set in OpenSSL dgram API.");
+ result = CURLE_QUIC_CONNECT_ERROR;
+ goto out;
+ }
+ bio = BIO_new_dgram((int)ctx->q.sockfd, BIO_NOCLOSE);
+#else
bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE);
+#endif
if(!bio) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1095,6 +1104,16 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, goto out;
}
+#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
+ /* Added in OpenSSL v3.3.x */
+ if(!SSL_set_feature_request_uint(ctx->tls.ssl, SSL_VALUE_QUIC_IDLE_TIMEOUT,
+ CURL_QUIC_MAX_IDLE_MS)) {
+ CURL_TRC_CF(data, cf, "error setting idle timeout, ");
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+#endif
+
SSL_set_bio(ctx->tls.ssl, bio, bio);
bio = NULL;
SSL_set_connect_state(ctx->tls.ssl);
@@ -1146,7 +1165,7 @@ static ssize_t h3_quic_recv(void *reader_ctx, SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> RESET, "
"rv=%d, app_err=%" PRIu64,
- x->s->id, rv, app_error_code);
+ x->s->id, rv, app_error_code);
if(app_error_code != NGHTTP3_H3_NO_ERROR) {
x->s->reset = TRUE;
}
@@ -1361,7 +1380,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, size_t written;
int eos, ok, rv;
size_t total_len, acked_len = 0;
- bool blocked = FALSE;
+ bool blocked = FALSE, eos_written = FALSE;
n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos,
vec, ARRAYSIZE(vec));
@@ -1392,9 +1411,19 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, for(i = 0; (i < n) && !blocked; ++i) {
/* Without stream->s.ssl, we closed that already, so
* pretend the write did succeed. */
+#ifdef SSL_WRITE_FLAG_CONCLUDE
+ /* Since OpenSSL v3.3.x, on last chunk set EOS if needed */
+ uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
+ written = vec[i].len;
+ ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
+ &written);
+ if(ok && flags & SSL_WRITE_FLAG_CONCLUDE)
+ eos_written = TRUE;
+#else
written = vec[i].len;
ok = !s->ssl || SSL_write_ex(s->ssl, vec[i].base, vec[i].len,
&written);
+#endif
if(ok) {
/* As OpenSSL buffers the data, we count this as acknowledged
* from nghttp3's point of view */
@@ -1409,7 +1438,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, case SSL_ERROR_WANT_READ:
/* QUIC blocked us from writing more */
CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC blocked",
- s->id, vec[i].len);
+ s->id, vec[i].len);
written = 0;
nghttp3_conn_block_stream(ctx->h3.conn, s->id);
s->send_blocked = blocked = TRUE;
@@ -1426,6 +1455,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, if(acked_len > 0 || (eos && !s->send_blocked)) {
/* Since QUIC buffers the data written internally, we can tell
* nghttp3 that it can move forward on it */
+ ctx->q.last_io = Curl_now();
rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
@@ -1444,7 +1474,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, "to QUIC, eos=%d", s->id, acked_len, total_len, eos);
}
- if(eos && !s->send_blocked) {
+ if(eos && !s->send_blocked && !eos_written) {
/* wrote everything and H3 indicates end of stream */
CURL_TRC_CF(data, cf, "[%" PRId64 "] closing QUIC stream", s->id);
SSL_stream_conclude(s->ssl, 0);
@@ -1569,6 +1599,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, if(err == 1) {
/* connected */
ctx->handshake_at = now;
+ ctx->q.last_io = now;
CURL_TRC_CF(data, cf, "handshake complete after %dms",
(int)Curl_timediff(now, ctx->started_at));
result = cf_osslq_verify_peer(cf, data);
@@ -1584,15 +1615,18 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, int detail = SSL_get_error(ctx->tls.ssl, err);
switch(detail) {
case SSL_ERROR_WANT_READ:
+ ctx->q.last_io = now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
goto out;
case SSL_ERROR_WANT_WRITE:
+ ctx->q.last_io = now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND");
result = CURLE_OK;
goto out;
#ifdef SSL_ERROR_WANT_ASYNC
case SSL_ERROR_WANT_ASYNC:
+ ctx->q.last_io = now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC");
result = CURLE_OK;
goto out;
@@ -1619,13 +1653,11 @@ out: #ifndef CURL_DISABLE_VERBOSE_STRINGS
if(result) {
- const char *r_ip = NULL;
- int r_port = 0;
+ struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
infof(data, "QUIC connect to %s port %u failed: %s",
- r_ip, r_port, curl_easy_strerror(result));
+ ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
}
#endif
if(!result)
@@ -1885,7 +1917,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, if(stream->reset) {
failf(data,
"HTTP/3 stream %" PRId64 " reset by server", stream->s.id);
- *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
@@ -2055,7 +2087,24 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, if(!ctx->tls.ssl)
goto out;
- /* TODO: how to check negotiated connection idle time? */
+#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
+ /* Added in OpenSSL v3.3.x */
+ {
+ timediff_t idletime;
+ uint64_t idle_ms = ctx->max_idle_ms;
+ if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
+ SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) {
+ CURL_TRC_CF(data, cf, "error getting negotiated idle timeout, "
+ "assume connection is dead.");
+ goto out;
+ }
+ CURL_TRC_CF(data, cf, "negotiated idle timeout: %zums", (size_t)idle_ms);
+ idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
+ if(idletime > 0 && (uint64_t)idletime > idle_ms)
+ goto out;
+ }
+
+#endif
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
goto out;
@@ -2111,15 +2160,24 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, int query, int *pres1, void *pres2)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct cf_call_data save;
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- /* TODO: how to get this? */
- CF_DATA_SAVE(save, cf, data);
+#ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
+ /* Added in OpenSSL v3.3.x */
+ uint64_t v;
+ if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_GENERIC,
+ SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
+ CURL_TRC_CF(data, cf, "error getting available local bidi streams");
+ return CURLE_HTTP3;
+ }
+ /* we report avail + in_use */
+ v += CONN_INUSE(cf->conn);
+ *pres1 = (v > INT_MAX)? INT_MAX : (int)v;
+#else
*pres1 = 100;
+#endif
CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
- CF_DATA_RESTORE(cf, save);
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c index 263b9180f7..e79137ebbd 100644 --- a/libs/libcurl/src/vquic/curl_quiche.c +++ b/libs/libcurl/src/vquic/curl_quiche.c @@ -732,7 +732,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, if(stream->reset) {
failf(data,
"HTTP/3 stream %" PRId64 " reset by server", stream->id);
- *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d",
stream->id, *err);
}
@@ -1243,8 +1243,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result)
return result;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
- &sockaddr, NULL, NULL, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
&ctx->q.local_addrlen);
@@ -1390,13 +1389,11 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, out:
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(result && result != CURLE_AGAIN) {
- const char *r_ip;
- int r_port;
+ struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
infof(data, "connect to %s port %u failed: %s",
- r_ip, r_port, curl_easy_strerror(result));
+ ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
}
#endif
return result;
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c index 29c23ef58c..2a5f243e5d 100644 --- a/libs/libcurl/src/vquic/vquic-tls.c +++ b/libs/libcurl/src/vquic/vquic-tls.c @@ -375,6 +375,7 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, char error_buffer[256];
ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
@@ -382,6 +383,7 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, conn_config->curves :
(char *)QUIC_GROUPS) != 1) {
failf(data, "wolfSSL failed to set curves");
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
@@ -392,6 +394,7 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
#else
failf(data, "wolfSSL was built without keylog callback");
+ result = CURLE_NOT_BUILT_IN;
goto out;
#endif
}
@@ -414,6 +417,7 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, " CAfile: %s CApath: %s",
ssl_cafile ? ssl_cafile : "none",
ssl_capath ? ssl_capath : "none");
+ result = CURLE_SSL_CACERT_BADFILE;
goto out;
}
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c index 8a6bb99aac..422f7d18c0 100644 --- a/libs/libcurl/src/vquic/vquic.c +++ b/libs/libcurl/src/vquic/vquic.c @@ -370,12 +370,10 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- const char *r_ip = NULL;
- int r_port = 0;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ struct ip_quadruple ip;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
- r_ip, r_port);
+ ip.remote_ip, ip.remote_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
@@ -440,12 +438,10 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- const char *r_ip = NULL;
- int r_port = 0;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ struct ip_quadruple ip;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
- r_ip, r_port);
+ ip.remote_ip, ip.remote_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
@@ -500,12 +496,10 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- const char *r_ip = NULL;
- int r_port = 0;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL,
- &r_ip, &r_port, NULL, NULL);
+ struct ip_quadruple ip;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
- r_ip, r_port);
+ ip.remote_ip, ip.remote_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
|
