summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vquic
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vquic')
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.c38
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.c134
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c44
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.c37
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.c38
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.h2
-rw-r--r--libs/libcurl/src/vquic/vquic.c49
7 files changed, 202 insertions, 140 deletions
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c
index 464f7c5af6..0ce9fe4cac 100644
--- a/libs/libcurl/src/vquic/curl_msh3.c
+++ b/libs/libcurl/src/vquic/curl_msh3.c
@@ -71,7 +71,7 @@
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
pthread_mutex_init(lock, &attr); \
pthread_mutexattr_destroy(&attr); \
-}while(0)
+} while(0)
#define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock)
#define msh3_lock_acquire(lock) pthread_mutex_lock(lock)
#define msh3_lock_release(lock) pthread_mutex_unlock(lock)
@@ -248,8 +248,8 @@ static void drain_stream_from_other_thread(struct Curl_easy *data,
}
}
-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 cf_msh3_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -280,9 +280,9 @@ static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
(void)Connection;
CURL_TRC_CF(data, cf, "[MSH3] connected");
- ctx->handshake_succeeded = true;
- ctx->connected = true;
- ctx->handshake_complete = true;
+ ctx->handshake_succeeded = TRUE;
+ ctx->connected = TRUE;
+ ctx->handshake_complete = TRUE;
}
static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
@@ -294,8 +294,8 @@ static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
(void)Connection;
CURL_TRC_CF(data, cf, "[MSH3] shutdown complete");
- ctx->connected = false;
- ctx->handshake_complete = true;
+ ctx->connected = FALSE;
+ ctx->handshake_complete = TRUE;
}
static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
@@ -450,7 +450,7 @@ static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
stream->recv_error = result;
goto out;
}
- stream->recv_header_complete = true;
+ stream->recv_header_complete = TRUE;
}
result = write_resp_raw(data, buf, *buflen);
@@ -476,7 +476,7 @@ static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
return;
msh3_lock_acquire(&stream->recv_lock);
stream->closed = TRUE;
- stream->recv_header_complete = true;
+ stream->recv_header_complete = TRUE;
if(error)
stream->error3 = error;
if(aborted)
@@ -596,7 +596,7 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(nread < 0)
goto out;
if(stream->closed)
- drain_stream(cf, data);
+ h3_drain_stream(cf, data);
}
else if(stream->closed) {
nread = recv_closed_stream(cf, data, err);
@@ -722,11 +722,11 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
if(stream->recv_error) {
Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]);
- drain_stream(cf, data);
+ h3_drain_stream(cf, data);
}
else if(stream->req) {
Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]);
- drain_stream(cf, data);
+ h3_drain_stream(cf, data);
}
}
}
@@ -749,7 +749,7 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
pending = !Curl_bufq_is_empty(&stream->recvbuf);
msh3_lock_release(&stream->recv_lock);
if(pending)
- drain_stream(cf, (struct Curl_easy *)data);
+ h3_drain_stream(cf, (struct Curl_easy *)data);
}
CF_DATA_RESTORE(cf, save);
@@ -761,7 +761,7 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf,
bool pause)
{
if(!pause) {
- drain_stream(cf, data);
+ h3_drain_stream(cf, data);
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
return CURLE_OK;
@@ -826,7 +826,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
verify = !!conn_config->verifypeer;
- memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen);
+ memcpy(&addr, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
if(verify && (conn_config->CAfile || conn_config->CApath)) {
@@ -1020,7 +1020,7 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
default:
break;
}
- return cf->next?
+ return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
@@ -1092,7 +1092,7 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
out:
- *pcf = (!result)? cf : NULL;
+ *pcf = (!result) ? cf : NULL;
if(result) {
Curl_safefree(cf);
cf_msh3_ctx_free(ctx);
@@ -1105,7 +1105,7 @@ bool Curl_conn_is_msh3(const struct Curl_easy *data,
const struct connectdata *conn,
int sockindex)
{
- struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
(void)data;
for(; cf; cf = cf->next) {
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c
index bee8689af6..b017b49ace 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.c
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.c
@@ -41,6 +41,7 @@
#include "vtls/gtls.h"
#elif defined(USE_WOLFSSL)
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
+#include "vtls/wolfssl.h"
#endif
#include "urldata.h"
@@ -342,7 +343,6 @@ struct pkt_io_ctx {
struct Curl_cfilter *cf;
struct Curl_easy *data;
ngtcp2_tstamp ts;
- size_t pkt_count;
ngtcp2_path_storage ps;
};
@@ -362,7 +362,6 @@ static void pktx_init(struct pkt_io_ctx *pktx,
{
pktx->cf = cf;
pktx->data = data;
- pktx->pkt_count = 0;
ngtcp2_path_storage_zero(&pktx->ps);
pktx_update_time(pktx, cf);
}
@@ -429,7 +428,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
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;
+ s->max_stream_window = 10 * ctx->max_stream_window;
t->initial_max_data = 10 * ctx->max_stream_window;
t->initial_max_stream_data_bidi_local = ctx->max_stream_window;
@@ -1199,7 +1198,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
@@ -1277,7 +1276,7 @@ out:
}
}
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
- stream? stream->id : -1, blen, nread, *err);
+ stream ? stream->id : -1, blen, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -1375,7 +1374,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
"%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
stream->id, (int)nvecs,
- *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
+ *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
nwritten, Curl_bufq_len(&stream->sendbuf),
stream->upload_left);
return (nghttp3_ssize)nvecs;
@@ -1612,7 +1611,7 @@ out:
sent = -1;
}
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->id : -1, len, sent, *err);
+ stream ? stream->id : -1, len, sent, *err);
CF_DATA_RESTORE(cf, save);
return sent;
}
@@ -1639,7 +1638,6 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
ngtcp2_path path;
int rv;
- ++pktx->pkt_count;
ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
(socklen_t)ctx->q.local_addrlen);
ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
@@ -1668,31 +1666,18 @@ 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;
CURLcode result = CURLE_OK;
if(!pktx) {
pktx_init(&local_pktx, cf, data);
pktx = &local_pktx;
}
- else {
- pktx_update_time(pktx, cf);
- }
result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
if(result)
return result;
- 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 || !pktx->pkt_count) /* error or got nothing */
- break;
- }
- return result;
+ return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx);
}
/**
@@ -2142,9 +2127,9 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
ngtcp2_crypto_conn_ref *cref;
cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
- cf = cref? cref->user_data : NULL;
- ctx = cf? cf->ctx : NULL;
- data = cf? CF_DATA_CURRENT(cf) : NULL;
+ cf = cref ? cref->user_data : NULL;
+ ctx = cf ? cf->ctx : NULL;
+ data = cf ? CF_DATA_CURRENT(cf) : NULL;
if(cf && data && ctx) {
Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
return 1;
@@ -2153,12 +2138,63 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
}
#endif /* USE_OPENSSL */
+#ifdef USE_GNUTLS
+static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming,
+ const gnutls_datum_t *msg)
+{
+ ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session);
+ struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
+ struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
+
+ (void)msg;
+ (void)incoming;
+ if(when && cf && ctx) { /* after message has been processed */
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ DEBUGASSERT(data);
+ if(data) {
+ CURL_TRC_CF(data, cf, "handshake: %s message type %d",
+ incoming ? "incoming" : "outgoing", htype);
+ }
+ switch(htype) {
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
+ (void)Curl_gtls_update_session_id(cf, data, session, &ctx->peer, "h3");
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+#endif /* USE_GNUTLS */
+
+#ifdef USE_WOLFSSL
+static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
+{
+ ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl);
+ struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
+
+ DEBUGASSERT(cf != NULL);
+ if(cf && session) {
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ DEBUGASSERT(data);
+ if(data && ctx) {
+ (void)wssl_cache_session(cf, data, &ctx->peer, session);
+ }
+ }
+ return 0;
+}
+#endif /* USE_WOLFSSL */
+
static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
void *user_data)
{
struct curl_tls_ctx *ctx = user_data;
- (void)cf;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
#ifdef USE_OPENSSL
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
@@ -2172,25 +2208,37 @@ static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
}
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
- /* Enable the session cache because it is a prerequisite for the
- * "new session" callback. Use the "external storage" mode to prevent
- * OpenSSL from creating an internal session cache.
- */
- SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
- SSL_SESS_CACHE_CLIENT |
- SSL_SESS_CACHE_NO_INTERNAL);
- SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
+ if(ssl_config->primary.cache_session) {
+ /* Enable the session cache because it is a prerequisite for the
+ * "new session" callback. Use the "external storage" mode to prevent
+ * OpenSSL from creating an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
+ SSL_SESS_CACHE_CLIENT |
+ SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
+ }
#elif defined(USE_GNUTLS)
if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
return CURLE_FAILED_INIT;
}
+ if(ssl_config->primary.cache_session) {
+ gnutls_handshake_set_hook_function(ctx->gtls.session,
+ GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
+ quic_gtls_handshake_cb);
+ }
+
#elif defined(USE_WOLFSSL)
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
+ if(ssl_config->primary.cache_session) {
+ /* Register to get notified when a new session is received */
+ wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
+ }
#endif
return CURLE_OK;
}
@@ -2256,7 +2304,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
(struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen);
ngtcp2_addr_init(&ctx->connected_path.remote,
- &sockaddr->sa_addr, (socklen_t)sockaddr->addrlen);
+ &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen);
rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
&ctx->connected_path,
@@ -2270,8 +2318,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
#elif defined(USE_GNUTLS)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
-#else
+#elif defined(USE_WOLFSSL)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
+#else
+ #error "ngtcp2 TLS backend not defined"
#endif
ngtcp2_ccerr_default(&ctx->last_error);
@@ -2394,7 +2444,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
if(ctx->max_bidi_streams > ctx->used_bidi_streams)
avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
max_streams += avail_bidi_streams;
- *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+ *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
}
else /* transport params not arrived yet? take our default. */
*pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
@@ -2407,7 +2457,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->q.got_first_byte) {
timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
- *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+ *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
*pres1 = -1;
@@ -2427,7 +2477,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
default:
break;
}
- return cf->next?
+ return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
@@ -2476,7 +2526,7 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
*input_pending = FALSE;
result = cf_progress_ingress(cf, data, NULL);
CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
- alive = result? FALSE : TRUE;
+ alive = result ? FALSE : TRUE;
}
out:
@@ -2534,7 +2584,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
cf->next = udp_cf;
out:
- *pcf = (!result)? cf : NULL;
+ *pcf = (!result) ? cf : NULL;
if(result) {
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -2548,7 +2598,7 @@ bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
const struct connectdata *conn,
int sockindex)
{
- struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
(void)data;
for(; cf; cf = cf->next) {
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index 4ceceb5ad0..c3d695d415 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -175,7 +175,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
switch(addr->family) {
case AF_INET: {
struct sockaddr_in * const sin =
- (struct sockaddr_in * const)(void *)&addr->sa_addr;
+ (struct sockaddr_in * const)(void *)&addr->curl_sa_addr;
if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
sizeof(sin->sin_addr), sin->sin_port)) {
goto out;
@@ -186,7 +186,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
#ifdef USE_IPV6
case AF_INET6: {
struct sockaddr_in6 * const sin =
- (struct sockaddr_in6 * const)(void *)&addr->sa_addr;
+ (struct sockaddr_in6 * const)(void *)&addr->curl_sa_addr;
if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
sizeof(sin->sin6_addr), sin->sin6_port)) {
}
@@ -1037,7 +1037,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
"%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
stream->s.id, (int)nvecs,
- *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
+ *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
nwritten, Curl_bufq_len(&stream->sendbuf),
stream->upload_left);
return (nghttp3_ssize)nvecs;
@@ -1309,7 +1309,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
CURLcode result = CURLE_OK;
ssize_t nread;
struct h3_quic_recv_ctx x;
- int rv, eagain = FALSE;
+ bool eagain = FALSE;
size_t total_recv_len = 0;
DEBUGASSERT(s);
@@ -1359,6 +1359,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
/* When we forwarded everything, handle RESET/EOS */
if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) {
+ int rv;
result = CURLE_OK;
if(s->reset) {
uint64_t app_error;
@@ -1531,7 +1532,7 @@ 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. */
- uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
+ 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);
@@ -1632,11 +1633,11 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
struct timeval tv;
timediff_t timeoutms;
- int is_infinite = TRUE;
+ int is_infinite = 1;
if(ctx->tls.ossl.ssl &&
- SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
- !is_infinite) {
+ SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
+ !is_infinite) {
timeoutms = curlx_tvtoms(&tv);
/* QUIC want to be called again latest at the returned timeout */
if(timeoutms <= 0) {
@@ -1700,6 +1701,14 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
}
+ /* Since OpenSSL does its own send/recv internally, we may miss the
+ * moment to populate the x509 store right before the server response.
+ * Do it instead before we start the handshake, at the loss of the
+ * time to set this up. */
+ result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
+ if(result)
+ goto out;
+
ERR_clear_error();
err = SSL_do_handshake(ctx->tls.ossl.ssl);
@@ -1724,7 +1733,6 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
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;
@@ -1985,7 +1993,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
result = check_and_set_expiry(cf, data);
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->s.id : -1, len, nwritten, *err);
+ stream ? stream->s.id : -1, len, nwritten, *err);
CF_DATA_RESTORE(cf, save);
return nwritten;
}
@@ -2002,7 +2010,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
failf(data,
"HTTP/3 stream %" FMT_PRId64 " reset by server",
stream->s.id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
@@ -2096,7 +2104,7 @@ out:
}
}
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
- stream? stream->s.id : -1, len, nread, *err);
+ stream ? stream->s.id : -1, len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -2207,7 +2215,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
*input_pending = FALSE;
result = cf_progress_ingress(cf, data);
CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
- alive = result? FALSE : TRUE;
+ alive = result ? FALSE : TRUE;
}
out:
@@ -2266,7 +2274,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
}
/* we report avail + in_use */
v += CONN_INUSE(cf->conn);
- *pres1 = (v > INT_MAX)? INT_MAX : (int)v;
+ *pres1 = (v > INT_MAX) ? INT_MAX : (int)v;
#else
*pres1 = 100;
#endif
@@ -2276,7 +2284,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->got_first_byte) {
timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
- *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+ *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
*pres1 = -1;
@@ -2296,7 +2304,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
default:
break;
}
- return cf->next?
+ return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
@@ -2351,7 +2359,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
cf->next = udp_cf;
out:
- *pcf = (!result)? cf : NULL;
+ *pcf = (!result) ? cf : NULL;
if(result) {
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -2365,7 +2373,7 @@ bool Curl_conn_is_osslq(const struct Curl_easy *data,
const struct connectdata *conn,
int sockindex)
{
- struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
(void)data;
for(; cf; cf = cf->next) {
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c
index fb84f9d709..8cdd512dd0 100644
--- a/libs/libcurl/src/vquic/curl_quiche.c
+++ b/libs/libcurl/src/vquic/curl_quiche.c
@@ -268,8 +268,8 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-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 cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -584,7 +584,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
}
else {
result = h3_process_event(cf, sdata, stream, ev);
- drain_stream(cf, sdata);
+ h3_drain_stream(cf, sdata);
if(result) {
CURL_TRC_CF(data, cf, "error processing event %s "
"for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
@@ -818,7 +818,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
if(stream->reset) {
failf(data,
"HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
stream->id, *err);
}
@@ -882,7 +882,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(nread > 0) {
if(stream->closed)
- drain_stream(cf, data);
+ h3_drain_stream(cf, data);
}
else {
if(stream->closed) {
@@ -1146,7 +1146,7 @@ out:
nwritten = -1;
}
CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
+ stream ? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
return nwritten;
}
@@ -1207,7 +1207,7 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf,
/* TODO: there seems right now no API in quiche 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;
@@ -1287,7 +1287,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
failf(data, "cannot create quiche config");
return CURLE_FAILED_INIT;
}
- quiche_config_enable_pacing(ctx->cfg, false);
+ quiche_config_enable_pacing(ctx->cfg, FALSE);
quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
/* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
@@ -1329,11 +1329,12 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
return CURLE_QUIC_CONNECT_ERROR;
ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
- sizeof(ctx->scid), NULL, 0,
- (struct sockaddr *)&ctx->q.local_addr,
- ctx->q.local_addrlen,
- &sockaddr->sa_addr, sockaddr->addrlen,
- ctx->cfg, ctx->tls.ossl.ssl, false);
+ sizeof(ctx->scid), NULL, 0,
+ (struct sockaddr *)&ctx->q.local_addr,
+ ctx->q.local_addrlen,
+ &sockaddr->curl_sa_addr,
+ sockaddr->addrlen,
+ ctx->cfg, ctx->tls.ossl.ssl, FALSE);
if(!ctx->qconn) {
failf(data, "cannot create quiche connection");
return CURLE_OUT_OF_MEMORY;
@@ -1546,7 +1547,7 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
if(!ctx->goaway) {
max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
}
- *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+ *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
"MAX_CONCURRENT -> %d (%zu in use)",
cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
@@ -1555,7 +1556,7 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->q.got_first_byte) {
timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
- *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+ *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
*pres1 = -1;
@@ -1575,7 +1576,7 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
default:
break;
}
- return cf->next?
+ return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
@@ -1667,7 +1668,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
cf->next = udp_cf;
out:
- *pcf = (!result)? cf : NULL;
+ *pcf = (!result) ? cf : NULL;
if(result) {
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -1682,7 +1683,7 @@ bool Curl_conn_is_quiche(const struct Curl_easy *data,
const struct connectdata *conn,
int sockindex)
{
- struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+ struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
(void)data;
for(; cf; cf = cf->next) {
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c
index f51ec0cc22..b246d7fdc3 100644
--- a/libs/libcurl/src/vquic/vquic-tls.c
+++ b/libs/libcurl/src/vquic/vquic-tls.c
@@ -76,11 +76,11 @@ static void keylog_callback(const WOLFSSL *ssl, const char *line)
}
#endif
-static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- Curl_vquic_tls_ctx_setup *cb_setup,
- void *cb_user_data)
+static CURLcode wssl_init_ctx(struct curl_tls_ctx *ctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ Curl_vquic_tls_ctx_setup *cb_setup,
+ void *cb_user_data)
{
struct ssl_primary_config *conn_config;
CURLcode result = CURLE_FAILED_INIT;
@@ -173,10 +173,10 @@ static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- Curl_set_in_callback(data, true);
+ Curl_set_in_callback(data, TRUE);
result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
data->set.ssl.fsslctxp);
- Curl_set_in_callback(data, false);
+ Curl_set_in_callback(data, FALSE);
if(result) {
failf(data, "error signaled by ssl ctx callback");
goto out;
@@ -194,13 +194,15 @@ out:
/** SSL callbacks ***/
-static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- void *user_data)
+static CURLcode wssl_init_ssl(struct curl_tls_ctx *ctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const char *alpn, size_t alpn_len,
+ void *user_data)
{
- (void)data;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
DEBUGASSERT(!ctx->wssl.handle);
DEBUGASSERT(ctx->wssl.ctx);
ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
@@ -218,6 +220,10 @@ static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
peer->sni, (unsigned short)strlen(peer->sni));
}
+ if(ssl_config->primary.cache_session) {
+ (void)wssl_setup_session(cf, data, &ctx->wssl, peer);
+ }
+
return CURLE_OK;
}
#endif /* defined(USE_WOLFSSL) */
@@ -240,14 +246,14 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
#elif defined(USE_GNUTLS)
(void)result;
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
- (const unsigned char *)alpn, alpn_len,
+ (const unsigned char *)alpn, alpn_len, NULL,
cb_setup, cb_user_data, ssl_user_data);
#elif defined(USE_WOLFSSL)
- result = Curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
+ result = wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
if(result)
return result;
- return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
+ return wssl_init_ssl(ctx, cf, data, peer, alpn, alpn_len, ssl_user_data);
#else
#error "no TLS lib in used, should not happen"
return CURLE_FAILED_INIT;
diff --git a/libs/libcurl/src/vquic/vquic-tls.h b/libs/libcurl/src/vquic/vquic-tls.h
index 74db0e0ada..558170810b 100644
--- a/libs/libcurl/src/vquic/vquic-tls.h
+++ b/libs/libcurl/src/vquic/vquic-tls.h
@@ -64,7 +64,7 @@ typedef CURLcode Curl_vquic_tls_ctx_setup(struct Curl_cfilter *cf,
* @param alpn the ALPN string in protocol format ((len+bytes+)+),
* may be NULL
* @param alpn_len the overall number of bytes in `alpn`
- * @param cb_setup optional callback for very early TLS config
+ * @param cb_setup optional callback for early TLS config
± @param cb_user_data user_data param for callback
* @param ssl_user_data optional pointer to set in TLS application context
*/
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c
index f68a8d2912..960c710170 100644
--- a/libs/libcurl/src/vquic/vquic.c
+++ b/libs/libcurl/src/vquic/vquic.c
@@ -22,18 +22,6 @@
*
***************************************************************************/
-/* WIP, experimental: use recvmmsg() on Linux
- * we have no configure check, yet
- * and also it is only available for _GNU_SOURCE, which
- * we do not use otherwise.
-#define HAVE_SENDMMSG
- */
-#if defined(HAVE_SENDMMSG)
-#define _GNU_SOURCE
-#include <sys/socket.h>
-#undef _GNU_SOURCE
-#endif
-
#include "curl_setup.h"
#ifdef HAVE_NETINET_UDP_H
@@ -51,6 +39,7 @@
#include "curl_ngtcp2.h"
#include "curl_osslq.h"
#include "curl_quiche.h"
+#include "multiif.h"
#include "rand.h"
#include "vquic.h"
#include "vquic_int.h"
@@ -153,8 +142,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
/* Only set this, when we need it. macOS, for example,
* does not seem to like a msg_control of length 0. */
msg.msg_control = msg_ctrl;
- assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t)));
- msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
+ assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(int)));
+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
cm = CMSG_FIRSTHDR(&msg);
cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT;
@@ -333,20 +322,20 @@ CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
}
#if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
-static size_t msghdr_get_udp_gro(struct msghdr *msg)
+static size_t vquic_msghdr_get_udp_gro(struct msghdr *msg)
{
int gso_size = 0;
#if defined(__linux__) && defined(UDP_GRO)
struct cmsghdr *cmsg;
/* Workaround musl CMSG_NXTHDR issue */
-#ifndef __GLIBC__
+#if defined(__clang__) && !defined(__GLIBC__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wcast-align"
#endif
for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-#ifndef __GLIBC__
+#if defined(__clang__) && !defined(__GLIBC__)
#pragma clang diagnostic pop
#endif
if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
@@ -369,21 +358,28 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
size_t max_pkts,
vquic_recv_pkt_cb *recv_cb, void *userp)
{
-#define MMSG_NUM 64
+#define MMSG_NUM 16
struct iovec msg_iov[MMSG_NUM];
struct mmsghdr mmsg[MMSG_NUM];
- uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
- uint8_t bufs[MMSG_NUM][2*1024];
+ uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(int))];
struct sockaddr_storage remote_addr[MMSG_NUM];
- size_t total_nread, pkts;
+ size_t total_nread = 0, pkts;
int mcount, i, n;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
size_t gso_size;
size_t pktlen;
size_t offset, to;
+ char *sockbuf = NULL;
+ uint8_t (*bufs)[64*1024] = NULL;
DEBUGASSERT(max_pkts > 0);
+ result = Curl_multi_xfer_sockbuf_borrow(data, MMSG_NUM * sizeof(bufs[0]),
+ &sockbuf);
+ if(result)
+ goto out;
+ bufs = (uint8_t (*)[64*1024])sockbuf;
+
pkts = 0;
total_nread = 0;
while(pkts < max_pkts) {
@@ -396,8 +392,8 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
mmsg[i].msg_hdr.msg_iovlen = 1;
mmsg[i].msg_hdr.msg_name = &remote_addr[i];
mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
- mmsg[i].msg_hdr.msg_control = &msg_ctrl[i];
- mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
+ mmsg[i].msg_hdr.msg_control = &msg_ctrl[i * CMSG_SPACE(sizeof(int))];
+ mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
@@ -427,7 +423,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
for(i = 0; i < mcount; ++i) {
total_nread += mmsg[i].msg_len;
- gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
+ gso_size = vquic_msghdr_get_udp_gro(&mmsg[i].msg_hdr);
if(gso_size == 0) {
gso_size = mmsg[i].msg_len;
}
@@ -455,6 +451,7 @@ out:
if(total_nread || result)
CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
pkts, total_nread, result);
+ Curl_multi_xfer_sockbuf_release(data, sockbuf);
return result;
}
@@ -473,7 +470,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
ssize_t nread;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
- uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
+ uint8_t msg_ctrl[CMSG_SPACE(sizeof(int))];
size_t gso_size;
size_t pktlen;
size_t offset, to;
@@ -515,7 +512,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
total_nread += (size_t)nread;
- gso_size = msghdr_get_udp_gro(&msg);
+ gso_size = vquic_msghdr_get_udp_gro(&msg);
if(gso_size == 0) {
gso_size = (size_t)nread;
}