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_OPENSSL_QUIC) && defined(USE_NGHTTP3)
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Worker #include <openssl/ssl.h>
30*6236dae4SAndroid Build Coastguard Worker #include <openssl/bio.h>
31*6236dae4SAndroid Build Coastguard Worker #include <openssl/err.h>
32*6236dae4SAndroid Build Coastguard Worker #include <nghttp3/nghttp3.h>
33*6236dae4SAndroid Build Coastguard Worker
34*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
35*6236dae4SAndroid Build Coastguard Worker #include "hash.h"
36*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
37*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
38*6236dae4SAndroid Build Coastguard Worker #include "rand.h"
39*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
40*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
41*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
42*6236dae4SAndroid Build Coastguard Worker #include "cf-socket.h"
43*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
44*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
45*6236dae4SAndroid Build Coastguard Worker #include "strerror.h"
46*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
47*6236dae4SAndroid Build Coastguard Worker #include "http1.h"
48*6236dae4SAndroid Build Coastguard Worker #include "select.h"
49*6236dae4SAndroid Build Coastguard Worker #include "inet_pton.h"
50*6236dae4SAndroid Build Coastguard Worker #include "vquic.h"
51*6236dae4SAndroid Build Coastguard Worker #include "vquic_int.h"
52*6236dae4SAndroid Build Coastguard Worker #include "vquic-tls.h"
53*6236dae4SAndroid Build Coastguard Worker #include "vtls/keylog.h"
54*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
55*6236dae4SAndroid Build Coastguard Worker #include "vtls/openssl.h"
56*6236dae4SAndroid Build Coastguard Worker #include "curl_osslq.h"
57*6236dae4SAndroid Build Coastguard Worker
58*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
59*6236dae4SAndroid Build Coastguard Worker
60*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
61*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
62*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
63*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
64*6236dae4SAndroid Build Coastguard Worker
65*6236dae4SAndroid Build Coastguard Worker /* A stream window is the maximum amount we need to buffer for
66*6236dae4SAndroid Build Coastguard Worker * each active transfer. We use HTTP/3 flow control and only ACK
67*6236dae4SAndroid Build Coastguard Worker * when we take things out of the buffer.
68*6236dae4SAndroid Build Coastguard Worker * Chunk size is large enough to take a full DATA frame */
69*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_WINDOW_SIZE (128 * 1024)
70*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CHUNK_SIZE (16 * 1024)
71*6236dae4SAndroid Build Coastguard Worker /* The pool keeps spares around and half of a full stream window
72*6236dae4SAndroid Build Coastguard Worker * seems good. More does not seem to improve performance.
73*6236dae4SAndroid Build Coastguard Worker * The benefit of the pool is that stream buffer to not keep
74*6236dae4SAndroid Build Coastguard Worker * spares. Memory consumption goes down when streams run empty,
75*6236dae4SAndroid Build Coastguard Worker * have a large upload done, etc. */
76*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_POOL_SPARES \
77*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
78*6236dae4SAndroid Build Coastguard Worker /* Receive and Send max number of chunks just follows from the
79*6236dae4SAndroid Build Coastguard Worker * chunk size and window size */
80*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_RECV_CHUNKS \
81*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
82*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_SEND_CHUNKS \
83*6236dae4SAndroid Build Coastguard Worker (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
84*6236dae4SAndroid Build Coastguard Worker
85*6236dae4SAndroid Build Coastguard Worker #ifndef ARRAYSIZE
86*6236dae4SAndroid Build Coastguard Worker #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
87*6236dae4SAndroid Build Coastguard Worker #endif
88*6236dae4SAndroid Build Coastguard Worker
89*6236dae4SAndroid Build Coastguard Worker #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
90*6236dae4SAndroid Build Coastguard Worker typedef uint32_t sslerr_t;
91*6236dae4SAndroid Build Coastguard Worker #else
92*6236dae4SAndroid Build Coastguard Worker typedef unsigned long sslerr_t;
93*6236dae4SAndroid Build Coastguard Worker #endif
94*6236dae4SAndroid Build Coastguard Worker
95*6236dae4SAndroid Build Coastguard Worker
96*6236dae4SAndroid Build Coastguard Worker /* How to access `call_data` from a cf_osslq filter */
97*6236dae4SAndroid Build Coastguard Worker #undef CF_CTX_CALL_DATA
98*6236dae4SAndroid Build Coastguard Worker #define CF_CTX_CALL_DATA(cf) \
99*6236dae4SAndroid Build Coastguard Worker ((struct cf_osslq_ctx *)(cf)->ctx)->call_data
100*6236dae4SAndroid Build Coastguard Worker
101*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
102*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data);
103*6236dae4SAndroid Build Coastguard Worker
osslq_SSL_ERROR_to_str(int err)104*6236dae4SAndroid Build Coastguard Worker static const char *osslq_SSL_ERROR_to_str(int err)
105*6236dae4SAndroid Build Coastguard Worker {
106*6236dae4SAndroid Build Coastguard Worker switch(err) {
107*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_NONE:
108*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_NONE";
109*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_SSL:
110*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_SSL";
111*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_READ:
112*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_READ";
113*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_WRITE:
114*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_WRITE";
115*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_X509_LOOKUP:
116*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_X509_LOOKUP";
117*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_SYSCALL:
118*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_SYSCALL";
119*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_ZERO_RETURN:
120*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_ZERO_RETURN";
121*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_CONNECT:
122*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_CONNECT";
123*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_ACCEPT:
124*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_ACCEPT";
125*6236dae4SAndroid Build Coastguard Worker #if defined(SSL_ERROR_WANT_ASYNC)
126*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_ASYNC:
127*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_ASYNC";
128*6236dae4SAndroid Build Coastguard Worker #endif
129*6236dae4SAndroid Build Coastguard Worker #if defined(SSL_ERROR_WANT_ASYNC_JOB)
130*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_ASYNC_JOB:
131*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_ASYNC_JOB";
132*6236dae4SAndroid Build Coastguard Worker #endif
133*6236dae4SAndroid Build Coastguard Worker #if defined(SSL_ERROR_WANT_EARLY)
134*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_EARLY:
135*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR_WANT_EARLY";
136*6236dae4SAndroid Build Coastguard Worker #endif
137*6236dae4SAndroid Build Coastguard Worker default:
138*6236dae4SAndroid Build Coastguard Worker return "SSL_ERROR unknown";
139*6236dae4SAndroid Build Coastguard Worker }
140*6236dae4SAndroid Build Coastguard Worker }
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker /* Return error string for last OpenSSL error */
osslq_strerror(unsigned long error,char * buf,size_t size)143*6236dae4SAndroid Build Coastguard Worker static char *osslq_strerror(unsigned long error, char *buf, size_t size)
144*6236dae4SAndroid Build Coastguard Worker {
145*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(size);
146*6236dae4SAndroid Build Coastguard Worker *buf = '\0';
147*6236dae4SAndroid Build Coastguard Worker
148*6236dae4SAndroid Build Coastguard Worker #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
149*6236dae4SAndroid Build Coastguard Worker ERR_error_string_n((uint32_t)error, buf, size);
150*6236dae4SAndroid Build Coastguard Worker #else
151*6236dae4SAndroid Build Coastguard Worker ERR_error_string_n(error, buf, size);
152*6236dae4SAndroid Build Coastguard Worker #endif
153*6236dae4SAndroid Build Coastguard Worker
154*6236dae4SAndroid Build Coastguard Worker if(!*buf) {
155*6236dae4SAndroid Build Coastguard Worker const char *msg = error ? "Unknown error" : "No error";
156*6236dae4SAndroid Build Coastguard Worker if(strlen(msg) < size)
157*6236dae4SAndroid Build Coastguard Worker strcpy(buf, msg);
158*6236dae4SAndroid Build Coastguard Worker }
159*6236dae4SAndroid Build Coastguard Worker
160*6236dae4SAndroid Build Coastguard Worker return buf;
161*6236dae4SAndroid Build Coastguard Worker }
162*6236dae4SAndroid Build Coastguard Worker
make_bio_addr(BIO_ADDR ** pbio_addr,const struct Curl_sockaddr_ex * addr)163*6236dae4SAndroid Build Coastguard Worker static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
164*6236dae4SAndroid Build Coastguard Worker const struct Curl_sockaddr_ex *addr)
165*6236dae4SAndroid Build Coastguard Worker {
166*6236dae4SAndroid Build Coastguard Worker BIO_ADDR *ba;
167*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_FAILED_INIT;
168*6236dae4SAndroid Build Coastguard Worker
169*6236dae4SAndroid Build Coastguard Worker ba = BIO_ADDR_new();
170*6236dae4SAndroid Build Coastguard Worker if(!ba) {
171*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
172*6236dae4SAndroid Build Coastguard Worker goto out;
173*6236dae4SAndroid Build Coastguard Worker }
174*6236dae4SAndroid Build Coastguard Worker
175*6236dae4SAndroid Build Coastguard Worker switch(addr->family) {
176*6236dae4SAndroid Build Coastguard Worker case AF_INET: {
177*6236dae4SAndroid Build Coastguard Worker struct sockaddr_in * const sin =
178*6236dae4SAndroid Build Coastguard Worker (struct sockaddr_in * const)(void *)&addr->curl_sa_addr;
179*6236dae4SAndroid Build Coastguard Worker if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
180*6236dae4SAndroid Build Coastguard Worker sizeof(sin->sin_addr), sin->sin_port)) {
181*6236dae4SAndroid Build Coastguard Worker goto out;
182*6236dae4SAndroid Build Coastguard Worker }
183*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
184*6236dae4SAndroid Build Coastguard Worker break;
185*6236dae4SAndroid Build Coastguard Worker }
186*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
187*6236dae4SAndroid Build Coastguard Worker case AF_INET6: {
188*6236dae4SAndroid Build Coastguard Worker struct sockaddr_in6 * const sin =
189*6236dae4SAndroid Build Coastguard Worker (struct sockaddr_in6 * const)(void *)&addr->curl_sa_addr;
190*6236dae4SAndroid Build Coastguard Worker if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
191*6236dae4SAndroid Build Coastguard Worker sizeof(sin->sin6_addr), sin->sin6_port)) {
192*6236dae4SAndroid Build Coastguard Worker }
193*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
194*6236dae4SAndroid Build Coastguard Worker break;
195*6236dae4SAndroid Build Coastguard Worker }
196*6236dae4SAndroid Build Coastguard Worker #endif /* USE_IPV6 */
197*6236dae4SAndroid Build Coastguard Worker default:
198*6236dae4SAndroid Build Coastguard Worker /* sunsupported */
199*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(0);
200*6236dae4SAndroid Build Coastguard Worker break;
201*6236dae4SAndroid Build Coastguard Worker }
202*6236dae4SAndroid Build Coastguard Worker
203*6236dae4SAndroid Build Coastguard Worker out:
204*6236dae4SAndroid Build Coastguard Worker if(result && ba) {
205*6236dae4SAndroid Build Coastguard Worker BIO_ADDR_free(ba);
206*6236dae4SAndroid Build Coastguard Worker ba = NULL;
207*6236dae4SAndroid Build Coastguard Worker }
208*6236dae4SAndroid Build Coastguard Worker *pbio_addr = ba;
209*6236dae4SAndroid Build Coastguard Worker return result;
210*6236dae4SAndroid Build Coastguard Worker }
211*6236dae4SAndroid Build Coastguard Worker
212*6236dae4SAndroid Build Coastguard Worker /* QUIC stream (not necessarily H3) */
213*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream {
214*6236dae4SAndroid Build Coastguard Worker curl_int64_t id;
215*6236dae4SAndroid Build Coastguard Worker SSL *ssl;
216*6236dae4SAndroid Build Coastguard Worker struct bufq recvbuf; /* QUIC war data recv buffer */
217*6236dae4SAndroid Build Coastguard Worker BIT(recvd_eos);
218*6236dae4SAndroid Build Coastguard Worker BIT(closed);
219*6236dae4SAndroid Build Coastguard Worker BIT(reset);
220*6236dae4SAndroid Build Coastguard Worker BIT(send_blocked);
221*6236dae4SAndroid Build Coastguard Worker };
222*6236dae4SAndroid Build Coastguard Worker
cf_osslq_stream_open(struct cf_osslq_stream * s,SSL * conn,uint64_t flags,struct bufc_pool * bufcp,void * user_data)223*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_stream_open(struct cf_osslq_stream *s,
224*6236dae4SAndroid Build Coastguard Worker SSL *conn,
225*6236dae4SAndroid Build Coastguard Worker uint64_t flags,
226*6236dae4SAndroid Build Coastguard Worker struct bufc_pool *bufcp,
227*6236dae4SAndroid Build Coastguard Worker void *user_data)
228*6236dae4SAndroid Build Coastguard Worker {
229*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!s->ssl);
230*6236dae4SAndroid Build Coastguard Worker Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE);
231*6236dae4SAndroid Build Coastguard Worker s->ssl = SSL_new_stream(conn, flags);
232*6236dae4SAndroid Build Coastguard Worker if(!s->ssl) {
233*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
234*6236dae4SAndroid Build Coastguard Worker }
235*6236dae4SAndroid Build Coastguard Worker s->id = (curl_int64_t)SSL_get_stream_id(s->ssl);
236*6236dae4SAndroid Build Coastguard Worker SSL_set_app_data(s->ssl, user_data);
237*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
238*6236dae4SAndroid Build Coastguard Worker }
239*6236dae4SAndroid Build Coastguard Worker
cf_osslq_stream_cleanup(struct cf_osslq_stream * s)240*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s)
241*6236dae4SAndroid Build Coastguard Worker {
242*6236dae4SAndroid Build Coastguard Worker if(s->ssl) {
243*6236dae4SAndroid Build Coastguard Worker SSL_set_app_data(s->ssl, NULL);
244*6236dae4SAndroid Build Coastguard Worker SSL_free(s->ssl);
245*6236dae4SAndroid Build Coastguard Worker }
246*6236dae4SAndroid Build Coastguard Worker Curl_bufq_free(&s->recvbuf);
247*6236dae4SAndroid Build Coastguard Worker memset(s, 0, sizeof(*s));
248*6236dae4SAndroid Build Coastguard Worker }
249*6236dae4SAndroid Build Coastguard Worker
cf_osslq_stream_close(struct cf_osslq_stream * s)250*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_stream_close(struct cf_osslq_stream *s)
251*6236dae4SAndroid Build Coastguard Worker {
252*6236dae4SAndroid Build Coastguard Worker if(s->ssl) {
253*6236dae4SAndroid Build Coastguard Worker SSL_free(s->ssl);
254*6236dae4SAndroid Build Coastguard Worker s->ssl = NULL;
255*6236dae4SAndroid Build Coastguard Worker }
256*6236dae4SAndroid Build Coastguard Worker }
257*6236dae4SAndroid Build Coastguard Worker
258*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_h3conn {
259*6236dae4SAndroid Build Coastguard Worker nghttp3_conn *conn;
260*6236dae4SAndroid Build Coastguard Worker nghttp3_settings settings;
261*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream s_ctrl;
262*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream s_qpack_enc;
263*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream s_qpack_dec;
264*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream remote_ctrl[3]; /* uni streams opened by the peer */
265*6236dae4SAndroid Build Coastguard Worker size_t remote_ctrl_n; /* number of peer streams opened */
266*6236dae4SAndroid Build Coastguard Worker };
267*6236dae4SAndroid Build Coastguard Worker
cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn * h3)268*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3)
269*6236dae4SAndroid Build Coastguard Worker {
270*6236dae4SAndroid Build Coastguard Worker size_t i;
271*6236dae4SAndroid Build Coastguard Worker
272*6236dae4SAndroid Build Coastguard Worker if(h3->conn)
273*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_del(h3->conn);
274*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_cleanup(&h3->s_ctrl);
275*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_cleanup(&h3->s_qpack_enc);
276*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_cleanup(&h3->s_qpack_dec);
277*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < h3->remote_ctrl_n; ++i) {
278*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_cleanup(&h3->remote_ctrl[i]);
279*6236dae4SAndroid Build Coastguard Worker }
280*6236dae4SAndroid Build Coastguard Worker }
281*6236dae4SAndroid Build Coastguard Worker
282*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx {
283*6236dae4SAndroid Build Coastguard Worker struct cf_quic_ctx q;
284*6236dae4SAndroid Build Coastguard Worker struct ssl_peer peer;
285*6236dae4SAndroid Build Coastguard Worker struct curl_tls_ctx tls;
286*6236dae4SAndroid Build Coastguard Worker struct cf_call_data call_data;
287*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_h3conn h3;
288*6236dae4SAndroid Build Coastguard Worker struct curltime started_at; /* time the current attempt started */
289*6236dae4SAndroid Build Coastguard Worker struct curltime handshake_at; /* time connect handshake finished */
290*6236dae4SAndroid Build Coastguard Worker struct curltime first_byte_at; /* when first byte was recvd */
291*6236dae4SAndroid Build Coastguard Worker struct bufc_pool stream_bufcp; /* chunk pool for streams */
292*6236dae4SAndroid Build Coastguard Worker struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
293*6236dae4SAndroid Build Coastguard Worker size_t max_stream_window; /* max flow window for one stream */
294*6236dae4SAndroid Build Coastguard Worker uint64_t max_idle_ms; /* max idle time for QUIC connection */
295*6236dae4SAndroid Build Coastguard Worker BIT(initialized);
296*6236dae4SAndroid Build Coastguard Worker BIT(got_first_byte); /* if first byte was received */
297*6236dae4SAndroid Build Coastguard Worker BIT(x509_store_setup); /* if x509 store has been set up */
298*6236dae4SAndroid Build Coastguard Worker BIT(protocol_shutdown); /* QUIC connection is shut down */
299*6236dae4SAndroid Build Coastguard Worker BIT(need_recv); /* QUIC connection needs to receive */
300*6236dae4SAndroid Build Coastguard Worker BIT(need_send); /* QUIC connection needs to send */
301*6236dae4SAndroid Build Coastguard Worker };
302*6236dae4SAndroid Build Coastguard Worker
303*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream);
304*6236dae4SAndroid Build Coastguard Worker
cf_osslq_ctx_init(struct cf_osslq_ctx * ctx)305*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
306*6236dae4SAndroid Build Coastguard Worker {
307*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!ctx->initialized);
308*6236dae4SAndroid Build Coastguard Worker Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
309*6236dae4SAndroid Build Coastguard Worker H3_STREAM_POOL_SPARES);
310*6236dae4SAndroid Build Coastguard Worker Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
311*6236dae4SAndroid Build Coastguard Worker ctx->initialized = TRUE;
312*6236dae4SAndroid Build Coastguard Worker }
313*6236dae4SAndroid Build Coastguard Worker
cf_osslq_ctx_free(struct cf_osslq_ctx * ctx)314*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
315*6236dae4SAndroid Build Coastguard Worker {
316*6236dae4SAndroid Build Coastguard Worker if(ctx && ctx->initialized) {
317*6236dae4SAndroid Build Coastguard Worker Curl_bufcp_free(&ctx->stream_bufcp);
318*6236dae4SAndroid Build Coastguard Worker Curl_hash_clean(&ctx->streams);
319*6236dae4SAndroid Build Coastguard Worker Curl_hash_destroy(&ctx->streams);
320*6236dae4SAndroid Build Coastguard Worker Curl_ssl_peer_cleanup(&ctx->peer);
321*6236dae4SAndroid Build Coastguard Worker }
322*6236dae4SAndroid Build Coastguard Worker free(ctx);
323*6236dae4SAndroid Build Coastguard Worker }
324*6236dae4SAndroid Build Coastguard Worker
cf_osslq_ctx_close(struct cf_osslq_ctx * ctx)325*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_ctx_close(struct cf_osslq_ctx *ctx)
326*6236dae4SAndroid Build Coastguard Worker {
327*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save = ctx->call_data;
328*6236dae4SAndroid Build Coastguard Worker
329*6236dae4SAndroid Build Coastguard Worker cf_osslq_h3conn_cleanup(&ctx->h3);
330*6236dae4SAndroid Build Coastguard Worker Curl_vquic_tls_cleanup(&ctx->tls);
331*6236dae4SAndroid Build Coastguard Worker vquic_ctx_free(&ctx->q);
332*6236dae4SAndroid Build Coastguard Worker ctx->call_data = save;
333*6236dae4SAndroid Build Coastguard Worker }
334*6236dae4SAndroid Build Coastguard Worker
cf_osslq_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)335*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_shutdown(struct Curl_cfilter *cf,
336*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, bool *done)
337*6236dae4SAndroid Build Coastguard Worker {
338*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
339*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
340*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
341*6236dae4SAndroid Build Coastguard Worker int rc;
342*6236dae4SAndroid Build Coastguard Worker
343*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
344*6236dae4SAndroid Build Coastguard Worker
345*6236dae4SAndroid Build Coastguard Worker if(cf->shutdown || ctx->protocol_shutdown) {
346*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
347*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker
350*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
351*6236dae4SAndroid Build Coastguard Worker *done = FALSE;
352*6236dae4SAndroid Build Coastguard Worker ctx->need_send = FALSE;
353*6236dae4SAndroid Build Coastguard Worker ctx->need_recv = FALSE;
354*6236dae4SAndroid Build Coastguard Worker
355*6236dae4SAndroid Build Coastguard Worker rc = SSL_shutdown_ex(ctx->tls.ossl.ssl,
356*6236dae4SAndroid Build Coastguard Worker SSL_SHUTDOWN_FLAG_NO_BLOCK, NULL, 0);
357*6236dae4SAndroid Build Coastguard Worker if(rc == 0) { /* ongoing */
358*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown ongoing");
359*6236dae4SAndroid Build Coastguard Worker ctx->need_recv = TRUE;
360*6236dae4SAndroid Build Coastguard Worker goto out;
361*6236dae4SAndroid Build Coastguard Worker }
362*6236dae4SAndroid Build Coastguard Worker else if(rc == 1) { /* done */
363*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown finished");
364*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
365*6236dae4SAndroid Build Coastguard Worker goto out;
366*6236dae4SAndroid Build Coastguard Worker }
367*6236dae4SAndroid Build Coastguard Worker else {
368*6236dae4SAndroid Build Coastguard Worker long sslerr;
369*6236dae4SAndroid Build Coastguard Worker char err_buffer[256];
370*6236dae4SAndroid Build Coastguard Worker int err = SSL_get_error(ctx->tls.ossl.ssl, rc);
371*6236dae4SAndroid Build Coastguard Worker
372*6236dae4SAndroid Build Coastguard Worker switch(err) {
373*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_NONE:
374*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_ZERO_RETURN:
375*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown not received, but closed");
376*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
377*6236dae4SAndroid Build Coastguard Worker goto out;
378*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_READ:
379*6236dae4SAndroid Build Coastguard Worker /* SSL has send its notify and now wants to read the reply
380*6236dae4SAndroid Build Coastguard Worker * from the server. We are not really interested in that. */
381*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown sent, want receive");
382*6236dae4SAndroid Build Coastguard Worker ctx->need_recv = TRUE;
383*6236dae4SAndroid Build Coastguard Worker goto out;
384*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_WRITE:
385*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown send blocked");
386*6236dae4SAndroid Build Coastguard Worker ctx->need_send = TRUE;
387*6236dae4SAndroid Build Coastguard Worker goto out;
388*6236dae4SAndroid Build Coastguard Worker default:
389*6236dae4SAndroid Build Coastguard Worker /* We give up on this. */
390*6236dae4SAndroid Build Coastguard Worker sslerr = ERR_get_error();
391*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "shutdown, ignore recv error: '%s', errno %d",
392*6236dae4SAndroid Build Coastguard Worker (sslerr ?
393*6236dae4SAndroid Build Coastguard Worker osslq_strerror(sslerr, err_buffer, sizeof(err_buffer)) :
394*6236dae4SAndroid Build Coastguard Worker osslq_SSL_ERROR_to_str(err)),
395*6236dae4SAndroid Build Coastguard Worker SOCKERRNO);
396*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
397*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
398*6236dae4SAndroid Build Coastguard Worker goto out;
399*6236dae4SAndroid Build Coastguard Worker }
400*6236dae4SAndroid Build Coastguard Worker }
401*6236dae4SAndroid Build Coastguard Worker out:
402*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
403*6236dae4SAndroid Build Coastguard Worker return result;
404*6236dae4SAndroid Build Coastguard Worker }
405*6236dae4SAndroid Build Coastguard Worker
cf_osslq_close(struct Curl_cfilter * cf,struct Curl_easy * data)406*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
407*6236dae4SAndroid Build Coastguard Worker {
408*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
409*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
410*6236dae4SAndroid Build Coastguard Worker
411*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
412*6236dae4SAndroid Build Coastguard Worker if(ctx && ctx->tls.ossl.ssl) {
413*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "cf_osslq_close()");
414*6236dae4SAndroid Build Coastguard Worker if(!cf->shutdown && !ctx->protocol_shutdown) {
415*6236dae4SAndroid Build Coastguard Worker /* last best effort, which OpenSSL calls a "rapid" shutdown. */
416*6236dae4SAndroid Build Coastguard Worker SSL_shutdown_ex(ctx->tls.ossl.ssl,
417*6236dae4SAndroid Build Coastguard Worker (SSL_SHUTDOWN_FLAG_NO_BLOCK | SSL_SHUTDOWN_FLAG_RAPID),
418*6236dae4SAndroid Build Coastguard Worker NULL, 0);
419*6236dae4SAndroid Build Coastguard Worker }
420*6236dae4SAndroid Build Coastguard Worker cf_osslq_ctx_close(ctx);
421*6236dae4SAndroid Build Coastguard Worker }
422*6236dae4SAndroid Build Coastguard Worker
423*6236dae4SAndroid Build Coastguard Worker cf->connected = FALSE;
424*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
425*6236dae4SAndroid Build Coastguard Worker }
426*6236dae4SAndroid Build Coastguard Worker
cf_osslq_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)427*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
428*6236dae4SAndroid Build Coastguard Worker {
429*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
430*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
431*6236dae4SAndroid Build Coastguard Worker
432*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
433*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "destroy");
434*6236dae4SAndroid Build Coastguard Worker if(ctx) {
435*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "cf_osslq_destroy()");
436*6236dae4SAndroid Build Coastguard Worker if(ctx->tls.ossl.ssl)
437*6236dae4SAndroid Build Coastguard Worker cf_osslq_ctx_close(ctx);
438*6236dae4SAndroid Build Coastguard Worker cf_osslq_ctx_free(ctx);
439*6236dae4SAndroid Build Coastguard Worker }
440*6236dae4SAndroid Build Coastguard Worker cf->ctx = NULL;
441*6236dae4SAndroid Build Coastguard Worker /* No CF_DATA_RESTORE(cf, save) possible */
442*6236dae4SAndroid Build Coastguard Worker (void)save;
443*6236dae4SAndroid Build Coastguard Worker }
444*6236dae4SAndroid Build Coastguard Worker
cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn * h3,SSL * stream_ssl,struct Curl_cfilter * cf,struct Curl_easy * data)445*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
446*6236dae4SAndroid Build Coastguard Worker SSL *stream_ssl,
447*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf,
448*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
449*6236dae4SAndroid Build Coastguard Worker {
450*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
451*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = (curl_int64_t)SSL_get_stream_id(stream_ssl);
452*6236dae4SAndroid Build Coastguard Worker
453*6236dae4SAndroid Build Coastguard Worker if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
454*6236dae4SAndroid Build Coastguard Worker /* rejected, we are full */
455*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] rejecting remote stream",
456*6236dae4SAndroid Build Coastguard Worker stream_id);
457*6236dae4SAndroid Build Coastguard Worker SSL_free(stream_ssl);
458*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
459*6236dae4SAndroid Build Coastguard Worker }
460*6236dae4SAndroid Build Coastguard Worker switch(SSL_get_stream_type(stream_ssl)) {
461*6236dae4SAndroid Build Coastguard Worker case SSL_STREAM_TYPE_READ: {
462*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++];
463*6236dae4SAndroid Build Coastguard Worker nstream->id = stream_id;
464*6236dae4SAndroid Build Coastguard Worker nstream->ssl = stream_ssl;
465*6236dae4SAndroid Build Coastguard Worker Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
466*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] accepted remote uni stream",
467*6236dae4SAndroid Build Coastguard Worker stream_id);
468*6236dae4SAndroid Build Coastguard Worker break;
469*6236dae4SAndroid Build Coastguard Worker }
470*6236dae4SAndroid Build Coastguard Worker default:
471*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote non-uni-read"
472*6236dae4SAndroid Build Coastguard Worker " stream", stream_id);
473*6236dae4SAndroid Build Coastguard Worker SSL_free(stream_ssl);
474*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
475*6236dae4SAndroid Build Coastguard Worker }
476*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
477*6236dae4SAndroid Build Coastguard Worker
478*6236dae4SAndroid Build Coastguard Worker }
479*6236dae4SAndroid Build Coastguard Worker
cf_osslq_ssl_err(struct Curl_cfilter * cf,struct Curl_easy * data,int detail,CURLcode def_result)480*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
481*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
482*6236dae4SAndroid Build Coastguard Worker int detail, CURLcode def_result)
483*6236dae4SAndroid Build Coastguard Worker {
484*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
485*6236dae4SAndroid Build Coastguard Worker CURLcode result = def_result;
486*6236dae4SAndroid Build Coastguard Worker sslerr_t errdetail;
487*6236dae4SAndroid Build Coastguard Worker char ebuf[256] = "unknown";
488*6236dae4SAndroid Build Coastguard Worker const char *err_descr = ebuf;
489*6236dae4SAndroid Build Coastguard Worker long lerr;
490*6236dae4SAndroid Build Coastguard Worker int lib;
491*6236dae4SAndroid Build Coastguard Worker int reason;
492*6236dae4SAndroid Build Coastguard Worker struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
493*6236dae4SAndroid Build Coastguard Worker
494*6236dae4SAndroid Build Coastguard Worker errdetail = ERR_get_error();
495*6236dae4SAndroid Build Coastguard Worker lib = ERR_GET_LIB(errdetail);
496*6236dae4SAndroid Build Coastguard Worker reason = ERR_GET_REASON(errdetail);
497*6236dae4SAndroid Build Coastguard Worker
498*6236dae4SAndroid Build Coastguard Worker if((lib == ERR_LIB_SSL) &&
499*6236dae4SAndroid Build Coastguard Worker ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) ||
500*6236dae4SAndroid Build Coastguard Worker (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
501*6236dae4SAndroid Build Coastguard Worker result = CURLE_PEER_FAILED_VERIFICATION;
502*6236dae4SAndroid Build Coastguard Worker
503*6236dae4SAndroid Build Coastguard Worker lerr = SSL_get_verify_result(ctx->tls.ossl.ssl);
504*6236dae4SAndroid Build Coastguard Worker if(lerr != X509_V_OK) {
505*6236dae4SAndroid Build Coastguard Worker ssl_config->certverifyresult = lerr;
506*6236dae4SAndroid Build Coastguard Worker msnprintf(ebuf, sizeof(ebuf),
507*6236dae4SAndroid Build Coastguard Worker "SSL certificate problem: %s",
508*6236dae4SAndroid Build Coastguard Worker X509_verify_cert_error_string(lerr));
509*6236dae4SAndroid Build Coastguard Worker }
510*6236dae4SAndroid Build Coastguard Worker else
511*6236dae4SAndroid Build Coastguard Worker err_descr = "SSL certificate verification failed";
512*6236dae4SAndroid Build Coastguard Worker }
513*6236dae4SAndroid Build Coastguard Worker #if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
514*6236dae4SAndroid Build Coastguard Worker /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
515*6236dae4SAndroid Build Coastguard Worker OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
516*6236dae4SAndroid Build Coastguard Worker else if((lib == ERR_LIB_SSL) &&
517*6236dae4SAndroid Build Coastguard Worker (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
518*6236dae4SAndroid Build Coastguard Worker /* If client certificate is required, communicate the
519*6236dae4SAndroid Build Coastguard Worker error to client */
520*6236dae4SAndroid Build Coastguard Worker result = CURLE_SSL_CLIENTCERT;
521*6236dae4SAndroid Build Coastguard Worker osslq_strerror(errdetail, ebuf, sizeof(ebuf));
522*6236dae4SAndroid Build Coastguard Worker }
523*6236dae4SAndroid Build Coastguard Worker #endif
524*6236dae4SAndroid Build Coastguard Worker else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) {
525*6236dae4SAndroid Build Coastguard Worker ctx->protocol_shutdown = TRUE;
526*6236dae4SAndroid Build Coastguard Worker err_descr = "QUIC connection has been shut down";
527*6236dae4SAndroid Build Coastguard Worker result = def_result;
528*6236dae4SAndroid Build Coastguard Worker }
529*6236dae4SAndroid Build Coastguard Worker else {
530*6236dae4SAndroid Build Coastguard Worker result = def_result;
531*6236dae4SAndroid Build Coastguard Worker osslq_strerror(errdetail, ebuf, sizeof(ebuf));
532*6236dae4SAndroid Build Coastguard Worker }
533*6236dae4SAndroid Build Coastguard Worker
534*6236dae4SAndroid Build Coastguard Worker /* detail is already set to the SSL error above */
535*6236dae4SAndroid Build Coastguard Worker
536*6236dae4SAndroid Build Coastguard Worker /* If we e.g. use SSLv2 request-method and the server does not like us
537*6236dae4SAndroid Build Coastguard Worker * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
538*6236dae4SAndroid Build Coastguard Worker * the SO_ERROR is also lost.
539*6236dae4SAndroid Build Coastguard Worker */
540*6236dae4SAndroid Build Coastguard Worker if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
541*6236dae4SAndroid Build Coastguard Worker char extramsg[80]="";
542*6236dae4SAndroid Build Coastguard Worker int sockerr = SOCKERRNO;
543*6236dae4SAndroid Build Coastguard Worker struct ip_quadruple ip;
544*6236dae4SAndroid Build Coastguard Worker
545*6236dae4SAndroid Build Coastguard Worker Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
546*6236dae4SAndroid Build Coastguard Worker if(sockerr && detail == SSL_ERROR_SYSCALL)
547*6236dae4SAndroid Build Coastguard Worker Curl_strerror(sockerr, extramsg, sizeof(extramsg));
548*6236dae4SAndroid Build Coastguard Worker failf(data, "QUIC connect: %s in connection to %s:%d (%s)",
549*6236dae4SAndroid Build Coastguard Worker extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail),
550*6236dae4SAndroid Build Coastguard Worker ctx->peer.dispname, ip.remote_port, ip.remote_ip);
551*6236dae4SAndroid Build Coastguard Worker }
552*6236dae4SAndroid Build Coastguard Worker else {
553*6236dae4SAndroid Build Coastguard Worker /* Could be a CERT problem */
554*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_descr);
555*6236dae4SAndroid Build Coastguard Worker }
556*6236dae4SAndroid Build Coastguard Worker return result;
557*6236dae4SAndroid Build Coastguard Worker }
558*6236dae4SAndroid Build Coastguard Worker
cf_osslq_verify_peer(struct Curl_cfilter * cf,struct Curl_easy * data)559*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
560*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
561*6236dae4SAndroid Build Coastguard Worker {
562*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
563*6236dae4SAndroid Build Coastguard Worker
564*6236dae4SAndroid Build Coastguard Worker cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
565*6236dae4SAndroid Build Coastguard Worker cf->conn->httpversion = 30;
566*6236dae4SAndroid Build Coastguard Worker
567*6236dae4SAndroid Build Coastguard Worker return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
568*6236dae4SAndroid Build Coastguard Worker }
569*6236dae4SAndroid Build Coastguard Worker
570*6236dae4SAndroid Build Coastguard Worker /**
571*6236dae4SAndroid Build Coastguard Worker * All about the H3 internals of a stream
572*6236dae4SAndroid Build Coastguard Worker */
573*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx {
574*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream s;
575*6236dae4SAndroid Build Coastguard Worker struct bufq sendbuf; /* h3 request body */
576*6236dae4SAndroid Build Coastguard Worker struct bufq recvbuf; /* h3 response body */
577*6236dae4SAndroid Build Coastguard Worker struct h1_req_parser h1; /* h1 request parsing */
578*6236dae4SAndroid Build Coastguard Worker size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
579*6236dae4SAndroid Build Coastguard Worker size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
580*6236dae4SAndroid Build Coastguard Worker curl_uint64_t error3; /* HTTP/3 stream error code */
581*6236dae4SAndroid Build Coastguard Worker curl_off_t upload_left; /* number of request bytes left to upload */
582*6236dae4SAndroid Build Coastguard Worker curl_off_t download_recvd; /* number of response DATA bytes received */
583*6236dae4SAndroid Build Coastguard Worker int status_code; /* HTTP status code */
584*6236dae4SAndroid Build Coastguard Worker bool resp_hds_complete; /* we have a complete, final response */
585*6236dae4SAndroid Build Coastguard Worker bool closed; /* TRUE on stream close */
586*6236dae4SAndroid Build Coastguard Worker bool reset; /* TRUE on stream reset */
587*6236dae4SAndroid Build Coastguard Worker bool send_closed; /* stream is local closed */
588*6236dae4SAndroid Build Coastguard Worker BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
589*6236dae4SAndroid Build Coastguard Worker };
590*6236dae4SAndroid Build Coastguard Worker
591*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
592*6236dae4SAndroid Build Coastguard Worker data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
593*6236dae4SAndroid Build Coastguard Worker
h3_stream_ctx_free(struct h3_stream_ctx * stream)594*6236dae4SAndroid Build Coastguard Worker static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
595*6236dae4SAndroid Build Coastguard Worker {
596*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_cleanup(&stream->s);
597*6236dae4SAndroid Build Coastguard Worker Curl_bufq_free(&stream->sendbuf);
598*6236dae4SAndroid Build Coastguard Worker Curl_bufq_free(&stream->recvbuf);
599*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_free(&stream->h1);
600*6236dae4SAndroid Build Coastguard Worker free(stream);
601*6236dae4SAndroid Build Coastguard Worker }
602*6236dae4SAndroid Build Coastguard Worker
h3_stream_hash_free(void * stream)603*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream)
604*6236dae4SAndroid Build Coastguard Worker {
605*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
606*6236dae4SAndroid Build Coastguard Worker h3_stream_ctx_free((struct h3_stream_ctx *)stream);
607*6236dae4SAndroid Build Coastguard Worker }
608*6236dae4SAndroid Build Coastguard Worker
h3_data_setup(struct Curl_cfilter * cf,struct Curl_easy * data)609*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_setup(struct Curl_cfilter *cf,
610*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
611*6236dae4SAndroid Build Coastguard Worker {
612*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
613*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
614*6236dae4SAndroid Build Coastguard Worker
615*6236dae4SAndroid Build Coastguard Worker if(!data)
616*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
617*6236dae4SAndroid Build Coastguard Worker
618*6236dae4SAndroid Build Coastguard Worker if(stream)
619*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
620*6236dae4SAndroid Build Coastguard Worker
621*6236dae4SAndroid Build Coastguard Worker stream = calloc(1, sizeof(*stream));
622*6236dae4SAndroid Build Coastguard Worker if(!stream)
623*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
624*6236dae4SAndroid Build Coastguard Worker
625*6236dae4SAndroid Build Coastguard Worker stream->s.id = -1;
626*6236dae4SAndroid Build Coastguard Worker /* on send, we control how much we put into the buffer */
627*6236dae4SAndroid Build Coastguard Worker Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
628*6236dae4SAndroid Build Coastguard Worker H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
629*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight = 0;
630*6236dae4SAndroid Build Coastguard Worker /* on recv, we need a flexible buffer limit since we also write
631*6236dae4SAndroid Build Coastguard Worker * headers to it that are not counted against the nghttp3 flow limits. */
632*6236dae4SAndroid Build Coastguard Worker Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
633*6236dae4SAndroid Build Coastguard Worker H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
634*6236dae4SAndroid Build Coastguard Worker stream->recv_buf_nonflow = 0;
635*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
636*6236dae4SAndroid Build Coastguard Worker
637*6236dae4SAndroid Build Coastguard Worker if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
638*6236dae4SAndroid Build Coastguard Worker h3_stream_ctx_free(stream);
639*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
640*6236dae4SAndroid Build Coastguard Worker }
641*6236dae4SAndroid Build Coastguard Worker
642*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
643*6236dae4SAndroid Build Coastguard Worker }
644*6236dae4SAndroid Build Coastguard Worker
h3_data_done(struct Curl_cfilter * cf,struct Curl_easy * data)645*6236dae4SAndroid Build Coastguard Worker static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
646*6236dae4SAndroid Build Coastguard Worker {
647*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
648*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
649*6236dae4SAndroid Build Coastguard Worker
650*6236dae4SAndroid Build Coastguard Worker (void)cf;
651*6236dae4SAndroid Build Coastguard Worker if(stream) {
652*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] easy handle is done",
653*6236dae4SAndroid Build Coastguard Worker stream->s.id);
654*6236dae4SAndroid Build Coastguard Worker if(ctx->h3.conn && !stream->closed) {
655*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
656*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id,
657*6236dae4SAndroid Build Coastguard Worker NGHTTP3_H3_REQUEST_CANCELLED);
658*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_set_stream_user_data(ctx->h3.conn, stream->s.id, NULL);
659*6236dae4SAndroid Build Coastguard Worker stream->closed = TRUE;
660*6236dae4SAndroid Build Coastguard Worker }
661*6236dae4SAndroid Build Coastguard Worker
662*6236dae4SAndroid Build Coastguard Worker Curl_hash_offt_remove(&ctx->streams, data->mid);
663*6236dae4SAndroid Build Coastguard Worker }
664*6236dae4SAndroid Build Coastguard Worker }
665*6236dae4SAndroid Build Coastguard Worker
cf_osslq_get_qstream(struct Curl_cfilter * cf,struct Curl_easy * data,int64_t stream_id)666*6236dae4SAndroid Build Coastguard Worker static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
667*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
668*6236dae4SAndroid Build Coastguard Worker int64_t stream_id)
669*6236dae4SAndroid Build Coastguard Worker {
670*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
671*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
672*6236dae4SAndroid Build Coastguard Worker
673*6236dae4SAndroid Build Coastguard Worker if(stream && stream->s.id == stream_id) {
674*6236dae4SAndroid Build Coastguard Worker return &stream->s;
675*6236dae4SAndroid Build Coastguard Worker }
676*6236dae4SAndroid Build Coastguard Worker else if(ctx->h3.s_ctrl.id == stream_id) {
677*6236dae4SAndroid Build Coastguard Worker return &ctx->h3.s_ctrl;
678*6236dae4SAndroid Build Coastguard Worker }
679*6236dae4SAndroid Build Coastguard Worker else if(ctx->h3.s_qpack_enc.id == stream_id) {
680*6236dae4SAndroid Build Coastguard Worker return &ctx->h3.s_qpack_enc;
681*6236dae4SAndroid Build Coastguard Worker }
682*6236dae4SAndroid Build Coastguard Worker else if(ctx->h3.s_qpack_dec.id == stream_id) {
683*6236dae4SAndroid Build Coastguard Worker return &ctx->h3.s_qpack_dec;
684*6236dae4SAndroid Build Coastguard Worker }
685*6236dae4SAndroid Build Coastguard Worker else {
686*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
687*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data->multi);
688*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
689*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *sdata = Curl_node_elem(e);
690*6236dae4SAndroid Build Coastguard Worker if(sdata->conn != data->conn)
691*6236dae4SAndroid Build Coastguard Worker continue;
692*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, sdata);
693*6236dae4SAndroid Build Coastguard Worker if(stream && stream->s.id == stream_id) {
694*6236dae4SAndroid Build Coastguard Worker return &stream->s;
695*6236dae4SAndroid Build Coastguard Worker }
696*6236dae4SAndroid Build Coastguard Worker }
697*6236dae4SAndroid Build Coastguard Worker }
698*6236dae4SAndroid Build Coastguard Worker return NULL;
699*6236dae4SAndroid Build Coastguard Worker }
700*6236dae4SAndroid Build Coastguard Worker
h3_drain_stream(struct Curl_cfilter * cf,struct Curl_easy * data)701*6236dae4SAndroid Build Coastguard Worker static void h3_drain_stream(struct Curl_cfilter *cf,
702*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
703*6236dae4SAndroid Build Coastguard Worker {
704*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
705*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
706*6236dae4SAndroid Build Coastguard Worker unsigned char bits;
707*6236dae4SAndroid Build Coastguard Worker
708*6236dae4SAndroid Build Coastguard Worker (void)cf;
709*6236dae4SAndroid Build Coastguard Worker bits = CURL_CSELECT_IN;
710*6236dae4SAndroid Build Coastguard Worker if(stream && stream->upload_left && !stream->send_closed)
711*6236dae4SAndroid Build Coastguard Worker bits |= CURL_CSELECT_OUT;
712*6236dae4SAndroid Build Coastguard Worker if(data->state.select_bits != bits) {
713*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = bits;
714*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 0, EXPIRE_RUN_NOW);
715*6236dae4SAndroid Build Coastguard Worker }
716*6236dae4SAndroid Build Coastguard Worker }
717*6236dae4SAndroid Build Coastguard Worker
h3_data_pause(struct Curl_cfilter * cf,struct Curl_easy * data,bool pause)718*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_pause(struct Curl_cfilter *cf,
719*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
720*6236dae4SAndroid Build Coastguard Worker bool pause)
721*6236dae4SAndroid Build Coastguard Worker {
722*6236dae4SAndroid Build Coastguard Worker if(!pause) {
723*6236dae4SAndroid Build Coastguard Worker /* unpaused. make it run again right away */
724*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
725*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 0, EXPIRE_RUN_NOW);
726*6236dae4SAndroid Build Coastguard Worker }
727*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
728*6236dae4SAndroid Build Coastguard Worker }
729*6236dae4SAndroid Build Coastguard Worker
cb_h3_stream_close(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)730*6236dae4SAndroid Build Coastguard Worker static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
731*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
732*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
733*6236dae4SAndroid Build Coastguard Worker {
734*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
735*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
736*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
737*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
738*6236dae4SAndroid Build Coastguard Worker (void)conn;
739*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
740*6236dae4SAndroid Build Coastguard Worker
741*6236dae4SAndroid Build Coastguard Worker /* we might be called by nghttp3 after we already cleaned up */
742*6236dae4SAndroid Build Coastguard Worker if(!stream)
743*6236dae4SAndroid Build Coastguard Worker return 0;
744*6236dae4SAndroid Build Coastguard Worker
745*6236dae4SAndroid Build Coastguard Worker stream->closed = TRUE;
746*6236dae4SAndroid Build Coastguard Worker stream->error3 = app_error_code;
747*6236dae4SAndroid Build Coastguard Worker if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
748*6236dae4SAndroid Build Coastguard Worker stream->reset = TRUE;
749*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
750*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
751*6236dae4SAndroid Build Coastguard Worker stream->s.id, stream->error3);
752*6236dae4SAndroid Build Coastguard Worker }
753*6236dae4SAndroid Build Coastguard Worker else {
754*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->s.id);
755*6236dae4SAndroid Build Coastguard Worker }
756*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
757*6236dae4SAndroid Build Coastguard Worker return 0;
758*6236dae4SAndroid Build Coastguard Worker }
759*6236dae4SAndroid Build Coastguard Worker
760*6236dae4SAndroid Build Coastguard Worker /*
761*6236dae4SAndroid Build Coastguard Worker * write_resp_raw() copies response data in raw format to the `data`'s
762*6236dae4SAndroid Build Coastguard Worker * receive buffer. If not enough space is available, it appends to the
763*6236dae4SAndroid Build Coastguard Worker * `data`'s overflow buffer.
764*6236dae4SAndroid Build Coastguard Worker */
write_resp_raw(struct Curl_cfilter * cf,struct Curl_easy * data,const void * mem,size_t memlen,bool flow)765*6236dae4SAndroid Build Coastguard Worker static CURLcode write_resp_raw(struct Curl_cfilter *cf,
766*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
767*6236dae4SAndroid Build Coastguard Worker const void *mem, size_t memlen,
768*6236dae4SAndroid Build Coastguard Worker bool flow)
769*6236dae4SAndroid Build Coastguard Worker {
770*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
771*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
772*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
773*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten;
774*6236dae4SAndroid Build Coastguard Worker
775*6236dae4SAndroid Build Coastguard Worker (void)cf;
776*6236dae4SAndroid Build Coastguard Worker if(!stream) {
777*6236dae4SAndroid Build Coastguard Worker return CURLE_RECV_ERROR;
778*6236dae4SAndroid Build Coastguard Worker }
779*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
780*6236dae4SAndroid Build Coastguard Worker if(nwritten < 0) {
781*6236dae4SAndroid Build Coastguard Worker return result;
782*6236dae4SAndroid Build Coastguard Worker }
783*6236dae4SAndroid Build Coastguard Worker
784*6236dae4SAndroid Build Coastguard Worker if(!flow)
785*6236dae4SAndroid Build Coastguard Worker stream->recv_buf_nonflow += (size_t)nwritten;
786*6236dae4SAndroid Build Coastguard Worker
787*6236dae4SAndroid Build Coastguard Worker if((size_t)nwritten < memlen) {
788*6236dae4SAndroid Build Coastguard Worker /* This MUST not happen. Our recbuf is dimensioned to hold the
789*6236dae4SAndroid Build Coastguard Worker * full max_stream_window and then some for this very reason. */
790*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(0);
791*6236dae4SAndroid Build Coastguard Worker return CURLE_RECV_ERROR;
792*6236dae4SAndroid Build Coastguard Worker }
793*6236dae4SAndroid Build Coastguard Worker return result;
794*6236dae4SAndroid Build Coastguard Worker }
795*6236dae4SAndroid Build Coastguard Worker
cb_h3_recv_data(nghttp3_conn * conn,int64_t stream3_id,const uint8_t * buf,size_t buflen,void * user_data,void * stream_user_data)796*6236dae4SAndroid Build Coastguard Worker static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
797*6236dae4SAndroid Build Coastguard Worker const uint8_t *buf, size_t buflen,
798*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
799*6236dae4SAndroid Build Coastguard Worker {
800*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
801*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
802*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
803*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
804*6236dae4SAndroid Build Coastguard Worker CURLcode result;
805*6236dae4SAndroid Build Coastguard Worker
806*6236dae4SAndroid Build Coastguard Worker (void)conn;
807*6236dae4SAndroid Build Coastguard Worker (void)stream3_id;
808*6236dae4SAndroid Build Coastguard Worker
809*6236dae4SAndroid Build Coastguard Worker if(!stream)
810*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
811*6236dae4SAndroid Build Coastguard Worker
812*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, buf, buflen, TRUE);
813*6236dae4SAndroid Build Coastguard Worker if(result) {
814*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, ERROR %d",
815*6236dae4SAndroid Build Coastguard Worker stream->s.id, buflen, result);
816*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
817*6236dae4SAndroid Build Coastguard Worker }
818*6236dae4SAndroid Build Coastguard Worker stream->download_recvd += (curl_off_t)buflen;
819*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%zd",
820*6236dae4SAndroid Build Coastguard Worker stream->s.id, buflen, stream->download_recvd);
821*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
822*6236dae4SAndroid Build Coastguard Worker return 0;
823*6236dae4SAndroid Build Coastguard Worker }
824*6236dae4SAndroid Build Coastguard Worker
cb_h3_deferred_consume(nghttp3_conn * conn,int64_t stream_id,size_t consumed,void * user_data,void * stream_user_data)825*6236dae4SAndroid Build Coastguard Worker static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
826*6236dae4SAndroid Build Coastguard Worker size_t consumed, void *user_data,
827*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
828*6236dae4SAndroid Build Coastguard Worker {
829*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
830*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
831*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
832*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
833*6236dae4SAndroid Build Coastguard Worker
834*6236dae4SAndroid Build Coastguard Worker (void)conn;
835*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
836*6236dae4SAndroid Build Coastguard Worker if(stream)
837*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] deferred consume %zu bytes",
838*6236dae4SAndroid Build Coastguard Worker stream->s.id, consumed);
839*6236dae4SAndroid Build Coastguard Worker return 0;
840*6236dae4SAndroid Build Coastguard Worker }
841*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)842*6236dae4SAndroid Build Coastguard Worker static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
843*6236dae4SAndroid Build Coastguard Worker int32_t token, nghttp3_rcbuf *name,
844*6236dae4SAndroid Build Coastguard Worker nghttp3_rcbuf *value, uint8_t flags,
845*6236dae4SAndroid Build Coastguard Worker void *user_data, void *stream_user_data)
846*6236dae4SAndroid Build Coastguard Worker {
847*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
848*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = sid;
849*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
850*6236dae4SAndroid Build Coastguard Worker nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
851*6236dae4SAndroid Build Coastguard Worker nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
852*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
853*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
854*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
855*6236dae4SAndroid Build Coastguard Worker (void)conn;
856*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
857*6236dae4SAndroid Build Coastguard Worker (void)token;
858*6236dae4SAndroid Build Coastguard Worker (void)flags;
859*6236dae4SAndroid Build Coastguard Worker (void)cf;
860*6236dae4SAndroid Build Coastguard Worker
861*6236dae4SAndroid Build Coastguard Worker /* we might have cleaned up this transfer already */
862*6236dae4SAndroid Build Coastguard Worker if(!stream)
863*6236dae4SAndroid Build Coastguard Worker return 0;
864*6236dae4SAndroid Build Coastguard Worker
865*6236dae4SAndroid Build Coastguard Worker if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
866*6236dae4SAndroid Build Coastguard Worker char line[14]; /* status line is always 13 characters long */
867*6236dae4SAndroid Build Coastguard Worker size_t ncopy;
868*6236dae4SAndroid Build Coastguard Worker
869*6236dae4SAndroid Build Coastguard Worker result = Curl_http_decode_status(&stream->status_code,
870*6236dae4SAndroid Build Coastguard Worker (const char *)h3val.base, h3val.len);
871*6236dae4SAndroid Build Coastguard Worker if(result)
872*6236dae4SAndroid Build Coastguard Worker return -1;
873*6236dae4SAndroid Build Coastguard Worker ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
874*6236dae4SAndroid Build Coastguard Worker stream->status_code);
875*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", stream_id, line);
876*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, line, ncopy, FALSE);
877*6236dae4SAndroid Build Coastguard Worker if(result) {
878*6236dae4SAndroid Build Coastguard Worker return -1;
879*6236dae4SAndroid Build Coastguard Worker }
880*6236dae4SAndroid Build Coastguard Worker }
881*6236dae4SAndroid Build Coastguard Worker else {
882*6236dae4SAndroid Build Coastguard Worker /* store as an HTTP1-style header */
883*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
884*6236dae4SAndroid Build Coastguard Worker stream_id, (int)h3name.len, h3name.base,
885*6236dae4SAndroid Build Coastguard Worker (int)h3val.len, h3val.base);
886*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
887*6236dae4SAndroid Build Coastguard Worker if(result) {
888*6236dae4SAndroid Build Coastguard Worker return -1;
889*6236dae4SAndroid Build Coastguard Worker }
890*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, ": ", 2, FALSE);
891*6236dae4SAndroid Build Coastguard Worker if(result) {
892*6236dae4SAndroid Build Coastguard Worker return -1;
893*6236dae4SAndroid Build Coastguard Worker }
894*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE);
895*6236dae4SAndroid Build Coastguard Worker if(result) {
896*6236dae4SAndroid Build Coastguard Worker return -1;
897*6236dae4SAndroid Build Coastguard Worker }
898*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
899*6236dae4SAndroid Build Coastguard Worker if(result) {
900*6236dae4SAndroid Build Coastguard Worker return -1;
901*6236dae4SAndroid Build Coastguard Worker }
902*6236dae4SAndroid Build Coastguard Worker }
903*6236dae4SAndroid Build Coastguard Worker return 0;
904*6236dae4SAndroid Build Coastguard Worker }
905*6236dae4SAndroid Build Coastguard Worker
cb_h3_end_headers(nghttp3_conn * conn,int64_t sid,int fin,void * user_data,void * stream_user_data)906*6236dae4SAndroid Build Coastguard Worker static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
907*6236dae4SAndroid Build Coastguard Worker int fin, void *user_data, void *stream_user_data)
908*6236dae4SAndroid Build Coastguard Worker {
909*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
910*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
911*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
912*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = sid;
913*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
914*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
915*6236dae4SAndroid Build Coastguard Worker (void)conn;
916*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
917*6236dae4SAndroid Build Coastguard Worker (void)fin;
918*6236dae4SAndroid Build Coastguard Worker (void)cf;
919*6236dae4SAndroid Build Coastguard Worker
920*6236dae4SAndroid Build Coastguard Worker if(!stream)
921*6236dae4SAndroid Build Coastguard Worker return 0;
922*6236dae4SAndroid Build Coastguard Worker /* add a CRLF only if we have received some headers */
923*6236dae4SAndroid Build Coastguard Worker result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
924*6236dae4SAndroid Build Coastguard Worker if(result) {
925*6236dae4SAndroid Build Coastguard Worker return -1;
926*6236dae4SAndroid Build Coastguard Worker }
927*6236dae4SAndroid Build Coastguard Worker
928*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
929*6236dae4SAndroid Build Coastguard Worker stream_id, stream->status_code);
930*6236dae4SAndroid Build Coastguard Worker if(stream->status_code / 100 != 1) {
931*6236dae4SAndroid Build Coastguard Worker stream->resp_hds_complete = TRUE;
932*6236dae4SAndroid Build Coastguard Worker }
933*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
934*6236dae4SAndroid Build Coastguard Worker return 0;
935*6236dae4SAndroid Build Coastguard Worker }
936*6236dae4SAndroid Build Coastguard Worker
cb_h3_stop_sending(nghttp3_conn * conn,int64_t sid,uint64_t app_error_code,void * user_data,void * stream_user_data)937*6236dae4SAndroid Build Coastguard Worker static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t sid,
938*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
939*6236dae4SAndroid Build Coastguard Worker 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_osslq_ctx *ctx = cf->ctx;
943*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
944*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = sid;
945*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
946*6236dae4SAndroid Build Coastguard Worker (void)conn;
947*6236dae4SAndroid Build Coastguard Worker (void)app_error_code;
948*6236dae4SAndroid Build Coastguard Worker
949*6236dae4SAndroid Build Coastguard Worker if(!stream || !stream->s.ssl)
950*6236dae4SAndroid Build Coastguard Worker return 0;
951*6236dae4SAndroid Build Coastguard Worker
952*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] stop_sending", stream_id);
953*6236dae4SAndroid Build Coastguard Worker cf_osslq_stream_close(&stream->s);
954*6236dae4SAndroid Build Coastguard Worker return 0;
955*6236dae4SAndroid Build Coastguard Worker }
956*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)957*6236dae4SAndroid Build Coastguard Worker static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
958*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code, void *user_data,
959*6236dae4SAndroid Build Coastguard Worker void *stream_user_data) {
960*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
961*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
962*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
963*6236dae4SAndroid Build Coastguard Worker curl_int64_t stream_id = sid;
964*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
965*6236dae4SAndroid Build Coastguard Worker int rv;
966*6236dae4SAndroid Build Coastguard Worker (void)conn;
967*6236dae4SAndroid Build Coastguard Worker
968*6236dae4SAndroid Build Coastguard Worker if(stream && stream->s.ssl) {
969*6236dae4SAndroid Build Coastguard Worker SSL_STREAM_RESET_ARGS args = {0};
970*6236dae4SAndroid Build Coastguard Worker args.quic_error_code = app_error_code;
971*6236dae4SAndroid Build Coastguard Worker rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args));
972*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
973*6236dae4SAndroid Build Coastguard Worker if(!rv) {
974*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
975*6236dae4SAndroid Build Coastguard Worker }
976*6236dae4SAndroid Build Coastguard Worker }
977*6236dae4SAndroid Build Coastguard Worker return 0;
978*6236dae4SAndroid Build Coastguard Worker }
979*6236dae4SAndroid Build Coastguard Worker
980*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)981*6236dae4SAndroid Build Coastguard Worker cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
982*6236dae4SAndroid Build Coastguard Worker nghttp3_vec *vec, size_t veccnt,
983*6236dae4SAndroid Build Coastguard Worker uint32_t *pflags, void *user_data,
984*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
985*6236dae4SAndroid Build Coastguard Worker {
986*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
987*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
988*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
989*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
990*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = 0;
991*6236dae4SAndroid Build Coastguard Worker size_t nvecs = 0;
992*6236dae4SAndroid Build Coastguard Worker (void)cf;
993*6236dae4SAndroid Build Coastguard Worker (void)conn;
994*6236dae4SAndroid Build Coastguard Worker (void)stream_id;
995*6236dae4SAndroid Build Coastguard Worker (void)user_data;
996*6236dae4SAndroid Build Coastguard Worker (void)veccnt;
997*6236dae4SAndroid Build Coastguard Worker
998*6236dae4SAndroid Build Coastguard Worker if(!stream)
999*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1000*6236dae4SAndroid Build Coastguard Worker /* nghttp3 keeps references to the sendbuf data until it is ACKed
1001*6236dae4SAndroid Build Coastguard Worker * by the server (see `cb_h3_acked_req_body()` for updates).
1002*6236dae4SAndroid Build Coastguard Worker * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
1003*6236dae4SAndroid Build Coastguard Worker * that we have already passed to nghttp3, but which have not been
1004*6236dae4SAndroid Build Coastguard Worker * ACKed yet.
1005*6236dae4SAndroid Build Coastguard Worker * Any amount beyond `sendbuf_len_in_flight` we need still to pass
1006*6236dae4SAndroid Build Coastguard Worker * to nghttp3. Do that now, if we can. */
1007*6236dae4SAndroid Build Coastguard Worker if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1008*6236dae4SAndroid Build Coastguard Worker nvecs = 0;
1009*6236dae4SAndroid Build Coastguard Worker while(nvecs < veccnt &&
1010*6236dae4SAndroid Build Coastguard Worker Curl_bufq_peek_at(&stream->sendbuf,
1011*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight,
1012*6236dae4SAndroid Build Coastguard Worker (const unsigned char **)&vec[nvecs].base,
1013*6236dae4SAndroid Build Coastguard Worker &vec[nvecs].len)) {
1014*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight += vec[nvecs].len;
1015*6236dae4SAndroid Build Coastguard Worker nwritten += vec[nvecs].len;
1016*6236dae4SAndroid Build Coastguard Worker ++nvecs;
1017*6236dae4SAndroid Build Coastguard Worker }
1018*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
1019*6236dae4SAndroid Build Coastguard Worker }
1020*6236dae4SAndroid Build Coastguard Worker
1021*6236dae4SAndroid Build Coastguard Worker if(nwritten > 0 && stream->upload_left != -1)
1022*6236dae4SAndroid Build Coastguard Worker stream->upload_left -= nwritten;
1023*6236dae4SAndroid Build Coastguard Worker
1024*6236dae4SAndroid Build Coastguard Worker /* When we stopped sending and everything in `sendbuf` is "in flight",
1025*6236dae4SAndroid Build Coastguard Worker * we are at the end of the request body. */
1026*6236dae4SAndroid Build Coastguard Worker if(stream->upload_left == 0) {
1027*6236dae4SAndroid Build Coastguard Worker *pflags = NGHTTP3_DATA_FLAG_EOF;
1028*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
1029*6236dae4SAndroid Build Coastguard Worker }
1030*6236dae4SAndroid Build Coastguard Worker else if(!nwritten) {
1031*6236dae4SAndroid Build Coastguard Worker /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
1032*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
1033*6236dae4SAndroid Build Coastguard Worker stream->s.id);
1034*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_WOULDBLOCK;
1035*6236dae4SAndroid Build Coastguard Worker }
1036*6236dae4SAndroid Build Coastguard Worker
1037*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
1038*6236dae4SAndroid Build Coastguard Worker "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
1039*6236dae4SAndroid Build Coastguard Worker stream->s.id, (int)nvecs,
1040*6236dae4SAndroid Build Coastguard Worker *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
1041*6236dae4SAndroid Build Coastguard Worker nwritten, Curl_bufq_len(&stream->sendbuf),
1042*6236dae4SAndroid Build Coastguard Worker stream->upload_left);
1043*6236dae4SAndroid Build Coastguard Worker return (nghttp3_ssize)nvecs;
1044*6236dae4SAndroid Build Coastguard Worker }
1045*6236dae4SAndroid Build Coastguard Worker
cb_h3_acked_stream_data(nghttp3_conn * conn,int64_t stream_id,uint64_t datalen,void * user_data,void * stream_user_data)1046*6236dae4SAndroid Build Coastguard Worker static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1047*6236dae4SAndroid Build Coastguard Worker uint64_t datalen, void *user_data,
1048*6236dae4SAndroid Build Coastguard Worker void *stream_user_data)
1049*6236dae4SAndroid Build Coastguard Worker {
1050*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = user_data;
1051*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1052*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = stream_user_data;
1053*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1054*6236dae4SAndroid Build Coastguard Worker size_t skiplen;
1055*6236dae4SAndroid Build Coastguard Worker
1056*6236dae4SAndroid Build Coastguard Worker (void)cf;
1057*6236dae4SAndroid Build Coastguard Worker if(!stream)
1058*6236dae4SAndroid Build Coastguard Worker return 0;
1059*6236dae4SAndroid Build Coastguard Worker /* The server acknowledged `datalen` of bytes from our request body.
1060*6236dae4SAndroid Build Coastguard Worker * This is a delta. We have kept this data in `sendbuf` for
1061*6236dae4SAndroid Build Coastguard Worker * re-transmissions and can free it now. */
1062*6236dae4SAndroid Build Coastguard Worker if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
1063*6236dae4SAndroid Build Coastguard Worker skiplen = stream->sendbuf_len_in_flight;
1064*6236dae4SAndroid Build Coastguard Worker else
1065*6236dae4SAndroid Build Coastguard Worker skiplen = (size_t)datalen;
1066*6236dae4SAndroid Build Coastguard Worker Curl_bufq_skip(&stream->sendbuf, skiplen);
1067*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight -= skiplen;
1068*6236dae4SAndroid Build Coastguard Worker
1069*6236dae4SAndroid Build Coastguard Worker /* Resume upload processing if we have more data to send */
1070*6236dae4SAndroid Build Coastguard Worker if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1071*6236dae4SAndroid Build Coastguard Worker int rv = nghttp3_conn_resume_stream(conn, stream_id);
1072*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1073*6236dae4SAndroid Build Coastguard Worker return NGHTTP3_ERR_CALLBACK_FAILURE;
1074*6236dae4SAndroid Build Coastguard Worker }
1075*6236dae4SAndroid Build Coastguard Worker }
1076*6236dae4SAndroid Build Coastguard Worker return 0;
1077*6236dae4SAndroid Build Coastguard Worker }
1078*6236dae4SAndroid Build Coastguard Worker
1079*6236dae4SAndroid Build Coastguard Worker static nghttp3_callbacks ngh3_callbacks = {
1080*6236dae4SAndroid Build Coastguard Worker cb_h3_acked_stream_data,
1081*6236dae4SAndroid Build Coastguard Worker cb_h3_stream_close,
1082*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_data,
1083*6236dae4SAndroid Build Coastguard Worker cb_h3_deferred_consume,
1084*6236dae4SAndroid Build Coastguard Worker NULL, /* begin_headers */
1085*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_header,
1086*6236dae4SAndroid Build Coastguard Worker cb_h3_end_headers,
1087*6236dae4SAndroid Build Coastguard Worker NULL, /* begin_trailers */
1088*6236dae4SAndroid Build Coastguard Worker cb_h3_recv_header,
1089*6236dae4SAndroid Build Coastguard Worker NULL, /* end_trailers */
1090*6236dae4SAndroid Build Coastguard Worker cb_h3_stop_sending,
1091*6236dae4SAndroid Build Coastguard Worker NULL, /* end_stream */
1092*6236dae4SAndroid Build Coastguard Worker cb_h3_reset_stream,
1093*6236dae4SAndroid Build Coastguard Worker NULL, /* shutdown */
1094*6236dae4SAndroid Build Coastguard Worker NULL /* recv_settings */
1095*6236dae4SAndroid Build Coastguard Worker };
1096*6236dae4SAndroid Build Coastguard Worker
cf_osslq_h3conn_init(struct cf_osslq_ctx * ctx,SSL * conn,void * user_data)1097*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn,
1098*6236dae4SAndroid Build Coastguard Worker void *user_data)
1099*6236dae4SAndroid Build Coastguard Worker {
1100*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_h3conn *h3 = &ctx->h3;
1101*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1102*6236dae4SAndroid Build Coastguard Worker int rc;
1103*6236dae4SAndroid Build Coastguard Worker
1104*6236dae4SAndroid Build Coastguard Worker nghttp3_settings_default(&h3->settings);
1105*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_client_new(&h3->conn,
1106*6236dae4SAndroid Build Coastguard Worker &ngh3_callbacks,
1107*6236dae4SAndroid Build Coastguard Worker &h3->settings,
1108*6236dae4SAndroid Build Coastguard Worker nghttp3_mem_default(),
1109*6236dae4SAndroid Build Coastguard Worker user_data);
1110*6236dae4SAndroid Build Coastguard Worker if(rc) {
1111*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1112*6236dae4SAndroid Build Coastguard Worker goto out;
1113*6236dae4SAndroid Build Coastguard Worker }
1114*6236dae4SAndroid Build Coastguard Worker
1115*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_stream_open(&h3->s_ctrl, conn,
1116*6236dae4SAndroid Build Coastguard Worker SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
1117*6236dae4SAndroid Build Coastguard Worker &ctx->stream_bufcp, NULL);
1118*6236dae4SAndroid Build Coastguard Worker if(result) {
1119*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1120*6236dae4SAndroid Build Coastguard Worker goto out;
1121*6236dae4SAndroid Build Coastguard Worker }
1122*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_stream_open(&h3->s_qpack_enc, conn,
1123*6236dae4SAndroid Build Coastguard Worker SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
1124*6236dae4SAndroid Build Coastguard Worker &ctx->stream_bufcp, NULL);
1125*6236dae4SAndroid Build Coastguard Worker if(result) {
1126*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1127*6236dae4SAndroid Build Coastguard Worker goto out;
1128*6236dae4SAndroid Build Coastguard Worker }
1129*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_stream_open(&h3->s_qpack_dec, conn,
1130*6236dae4SAndroid Build Coastguard Worker SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
1131*6236dae4SAndroid Build Coastguard Worker &ctx->stream_bufcp, NULL);
1132*6236dae4SAndroid Build Coastguard Worker if(result) {
1133*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1134*6236dae4SAndroid Build Coastguard Worker goto out;
1135*6236dae4SAndroid Build Coastguard Worker }
1136*6236dae4SAndroid Build Coastguard Worker
1137*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_bind_control_stream(h3->conn, h3->s_ctrl.id);
1138*6236dae4SAndroid Build Coastguard Worker if(rc) {
1139*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1140*6236dae4SAndroid Build Coastguard Worker goto out;
1141*6236dae4SAndroid Build Coastguard Worker }
1142*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_bind_qpack_streams(h3->conn, h3->s_qpack_enc.id,
1143*6236dae4SAndroid Build Coastguard Worker h3->s_qpack_dec.id);
1144*6236dae4SAndroid Build Coastguard Worker if(rc) {
1145*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1146*6236dae4SAndroid Build Coastguard Worker goto out;
1147*6236dae4SAndroid Build Coastguard Worker }
1148*6236dae4SAndroid Build Coastguard Worker
1149*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1150*6236dae4SAndroid Build Coastguard Worker out:
1151*6236dae4SAndroid Build Coastguard Worker return result;
1152*6236dae4SAndroid Build Coastguard Worker }
1153*6236dae4SAndroid Build Coastguard Worker
cf_osslq_ctx_start(struct Curl_cfilter * cf,struct Curl_easy * data)1154*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
1155*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1156*6236dae4SAndroid Build Coastguard Worker {
1157*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1158*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1159*6236dae4SAndroid Build Coastguard Worker int rv;
1160*6236dae4SAndroid Build Coastguard Worker const struct Curl_sockaddr_ex *peer_addr = NULL;
1161*6236dae4SAndroid Build Coastguard Worker BIO *bio = NULL;
1162*6236dae4SAndroid Build Coastguard Worker BIO_ADDR *baddr = NULL;
1163*6236dae4SAndroid Build Coastguard Worker
1164*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->initialized);
1165*6236dae4SAndroid Build Coastguard Worker result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
1166*6236dae4SAndroid Build Coastguard Worker if(result)
1167*6236dae4SAndroid Build Coastguard Worker goto out;
1168*6236dae4SAndroid Build Coastguard Worker
1169*6236dae4SAndroid Build Coastguard Worker #define H3_ALPN "\x2h3"
1170*6236dae4SAndroid Build Coastguard Worker result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
1171*6236dae4SAndroid Build Coastguard Worker H3_ALPN, sizeof(H3_ALPN) - 1,
1172*6236dae4SAndroid Build Coastguard Worker NULL, NULL, NULL);
1173*6236dae4SAndroid Build Coastguard Worker if(result)
1174*6236dae4SAndroid Build Coastguard Worker goto out;
1175*6236dae4SAndroid Build Coastguard Worker
1176*6236dae4SAndroid Build Coastguard Worker result = vquic_ctx_init(&ctx->q);
1177*6236dae4SAndroid Build Coastguard Worker if(result)
1178*6236dae4SAndroid Build Coastguard Worker goto out;
1179*6236dae4SAndroid Build Coastguard Worker
1180*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1181*6236dae4SAndroid Build Coastguard Worker Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL);
1182*6236dae4SAndroid Build Coastguard Worker if(!peer_addr)
1183*6236dae4SAndroid Build Coastguard Worker goto out;
1184*6236dae4SAndroid Build Coastguard Worker
1185*6236dae4SAndroid Build Coastguard Worker ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
1186*6236dae4SAndroid Build Coastguard Worker rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
1187*6236dae4SAndroid Build Coastguard Worker &ctx->q.local_addrlen);
1188*6236dae4SAndroid Build Coastguard Worker if(rv == -1)
1189*6236dae4SAndroid Build Coastguard Worker goto out;
1190*6236dae4SAndroid Build Coastguard Worker
1191*6236dae4SAndroid Build Coastguard Worker result = make_bio_addr(&baddr, peer_addr);
1192*6236dae4SAndroid Build Coastguard Worker if(result) {
1193*6236dae4SAndroid Build Coastguard Worker failf(data, "error creating BIO_ADDR from sockaddr");
1194*6236dae4SAndroid Build Coastguard Worker goto out;
1195*6236dae4SAndroid Build Coastguard Worker }
1196*6236dae4SAndroid Build Coastguard Worker
1197*6236dae4SAndroid Build Coastguard Worker /* Type conversions, see #12861: OpenSSL wants an `int`, but on 64-bit
1198*6236dae4SAndroid Build Coastguard Worker * Win32 systems, Microsoft defines SOCKET as `unsigned long long`.
1199*6236dae4SAndroid Build Coastguard Worker */
1200*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
1201*6236dae4SAndroid Build Coastguard Worker if(ctx->q.sockfd > INT_MAX) {
1202*6236dae4SAndroid Build Coastguard Worker failf(data, "Windows socket identifier larger than MAX_INT, "
1203*6236dae4SAndroid Build Coastguard Worker "unable to set in OpenSSL dgram API.");
1204*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUIC_CONNECT_ERROR;
1205*6236dae4SAndroid Build Coastguard Worker goto out;
1206*6236dae4SAndroid Build Coastguard Worker }
1207*6236dae4SAndroid Build Coastguard Worker bio = BIO_new_dgram((int)ctx->q.sockfd, BIO_NOCLOSE);
1208*6236dae4SAndroid Build Coastguard Worker #else
1209*6236dae4SAndroid Build Coastguard Worker bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE);
1210*6236dae4SAndroid Build Coastguard Worker #endif
1211*6236dae4SAndroid Build Coastguard Worker if(!bio) {
1212*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1213*6236dae4SAndroid Build Coastguard Worker goto out;
1214*6236dae4SAndroid Build Coastguard Worker }
1215*6236dae4SAndroid Build Coastguard Worker
1216*6236dae4SAndroid Build Coastguard Worker if(!SSL_set1_initial_peer_addr(ctx->tls.ossl.ssl, baddr)) {
1217*6236dae4SAndroid Build Coastguard Worker failf(data, "failed to set the initial peer address");
1218*6236dae4SAndroid Build Coastguard Worker result = CURLE_FAILED_INIT;
1219*6236dae4SAndroid Build Coastguard Worker goto out;
1220*6236dae4SAndroid Build Coastguard Worker }
1221*6236dae4SAndroid Build Coastguard Worker if(!SSL_set_blocking_mode(ctx->tls.ossl.ssl, 0)) {
1222*6236dae4SAndroid Build Coastguard Worker failf(data, "failed to turn off blocking mode");
1223*6236dae4SAndroid Build Coastguard Worker result = CURLE_FAILED_INIT;
1224*6236dae4SAndroid Build Coastguard Worker goto out;
1225*6236dae4SAndroid Build Coastguard Worker }
1226*6236dae4SAndroid Build Coastguard Worker
1227*6236dae4SAndroid Build Coastguard Worker #ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
1228*6236dae4SAndroid Build Coastguard Worker /* Added in OpenSSL v3.3.x */
1229*6236dae4SAndroid Build Coastguard Worker if(!SSL_set_feature_request_uint(ctx->tls.ossl.ssl,
1230*6236dae4SAndroid Build Coastguard Worker SSL_VALUE_QUIC_IDLE_TIMEOUT,
1231*6236dae4SAndroid Build Coastguard Worker CURL_QUIC_MAX_IDLE_MS)) {
1232*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "error setting idle timeout, ");
1233*6236dae4SAndroid Build Coastguard Worker result = CURLE_FAILED_INIT;
1234*6236dae4SAndroid Build Coastguard Worker goto out;
1235*6236dae4SAndroid Build Coastguard Worker }
1236*6236dae4SAndroid Build Coastguard Worker #endif
1237*6236dae4SAndroid Build Coastguard Worker
1238*6236dae4SAndroid Build Coastguard Worker SSL_set_bio(ctx->tls.ossl.ssl, bio, bio);
1239*6236dae4SAndroid Build Coastguard Worker bio = NULL;
1240*6236dae4SAndroid Build Coastguard Worker SSL_set_connect_state(ctx->tls.ossl.ssl);
1241*6236dae4SAndroid Build Coastguard Worker SSL_set_incoming_stream_policy(ctx->tls.ossl.ssl,
1242*6236dae4SAndroid Build Coastguard Worker SSL_INCOMING_STREAM_POLICY_ACCEPT, 0);
1243*6236dae4SAndroid Build Coastguard Worker /* setup the H3 things on top of the QUIC connection */
1244*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_h3conn_init(ctx, ctx->tls.ossl.ssl, cf);
1245*6236dae4SAndroid Build Coastguard Worker
1246*6236dae4SAndroid Build Coastguard Worker out:
1247*6236dae4SAndroid Build Coastguard Worker if(bio)
1248*6236dae4SAndroid Build Coastguard Worker BIO_free(bio);
1249*6236dae4SAndroid Build Coastguard Worker if(baddr)
1250*6236dae4SAndroid Build Coastguard Worker BIO_ADDR_free(baddr);
1251*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "QUIC tls init -> %d", result);
1252*6236dae4SAndroid Build Coastguard Worker return result;
1253*6236dae4SAndroid Build Coastguard Worker }
1254*6236dae4SAndroid Build Coastguard Worker
1255*6236dae4SAndroid Build Coastguard Worker struct h3_quic_recv_ctx {
1256*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf;
1257*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data;
1258*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream *s;
1259*6236dae4SAndroid Build Coastguard Worker };
1260*6236dae4SAndroid Build Coastguard Worker
h3_quic_recv(void * reader_ctx,unsigned char * buf,size_t len,CURLcode * err)1261*6236dae4SAndroid Build Coastguard Worker static ssize_t h3_quic_recv(void *reader_ctx,
1262*6236dae4SAndroid Build Coastguard Worker unsigned char *buf, size_t len,
1263*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1264*6236dae4SAndroid Build Coastguard Worker {
1265*6236dae4SAndroid Build Coastguard Worker struct h3_quic_recv_ctx *x = reader_ctx;
1266*6236dae4SAndroid Build Coastguard Worker size_t nread;
1267*6236dae4SAndroid Build Coastguard Worker int rv;
1268*6236dae4SAndroid Build Coastguard Worker
1269*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1270*6236dae4SAndroid Build Coastguard Worker rv = SSL_read_ex(x->s->ssl, buf, len, &nread);
1271*6236dae4SAndroid Build Coastguard Worker if(rv <= 0) {
1272*6236dae4SAndroid Build Coastguard Worker int detail = SSL_get_error(x->s->ssl, rv);
1273*6236dae4SAndroid Build Coastguard Worker if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) {
1274*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
1275*6236dae4SAndroid Build Coastguard Worker return -1;
1276*6236dae4SAndroid Build Coastguard Worker }
1277*6236dae4SAndroid Build Coastguard Worker else if(detail == SSL_ERROR_ZERO_RETURN) {
1278*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS",
1279*6236dae4SAndroid Build Coastguard Worker x->s->id);
1280*6236dae4SAndroid Build Coastguard Worker x->s->recvd_eos = TRUE;
1281*6236dae4SAndroid Build Coastguard Worker return 0;
1282*6236dae4SAndroid Build Coastguard Worker }
1283*6236dae4SAndroid Build Coastguard Worker else if(SSL_get_stream_read_state(x->s->ssl) ==
1284*6236dae4SAndroid Build Coastguard Worker SSL_STREAM_STATE_RESET_REMOTE) {
1285*6236dae4SAndroid Build Coastguard Worker uint64_t app_error_code = NGHTTP3_H3_NO_ERROR;
1286*6236dae4SAndroid Build Coastguard Worker SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
1287*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, "
1288*6236dae4SAndroid Build Coastguard Worker "rv=%d, app_err=%" FMT_PRIu64,
1289*6236dae4SAndroid Build Coastguard Worker x->s->id, rv, (curl_uint64_t)app_error_code);
1290*6236dae4SAndroid Build Coastguard Worker if(app_error_code != NGHTTP3_H3_NO_ERROR) {
1291*6236dae4SAndroid Build Coastguard Worker x->s->reset = TRUE;
1292*6236dae4SAndroid Build Coastguard Worker }
1293*6236dae4SAndroid Build Coastguard Worker x->s->recvd_eos = TRUE;
1294*6236dae4SAndroid Build Coastguard Worker return 0;
1295*6236dae4SAndroid Build Coastguard Worker }
1296*6236dae4SAndroid Build Coastguard Worker else {
1297*6236dae4SAndroid Build Coastguard Worker *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
1298*6236dae4SAndroid Build Coastguard Worker return -1;
1299*6236dae4SAndroid Build Coastguard Worker }
1300*6236dae4SAndroid Build Coastguard Worker }
1301*6236dae4SAndroid Build Coastguard Worker return (ssize_t)nread;
1302*6236dae4SAndroid Build Coastguard Worker }
1303*6236dae4SAndroid Build Coastguard Worker
cf_osslq_stream_recv(struct cf_osslq_stream * s,struct Curl_cfilter * cf,struct Curl_easy * data)1304*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
1305*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf,
1306*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1307*6236dae4SAndroid Build Coastguard Worker {
1308*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1309*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1310*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
1311*6236dae4SAndroid Build Coastguard Worker struct h3_quic_recv_ctx x;
1312*6236dae4SAndroid Build Coastguard Worker bool eagain = FALSE;
1313*6236dae4SAndroid Build Coastguard Worker size_t total_recv_len = 0;
1314*6236dae4SAndroid Build Coastguard Worker
1315*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(s);
1316*6236dae4SAndroid Build Coastguard Worker if(s->closed)
1317*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1318*6236dae4SAndroid Build Coastguard Worker
1319*6236dae4SAndroid Build Coastguard Worker x.cf = cf;
1320*6236dae4SAndroid Build Coastguard Worker x.data = data;
1321*6236dae4SAndroid Build Coastguard Worker x.s = s;
1322*6236dae4SAndroid Build Coastguard Worker while(s->ssl && !s->closed && !eagain &&
1323*6236dae4SAndroid Build Coastguard Worker (total_recv_len < H3_STREAM_CHUNK_SIZE)) {
1324*6236dae4SAndroid Build Coastguard Worker if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) {
1325*6236dae4SAndroid Build Coastguard Worker while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) {
1326*6236dae4SAndroid Build Coastguard Worker nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result);
1327*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
1328*6236dae4SAndroid Build Coastguard Worker if(result != CURLE_AGAIN)
1329*6236dae4SAndroid Build Coastguard Worker goto out;
1330*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1331*6236dae4SAndroid Build Coastguard Worker eagain = TRUE;
1332*6236dae4SAndroid Build Coastguard Worker }
1333*6236dae4SAndroid Build Coastguard Worker }
1334*6236dae4SAndroid Build Coastguard Worker }
1335*6236dae4SAndroid Build Coastguard Worker
1336*6236dae4SAndroid Build Coastguard Worker /* Forward what we have to nghttp3 */
1337*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufq_is_empty(&s->recvbuf)) {
1338*6236dae4SAndroid Build Coastguard Worker const unsigned char *buf;
1339*6236dae4SAndroid Build Coastguard Worker size_t blen;
1340*6236dae4SAndroid Build Coastguard Worker
1341*6236dae4SAndroid Build Coastguard Worker while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) {
1342*6236dae4SAndroid Build Coastguard Worker nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id,
1343*6236dae4SAndroid Build Coastguard Worker buf, blen, 0);
1344*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forward %zu bytes "
1345*6236dae4SAndroid Build Coastguard Worker "to nghttp3 -> %zd", s->id, blen, nread);
1346*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
1347*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s",
1348*6236dae4SAndroid Build Coastguard Worker blen, nghttp3_strerror((int)nread));
1349*6236dae4SAndroid Build Coastguard Worker result = CURLE_RECV_ERROR;
1350*6236dae4SAndroid Build Coastguard Worker goto out;
1351*6236dae4SAndroid Build Coastguard Worker }
1352*6236dae4SAndroid Build Coastguard Worker /* success, `nread` is the flow for QUIC to count as "consumed",
1353*6236dae4SAndroid Build Coastguard Worker * not sure how that will work with OpenSSL. Anyways, without error,
1354*6236dae4SAndroid Build Coastguard Worker * all data that we passed is not owned by nghttp3. */
1355*6236dae4SAndroid Build Coastguard Worker Curl_bufq_skip(&s->recvbuf, blen);
1356*6236dae4SAndroid Build Coastguard Worker total_recv_len += blen;
1357*6236dae4SAndroid Build Coastguard Worker }
1358*6236dae4SAndroid Build Coastguard Worker }
1359*6236dae4SAndroid Build Coastguard Worker
1360*6236dae4SAndroid Build Coastguard Worker /* When we forwarded everything, handle RESET/EOS */
1361*6236dae4SAndroid Build Coastguard Worker if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) {
1362*6236dae4SAndroid Build Coastguard Worker int rv;
1363*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1364*6236dae4SAndroid Build Coastguard Worker if(s->reset) {
1365*6236dae4SAndroid Build Coastguard Worker uint64_t app_error;
1366*6236dae4SAndroid Build Coastguard Worker if(!SSL_get_stream_read_error_code(s->ssl, &app_error)) {
1367*6236dae4SAndroid Build Coastguard Worker failf(data, "SSL_get_stream_read_error_code returned error");
1368*6236dae4SAndroid Build Coastguard Worker result = CURLE_RECV_ERROR;
1369*6236dae4SAndroid Build Coastguard Worker goto out;
1370*6236dae4SAndroid Build Coastguard Worker }
1371*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, app_error);
1372*6236dae4SAndroid Build Coastguard Worker s->closed = TRUE;
1373*6236dae4SAndroid Build Coastguard Worker if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1374*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_close_stream returned error: %s",
1375*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror(rv));
1376*6236dae4SAndroid Build Coastguard Worker result = CURLE_RECV_ERROR;
1377*6236dae4SAndroid Build Coastguard Worker goto out;
1378*6236dae4SAndroid Build Coastguard Worker }
1379*6236dae4SAndroid Build Coastguard Worker }
1380*6236dae4SAndroid Build Coastguard Worker else if(s->recvd_eos) {
1381*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id,
1382*6236dae4SAndroid Build Coastguard Worker NGHTTP3_H3_NO_ERROR);
1383*6236dae4SAndroid Build Coastguard Worker s->closed = TRUE;
1384*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] close nghttp3 stream -> %d",
1385*6236dae4SAndroid Build Coastguard Worker s->id, rv);
1386*6236dae4SAndroid Build Coastguard Worker if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1387*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_close_stream returned error: %s",
1388*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror(rv));
1389*6236dae4SAndroid Build Coastguard Worker result = CURLE_RECV_ERROR;
1390*6236dae4SAndroid Build Coastguard Worker goto out;
1391*6236dae4SAndroid Build Coastguard Worker }
1392*6236dae4SAndroid Build Coastguard Worker }
1393*6236dae4SAndroid Build Coastguard Worker }
1394*6236dae4SAndroid Build Coastguard Worker }
1395*6236dae4SAndroid Build Coastguard Worker out:
1396*6236dae4SAndroid Build Coastguard Worker if(result)
1397*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_osslq_stream_recv -> %d",
1398*6236dae4SAndroid Build Coastguard Worker s->id, result);
1399*6236dae4SAndroid Build Coastguard Worker return result;
1400*6236dae4SAndroid Build Coastguard Worker }
1401*6236dae4SAndroid Build Coastguard Worker
cf_progress_ingress(struct Curl_cfilter * cf,struct Curl_easy * data)1402*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
1403*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1404*6236dae4SAndroid Build Coastguard Worker {
1405*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1406*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1407*6236dae4SAndroid Build Coastguard Worker
1408*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl)
1409*6236dae4SAndroid Build Coastguard Worker goto out;
1410*6236dae4SAndroid Build Coastguard Worker
1411*6236dae4SAndroid Build Coastguard Worker ERR_clear_error();
1412*6236dae4SAndroid Build Coastguard Worker
1413*6236dae4SAndroid Build Coastguard Worker /* 1. Check for new incoming streams */
1414*6236dae4SAndroid Build Coastguard Worker while(1) {
1415*6236dae4SAndroid Build Coastguard Worker SSL *snew = SSL_accept_stream(ctx->tls.ossl.ssl,
1416*6236dae4SAndroid Build Coastguard Worker SSL_ACCEPT_STREAM_NO_BLOCK);
1417*6236dae4SAndroid Build Coastguard Worker if(!snew)
1418*6236dae4SAndroid Build Coastguard Worker break;
1419*6236dae4SAndroid Build Coastguard Worker
1420*6236dae4SAndroid Build Coastguard Worker (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data);
1421*6236dae4SAndroid Build Coastguard Worker }
1422*6236dae4SAndroid Build Coastguard Worker
1423*6236dae4SAndroid Build Coastguard Worker if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
1424*6236dae4SAndroid Build Coastguard Worker int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
1425*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR);
1426*6236dae4SAndroid Build Coastguard Worker }
1427*6236dae4SAndroid Build Coastguard Worker
1428*6236dae4SAndroid Build Coastguard Worker if(ctx->h3.conn) {
1429*6236dae4SAndroid Build Coastguard Worker size_t i;
1430*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < ctx->h3.remote_ctrl_n; ++i) {
1431*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_stream_recv(&ctx->h3.remote_ctrl[i], cf, data);
1432*6236dae4SAndroid Build Coastguard Worker if(result)
1433*6236dae4SAndroid Build Coastguard Worker goto out;
1434*6236dae4SAndroid Build Coastguard Worker }
1435*6236dae4SAndroid Build Coastguard Worker }
1436*6236dae4SAndroid Build Coastguard Worker
1437*6236dae4SAndroid Build Coastguard Worker if(ctx->h3.conn) {
1438*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
1439*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream;
1440*6236dae4SAndroid Build Coastguard Worker /* PULL all open streams */
1441*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data->multi);
1442*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
1443*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *sdata = Curl_node_elem(e);
1444*6236dae4SAndroid Build Coastguard Worker if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
1445*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, sdata);
1446*6236dae4SAndroid Build Coastguard Worker if(stream && !stream->closed &&
1447*6236dae4SAndroid Build Coastguard Worker !Curl_bufq_is_full(&stream->recvbuf)) {
1448*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_stream_recv(&stream->s, cf, sdata);
1449*6236dae4SAndroid Build Coastguard Worker if(result)
1450*6236dae4SAndroid Build Coastguard Worker goto out;
1451*6236dae4SAndroid Build Coastguard Worker }
1452*6236dae4SAndroid Build Coastguard Worker }
1453*6236dae4SAndroid Build Coastguard Worker }
1454*6236dae4SAndroid Build Coastguard Worker }
1455*6236dae4SAndroid Build Coastguard Worker
1456*6236dae4SAndroid Build Coastguard Worker out:
1457*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "progress_ingress -> %d", result);
1458*6236dae4SAndroid Build Coastguard Worker return result;
1459*6236dae4SAndroid Build Coastguard Worker }
1460*6236dae4SAndroid Build Coastguard Worker
1461*6236dae4SAndroid Build Coastguard Worker /* Iterate over all streams and check if blocked can be unblocked */
cf_osslq_check_and_unblock(struct Curl_cfilter * cf,struct Curl_easy * data)1462*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
1463*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1464*6236dae4SAndroid Build Coastguard Worker {
1465*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1466*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream;
1467*6236dae4SAndroid Build Coastguard Worker
1468*6236dae4SAndroid Build Coastguard Worker if(ctx->h3.conn) {
1469*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
1470*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
1471*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *sdata = Curl_node_elem(e);
1472*6236dae4SAndroid Build Coastguard Worker if(sdata->conn == data->conn) {
1473*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, sdata);
1474*6236dae4SAndroid Build Coastguard Worker if(stream && stream->s.ssl && stream->s.send_blocked &&
1475*6236dae4SAndroid Build Coastguard Worker !SSL_want_write(stream->s.ssl)) {
1476*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
1477*6236dae4SAndroid Build Coastguard Worker stream->s.send_blocked = FALSE;
1478*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, sdata);
1479*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(sdata, cf, "unblocked");
1480*6236dae4SAndroid Build Coastguard Worker }
1481*6236dae4SAndroid Build Coastguard Worker }
1482*6236dae4SAndroid Build Coastguard Worker }
1483*6236dae4SAndroid Build Coastguard Worker }
1484*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1485*6236dae4SAndroid Build Coastguard Worker }
1486*6236dae4SAndroid Build Coastguard Worker
h3_send_streams(struct Curl_cfilter * cf,struct Curl_easy * data)1487*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_send_streams(struct Curl_cfilter *cf,
1488*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1489*6236dae4SAndroid Build Coastguard Worker {
1490*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1491*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1492*6236dae4SAndroid Build Coastguard Worker
1493*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl || !ctx->h3.conn)
1494*6236dae4SAndroid Build Coastguard Worker goto out;
1495*6236dae4SAndroid Build Coastguard Worker
1496*6236dae4SAndroid Build Coastguard Worker for(;;) {
1497*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_stream *s = NULL;
1498*6236dae4SAndroid Build Coastguard Worker nghttp3_vec vec[16];
1499*6236dae4SAndroid Build Coastguard Worker nghttp3_ssize n, i;
1500*6236dae4SAndroid Build Coastguard Worker int64_t stream_id;
1501*6236dae4SAndroid Build Coastguard Worker size_t written;
1502*6236dae4SAndroid Build Coastguard Worker int eos, ok, rv;
1503*6236dae4SAndroid Build Coastguard Worker size_t total_len, acked_len = 0;
1504*6236dae4SAndroid Build Coastguard Worker bool blocked = FALSE, eos_written = FALSE;
1505*6236dae4SAndroid Build Coastguard Worker
1506*6236dae4SAndroid Build Coastguard Worker n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos,
1507*6236dae4SAndroid Build Coastguard Worker vec, ARRAYSIZE(vec));
1508*6236dae4SAndroid Build Coastguard Worker if(n < 0) {
1509*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_writev_stream returned error: %s",
1510*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror((int)n));
1511*6236dae4SAndroid Build Coastguard Worker result = CURLE_SEND_ERROR;
1512*6236dae4SAndroid Build Coastguard Worker goto out;
1513*6236dae4SAndroid Build Coastguard Worker }
1514*6236dae4SAndroid Build Coastguard Worker if(stream_id < 0) {
1515*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1516*6236dae4SAndroid Build Coastguard Worker goto out;
1517*6236dae4SAndroid Build Coastguard Worker }
1518*6236dae4SAndroid Build Coastguard Worker
1519*6236dae4SAndroid Build Coastguard Worker /* Get the stream for this data */
1520*6236dae4SAndroid Build Coastguard Worker s = cf_osslq_get_qstream(cf, data, stream_id);
1521*6236dae4SAndroid Build Coastguard Worker if(!s) {
1522*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_writev_stream gave unknown stream %"
1523*6236dae4SAndroid Build Coastguard Worker FMT_PRId64, (curl_int64_t)stream_id);
1524*6236dae4SAndroid Build Coastguard Worker result = CURLE_SEND_ERROR;
1525*6236dae4SAndroid Build Coastguard Worker goto out;
1526*6236dae4SAndroid Build Coastguard Worker }
1527*6236dae4SAndroid Build Coastguard Worker /* Now write the data to the stream's SSL*, it may not all fit! */
1528*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(s->id == stream_id);
1529*6236dae4SAndroid Build Coastguard Worker for(i = 0, total_len = 0; i < n; ++i) {
1530*6236dae4SAndroid Build Coastguard Worker total_len += vec[i].len;
1531*6236dae4SAndroid Build Coastguard Worker }
1532*6236dae4SAndroid Build Coastguard Worker for(i = 0; (i < n) && !blocked; ++i) {
1533*6236dae4SAndroid Build Coastguard Worker /* Without stream->s.ssl, we closed that already, so
1534*6236dae4SAndroid Build Coastguard Worker * pretend the write did succeed. */
1535*6236dae4SAndroid Build Coastguard Worker uint64_t flags = (eos && ((i + 1) == n)) ? SSL_WRITE_FLAG_CONCLUDE : 0;
1536*6236dae4SAndroid Build Coastguard Worker written = vec[i].len;
1537*6236dae4SAndroid Build Coastguard Worker ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
1538*6236dae4SAndroid Build Coastguard Worker &written);
1539*6236dae4SAndroid Build Coastguard Worker if(ok && flags & SSL_WRITE_FLAG_CONCLUDE)
1540*6236dae4SAndroid Build Coastguard Worker eos_written = TRUE;
1541*6236dae4SAndroid Build Coastguard Worker if(ok) {
1542*6236dae4SAndroid Build Coastguard Worker /* As OpenSSL buffers the data, we count this as acknowledged
1543*6236dae4SAndroid Build Coastguard Worker * from nghttp3's point of view */
1544*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send %zu bytes to QUIC ok",
1545*6236dae4SAndroid Build Coastguard Worker s->id, vec[i].len);
1546*6236dae4SAndroid Build Coastguard Worker acked_len += vec[i].len;
1547*6236dae4SAndroid Build Coastguard Worker }
1548*6236dae4SAndroid Build Coastguard Worker else {
1549*6236dae4SAndroid Build Coastguard Worker int detail = SSL_get_error(s->ssl, 0);
1550*6236dae4SAndroid Build Coastguard Worker switch(detail) {
1551*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_WRITE:
1552*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_READ:
1553*6236dae4SAndroid Build Coastguard Worker /* QUIC blocked us from writing more */
1554*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%"FMT_PRId64 "] send %zu bytes to "
1555*6236dae4SAndroid Build Coastguard Worker "QUIC blocked", s->id, vec[i].len);
1556*6236dae4SAndroid Build Coastguard Worker written = 0;
1557*6236dae4SAndroid Build Coastguard Worker nghttp3_conn_block_stream(ctx->h3.conn, s->id);
1558*6236dae4SAndroid Build Coastguard Worker s->send_blocked = blocked = TRUE;
1559*6236dae4SAndroid Build Coastguard Worker break;
1560*6236dae4SAndroid Build Coastguard Worker default:
1561*6236dae4SAndroid Build Coastguard Worker failf(data, "[%"FMT_PRId64 "] send %zu bytes to QUIC, SSL error %d",
1562*6236dae4SAndroid Build Coastguard Worker s->id, vec[i].len, detail);
1563*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_ssl_err(cf, data, detail, CURLE_HTTP3);
1564*6236dae4SAndroid Build Coastguard Worker goto out;
1565*6236dae4SAndroid Build Coastguard Worker }
1566*6236dae4SAndroid Build Coastguard Worker }
1567*6236dae4SAndroid Build Coastguard Worker }
1568*6236dae4SAndroid Build Coastguard Worker
1569*6236dae4SAndroid Build Coastguard Worker if(acked_len > 0 || (eos && !s->send_blocked)) {
1570*6236dae4SAndroid Build Coastguard Worker /* Since QUIC buffers the data written internally, we can tell
1571*6236dae4SAndroid Build Coastguard Worker * nghttp3 that it can move forward on it */
1572*6236dae4SAndroid Build Coastguard Worker ctx->q.last_io = Curl_now();
1573*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len);
1574*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1575*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
1576*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror(rv));
1577*6236dae4SAndroid Build Coastguard Worker result = CURLE_SEND_ERROR;
1578*6236dae4SAndroid Build Coastguard Worker goto out;
1579*6236dae4SAndroid Build Coastguard Worker }
1580*6236dae4SAndroid Build Coastguard Worker rv = nghttp3_conn_add_ack_offset(ctx->h3.conn, s->id, acked_len);
1581*6236dae4SAndroid Build Coastguard Worker if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1582*6236dae4SAndroid Build Coastguard Worker failf(data, "nghttp3_conn_add_ack_offset returned error: %s\n",
1583*6236dae4SAndroid Build Coastguard Worker nghttp3_strerror(rv));
1584*6236dae4SAndroid Build Coastguard Worker result = CURLE_SEND_ERROR;
1585*6236dae4SAndroid Build Coastguard Worker goto out;
1586*6236dae4SAndroid Build Coastguard Worker }
1587*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forwarded %zu/%zu h3 bytes "
1588*6236dae4SAndroid Build Coastguard Worker "to QUIC, eos=%d", s->id, acked_len, total_len, eos);
1589*6236dae4SAndroid Build Coastguard Worker }
1590*6236dae4SAndroid Build Coastguard Worker
1591*6236dae4SAndroid Build Coastguard Worker if(eos && !s->send_blocked && !eos_written) {
1592*6236dae4SAndroid Build Coastguard Worker /* wrote everything and H3 indicates end of stream */
1593*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] closing QUIC stream", s->id);
1594*6236dae4SAndroid Build Coastguard Worker SSL_stream_conclude(s->ssl, 0);
1595*6236dae4SAndroid Build Coastguard Worker }
1596*6236dae4SAndroid Build Coastguard Worker }
1597*6236dae4SAndroid Build Coastguard Worker
1598*6236dae4SAndroid Build Coastguard Worker out:
1599*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "h3_send_streams -> %d", result);
1600*6236dae4SAndroid Build Coastguard Worker return result;
1601*6236dae4SAndroid Build Coastguard Worker }
1602*6236dae4SAndroid Build Coastguard Worker
cf_progress_egress(struct Curl_cfilter * cf,struct Curl_easy * data)1603*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
1604*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1605*6236dae4SAndroid Build Coastguard Worker {
1606*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1607*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1608*6236dae4SAndroid Build Coastguard Worker
1609*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl)
1610*6236dae4SAndroid Build Coastguard Worker goto out;
1611*6236dae4SAndroid Build Coastguard Worker
1612*6236dae4SAndroid Build Coastguard Worker ERR_clear_error();
1613*6236dae4SAndroid Build Coastguard Worker result = h3_send_streams(cf, data);
1614*6236dae4SAndroid Build Coastguard Worker if(result)
1615*6236dae4SAndroid Build Coastguard Worker goto out;
1616*6236dae4SAndroid Build Coastguard Worker
1617*6236dae4SAndroid Build Coastguard Worker if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
1618*6236dae4SAndroid Build Coastguard Worker int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
1619*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
1620*6236dae4SAndroid Build Coastguard Worker }
1621*6236dae4SAndroid Build Coastguard Worker
1622*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_check_and_unblock(cf, data);
1623*6236dae4SAndroid Build Coastguard Worker
1624*6236dae4SAndroid Build Coastguard Worker out:
1625*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "progress_egress -> %d", result);
1626*6236dae4SAndroid Build Coastguard Worker return result;
1627*6236dae4SAndroid Build Coastguard Worker }
1628*6236dae4SAndroid Build Coastguard Worker
check_and_set_expiry(struct Curl_cfilter * cf,struct Curl_easy * data)1629*6236dae4SAndroid Build Coastguard Worker static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
1630*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data)
1631*6236dae4SAndroid Build Coastguard Worker {
1632*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1633*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1634*6236dae4SAndroid Build Coastguard Worker struct timeval tv;
1635*6236dae4SAndroid Build Coastguard Worker timediff_t timeoutms;
1636*6236dae4SAndroid Build Coastguard Worker int is_infinite = 1;
1637*6236dae4SAndroid Build Coastguard Worker
1638*6236dae4SAndroid Build Coastguard Worker if(ctx->tls.ossl.ssl &&
1639*6236dae4SAndroid Build Coastguard Worker SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
1640*6236dae4SAndroid Build Coastguard Worker !is_infinite) {
1641*6236dae4SAndroid Build Coastguard Worker timeoutms = curlx_tvtoms(&tv);
1642*6236dae4SAndroid Build Coastguard Worker /* QUIC want to be called again latest at the returned timeout */
1643*6236dae4SAndroid Build Coastguard Worker if(timeoutms <= 0) {
1644*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data);
1645*6236dae4SAndroid Build Coastguard Worker if(result)
1646*6236dae4SAndroid Build Coastguard Worker goto out;
1647*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data);
1648*6236dae4SAndroid Build Coastguard Worker if(result)
1649*6236dae4SAndroid Build Coastguard Worker goto out;
1650*6236dae4SAndroid Build Coastguard Worker if(SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite)) {
1651*6236dae4SAndroid Build Coastguard Worker timeoutms = curlx_tvtoms(&tv);
1652*6236dae4SAndroid Build Coastguard Worker }
1653*6236dae4SAndroid Build Coastguard Worker }
1654*6236dae4SAndroid Build Coastguard Worker if(!is_infinite) {
1655*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, timeoutms, EXPIRE_QUIC);
1656*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "QUIC expiry in %ldms", (long)timeoutms);
1657*6236dae4SAndroid Build Coastguard Worker }
1658*6236dae4SAndroid Build Coastguard Worker }
1659*6236dae4SAndroid Build Coastguard Worker out:
1660*6236dae4SAndroid Build Coastguard Worker return result;
1661*6236dae4SAndroid Build Coastguard Worker }
1662*6236dae4SAndroid Build Coastguard Worker
cf_osslq_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1663*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
1664*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1665*6236dae4SAndroid Build Coastguard Worker bool blocking, bool *done)
1666*6236dae4SAndroid Build Coastguard Worker {
1667*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1668*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1669*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
1670*6236dae4SAndroid Build Coastguard Worker struct curltime now;
1671*6236dae4SAndroid Build Coastguard Worker int err;
1672*6236dae4SAndroid Build Coastguard Worker
1673*6236dae4SAndroid Build Coastguard Worker if(cf->connected) {
1674*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
1675*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1676*6236dae4SAndroid Build Coastguard Worker }
1677*6236dae4SAndroid Build Coastguard Worker
1678*6236dae4SAndroid Build Coastguard Worker /* Connect the UDP filter first */
1679*6236dae4SAndroid Build Coastguard Worker if(!cf->next->connected) {
1680*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_cf_connect(cf->next, data, blocking, done);
1681*6236dae4SAndroid Build Coastguard Worker if(result || !*done)
1682*6236dae4SAndroid Build Coastguard Worker return result;
1683*6236dae4SAndroid Build Coastguard Worker }
1684*6236dae4SAndroid Build Coastguard Worker
1685*6236dae4SAndroid Build Coastguard Worker *done = FALSE;
1686*6236dae4SAndroid Build Coastguard Worker now = Curl_now();
1687*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
1688*6236dae4SAndroid Build Coastguard Worker
1689*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl) {
1690*6236dae4SAndroid Build Coastguard Worker ctx->started_at = now;
1691*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_ctx_start(cf, data);
1692*6236dae4SAndroid Build Coastguard Worker if(result)
1693*6236dae4SAndroid Build Coastguard Worker goto out;
1694*6236dae4SAndroid Build Coastguard Worker }
1695*6236dae4SAndroid Build Coastguard Worker
1696*6236dae4SAndroid Build Coastguard Worker if(!ctx->got_first_byte) {
1697*6236dae4SAndroid Build Coastguard Worker int readable = SOCKET_READABLE(ctx->q.sockfd, 0);
1698*6236dae4SAndroid Build Coastguard Worker if(readable > 0 && (readable & CURL_CSELECT_IN)) {
1699*6236dae4SAndroid Build Coastguard Worker ctx->got_first_byte = TRUE;
1700*6236dae4SAndroid Build Coastguard Worker ctx->first_byte_at = Curl_now();
1701*6236dae4SAndroid Build Coastguard Worker }
1702*6236dae4SAndroid Build Coastguard Worker }
1703*6236dae4SAndroid Build Coastguard Worker
1704*6236dae4SAndroid Build Coastguard Worker /* Since OpenSSL does its own send/recv internally, we may miss the
1705*6236dae4SAndroid Build Coastguard Worker * moment to populate the x509 store right before the server response.
1706*6236dae4SAndroid Build Coastguard Worker * Do it instead before we start the handshake, at the loss of the
1707*6236dae4SAndroid Build Coastguard Worker * time to set this up. */
1708*6236dae4SAndroid Build Coastguard Worker result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
1709*6236dae4SAndroid Build Coastguard Worker if(result)
1710*6236dae4SAndroid Build Coastguard Worker goto out;
1711*6236dae4SAndroid Build Coastguard Worker
1712*6236dae4SAndroid Build Coastguard Worker ERR_clear_error();
1713*6236dae4SAndroid Build Coastguard Worker err = SSL_do_handshake(ctx->tls.ossl.ssl);
1714*6236dae4SAndroid Build Coastguard Worker
1715*6236dae4SAndroid Build Coastguard Worker if(err == 1) {
1716*6236dae4SAndroid Build Coastguard Worker /* connected */
1717*6236dae4SAndroid Build Coastguard Worker ctx->handshake_at = now;
1718*6236dae4SAndroid Build Coastguard Worker ctx->q.last_io = now;
1719*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "handshake complete after %dms",
1720*6236dae4SAndroid Build Coastguard Worker (int)Curl_timediff(now, ctx->started_at));
1721*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_verify_peer(cf, data);
1722*6236dae4SAndroid Build Coastguard Worker if(!result) {
1723*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "peer verified");
1724*6236dae4SAndroid Build Coastguard Worker cf->connected = TRUE;
1725*6236dae4SAndroid Build Coastguard Worker cf->conn->alpn = CURL_HTTP_VERSION_3;
1726*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
1727*6236dae4SAndroid Build Coastguard Worker connkeep(cf->conn, "HTTP/3 default");
1728*6236dae4SAndroid Build Coastguard Worker }
1729*6236dae4SAndroid Build Coastguard Worker }
1730*6236dae4SAndroid Build Coastguard Worker else {
1731*6236dae4SAndroid Build Coastguard Worker int detail = SSL_get_error(ctx->tls.ossl.ssl, err);
1732*6236dae4SAndroid Build Coastguard Worker switch(detail) {
1733*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_READ:
1734*6236dae4SAndroid Build Coastguard Worker ctx->q.last_io = now;
1735*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
1736*6236dae4SAndroid Build Coastguard Worker goto out;
1737*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_WRITE:
1738*6236dae4SAndroid Build Coastguard Worker ctx->q.last_io = now;
1739*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND");
1740*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1741*6236dae4SAndroid Build Coastguard Worker goto out;
1742*6236dae4SAndroid Build Coastguard Worker #ifdef SSL_ERROR_WANT_ASYNC
1743*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_ASYNC:
1744*6236dae4SAndroid Build Coastguard Worker ctx->q.last_io = now;
1745*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC");
1746*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1747*6236dae4SAndroid Build Coastguard Worker goto out;
1748*6236dae4SAndroid Build Coastguard Worker #endif
1749*6236dae4SAndroid Build Coastguard Worker #ifdef SSL_ERROR_WANT_RETRY_VERIFY
1750*6236dae4SAndroid Build Coastguard Worker case SSL_ERROR_WANT_RETRY_VERIFY:
1751*6236dae4SAndroid Build Coastguard Worker result = CURLE_OK;
1752*6236dae4SAndroid Build Coastguard Worker goto out;
1753*6236dae4SAndroid Build Coastguard Worker #endif
1754*6236dae4SAndroid Build Coastguard Worker default:
1755*6236dae4SAndroid Build Coastguard Worker result = cf_osslq_ssl_err(cf, data, detail, CURLE_COULDNT_CONNECT);
1756*6236dae4SAndroid Build Coastguard Worker goto out;
1757*6236dae4SAndroid Build Coastguard Worker }
1758*6236dae4SAndroid Build Coastguard Worker }
1759*6236dae4SAndroid Build Coastguard Worker
1760*6236dae4SAndroid Build Coastguard Worker out:
1761*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_RECV_ERROR && ctx->tls.ossl.ssl &&
1762*6236dae4SAndroid Build Coastguard Worker ctx->protocol_shutdown) {
1763*6236dae4SAndroid Build Coastguard Worker /* When a QUIC server instance is shutting down, it may send us a
1764*6236dae4SAndroid Build Coastguard Worker * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
1765*6236dae4SAndroid Build Coastguard Worker * state. The CONNECT may work in the near future again. Indicate
1766*6236dae4SAndroid Build Coastguard Worker * that as a "weird" reply. */
1767*6236dae4SAndroid Build Coastguard Worker result = CURLE_WEIRD_SERVER_REPLY;
1768*6236dae4SAndroid Build Coastguard Worker }
1769*6236dae4SAndroid Build Coastguard Worker
1770*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
1771*6236dae4SAndroid Build Coastguard Worker if(result) {
1772*6236dae4SAndroid Build Coastguard Worker struct ip_quadruple ip;
1773*6236dae4SAndroid Build Coastguard Worker
1774*6236dae4SAndroid Build Coastguard Worker Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
1775*6236dae4SAndroid Build Coastguard Worker infof(data, "QUIC connect to %s port %u failed: %s",
1776*6236dae4SAndroid Build Coastguard Worker ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
1777*6236dae4SAndroid Build Coastguard Worker }
1778*6236dae4SAndroid Build Coastguard Worker #endif
1779*6236dae4SAndroid Build Coastguard Worker if(!result)
1780*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data);
1781*6236dae4SAndroid Build Coastguard Worker if(result || *done)
1782*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
1783*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
1784*6236dae4SAndroid Build Coastguard Worker return result;
1785*6236dae4SAndroid Build Coastguard Worker }
1786*6236dae4SAndroid Build Coastguard Worker
h3_stream_open(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1787*6236dae4SAndroid Build Coastguard Worker static ssize_t h3_stream_open(struct Curl_cfilter *cf,
1788*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1789*6236dae4SAndroid Build Coastguard Worker const void *buf, size_t len,
1790*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1791*6236dae4SAndroid Build Coastguard Worker {
1792*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1793*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = NULL;
1794*6236dae4SAndroid Build Coastguard Worker struct dynhds h2_headers;
1795*6236dae4SAndroid Build Coastguard Worker size_t nheader;
1796*6236dae4SAndroid Build Coastguard Worker nghttp3_nv *nva = NULL;
1797*6236dae4SAndroid Build Coastguard Worker int rc = 0;
1798*6236dae4SAndroid Build Coastguard Worker unsigned int i;
1799*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = -1;
1800*6236dae4SAndroid Build Coastguard Worker nghttp3_data_reader reader;
1801*6236dae4SAndroid Build Coastguard Worker nghttp3_data_reader *preader = NULL;
1802*6236dae4SAndroid Build Coastguard Worker
1803*6236dae4SAndroid Build Coastguard Worker Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
1804*6236dae4SAndroid Build Coastguard Worker
1805*6236dae4SAndroid Build Coastguard Worker *err = h3_data_setup(cf, data);
1806*6236dae4SAndroid Build Coastguard Worker if(*err)
1807*6236dae4SAndroid Build Coastguard Worker goto out;
1808*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, data);
1809*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream);
1810*6236dae4SAndroid Build Coastguard Worker if(!stream) {
1811*6236dae4SAndroid Build Coastguard Worker *err = CURLE_FAILED_INIT;
1812*6236dae4SAndroid Build Coastguard Worker goto out;
1813*6236dae4SAndroid Build Coastguard Worker }
1814*6236dae4SAndroid Build Coastguard Worker
1815*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
1816*6236dae4SAndroid Build Coastguard Worker if(nwritten < 0)
1817*6236dae4SAndroid Build Coastguard Worker goto out;
1818*6236dae4SAndroid Build Coastguard Worker if(!stream->h1.done) {
1819*6236dae4SAndroid Build Coastguard Worker /* need more data */
1820*6236dae4SAndroid Build Coastguard Worker goto out;
1821*6236dae4SAndroid Build Coastguard Worker }
1822*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream->h1.req);
1823*6236dae4SAndroid Build Coastguard Worker
1824*6236dae4SAndroid Build Coastguard Worker *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
1825*6236dae4SAndroid Build Coastguard Worker if(*err) {
1826*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1827*6236dae4SAndroid Build Coastguard Worker goto out;
1828*6236dae4SAndroid Build Coastguard Worker }
1829*6236dae4SAndroid Build Coastguard Worker /* no longer needed */
1830*6236dae4SAndroid Build Coastguard Worker Curl_h1_req_parse_free(&stream->h1);
1831*6236dae4SAndroid Build Coastguard Worker
1832*6236dae4SAndroid Build Coastguard Worker nheader = Curl_dynhds_count(&h2_headers);
1833*6236dae4SAndroid Build Coastguard Worker nva = malloc(sizeof(nghttp3_nv) * nheader);
1834*6236dae4SAndroid Build Coastguard Worker if(!nva) {
1835*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OUT_OF_MEMORY;
1836*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1837*6236dae4SAndroid Build Coastguard Worker goto out;
1838*6236dae4SAndroid Build Coastguard Worker }
1839*6236dae4SAndroid Build Coastguard Worker
1840*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < nheader; ++i) {
1841*6236dae4SAndroid Build Coastguard Worker struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
1842*6236dae4SAndroid Build Coastguard Worker nva[i].name = (unsigned char *)e->name;
1843*6236dae4SAndroid Build Coastguard Worker nva[i].namelen = e->namelen;
1844*6236dae4SAndroid Build Coastguard Worker nva[i].value = (unsigned char *)e->value;
1845*6236dae4SAndroid Build Coastguard Worker nva[i].valuelen = e->valuelen;
1846*6236dae4SAndroid Build Coastguard Worker nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1847*6236dae4SAndroid Build Coastguard Worker }
1848*6236dae4SAndroid Build Coastguard Worker
1849*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(stream->s.id == -1);
1850*6236dae4SAndroid Build Coastguard Worker *err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
1851*6236dae4SAndroid Build Coastguard Worker &ctx->stream_bufcp, data);
1852*6236dae4SAndroid Build Coastguard Worker if(*err) {
1853*6236dae4SAndroid Build Coastguard Worker failf(data, "cannot get bidi streams");
1854*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1855*6236dae4SAndroid Build Coastguard Worker goto out;
1856*6236dae4SAndroid Build Coastguard Worker }
1857*6236dae4SAndroid Build Coastguard Worker
1858*6236dae4SAndroid Build Coastguard Worker switch(data->state.httpreq) {
1859*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST:
1860*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST_FORM:
1861*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_POST_MIME:
1862*6236dae4SAndroid Build Coastguard Worker case HTTPREQ_PUT:
1863*6236dae4SAndroid Build Coastguard Worker /* known request body size or -1 */
1864*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize != -1)
1865*6236dae4SAndroid Build Coastguard Worker stream->upload_left = data->state.infilesize;
1866*6236dae4SAndroid Build Coastguard Worker else
1867*6236dae4SAndroid Build Coastguard Worker /* data sending without specifying the data amount up front */
1868*6236dae4SAndroid Build Coastguard Worker stream->upload_left = -1; /* unknown */
1869*6236dae4SAndroid Build Coastguard Worker break;
1870*6236dae4SAndroid Build Coastguard Worker default:
1871*6236dae4SAndroid Build Coastguard Worker /* there is not request body */
1872*6236dae4SAndroid Build Coastguard Worker stream->upload_left = 0; /* no request body */
1873*6236dae4SAndroid Build Coastguard Worker break;
1874*6236dae4SAndroid Build Coastguard Worker }
1875*6236dae4SAndroid Build Coastguard Worker
1876*6236dae4SAndroid Build Coastguard Worker stream->send_closed = (stream->upload_left == 0);
1877*6236dae4SAndroid Build Coastguard Worker if(!stream->send_closed) {
1878*6236dae4SAndroid Build Coastguard Worker reader.read_data = cb_h3_read_req_body;
1879*6236dae4SAndroid Build Coastguard Worker preader = &reader;
1880*6236dae4SAndroid Build Coastguard Worker }
1881*6236dae4SAndroid Build Coastguard Worker
1882*6236dae4SAndroid Build Coastguard Worker rc = nghttp3_conn_submit_request(ctx->h3.conn, stream->s.id,
1883*6236dae4SAndroid Build Coastguard Worker nva, nheader, preader, data);
1884*6236dae4SAndroid Build Coastguard Worker if(rc) {
1885*6236dae4SAndroid Build Coastguard Worker switch(rc) {
1886*6236dae4SAndroid Build Coastguard Worker case NGHTTP3_ERR_CONN_CLOSING:
1887*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64"] failed to send, "
1888*6236dae4SAndroid Build Coastguard Worker "connection is closing", stream->s.id);
1889*6236dae4SAndroid Build Coastguard Worker break;
1890*6236dae4SAndroid Build Coastguard Worker default:
1891*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64 "] failed to send -> %d (%s)",
1892*6236dae4SAndroid Build Coastguard Worker stream->s.id, rc, nghttp3_strerror(rc));
1893*6236dae4SAndroid Build Coastguard Worker break;
1894*6236dae4SAndroid Build Coastguard Worker }
1895*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
1896*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1897*6236dae4SAndroid Build Coastguard Worker goto out;
1898*6236dae4SAndroid Build Coastguard Worker }
1899*6236dae4SAndroid Build Coastguard Worker
1900*6236dae4SAndroid Build Coastguard Worker if(Curl_trc_is_verbose(data)) {
1901*6236dae4SAndroid Build Coastguard Worker infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
1902*6236dae4SAndroid Build Coastguard Worker stream->s.id, data->state.url);
1903*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < nheader; ++i) {
1904*6236dae4SAndroid Build Coastguard Worker infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]",
1905*6236dae4SAndroid Build Coastguard Worker stream->s.id,
1906*6236dae4SAndroid Build Coastguard Worker (int)nva[i].namelen, nva[i].name,
1907*6236dae4SAndroid Build Coastguard Worker (int)nva[i].valuelen, nva[i].value);
1908*6236dae4SAndroid Build Coastguard Worker }
1909*6236dae4SAndroid Build Coastguard Worker }
1910*6236dae4SAndroid Build Coastguard Worker
1911*6236dae4SAndroid Build Coastguard Worker out:
1912*6236dae4SAndroid Build Coastguard Worker free(nva);
1913*6236dae4SAndroid Build Coastguard Worker Curl_dynhds_free(&h2_headers);
1914*6236dae4SAndroid Build Coastguard Worker return nwritten;
1915*6236dae4SAndroid Build Coastguard Worker }
1916*6236dae4SAndroid Build Coastguard Worker
cf_osslq_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)1917*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1918*6236dae4SAndroid Build Coastguard Worker const void *buf, size_t len, bool eos,
1919*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
1920*6236dae4SAndroid Build Coastguard Worker {
1921*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
1922*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1923*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
1924*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten;
1925*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1926*6236dae4SAndroid Build Coastguard Worker
1927*6236dae4SAndroid Build Coastguard Worker (void)eos; /* TODO: use to end stream */
1928*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
1929*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cf->connected);
1930*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->tls.ossl.ssl);
1931*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->h3.conn);
1932*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1933*6236dae4SAndroid Build Coastguard Worker
1934*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data);
1935*6236dae4SAndroid Build Coastguard Worker if(result) {
1936*6236dae4SAndroid Build Coastguard Worker *err = result;
1937*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1938*6236dae4SAndroid Build Coastguard Worker goto out;
1939*6236dae4SAndroid Build Coastguard Worker }
1940*6236dae4SAndroid Build Coastguard Worker
1941*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data);
1942*6236dae4SAndroid Build Coastguard Worker if(result) {
1943*6236dae4SAndroid Build Coastguard Worker *err = result;
1944*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1945*6236dae4SAndroid Build Coastguard Worker goto out;
1946*6236dae4SAndroid Build Coastguard Worker }
1947*6236dae4SAndroid Build Coastguard Worker
1948*6236dae4SAndroid Build Coastguard Worker if(!stream || stream->s.id < 0) {
1949*6236dae4SAndroid Build Coastguard Worker nwritten = h3_stream_open(cf, data, buf, len, err);
1950*6236dae4SAndroid Build Coastguard Worker if(nwritten < 0) {
1951*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
1952*6236dae4SAndroid Build Coastguard Worker goto out;
1953*6236dae4SAndroid Build Coastguard Worker }
1954*6236dae4SAndroid Build Coastguard Worker stream = H3_STREAM_CTX(ctx, data);
1955*6236dae4SAndroid Build Coastguard Worker }
1956*6236dae4SAndroid Build Coastguard Worker else if(stream->closed) {
1957*6236dae4SAndroid Build Coastguard Worker if(stream->resp_hds_complete) {
1958*6236dae4SAndroid Build Coastguard Worker /* Server decided to close the stream after having sent us a final
1959*6236dae4SAndroid Build Coastguard Worker * response. This is valid if it is not interested in the request
1960*6236dae4SAndroid Build Coastguard Worker * body. This happens on 30x or 40x responses.
1961*6236dae4SAndroid Build Coastguard Worker * We silently discard the data sent, since this is not a transport
1962*6236dae4SAndroid Build Coastguard Worker * error situation. */
1963*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
1964*6236dae4SAndroid Build Coastguard Worker "on closed stream with response", stream->s.id);
1965*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
1966*6236dae4SAndroid Build Coastguard Worker nwritten = (ssize_t)len;
1967*6236dae4SAndroid Build Coastguard Worker goto out;
1968*6236dae4SAndroid Build Coastguard Worker }
1969*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
1970*6236dae4SAndroid Build Coastguard Worker "-> stream closed", stream->s.id, len);
1971*6236dae4SAndroid Build Coastguard Worker *err = CURLE_HTTP3;
1972*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1973*6236dae4SAndroid Build Coastguard Worker goto out;
1974*6236dae4SAndroid Build Coastguard Worker }
1975*6236dae4SAndroid Build Coastguard Worker else {
1976*6236dae4SAndroid Build Coastguard Worker nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
1977*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
1978*6236dae4SAndroid Build Coastguard Worker "sendbuf(len=%zu) -> %zd, %d",
1979*6236dae4SAndroid Build Coastguard Worker stream->s.id, len, nwritten, *err);
1980*6236dae4SAndroid Build Coastguard Worker if(nwritten < 0) {
1981*6236dae4SAndroid Build Coastguard Worker goto out;
1982*6236dae4SAndroid Build Coastguard Worker }
1983*6236dae4SAndroid Build Coastguard Worker
1984*6236dae4SAndroid Build Coastguard Worker (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
1985*6236dae4SAndroid Build Coastguard Worker }
1986*6236dae4SAndroid Build Coastguard Worker
1987*6236dae4SAndroid Build Coastguard Worker result = cf_progress_egress(cf, data);
1988*6236dae4SAndroid Build Coastguard Worker if(result) {
1989*6236dae4SAndroid Build Coastguard Worker *err = result;
1990*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
1991*6236dae4SAndroid Build Coastguard Worker }
1992*6236dae4SAndroid Build Coastguard Worker
1993*6236dae4SAndroid Build Coastguard Worker out:
1994*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data);
1995*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
1996*6236dae4SAndroid Build Coastguard Worker stream ? stream->s.id : -1, len, nwritten, *err);
1997*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
1998*6236dae4SAndroid Build Coastguard Worker return nwritten;
1999*6236dae4SAndroid Build Coastguard Worker }
2000*6236dae4SAndroid Build Coastguard Worker
recv_closed_stream(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream,CURLcode * err)2001*6236dae4SAndroid Build Coastguard Worker static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
2002*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2003*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream,
2004*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
2005*6236dae4SAndroid Build Coastguard Worker {
2006*6236dae4SAndroid Build Coastguard Worker ssize_t nread = -1;
2007*6236dae4SAndroid Build Coastguard Worker
2008*6236dae4SAndroid Build Coastguard Worker (void)cf;
2009*6236dae4SAndroid Build Coastguard Worker if(stream->reset) {
2010*6236dae4SAndroid Build Coastguard Worker failf(data,
2011*6236dae4SAndroid Build Coastguard Worker "HTTP/3 stream %" FMT_PRId64 " reset by server",
2012*6236dae4SAndroid Build Coastguard Worker stream->s.id);
2013*6236dae4SAndroid Build Coastguard Worker *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
2014*6236dae4SAndroid Build Coastguard Worker goto out;
2015*6236dae4SAndroid Build Coastguard Worker }
2016*6236dae4SAndroid Build Coastguard Worker else if(!stream->resp_hds_complete) {
2017*6236dae4SAndroid Build Coastguard Worker failf(data,
2018*6236dae4SAndroid Build Coastguard Worker "HTTP/3 stream %" FMT_PRId64
2019*6236dae4SAndroid Build Coastguard Worker " was closed cleanly, but before getting"
2020*6236dae4SAndroid Build Coastguard Worker " all response header fields, treated as error",
2021*6236dae4SAndroid Build Coastguard Worker stream->s.id);
2022*6236dae4SAndroid Build Coastguard Worker *err = CURLE_HTTP3;
2023*6236dae4SAndroid Build Coastguard Worker goto out;
2024*6236dae4SAndroid Build Coastguard Worker }
2025*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
2026*6236dae4SAndroid Build Coastguard Worker nread = 0;
2027*6236dae4SAndroid Build Coastguard Worker
2028*6236dae4SAndroid Build Coastguard Worker out:
2029*6236dae4SAndroid Build Coastguard Worker return nread;
2030*6236dae4SAndroid Build Coastguard Worker }
2031*6236dae4SAndroid Build Coastguard Worker
cf_osslq_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)2032*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
2033*6236dae4SAndroid Build Coastguard Worker char *buf, size_t len, CURLcode *err)
2034*6236dae4SAndroid Build Coastguard Worker {
2035*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2036*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
2037*6236dae4SAndroid Build Coastguard Worker ssize_t nread = -1;
2038*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2039*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2040*6236dae4SAndroid Build Coastguard Worker
2041*6236dae4SAndroid Build Coastguard Worker (void)ctx;
2042*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2043*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cf->connected);
2044*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx);
2045*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->tls.ossl.ssl);
2046*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(ctx->h3.conn);
2047*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
2048*6236dae4SAndroid Build Coastguard Worker
2049*6236dae4SAndroid Build Coastguard Worker if(!stream) {
2050*6236dae4SAndroid Build Coastguard Worker *err = CURLE_RECV_ERROR;
2051*6236dae4SAndroid Build Coastguard Worker goto out;
2052*6236dae4SAndroid Build Coastguard Worker }
2053*6236dae4SAndroid Build Coastguard Worker
2054*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufq_is_empty(&stream->recvbuf)) {
2055*6236dae4SAndroid Build Coastguard Worker nread = Curl_bufq_read(&stream->recvbuf,
2056*6236dae4SAndroid Build Coastguard Worker (unsigned char *)buf, len, err);
2057*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
2058*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
2059*6236dae4SAndroid Build Coastguard Worker "-> %zd, %d", stream->s.id, len, nread, *err);
2060*6236dae4SAndroid Build Coastguard Worker goto out;
2061*6236dae4SAndroid Build Coastguard Worker }
2062*6236dae4SAndroid Build Coastguard Worker }
2063*6236dae4SAndroid Build Coastguard Worker
2064*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data);
2065*6236dae4SAndroid Build Coastguard Worker if(result) {
2066*6236dae4SAndroid Build Coastguard Worker *err = result;
2067*6236dae4SAndroid Build Coastguard Worker nread = -1;
2068*6236dae4SAndroid Build Coastguard Worker goto out;
2069*6236dae4SAndroid Build Coastguard Worker }
2070*6236dae4SAndroid Build Coastguard Worker
2071*6236dae4SAndroid Build Coastguard Worker /* recvbuf had nothing before, maybe after progressing ingress? */
2072*6236dae4SAndroid Build Coastguard Worker if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
2073*6236dae4SAndroid Build Coastguard Worker nread = Curl_bufq_read(&stream->recvbuf,
2074*6236dae4SAndroid Build Coastguard Worker (unsigned char *)buf, len, err);
2075*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
2076*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
2077*6236dae4SAndroid Build Coastguard Worker "-> %zd, %d", stream->s.id, len, nread, *err);
2078*6236dae4SAndroid Build Coastguard Worker goto out;
2079*6236dae4SAndroid Build Coastguard Worker }
2080*6236dae4SAndroid Build Coastguard Worker }
2081*6236dae4SAndroid Build Coastguard Worker
2082*6236dae4SAndroid Build Coastguard Worker if(nread > 0) {
2083*6236dae4SAndroid Build Coastguard Worker h3_drain_stream(cf, data);
2084*6236dae4SAndroid Build Coastguard Worker }
2085*6236dae4SAndroid Build Coastguard Worker else {
2086*6236dae4SAndroid Build Coastguard Worker if(stream->closed) {
2087*6236dae4SAndroid Build Coastguard Worker nread = recv_closed_stream(cf, data, stream, err);
2088*6236dae4SAndroid Build Coastguard Worker goto out;
2089*6236dae4SAndroid Build Coastguard Worker }
2090*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
2091*6236dae4SAndroid Build Coastguard Worker nread = -1;
2092*6236dae4SAndroid Build Coastguard Worker }
2093*6236dae4SAndroid Build Coastguard Worker
2094*6236dae4SAndroid Build Coastguard Worker out:
2095*6236dae4SAndroid Build Coastguard Worker if(cf_progress_egress(cf, data)) {
2096*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SEND_ERROR;
2097*6236dae4SAndroid Build Coastguard Worker nread = -1;
2098*6236dae4SAndroid Build Coastguard Worker }
2099*6236dae4SAndroid Build Coastguard Worker else {
2100*6236dae4SAndroid Build Coastguard Worker CURLcode result2 = check_and_set_expiry(cf, data);
2101*6236dae4SAndroid Build Coastguard Worker if(result2) {
2102*6236dae4SAndroid Build Coastguard Worker *err = result2;
2103*6236dae4SAndroid Build Coastguard Worker nread = -1;
2104*6236dae4SAndroid Build Coastguard Worker }
2105*6236dae4SAndroid Build Coastguard Worker }
2106*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
2107*6236dae4SAndroid Build Coastguard Worker stream ? stream->s.id : -1, len, nread, *err);
2108*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2109*6236dae4SAndroid Build Coastguard Worker return nread;
2110*6236dae4SAndroid Build Coastguard Worker }
2111*6236dae4SAndroid Build Coastguard Worker
2112*6236dae4SAndroid Build Coastguard Worker /*
2113*6236dae4SAndroid Build Coastguard Worker * Called from transfer.c:data_pending to know if we should keep looping
2114*6236dae4SAndroid Build Coastguard Worker * to receive more data from the connection.
2115*6236dae4SAndroid Build Coastguard Worker */
cf_osslq_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)2116*6236dae4SAndroid Build Coastguard Worker static bool cf_osslq_data_pending(struct Curl_cfilter *cf,
2117*6236dae4SAndroid Build Coastguard Worker const struct Curl_easy *data)
2118*6236dae4SAndroid Build Coastguard Worker {
2119*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2120*6236dae4SAndroid Build Coastguard Worker const struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
2121*6236dae4SAndroid Build Coastguard Worker (void)cf;
2122*6236dae4SAndroid Build Coastguard Worker return stream && !Curl_bufq_is_empty(&stream->recvbuf);
2123*6236dae4SAndroid Build Coastguard Worker }
2124*6236dae4SAndroid Build Coastguard Worker
cf_osslq_data_event(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)2125*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
2126*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2127*6236dae4SAndroid Build Coastguard Worker int event, int arg1, void *arg2)
2128*6236dae4SAndroid Build Coastguard Worker {
2129*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2130*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2131*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2132*6236dae4SAndroid Build Coastguard Worker
2133*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2134*6236dae4SAndroid Build Coastguard Worker (void)arg1;
2135*6236dae4SAndroid Build Coastguard Worker (void)arg2;
2136*6236dae4SAndroid Build Coastguard Worker switch(event) {
2137*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_SETUP:
2138*6236dae4SAndroid Build Coastguard Worker break;
2139*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_PAUSE:
2140*6236dae4SAndroid Build Coastguard Worker result = h3_data_pause(cf, data, (arg1 != 0));
2141*6236dae4SAndroid Build Coastguard Worker break;
2142*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DETACH:
2143*6236dae4SAndroid Build Coastguard Worker h3_data_done(cf, data);
2144*6236dae4SAndroid Build Coastguard Worker break;
2145*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DONE:
2146*6236dae4SAndroid Build Coastguard Worker h3_data_done(cf, data);
2147*6236dae4SAndroid Build Coastguard Worker break;
2148*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_DONE_SEND: {
2149*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
2150*6236dae4SAndroid Build Coastguard Worker if(stream && !stream->send_closed) {
2151*6236dae4SAndroid Build Coastguard Worker stream->send_closed = TRUE;
2152*6236dae4SAndroid Build Coastguard Worker stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
2153*6236dae4SAndroid Build Coastguard Worker stream->sendbuf_len_in_flight;
2154*6236dae4SAndroid Build Coastguard Worker (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
2155*6236dae4SAndroid Build Coastguard Worker }
2156*6236dae4SAndroid Build Coastguard Worker break;
2157*6236dae4SAndroid Build Coastguard Worker }
2158*6236dae4SAndroid Build Coastguard Worker case CF_CTRL_DATA_IDLE: {
2159*6236dae4SAndroid Build Coastguard Worker struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
2160*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "data idle");
2161*6236dae4SAndroid Build Coastguard Worker if(stream && !stream->closed) {
2162*6236dae4SAndroid Build Coastguard Worker result = check_and_set_expiry(cf, data);
2163*6236dae4SAndroid Build Coastguard Worker }
2164*6236dae4SAndroid Build Coastguard Worker break;
2165*6236dae4SAndroid Build Coastguard Worker }
2166*6236dae4SAndroid Build Coastguard Worker default:
2167*6236dae4SAndroid Build Coastguard Worker break;
2168*6236dae4SAndroid Build Coastguard Worker }
2169*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2170*6236dae4SAndroid Build Coastguard Worker return result;
2171*6236dae4SAndroid Build Coastguard Worker }
2172*6236dae4SAndroid Build Coastguard Worker
cf_osslq_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)2173*6236dae4SAndroid Build Coastguard Worker static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
2174*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2175*6236dae4SAndroid Build Coastguard Worker bool *input_pending)
2176*6236dae4SAndroid Build Coastguard Worker {
2177*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2178*6236dae4SAndroid Build Coastguard Worker bool alive = FALSE;
2179*6236dae4SAndroid Build Coastguard Worker struct cf_call_data save;
2180*6236dae4SAndroid Build Coastguard Worker
2181*6236dae4SAndroid Build Coastguard Worker CF_DATA_SAVE(save, cf, data);
2182*6236dae4SAndroid Build Coastguard Worker *input_pending = FALSE;
2183*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl)
2184*6236dae4SAndroid Build Coastguard Worker goto out;
2185*6236dae4SAndroid Build Coastguard Worker
2186*6236dae4SAndroid Build Coastguard Worker #ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
2187*6236dae4SAndroid Build Coastguard Worker /* Added in OpenSSL v3.3.x */
2188*6236dae4SAndroid Build Coastguard Worker {
2189*6236dae4SAndroid Build Coastguard Worker timediff_t idletime;
2190*6236dae4SAndroid Build Coastguard Worker uint64_t idle_ms = ctx->max_idle_ms;
2191*6236dae4SAndroid Build Coastguard Worker if(!SSL_get_value_uint(ctx->tls.ossl.ssl,
2192*6236dae4SAndroid Build Coastguard Worker SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
2193*6236dae4SAndroid Build Coastguard Worker SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) {
2194*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "error getting negotiated idle timeout, "
2195*6236dae4SAndroid Build Coastguard Worker "assume connection is dead.");
2196*6236dae4SAndroid Build Coastguard Worker goto out;
2197*6236dae4SAndroid Build Coastguard Worker }
2198*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "negotiated idle timeout: %zums", (size_t)idle_ms);
2199*6236dae4SAndroid Build Coastguard Worker idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
2200*6236dae4SAndroid Build Coastguard Worker if(idletime > 0 && (uint64_t)idletime > idle_ms)
2201*6236dae4SAndroid Build Coastguard Worker goto out;
2202*6236dae4SAndroid Build Coastguard Worker }
2203*6236dae4SAndroid Build Coastguard Worker
2204*6236dae4SAndroid Build Coastguard Worker #endif
2205*6236dae4SAndroid Build Coastguard Worker
2206*6236dae4SAndroid Build Coastguard Worker if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
2207*6236dae4SAndroid Build Coastguard Worker goto out;
2208*6236dae4SAndroid Build Coastguard Worker
2209*6236dae4SAndroid Build Coastguard Worker alive = TRUE;
2210*6236dae4SAndroid Build Coastguard Worker if(*input_pending) {
2211*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2212*6236dae4SAndroid Build Coastguard Worker /* This happens before we have sent off a request and the connection is
2213*6236dae4SAndroid Build Coastguard Worker not in use by any other transfer, there should not be any data here,
2214*6236dae4SAndroid Build Coastguard Worker only "protocol frames" */
2215*6236dae4SAndroid Build Coastguard Worker *input_pending = FALSE;
2216*6236dae4SAndroid Build Coastguard Worker result = cf_progress_ingress(cf, data);
2217*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
2218*6236dae4SAndroid Build Coastguard Worker alive = result ? FALSE : TRUE;
2219*6236dae4SAndroid Build Coastguard Worker }
2220*6236dae4SAndroid Build Coastguard Worker
2221*6236dae4SAndroid Build Coastguard Worker out:
2222*6236dae4SAndroid Build Coastguard Worker CF_DATA_RESTORE(cf, save);
2223*6236dae4SAndroid Build Coastguard Worker return alive;
2224*6236dae4SAndroid Build Coastguard Worker }
2225*6236dae4SAndroid Build Coastguard Worker
cf_osslq_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)2226*6236dae4SAndroid Build Coastguard Worker static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
2227*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2228*6236dae4SAndroid Build Coastguard Worker struct easy_pollset *ps)
2229*6236dae4SAndroid Build Coastguard Worker {
2230*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2231*6236dae4SAndroid Build Coastguard Worker
2232*6236dae4SAndroid Build Coastguard Worker if(!ctx->tls.ossl.ssl) {
2233*6236dae4SAndroid Build Coastguard Worker /* NOP */
2234*6236dae4SAndroid Build Coastguard Worker }
2235*6236dae4SAndroid Build Coastguard Worker else if(!cf->connected) {
2236*6236dae4SAndroid Build Coastguard Worker /* during handshake, transfer has not started yet. we always
2237*6236dae4SAndroid Build Coastguard Worker * add our socket for polling if SSL wants to send/recv */
2238*6236dae4SAndroid Build Coastguard Worker Curl_pollset_set(data, ps, ctx->q.sockfd,
2239*6236dae4SAndroid Build Coastguard Worker SSL_net_read_desired(ctx->tls.ossl.ssl),
2240*6236dae4SAndroid Build Coastguard Worker SSL_net_write_desired(ctx->tls.ossl.ssl));
2241*6236dae4SAndroid Build Coastguard Worker }
2242*6236dae4SAndroid Build Coastguard Worker else {
2243*6236dae4SAndroid Build Coastguard Worker /* once connected, we only modify the socket if it is present.
2244*6236dae4SAndroid Build Coastguard Worker * this avoids adding it for paused transfers. */
2245*6236dae4SAndroid Build Coastguard Worker bool want_recv, want_send;
2246*6236dae4SAndroid Build Coastguard Worker Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
2247*6236dae4SAndroid Build Coastguard Worker if(want_recv || want_send) {
2248*6236dae4SAndroid Build Coastguard Worker Curl_pollset_set(data, ps, ctx->q.sockfd,
2249*6236dae4SAndroid Build Coastguard Worker SSL_net_read_desired(ctx->tls.ossl.ssl),
2250*6236dae4SAndroid Build Coastguard Worker SSL_net_write_desired(ctx->tls.ossl.ssl));
2251*6236dae4SAndroid Build Coastguard Worker }
2252*6236dae4SAndroid Build Coastguard Worker else if(ctx->need_recv || ctx->need_send) {
2253*6236dae4SAndroid Build Coastguard Worker Curl_pollset_set(data, ps, ctx->q.sockfd,
2254*6236dae4SAndroid Build Coastguard Worker ctx->need_recv, ctx->need_send);
2255*6236dae4SAndroid Build Coastguard Worker }
2256*6236dae4SAndroid Build Coastguard Worker }
2257*6236dae4SAndroid Build Coastguard Worker }
2258*6236dae4SAndroid Build Coastguard Worker
cf_osslq_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)2259*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
2260*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2261*6236dae4SAndroid Build Coastguard Worker int query, int *pres1, void *pres2)
2262*6236dae4SAndroid Build Coastguard Worker {
2263*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = cf->ctx;
2264*6236dae4SAndroid Build Coastguard Worker
2265*6236dae4SAndroid Build Coastguard Worker switch(query) {
2266*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_MAX_CONCURRENT: {
2267*6236dae4SAndroid Build Coastguard Worker #ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
2268*6236dae4SAndroid Build Coastguard Worker /* Added in OpenSSL v3.3.x */
2269*6236dae4SAndroid Build Coastguard Worker uint64_t v;
2270*6236dae4SAndroid Build Coastguard Worker if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
2271*6236dae4SAndroid Build Coastguard Worker SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
2272*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "error getting available local bidi streams");
2273*6236dae4SAndroid Build Coastguard Worker return CURLE_HTTP3;
2274*6236dae4SAndroid Build Coastguard Worker }
2275*6236dae4SAndroid Build Coastguard Worker /* we report avail + in_use */
2276*6236dae4SAndroid Build Coastguard Worker v += CONN_INUSE(cf->conn);
2277*6236dae4SAndroid Build Coastguard Worker *pres1 = (v > INT_MAX) ? INT_MAX : (int)v;
2278*6236dae4SAndroid Build Coastguard Worker #else
2279*6236dae4SAndroid Build Coastguard Worker *pres1 = 100;
2280*6236dae4SAndroid Build Coastguard Worker #endif
2281*6236dae4SAndroid Build Coastguard Worker CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
2282*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2283*6236dae4SAndroid Build Coastguard Worker }
2284*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_CONNECT_REPLY_MS:
2285*6236dae4SAndroid Build Coastguard Worker if(ctx->got_first_byte) {
2286*6236dae4SAndroid Build Coastguard Worker timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
2287*6236dae4SAndroid Build Coastguard Worker *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
2288*6236dae4SAndroid Build Coastguard Worker }
2289*6236dae4SAndroid Build Coastguard Worker else
2290*6236dae4SAndroid Build Coastguard Worker *pres1 = -1;
2291*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2292*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_TIMER_CONNECT: {
2293*6236dae4SAndroid Build Coastguard Worker struct curltime *when = pres2;
2294*6236dae4SAndroid Build Coastguard Worker if(ctx->got_first_byte)
2295*6236dae4SAndroid Build Coastguard Worker *when = ctx->first_byte_at;
2296*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2297*6236dae4SAndroid Build Coastguard Worker }
2298*6236dae4SAndroid Build Coastguard Worker case CF_QUERY_TIMER_APPCONNECT: {
2299*6236dae4SAndroid Build Coastguard Worker struct curltime *when = pres2;
2300*6236dae4SAndroid Build Coastguard Worker if(cf->connected)
2301*6236dae4SAndroid Build Coastguard Worker *when = ctx->handshake_at;
2302*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2303*6236dae4SAndroid Build Coastguard Worker }
2304*6236dae4SAndroid Build Coastguard Worker default:
2305*6236dae4SAndroid Build Coastguard Worker break;
2306*6236dae4SAndroid Build Coastguard Worker }
2307*6236dae4SAndroid Build Coastguard Worker return cf->next ?
2308*6236dae4SAndroid Build Coastguard Worker cf->next->cft->query(cf->next, data, query, pres1, pres2) :
2309*6236dae4SAndroid Build Coastguard Worker CURLE_UNKNOWN_OPTION;
2310*6236dae4SAndroid Build Coastguard Worker }
2311*6236dae4SAndroid Build Coastguard Worker
2312*6236dae4SAndroid Build Coastguard Worker struct Curl_cftype Curl_cft_http3 = {
2313*6236dae4SAndroid Build Coastguard Worker "HTTP/3",
2314*6236dae4SAndroid Build Coastguard Worker CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
2315*6236dae4SAndroid Build Coastguard Worker 0,
2316*6236dae4SAndroid Build Coastguard Worker cf_osslq_destroy,
2317*6236dae4SAndroid Build Coastguard Worker cf_osslq_connect,
2318*6236dae4SAndroid Build Coastguard Worker cf_osslq_close,
2319*6236dae4SAndroid Build Coastguard Worker cf_osslq_shutdown,
2320*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_get_host,
2321*6236dae4SAndroid Build Coastguard Worker cf_osslq_adjust_pollset,
2322*6236dae4SAndroid Build Coastguard Worker cf_osslq_data_pending,
2323*6236dae4SAndroid Build Coastguard Worker cf_osslq_send,
2324*6236dae4SAndroid Build Coastguard Worker cf_osslq_recv,
2325*6236dae4SAndroid Build Coastguard Worker cf_osslq_data_event,
2326*6236dae4SAndroid Build Coastguard Worker cf_osslq_conn_is_alive,
2327*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_conn_keep_alive,
2328*6236dae4SAndroid Build Coastguard Worker cf_osslq_query,
2329*6236dae4SAndroid Build Coastguard Worker };
2330*6236dae4SAndroid Build Coastguard Worker
Curl_cf_osslq_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai)2331*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
2332*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
2333*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
2334*6236dae4SAndroid Build Coastguard Worker const struct Curl_addrinfo *ai)
2335*6236dae4SAndroid Build Coastguard Worker {
2336*6236dae4SAndroid Build Coastguard Worker struct cf_osslq_ctx *ctx = NULL;
2337*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
2338*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2339*6236dae4SAndroid Build Coastguard Worker
2340*6236dae4SAndroid Build Coastguard Worker (void)data;
2341*6236dae4SAndroid Build Coastguard Worker ctx = calloc(1, sizeof(*ctx));
2342*6236dae4SAndroid Build Coastguard Worker if(!ctx) {
2343*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
2344*6236dae4SAndroid Build Coastguard Worker goto out;
2345*6236dae4SAndroid Build Coastguard Worker }
2346*6236dae4SAndroid Build Coastguard Worker cf_osslq_ctx_init(ctx);
2347*6236dae4SAndroid Build Coastguard Worker
2348*6236dae4SAndroid Build Coastguard Worker result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
2349*6236dae4SAndroid Build Coastguard Worker if(result)
2350*6236dae4SAndroid Build Coastguard Worker goto out;
2351*6236dae4SAndroid Build Coastguard Worker
2352*6236dae4SAndroid Build Coastguard Worker result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
2353*6236dae4SAndroid Build Coastguard Worker if(result)
2354*6236dae4SAndroid Build Coastguard Worker goto out;
2355*6236dae4SAndroid Build Coastguard Worker
2356*6236dae4SAndroid Build Coastguard Worker cf->conn = conn;
2357*6236dae4SAndroid Build Coastguard Worker udp_cf->conn = cf->conn;
2358*6236dae4SAndroid Build Coastguard Worker udp_cf->sockindex = cf->sockindex;
2359*6236dae4SAndroid Build Coastguard Worker cf->next = udp_cf;
2360*6236dae4SAndroid Build Coastguard Worker
2361*6236dae4SAndroid Build Coastguard Worker out:
2362*6236dae4SAndroid Build Coastguard Worker *pcf = (!result) ? cf : NULL;
2363*6236dae4SAndroid Build Coastguard Worker if(result) {
2364*6236dae4SAndroid Build Coastguard Worker if(udp_cf)
2365*6236dae4SAndroid Build Coastguard Worker Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
2366*6236dae4SAndroid Build Coastguard Worker Curl_safefree(cf);
2367*6236dae4SAndroid Build Coastguard Worker cf_osslq_ctx_free(ctx);
2368*6236dae4SAndroid Build Coastguard Worker }
2369*6236dae4SAndroid Build Coastguard Worker return result;
2370*6236dae4SAndroid Build Coastguard Worker }
2371*6236dae4SAndroid Build Coastguard Worker
Curl_conn_is_osslq(const struct Curl_easy * data,const struct connectdata * conn,int sockindex)2372*6236dae4SAndroid Build Coastguard Worker bool Curl_conn_is_osslq(const struct Curl_easy *data,
2373*6236dae4SAndroid Build Coastguard Worker const struct connectdata *conn,
2374*6236dae4SAndroid Build Coastguard Worker int sockindex)
2375*6236dae4SAndroid Build Coastguard Worker {
2376*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
2377*6236dae4SAndroid Build Coastguard Worker
2378*6236dae4SAndroid Build Coastguard Worker (void)data;
2379*6236dae4SAndroid Build Coastguard Worker for(; cf; cf = cf->next) {
2380*6236dae4SAndroid Build Coastguard Worker if(cf->cft == &Curl_cft_http3)
2381*6236dae4SAndroid Build Coastguard Worker return TRUE;
2382*6236dae4SAndroid Build Coastguard Worker if(cf->cft->flags & CF_TYPE_IP_CONNECT)
2383*6236dae4SAndroid Build Coastguard Worker return FALSE;
2384*6236dae4SAndroid Build Coastguard Worker }
2385*6236dae4SAndroid Build Coastguard Worker return FALSE;
2386*6236dae4SAndroid Build Coastguard Worker }
2387*6236dae4SAndroid Build Coastguard Worker
2388*6236dae4SAndroid Build Coastguard Worker /*
2389*6236dae4SAndroid Build Coastguard Worker * Store ngtcp2 version info in this buffer.
2390*6236dae4SAndroid Build Coastguard Worker */
Curl_osslq_ver(char * p,size_t len)2391*6236dae4SAndroid Build Coastguard Worker void Curl_osslq_ver(char *p, size_t len)
2392*6236dae4SAndroid Build Coastguard Worker {
2393*6236dae4SAndroid Build Coastguard Worker const nghttp3_info *ht3 = nghttp3_version(0);
2394*6236dae4SAndroid Build Coastguard Worker (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str);
2395*6236dae4SAndroid Build Coastguard Worker }
2396*6236dae4SAndroid Build Coastguard Worker
2397*6236dae4SAndroid Build Coastguard Worker #endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */
2398