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