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