1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker
27*6236dae4SAndroid Build Coastguard Worker #if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
28*6236dae4SAndroid Build Coastguard Worker #include <ngtcp2/ngtcp2.h>
29*6236dae4SAndroid Build Coastguard Worker #include <nghttp3/nghttp3.h>
30*6236dae4SAndroid Build Coastguard Worker
31*6236dae4SAndroid Build Coastguard Worker #ifdef USE_OPENSSL
32*6236dae4SAndroid Build Coastguard Worker #include <openssl/err.h>
33*6236dae4SAndroid Build Coastguard Worker #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
34*6236dae4SAndroid Build Coastguard Worker #include <ngtcp2/ngtcp2_crypto_boringssl.h>
35*6236dae4SAndroid Build Coastguard Worker #else
36*6236dae4SAndroid Build Coastguard Worker #include <ngtcp2/ngtcp2_crypto_quictls.h>
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker #include "vtls/openssl.h"
39*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_GNUTLS)
40*6236dae4SAndroid Build Coastguard Worker #include <ngtcp2/ngtcp2_crypto_gnutls.h>
41*6236dae4SAndroid Build Coastguard Worker #include "vtls/gtls.h"
42*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_WOLFSSL)
43*6236dae4SAndroid Build Coastguard Worker #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
44*6236dae4SAndroid Build Coastguard Worker #include "vtls/wolfssl.h"
45*6236dae4SAndroid Build Coastguard Worker #endif
46*6236dae4SAndroid Build Coastguard Worker
47*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
48*6236dae4SAndroid Build Coastguard Worker #include "hash.h"
49*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
50*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
51*6236dae4SAndroid Build Coastguard Worker #include "rand.h"
52*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
53*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
54*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
55*6236dae4SAndroid Build Coastguard Worker #include "cf-socket.h"
56*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
57*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
58*6236dae4SAndroid Build Coastguard Worker #include "strerror.h"
59*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
60*6236dae4SAndroid Build Coastguard Worker #include "http1.h"
61*6236dae4SAndroid Build Coastguard Worker #include "select.h"
62*6236dae4SAndroid Build Coastguard Worker #include "inet_pton.h"
63*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
64*6236dae4SAndroid Build Coastguard Worker #include "vquic.h"
65*6236dae4SAndroid Build Coastguard Worker #include "vquic_int.h"
66*6236dae4SAndroid Build Coastguard Worker #include "vquic-tls.h"
67*6236dae4SAndroid Build Coastguard Worker #include "vtls/keylog.h"
68*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
69*6236dae4SAndroid Build Coastguard Worker #include "curl_ngtcp2.h"
70*6236dae4SAndroid Build Coastguard Worker
71*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
72*6236dae4SAndroid Build Coastguard Worker
73*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
74*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
75*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
76*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
77*6236dae4SAndroid Build Coastguard Worker
78*6236dae4SAndroid Build Coastguard Worker
79*6236dae4SAndroid Build Coastguard Worker #define QUIC_MAX_STREAMS (256*1024)
80*6236dae4SAndroid Build Coastguard Worker #define QUIC_MAX_DATA (1*1024*1024)
81*6236dae4SAndroid Build Coastguard Worker #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
82*6236dae4SAndroid Build Coastguard Worker
83*6236dae4SAndroid Build Coastguard Worker /* A stream window is the maximum amount we need to buffer for
84*6236dae4SAndroid Build Coastguard Worker * each active transfer. We use HTTP/3 flow control and only ACK
85*6236dae4SAndroid Build Coastguard Worker * when we take things out of the buffer.
86*6236dae4SAndroid Build Coastguard Worker * Chunk size is large enough to take a full DATA frame */
87*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_WINDOW_SIZE (128 * 1024)
88*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CHUNK_SIZE (16 * 1024)
89*6236dae4SAndroid Build Coastguard Worker /* The pool keeps spares around and half of a full stream windows
90*6236dae4SAndroid Build Coastguard Worker * seems good. More does not seem to improve performance.
91*6236dae4SAndroid Build Coastguard Worker * The benefit of the pool is that stream buffer to not keep
92*6236dae4SAndroid Build Coastguard Worker * spares. Memory consumption goes down when streams run empty,
93*6236dae4SAndroid Build Coastguard Worker * have a large upload done, etc. */
94*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_POOL_SPARES \
95*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
96*6236dae4SAndroid Build Coastguard Worker /* Receive and Send max number of chunks just follows from the
97*6236dae4SAndroid Build Coastguard Worker * chunk size and window size */
98*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_RECV_CHUNKS \
99*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
100*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_SEND_CHUNKS \
101*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
102*6236dae4SAndroid Build Coastguard Worker
103*6236dae4SAndroid Build Coastguard Worker
104*6236dae4SAndroid Build Coastguard Worker /*
105*6236dae4SAndroid Build Coastguard Worker * Store ngtcp2 version info in this buffer.
106*6236dae4SAndroid Build Coastguard Worker */
Curl_ngtcp2_ver(char * p,size_t len)107*6236dae4SAndroid Build Coastguard Worker void Curl_ngtcp2_ver(char *p, size_t len)
108*6236dae4SAndroid Build Coastguard Worker {
109*6236dae4SAndroid Build Coastguard Worker const ngtcp2_info *ng2 = ngtcp2_version(0);
110*6236dae4SAndroid Build Coastguard Worker const nghttp3_info *ht3 = nghttp3_version(0);
111*6236dae4SAndroid Build Coastguard Worker (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
112*6236dae4SAndroid Build Coastguard Worker ng2->version_str, ht3->version_str);
113*6236dae4SAndroid Build Coastguard Worker }
114*6236dae4SAndroid Build Coastguard Worker
115*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx {
116*6236dae4SAndroid Build Coastguard Worker struct cf_quic_ctx q;
117*6236dae4SAndroid Build Coastguard Worker struct ssl_peer peer;
118*6236dae4SAndroid Build Coastguard Worker struct curl_tls_ctx tls;
119*6236dae4SAndroid Build Coastguard Worker ngtcp2_path connected_path;
120*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn *qconn;
121*6236dae4SAndroid Build Coastguard Worker ngtcp2_cid dcid;
122*6236dae4SAndroid Build Coastguard Worker ngtcp2_cid scid;
123*6236dae4SAndroid Build Coastguard Worker uint32_t version;
124*6236dae4SAndroid Build Coastguard Worker ngtcp2_settings settings;
125*6236dae4SAndroid Build Coastguard Worker ngtcp2_transport_params transport_params;
126*6236dae4SAndroid Build Coastguard Worker ngtcp2_ccerr last_error;
127*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_conn_ref conn_ref;
128*6236dae4SAndroid Build Coastguard Worker struct cf_call_data call_data;
129*6236dae4SAndroid Build Coastguard Worker nghttp3_conn *h3conn;
130*6236dae4SAndroid Build Coastguard Worker nghttp3_settings h3settings;
131*6236dae4SAndroid Build Coastguard Worker struct curltime started_at; /* time the current attempt started */
132*6236dae4SAndroid Build Coastguard Worker struct curltime handshake_at; /* time connect handshake finished */
133*6236dae4SAndroid Build Coastguard Worker struct bufc_pool stream_bufcp; /* chunk pool for streams */
134*6236dae4SAndroid Build Coastguard Worker struct dynbuf scratch; /* temp buffer for header construction */
135*6236dae4SAndroid Build Coastguard Worker struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
136*6236dae4SAndroid Build Coastguard Worker size_t max_stream_window; /* max flow window for one stream */
137*6236dae4SAndroid Build Coastguard Worker uint64_t max_idle_ms; /* max idle time for QUIC connection */
138*6236dae4SAndroid Build Coastguard Worker uint64_t used_bidi_streams; /* bidi streams we have opened */
139*6236dae4SAndroid Build Coastguard Worker uint64_t max_bidi_streams; /* max bidi streams we can open */
140*6236dae4SAndroid Build Coastguard Worker int qlogfd;
141*6236dae4SAndroid Build Coastguard Worker BIT(initialized);
142*6236dae4SAndroid Build Coastguard Worker BIT(shutdown_started); /* queued shutdown packets */
143*6236dae4SAndroid Build Coastguard Worker };
144*6236dae4SAndroid Build Coastguard Worker
145*6236dae4SAndroid Build Coastguard Worker /* How to access `call_data` from a cf_ngtcp2 filter */
146*6236dae4SAndroid Build Coastguard Worker #undef CF_CTX_CALL_DATA
147*6236dae4SAndroid Build Coastguard Worker #define CF_CTX_CALL_DATA(cf) \
148*6236dae4SAndroid Build Coastguard Worker ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
149*6236dae4SAndroid Build Coastguard Worker
150*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream);
151*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx * ctx)152*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
153*6236dae4SAndroid Build Coastguard Worker {
154*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!ctx->initialized);
155*6236dae4SAndroid Build Coastguard Worker ctx->qlogfd = -1;
156*6236dae4SAndroid Build Coastguard Worker ctx->version = NGTCP2_PROTO_VER_MAX;
157*6236dae4SAndroid Build Coastguard Worker ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
158*6236dae4SAndroid Build Coastguard Worker ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
159*6236dae4SAndroid Build Coastguard Worker Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
160*6236dae4SAndroid Build Coastguard Worker H3_STREAM_POOL_SPARES);
161*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
162*6236dae4SAndroid Build Coastguard Worker Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
163*6236dae4SAndroid Build Coastguard Worker ctx->initialized = TRUE;
164*6236dae4SAndroid Build Coastguard Worker }
165*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx * ctx)166*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx)
167*6236dae4SAndroid Build Coastguard Worker {
168*6236dae4SAndroid Build Coastguard Worker if(ctx && ctx->initialized) {
169*6236dae4SAndroid Build Coastguard Worker Curl_bufcp_free(&ctx->stream_bufcp);
170*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&ctx->scratch);
171*6236dae4SAndroid Build Coastguard Worker Curl_hash_clean(&ctx->streams);
172*6236dae4SAndroid Build Coastguard Worker Curl_hash_destroy(&ctx->streams);
173*6236dae4SAndroid Build Coastguard Worker Curl_ssl_peer_cleanup(&ctx->peer);
174*6236dae4SAndroid Build Coastguard Worker }
175*6236dae4SAndroid Build Coastguard Worker free(ctx);
176*6236dae4SAndroid Build Coastguard Worker }
177*6236dae4SAndroid Build Coastguard Worker
178*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx;
179*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
180*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
181*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx);
182*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
183*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
184*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx);
185*6236dae4SAndroid Build Coastguard Worker
186*6236dae4SAndroid Build Coastguard Worker /**
187*6236dae4SAndroid Build Coastguard Worker * All about the H3 internals of a stream
188*6236dae4SAndroid Build Coastguard Worker */
189*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx {
190*6236dae4SAndroid Build Coastguard Worker curl_int64_t id; /* HTTP/3 protocol identifier */
191*6236dae4SAndroid Build Coastguard Worker struct bufq sendbuf; /* h3 request body */
192*6236dae4SAndroid Build Coastguard Worker struct h1_req_parser h1; /* h1 request parsing */
193*6236dae4SAndroid Build Coastguard Worker size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
194*6236dae4SAndroid Build Coastguard Worker curl_uint64_t error3; /* HTTP/3 stream error code */
195*6236dae4SAndroid Build Coastguard Worker curl_off_t upload_left; /* number of request bytes left to upload */
196*6236dae4SAndroid Build Coastguard Worker int status_code; /* HTTP status code */
197*6236dae4SAndroid Build Coastguard Worker CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
198*6236dae4SAndroid Build Coastguard Worker bool resp_hds_complete; /* we have a complete, final response */
199*6236dae4SAndroid Build Coastguard Worker bool closed; /* TRUE on stream close */
200*6236dae4SAndroid Build Coastguard Worker bool reset; /* TRUE on stream reset */
201*6236dae4SAndroid Build Coastguard Worker bool send_closed; /* stream is local closed */
202*6236dae4SAndroid Build Coastguard Worker BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
203*6236dae4SAndroid Build Coastguard Worker };
204*6236dae4SAndroid Build Coastguard Worker
205*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
206*6236dae4SAndroid Build Coastguard Worker data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
207*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CTX_ID(ctx,id) ((struct h3_stream_ctx *)(\
208*6236dae4SAndroid Build Coastguard Worker Curl_hash_offt_get(&(ctx)->streams, (id))))
209*6236dae4SAndroid Build Coastguard Worker
h3_stream_ctx_free(struct h3_stream_ctx * stream)210*6236dae4SAndroid Build Coastguard Worker static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
211*6236dae4SAndroid Build Coastguard Worker {
212*6236dae4SAndroid Build Coastguard Worker Curl_bufq_free(&stream->sendbuf);
213*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_free(&stream->h1);
214*6236dae4SAndroid Build Coastguard Worker free(stream);
215*6236dae4SAndroid Build Coastguard Worker }
216*6236dae4SAndroid Build Coastguard Worker
h3_stream_hash_free(void * stream)217*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream)
218*6236dae4SAndroid Build Coastguard Worker {
219*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
220*6236dae4SAndroid Build Coastguard Worker h3_stream_ctx_free((struct h3_stream_ctx *)stream);
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker
h3_data_setup(struct Curl_cfilter * cf,struct Curl_easy * data)223*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_setup(struct Curl_cfilter *cf,
224*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
225*6236dae4SAndroid Build Coastguard Worker {
226*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
227*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
228*6236dae4SAndroid Build Coastguard Worker
229*6236dae4SAndroid Build Coastguard Worker if(!data)
230*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
231*6236dae4SAndroid Build Coastguard Worker
232*6236dae4SAndroid Build Coastguard Worker if(stream)
233*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
234*6236dae4SAndroid Build Coastguard Worker
235*6236dae4SAndroid Build Coastguard Worker stream = calloc(1, sizeof(*stream));
236*6236dae4SAndroid Build Coastguard Worker if(!stream)
237*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
238*6236dae4SAndroid Build Coastguard Worker
239*6236dae4SAndroid Build Coastguard Worker stream->id = -1;
240*6236dae4SAndroid Build Coastguard Worker /* on send, we control how much we put into the buffer */
241*6236dae4SAndroid Build Coastguard Worker Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
242*6236dae4SAndroid Build Coastguard Worker H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
243*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight = 0;
244*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
245*6236dae4SAndroid Build Coastguard Worker
246*6236dae4SAndroid Build Coastguard Worker if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
247*6236dae4SAndroid Build Coastguard Worker h3_stream_ctx_free(stream);
248*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
249*6236dae4SAndroid Build Coastguard Worker }
250*6236dae4SAndroid Build Coastguard Worker
251*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
252*6236dae4SAndroid Build Coastguard Worker }
253*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_stream_close(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream)254*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf,
255*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
256*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream)
257*6236dae4SAndroid Build Coastguard Worker {
258*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
259*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
260*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
261*6236dae4SAndroid Build Coastguard Worker if(!stream->closed && ctx->qconn && ctx->h3conn) {
262*6236dae4SAndroid Build Coastguard Worker CURLcode result;
263*6236dae4SAndroid Build Coastguard Worker
264*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
265*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
266*6236dae4SAndroid Build Coastguard Worker stream->closed = TRUE;
267*6236dae4SAndroid Build Coastguard Worker (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id,
268*6236dae4SAndroid Build Coastguard Worker NGHTTP3_H3_REQUEST_CANCELLED);
269*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, NULL);
270*6236dae4SAndroid Build Coastguard Worker if(result)
271*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cancel stream -> %d",
272*6236dae4SAndroid Build Coastguard Worker stream->id, result);
273*6236dae4SAndroid Build Coastguard Worker }
274*6236dae4SAndroid Build Coastguard Worker }
275*6236dae4SAndroid Build Coastguard Worker
h3_data_done(struct Curl_cfilter * cf,struct Curl_easy * data)276*6236dae4SAndroid Build Coastguard Worker static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
277*6236dae4SAndroid Build Coastguard Worker {
278*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
279*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
280*6236dae4SAndroid Build Coastguard Worker (void)cf;
281*6236dae4SAndroid Build Coastguard Worker if(stream) {
282*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] easy handle is done",
283*6236dae4SAndroid Build Coastguard Worker stream->id);
284*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_stream_close(cf, data, stream);
285*6236dae4SAndroid Build Coastguard Worker Curl_hash_offt_remove(&ctx->streams, data->mid);
286*6236dae4SAndroid Build Coastguard Worker }
287*6236dae4SAndroid Build Coastguard Worker }
288*6236dae4SAndroid Build Coastguard Worker
get_stream_easy(struct Curl_cfilter * cf,struct Curl_easy * data,int64_t stream_id,struct h3_stream_ctx ** pstream)289*6236dae4SAndroid Build Coastguard Worker static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
290*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
291*6236dae4SAndroid Build Coastguard Worker int64_t stream_id,
292*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx **pstream)
293*6236dae4SAndroid Build Coastguard Worker {
294*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
295*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream;
296*6236dae4SAndroid Build Coastguard Worker
297*6236dae4SAndroid Build Coastguard Worker (void)cf;
298*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, data);
299*6236dae4SAndroid Build Coastguard Worker if(stream && stream->id == stream_id) {
300*6236dae4SAndroid Build Coastguard Worker *pstream = stream;
301*6236dae4SAndroid Build Coastguard Worker return data;
302*6236dae4SAndroid Build Coastguard Worker }
303*6236dae4SAndroid Build Coastguard Worker else {
304*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
305*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data->multi);
306*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
307*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *sdata = Curl_node_elem(e);
308*6236dae4SAndroid Build Coastguard Worker if(sdata->conn != data->conn)
309*6236dae4SAndroid Build Coastguard Worker continue;
310*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, sdata);
311*6236dae4SAndroid Build Coastguard Worker if(stream && stream->id == stream_id) {
312*6236dae4SAndroid Build Coastguard Worker *pstream = stream;
313*6236dae4SAndroid Build Coastguard Worker return sdata;
314*6236dae4SAndroid Build Coastguard Worker }
315*6236dae4SAndroid Build Coastguard Worker }
316*6236dae4SAndroid Build Coastguard Worker }
317*6236dae4SAndroid Build Coastguard Worker *pstream = NULL;
318*6236dae4SAndroid Build Coastguard Worker return NULL;
319*6236dae4SAndroid Build Coastguard Worker }
320*6236dae4SAndroid Build Coastguard Worker
h3_drain_stream(struct Curl_cfilter * cf,struct Curl_easy * data)321*6236dae4SAndroid Build Coastguard Worker static void h3_drain_stream(struct Curl_cfilter *cf,
322*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
323*6236dae4SAndroid Build Coastguard Worker {
324*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
325*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
326*6236dae4SAndroid Build Coastguard Worker unsigned char bits;
327*6236dae4SAndroid Build Coastguard Worker
328*6236dae4SAndroid Build Coastguard Worker (void)cf;
329*6236dae4SAndroid Build Coastguard Worker bits = CURL_CSELECT_IN;
330*6236dae4SAndroid Build Coastguard Worker if(stream && stream->upload_left && !stream->send_closed)
331*6236dae4SAndroid Build Coastguard Worker bits |= CURL_CSELECT_OUT;
332*6236dae4SAndroid Build Coastguard Worker if(data->state.select_bits != bits) {
333*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = bits;
334*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 0, EXPIRE_RUN_NOW);
335*6236dae4SAndroid Build Coastguard Worker }
336*6236dae4SAndroid Build Coastguard Worker }
337*6236dae4SAndroid Build Coastguard Worker
338*6236dae4SAndroid Build Coastguard Worker /* ngtcp2 default congestion controller does not perform pacing. Limit
339*6236dae4SAndroid Build Coastguard Worker the maximum packet burst to MAX_PKT_BURST packets. */
340*6236dae4SAndroid Build Coastguard Worker #define MAX_PKT_BURST 10
341*6236dae4SAndroid Build Coastguard Worker
342*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx {
343*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf;
344*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data;
345*6236dae4SAndroid Build Coastguard Worker ngtcp2_tstamp ts;
346*6236dae4SAndroid Build Coastguard Worker ngtcp2_path_storage ps;
347*6236dae4SAndroid Build Coastguard Worker };
348*6236dae4SAndroid Build Coastguard Worker
pktx_update_time(struct pkt_io_ctx * pktx,struct Curl_cfilter * cf)349*6236dae4SAndroid Build Coastguard Worker static void pktx_update_time(struct pkt_io_ctx *pktx,
350*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf)
351*6236dae4SAndroid Build Coastguard Worker {
352*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
353*6236dae4SAndroid Build Coastguard Worker
354*6236dae4SAndroid Build Coastguard Worker vquic_ctx_update_time(&ctx->q);
355*6236dae4SAndroid Build Coastguard Worker pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
356*6236dae4SAndroid Build Coastguard Worker (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
357*6236dae4SAndroid Build Coastguard Worker }
358*6236dae4SAndroid Build Coastguard Worker
pktx_init(struct pkt_io_ctx * pktx,struct Curl_cfilter * cf,struct Curl_easy * data)359*6236dae4SAndroid Build Coastguard Worker static void pktx_init(struct pkt_io_ctx *pktx,
360*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf,
361*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
362*6236dae4SAndroid Build Coastguard Worker {
363*6236dae4SAndroid Build Coastguard Worker pktx->cf = cf;
364*6236dae4SAndroid Build Coastguard Worker pktx->data = data;
365*6236dae4SAndroid Build Coastguard Worker ngtcp2_path_storage_zero(&pktx->ps);
366*6236dae4SAndroid Build Coastguard Worker pktx_update_time(pktx, cf);
367*6236dae4SAndroid Build Coastguard Worker }
368*6236dae4SAndroid Build Coastguard Worker
369*6236dae4SAndroid Build Coastguard Worker static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
370*6236dae4SAndroid Build Coastguard Worker uint64_t datalen, void *user_data,
371*6236dae4SAndroid Build Coastguard Worker void *stream_user_data);
372*6236dae4SAndroid Build Coastguard Worker
get_conn(ngtcp2_crypto_conn_ref * conn_ref)373*6236dae4SAndroid Build Coastguard Worker static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
374*6236dae4SAndroid Build Coastguard Worker {
375*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = conn_ref->user_data;
376*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
377*6236dae4SAndroid Build Coastguard Worker return ctx->qconn;
378*6236dae4SAndroid Build Coastguard Worker }
379*6236dae4SAndroid Build Coastguard Worker
380*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUG_NGTCP2
quic_printf(void * user_data,const char * fmt,...)381*6236dae4SAndroid Build Coastguard Worker static void quic_printf(void *user_data, const char *fmt, ...)
382*6236dae4SAndroid Build Coastguard Worker {
383*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
384*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
385*6236dae4SAndroid Build Coastguard Worker
386*6236dae4SAndroid Build Coastguard Worker (void)ctx; /* TODO: need an easy handle to infof() message */
387*6236dae4SAndroid Build Coastguard Worker va_list ap;
388*6236dae4SAndroid Build Coastguard Worker va_start(ap, fmt);
389*6236dae4SAndroid Build Coastguard Worker vfprintf(stderr, fmt, ap);
390*6236dae4SAndroid Build Coastguard Worker va_end(ap);
391*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "\n");
392*6236dae4SAndroid Build Coastguard Worker }
393*6236dae4SAndroid Build Coastguard Worker #endif
394*6236dae4SAndroid Build Coastguard Worker
qlog_callback(void * user_data,uint32_t flags,const void * data,size_t datalen)395*6236dae4SAndroid Build Coastguard Worker static void qlog_callback(void *user_data, uint32_t flags,
396*6236dae4SAndroid Build Coastguard Worker const void *data, size_t datalen)
397*6236dae4SAndroid Build Coastguard Worker {
398*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
399*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
400*6236dae4SAndroid Build Coastguard Worker (void)flags;
401*6236dae4SAndroid Build Coastguard Worker if(ctx->qlogfd != -1) {
402*6236dae4SAndroid Build Coastguard Worker ssize_t rc = write(ctx->qlogfd, data, datalen);
403*6236dae4SAndroid Build Coastguard Worker if(rc == -1) {
404*6236dae4SAndroid Build Coastguard Worker /* on write error, stop further write attempts */
405*6236dae4SAndroid Build Coastguard Worker close(ctx->qlogfd);
406*6236dae4SAndroid Build Coastguard Worker ctx->qlogfd = -1;
407*6236dae4SAndroid Build Coastguard Worker }
408*6236dae4SAndroid Build Coastguard Worker }
409*6236dae4SAndroid Build Coastguard Worker
410*6236dae4SAndroid Build Coastguard Worker }
411*6236dae4SAndroid Build Coastguard Worker
quic_settings(struct cf_ngtcp2_ctx * ctx,struct Curl_easy * data,struct pkt_io_ctx * pktx)412*6236dae4SAndroid Build Coastguard Worker static void quic_settings(struct cf_ngtcp2_ctx *ctx,
413*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
414*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx)
415*6236dae4SAndroid Build Coastguard Worker {
416*6236dae4SAndroid Build Coastguard Worker ngtcp2_settings *s = &ctx->settings;
417*6236dae4SAndroid Build Coastguard Worker ngtcp2_transport_params *t = &ctx->transport_params;
418*6236dae4SAndroid Build Coastguard Worker
419*6236dae4SAndroid Build Coastguard Worker ngtcp2_settings_default(s);
420*6236dae4SAndroid Build Coastguard Worker ngtcp2_transport_params_default(t);
421*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUG_NGTCP2
422*6236dae4SAndroid Build Coastguard Worker s->log_printf = quic_printf;
423*6236dae4SAndroid Build Coastguard Worker #else
424*6236dae4SAndroid Build Coastguard Worker s->log_printf = NULL;
425*6236dae4SAndroid Build Coastguard Worker #endif
426*6236dae4SAndroid Build Coastguard Worker
427*6236dae4SAndroid Build Coastguard Worker (void)data;
428*6236dae4SAndroid Build Coastguard Worker s->initial_ts = pktx->ts;
429*6236dae4SAndroid Build Coastguard Worker s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT;
430*6236dae4SAndroid Build Coastguard Worker s->max_window = 100 * ctx->max_stream_window;
431*6236dae4SAndroid Build Coastguard Worker s->max_stream_window = 10 * ctx->max_stream_window;
432*6236dae4SAndroid Build Coastguard Worker
433*6236dae4SAndroid Build Coastguard Worker t->initial_max_data = 10 * ctx->max_stream_window;
434*6236dae4SAndroid Build Coastguard Worker t->initial_max_stream_data_bidi_local = ctx->max_stream_window;
435*6236dae4SAndroid Build Coastguard Worker t->initial_max_stream_data_bidi_remote = ctx->max_stream_window;
436*6236dae4SAndroid Build Coastguard Worker t->initial_max_stream_data_uni = ctx->max_stream_window;
437*6236dae4SAndroid Build Coastguard Worker t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
438*6236dae4SAndroid Build Coastguard Worker t->initial_max_streams_uni = QUIC_MAX_STREAMS;
439*6236dae4SAndroid Build Coastguard Worker t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
440*6236dae4SAndroid Build Coastguard Worker if(ctx->qlogfd != -1) {
441*6236dae4SAndroid Build Coastguard Worker s->qlog_write = qlog_callback;
442*6236dae4SAndroid Build Coastguard Worker }
443*6236dae4SAndroid Build Coastguard Worker }
444*6236dae4SAndroid Build Coastguard Worker
445*6236dae4SAndroid Build Coastguard Worker static CURLcode init_ngh3_conn(struct Curl_cfilter *cf);
446*6236dae4SAndroid Build Coastguard Worker
cb_handshake_completed(ngtcp2_conn * tconn,void * user_data)447*6236dae4SAndroid Build Coastguard Worker static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
448*6236dae4SAndroid Build Coastguard Worker {
449*6236dae4SAndroid Build Coastguard Worker (void)user_data;
450*6236dae4SAndroid Build Coastguard Worker (void)tconn;
451*6236dae4SAndroid Build Coastguard Worker return 0;
452*6236dae4SAndroid Build Coastguard Worker }
453*6236dae4SAndroid Build Coastguard Worker
454*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
455*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data);
456*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_err_is_fatal(int code)457*6236dae4SAndroid Build Coastguard Worker static bool cf_ngtcp2_err_is_fatal(int code)
458*6236dae4SAndroid Build Coastguard Worker {
459*6236dae4SAndroid Build Coastguard Worker return (NGTCP2_ERR_FATAL >= code) ||
460*6236dae4SAndroid Build Coastguard Worker (NGTCP2_ERR_DROP_CONN == code) ||
461*6236dae4SAndroid Build Coastguard Worker (NGTCP2_ERR_IDLE_CLOSE == code);
462*6236dae4SAndroid Build Coastguard Worker }
463*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_err_set(struct Curl_cfilter * cf,struct Curl_easy * data,int code)464*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_err_set(struct Curl_cfilter *cf,
465*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, int code)
466*6236dae4SAndroid Build Coastguard Worker {
467*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
468*6236dae4SAndroid Build Coastguard Worker if(!ctx->last_error.error_code) {
469*6236dae4SAndroid Build Coastguard Worker if(NGTCP2_ERR_CRYPTO == code) {
470*6236dae4SAndroid Build Coastguard Worker ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
471*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_get_tls_alert(ctx->qconn),
472*6236dae4SAndroid Build Coastguard Worker NULL, 0);
473*6236dae4SAndroid Build Coastguard Worker }
474*6236dae4SAndroid Build Coastguard Worker else {
475*6236dae4SAndroid Build Coastguard Worker ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0);
476*6236dae4SAndroid Build Coastguard Worker }
477*6236dae4SAndroid Build Coastguard Worker }
478*6236dae4SAndroid Build Coastguard Worker if(cf_ngtcp2_err_is_fatal(code))
479*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_conn_close(cf, data);
480*6236dae4SAndroid Build Coastguard Worker }
481*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_h3_err_is_fatal(int code)482*6236dae4SAndroid Build Coastguard Worker static bool cf_ngtcp2_h3_err_is_fatal(int code)
483*6236dae4SAndroid Build Coastguard Worker {
484*6236dae4SAndroid Build Coastguard Worker return (NGHTTP3_ERR_FATAL >= code) ||
485*6236dae4SAndroid Build Coastguard Worker (NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM == code);
486*6236dae4SAndroid Build Coastguard Worker }
487*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_h3_err_set(struct Curl_cfilter * cf,struct Curl_easy * data,int code)488*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf,
489*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, int code)
490*6236dae4SAndroid Build Coastguard Worker {
491*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
492*6236dae4SAndroid Build Coastguard Worker if(!ctx->last_error.error_code) {
493*6236dae4SAndroid Build Coastguard Worker ngtcp2_ccerr_set_application_error(&ctx->last_error,
494*6236dae4SAndroid Build Coastguard Worker nghttp3_err_infer_quic_app_error_code(code), NULL, 0);
495*6236dae4SAndroid Build Coastguard Worker }
496*6236dae4SAndroid Build Coastguard Worker if(cf_ngtcp2_h3_err_is_fatal(code))
497*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_conn_close(cf, data);
498*6236dae4SAndroid Build Coastguard Worker }
499*6236dae4SAndroid Build Coastguard Worker
cb_recv_stream_data(ngtcp2_conn * tconn,uint32_t flags,int64_t sid,uint64_t offset,const uint8_t * buf,size_t buflen,void * user_data,void * stream_user_data)500*6236dae4SAndroid Build Coastguard Worker static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
501*6236dae4SAndroid Build Coastguard Worker int64_t sid, uint64_t offset,
502*6236dae4SAndroid Build Coastguard Worker const uint8_t *buf, size_t buflen,
503*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
504*6236dae4SAndroid Build Coastguard Worker {
505*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
506*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
507*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
508*6236dae4SAndroid Build Coastguard Worker nghttp3_ssize nconsumed;
509*6236dae4SAndroid Build Coastguard Worker int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
510*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
511*6236dae4SAndroid Build Coastguard Worker (void)offset;
512*6236dae4SAndroid Build Coastguard Worker (void)data;
513*6236dae4SAndroid Build Coastguard Worker
514*6236dae4SAndroid Build Coastguard Worker nconsumed =
515*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
516*6236dae4SAndroid Build Coastguard Worker if(!data)
517*6236dae4SAndroid Build Coastguard Worker data = CF_DATA_CURRENT(cf);
518*6236dae4SAndroid Build Coastguard Worker if(data)
519*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read_stream(len=%zu) -> %zd",
520*6236dae4SAndroid Build Coastguard Worker stream_id, buflen, nconsumed);
521*6236dae4SAndroid Build Coastguard Worker if(nconsumed < 0) {
522*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX_ID(ctx, stream_id);
523*6236dae4SAndroid Build Coastguard Worker if(data && stream) {
524*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] error on known stream, "
525*6236dae4SAndroid Build Coastguard Worker "reset=%d, closed=%d",
526*6236dae4SAndroid Build Coastguard Worker stream_id, stream->reset, stream->closed);
527*6236dae4SAndroid Build Coastguard Worker }
528*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
529*6236dae4SAndroid Build Coastguard Worker }
530*6236dae4SAndroid Build Coastguard Worker
531*6236dae4SAndroid Build Coastguard Worker /* number of bytes inside buflen which consists of framing overhead
532*6236dae4SAndroid Build Coastguard Worker * including QPACK HEADERS. In other words, it does not consume payload of
533*6236dae4SAndroid Build Coastguard Worker * DATA frame. */
534*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, (uint64_t)nconsumed);
535*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_offset(tconn, (uint64_t)nconsumed);
536*6236dae4SAndroid Build Coastguard Worker
537*6236dae4SAndroid Build Coastguard Worker return 0;
538*6236dae4SAndroid Build Coastguard Worker }
539*6236dae4SAndroid Build Coastguard Worker
540*6236dae4SAndroid Build Coastguard Worker static int
cb_acked_stream_data_offset(ngtcp2_conn * tconn,int64_t stream_id,uint64_t offset,uint64_t datalen,void * user_data,void * stream_user_data)541*6236dae4SAndroid Build Coastguard Worker cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
542*6236dae4SAndroid Build Coastguard Worker uint64_t offset, uint64_t datalen, void *user_data,
543*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
544*6236dae4SAndroid Build Coastguard Worker {
545*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
546*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
547*6236dae4SAndroid Build Coastguard Worker int rv;
548*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
549*6236dae4SAndroid Build Coastguard Worker (void)tconn;
550*6236dae4SAndroid Build Coastguard Worker (void)offset;
551*6236dae4SAndroid Build Coastguard Worker (void)datalen;
552*6236dae4SAndroid Build Coastguard Worker (void)stream_user_data;
553*6236dae4SAndroid Build Coastguard Worker
554*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen);
555*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
556*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
557*6236dae4SAndroid Build Coastguard Worker }
558*6236dae4SAndroid Build Coastguard Worker
559*6236dae4SAndroid Build Coastguard Worker return 0;
560*6236dae4SAndroid Build Coastguard Worker }
561*6236dae4SAndroid Build Coastguard Worker
cb_stream_close(ngtcp2_conn * tconn,uint32_t flags,int64_t sid,uint64_t app_error_code,void * user_data,void * stream_user_data)562*6236dae4SAndroid Build Coastguard Worker static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
563*6236dae4SAndroid Build Coastguard Worker int64_t sid, uint64_t app_error_code,
564*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
565*6236dae4SAndroid Build Coastguard Worker {
566*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
567*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
568*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
569*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
570*6236dae4SAndroid Build Coastguard Worker int rv;
571*6236dae4SAndroid Build Coastguard Worker
572*6236dae4SAndroid Build Coastguard Worker (void)tconn;
573*6236dae4SAndroid Build Coastguard Worker /* stream is closed... */
574*6236dae4SAndroid Build Coastguard Worker if(!data)
575*6236dae4SAndroid Build Coastguard Worker data = CF_DATA_CURRENT(cf);
576*6236dae4SAndroid Build Coastguard Worker if(!data)
577*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
578*6236dae4SAndroid Build Coastguard Worker
579*6236dae4SAndroid Build Coastguard Worker if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
580*6236dae4SAndroid Build Coastguard Worker app_error_code = NGHTTP3_H3_NO_ERROR;
581*6236dae4SAndroid Build Coastguard Worker }
582*6236dae4SAndroid Build Coastguard Worker
583*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code);
584*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] quic close(app_error=%"
585*6236dae4SAndroid Build Coastguard Worker FMT_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code,
586*6236dae4SAndroid Build Coastguard Worker rv);
587*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
588*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_h3_err_set(cf, data, rv);
589*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
590*6236dae4SAndroid Build Coastguard Worker }
591*6236dae4SAndroid Build Coastguard Worker
592*6236dae4SAndroid Build Coastguard Worker return 0;
593*6236dae4SAndroid Build Coastguard Worker }
594*6236dae4SAndroid Build Coastguard Worker
cb_stream_reset(ngtcp2_conn * tconn,int64_t sid,uint64_t final_size,uint64_t app_error_code,void * user_data,void * stream_user_data)595*6236dae4SAndroid Build Coastguard Worker static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid,
596*6236dae4SAndroid Build Coastguard Worker uint64_t final_size, uint64_t app_error_code,
597*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
598*6236dae4SAndroid Build Coastguard Worker {
599*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
600*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
601*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
602*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
603*6236dae4SAndroid Build Coastguard Worker int rv;
604*6236dae4SAndroid Build Coastguard Worker (void)tconn;
605*6236dae4SAndroid Build Coastguard Worker (void)final_size;
606*6236dae4SAndroid Build Coastguard Worker (void)app_error_code;
607*6236dae4SAndroid Build Coastguard Worker (void)data;
608*6236dae4SAndroid Build Coastguard Worker
609*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
610*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
611*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
612*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
613*6236dae4SAndroid Build Coastguard Worker }
614*6236dae4SAndroid Build Coastguard Worker
615*6236dae4SAndroid Build Coastguard Worker return 0;
616*6236dae4SAndroid Build Coastguard Worker }
617*6236dae4SAndroid Build Coastguard Worker
cb_stream_stop_sending(ngtcp2_conn * tconn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)618*6236dae4SAndroid Build Coastguard Worker static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
619*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
620*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
621*6236dae4SAndroid Build Coastguard Worker {
622*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
623*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
624*6236dae4SAndroid Build Coastguard Worker int rv;
625*6236dae4SAndroid Build Coastguard Worker (void)tconn;
626*6236dae4SAndroid Build Coastguard Worker (void)app_error_code;
627*6236dae4SAndroid Build Coastguard Worker (void)stream_user_data;
628*6236dae4SAndroid Build Coastguard Worker
629*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
630*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
631*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
632*6236dae4SAndroid Build Coastguard Worker }
633*6236dae4SAndroid Build Coastguard Worker
634*6236dae4SAndroid Build Coastguard Worker return 0;
635*6236dae4SAndroid Build Coastguard Worker }
636*6236dae4SAndroid Build Coastguard Worker
cb_extend_max_local_streams_bidi(ngtcp2_conn * tconn,uint64_t max_streams,void * user_data)637*6236dae4SAndroid Build Coastguard Worker static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
638*6236dae4SAndroid Build Coastguard Worker uint64_t max_streams,
639*6236dae4SAndroid Build Coastguard Worker void *user_data)
640*6236dae4SAndroid Build Coastguard Worker {
641*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
642*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
643*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = CF_DATA_CURRENT(cf);
644*6236dae4SAndroid Build Coastguard Worker
645*6236dae4SAndroid Build Coastguard Worker (void)tconn;
646*6236dae4SAndroid Build Coastguard Worker ctx->max_bidi_streams = max_streams;
647*6236dae4SAndroid Build Coastguard Worker if(data)
648*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "max bidi streams now %" FMT_PRIu64
649*6236dae4SAndroid Build Coastguard Worker ", used %" FMT_PRIu64, (curl_uint64_t)ctx->max_bidi_streams,
650*6236dae4SAndroid Build Coastguard Worker (curl_uint64_t)ctx->used_bidi_streams);
651*6236dae4SAndroid Build Coastguard Worker return 0;
652*6236dae4SAndroid Build Coastguard Worker }
653*6236dae4SAndroid Build Coastguard Worker
cb_extend_max_stream_data(ngtcp2_conn * tconn,int64_t sid,uint64_t max_data,void * user_data,void * stream_user_data)654*6236dae4SAndroid Build Coastguard Worker static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
655*6236dae4SAndroid Build Coastguard Worker uint64_t max_data, void *user_data,
656*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
657*6236dae4SAndroid Build Coastguard Worker {
658*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
659*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
660*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
661*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = CF_DATA_CURRENT(cf);
662*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *s_data;
663*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream;
664*6236dae4SAndroid Build Coastguard Worker int rv;
665*6236dae4SAndroid Build Coastguard Worker (void)tconn;
666*6236dae4SAndroid Build Coastguard Worker (void)max_data;
667*6236dae4SAndroid Build Coastguard Worker (void)stream_user_data;
668*6236dae4SAndroid Build Coastguard Worker
669*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
670*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
671*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
672*6236dae4SAndroid Build Coastguard Worker }
673*6236dae4SAndroid Build Coastguard Worker s_data = get_stream_easy(cf, data, stream_id, &stream);
674*6236dae4SAndroid Build Coastguard Worker if(s_data && stream && stream->quic_flow_blocked) {
675*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", stream_id);
676*6236dae4SAndroid Build Coastguard Worker stream->quic_flow_blocked = FALSE;
677*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, s_data);
678*6236dae4SAndroid Build Coastguard Worker }
679*6236dae4SAndroid Build Coastguard Worker return 0;
680*6236dae4SAndroid Build Coastguard Worker }
681*6236dae4SAndroid Build Coastguard Worker
cb_rand(uint8_t * dest,size_t destlen,const ngtcp2_rand_ctx * rand_ctx)682*6236dae4SAndroid Build Coastguard Worker static void cb_rand(uint8_t *dest, size_t destlen,
683*6236dae4SAndroid Build Coastguard Worker const ngtcp2_rand_ctx *rand_ctx)
684*6236dae4SAndroid Build Coastguard Worker {
685*6236dae4SAndroid Build Coastguard Worker CURLcode result;
686*6236dae4SAndroid Build Coastguard Worker (void)rand_ctx;
687*6236dae4SAndroid Build Coastguard Worker
688*6236dae4SAndroid Build Coastguard Worker result = Curl_rand(NULL, dest, destlen);
689*6236dae4SAndroid Build Coastguard Worker if(result) {
690*6236dae4SAndroid Build Coastguard Worker /* cb_rand is only used for non-cryptographic context. If Curl_rand
691*6236dae4SAndroid Build Coastguard Worker failed, just fill 0 and call it *random*. */
692*6236dae4SAndroid Build Coastguard Worker memset(dest, 0, destlen);
693*6236dae4SAndroid Build Coastguard Worker }
694*6236dae4SAndroid Build Coastguard Worker }
695*6236dae4SAndroid Build Coastguard Worker
cb_get_new_connection_id(ngtcp2_conn * tconn,ngtcp2_cid * cid,uint8_t * token,size_t cidlen,void * user_data)696*6236dae4SAndroid Build Coastguard Worker static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
697*6236dae4SAndroid Build Coastguard Worker uint8_t *token, size_t cidlen,
698*6236dae4SAndroid Build Coastguard Worker void *user_data)
699*6236dae4SAndroid Build Coastguard Worker {
700*6236dae4SAndroid Build Coastguard Worker CURLcode result;
701*6236dae4SAndroid Build Coastguard Worker (void)tconn;
702*6236dae4SAndroid Build Coastguard Worker (void)user_data;
703*6236dae4SAndroid Build Coastguard Worker
704*6236dae4SAndroid Build Coastguard Worker result = Curl_rand(NULL, cid->data, cidlen);
705*6236dae4SAndroid Build Coastguard Worker if(result)
706*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
707*6236dae4SAndroid Build Coastguard Worker cid->datalen = cidlen;
708*6236dae4SAndroid Build Coastguard Worker
709*6236dae4SAndroid Build Coastguard Worker result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
710*6236dae4SAndroid Build Coastguard Worker if(result)
711*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
712*6236dae4SAndroid Build Coastguard Worker
713*6236dae4SAndroid Build Coastguard Worker return 0;
714*6236dae4SAndroid Build Coastguard Worker }
715*6236dae4SAndroid Build Coastguard Worker
cb_recv_rx_key(ngtcp2_conn * tconn,ngtcp2_encryption_level level,void * user_data)716*6236dae4SAndroid Build Coastguard Worker static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
717*6236dae4SAndroid Build Coastguard Worker void *user_data)
718*6236dae4SAndroid Build Coastguard Worker {
719*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
720*6236dae4SAndroid Build Coastguard Worker (void)tconn;
721*6236dae4SAndroid Build Coastguard Worker
722*6236dae4SAndroid Build Coastguard Worker if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) {
723*6236dae4SAndroid Build Coastguard Worker return 0;
724*6236dae4SAndroid Build Coastguard Worker }
725*6236dae4SAndroid Build Coastguard Worker
726*6236dae4SAndroid Build Coastguard Worker if(init_ngh3_conn(cf) != CURLE_OK) {
727*6236dae4SAndroid Build Coastguard Worker return NGTCP2_ERR_CALLBACK_FAILURE;
728*6236dae4SAndroid Build Coastguard Worker }
729*6236dae4SAndroid Build Coastguard Worker
730*6236dae4SAndroid Build Coastguard Worker return 0;
731*6236dae4SAndroid Build Coastguard Worker }
732*6236dae4SAndroid Build Coastguard Worker
733*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && defined(_DLL)
734*6236dae4SAndroid Build Coastguard Worker # pragma warning(push)
735*6236dae4SAndroid Build Coastguard Worker # pragma warning(disable:4232) /* MSVC extension, dllimport identity */
736*6236dae4SAndroid Build Coastguard Worker #endif
737*6236dae4SAndroid Build Coastguard Worker
738*6236dae4SAndroid Build Coastguard Worker static ngtcp2_callbacks ng_callbacks = {
739*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_client_initial_cb,
740*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_client_initial */
741*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_recv_crypto_data_cb,
742*6236dae4SAndroid Build Coastguard Worker cb_handshake_completed,
743*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_version_negotiation */
744*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_encrypt_cb,
745*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_decrypt_cb,
746*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_hp_mask_cb,
747*6236dae4SAndroid Build Coastguard Worker cb_recv_stream_data,
748*6236dae4SAndroid Build Coastguard Worker cb_acked_stream_data_offset,
749*6236dae4SAndroid Build Coastguard Worker NULL, /* stream_open */
750*6236dae4SAndroid Build Coastguard Worker cb_stream_close,
751*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_stateless_reset */
752*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_recv_retry_cb,
753*6236dae4SAndroid Build Coastguard Worker cb_extend_max_local_streams_bidi,
754*6236dae4SAndroid Build Coastguard Worker NULL, /* extend_max_local_streams_uni */
755*6236dae4SAndroid Build Coastguard Worker cb_rand,
756*6236dae4SAndroid Build Coastguard Worker cb_get_new_connection_id,
757*6236dae4SAndroid Build Coastguard Worker NULL, /* remove_connection_id */
758*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_update_key_cb, /* update_key */
759*6236dae4SAndroid Build Coastguard Worker NULL, /* path_validation */
760*6236dae4SAndroid Build Coastguard Worker NULL, /* select_preferred_addr */
761*6236dae4SAndroid Build Coastguard Worker cb_stream_reset,
762*6236dae4SAndroid Build Coastguard Worker NULL, /* extend_max_remote_streams_bidi */
763*6236dae4SAndroid Build Coastguard Worker NULL, /* extend_max_remote_streams_uni */
764*6236dae4SAndroid Build Coastguard Worker cb_extend_max_stream_data,
765*6236dae4SAndroid Build Coastguard Worker NULL, /* dcid_status */
766*6236dae4SAndroid Build Coastguard Worker NULL, /* handshake_confirmed */
767*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_new_token */
768*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_delete_crypto_aead_ctx_cb,
769*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
770*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_datagram */
771*6236dae4SAndroid Build Coastguard Worker NULL, /* ack_datagram */
772*6236dae4SAndroid Build Coastguard Worker NULL, /* lost_datagram */
773*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_get_path_challenge_data_cb,
774*6236dae4SAndroid Build Coastguard Worker cb_stream_stop_sending,
775*6236dae4SAndroid Build Coastguard Worker NULL, /* version_negotiation */
776*6236dae4SAndroid Build Coastguard Worker cb_recv_rx_key,
777*6236dae4SAndroid Build Coastguard Worker NULL, /* recv_tx_key */
778*6236dae4SAndroid Build Coastguard Worker NULL, /* early_data_rejected */
779*6236dae4SAndroid Build Coastguard Worker };
780*6236dae4SAndroid Build Coastguard Worker
781*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && defined(_DLL)
782*6236dae4SAndroid Build Coastguard Worker # pragma warning(pop)
783*6236dae4SAndroid Build Coastguard Worker #endif
784*6236dae4SAndroid Build Coastguard Worker
785*6236dae4SAndroid Build Coastguard Worker /**
786*6236dae4SAndroid Build Coastguard Worker * Connection maintenance like timeouts on packet ACKs etc. are done by us, not
787*6236dae4SAndroid Build Coastguard Worker * the OS like for TCP. POLL events on the socket therefore are not
788*6236dae4SAndroid Build Coastguard Worker * sufficient.
789*6236dae4SAndroid Build Coastguard Worker * ngtcp2 tells us when it wants to be invoked again. We handle that via
790*6236dae4SAndroid Build Coastguard Worker * the `Curl_expire()` mechanisms.
791*6236dae4SAndroid Build Coastguard Worker */
check_and_set_expiry(struct Curl_cfilter * cf,struct Curl_easy * data,struct pkt_io_ctx * pktx)792*6236dae4SAndroid Build Coastguard Worker static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
793*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
794*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx)
795*6236dae4SAndroid Build Coastguard Worker {
796*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
797*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx local_pktx;
798*6236dae4SAndroid Build Coastguard Worker ngtcp2_tstamp expiry;
799*6236dae4SAndroid Build Coastguard Worker
800*6236dae4SAndroid Build Coastguard Worker if(!pktx) {
801*6236dae4SAndroid Build Coastguard Worker pktx_init(&local_pktx, cf, data);
802*6236dae4SAndroid Build Coastguard Worker pktx = &local_pktx;
803*6236dae4SAndroid Build Coastguard Worker }
804*6236dae4SAndroid Build Coastguard Worker else {
805*6236dae4SAndroid Build Coastguard Worker pktx_update_time(pktx, cf);
806*6236dae4SAndroid Build Coastguard Worker }
807*6236dae4SAndroid Build Coastguard Worker
808*6236dae4SAndroid Build Coastguard Worker expiry = ngtcp2_conn_get_expiry(ctx->qconn);
809*6236dae4SAndroid Build Coastguard Worker if(expiry != UINT64_MAX) {
810*6236dae4SAndroid Build Coastguard Worker if(expiry <= pktx->ts) {
811*6236dae4SAndroid Build Coastguard Worker CURLcode result;
812*6236dae4SAndroid Build Coastguard Worker int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts);
813*6236dae4SAndroid Build Coastguard Worker if(rv) {
814*6236dae4SAndroid Build Coastguard Worker failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
815*6236dae4SAndroid Build Coastguard Worker ngtcp2_strerror(rv));
816*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_err_set(cf, data, rv);
817*6236dae4SAndroid Build Coastguard Worker return CURLE_SEND_ERROR;
818*6236dae4SAndroid Build Coastguard Worker }
819*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data, pktx);
820*6236dae4SAndroid Build Coastguard Worker if(result)
821*6236dae4SAndroid Build Coastguard Worker return result;
822*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, pktx);
823*6236dae4SAndroid Build Coastguard Worker if(result)
824*6236dae4SAndroid Build Coastguard Worker return result;
825*6236dae4SAndroid Build Coastguard Worker /* ask again, things might have changed */
826*6236dae4SAndroid Build Coastguard Worker expiry = ngtcp2_conn_get_expiry(ctx->qconn);
827*6236dae4SAndroid Build Coastguard Worker }
828*6236dae4SAndroid Build Coastguard Worker
829*6236dae4SAndroid Build Coastguard Worker if(expiry > pktx->ts) {
830*6236dae4SAndroid Build Coastguard Worker ngtcp2_duration timeout = expiry - pktx->ts;
831*6236dae4SAndroid Build Coastguard Worker if(timeout % NGTCP2_MILLISECONDS) {
832*6236dae4SAndroid Build Coastguard Worker timeout += NGTCP2_MILLISECONDS;
833*6236dae4SAndroid Build Coastguard Worker }
834*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, (timediff_t)(timeout / NGTCP2_MILLISECONDS),
835*6236dae4SAndroid Build Coastguard Worker EXPIRE_QUIC);
836*6236dae4SAndroid Build Coastguard Worker }
837*6236dae4SAndroid Build Coastguard Worker }
838*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
839*6236dae4SAndroid Build Coastguard Worker }
840*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)841*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
842*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
843*6236dae4SAndroid Build Coastguard Worker struct easy_pollset *ps)
844*6236dae4SAndroid Build Coastguard Worker {
845*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
846*6236dae4SAndroid Build Coastguard Worker bool want_recv, want_send;
847*6236dae4SAndroid Build Coastguard Worker
848*6236dae4SAndroid Build Coastguard Worker if(!ctx->qconn)
849*6236dae4SAndroid Build Coastguard Worker return;
850*6236dae4SAndroid Build Coastguard Worker
851*6236dae4SAndroid Build Coastguard Worker Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
852*6236dae4SAndroid Build Coastguard Worker if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf))
853*6236dae4SAndroid Build Coastguard Worker want_send = TRUE;
854*6236dae4SAndroid Build Coastguard Worker
855*6236dae4SAndroid Build Coastguard Worker if(want_recv || want_send) {
856*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
857*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
858*6236dae4SAndroid Build Coastguard Worker bool c_exhaust, s_exhaust;
859*6236dae4SAndroid Build Coastguard Worker
860*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
861*6236dae4SAndroid Build Coastguard Worker c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
862*6236dae4SAndroid Build Coastguard Worker !ngtcp2_conn_get_max_data_left(ctx->qconn));
863*6236dae4SAndroid Build Coastguard Worker s_exhaust = want_send && stream && stream->id >= 0 &&
864*6236dae4SAndroid Build Coastguard Worker stream->quic_flow_blocked;
865*6236dae4SAndroid Build Coastguard Worker want_recv = (want_recv || c_exhaust || s_exhaust);
866*6236dae4SAndroid Build Coastguard Worker want_send = (!s_exhaust && want_send) ||
867*6236dae4SAndroid Build Coastguard Worker !Curl_bufq_is_empty(&ctx->q.sendbuf);
868*6236dae4SAndroid Build Coastguard Worker
869*6236dae4SAndroid Build Coastguard Worker Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
870*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
871*6236dae4SAndroid Build Coastguard Worker }
872*6236dae4SAndroid Build Coastguard Worker }
873*6236dae4SAndroid Build Coastguard Worker
cb_h3_stream_close(nghttp3_conn * conn,int64_t sid,uint64_t app_error_code,void * user_data,void * stream_user_data)874*6236dae4SAndroid Build Coastguard Worker static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
875*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
876*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
877*6236dae4SAndroid Build Coastguard Worker {
878*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
879*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
880*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
881*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
882*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
883*6236dae4SAndroid Build Coastguard Worker (void)conn;
884*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
885*6236dae4SAndroid Build Coastguard Worker
886*6236dae4SAndroid Build Coastguard Worker /* we might be called by nghttp3 after we already cleaned up */
887*6236dae4SAndroid Build Coastguard Worker if(!stream)
888*6236dae4SAndroid Build Coastguard Worker return 0;
889*6236dae4SAndroid Build Coastguard Worker
890*6236dae4SAndroid Build Coastguard Worker stream->closed = TRUE;
891*6236dae4SAndroid Build Coastguard Worker stream->error3 = (curl_uint64_t)app_error_code;
892*6236dae4SAndroid Build Coastguard Worker if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
893*6236dae4SAndroid Build Coastguard Worker stream->reset = TRUE;
894*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
895*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
896*6236dae4SAndroid Build Coastguard Worker stream->id, stream->error3);
897*6236dae4SAndroid Build Coastguard Worker }
898*6236dae4SAndroid Build Coastguard Worker else {
899*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id);
900*6236dae4SAndroid Build Coastguard Worker }
901*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
902*6236dae4SAndroid Build Coastguard Worker return 0;
903*6236dae4SAndroid Build Coastguard Worker }
904*6236dae4SAndroid Build Coastguard Worker
h3_xfer_write_resp_hd(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream,const char * buf,size_t blen,bool eos)905*6236dae4SAndroid Build Coastguard Worker static void h3_xfer_write_resp_hd(struct Curl_cfilter *cf,
906*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
907*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream,
908*6236dae4SAndroid Build Coastguard Worker const char *buf, size_t blen, bool eos)
909*6236dae4SAndroid Build Coastguard Worker {
910*6236dae4SAndroid Build Coastguard Worker
911*6236dae4SAndroid Build Coastguard Worker /* If we already encountered an error, skip further writes */
912*6236dae4SAndroid Build Coastguard Worker if(!stream->xfer_result) {
913*6236dae4SAndroid Build Coastguard Worker stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
914*6236dae4SAndroid Build Coastguard Worker if(stream->xfer_result)
915*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu "
916*6236dae4SAndroid Build Coastguard Worker "bytes of headers", stream->id, stream->xfer_result, blen);
917*6236dae4SAndroid Build Coastguard Worker }
918*6236dae4SAndroid Build Coastguard Worker }
919*6236dae4SAndroid Build Coastguard Worker
h3_xfer_write_resp(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream,const char * buf,size_t blen,bool eos)920*6236dae4SAndroid Build Coastguard Worker static void h3_xfer_write_resp(struct Curl_cfilter *cf,
921*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
922*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream,
923*6236dae4SAndroid Build Coastguard Worker const char *buf, size_t blen, bool eos)
924*6236dae4SAndroid Build Coastguard Worker {
925*6236dae4SAndroid Build Coastguard Worker
926*6236dae4SAndroid Build Coastguard Worker /* If we already encountered an error, skip further writes */
927*6236dae4SAndroid Build Coastguard Worker if(!stream->xfer_result) {
928*6236dae4SAndroid Build Coastguard Worker stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
929*6236dae4SAndroid Build Coastguard Worker /* If the transfer write is errored, we do not want any more data */
930*6236dae4SAndroid Build Coastguard Worker if(stream->xfer_result) {
931*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu bytes "
932*6236dae4SAndroid Build Coastguard Worker "of data", stream->id, stream->xfer_result, blen);
933*6236dae4SAndroid Build Coastguard Worker }
934*6236dae4SAndroid Build Coastguard Worker }
935*6236dae4SAndroid Build Coastguard Worker }
936*6236dae4SAndroid Build Coastguard Worker
cb_h3_recv_data(nghttp3_conn * conn,int64_t stream3_id,const uint8_t * buf,size_t blen,void * user_data,void * stream_user_data)937*6236dae4SAndroid Build Coastguard Worker static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
938*6236dae4SAndroid Build Coastguard Worker const uint8_t *buf, size_t blen,
939*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
940*6236dae4SAndroid Build Coastguard Worker {
941*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
942*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
943*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
944*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
945*6236dae4SAndroid Build Coastguard Worker
946*6236dae4SAndroid Build Coastguard Worker (void)conn;
947*6236dae4SAndroid Build Coastguard Worker (void)stream3_id;
948*6236dae4SAndroid Build Coastguard Worker
949*6236dae4SAndroid Build Coastguard Worker if(!stream)
950*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
951*6236dae4SAndroid Build Coastguard Worker
952*6236dae4SAndroid Build Coastguard Worker h3_xfer_write_resp(cf, data, stream, (char *)buf, blen, FALSE);
953*6236dae4SAndroid Build Coastguard Worker if(blen) {
954*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] ACK %zu bytes of DATA",
955*6236dae4SAndroid Build Coastguard Worker stream->id, blen);
956*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
957*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
958*6236dae4SAndroid Build Coastguard Worker }
959*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu", stream->id, blen);
960*6236dae4SAndroid Build Coastguard Worker return 0;
961*6236dae4SAndroid Build Coastguard Worker }
962*6236dae4SAndroid Build Coastguard Worker
cb_h3_deferred_consume(nghttp3_conn * conn,int64_t stream3_id,size_t consumed,void * user_data,void * stream_user_data)963*6236dae4SAndroid Build Coastguard Worker static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id,
964*6236dae4SAndroid Build Coastguard Worker size_t consumed, void *user_data,
965*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
966*6236dae4SAndroid Build Coastguard Worker {
967*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
968*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
969*6236dae4SAndroid Build Coastguard Worker (void)conn;
970*6236dae4SAndroid Build Coastguard Worker (void)stream_user_data;
971*6236dae4SAndroid Build Coastguard Worker
972*6236dae4SAndroid Build Coastguard Worker /* nghttp3 has consumed bytes on the QUIC stream and we need to
973*6236dae4SAndroid Build Coastguard Worker * tell the QUIC connection to increase its flow control */
974*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed);
975*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_extend_max_offset(ctx->qconn, consumed);
976*6236dae4SAndroid Build Coastguard Worker return 0;
977*6236dae4SAndroid Build Coastguard Worker }
978*6236dae4SAndroid Build Coastguard Worker
cb_h3_end_headers(nghttp3_conn * conn,int64_t sid,int fin,void * user_data,void * stream_user_data)979*6236dae4SAndroid Build Coastguard Worker static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
980*6236dae4SAndroid Build Coastguard Worker int fin, void *user_data, void *stream_user_data)
981*6236dae4SAndroid Build Coastguard Worker {
982*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
983*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
984*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
985*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
986*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
987*6236dae4SAndroid Build Coastguard Worker (void)conn;
988*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
989*6236dae4SAndroid Build Coastguard Worker (void)fin;
990*6236dae4SAndroid Build Coastguard Worker (void)cf;
991*6236dae4SAndroid Build Coastguard Worker
992*6236dae4SAndroid Build Coastguard Worker if(!stream)
993*6236dae4SAndroid Build Coastguard Worker return 0;
994*6236dae4SAndroid Build Coastguard Worker /* add a CRLF only if we have received some headers */
995*6236dae4SAndroid Build Coastguard Worker h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
996*6236dae4SAndroid Build Coastguard Worker
997*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
998*6236dae4SAndroid Build Coastguard Worker stream_id, stream->status_code);
999*6236dae4SAndroid Build Coastguard Worker if(stream->status_code / 100 != 1) {
1000*6236dae4SAndroid Build Coastguard Worker stream->resp_hds_complete = TRUE;
1001*6236dae4SAndroid Build Coastguard Worker }
1002*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
1003*6236dae4SAndroid Build Coastguard Worker return 0;
1004*6236dae4SAndroid Build Coastguard Worker }
1005*6236dae4SAndroid Build Coastguard Worker
cb_h3_recv_header(nghttp3_conn * conn,int64_t sid,int32_t token,nghttp3_rcbuf * name,nghttp3_rcbuf * value,uint8_t flags,void * user_data,void * stream_user_data)1006*6236dae4SAndroid Build Coastguard Worker static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
1007*6236dae4SAndroid Build Coastguard Worker int32_t token, nghttp3_rcbuf *name,
1008*6236dae4SAndroid Build Coastguard Worker nghttp3_rcbuf *value, uint8_t flags,
1009*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
1010*6236dae4SAndroid Build Coastguard Worker {
1011*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1012*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1013*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
1014*6236dae4SAndroid Build Coastguard Worker nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
1015*6236dae4SAndroid Build Coastguard Worker nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
1016*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
1017*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1018*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1019*6236dae4SAndroid Build Coastguard Worker (void)conn;
1020*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
1021*6236dae4SAndroid Build Coastguard Worker (void)token;
1022*6236dae4SAndroid Build Coastguard Worker (void)flags;
1023*6236dae4SAndroid Build Coastguard Worker (void)cf;
1024*6236dae4SAndroid Build Coastguard Worker
1025*6236dae4SAndroid Build Coastguard Worker /* we might have cleaned up this transfer already */
1026*6236dae4SAndroid Build Coastguard Worker if(!stream)
1027*6236dae4SAndroid Build Coastguard Worker return 0;
1028*6236dae4SAndroid Build Coastguard Worker
1029*6236dae4SAndroid Build Coastguard Worker if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
1030*6236dae4SAndroid Build Coastguard Worker
1031*6236dae4SAndroid Build Coastguard Worker result = Curl_http_decode_status(&stream->status_code,
1032*6236dae4SAndroid Build Coastguard Worker (const char *)h3val.base, h3val.len);
1033*6236dae4SAndroid Build Coastguard Worker if(result)
1034*6236dae4SAndroid Build Coastguard Worker return -1;
1035*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&ctx->scratch);
1036*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
1037*6236dae4SAndroid Build Coastguard Worker if(!result)
1038*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch,
1039*6236dae4SAndroid Build Coastguard Worker (const char *)h3val.base, h3val.len);
1040*6236dae4SAndroid Build Coastguard Worker if(!result)
1041*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
1042*6236dae4SAndroid Build Coastguard Worker if(!result)
1043*6236dae4SAndroid Build Coastguard Worker h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
1044*6236dae4SAndroid Build Coastguard Worker Curl_dyn_len(&ctx->scratch), FALSE);
1045*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s",
1046*6236dae4SAndroid Build Coastguard Worker stream_id, Curl_dyn_ptr(&ctx->scratch));
1047*6236dae4SAndroid Build Coastguard Worker if(result) {
1048*6236dae4SAndroid Build Coastguard Worker return -1;
1049*6236dae4SAndroid Build Coastguard Worker }
1050*6236dae4SAndroid Build Coastguard Worker }
1051*6236dae4SAndroid Build Coastguard Worker else {
1052*6236dae4SAndroid Build Coastguard Worker /* store as an HTTP1-style header */
1053*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
1054*6236dae4SAndroid Build Coastguard Worker stream_id, (int)h3name.len, h3name.base,
1055*6236dae4SAndroid Build Coastguard Worker (int)h3val.len, h3val.base);
1056*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&ctx->scratch);
1057*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch,
1058*6236dae4SAndroid Build Coastguard Worker (const char *)h3name.base, h3name.len);
1059*6236dae4SAndroid Build Coastguard Worker if(!result)
1060*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
1061*6236dae4SAndroid Build Coastguard Worker if(!result)
1062*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch,
1063*6236dae4SAndroid Build Coastguard Worker (const char *)h3val.base, h3val.len);
1064*6236dae4SAndroid Build Coastguard Worker if(!result)
1065*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
1066*6236dae4SAndroid Build Coastguard Worker if(!result)
1067*6236dae4SAndroid Build Coastguard Worker h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
1068*6236dae4SAndroid Build Coastguard Worker Curl_dyn_len(&ctx->scratch), FALSE);
1069*6236dae4SAndroid Build Coastguard Worker }
1070*6236dae4SAndroid Build Coastguard Worker return 0;
1071*6236dae4SAndroid Build Coastguard Worker }
1072*6236dae4SAndroid Build Coastguard Worker
cb_h3_stop_sending(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)1073*6236dae4SAndroid Build Coastguard Worker static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1074*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
1075*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
1076*6236dae4SAndroid Build Coastguard Worker {
1077*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1078*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1079*6236dae4SAndroid Build Coastguard Worker int rv;
1080*6236dae4SAndroid Build Coastguard Worker (void)conn;
1081*6236dae4SAndroid Build Coastguard Worker (void)stream_user_data;
1082*6236dae4SAndroid Build Coastguard Worker
1083*6236dae4SAndroid Build Coastguard Worker rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
1084*6236dae4SAndroid Build Coastguard Worker app_error_code);
1085*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1086*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1087*6236dae4SAndroid Build Coastguard Worker }
1088*6236dae4SAndroid Build Coastguard Worker
1089*6236dae4SAndroid Build Coastguard Worker return 0;
1090*6236dae4SAndroid Build Coastguard Worker }
1091*6236dae4SAndroid Build Coastguard Worker
cb_h3_reset_stream(nghttp3_conn * conn,int64_t sid,uint64_t app_error_code,void * user_data,void * stream_user_data)1092*6236dae4SAndroid Build Coastguard Worker static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
1093*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
1094*6236dae4SAndroid Build Coastguard Worker void *stream_user_data) {
1095*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1096*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1097*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)sid;
1098*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
1099*6236dae4SAndroid Build Coastguard Worker int rv;
1100*6236dae4SAndroid Build Coastguard Worker (void)conn;
1101*6236dae4SAndroid Build Coastguard Worker (void)data;
1102*6236dae4SAndroid Build Coastguard Worker
1103*6236dae4SAndroid Build Coastguard Worker rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
1104*6236dae4SAndroid Build Coastguard Worker app_error_code);
1105*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
1106*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1107*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1108*6236dae4SAndroid Build Coastguard Worker }
1109*6236dae4SAndroid Build Coastguard Worker
1110*6236dae4SAndroid Build Coastguard Worker return 0;
1111*6236dae4SAndroid Build Coastguard Worker }
1112*6236dae4SAndroid Build Coastguard Worker
1113*6236dae4SAndroid Build Coastguard Worker static nghttp3_callbacks ngh3_callbacks = {
1114*6236dae4SAndroid Build Coastguard Worker cb_h3_acked_req_body, /* acked_stream_data */
1115*6236dae4SAndroid Build Coastguard Worker cb_h3_stream_close,
1116*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_data,
1117*6236dae4SAndroid Build Coastguard Worker cb_h3_deferred_consume,
1118*6236dae4SAndroid Build Coastguard Worker NULL, /* begin_headers */
1119*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_header,
1120*6236dae4SAndroid Build Coastguard Worker cb_h3_end_headers,
1121*6236dae4SAndroid Build Coastguard Worker NULL, /* begin_trailers */
1122*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_header,
1123*6236dae4SAndroid Build Coastguard Worker NULL, /* end_trailers */
1124*6236dae4SAndroid Build Coastguard Worker cb_h3_stop_sending,
1125*6236dae4SAndroid Build Coastguard Worker NULL, /* end_stream */
1126*6236dae4SAndroid Build Coastguard Worker cb_h3_reset_stream,
1127*6236dae4SAndroid Build Coastguard Worker NULL, /* shutdown */
1128*6236dae4SAndroid Build Coastguard Worker NULL /* recv_settings */
1129*6236dae4SAndroid Build Coastguard Worker };
1130*6236dae4SAndroid Build Coastguard Worker
init_ngh3_conn(struct Curl_cfilter * cf)1131*6236dae4SAndroid Build Coastguard Worker static CURLcode init_ngh3_conn(struct Curl_cfilter *cf)
1132*6236dae4SAndroid Build Coastguard Worker {
1133*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1134*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1135*6236dae4SAndroid Build Coastguard Worker int rc;
1136*6236dae4SAndroid Build Coastguard Worker int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
1137*6236dae4SAndroid Build Coastguard Worker
1138*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) {
1139*6236dae4SAndroid Build Coastguard Worker return CURLE_QUIC_CONNECT_ERROR;
1140*6236dae4SAndroid Build Coastguard Worker }
1141*6236dae4SAndroid Build Coastguard Worker
1142*6236dae4SAndroid Build Coastguard Worker nghttp3_settings_default(&ctx->h3settings);
1143*6236dae4SAndroid Build Coastguard Worker
1144*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_client_new(&ctx->h3conn,
1145*6236dae4SAndroid Build Coastguard Worker &ngh3_callbacks,
1146*6236dae4SAndroid Build Coastguard Worker &ctx->h3settings,
1147*6236dae4SAndroid Build Coastguard Worker nghttp3_mem_default(),
1148*6236dae4SAndroid Build Coastguard Worker cf);
1149*6236dae4SAndroid Build Coastguard Worker if(rc) {
1150*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1151*6236dae4SAndroid Build Coastguard Worker goto fail;
1152*6236dae4SAndroid Build Coastguard Worker }
1153*6236dae4SAndroid Build Coastguard Worker
1154*6236dae4SAndroid Build Coastguard Worker rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL);
1155*6236dae4SAndroid Build Coastguard Worker if(rc) {
1156*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1157*6236dae4SAndroid Build Coastguard Worker goto fail;
1158*6236dae4SAndroid Build Coastguard Worker }
1159*6236dae4SAndroid Build Coastguard Worker
1160*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id);
1161*6236dae4SAndroid Build Coastguard Worker if(rc) {
1162*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1163*6236dae4SAndroid Build Coastguard Worker goto fail;
1164*6236dae4SAndroid Build Coastguard Worker }
1165*6236dae4SAndroid Build Coastguard Worker
1166*6236dae4SAndroid Build Coastguard Worker rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL);
1167*6236dae4SAndroid Build Coastguard Worker if(rc) {
1168*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1169*6236dae4SAndroid Build Coastguard Worker goto fail;
1170*6236dae4SAndroid Build Coastguard Worker }
1171*6236dae4SAndroid Build Coastguard Worker
1172*6236dae4SAndroid Build Coastguard Worker rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL);
1173*6236dae4SAndroid Build Coastguard Worker if(rc) {
1174*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1175*6236dae4SAndroid Build Coastguard Worker goto fail;
1176*6236dae4SAndroid Build Coastguard Worker }
1177*6236dae4SAndroid Build Coastguard Worker
1178*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id,
1179*6236dae4SAndroid Build Coastguard Worker qpack_dec_stream_id);
1180*6236dae4SAndroid Build Coastguard Worker if(rc) {
1181*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1182*6236dae4SAndroid Build Coastguard Worker goto fail;
1183*6236dae4SAndroid Build Coastguard Worker }
1184*6236dae4SAndroid Build Coastguard Worker
1185*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1186*6236dae4SAndroid Build Coastguard Worker fail:
1187*6236dae4SAndroid Build Coastguard Worker
1188*6236dae4SAndroid Build Coastguard Worker return result;
1189*6236dae4SAndroid Build Coastguard Worker }
1190*6236dae4SAndroid Build Coastguard Worker
recv_closed_stream(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream,CURLcode * err)1191*6236dae4SAndroid Build Coastguard Worker static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
1192*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1193*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream,
1194*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1195*6236dae4SAndroid Build Coastguard Worker {
1196*6236dae4SAndroid Build Coastguard Worker ssize_t nread = -1;
1197*6236dae4SAndroid Build Coastguard Worker
1198*6236dae4SAndroid Build Coastguard Worker (void)cf;
1199*6236dae4SAndroid Build Coastguard Worker if(stream->reset) {
1200*6236dae4SAndroid Build Coastguard Worker failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
1201*6236dae4SAndroid Build Coastguard Worker *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
1202*6236dae4SAndroid Build Coastguard Worker goto out;
1203*6236dae4SAndroid Build Coastguard Worker }
1204*6236dae4SAndroid Build Coastguard Worker else if(!stream->resp_hds_complete) {
1205*6236dae4SAndroid Build Coastguard Worker failf(data,
1206*6236dae4SAndroid Build Coastguard Worker "HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
1207*6236dae4SAndroid Build Coastguard Worker "getting all response header fields, treated as error",
1208*6236dae4SAndroid Build Coastguard Worker stream->id);
1209*6236dae4SAndroid Build Coastguard Worker *err = CURLE_HTTP3;
1210*6236dae4SAndroid Build Coastguard Worker goto out;
1211*6236dae4SAndroid Build Coastguard Worker }
1212*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1213*6236dae4SAndroid Build Coastguard Worker nread = 0;
1214*6236dae4SAndroid Build Coastguard Worker
1215*6236dae4SAndroid Build Coastguard Worker out:
1216*6236dae4SAndroid Build Coastguard Worker return nread;
1217*6236dae4SAndroid Build Coastguard Worker }
1218*6236dae4SAndroid Build Coastguard Worker
1219*6236dae4SAndroid Build Coastguard Worker /* incoming data frames on the h3 stream */
cf_ngtcp2_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t blen,CURLcode * err)1220*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1221*6236dae4SAndroid Build Coastguard Worker char *buf, size_t blen, CURLcode *err)
1222*6236dae4SAndroid Build Coastguard Worker {
1223*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1224*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1225*6236dae4SAndroid Build Coastguard Worker ssize_t nread = -1;
1226*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
1227*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx pktx;
1228*6236dae4SAndroid Build Coastguard Worker
1229*6236dae4SAndroid Build Coastguard Worker (void)ctx;
1230*6236dae4SAndroid Build Coastguard Worker (void)buf;
1231*6236dae4SAndroid Build Coastguard Worker
1232*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
1233*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cf->connected);
1234*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx);
1235*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->qconn);
1236*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->h3conn);
1237*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1238*6236dae4SAndroid Build Coastguard Worker
1239*6236dae4SAndroid Build Coastguard Worker pktx_init(&pktx, cf, data);
1240*6236dae4SAndroid Build Coastguard Worker
1241*6236dae4SAndroid Build Coastguard Worker if(!stream || ctx->shutdown_started) {
1242*6236dae4SAndroid Build Coastguard Worker *err = CURLE_RECV_ERROR;
1243*6236dae4SAndroid Build Coastguard Worker goto out;
1244*6236dae4SAndroid Build Coastguard Worker }
1245*6236dae4SAndroid Build Coastguard Worker
1246*6236dae4SAndroid Build Coastguard Worker if(cf_progress_ingress(cf, data, &pktx)) {
1247*6236dae4SAndroid Build Coastguard Worker *err = CURLE_RECV_ERROR;
1248*6236dae4SAndroid Build Coastguard Worker nread = -1;
1249*6236dae4SAndroid Build Coastguard Worker goto out;
1250*6236dae4SAndroid Build Coastguard Worker }
1251*6236dae4SAndroid Build Coastguard Worker
1252*6236dae4SAndroid Build Coastguard Worker if(stream->xfer_result) {
1253*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
1254*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_stream_close(cf, data, stream);
1255*6236dae4SAndroid Build Coastguard Worker *err = stream->xfer_result;
1256*6236dae4SAndroid Build Coastguard Worker nread = -1;
1257*6236dae4SAndroid Build Coastguard Worker goto out;
1258*6236dae4SAndroid Build Coastguard Worker }
1259*6236dae4SAndroid Build Coastguard Worker else if(stream->closed) {
1260*6236dae4SAndroid Build Coastguard Worker nread = recv_closed_stream(cf, data, stream, err);
1261*6236dae4SAndroid Build Coastguard Worker goto out;
1262*6236dae4SAndroid Build Coastguard Worker }
1263*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
1264*6236dae4SAndroid Build Coastguard Worker nread = -1;
1265*6236dae4SAndroid Build Coastguard Worker
1266*6236dae4SAndroid Build Coastguard Worker out:
1267*6236dae4SAndroid Build Coastguard Worker if(cf_progress_egress(cf, data, &pktx)) {
1268*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1269*6236dae4SAndroid Build Coastguard Worker nread = -1;
1270*6236dae4SAndroid Build Coastguard Worker }
1271*6236dae4SAndroid Build Coastguard Worker else {
1272*6236dae4SAndroid Build Coastguard Worker CURLcode result2 = check_and_set_expiry(cf, data, &pktx);
1273*6236dae4SAndroid Build Coastguard Worker if(result2) {
1274*6236dae4SAndroid Build Coastguard Worker *err = result2;
1275*6236dae4SAndroid Build Coastguard Worker nread = -1;
1276*6236dae4SAndroid Build Coastguard Worker }
1277*6236dae4SAndroid Build Coastguard Worker }
1278*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
1279*6236dae4SAndroid Build Coastguard Worker stream ? stream->id : -1, blen, nread, *err);
1280*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
1281*6236dae4SAndroid Build Coastguard Worker return nread;
1282*6236dae4SAndroid Build Coastguard Worker }
1283*6236dae4SAndroid Build Coastguard Worker
cb_h3_acked_req_body(nghttp3_conn * conn,int64_t stream_id,uint64_t datalen,void * user_data,void * stream_user_data)1284*6236dae4SAndroid Build Coastguard Worker static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
1285*6236dae4SAndroid Build Coastguard Worker uint64_t datalen, void *user_data,
1286*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
1287*6236dae4SAndroid Build Coastguard Worker {
1288*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1289*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1290*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
1291*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1292*6236dae4SAndroid Build Coastguard Worker size_t skiplen;
1293*6236dae4SAndroid Build Coastguard Worker
1294*6236dae4SAndroid Build Coastguard Worker (void)cf;
1295*6236dae4SAndroid Build Coastguard Worker if(!stream)
1296*6236dae4SAndroid Build Coastguard Worker return 0;
1297*6236dae4SAndroid Build Coastguard Worker /* The server acknowledged `datalen` of bytes from our request body.
1298*6236dae4SAndroid Build Coastguard Worker * This is a delta. We have kept this data in `sendbuf` for
1299*6236dae4SAndroid Build Coastguard Worker * re-transmissions and can free it now. */
1300*6236dae4SAndroid Build Coastguard Worker if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
1301*6236dae4SAndroid Build Coastguard Worker skiplen = stream->sendbuf_len_in_flight;
1302*6236dae4SAndroid Build Coastguard Worker else
1303*6236dae4SAndroid Build Coastguard Worker skiplen = (size_t)datalen;
1304*6236dae4SAndroid Build Coastguard Worker Curl_bufq_skip(&stream->sendbuf, skiplen);
1305*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight -= skiplen;
1306*6236dae4SAndroid Build Coastguard Worker
1307*6236dae4SAndroid Build Coastguard Worker /* Resume upload processing if we have more data to send */
1308*6236dae4SAndroid Build Coastguard Worker if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1309*6236dae4SAndroid Build Coastguard Worker int rv = nghttp3_conn_resume_stream(conn, stream_id);
1310*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1311*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1312*6236dae4SAndroid Build Coastguard Worker }
1313*6236dae4SAndroid Build Coastguard Worker }
1314*6236dae4SAndroid Build Coastguard Worker return 0;
1315*6236dae4SAndroid Build Coastguard Worker }
1316*6236dae4SAndroid Build Coastguard Worker
1317*6236dae4SAndroid Build Coastguard Worker static nghttp3_ssize
cb_h3_read_req_body(nghttp3_conn * conn,int64_t stream_id,nghttp3_vec * vec,size_t veccnt,uint32_t * pflags,void * user_data,void * stream_user_data)1318*6236dae4SAndroid Build Coastguard Worker cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
1319*6236dae4SAndroid Build Coastguard Worker nghttp3_vec *vec, size_t veccnt,
1320*6236dae4SAndroid Build Coastguard Worker uint32_t *pflags, void *user_data,
1321*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
1322*6236dae4SAndroid Build Coastguard Worker {
1323*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1324*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1325*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
1326*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1327*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = 0;
1328*6236dae4SAndroid Build Coastguard Worker size_t nvecs = 0;
1329*6236dae4SAndroid Build Coastguard Worker (void)cf;
1330*6236dae4SAndroid Build Coastguard Worker (void)conn;
1331*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
1332*6236dae4SAndroid Build Coastguard Worker (void)user_data;
1333*6236dae4SAndroid Build Coastguard Worker (void)veccnt;
1334*6236dae4SAndroid Build Coastguard Worker
1335*6236dae4SAndroid Build Coastguard Worker if(!stream)
1336*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1337*6236dae4SAndroid Build Coastguard Worker /* nghttp3 keeps references to the sendbuf data until it is ACKed
1338*6236dae4SAndroid Build Coastguard Worker * by the server (see `cb_h3_acked_req_body()` for updates).
1339*6236dae4SAndroid Build Coastguard Worker * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
1340*6236dae4SAndroid Build Coastguard Worker * that we have already passed to nghttp3, but which have not been
1341*6236dae4SAndroid Build Coastguard Worker * ACKed yet.
1342*6236dae4SAndroid Build Coastguard Worker * Any amount beyond `sendbuf_len_in_flight` we need still to pass
1343*6236dae4SAndroid Build Coastguard Worker * to nghttp3. Do that now, if we can. */
1344*6236dae4SAndroid Build Coastguard Worker if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1345*6236dae4SAndroid Build Coastguard Worker nvecs = 0;
1346*6236dae4SAndroid Build Coastguard Worker while(nvecs < veccnt &&
1347*6236dae4SAndroid Build Coastguard Worker Curl_bufq_peek_at(&stream->sendbuf,
1348*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight,
1349*6236dae4SAndroid Build Coastguard Worker (const unsigned char **)&vec[nvecs].base,
1350*6236dae4SAndroid Build Coastguard Worker &vec[nvecs].len)) {
1351*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight += vec[nvecs].len;
1352*6236dae4SAndroid Build Coastguard Worker nwritten += vec[nvecs].len;
1353*6236dae4SAndroid Build Coastguard Worker ++nvecs;
1354*6236dae4SAndroid Build Coastguard Worker }
1355*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
1356*6236dae4SAndroid Build Coastguard Worker }
1357*6236dae4SAndroid Build Coastguard Worker
1358*6236dae4SAndroid Build Coastguard Worker if(nwritten > 0 && stream->upload_left != -1)
1359*6236dae4SAndroid Build Coastguard Worker stream->upload_left -= nwritten;
1360*6236dae4SAndroid Build Coastguard Worker
1361*6236dae4SAndroid Build Coastguard Worker /* When we stopped sending and everything in `sendbuf` is "in flight",
1362*6236dae4SAndroid Build Coastguard Worker * we are at the end of the request body. */
1363*6236dae4SAndroid Build Coastguard Worker if(stream->upload_left == 0) {
1364*6236dae4SAndroid Build Coastguard Worker *pflags = NGHTTP3_DATA_FLAG_EOF;
1365*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
1366*6236dae4SAndroid Build Coastguard Worker }
1367*6236dae4SAndroid Build Coastguard Worker else if(!nwritten) {
1368*6236dae4SAndroid Build Coastguard Worker /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
1369*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
1370*6236dae4SAndroid Build Coastguard Worker stream->id);
1371*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_WOULDBLOCK;
1372*6236dae4SAndroid Build Coastguard Worker }
1373*6236dae4SAndroid Build Coastguard Worker
1374*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
1375*6236dae4SAndroid Build Coastguard Worker "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
1376*6236dae4SAndroid Build Coastguard Worker stream->id, (int)nvecs,
1377*6236dae4SAndroid Build Coastguard Worker *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
1378*6236dae4SAndroid Build Coastguard Worker nwritten, Curl_bufq_len(&stream->sendbuf),
1379*6236dae4SAndroid Build Coastguard Worker stream->upload_left);
1380*6236dae4SAndroid Build Coastguard Worker return (nghttp3_ssize)nvecs;
1381*6236dae4SAndroid Build Coastguard Worker }
1382*6236dae4SAndroid Build Coastguard Worker
1383*6236dae4SAndroid Build Coastguard Worker /* Index where :authority header field will appear in request header
1384*6236dae4SAndroid Build Coastguard Worker field list. */
1385*6236dae4SAndroid Build Coastguard Worker #define AUTHORITY_DST_IDX 3
1386*6236dae4SAndroid Build Coastguard Worker
h3_stream_open(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1387*6236dae4SAndroid Build Coastguard Worker static ssize_t h3_stream_open(struct Curl_cfilter *cf,
1388*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1389*6236dae4SAndroid Build Coastguard Worker const void *buf, size_t len,
1390*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1391*6236dae4SAndroid Build Coastguard Worker {
1392*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1393*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = NULL;
1394*6236dae4SAndroid Build Coastguard Worker int64_t sid;
1395*6236dae4SAndroid Build Coastguard Worker struct dynhds h2_headers;
1396*6236dae4SAndroid Build Coastguard Worker size_t nheader;
1397*6236dae4SAndroid Build Coastguard Worker nghttp3_nv *nva = NULL;
1398*6236dae4SAndroid Build Coastguard Worker int rc = 0;
1399*6236dae4SAndroid Build Coastguard Worker unsigned int i;
1400*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = -1;
1401*6236dae4SAndroid Build Coastguard Worker nghttp3_data_reader reader;
1402*6236dae4SAndroid Build Coastguard Worker nghttp3_data_reader *preader = NULL;
1403*6236dae4SAndroid Build Coastguard Worker
1404*6236dae4SAndroid Build Coastguard Worker Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
1405*6236dae4SAndroid Build Coastguard Worker
1406*6236dae4SAndroid Build Coastguard Worker *err = h3_data_setup(cf, data);
1407*6236dae4SAndroid Build Coastguard Worker if(*err)
1408*6236dae4SAndroid Build Coastguard Worker goto out;
1409*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, data);
1410*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
1411*6236dae4SAndroid Build Coastguard Worker if(!stream) {
1412*6236dae4SAndroid Build Coastguard Worker *err = CURLE_FAILED_INIT;
1413*6236dae4SAndroid Build Coastguard Worker goto out;
1414*6236dae4SAndroid Build Coastguard Worker }
1415*6236dae4SAndroid Build Coastguard Worker
1416*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
1417*6236dae4SAndroid Build Coastguard Worker if(nwritten < 0)
1418*6236dae4SAndroid Build Coastguard Worker goto out;
1419*6236dae4SAndroid Build Coastguard Worker if(!stream->h1.done) {
1420*6236dae4SAndroid Build Coastguard Worker /* need more data */
1421*6236dae4SAndroid Build Coastguard Worker goto out;
1422*6236dae4SAndroid Build Coastguard Worker }
1423*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream->h1.req);
1424*6236dae4SAndroid Build Coastguard Worker
1425*6236dae4SAndroid Build Coastguard Worker *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
1426*6236dae4SAndroid Build Coastguard Worker if(*err) {
1427*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1428*6236dae4SAndroid Build Coastguard Worker goto out;
1429*6236dae4SAndroid Build Coastguard Worker }
1430*6236dae4SAndroid Build Coastguard Worker /* no longer needed */
1431*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_free(&stream->h1);
1432*6236dae4SAndroid Build Coastguard Worker
1433*6236dae4SAndroid Build Coastguard Worker nheader = Curl_dynhds_count(&h2_headers);
1434*6236dae4SAndroid Build Coastguard Worker nva = malloc(sizeof(nghttp3_nv) * nheader);
1435*6236dae4SAndroid Build Coastguard Worker if(!nva) {
1436*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OUT_OF_MEMORY;
1437*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1438*6236dae4SAndroid Build Coastguard Worker goto out;
1439*6236dae4SAndroid Build Coastguard Worker }
1440*6236dae4SAndroid Build Coastguard Worker
1441*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < nheader; ++i) {
1442*6236dae4SAndroid Build Coastguard Worker struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
1443*6236dae4SAndroid Build Coastguard Worker nva[i].name = (unsigned char *)e->name;
1444*6236dae4SAndroid Build Coastguard Worker nva[i].namelen = e->namelen;
1445*6236dae4SAndroid Build Coastguard Worker nva[i].value = (unsigned char *)e->value;
1446*6236dae4SAndroid Build Coastguard Worker nva[i].valuelen = e->valuelen;
1447*6236dae4SAndroid Build Coastguard Worker nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1448*6236dae4SAndroid Build Coastguard Worker }
1449*6236dae4SAndroid Build Coastguard Worker
1450*6236dae4SAndroid Build Coastguard Worker rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data);
1451*6236dae4SAndroid Build Coastguard Worker if(rc) {
1452*6236dae4SAndroid Build Coastguard Worker failf(data, "can get bidi streams");
1453*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1454*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1455*6236dae4SAndroid Build Coastguard Worker goto out;
1456*6236dae4SAndroid Build Coastguard Worker }
1457*6236dae4SAndroid Build Coastguard Worker stream->id = (curl_int64_t)sid;
1458*6236dae4SAndroid Build Coastguard Worker ++ctx->used_bidi_streams;
1459*6236dae4SAndroid Build Coastguard Worker
1460*6236dae4SAndroid Build Coastguard Worker switch(data->state.httpreq) {
1461*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST:
1462*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST_FORM:
1463*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST_MIME:
1464*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_PUT:
1465*6236dae4SAndroid Build Coastguard Worker /* known request body size or -1 */
1466*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize != -1)
1467*6236dae4SAndroid Build Coastguard Worker stream->upload_left = data->state.infilesize;
1468*6236dae4SAndroid Build Coastguard Worker else
1469*6236dae4SAndroid Build Coastguard Worker /* data sending without specifying the data amount up front */
1470*6236dae4SAndroid Build Coastguard Worker stream->upload_left = -1; /* unknown */
1471*6236dae4SAndroid Build Coastguard Worker break;
1472*6236dae4SAndroid Build Coastguard Worker default:
1473*6236dae4SAndroid Build Coastguard Worker /* there is not request body */
1474*6236dae4SAndroid Build Coastguard Worker stream->upload_left = 0; /* no request body */
1475*6236dae4SAndroid Build Coastguard Worker break;
1476*6236dae4SAndroid Build Coastguard Worker }
1477*6236dae4SAndroid Build Coastguard Worker
1478*6236dae4SAndroid Build Coastguard Worker stream->send_closed = (stream->upload_left == 0);
1479*6236dae4SAndroid Build Coastguard Worker if(!stream->send_closed) {
1480*6236dae4SAndroid Build Coastguard Worker reader.read_data = cb_h3_read_req_body;
1481*6236dae4SAndroid Build Coastguard Worker preader = &reader;
1482*6236dae4SAndroid Build Coastguard Worker }
1483*6236dae4SAndroid Build Coastguard Worker
1484*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id,
1485*6236dae4SAndroid Build Coastguard Worker nva, nheader, preader, data);
1486*6236dae4SAndroid Build Coastguard Worker if(rc) {
1487*6236dae4SAndroid Build Coastguard Worker switch(rc) {
1488*6236dae4SAndroid Build Coastguard Worker case NGHTTP3_ERR_CONN_CLOSING:
1489*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send, "
1490*6236dae4SAndroid Build Coastguard Worker "connection is closing", stream->id);
1491*6236dae4SAndroid Build Coastguard Worker break;
1492*6236dae4SAndroid Build Coastguard Worker default:
1493*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send -> "
1494*6236dae4SAndroid Build Coastguard Worker "%d (%s)", stream->id, rc, nghttp3_strerror(rc));
1495*6236dae4SAndroid Build Coastguard Worker break;
1496*6236dae4SAndroid Build Coastguard Worker }
1497*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1498*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1499*6236dae4SAndroid Build Coastguard Worker goto out;
1500*6236dae4SAndroid Build Coastguard Worker }
1501*6236dae4SAndroid Build Coastguard Worker
1502*6236dae4SAndroid Build Coastguard Worker if(Curl_trc_is_verbose(data)) {
1503*6236dae4SAndroid Build Coastguard Worker infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
1504*6236dae4SAndroid Build Coastguard Worker stream->id, data->state.url);
1505*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < nheader; ++i) {
1506*6236dae4SAndroid Build Coastguard Worker infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]", stream->id,
1507*6236dae4SAndroid Build Coastguard Worker (int)nva[i].namelen, nva[i].name,
1508*6236dae4SAndroid Build Coastguard Worker (int)nva[i].valuelen, nva[i].value);
1509*6236dae4SAndroid Build Coastguard Worker }
1510*6236dae4SAndroid Build Coastguard Worker }
1511*6236dae4SAndroid Build Coastguard Worker
1512*6236dae4SAndroid Build Coastguard Worker out:
1513*6236dae4SAndroid Build Coastguard Worker free(nva);
1514*6236dae4SAndroid Build Coastguard Worker Curl_dynhds_free(&h2_headers);
1515*6236dae4SAndroid Build Coastguard Worker return nwritten;
1516*6236dae4SAndroid Build Coastguard Worker }
1517*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)1518*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1519*6236dae4SAndroid Build Coastguard Worker const void *buf, size_t len, bool eos,
1520*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1521*6236dae4SAndroid Build Coastguard Worker {
1522*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1523*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1524*6236dae4SAndroid Build Coastguard Worker ssize_t sent = 0;
1525*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
1526*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx pktx;
1527*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1528*6236dae4SAndroid Build Coastguard Worker
1529*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
1530*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cf->connected);
1531*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->qconn);
1532*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->h3conn);
1533*6236dae4SAndroid Build Coastguard Worker pktx_init(&pktx, cf, data);
1534*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1535*6236dae4SAndroid Build Coastguard Worker
1536*6236dae4SAndroid Build Coastguard Worker (void)eos; /* TODO: use for stream EOF and block handling */
1537*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data, &pktx);
1538*6236dae4SAndroid Build Coastguard Worker if(result) {
1539*6236dae4SAndroid Build Coastguard Worker *err = result;
1540*6236dae4SAndroid Build Coastguard Worker sent = -1;
1541*6236dae4SAndroid Build Coastguard Worker }
1542*6236dae4SAndroid Build Coastguard Worker
1543*6236dae4SAndroid Build Coastguard Worker if(!stream || stream->id < 0) {
1544*6236dae4SAndroid Build Coastguard Worker if(ctx->shutdown_started) {
1545*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
1546*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1547*6236dae4SAndroid Build Coastguard Worker sent = -1;
1548*6236dae4SAndroid Build Coastguard Worker goto out;
1549*6236dae4SAndroid Build Coastguard Worker }
1550*6236dae4SAndroid Build Coastguard Worker sent = h3_stream_open(cf, data, buf, len, err);
1551*6236dae4SAndroid Build Coastguard Worker if(sent < 0) {
1552*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
1553*6236dae4SAndroid Build Coastguard Worker goto out;
1554*6236dae4SAndroid Build Coastguard Worker }
1555*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, data);
1556*6236dae4SAndroid Build Coastguard Worker }
1557*6236dae4SAndroid Build Coastguard Worker else if(stream->xfer_result) {
1558*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
1559*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_stream_close(cf, data, stream);
1560*6236dae4SAndroid Build Coastguard Worker *err = stream->xfer_result;
1561*6236dae4SAndroid Build Coastguard Worker sent = -1;
1562*6236dae4SAndroid Build Coastguard Worker goto out;
1563*6236dae4SAndroid Build Coastguard Worker }
1564*6236dae4SAndroid Build Coastguard Worker else if(stream->closed) {
1565*6236dae4SAndroid Build Coastguard Worker if(stream->resp_hds_complete) {
1566*6236dae4SAndroid Build Coastguard Worker /* Server decided to close the stream after having sent us a final
1567*6236dae4SAndroid Build Coastguard Worker * response. This is valid if it is not interested in the request
1568*6236dae4SAndroid Build Coastguard Worker * body. This happens on 30x or 40x responses.
1569*6236dae4SAndroid Build Coastguard Worker * We silently discard the data sent, since this is not a transport
1570*6236dae4SAndroid Build Coastguard Worker * error situation. */
1571*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
1572*6236dae4SAndroid Build Coastguard Worker "on closed stream with response", stream->id);
1573*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1574*6236dae4SAndroid Build Coastguard Worker sent = (ssize_t)len;
1575*6236dae4SAndroid Build Coastguard Worker goto out;
1576*6236dae4SAndroid Build Coastguard Worker }
1577*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
1578*6236dae4SAndroid Build Coastguard Worker "-> stream closed", stream->id, len);
1579*6236dae4SAndroid Build Coastguard Worker *err = CURLE_HTTP3;
1580*6236dae4SAndroid Build Coastguard Worker sent = -1;
1581*6236dae4SAndroid Build Coastguard Worker goto out;
1582*6236dae4SAndroid Build Coastguard Worker }
1583*6236dae4SAndroid Build Coastguard Worker else if(ctx->shutdown_started) {
1584*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "cannot send on closed connection");
1585*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1586*6236dae4SAndroid Build Coastguard Worker sent = -1;
1587*6236dae4SAndroid Build Coastguard Worker goto out;
1588*6236dae4SAndroid Build Coastguard Worker }
1589*6236dae4SAndroid Build Coastguard Worker else {
1590*6236dae4SAndroid Build Coastguard Worker sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
1591*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
1592*6236dae4SAndroid Build Coastguard Worker "sendbuf(len=%zu) -> %zd, %d",
1593*6236dae4SAndroid Build Coastguard Worker stream->id, len, sent, *err);
1594*6236dae4SAndroid Build Coastguard Worker if(sent < 0) {
1595*6236dae4SAndroid Build Coastguard Worker goto out;
1596*6236dae4SAndroid Build Coastguard Worker }
1597*6236dae4SAndroid Build Coastguard Worker
1598*6236dae4SAndroid Build Coastguard Worker (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
1599*6236dae4SAndroid Build Coastguard Worker }
1600*6236dae4SAndroid Build Coastguard Worker
1601*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, &pktx);
1602*6236dae4SAndroid Build Coastguard Worker if(result) {
1603*6236dae4SAndroid Build Coastguard Worker *err = result;
1604*6236dae4SAndroid Build Coastguard Worker sent = -1;
1605*6236dae4SAndroid Build Coastguard Worker }
1606*6236dae4SAndroid Build Coastguard Worker
1607*6236dae4SAndroid Build Coastguard Worker out:
1608*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data, &pktx);
1609*6236dae4SAndroid Build Coastguard Worker if(result) {
1610*6236dae4SAndroid Build Coastguard Worker *err = result;
1611*6236dae4SAndroid Build Coastguard Worker sent = -1;
1612*6236dae4SAndroid Build Coastguard Worker }
1613*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
1614*6236dae4SAndroid Build Coastguard Worker stream ? stream->id : -1, len, sent, *err);
1615*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
1616*6236dae4SAndroid Build Coastguard Worker return sent;
1617*6236dae4SAndroid Build Coastguard Worker }
1618*6236dae4SAndroid Build Coastguard Worker
qng_verify_peer(struct Curl_cfilter * cf,struct Curl_easy * data)1619*6236dae4SAndroid Build Coastguard Worker static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
1620*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1621*6236dae4SAndroid Build Coastguard Worker {
1622*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1623*6236dae4SAndroid Build Coastguard Worker
1624*6236dae4SAndroid Build Coastguard Worker cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1625*6236dae4SAndroid Build Coastguard Worker cf->conn->httpversion = 30;
1626*6236dae4SAndroid Build Coastguard Worker
1627*6236dae4SAndroid Build Coastguard Worker return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
1628*6236dae4SAndroid Build Coastguard Worker }
1629*6236dae4SAndroid Build Coastguard Worker
recv_pkt(const unsigned char * pkt,size_t pktlen,struct sockaddr_storage * remote_addr,socklen_t remote_addrlen,int ecn,void * userp)1630*6236dae4SAndroid Build Coastguard Worker static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
1631*6236dae4SAndroid Build Coastguard Worker struct sockaddr_storage *remote_addr,
1632*6236dae4SAndroid Build Coastguard Worker socklen_t remote_addrlen, int ecn,
1633*6236dae4SAndroid Build Coastguard Worker void *userp)
1634*6236dae4SAndroid Build Coastguard Worker {
1635*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx = userp;
1636*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
1637*6236dae4SAndroid Build Coastguard Worker ngtcp2_pkt_info pi;
1638*6236dae4SAndroid Build Coastguard Worker ngtcp2_path path;
1639*6236dae4SAndroid Build Coastguard Worker int rv;
1640*6236dae4SAndroid Build Coastguard Worker
1641*6236dae4SAndroid Build Coastguard Worker ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
1642*6236dae4SAndroid Build Coastguard Worker (socklen_t)ctx->q.local_addrlen);
1643*6236dae4SAndroid Build Coastguard Worker ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
1644*6236dae4SAndroid Build Coastguard Worker remote_addrlen);
1645*6236dae4SAndroid Build Coastguard Worker pi.ecn = (uint8_t)ecn;
1646*6236dae4SAndroid Build Coastguard Worker
1647*6236dae4SAndroid Build Coastguard Worker rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
1648*6236dae4SAndroid Build Coastguard Worker if(rv) {
1649*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
1650*6236dae4SAndroid Build Coastguard Worker ngtcp2_strerror(rv), rv);
1651*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_err_set(pktx->cf, pktx->data, rv);
1652*6236dae4SAndroid Build Coastguard Worker
1653*6236dae4SAndroid Build Coastguard Worker if(rv == NGTCP2_ERR_CRYPTO)
1654*6236dae4SAndroid Build Coastguard Worker /* this is a "TLS problem", but a failed certificate verification
1655*6236dae4SAndroid Build Coastguard Worker is a common reason for this */
1656*6236dae4SAndroid Build Coastguard Worker return CURLE_PEER_FAILED_VERIFICATION;
1657*6236dae4SAndroid Build Coastguard Worker return CURLE_RECV_ERROR;
1658*6236dae4SAndroid Build Coastguard Worker }
1659*6236dae4SAndroid Build Coastguard Worker
1660*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1661*6236dae4SAndroid Build Coastguard Worker }
1662*6236dae4SAndroid Build Coastguard Worker
cf_progress_ingress(struct Curl_cfilter * cf,struct Curl_easy * data,struct pkt_io_ctx * pktx)1663*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
1664*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1665*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx)
1666*6236dae4SAndroid Build Coastguard Worker {
1667*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1668*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx local_pktx;
1669*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1670*6236dae4SAndroid Build Coastguard Worker
1671*6236dae4SAndroid Build Coastguard Worker if(!pktx) {
1672*6236dae4SAndroid Build Coastguard Worker pktx_init(&local_pktx, cf, data);
1673*6236dae4SAndroid Build Coastguard Worker pktx = &local_pktx;
1674*6236dae4SAndroid Build Coastguard Worker }
1675*6236dae4SAndroid Build Coastguard Worker
1676*6236dae4SAndroid Build Coastguard Worker result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
1677*6236dae4SAndroid Build Coastguard Worker if(result)
1678*6236dae4SAndroid Build Coastguard Worker return result;
1679*6236dae4SAndroid Build Coastguard Worker
1680*6236dae4SAndroid Build Coastguard Worker return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx);
1681*6236dae4SAndroid Build Coastguard Worker }
1682*6236dae4SAndroid Build Coastguard Worker
1683*6236dae4SAndroid Build Coastguard Worker /**
1684*6236dae4SAndroid Build Coastguard Worker * Read a network packet to send from ngtcp2 into `buf`.
1685*6236dae4SAndroid Build Coastguard Worker * Return number of bytes written or -1 with *err set.
1686*6236dae4SAndroid Build Coastguard Worker */
read_pkt_to_send(void * userp,unsigned char * buf,size_t buflen,CURLcode * err)1687*6236dae4SAndroid Build Coastguard Worker static ssize_t read_pkt_to_send(void *userp,
1688*6236dae4SAndroid Build Coastguard Worker unsigned char *buf, size_t buflen,
1689*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1690*6236dae4SAndroid Build Coastguard Worker {
1691*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *x = userp;
1692*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
1693*6236dae4SAndroid Build Coastguard Worker nghttp3_vec vec[16];
1694*6236dae4SAndroid Build Coastguard Worker nghttp3_ssize veccnt;
1695*6236dae4SAndroid Build Coastguard Worker ngtcp2_ssize ndatalen;
1696*6236dae4SAndroid Build Coastguard Worker uint32_t flags;
1697*6236dae4SAndroid Build Coastguard Worker int64_t stream_id;
1698*6236dae4SAndroid Build Coastguard Worker int fin;
1699*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten, n;
1700*6236dae4SAndroid Build Coastguard Worker veccnt = 0;
1701*6236dae4SAndroid Build Coastguard Worker stream_id = -1;
1702*6236dae4SAndroid Build Coastguard Worker fin = 0;
1703*6236dae4SAndroid Build Coastguard Worker
1704*6236dae4SAndroid Build Coastguard Worker /* ngtcp2 may want to put several frames from different streams into
1705*6236dae4SAndroid Build Coastguard Worker * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so.
1706*6236dae4SAndroid Build Coastguard Worker * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make
1707*6236dae4SAndroid Build Coastguard Worker * another iteration.
1708*6236dae4SAndroid Build Coastguard Worker * When ngtcp2 is happy (because it has no other frame that would fit
1709*6236dae4SAndroid Build Coastguard Worker * or it has nothing more to send), it returns the total length
1710*6236dae4SAndroid Build Coastguard Worker * of the assembled packet. This may be 0 if there was nothing to send. */
1711*6236dae4SAndroid Build Coastguard Worker nwritten = 0;
1712*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1713*6236dae4SAndroid Build Coastguard Worker for(;;) {
1714*6236dae4SAndroid Build Coastguard Worker
1715*6236dae4SAndroid Build Coastguard Worker if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
1716*6236dae4SAndroid Build Coastguard Worker veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec,
1717*6236dae4SAndroid Build Coastguard Worker sizeof(vec) / sizeof(vec[0]));
1718*6236dae4SAndroid Build Coastguard Worker if(veccnt < 0) {
1719*6236dae4SAndroid Build Coastguard Worker failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
1720*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror((int)veccnt));
1721*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
1722*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1723*6236dae4SAndroid Build Coastguard Worker return -1;
1724*6236dae4SAndroid Build Coastguard Worker }
1725*6236dae4SAndroid Build Coastguard Worker }
1726*6236dae4SAndroid Build Coastguard Worker
1727*6236dae4SAndroid Build Coastguard Worker flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
1728*6236dae4SAndroid Build Coastguard Worker (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
1729*6236dae4SAndroid Build Coastguard Worker n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path,
1730*6236dae4SAndroid Build Coastguard Worker NULL, buf, buflen,
1731*6236dae4SAndroid Build Coastguard Worker &ndatalen, flags, stream_id,
1732*6236dae4SAndroid Build Coastguard Worker (const ngtcp2_vec *)vec, veccnt, x->ts);
1733*6236dae4SAndroid Build Coastguard Worker if(n == 0) {
1734*6236dae4SAndroid Build Coastguard Worker /* nothing to send */
1735*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
1736*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1737*6236dae4SAndroid Build Coastguard Worker goto out;
1738*6236dae4SAndroid Build Coastguard Worker }
1739*6236dae4SAndroid Build Coastguard Worker else if(n < 0) {
1740*6236dae4SAndroid Build Coastguard Worker switch(n) {
1741*6236dae4SAndroid Build Coastguard Worker case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
1742*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
1743*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ndatalen == -1);
1744*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_block_stream(ctx->h3conn, stream_id);
1745*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow",
1746*6236dae4SAndroid Build Coastguard Worker (curl_int64_t)stream_id);
1747*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
1748*6236dae4SAndroid Build Coastguard Worker if(stream)
1749*6236dae4SAndroid Build Coastguard Worker stream->quic_flow_blocked = TRUE;
1750*6236dae4SAndroid Build Coastguard Worker n = 0;
1751*6236dae4SAndroid Build Coastguard Worker break;
1752*6236dae4SAndroid Build Coastguard Worker }
1753*6236dae4SAndroid Build Coastguard Worker case NGTCP2_ERR_STREAM_SHUT_WR:
1754*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ndatalen == -1);
1755*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id);
1756*6236dae4SAndroid Build Coastguard Worker n = 0;
1757*6236dae4SAndroid Build Coastguard Worker break;
1758*6236dae4SAndroid Build Coastguard Worker case NGTCP2_ERR_WRITE_MORE:
1759*6236dae4SAndroid Build Coastguard Worker /* ngtcp2 wants to send more. update the flow of the stream whose data
1760*6236dae4SAndroid Build Coastguard Worker * is in the buffer and continue */
1761*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ndatalen >= 0);
1762*6236dae4SAndroid Build Coastguard Worker n = 0;
1763*6236dae4SAndroid Build Coastguard Worker break;
1764*6236dae4SAndroid Build Coastguard Worker default:
1765*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ndatalen == -1);
1766*6236dae4SAndroid Build Coastguard Worker failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
1767*6236dae4SAndroid Build Coastguard Worker ngtcp2_strerror((int)n));
1768*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_err_set(x->cf, x->data, (int)n);
1769*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1770*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1771*6236dae4SAndroid Build Coastguard Worker goto out;
1772*6236dae4SAndroid Build Coastguard Worker }
1773*6236dae4SAndroid Build Coastguard Worker }
1774*6236dae4SAndroid Build Coastguard Worker
1775*6236dae4SAndroid Build Coastguard Worker if(ndatalen >= 0) {
1776*6236dae4SAndroid Build Coastguard Worker /* we add the amount of data bytes to the flow windows */
1777*6236dae4SAndroid Build Coastguard Worker int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen);
1778*6236dae4SAndroid Build Coastguard Worker if(rv) {
1779*6236dae4SAndroid Build Coastguard Worker failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n",
1780*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror(rv));
1781*6236dae4SAndroid Build Coastguard Worker return CURLE_SEND_ERROR;
1782*6236dae4SAndroid Build Coastguard Worker }
1783*6236dae4SAndroid Build Coastguard Worker }
1784*6236dae4SAndroid Build Coastguard Worker
1785*6236dae4SAndroid Build Coastguard Worker if(n > 0) {
1786*6236dae4SAndroid Build Coastguard Worker /* packet assembled, leave */
1787*6236dae4SAndroid Build Coastguard Worker nwritten = n;
1788*6236dae4SAndroid Build Coastguard Worker goto out;
1789*6236dae4SAndroid Build Coastguard Worker }
1790*6236dae4SAndroid Build Coastguard Worker }
1791*6236dae4SAndroid Build Coastguard Worker out:
1792*6236dae4SAndroid Build Coastguard Worker return nwritten;
1793*6236dae4SAndroid Build Coastguard Worker }
1794*6236dae4SAndroid Build Coastguard Worker
cf_progress_egress(struct Curl_cfilter * cf,struct Curl_easy * data,struct pkt_io_ctx * pktx)1795*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
1796*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1797*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx)
1798*6236dae4SAndroid Build Coastguard Worker {
1799*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1800*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
1801*6236dae4SAndroid Build Coastguard Worker size_t max_payload_size, path_max_payload_size, max_pktcnt;
1802*6236dae4SAndroid Build Coastguard Worker size_t pktcnt = 0;
1803*6236dae4SAndroid Build Coastguard Worker size_t gsolen = 0; /* this disables gso until we have a clue */
1804*6236dae4SAndroid Build Coastguard Worker CURLcode curlcode;
1805*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx local_pktx;
1806*6236dae4SAndroid Build Coastguard Worker
1807*6236dae4SAndroid Build Coastguard Worker if(!pktx) {
1808*6236dae4SAndroid Build Coastguard Worker pktx_init(&local_pktx, cf, data);
1809*6236dae4SAndroid Build Coastguard Worker pktx = &local_pktx;
1810*6236dae4SAndroid Build Coastguard Worker }
1811*6236dae4SAndroid Build Coastguard Worker else {
1812*6236dae4SAndroid Build Coastguard Worker pktx_update_time(pktx, cf);
1813*6236dae4SAndroid Build Coastguard Worker ngtcp2_path_storage_zero(&pktx->ps);
1814*6236dae4SAndroid Build Coastguard Worker }
1815*6236dae4SAndroid Build Coastguard Worker
1816*6236dae4SAndroid Build Coastguard Worker curlcode = vquic_flush(cf, data, &ctx->q);
1817*6236dae4SAndroid Build Coastguard Worker if(curlcode) {
1818*6236dae4SAndroid Build Coastguard Worker if(curlcode == CURLE_AGAIN) {
1819*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 1, EXPIRE_QUIC);
1820*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1821*6236dae4SAndroid Build Coastguard Worker }
1822*6236dae4SAndroid Build Coastguard Worker return curlcode;
1823*6236dae4SAndroid Build Coastguard Worker }
1824*6236dae4SAndroid Build Coastguard Worker
1825*6236dae4SAndroid Build Coastguard Worker /* In UDP, there is a maximum theoretical packet paload length and
1826*6236dae4SAndroid Build Coastguard Worker * a minimum payload length that is "guaranteed" to work.
1827*6236dae4SAndroid Build Coastguard Worker * To detect if this minimum payload can be increased, ngtcp2 sends
1828*6236dae4SAndroid Build Coastguard Worker * now and then a packet payload larger than the minimum. It that
1829*6236dae4SAndroid Build Coastguard Worker * is ACKed by the peer, both parties know that it works and
1830*6236dae4SAndroid Build Coastguard Worker * the subsequent packets can use a larger one.
1831*6236dae4SAndroid Build Coastguard Worker * This is called PMTUD (Path Maximum Transmission Unit Discovery).
1832*6236dae4SAndroid Build Coastguard Worker * Since a PMTUD might be rejected right on send, we do not want it
1833*6236dae4SAndroid Build Coastguard Worker * be followed by other packets of lesser size. Because those would
1834*6236dae4SAndroid Build Coastguard Worker * also fail then. So, if we detect a PMTUD while buffering, we flush.
1835*6236dae4SAndroid Build Coastguard Worker */
1836*6236dae4SAndroid Build Coastguard Worker max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn);
1837*6236dae4SAndroid Build Coastguard Worker path_max_payload_size =
1838*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn);
1839*6236dae4SAndroid Build Coastguard Worker /* maximum number of packets buffered before we flush to the socket */
1840*6236dae4SAndroid Build Coastguard Worker max_pktcnt = CURLMIN(MAX_PKT_BURST,
1841*6236dae4SAndroid Build Coastguard Worker ctx->q.sendbuf.chunk_size / max_payload_size);
1842*6236dae4SAndroid Build Coastguard Worker
1843*6236dae4SAndroid Build Coastguard Worker for(;;) {
1844*6236dae4SAndroid Build Coastguard Worker /* add the next packet to send, if any, to our buffer */
1845*6236dae4SAndroid Build Coastguard Worker nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
1846*6236dae4SAndroid Build Coastguard Worker read_pkt_to_send, pktx, &curlcode);
1847*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
1848*6236dae4SAndroid Build Coastguard Worker if(curlcode != CURLE_AGAIN)
1849*6236dae4SAndroid Build Coastguard Worker return curlcode;
1850*6236dae4SAndroid Build Coastguard Worker /* Nothing more to add, flush and leave */
1851*6236dae4SAndroid Build Coastguard Worker curlcode = vquic_send(cf, data, &ctx->q, gsolen);
1852*6236dae4SAndroid Build Coastguard Worker if(curlcode) {
1853*6236dae4SAndroid Build Coastguard Worker if(curlcode == CURLE_AGAIN) {
1854*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 1, EXPIRE_QUIC);
1855*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1856*6236dae4SAndroid Build Coastguard Worker }
1857*6236dae4SAndroid Build Coastguard Worker return curlcode;
1858*6236dae4SAndroid Build Coastguard Worker }
1859*6236dae4SAndroid Build Coastguard Worker goto out;
1860*6236dae4SAndroid Build Coastguard Worker }
1861*6236dae4SAndroid Build Coastguard Worker
1862*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(nread > 0);
1863*6236dae4SAndroid Build Coastguard Worker if(pktcnt == 0) {
1864*6236dae4SAndroid Build Coastguard Worker /* first packet in buffer. This is either of a known, "good"
1865*6236dae4SAndroid Build Coastguard Worker * payload size or it is a PMTUD. We will see. */
1866*6236dae4SAndroid Build Coastguard Worker gsolen = (size_t)nread;
1867*6236dae4SAndroid Build Coastguard Worker }
1868*6236dae4SAndroid Build Coastguard Worker else if((size_t)nread > gsolen ||
1869*6236dae4SAndroid Build Coastguard Worker (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
1870*6236dae4SAndroid Build Coastguard Worker /* The just added packet is a PMTUD *or* the one(s) before the
1871*6236dae4SAndroid Build Coastguard Worker * just added were PMTUD and the last one is smaller.
1872*6236dae4SAndroid Build Coastguard Worker * Flush the buffer before the last add. */
1873*6236dae4SAndroid Build Coastguard Worker curlcode = vquic_send_tail_split(cf, data, &ctx->q,
1874*6236dae4SAndroid Build Coastguard Worker gsolen, nread, nread);
1875*6236dae4SAndroid Build Coastguard Worker if(curlcode) {
1876*6236dae4SAndroid Build Coastguard Worker if(curlcode == CURLE_AGAIN) {
1877*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 1, EXPIRE_QUIC);
1878*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1879*6236dae4SAndroid Build Coastguard Worker }
1880*6236dae4SAndroid Build Coastguard Worker return curlcode;
1881*6236dae4SAndroid Build Coastguard Worker }
1882*6236dae4SAndroid Build Coastguard Worker pktcnt = 0;
1883*6236dae4SAndroid Build Coastguard Worker continue;
1884*6236dae4SAndroid Build Coastguard Worker }
1885*6236dae4SAndroid Build Coastguard Worker
1886*6236dae4SAndroid Build Coastguard Worker if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) {
1887*6236dae4SAndroid Build Coastguard Worker /* Reached MAX_PKT_BURST *or*
1888*6236dae4SAndroid Build Coastguard Worker * the capacity of our buffer *or*
1889*6236dae4SAndroid Build Coastguard Worker * last add was shorter than the previous ones, flush */
1890*6236dae4SAndroid Build Coastguard Worker curlcode = vquic_send(cf, data, &ctx->q, gsolen);
1891*6236dae4SAndroid Build Coastguard Worker if(curlcode) {
1892*6236dae4SAndroid Build Coastguard Worker if(curlcode == CURLE_AGAIN) {
1893*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 1, EXPIRE_QUIC);
1894*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1895*6236dae4SAndroid Build Coastguard Worker }
1896*6236dae4SAndroid Build Coastguard Worker return curlcode;
1897*6236dae4SAndroid Build Coastguard Worker }
1898*6236dae4SAndroid Build Coastguard Worker /* pktbuf has been completely sent */
1899*6236dae4SAndroid Build Coastguard Worker pktcnt = 0;
1900*6236dae4SAndroid Build Coastguard Worker }
1901*6236dae4SAndroid Build Coastguard Worker }
1902*6236dae4SAndroid Build Coastguard Worker
1903*6236dae4SAndroid Build Coastguard Worker out:
1904*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1905*6236dae4SAndroid Build Coastguard Worker }
1906*6236dae4SAndroid Build Coastguard Worker
1907*6236dae4SAndroid Build Coastguard Worker /*
1908*6236dae4SAndroid Build Coastguard Worker * Called from transfer.c:data_pending to know if we should keep looping
1909*6236dae4SAndroid Build Coastguard Worker * to receive more data from the connection.
1910*6236dae4SAndroid Build Coastguard Worker */
cf_ngtcp2_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1911*6236dae4SAndroid Build Coastguard Worker static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
1912*6236dae4SAndroid Build Coastguard Worker const struct Curl_easy *data)
1913*6236dae4SAndroid Build Coastguard Worker {
1914*6236dae4SAndroid Build Coastguard Worker (void)cf;
1915*6236dae4SAndroid Build Coastguard Worker (void)data;
1916*6236dae4SAndroid Build Coastguard Worker return FALSE;
1917*6236dae4SAndroid Build Coastguard Worker }
1918*6236dae4SAndroid Build Coastguard Worker
h3_data_pause(struct Curl_cfilter * cf,struct Curl_easy * data,bool pause)1919*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_pause(struct Curl_cfilter *cf,
1920*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1921*6236dae4SAndroid Build Coastguard Worker bool pause)
1922*6236dae4SAndroid Build Coastguard Worker {
1923*6236dae4SAndroid Build Coastguard Worker /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge
1924*6236dae4SAndroid Build Coastguard Worker * the streams windows. As we do in HTTP/2. */
1925*6236dae4SAndroid Build Coastguard Worker if(!pause) {
1926*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
1927*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 0, EXPIRE_RUN_NOW);
1928*6236dae4SAndroid Build Coastguard Worker }
1929*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1930*6236dae4SAndroid Build Coastguard Worker }
1931*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_data_event(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1932*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
1933*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1934*6236dae4SAndroid Build Coastguard Worker int event, int arg1, void *arg2)
1935*6236dae4SAndroid Build Coastguard Worker {
1936*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
1937*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1938*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
1939*6236dae4SAndroid Build Coastguard Worker
1940*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
1941*6236dae4SAndroid Build Coastguard Worker (void)arg1;
1942*6236dae4SAndroid Build Coastguard Worker (void)arg2;
1943*6236dae4SAndroid Build Coastguard Worker switch(event) {
1944*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_SETUP:
1945*6236dae4SAndroid Build Coastguard Worker break;
1946*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_PAUSE:
1947*6236dae4SAndroid Build Coastguard Worker result = h3_data_pause(cf, data, (arg1 != 0));
1948*6236dae4SAndroid Build Coastguard Worker break;
1949*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DETACH:
1950*6236dae4SAndroid Build Coastguard Worker h3_data_done(cf, data);
1951*6236dae4SAndroid Build Coastguard Worker break;
1952*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DONE:
1953*6236dae4SAndroid Build Coastguard Worker h3_data_done(cf, data);
1954*6236dae4SAndroid Build Coastguard Worker break;
1955*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DONE_SEND: {
1956*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1957*6236dae4SAndroid Build Coastguard Worker if(stream && !stream->send_closed) {
1958*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
1959*6236dae4SAndroid Build Coastguard Worker stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
1960*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight;
1961*6236dae4SAndroid Build Coastguard Worker (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
1962*6236dae4SAndroid Build Coastguard Worker }
1963*6236dae4SAndroid Build Coastguard Worker break;
1964*6236dae4SAndroid Build Coastguard Worker }
1965*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_IDLE: {
1966*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1967*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "data idle");
1968*6236dae4SAndroid Build Coastguard Worker if(stream && !stream->closed) {
1969*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data, NULL);
1970*6236dae4SAndroid Build Coastguard Worker if(result)
1971*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result);
1972*6236dae4SAndroid Build Coastguard Worker }
1973*6236dae4SAndroid Build Coastguard Worker break;
1974*6236dae4SAndroid Build Coastguard Worker }
1975*6236dae4SAndroid Build Coastguard Worker default:
1976*6236dae4SAndroid Build Coastguard Worker break;
1977*6236dae4SAndroid Build Coastguard Worker }
1978*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
1979*6236dae4SAndroid Build Coastguard Worker return result;
1980*6236dae4SAndroid Build Coastguard Worker }
1981*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx * ctx)1982*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx)
1983*6236dae4SAndroid Build Coastguard Worker {
1984*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save = ctx->call_data;
1985*6236dae4SAndroid Build Coastguard Worker
1986*6236dae4SAndroid Build Coastguard Worker if(!ctx->initialized)
1987*6236dae4SAndroid Build Coastguard Worker return;
1988*6236dae4SAndroid Build Coastguard Worker if(ctx->qlogfd != -1) {
1989*6236dae4SAndroid Build Coastguard Worker close(ctx->qlogfd);
1990*6236dae4SAndroid Build Coastguard Worker }
1991*6236dae4SAndroid Build Coastguard Worker ctx->qlogfd = -1;
1992*6236dae4SAndroid Build Coastguard Worker Curl_vquic_tls_cleanup(&ctx->tls);
1993*6236dae4SAndroid Build Coastguard Worker vquic_ctx_free(&ctx->q);
1994*6236dae4SAndroid Build Coastguard Worker if(ctx->h3conn)
1995*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_del(ctx->h3conn);
1996*6236dae4SAndroid Build Coastguard Worker if(ctx->qconn)
1997*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_del(ctx->qconn);
1998*6236dae4SAndroid Build Coastguard Worker ctx->call_data = save;
1999*6236dae4SAndroid Build Coastguard Worker }
2000*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)2001*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
2002*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, bool *done)
2003*6236dae4SAndroid Build Coastguard Worker {
2004*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2005*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2006*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx pktx;
2007*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2008*6236dae4SAndroid Build Coastguard Worker
2009*6236dae4SAndroid Build Coastguard Worker if(cf->shutdown || !ctx->qconn) {
2010*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2011*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2012*6236dae4SAndroid Build Coastguard Worker }
2013*6236dae4SAndroid Build Coastguard Worker
2014*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2015*6236dae4SAndroid Build Coastguard Worker *done = FALSE;
2016*6236dae4SAndroid Build Coastguard Worker pktx_init(&pktx, cf, data);
2017*6236dae4SAndroid Build Coastguard Worker
2018*6236dae4SAndroid Build Coastguard Worker if(!ctx->shutdown_started) {
2019*6236dae4SAndroid Build Coastguard Worker char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
2020*6236dae4SAndroid Build Coastguard Worker ngtcp2_ssize nwritten;
2021*6236dae4SAndroid Build Coastguard Worker
2022*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
2023*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
2024*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, &pktx);
2025*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
2026*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
2027*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
2028*6236dae4SAndroid Build Coastguard Worker goto out;
2029*6236dae4SAndroid Build Coastguard Worker }
2030*6236dae4SAndroid Build Coastguard Worker else if(result) {
2031*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
2032*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2033*6236dae4SAndroid Build Coastguard Worker goto out;
2034*6236dae4SAndroid Build Coastguard Worker }
2035*6236dae4SAndroid Build Coastguard Worker }
2036*6236dae4SAndroid Build Coastguard Worker
2037*6236dae4SAndroid Build Coastguard Worker ctx->shutdown_started = TRUE;
2038*6236dae4SAndroid Build Coastguard Worker nwritten = ngtcp2_conn_write_connection_close(
2039*6236dae4SAndroid Build Coastguard Worker ctx->qconn, NULL, /* path */
2040*6236dae4SAndroid Build Coastguard Worker NULL, /* pkt_info */
2041*6236dae4SAndroid Build Coastguard Worker (uint8_t *)buffer, sizeof(buffer),
2042*6236dae4SAndroid Build Coastguard Worker &ctx->last_error, pktx.ts);
2043*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
2044*6236dae4SAndroid Build Coastguard Worker FMT_PRIu64 ") -> %d", ctx->last_error.type,
2045*6236dae4SAndroid Build Coastguard Worker (curl_uint64_t)ctx->last_error.error_code, (int)nwritten);
2046*6236dae4SAndroid Build Coastguard Worker if(nwritten > 0) {
2047*6236dae4SAndroid Build Coastguard Worker Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
2048*6236dae4SAndroid Build Coastguard Worker (size_t)nwritten, &result);
2049*6236dae4SAndroid Build Coastguard Worker if(result) {
2050*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
2051*6236dae4SAndroid Build Coastguard Worker "aborting shutdown", result);
2052*6236dae4SAndroid Build Coastguard Worker goto out;
2053*6236dae4SAndroid Build Coastguard Worker }
2054*6236dae4SAndroid Build Coastguard Worker ctx->q.no_gso = TRUE;
2055*6236dae4SAndroid Build Coastguard Worker ctx->q.gsolen = (size_t)nwritten;
2056*6236dae4SAndroid Build Coastguard Worker ctx->q.split_len = 0;
2057*6236dae4SAndroid Build Coastguard Worker }
2058*6236dae4SAndroid Build Coastguard Worker }
2059*6236dae4SAndroid Build Coastguard Worker
2060*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
2061*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown, flushing egress");
2062*6236dae4SAndroid Build Coastguard Worker result = vquic_flush(cf, data, &ctx->q);
2063*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_AGAIN) {
2064*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
2065*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
2066*6236dae4SAndroid Build Coastguard Worker goto out;
2067*6236dae4SAndroid Build Coastguard Worker }
2068*6236dae4SAndroid Build Coastguard Worker else if(result) {
2069*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
2070*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2071*6236dae4SAndroid Build Coastguard Worker goto out;
2072*6236dae4SAndroid Build Coastguard Worker }
2073*6236dae4SAndroid Build Coastguard Worker }
2074*6236dae4SAndroid Build Coastguard Worker
2075*6236dae4SAndroid Build Coastguard Worker if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
2076*6236dae4SAndroid Build Coastguard Worker /* Sent everything off. ngtcp2 seems to have no support for graceful
2077*6236dae4SAndroid Build Coastguard Worker * shutdowns. So, we are done. */
2078*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
2079*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2080*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
2081*6236dae4SAndroid Build Coastguard Worker }
2082*6236dae4SAndroid Build Coastguard Worker out:
2083*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2084*6236dae4SAndroid Build Coastguard Worker return result;
2085*6236dae4SAndroid Build Coastguard Worker }
2086*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_conn_close(struct Curl_cfilter * cf,struct Curl_easy * data)2087*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
2088*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
2089*6236dae4SAndroid Build Coastguard Worker {
2090*6236dae4SAndroid Build Coastguard Worker bool done;
2091*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_shutdown(cf, data, &done);
2092*6236dae4SAndroid Build Coastguard Worker }
2093*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_close(struct Curl_cfilter * cf,struct Curl_easy * data)2094*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2095*6236dae4SAndroid Build Coastguard Worker {
2096*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2097*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2098*6236dae4SAndroid Build Coastguard Worker
2099*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2100*6236dae4SAndroid Build Coastguard Worker if(ctx && ctx->qconn) {
2101*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_conn_close(cf, data);
2102*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_ctx_close(ctx);
2103*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "close");
2104*6236dae4SAndroid Build Coastguard Worker }
2105*6236dae4SAndroid Build Coastguard Worker cf->connected = FALSE;
2106*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2107*6236dae4SAndroid Build Coastguard Worker }
2108*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)2109*6236dae4SAndroid Build Coastguard Worker static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
2110*6236dae4SAndroid Build Coastguard Worker {
2111*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "destroy");
2112*6236dae4SAndroid Build Coastguard Worker if(cf->ctx) {
2113*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_ctx_free(cf->ctx);
2114*6236dae4SAndroid Build Coastguard Worker cf->ctx = NULL;
2115*6236dae4SAndroid Build Coastguard Worker }
2116*6236dae4SAndroid Build Coastguard Worker }
2117*6236dae4SAndroid Build Coastguard Worker
2118*6236dae4SAndroid Build Coastguard Worker #ifdef USE_OPENSSL
2119*6236dae4SAndroid Build Coastguard Worker /* The "new session" callback must return zero if the session can be removed
2120*6236dae4SAndroid Build Coastguard Worker * or non-zero if the session has been put into the session cache.
2121*6236dae4SAndroid Build Coastguard Worker */
quic_ossl_new_session_cb(SSL * ssl,SSL_SESSION * ssl_sessionid)2122*6236dae4SAndroid Build Coastguard Worker static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
2123*6236dae4SAndroid Build Coastguard Worker {
2124*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf;
2125*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx;
2126*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data;
2127*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_conn_ref *cref;
2128*6236dae4SAndroid Build Coastguard Worker
2129*6236dae4SAndroid Build Coastguard Worker cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
2130*6236dae4SAndroid Build Coastguard Worker cf = cref ? cref->user_data : NULL;
2131*6236dae4SAndroid Build Coastguard Worker ctx = cf ? cf->ctx : NULL;
2132*6236dae4SAndroid Build Coastguard Worker data = cf ? CF_DATA_CURRENT(cf) : NULL;
2133*6236dae4SAndroid Build Coastguard Worker if(cf && data && ctx) {
2134*6236dae4SAndroid Build Coastguard Worker Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
2135*6236dae4SAndroid Build Coastguard Worker return 1;
2136*6236dae4SAndroid Build Coastguard Worker }
2137*6236dae4SAndroid Build Coastguard Worker return 0;
2138*6236dae4SAndroid Build Coastguard Worker }
2139*6236dae4SAndroid Build Coastguard Worker #endif /* USE_OPENSSL */
2140*6236dae4SAndroid Build Coastguard Worker
2141*6236dae4SAndroid Build Coastguard Worker #ifdef USE_GNUTLS
quic_gtls_handshake_cb(gnutls_session_t session,unsigned int htype,unsigned when,unsigned int incoming,const gnutls_datum_t * msg)2142*6236dae4SAndroid Build Coastguard Worker static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
2143*6236dae4SAndroid Build Coastguard Worker unsigned when, unsigned int incoming,
2144*6236dae4SAndroid Build Coastguard Worker const gnutls_datum_t *msg)
2145*6236dae4SAndroid Build Coastguard Worker {
2146*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session);
2147*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
2148*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
2149*6236dae4SAndroid Build Coastguard Worker
2150*6236dae4SAndroid Build Coastguard Worker (void)msg;
2151*6236dae4SAndroid Build Coastguard Worker (void)incoming;
2152*6236dae4SAndroid Build Coastguard Worker if(when && cf && ctx) { /* after message has been processed */
2153*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = CF_DATA_CURRENT(cf);
2154*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
2155*6236dae4SAndroid Build Coastguard Worker if(data) {
2156*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "handshake: %s message type %d",
2157*6236dae4SAndroid Build Coastguard Worker incoming ? "incoming" : "outgoing", htype);
2158*6236dae4SAndroid Build Coastguard Worker }
2159*6236dae4SAndroid Build Coastguard Worker switch(htype) {
2160*6236dae4SAndroid Build Coastguard Worker case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
2161*6236dae4SAndroid Build Coastguard Worker (void)Curl_gtls_update_session_id(cf, data, session, &ctx->peer, "h3");
2162*6236dae4SAndroid Build Coastguard Worker break;
2163*6236dae4SAndroid Build Coastguard Worker }
2164*6236dae4SAndroid Build Coastguard Worker default:
2165*6236dae4SAndroid Build Coastguard Worker break;
2166*6236dae4SAndroid Build Coastguard Worker }
2167*6236dae4SAndroid Build Coastguard Worker }
2168*6236dae4SAndroid Build Coastguard Worker return 0;
2169*6236dae4SAndroid Build Coastguard Worker }
2170*6236dae4SAndroid Build Coastguard Worker #endif /* USE_GNUTLS */
2171*6236dae4SAndroid Build Coastguard Worker
2172*6236dae4SAndroid Build Coastguard Worker #ifdef USE_WOLFSSL
wssl_quic_new_session_cb(WOLFSSL * ssl,WOLFSSL_SESSION * session)2173*6236dae4SAndroid Build Coastguard Worker static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
2174*6236dae4SAndroid Build Coastguard Worker {
2175*6236dae4SAndroid Build Coastguard Worker ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl);
2176*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
2177*6236dae4SAndroid Build Coastguard Worker
2178*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cf != NULL);
2179*6236dae4SAndroid Build Coastguard Worker if(cf && session) {
2180*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2181*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = CF_DATA_CURRENT(cf);
2182*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
2183*6236dae4SAndroid Build Coastguard Worker if(data && ctx) {
2184*6236dae4SAndroid Build Coastguard Worker (void)wssl_cache_session(cf, data, &ctx->peer, session);
2185*6236dae4SAndroid Build Coastguard Worker }
2186*6236dae4SAndroid Build Coastguard Worker }
2187*6236dae4SAndroid Build Coastguard Worker return 0;
2188*6236dae4SAndroid Build Coastguard Worker }
2189*6236dae4SAndroid Build Coastguard Worker #endif /* USE_WOLFSSL */
2190*6236dae4SAndroid Build Coastguard Worker
tls_ctx_setup(struct Curl_cfilter * cf,struct Curl_easy * data,void * user_data)2191*6236dae4SAndroid Build Coastguard Worker static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
2192*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2193*6236dae4SAndroid Build Coastguard Worker void *user_data)
2194*6236dae4SAndroid Build Coastguard Worker {
2195*6236dae4SAndroid Build Coastguard Worker struct curl_tls_ctx *ctx = user_data;
2196*6236dae4SAndroid Build Coastguard Worker struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
2197*6236dae4SAndroid Build Coastguard Worker
2198*6236dae4SAndroid Build Coastguard Worker #ifdef USE_OPENSSL
2199*6236dae4SAndroid Build Coastguard Worker #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
2200*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
2201*6236dae4SAndroid Build Coastguard Worker != 0) {
2202*6236dae4SAndroid Build Coastguard Worker failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
2203*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2204*6236dae4SAndroid Build Coastguard Worker }
2205*6236dae4SAndroid Build Coastguard Worker #else
2206*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
2207*6236dae4SAndroid Build Coastguard Worker failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
2208*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2209*6236dae4SAndroid Build Coastguard Worker }
2210*6236dae4SAndroid Build Coastguard Worker #endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
2211*6236dae4SAndroid Build Coastguard Worker if(ssl_config->primary.cache_session) {
2212*6236dae4SAndroid Build Coastguard Worker /* Enable the session cache because it is a prerequisite for the
2213*6236dae4SAndroid Build Coastguard Worker * "new session" callback. Use the "external storage" mode to prevent
2214*6236dae4SAndroid Build Coastguard Worker * OpenSSL from creating an internal session cache.
2215*6236dae4SAndroid Build Coastguard Worker */
2216*6236dae4SAndroid Build Coastguard Worker SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
2217*6236dae4SAndroid Build Coastguard Worker SSL_SESS_CACHE_CLIENT |
2218*6236dae4SAndroid Build Coastguard Worker SSL_SESS_CACHE_NO_INTERNAL);
2219*6236dae4SAndroid Build Coastguard Worker SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
2220*6236dae4SAndroid Build Coastguard Worker }
2221*6236dae4SAndroid Build Coastguard Worker
2222*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_GNUTLS)
2223*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
2224*6236dae4SAndroid Build Coastguard Worker failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
2225*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2226*6236dae4SAndroid Build Coastguard Worker }
2227*6236dae4SAndroid Build Coastguard Worker if(ssl_config->primary.cache_session) {
2228*6236dae4SAndroid Build Coastguard Worker gnutls_handshake_set_hook_function(ctx->gtls.session,
2229*6236dae4SAndroid Build Coastguard Worker GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
2230*6236dae4SAndroid Build Coastguard Worker quic_gtls_handshake_cb);
2231*6236dae4SAndroid Build Coastguard Worker }
2232*6236dae4SAndroid Build Coastguard Worker
2233*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_WOLFSSL)
2234*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
2235*6236dae4SAndroid Build Coastguard Worker failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
2236*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2237*6236dae4SAndroid Build Coastguard Worker }
2238*6236dae4SAndroid Build Coastguard Worker if(ssl_config->primary.cache_session) {
2239*6236dae4SAndroid Build Coastguard Worker /* Register to get notified when a new session is received */
2240*6236dae4SAndroid Build Coastguard Worker wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
2241*6236dae4SAndroid Build Coastguard Worker }
2242*6236dae4SAndroid Build Coastguard Worker #endif
2243*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2244*6236dae4SAndroid Build Coastguard Worker }
2245*6236dae4SAndroid Build Coastguard Worker
2246*6236dae4SAndroid Build Coastguard Worker /*
2247*6236dae4SAndroid Build Coastguard Worker * Might be called twice for happy eyeballs.
2248*6236dae4SAndroid Build Coastguard Worker */
cf_connect_start(struct Curl_cfilter * cf,struct Curl_easy * data,struct pkt_io_ctx * pktx)2249*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_connect_start(struct Curl_cfilter *cf,
2250*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2251*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx *pktx)
2252*6236dae4SAndroid Build Coastguard Worker {
2253*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2254*6236dae4SAndroid Build Coastguard Worker int rc;
2255*6236dae4SAndroid Build Coastguard Worker int rv;
2256*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2257*6236dae4SAndroid Build Coastguard Worker const struct Curl_sockaddr_ex *sockaddr = NULL;
2258*6236dae4SAndroid Build Coastguard Worker int qfd;
2259*6236dae4SAndroid Build Coastguard Worker
2260*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->initialized);
2261*6236dae4SAndroid Build Coastguard Worker result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
2262*6236dae4SAndroid Build Coastguard Worker if(result)
2263*6236dae4SAndroid Build Coastguard Worker return result;
2264*6236dae4SAndroid Build Coastguard Worker
2265*6236dae4SAndroid Build Coastguard Worker #define H3_ALPN "\x2h3\x5h3-29"
2266*6236dae4SAndroid Build Coastguard Worker result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
2267*6236dae4SAndroid Build Coastguard Worker H3_ALPN, sizeof(H3_ALPN) - 1,
2268*6236dae4SAndroid Build Coastguard Worker tls_ctx_setup, &ctx->tls, &ctx->conn_ref);
2269*6236dae4SAndroid Build Coastguard Worker if(result)
2270*6236dae4SAndroid Build Coastguard Worker return result;
2271*6236dae4SAndroid Build Coastguard Worker
2272*6236dae4SAndroid Build Coastguard Worker #ifdef USE_OPENSSL
2273*6236dae4SAndroid Build Coastguard Worker SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
2274*6236dae4SAndroid Build Coastguard Worker #endif
2275*6236dae4SAndroid Build Coastguard Worker
2276*6236dae4SAndroid Build Coastguard Worker ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
2277*6236dae4SAndroid Build Coastguard Worker result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
2278*6236dae4SAndroid Build Coastguard Worker if(result)
2279*6236dae4SAndroid Build Coastguard Worker return result;
2280*6236dae4SAndroid Build Coastguard Worker
2281*6236dae4SAndroid Build Coastguard Worker ctx->scid.datalen = NGTCP2_MAX_CIDLEN;
2282*6236dae4SAndroid Build Coastguard Worker result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN);
2283*6236dae4SAndroid Build Coastguard Worker if(result)
2284*6236dae4SAndroid Build Coastguard Worker return result;
2285*6236dae4SAndroid Build Coastguard Worker
2286*6236dae4SAndroid Build Coastguard Worker (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
2287*6236dae4SAndroid Build Coastguard Worker ctx->qlogfd = qfd; /* -1 if failure above */
2288*6236dae4SAndroid Build Coastguard Worker quic_settings(ctx, data, pktx);
2289*6236dae4SAndroid Build Coastguard Worker
2290*6236dae4SAndroid Build Coastguard Worker result = vquic_ctx_init(&ctx->q);
2291*6236dae4SAndroid Build Coastguard Worker if(result)
2292*6236dae4SAndroid Build Coastguard Worker return result;
2293*6236dae4SAndroid Build Coastguard Worker
2294*6236dae4SAndroid Build Coastguard Worker Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
2295*6236dae4SAndroid Build Coastguard Worker if(!sockaddr)
2296*6236dae4SAndroid Build Coastguard Worker return CURLE_QUIC_CONNECT_ERROR;
2297*6236dae4SAndroid Build Coastguard Worker ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
2298*6236dae4SAndroid Build Coastguard Worker rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
2299*6236dae4SAndroid Build Coastguard Worker &ctx->q.local_addrlen);
2300*6236dae4SAndroid Build Coastguard Worker if(rv == -1)
2301*6236dae4SAndroid Build Coastguard Worker return CURLE_QUIC_CONNECT_ERROR;
2302*6236dae4SAndroid Build Coastguard Worker
2303*6236dae4SAndroid Build Coastguard Worker ngtcp2_addr_init(&ctx->connected_path.local,
2304*6236dae4SAndroid Build Coastguard Worker (struct sockaddr *)&ctx->q.local_addr,
2305*6236dae4SAndroid Build Coastguard Worker ctx->q.local_addrlen);
2306*6236dae4SAndroid Build Coastguard Worker ngtcp2_addr_init(&ctx->connected_path.remote,
2307*6236dae4SAndroid Build Coastguard Worker &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen);
2308*6236dae4SAndroid Build Coastguard Worker
2309*6236dae4SAndroid Build Coastguard Worker rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
2310*6236dae4SAndroid Build Coastguard Worker &ctx->connected_path,
2311*6236dae4SAndroid Build Coastguard Worker NGTCP2_PROTO_VER_V1, &ng_callbacks,
2312*6236dae4SAndroid Build Coastguard Worker &ctx->settings, &ctx->transport_params,
2313*6236dae4SAndroid Build Coastguard Worker NULL, cf);
2314*6236dae4SAndroid Build Coastguard Worker if(rc)
2315*6236dae4SAndroid Build Coastguard Worker return CURLE_QUIC_CONNECT_ERROR;
2316*6236dae4SAndroid Build Coastguard Worker
2317*6236dae4SAndroid Build Coastguard Worker #ifdef USE_OPENSSL
2318*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
2319*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_GNUTLS)
2320*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
2321*6236dae4SAndroid Build Coastguard Worker #elif defined(USE_WOLFSSL)
2322*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
2323*6236dae4SAndroid Build Coastguard Worker #else
2324*6236dae4SAndroid Build Coastguard Worker #error "ngtcp2 TLS backend not defined"
2325*6236dae4SAndroid Build Coastguard Worker #endif
2326*6236dae4SAndroid Build Coastguard Worker
2327*6236dae4SAndroid Build Coastguard Worker ngtcp2_ccerr_default(&ctx->last_error);
2328*6236dae4SAndroid Build Coastguard Worker
2329*6236dae4SAndroid Build Coastguard Worker ctx->conn_ref.get_conn = get_conn;
2330*6236dae4SAndroid Build Coastguard Worker ctx->conn_ref.user_data = cf;
2331*6236dae4SAndroid Build Coastguard Worker
2332*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2333*6236dae4SAndroid Build Coastguard Worker }
2334*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)2335*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
2336*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2337*6236dae4SAndroid Build Coastguard Worker bool blocking, bool *done)
2338*6236dae4SAndroid Build Coastguard Worker {
2339*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2340*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2341*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2342*6236dae4SAndroid Build Coastguard Worker struct curltime now;
2343*6236dae4SAndroid Build Coastguard Worker struct pkt_io_ctx pktx;
2344*6236dae4SAndroid Build Coastguard Worker
2345*6236dae4SAndroid Build Coastguard Worker if(cf->connected) {
2346*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2347*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2348*6236dae4SAndroid Build Coastguard Worker }
2349*6236dae4SAndroid Build Coastguard Worker
2350*6236dae4SAndroid Build Coastguard Worker /* Connect the UDP filter first */
2351*6236dae4SAndroid Build Coastguard Worker if(!cf->next->connected) {
2352*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_cf_connect(cf->next, data, blocking, done);
2353*6236dae4SAndroid Build Coastguard Worker if(result || !*done)
2354*6236dae4SAndroid Build Coastguard Worker return result;
2355*6236dae4SAndroid Build Coastguard Worker }
2356*6236dae4SAndroid Build Coastguard Worker
2357*6236dae4SAndroid Build Coastguard Worker *done = FALSE;
2358*6236dae4SAndroid Build Coastguard Worker now = Curl_now();
2359*6236dae4SAndroid Build Coastguard Worker pktx_init(&pktx, cf, data);
2360*6236dae4SAndroid Build Coastguard Worker
2361*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2362*6236dae4SAndroid Build Coastguard Worker
2363*6236dae4SAndroid Build Coastguard Worker if(!ctx->qconn) {
2364*6236dae4SAndroid Build Coastguard Worker ctx->started_at = now;
2365*6236dae4SAndroid Build Coastguard Worker result = cf_connect_start(cf, data, &pktx);
2366*6236dae4SAndroid Build Coastguard Worker if(result)
2367*6236dae4SAndroid Build Coastguard Worker goto out;
2368*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, &pktx);
2369*6236dae4SAndroid Build Coastguard Worker /* we do not expect to be able to recv anything yet */
2370*6236dae4SAndroid Build Coastguard Worker goto out;
2371*6236dae4SAndroid Build Coastguard Worker }
2372*6236dae4SAndroid Build Coastguard Worker
2373*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data, &pktx);
2374*6236dae4SAndroid Build Coastguard Worker if(result)
2375*6236dae4SAndroid Build Coastguard Worker goto out;
2376*6236dae4SAndroid Build Coastguard Worker
2377*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data, &pktx);
2378*6236dae4SAndroid Build Coastguard Worker if(result)
2379*6236dae4SAndroid Build Coastguard Worker goto out;
2380*6236dae4SAndroid Build Coastguard Worker
2381*6236dae4SAndroid Build Coastguard Worker if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) {
2382*6236dae4SAndroid Build Coastguard Worker ctx->handshake_at = now;
2383*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "handshake complete after %dms",
2384*6236dae4SAndroid Build Coastguard Worker (int)Curl_timediff(now, ctx->started_at));
2385*6236dae4SAndroid Build Coastguard Worker result = qng_verify_peer(cf, data);
2386*6236dae4SAndroid Build Coastguard Worker if(!result) {
2387*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "peer verified");
2388*6236dae4SAndroid Build Coastguard Worker cf->connected = TRUE;
2389*6236dae4SAndroid Build Coastguard Worker cf->conn->alpn = CURL_HTTP_VERSION_3;
2390*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
2391*6236dae4SAndroid Build Coastguard Worker connkeep(cf->conn, "HTTP/3 default");
2392*6236dae4SAndroid Build Coastguard Worker }
2393*6236dae4SAndroid Build Coastguard Worker }
2394*6236dae4SAndroid Build Coastguard Worker
2395*6236dae4SAndroid Build Coastguard Worker out:
2396*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_RECV_ERROR && ctx->qconn &&
2397*6236dae4SAndroid Build Coastguard Worker ngtcp2_conn_in_draining_period(ctx->qconn)) {
2398*6236dae4SAndroid Build Coastguard Worker /* When a QUIC server instance is shutting down, it may send us a
2399*6236dae4SAndroid Build Coastguard Worker * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
2400*6236dae4SAndroid Build Coastguard Worker * state. The CONNECT may work in the near future again. Indicate
2401*6236dae4SAndroid Build Coastguard Worker * that as a "weird" reply. */
2402*6236dae4SAndroid Build Coastguard Worker result = CURLE_WEIRD_SERVER_REPLY;
2403*6236dae4SAndroid Build Coastguard Worker }
2404*6236dae4SAndroid Build Coastguard Worker
2405*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
2406*6236dae4SAndroid Build Coastguard Worker if(result) {
2407*6236dae4SAndroid Build Coastguard Worker struct ip_quadruple ip;
2408*6236dae4SAndroid Build Coastguard Worker
2409*6236dae4SAndroid Build Coastguard Worker Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
2410*6236dae4SAndroid Build Coastguard Worker infof(data, "QUIC connect to %s port %u failed: %s",
2411*6236dae4SAndroid Build Coastguard Worker ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
2412*6236dae4SAndroid Build Coastguard Worker }
2413*6236dae4SAndroid Build Coastguard Worker #endif
2414*6236dae4SAndroid Build Coastguard Worker if(!result && ctx->qconn) {
2415*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data, &pktx);
2416*6236dae4SAndroid Build Coastguard Worker }
2417*6236dae4SAndroid Build Coastguard Worker if(result || *done)
2418*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
2419*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2420*6236dae4SAndroid Build Coastguard Worker return result;
2421*6236dae4SAndroid Build Coastguard Worker }
2422*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)2423*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
2424*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2425*6236dae4SAndroid Build Coastguard Worker int query, int *pres1, void *pres2)
2426*6236dae4SAndroid Build Coastguard Worker {
2427*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2428*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2429*6236dae4SAndroid Build Coastguard Worker
2430*6236dae4SAndroid Build Coastguard Worker switch(query) {
2431*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_MAX_CONCURRENT: {
2432*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(pres1);
2433*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2434*6236dae4SAndroid Build Coastguard Worker /* Set after transport params arrived and continually updated
2435*6236dae4SAndroid Build Coastguard Worker * by callback. QUIC counts the number over the lifetime of the
2436*6236dae4SAndroid Build Coastguard Worker * connection, ever increasing.
2437*6236dae4SAndroid Build Coastguard Worker * We count the *open* transfers plus the budget for new ones. */
2438*6236dae4SAndroid Build Coastguard Worker if(!ctx->qconn || ctx->shutdown_started) {
2439*6236dae4SAndroid Build Coastguard Worker *pres1 = 0;
2440*6236dae4SAndroid Build Coastguard Worker }
2441*6236dae4SAndroid Build Coastguard Worker else if(ctx->max_bidi_streams) {
2442*6236dae4SAndroid Build Coastguard Worker uint64_t avail_bidi_streams = 0;
2443*6236dae4SAndroid Build Coastguard Worker uint64_t max_streams = CONN_INUSE(cf->conn);
2444*6236dae4SAndroid Build Coastguard Worker if(ctx->max_bidi_streams > ctx->used_bidi_streams)
2445*6236dae4SAndroid Build Coastguard Worker avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
2446*6236dae4SAndroid Build Coastguard Worker max_streams += avail_bidi_streams;
2447*6236dae4SAndroid Build Coastguard Worker *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
2448*6236dae4SAndroid Build Coastguard Worker }
2449*6236dae4SAndroid Build Coastguard Worker else /* transport params not arrived yet? take our default. */
2450*6236dae4SAndroid Build Coastguard Worker *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
2451*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
2452*6236dae4SAndroid Build Coastguard Worker "MAX_CONCURRENT -> %d (%zu in use)",
2453*6236dae4SAndroid Build Coastguard Worker cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
2454*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2455*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2456*6236dae4SAndroid Build Coastguard Worker }
2457*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_CONNECT_REPLY_MS:
2458*6236dae4SAndroid Build Coastguard Worker if(ctx->q.got_first_byte) {
2459*6236dae4SAndroid Build Coastguard Worker timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
2460*6236dae4SAndroid Build Coastguard Worker *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
2461*6236dae4SAndroid Build Coastguard Worker }
2462*6236dae4SAndroid Build Coastguard Worker else
2463*6236dae4SAndroid Build Coastguard Worker *pres1 = -1;
2464*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2465*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_TIMER_CONNECT: {
2466*6236dae4SAndroid Build Coastguard Worker struct curltime *when = pres2;
2467*6236dae4SAndroid Build Coastguard Worker if(ctx->q.got_first_byte)
2468*6236dae4SAndroid Build Coastguard Worker *when = ctx->q.first_byte_at;
2469*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2470*6236dae4SAndroid Build Coastguard Worker }
2471*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_TIMER_APPCONNECT: {
2472*6236dae4SAndroid Build Coastguard Worker struct curltime *when = pres2;
2473*6236dae4SAndroid Build Coastguard Worker if(cf->connected)
2474*6236dae4SAndroid Build Coastguard Worker *when = ctx->handshake_at;
2475*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2476*6236dae4SAndroid Build Coastguard Worker }
2477*6236dae4SAndroid Build Coastguard Worker default:
2478*6236dae4SAndroid Build Coastguard Worker break;
2479*6236dae4SAndroid Build Coastguard Worker }
2480*6236dae4SAndroid Build Coastguard Worker return cf->next ?
2481*6236dae4SAndroid Build Coastguard Worker cf->next->cft->query(cf->next, data, query, pres1, pres2) :
2482*6236dae4SAndroid Build Coastguard Worker CURLE_UNKNOWN_OPTION;
2483*6236dae4SAndroid Build Coastguard Worker }
2484*6236dae4SAndroid Build Coastguard Worker
cf_ngtcp2_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)2485*6236dae4SAndroid Build Coastguard Worker static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
2486*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2487*6236dae4SAndroid Build Coastguard Worker bool *input_pending)
2488*6236dae4SAndroid Build Coastguard Worker {
2489*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = cf->ctx;
2490*6236dae4SAndroid Build Coastguard Worker bool alive = FALSE;
2491*6236dae4SAndroid Build Coastguard Worker const ngtcp2_transport_params *rp;
2492*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2493*6236dae4SAndroid Build Coastguard Worker
2494*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2495*6236dae4SAndroid Build Coastguard Worker *input_pending = FALSE;
2496*6236dae4SAndroid Build Coastguard Worker if(!ctx->qconn || ctx->shutdown_started)
2497*6236dae4SAndroid Build Coastguard Worker goto out;
2498*6236dae4SAndroid Build Coastguard Worker
2499*6236dae4SAndroid Build Coastguard Worker /* Both sides of the QUIC connection announce they max idle times in
2500*6236dae4SAndroid Build Coastguard Worker * the transport parameters. Look at the minimum of both and if
2501*6236dae4SAndroid Build Coastguard Worker * we exceed this, regard the connection as dead. The other side
2502*6236dae4SAndroid Build Coastguard Worker * may have completely purged it and will no longer respond
2503*6236dae4SAndroid Build Coastguard Worker * to any packets from us. */
2504*6236dae4SAndroid Build Coastguard Worker rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
2505*6236dae4SAndroid Build Coastguard Worker if(rp) {
2506*6236dae4SAndroid Build Coastguard Worker timediff_t idletime;
2507*6236dae4SAndroid Build Coastguard Worker uint64_t idle_ms = ctx->max_idle_ms;
2508*6236dae4SAndroid Build Coastguard Worker
2509*6236dae4SAndroid Build Coastguard Worker if(rp->max_idle_timeout &&
2510*6236dae4SAndroid Build Coastguard Worker (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms)
2511*6236dae4SAndroid Build Coastguard Worker idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS);
2512*6236dae4SAndroid Build Coastguard Worker idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
2513*6236dae4SAndroid Build Coastguard Worker if(idletime > 0 && (uint64_t)idletime > idle_ms)
2514*6236dae4SAndroid Build Coastguard Worker goto out;
2515*6236dae4SAndroid Build Coastguard Worker }
2516*6236dae4SAndroid Build Coastguard Worker
2517*6236dae4SAndroid Build Coastguard Worker if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
2518*6236dae4SAndroid Build Coastguard Worker goto out;
2519*6236dae4SAndroid Build Coastguard Worker
2520*6236dae4SAndroid Build Coastguard Worker alive = TRUE;
2521*6236dae4SAndroid Build Coastguard Worker if(*input_pending) {
2522*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2523*6236dae4SAndroid Build Coastguard Worker /* This happens before we have sent off a request and the connection is
2524*6236dae4SAndroid Build Coastguard Worker not in use by any other transfer, there should not be any data here,
2525*6236dae4SAndroid Build Coastguard Worker only "protocol frames" */
2526*6236dae4SAndroid Build Coastguard Worker *input_pending = FALSE;
2527*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data, NULL);
2528*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
2529*6236dae4SAndroid Build Coastguard Worker alive = result ? FALSE : TRUE;
2530*6236dae4SAndroid Build Coastguard Worker }
2531*6236dae4SAndroid Build Coastguard Worker
2532*6236dae4SAndroid Build Coastguard Worker out:
2533*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2534*6236dae4SAndroid Build Coastguard Worker return alive;
2535*6236dae4SAndroid Build Coastguard Worker }
2536*6236dae4SAndroid Build Coastguard Worker
2537*6236dae4SAndroid Build Coastguard Worker struct Curl_cftype Curl_cft_http3 = {
2538*6236dae4SAndroid Build Coastguard Worker "HTTP/3",
2539*6236dae4SAndroid Build Coastguard Worker CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
2540*6236dae4SAndroid Build Coastguard Worker 0,
2541*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_destroy,
2542*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_connect,
2543*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_close,
2544*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_shutdown,
2545*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_get_host,
2546*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_adjust_pollset,
2547*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_data_pending,
2548*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_send,
2549*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_recv,
2550*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_data_event,
2551*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_conn_is_alive,
2552*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_conn_keep_alive,
2553*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_query,
2554*6236dae4SAndroid Build Coastguard Worker };
2555*6236dae4SAndroid Build Coastguard Worker
Curl_cf_ngtcp2_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai)2556*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
2557*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2558*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
2559*6236dae4SAndroid Build Coastguard Worker const struct Curl_addrinfo *ai)
2560*6236dae4SAndroid Build Coastguard Worker {
2561*6236dae4SAndroid Build Coastguard Worker struct cf_ngtcp2_ctx *ctx = NULL;
2562*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
2563*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2564*6236dae4SAndroid Build Coastguard Worker
2565*6236dae4SAndroid Build Coastguard Worker (void)data;
2566*6236dae4SAndroid Build Coastguard Worker ctx = calloc(1, sizeof(*ctx));
2567*6236dae4SAndroid Build Coastguard Worker if(!ctx) {
2568*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
2569*6236dae4SAndroid Build Coastguard Worker goto out;
2570*6236dae4SAndroid Build Coastguard Worker }
2571*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_ctx_init(ctx);
2572*6236dae4SAndroid Build Coastguard Worker
2573*6236dae4SAndroid Build Coastguard Worker result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
2574*6236dae4SAndroid Build Coastguard Worker if(result)
2575*6236dae4SAndroid Build Coastguard Worker goto out;
2576*6236dae4SAndroid Build Coastguard Worker
2577*6236dae4SAndroid Build Coastguard Worker result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
2578*6236dae4SAndroid Build Coastguard Worker if(result)
2579*6236dae4SAndroid Build Coastguard Worker goto out;
2580*6236dae4SAndroid Build Coastguard Worker
2581*6236dae4SAndroid Build Coastguard Worker cf->conn = conn;
2582*6236dae4SAndroid Build Coastguard Worker udp_cf->conn = cf->conn;
2583*6236dae4SAndroid Build Coastguard Worker udp_cf->sockindex = cf->sockindex;
2584*6236dae4SAndroid Build Coastguard Worker cf->next = udp_cf;
2585*6236dae4SAndroid Build Coastguard Worker
2586*6236dae4SAndroid Build Coastguard Worker out:
2587*6236dae4SAndroid Build Coastguard Worker *pcf = (!result) ? cf : NULL;
2588*6236dae4SAndroid Build Coastguard Worker if(result) {
2589*6236dae4SAndroid Build Coastguard Worker if(udp_cf)
2590*6236dae4SAndroid Build Coastguard Worker Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
2591*6236dae4SAndroid Build Coastguard Worker Curl_safefree(cf);
2592*6236dae4SAndroid Build Coastguard Worker cf_ngtcp2_ctx_free(ctx);
2593*6236dae4SAndroid Build Coastguard Worker }
2594*6236dae4SAndroid Build Coastguard Worker return result;
2595*6236dae4SAndroid Build Coastguard Worker }
2596*6236dae4SAndroid Build Coastguard Worker
Curl_conn_is_ngtcp2(const struct Curl_easy * data,const struct connectdata * conn,int sockindex)2597*6236dae4SAndroid Build Coastguard Worker bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
2598*6236dae4SAndroid Build Coastguard Worker const struct connectdata *conn,
2599*6236dae4SAndroid Build Coastguard Worker int sockindex)
2600*6236dae4SAndroid Build Coastguard Worker {
2601*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
2602*6236dae4SAndroid Build Coastguard Worker
2603*6236dae4SAndroid Build Coastguard Worker (void)data;
2604*6236dae4SAndroid Build Coastguard Worker for(; cf; cf = cf->next) {
2605*6236dae4SAndroid Build Coastguard Worker if(cf->cft == &Curl_cft_http3)
2606*6236dae4SAndroid Build Coastguard Worker return TRUE;
2607*6236dae4SAndroid Build Coastguard Worker if(cf->cft->flags & CF_TYPE_IP_CONNECT)
2608*6236dae4SAndroid Build Coastguard Worker return FALSE;
2609*6236dae4SAndroid Build Coastguard Worker }
2610*6236dae4SAndroid Build Coastguard Worker return FALSE;
2611*6236dae4SAndroid Build Coastguard Worker }
2612*6236dae4SAndroid Build Coastguard Worker
2613*6236dae4SAndroid Build Coastguard Worker #endif
2614