File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vquic / ngtcp2.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    1: /***************************************************************************
    2:  *                                  _   _ ____  _
    3:  *  Project                     ___| | | |  _ \| |
    4:  *                             / __| | | | |_) | |
    5:  *                            | (__| |_| |  _ <| |___
    6:  *                             \___|\___/|_| \_\_____|
    7:  *
    8:  * Copyright (C) 1998 - 2020, 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.haxx.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:  ***************************************************************************/
   22: 
   23: #include "curl_setup.h"
   24: 
   25: #ifdef USE_NGTCP2
   26: #include <ngtcp2/ngtcp2.h>
   27: #include <ngtcp2/ngtcp2_crypto.h>
   28: #include <nghttp3/nghttp3.h>
   29: #ifdef USE_OPENSSL
   30: #include <openssl/err.h>
   31: #endif
   32: #include "urldata.h"
   33: #include "sendf.h"
   34: #include "strdup.h"
   35: #include "rand.h"
   36: #include "ngtcp2.h"
   37: #include "multiif.h"
   38: #include "strcase.h"
   39: #include "connect.h"
   40: #include "strerror.h"
   41: 
   42: /* The last 3 #include files should be in this order */
   43: #include "curl_printf.h"
   44: #include "curl_memory.h"
   45: #include "memdebug.h"
   46: 
   47: /* #define DEBUG_NGTCP2 */
   48: #ifdef CURLDEBUG
   49: #define DEBUG_HTTP3
   50: #endif
   51: #ifdef DEBUG_HTTP3
   52: #define H3BUGF(x) x
   53: #else
   54: #define H3BUGF(x) do { } while(0)
   55: #endif
   56: 
   57: /*
   58:  * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
   59:  * It is used as a circular buffer. Add new bytes at the end until it reaches
   60:  * the far end, then start over at index 0 again.
   61:  */
   62: 
   63: #define H3_SEND_SIZE (20*1024)
   64: struct h3out {
   65:   uint8_t buf[H3_SEND_SIZE];
   66:   size_t used;   /* number of bytes used in the buffer */
   67:   size_t windex; /* index in the buffer where to start writing the next
   68:                     data block */
   69: };
   70: 
   71: #define QUIC_MAX_STREAMS (256*1024)
   72: #define QUIC_MAX_DATA (1*1024*1024)
   73: #define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */
   74: 
   75: #ifdef USE_OPENSSL
   76: #define QUIC_CIPHERS                                                          \
   77:   "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_"               \
   78:   "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
   79: #define QUIC_GROUPS "P-256:X25519:P-384:P-521"
   80: #elif defined(USE_GNUTLS)
   81: #define QUIC_PRIORITY \
   82:   "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
   83:   "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
   84:   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
   85: #endif
   86: 
   87: static CURLcode ng_process_ingress(struct connectdata *conn,
   88:                                    curl_socket_t sockfd,
   89:                                    struct quicsocket *qs);
   90: static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
   91:                                 struct quicsocket *qs);
   92: static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
   93:                                    size_t datalen, void *user_data,
   94:                                    void *stream_user_data);
   95: 
   96: static ngtcp2_tstamp timestamp(void)
   97: {
   98:   struct curltime ct = Curl_now();
   99:   return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
  100: }
  101: 
  102: #ifdef DEBUG_NGTCP2
  103: static void quic_printf(void *user_data, const char *fmt, ...)
  104: {
  105:   va_list ap;
  106:   (void)user_data; /* TODO, use this to do infof() instead long-term */
  107:   va_start(ap, fmt);
  108:   vfprintf(stderr, fmt, ap);
  109:   va_end(ap);
  110:   fprintf(stderr, "\n");
  111: }
  112: #endif
  113: 
  114: #ifdef USE_OPENSSL
  115: static ngtcp2_crypto_level
  116: quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
  117: {
  118:   switch(ossl_level) {
  119:   case ssl_encryption_initial:
  120:     return NGTCP2_CRYPTO_LEVEL_INITIAL;
  121:   case ssl_encryption_early_data:
  122:     return NGTCP2_CRYPTO_LEVEL_EARLY;
  123:   case ssl_encryption_handshake:
  124:     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
  125:   case ssl_encryption_application:
  126:     return NGTCP2_CRYPTO_LEVEL_APP;
  127:   default:
  128:     assert(0);
  129:   }
  130: }
  131: #elif defined(USE_GNUTLS)
  132: static ngtcp2_crypto_level
  133: quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
  134: {
  135:   switch(gtls_level) {
  136:   case GNUTLS_ENCRYPTION_LEVEL_INITIAL:
  137:     return NGTCP2_CRYPTO_LEVEL_INITIAL;
  138:   case GNUTLS_ENCRYPTION_LEVEL_EARLY:
  139:     return NGTCP2_CRYPTO_LEVEL_EARLY;
  140:   case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
  141:     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
  142:   case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
  143:     return NGTCP2_CRYPTO_LEVEL_APP;
  144:   default:
  145:     assert(0);
  146:   }
  147: }
  148: #endif
  149: 
  150: static int setup_initial_crypto_context(struct quicsocket *qs)
  151: {
  152:   const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn);
  153: 
  154:   if(ngtcp2_crypto_derive_and_install_initial_key(
  155:          qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  156:          dcid) != 0)
  157:     return -1;
  158: 
  159:   return 0;
  160: }
  161: 
  162: static void quic_settings(ngtcp2_settings *s,
  163:                           uint64_t stream_buffer_size)
  164: {
  165:   ngtcp2_settings_default(s);
  166: #ifdef DEBUG_NGTCP2
  167:   s->log_printf = quic_printf;
  168: #else
  169:   s->log_printf = NULL;
  170: #endif
  171:   s->initial_ts = timestamp();
  172:   s->transport_params.initial_max_stream_data_bidi_local = stream_buffer_size;
  173:   s->transport_params.initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
  174:   s->transport_params.initial_max_stream_data_uni = QUIC_MAX_STREAMS;
  175:   s->transport_params.initial_max_data = QUIC_MAX_DATA;
  176:   s->transport_params.initial_max_streams_bidi = 1;
  177:   s->transport_params.initial_max_streams_uni = 3;
  178:   s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT;
  179: }
  180: 
  181: static FILE *keylog_file; /* not thread-safe */
  182: #ifdef USE_OPENSSL
  183: static void keylog_callback(const SSL *ssl, const char *line)
  184: {
  185:   (void)ssl;
  186:   fputs(line, keylog_file);
  187:   fputc('\n', keylog_file);
  188:   fflush(keylog_file);
  189: }
  190: #elif defined(USE_GNUTLS)
  191: static int keylog_callback(gnutls_session_t session, const char *label,
  192:                     const gnutls_datum_t *secret)
  193: {
  194:   gnutls_datum_t crandom;
  195:   gnutls_datum_t srandom;
  196:   gnutls_datum_t crandom_hex = { NULL, 0 };
  197:   gnutls_datum_t secret_hex = { NULL, 0 };
  198:   int rc = 0;
  199: 
  200:   gnutls_session_get_random(session, &crandom, &srandom);
  201:   if(crandom.size != 32) {
  202:     return -1;
  203:   }
  204: 
  205:   rc = gnutls_hex_encode2(&crandom, &crandom_hex);
  206:   if(rc < 0) {
  207:     fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
  208:             gnutls_strerror(rc));
  209:     goto out;
  210:   }
  211: 
  212:   rc = gnutls_hex_encode2(secret, &secret_hex);
  213:   if(rc < 0) {
  214:     fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
  215:             gnutls_strerror(rc));
  216:     goto out;
  217:   }
  218: 
  219:   fprintf(keylog_file, "%s %s %s\n", label, crandom_hex.data, secret_hex.data);
  220:   fflush(keylog_file);
  221: 
  222:  out:
  223:   gnutls_free(crandom_hex.data);
  224:   gnutls_free(secret_hex.data);
  225:   return rc;
  226: }
  227: #endif
  228: 
  229: static int init_ngh3_conn(struct quicsocket *qs);
  230: 
  231: static int write_client_handshake(struct quicsocket *qs,
  232:                                   ngtcp2_crypto_level level,
  233:                                   const uint8_t *data, size_t len)
  234: {
  235:   struct quic_handshake *crypto_data;
  236:   int rv;
  237: 
  238:   crypto_data = &qs->crypto_data[level];
  239:   if(crypto_data->buf == NULL) {
  240:     crypto_data->buf = malloc(4096);
  241:     if(!crypto_data->buf)
  242:       return 0;
  243:     crypto_data->alloclen = 4096;
  244:   }
  245: 
  246:   /* TODO Just pretend that handshake does not grow more than 4KiB for
  247:      now */
  248:   assert(crypto_data->len + len <= crypto_data->alloclen);
  249: 
  250:   memcpy(&crypto_data->buf[crypto_data->len], data, len);
  251:   crypto_data->len += len;
  252: 
  253:   rv = ngtcp2_conn_submit_crypto_data(
  254:     qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
  255:     len);
  256:   if(rv) {
  257:     H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
  258:   }
  259:   assert(0 == rv);
  260: 
  261:   return 1;
  262: }
  263: 
  264: #ifdef USE_OPENSSL
  265: static int quic_set_encryption_secrets(SSL *ssl,
  266:                                        OSSL_ENCRYPTION_LEVEL ossl_level,
  267:                                        const uint8_t *rx_secret,
  268:                                        const uint8_t *tx_secret,
  269:                                        size_t secretlen)
  270: {
  271:   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
  272:   int level = quic_from_ossl_level(ossl_level);
  273: 
  274:   if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
  275:      ngtcp2_crypto_derive_and_install_rx_key(
  276:          qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
  277:     return 0;
  278: 
  279:   if(ngtcp2_crypto_derive_and_install_tx_key(
  280:          qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
  281:     return 0;
  282: 
  283:   if(level == NGTCP2_CRYPTO_LEVEL_APP) {
  284:     if(init_ngh3_conn(qs) != CURLE_OK)
  285:       return 0;
  286:   }
  287: 
  288:   return 1;
  289: }
  290: 
  291: static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
  292:                                    const uint8_t *data, size_t len)
  293: {
  294:   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
  295:   ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
  296: 
  297:   return write_client_handshake(qs, level, data, len);
  298: }
  299: 
  300: static int quic_flush_flight(SSL *ssl)
  301: {
  302:   (void)ssl;
  303:   return 1;
  304: }
  305: 
  306: static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level,
  307:                            uint8_t alert)
  308: {
  309:   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
  310:   (void)level;
  311: 
  312:   qs->tls_alert = alert;
  313:   return 1;
  314: }
  315: 
  316: static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets,
  317:                                       quic_add_handshake_data,
  318:                                       quic_flush_flight, quic_send_alert};
  319: 
  320: static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
  321: {
  322:   SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
  323:   const char *keylog_filename;
  324: 
  325:   SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
  326:   SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
  327: 
  328:   SSL_CTX_set_default_verify_paths(ssl_ctx);
  329: 
  330:   if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) {
  331:     char error_buffer[256];
  332:     ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
  333:     failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
  334:     return NULL;
  335:   }
  336: 
  337:   if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
  338:     failf(data, "SSL_CTX_set1_groups_list failed");
  339:     return NULL;
  340:   }
  341: 
  342:   SSL_CTX_set_quic_method(ssl_ctx, &quic_method);
  343: 
  344:   keylog_filename = getenv("SSLKEYLOGFILE");
  345:   if(keylog_filename) {
  346:     keylog_file = fopen(keylog_filename, "wb");
  347:     if(keylog_file) {
  348:       SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
  349:     }
  350:   }
  351: 
  352:   return ssl_ctx;
  353: }
  354: 
  355: /** SSL callbacks ***/
  356: 
  357: static int quic_init_ssl(struct quicsocket *qs)
  358: {
  359:   const uint8_t *alpn = NULL;
  360:   size_t alpnlen = 0;
  361:   /* this will need some attention when HTTPS proxy over QUIC get fixed */
  362:   const char * const hostname = qs->conn->host.name;
  363: 
  364:   if(qs->ssl)
  365:     SSL_free(qs->ssl);
  366: 
  367:   qs->ssl = SSL_new(qs->sslctx);
  368: 
  369:   SSL_set_app_data(qs->ssl, qs);
  370:   SSL_set_connect_state(qs->ssl);
  371: 
  372:   switch(qs->version) {
  373: #ifdef NGTCP2_PROTO_VER
  374:   case NGTCP2_PROTO_VER:
  375:     alpn = (const uint8_t *)NGTCP2_ALPN_H3;
  376:     alpnlen = sizeof(NGTCP2_ALPN_H3) - 1;
  377:     break;
  378: #endif
  379:   }
  380:   if(alpn)
  381:     SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
  382: 
  383:   /* set SNI */
  384:   SSL_set_tlsext_host_name(qs->ssl, hostname);
  385:   return 0;
  386: }
  387: #elif defined(USE_GNUTLS)
  388: static int secret_func(gnutls_session_t ssl,
  389:                        gnutls_record_encryption_level_t gtls_level,
  390:                        const void *rx_secret,
  391:                        const void *tx_secret, size_t secretlen)
  392: {
  393:   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
  394:   int level = quic_from_gtls_level(gtls_level);
  395: 
  396:   if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
  397:      ngtcp2_crypto_derive_and_install_rx_key(
  398:          qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
  399:     return 0;
  400: 
  401:   if(ngtcp2_crypto_derive_and_install_tx_key(
  402:          qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
  403:     return 0;
  404: 
  405:   if(level == NGTCP2_CRYPTO_LEVEL_APP) {
  406:     if(init_ngh3_conn(qs) != CURLE_OK)
  407:       return -1;
  408:   }
  409: 
  410:   return 0;
  411: }
  412: 
  413: static int read_func(gnutls_session_t ssl,
  414:                      gnutls_record_encryption_level_t gtls_level,
  415:                      gnutls_handshake_description_t htype, const void *data,
  416:                      size_t len)
  417: {
  418:   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
  419:   ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level);
  420:   int rv;
  421: 
  422:   if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
  423:     return 0;
  424: 
  425:   rv = write_client_handshake(qs, level, data, len);
  426:   if(rv == 0)
  427:     return -1;
  428: 
  429:   return 0;
  430: }
  431: 
  432: static int alert_read_func(gnutls_session_t ssl,
  433:                            gnutls_record_encryption_level_t gtls_level,
  434:                            gnutls_alert_level_t alert_level,
  435:                            gnutls_alert_description_t alert_desc)
  436: {
  437:   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
  438:   (void)gtls_level;
  439:   (void)alert_level;
  440: 
  441:   qs->tls_alert = alert_desc;
  442:   return 1;
  443: }
  444: 
  445: static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data,
  446:                         size_t data_size)
  447: {
  448:   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
  449:   ngtcp2_transport_params params;
  450: 
  451:   if(ngtcp2_decode_transport_params(
  452:          &params, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
  453:          data, data_size) != 0)
  454:     return -1;
  455: 
  456:   if(ngtcp2_conn_set_remote_transport_params(qs->qconn, &params) != 0)
  457:     return -1;
  458: 
  459:   return 0;
  460: }
  461: 
  462: static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
  463: {
  464:   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
  465:   uint8_t paramsbuf[64];
  466:   ngtcp2_transport_params params;
  467:   ssize_t nwrite;
  468:   int rc;
  469: 
  470:   ngtcp2_conn_get_local_transport_params(qs->qconn, &params);
  471:   nwrite = ngtcp2_encode_transport_params(
  472:     paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
  473:     &params);
  474:   if(nwrite < 0) {
  475:     fprintf(stderr, "ngtcp2_encode_transport_params: %s\n",
  476:           ngtcp2_strerror((int)nwrite));
  477:     return -1;
  478:   }
  479: 
  480:   rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite);
  481:   if(rc < 0)
  482:     return rc;
  483: 
  484:   return (int)nwrite;
  485: }
  486: 
  487: static int quic_init_ssl(struct quicsocket *qs)
  488: {
  489:   gnutls_datum_t alpn = {NULL, 0};
  490:   /* this will need some attention when HTTPS proxy over QUIC get fixed */
  491:   const char * const hostname = qs->conn->host.name;
  492:   const char *keylog_filename;
  493:   int rc;
  494: 
  495:   if(qs->ssl)
  496:     gnutls_deinit(qs->ssl);
  497: 
  498:   gnutls_init(&qs->ssl, GNUTLS_CLIENT);
  499:   gnutls_session_set_ptr(qs->ssl, qs);
  500: 
  501:   rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
  502:   if(rc < 0) {
  503:     fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
  504:             gnutls_strerror(rc));
  505:     return 1;
  506:   }
  507: 
  508:   gnutls_handshake_set_secret_function(qs->ssl, secret_func);
  509:   gnutls_handshake_set_read_function(qs->ssl, read_func);
  510:   gnutls_alert_set_read_function(qs->ssl, alert_read_func);
  511: 
  512:   rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
  513:                                    0xffa5, GNUTLS_EXT_TLS,
  514:                                    tp_recv_func, tp_send_func,
  515:                                    NULL, NULL, NULL,
  516:                                    GNUTLS_EXT_FLAG_TLS |
  517:                                    GNUTLS_EXT_FLAG_CLIENT_HELLO |
  518:                                    GNUTLS_EXT_FLAG_EE);
  519:   if(rc < 0) {
  520:     fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
  521:             gnutls_strerror(rc));
  522:     return 1;
  523:   }
  524: 
  525:   keylog_filename = getenv("SSLKEYLOGFILE");
  526:   if(keylog_filename) {
  527:     keylog_file = fopen(keylog_filename, "wb");
  528:     if(keylog_file) {
  529:       gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
  530:     }
  531:   }
  532: 
  533:   if(qs->cred)
  534:     gnutls_certificate_free_credentials(qs->cred);
  535: 
  536:   rc = gnutls_certificate_allocate_credentials(&qs->cred);
  537:   if(rc < 0) {
  538:     fprintf(stderr, "gnutls_certificate_allocate_credentials failed: %s\n",
  539:             gnutls_strerror(rc));
  540:     return 1;
  541:   }
  542: 
  543:   rc = gnutls_certificate_set_x509_system_trust(qs->cred);
  544:   if(rc < 0) {
  545:     fprintf(stderr, "gnutls_certificate_set_x509_system_trust failed: %s\n",
  546:             gnutls_strerror(rc));
  547:     return 1;
  548:   }
  549: 
  550:   rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
  551:   if(rc < 0) {
  552:     fprintf(stderr, "gnutls_credentials_set failed: %s\n",
  553:             gnutls_strerror(rc));
  554:     return 1;
  555:   }
  556: 
  557:   switch(qs->version) {
  558: #ifdef NGTCP2_PROTO_VER
  559:   case NGTCP2_PROTO_VER:
  560:     /* strip the first byte from NGTCP2_ALPN_H3 */
  561:     alpn.data = (unsigned char *)NGTCP2_ALPN_H3 + 1;
  562:     alpn.size = sizeof(NGTCP2_ALPN_H3) - 2;
  563:     break;
  564: #endif
  565:   }
  566:   if(alpn.data)
  567:     gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
  568: 
  569:   /* set SNI */
  570:   gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
  571:   return 0;
  572: }
  573: #endif
  574: 
  575: static int cb_initial(ngtcp2_conn *quic, void *user_data)
  576: {
  577:   struct quicsocket *qs = (struct quicsocket *)user_data;
  578: 
  579:   if(ngtcp2_crypto_read_write_crypto_data(
  580:        quic, qs->ssl, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0)
  581:     return NGTCP2_ERR_CALLBACK_FAILURE;
  582: 
  583:   return 0;
  584: }
  585: 
  586: static int
  587: cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
  588:                     uint64_t offset,
  589:                     const uint8_t *data, size_t datalen,
  590:                     void *user_data)
  591: {
  592:   struct quicsocket *qs = (struct quicsocket *)user_data;
  593:   (void)offset;
  594: 
  595:   if(ngtcp2_crypto_read_write_crypto_data(tconn, qs->ssl, crypto_level, data,
  596:                                           datalen) != 0)
  597:     return NGTCP2_ERR_CRYPTO;
  598: 
  599:   return 0;
  600: }
  601: 
  602: static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
  603: {
  604:   struct quicsocket *qs = (struct quicsocket *)user_data;
  605:   (void)tconn;
  606:   infof(qs->conn->data, "QUIC handshake is completed\n");
  607: 
  608:   return 0;
  609: }
  610: 
  611: static void extend_stream_window(ngtcp2_conn *tconn,
  612:                                  struct HTTP *stream)
  613: {
  614:   size_t thismuch = stream->unacked_window;
  615:   ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch);
  616:   ngtcp2_conn_extend_max_offset(tconn, thismuch);
  617:   stream->unacked_window = 0;
  618: }
  619: 
  620: 
  621: static int cb_recv_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
  622:                                int fin, uint64_t offset,
  623:                                const uint8_t *buf, size_t buflen,
  624:                                void *user_data, void *stream_user_data)
  625: {
  626:   struct quicsocket *qs = (struct quicsocket *)user_data;
  627:   ssize_t nconsumed;
  628:   (void)offset;
  629:   (void)stream_user_data;
  630: 
  631:   nconsumed =
  632:     nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
  633:   if(nconsumed < 0) {
  634:     failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s\n",
  635:           nghttp3_strerror((int)nconsumed));
  636:     return NGTCP2_ERR_CALLBACK_FAILURE;
  637:   }
  638: 
  639:   /* number of bytes inside buflen which consists of framing overhead
  640:    * including QPACK HEADERS. In other words, it does not consume payload of
  641:    * DATA frame. */
  642:   ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
  643:   ngtcp2_conn_extend_max_offset(tconn, nconsumed);
  644: 
  645:   return 0;
  646: }
  647: 
  648: static int
  649: cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
  650:                             uint64_t offset, size_t datalen, void *user_data,
  651:                             void *stream_user_data)
  652: {
  653:   struct quicsocket *qs = (struct quicsocket *)user_data;
  654:   int rv;
  655:   (void)stream_id;
  656:   (void)tconn;
  657:   (void)offset;
  658:   (void)datalen;
  659:   (void)stream_user_data;
  660: 
  661:   rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
  662:   if(rv != 0) {
  663:     failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s\n",
  664:           nghttp3_strerror(rv));
  665:     return NGTCP2_ERR_CALLBACK_FAILURE;
  666:   }
  667: 
  668:   return 0;
  669: }
  670: 
  671: static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
  672:                            uint64_t app_error_code,
  673:                            void *user_data, void *stream_user_data)
  674: {
  675:   struct quicsocket *qs = (struct quicsocket *)user_data;
  676:   int rv;
  677:   (void)tconn;
  678:   (void)stream_user_data;
  679:   /* stream is closed... */
  680: 
  681:   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
  682:                                  app_error_code);
  683:   if(rv != 0) {
  684:     failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s\n",
  685:           nghttp3_strerror(rv));
  686:     return NGTCP2_ERR_CALLBACK_FAILURE;
  687:   }
  688: 
  689:   return 0;
  690: }
  691: 
  692: static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
  693:                            uint64_t final_size, uint64_t app_error_code,
  694:                            void *user_data, void *stream_user_data)
  695: {
  696:   struct quicsocket *qs = (struct quicsocket *)user_data;
  697:   int rv;
  698:   (void)tconn;
  699:   (void)final_size;
  700:   (void)app_error_code;
  701:   (void)stream_user_data;
  702: 
  703:   rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
  704:   if(rv != 0) {
  705:     failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s\n",
  706:           nghttp3_strerror(rv));
  707:     return NGTCP2_ERR_CALLBACK_FAILURE;
  708:   }
  709: 
  710:   return 0;
  711: }
  712: 
  713: static int cb_recv_retry(ngtcp2_conn *tconn, const ngtcp2_pkt_hd *hd,
  714:                          const ngtcp2_pkt_retry *retry, void *user_data)
  715: {
  716:   /* Re-generate handshake secrets here because connection ID might change. */
  717:   struct quicsocket *qs = (struct quicsocket *)user_data;
  718:   (void)tconn;
  719:   (void)hd;
  720:   (void)retry;
  721: 
  722:   setup_initial_crypto_context(qs);
  723: 
  724:   return 0;
  725: }
  726: 
  727: static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
  728:                                             uint64_t max_streams,
  729:                                             void *user_data)
  730: {
  731:   (void)tconn;
  732:   (void)max_streams;
  733:   (void)user_data;
  734: 
  735:   return 0;
  736: }
  737: 
  738: static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
  739:                                      uint64_t max_data, void *user_data,
  740:                                      void *stream_user_data)
  741: {
  742:   struct quicsocket *qs = (struct quicsocket *)user_data;
  743:   int rv;
  744:   (void)tconn;
  745:   (void)max_data;
  746:   (void)stream_user_data;
  747: 
  748:   rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
  749:   if(rv != 0) {
  750:     failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s\n",
  751:           nghttp3_strerror(rv));
  752:     return NGTCP2_ERR_CALLBACK_FAILURE;
  753:   }
  754: 
  755:   return 0;
  756: }
  757: 
  758: static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
  759:                                     uint8_t *token, size_t cidlen,
  760:                                     void *user_data)
  761: {
  762:   struct quicsocket *qs = (struct quicsocket *)user_data;
  763:   CURLcode result;
  764:   (void)tconn;
  765: 
  766:   result = Curl_rand(qs->conn->data, cid->data, cidlen);
  767:   if(result)
  768:     return NGTCP2_ERR_CALLBACK_FAILURE;
  769:   cid->datalen = cidlen;
  770: 
  771:   result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN);
  772:   if(result)
  773:     return NGTCP2_ERR_CALLBACK_FAILURE;
  774: 
  775:   return 0;
  776: }
  777: 
  778: static ngtcp2_conn_callbacks ng_callbacks = {
  779:   cb_initial,
  780:   NULL, /* recv_client_initial */
  781:   cb_recv_crypto_data,
  782:   cb_handshake_completed,
  783:   NULL, /* recv_version_negotiation */
  784:   ngtcp2_crypto_encrypt_cb,
  785:   ngtcp2_crypto_decrypt_cb,
  786:   ngtcp2_crypto_hp_mask_cb,
  787:   cb_recv_stream_data,
  788:   NULL, /* acked_crypto_offset */
  789:   cb_acked_stream_data_offset,
  790:   NULL, /* stream_open */
  791:   cb_stream_close,
  792:   NULL, /* recv_stateless_reset */
  793:   cb_recv_retry,
  794:   cb_extend_max_local_streams_bidi,
  795:   NULL, /* extend_max_local_streams_uni */
  796:   NULL, /* rand  */
  797:   cb_get_new_connection_id,
  798:   NULL, /* remove_connection_id */
  799:   ngtcp2_crypto_update_key_cb, /* update_key */
  800:   NULL, /* path_validation */
  801:   NULL, /* select_preferred_addr */
  802:   cb_stream_reset,
  803:   NULL, /* extend_max_remote_streams_bidi */
  804:   NULL, /* extend_max_remote_streams_uni */
  805:   cb_extend_max_stream_data,
  806:   NULL, /* dcid_status */
  807:   NULL  /* handshake_confirmed */
  808: };
  809: 
  810: /*
  811:  * Might be called twice for happy eyeballs.
  812:  */
  813: CURLcode Curl_quic_connect(struct connectdata *conn,
  814:                            curl_socket_t sockfd,
  815:                            int sockindex,
  816:                            const struct sockaddr *addr,
  817:                            socklen_t addrlen)
  818: {
  819:   int rc;
  820:   int rv;
  821:   CURLcode result;
  822:   ngtcp2_path path; /* TODO: this must be initialized properly */
  823:   struct Curl_easy *data = conn->data;
  824:   struct quicsocket *qs = &conn->hequic[sockindex];
  825:   char ipbuf[40];
  826:   long port;
  827: #ifdef USE_OPENSSL
  828:   uint8_t paramsbuf[64];
  829:   ngtcp2_transport_params params;
  830:   ssize_t nwrite;
  831: #endif
  832: 
  833:   qs->conn = conn;
  834: 
  835:   /* extract the used address as a string */
  836:   if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
  837:     char buffer[STRERROR_LEN];
  838:     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
  839:           SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
  840:     return CURLE_BAD_FUNCTION_ARGUMENT;
  841:   }
  842: 
  843:   infof(data, "Connect socket %d over QUIC to %s:%ld\n",
  844:         sockfd, ipbuf, port);
  845: 
  846:   qs->version = NGTCP2_PROTO_VER;
  847: #ifdef USE_OPENSSL
  848:   qs->sslctx = quic_ssl_ctx(data);
  849:   if(!qs->sslctx)
  850:     return CURLE_QUIC_CONNECT_ERROR;
  851: #endif
  852: 
  853:   if(quic_init_ssl(qs))
  854:     return CURLE_QUIC_CONNECT_ERROR;
  855: 
  856:   qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
  857:   result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
  858:   if(result)
  859:     return result;
  860: 
  861:   qs->scid.datalen = NGTCP2_MAX_CIDLEN;
  862:   result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN);
  863:   if(result)
  864:     return result;
  865: 
  866:   quic_settings(&qs->settings, data->set.buffer_size);
  867: 
  868:   qs->local_addrlen = sizeof(qs->local_addr);
  869:   rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
  870:                    &qs->local_addrlen);
  871:   if(rv == -1)
  872:     return CURLE_QUIC_CONNECT_ERROR;
  873: 
  874:   ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen,
  875:                    NULL);
  876:   ngtcp2_addr_init(&path.remote, (uint8_t*)addr, addrlen, NULL);
  877: 
  878: #ifdef NGTCP2_PROTO_VER
  879: #define QUICVER NGTCP2_PROTO_VER
  880: #else
  881: #error "unsupported ngtcp2 version"
  882: #endif
  883:   rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, QUICVER,
  884:                               &ng_callbacks, &qs->settings, NULL, qs);
  885:   if(rc)
  886:     return CURLE_QUIC_CONNECT_ERROR;
  887: 
  888: #ifdef USE_OPENSSL
  889:   ngtcp2_conn_get_local_transport_params(qs->qconn, &params);
  890:   nwrite = ngtcp2_encode_transport_params(
  891:     paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
  892:     &params);
  893:   if(nwrite < 0) {
  894:     failf(data, "ngtcp2_encode_transport_params: %s\n",
  895:           ngtcp2_strerror((int)nwrite));
  896:     return CURLE_QUIC_CONNECT_ERROR;
  897:   }
  898: 
  899:   if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite))
  900:     return CURLE_QUIC_CONNECT_ERROR;
  901: #endif
  902: 
  903:   rc = setup_initial_crypto_context(qs);
  904:   if(rc)
  905:     return CURLE_QUIC_CONNECT_ERROR;
  906: 
  907:   return CURLE_OK;
  908: }
  909: 
  910: /*
  911:  * Store ngtp2 version info in this buffer, Prefix with a space.  Return total
  912:  * length written.
  913:  */
  914: int Curl_quic_ver(char *p, size_t len)
  915: {
  916:   ngtcp2_info *ng2 = ngtcp2_version(0);
  917:   nghttp3_info *ht3 = nghttp3_version(0);
  918:   return msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
  919:                    ng2->version_str, ht3->version_str);
  920: }
  921: 
  922: static int ng_getsock(struct connectdata *conn, curl_socket_t *socks)
  923: {
  924:   struct SingleRequest *k = &conn->data->req;
  925:   int bitmap = GETSOCK_BLANK;
  926: 
  927:   socks[0] = conn->sock[FIRSTSOCKET];
  928: 
  929:   /* in a HTTP/2 connection we can basically always get a frame so we should
  930:      always be ready for one */
  931:   bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
  932: 
  933:   /* we're still uploading or the HTTP/2 layer wants to send data */
  934:   if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND)
  935:     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
  936: 
  937:   return bitmap;
  938: }
  939: 
  940: static int ng_perform_getsock(const struct connectdata *conn,
  941:                               curl_socket_t *socks)
  942: {
  943:   return ng_getsock((struct connectdata *)conn, socks);
  944: }
  945: 
  946: static CURLcode ng_disconnect(struct connectdata *conn,
  947:                               bool dead_connection)
  948: {
  949:   int i;
  950:   struct quicsocket *qs = &conn->hequic[0];
  951:   (void)dead_connection;
  952:   if(qs->ssl)
  953: #ifdef USE_OPENSSL
  954:     SSL_free(qs->ssl);
  955: #elif defined(USE_GNUTLS)
  956:     gnutls_deinit(qs->ssl);
  957: #endif
  958: #ifdef USE_GNUTLS
  959:   if(qs->cred)
  960:     gnutls_certificate_free_credentials(qs->cred);
  961: #endif
  962:   for(i = 0; i < 3; i++)
  963:     free(qs->crypto_data[i].buf);
  964:   nghttp3_conn_del(qs->h3conn);
  965:   ngtcp2_conn_del(qs->qconn);
  966: #ifdef USE_OPENSSL
  967:   SSL_CTX_free(qs->sslctx);
  968: #endif
  969:   return CURLE_OK;
  970: }
  971: 
  972: static unsigned int ng_conncheck(struct connectdata *conn,
  973:                                  unsigned int checks_to_perform)
  974: {
  975:   (void)conn;
  976:   (void)checks_to_perform;
  977:   return CONNRESULT_NONE;
  978: }
  979: 
  980: static const struct Curl_handler Curl_handler_http3 = {
  981:   "HTTPS",                              /* scheme */
  982:   ZERO_NULL,                            /* setup_connection */
  983:   Curl_http,                            /* do_it */
  984:   Curl_http_done,                       /* done */
  985:   ZERO_NULL,                            /* do_more */
  986:   ZERO_NULL,                            /* connect_it */
  987:   ZERO_NULL,                            /* connecting */
  988:   ZERO_NULL,                            /* doing */
  989:   ng_getsock,                           /* proto_getsock */
  990:   ng_getsock,                           /* doing_getsock */
  991:   ZERO_NULL,                            /* domore_getsock */
  992:   ng_perform_getsock,                   /* perform_getsock */
  993:   ng_disconnect,                        /* disconnect */
  994:   ZERO_NULL,                            /* readwrite */
  995:   ng_conncheck,                         /* connection_check */
  996:   PORT_HTTP,                            /* defport */
  997:   CURLPROTO_HTTPS,                      /* protocol */
  998:   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
  999: };
 1000: 
 1001: static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
 1002:                               uint64_t app_error_code, void *user_data,
 1003:                               void *stream_user_data)
 1004: {
 1005:   struct Curl_easy *data = stream_user_data;
 1006:   struct HTTP *stream = data->req.protop;
 1007:   (void)conn;
 1008:   (void)stream_id;
 1009:   (void)app_error_code;
 1010:   (void)user_data;
 1011:   H3BUGF(infof(data, "cb_h3_stream_close CALLED\n"));
 1012: 
 1013:   stream->closed = TRUE;
 1014:   Curl_expire(data, 0, EXPIRE_QUIC);
 1015:   /* make sure that ngh3_stream_recv is called again to complete the transfer
 1016:      even if there are no more packets to be received from the server. */
 1017:   data->state.drain = 1;
 1018:   return 0;
 1019: }
 1020: 
 1021: /* Minimum size of the overflow buffer */
 1022: #define OVERFLOWSIZE 1024
 1023: 
 1024: /*
 1025:  * allocate_overflow() ensures that there is room for incoming data in the
 1026:  * overflow buffer, growing it to accommodate the new data if necessary. We
 1027:  * may need to use the overflow buffer because we can't precisely limit the
 1028:  * amount of HTTP/3 header data we receive using QUIC flow control mechanisms.
 1029:  */
 1030: static CURLcode allocate_overflow(struct Curl_easy *data,
 1031:                                   struct HTTP *stream,
 1032:                                   size_t length)
 1033: {
 1034:   size_t maxleft;
 1035:   size_t newsize;
 1036:   /* length can be arbitrarily large, so take care not to overflow newsize */
 1037:   maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen;
 1038:   if(length > maxleft) {
 1039:     /* The reason to have a max limit for this is to avoid the risk of a bad
 1040:        server feeding libcurl with a highly compressed list of headers that
 1041:        will cause our overflow buffer to grow too large */
 1042:     failf(data, "Rejected %zu bytes of overflow data (max is %d)!",
 1043:           stream->overflow_buflen + length, CURL_MAX_READ_SIZE);
 1044:     return CURLE_OUT_OF_MEMORY;
 1045:   }
 1046:   newsize = stream->overflow_buflen + length;
 1047:   if(newsize > stream->overflow_bufsize) {
 1048:     /* We enlarge the overflow buffer as it is too small */
 1049:     char *newbuff;
 1050:     newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2);
 1051:     newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE);
 1052:     newbuff = realloc(stream->overflow_buf, newsize);
 1053:     if(!newbuff) {
 1054:       failf(data, "Failed to alloc memory for overflow buffer!");
 1055:       return CURLE_OUT_OF_MEMORY;
 1056:     }
 1057:     stream->overflow_buf = newbuff;
 1058:     stream->overflow_bufsize = newsize;
 1059:     infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize);
 1060:   }
 1061:   return CURLE_OK;
 1062: }
 1063: 
 1064: /*
 1065:  * write_data() copies data to the stream's receive buffer. If not enough
 1066:  * space is available in the receive buffer, it copies the rest to the
 1067:  * stream's overflow buffer.
 1068:  */
 1069: static CURLcode write_data(struct Curl_easy *data,
 1070:                            struct HTTP *stream,
 1071:                            const void *mem, size_t memlen)
 1072: {
 1073:   CURLcode result = CURLE_OK;
 1074:   const char *buf = mem;
 1075:   size_t ncopy = memlen;
 1076:   /* copy as much as possible to the receive buffer */
 1077:   if(stream->len) {
 1078:     size_t len = CURLMIN(ncopy, stream->len);
 1079: #if 0 /* extra debugging of incoming h3 data */
 1080:     fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n",
 1081:             len, stream->mem, stream->memlen);
 1082: #endif
 1083:     memcpy(stream->mem, buf, len);
 1084:     stream->len -= len;
 1085:     stream->memlen += len;
 1086:     stream->mem += len;
 1087:     buf += len;
 1088:     ncopy -= len;
 1089:   }
 1090:   /* copy the rest to the overflow buffer */
 1091:   if(ncopy) {
 1092:     result = allocate_overflow(data, stream, ncopy);
 1093:     if(result) {
 1094:       return result;
 1095:     }
 1096: #if 0 /* extra debugging of incoming h3 data */
 1097:     fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n",
 1098:             ncopy, stream->overflow_buf, stream->overflow_buflen);
 1099: #endif
 1100:     memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy);
 1101:     stream->overflow_buflen += ncopy;
 1102:   }
 1103: #if 0 /* extra debugging of incoming h3 data */
 1104:   {
 1105:     size_t i;
 1106:     for(i = 0; i < memlen; i++) {
 1107:       fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]);
 1108:     }
 1109:   }
 1110: #endif
 1111:   return result;
 1112: }
 1113: 
 1114: static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
 1115:                            const uint8_t *buf, size_t buflen,
 1116:                            void *user_data, void *stream_user_data)
 1117: {
 1118:   struct Curl_easy *data = stream_user_data;
 1119:   struct HTTP *stream = data->req.protop;
 1120:   CURLcode result = CURLE_OK;
 1121:   (void)conn;
 1122: 
 1123:   result = write_data(data, stream, buf, buflen);
 1124:   if(result) {
 1125:     return -1;
 1126:   }
 1127:   stream->unacked_window += buflen;
 1128:   (void)stream_id;
 1129:   (void)user_data;
 1130:   return 0;
 1131: }
 1132: 
 1133: static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
 1134:                                   size_t consumed, void *user_data,
 1135:                                   void *stream_user_data)
 1136: {
 1137:   struct quicsocket *qs = user_data;
 1138:   (void)conn;
 1139:   (void)stream_user_data;
 1140:   (void)stream_id;
 1141: 
 1142:   ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed);
 1143:   ngtcp2_conn_extend_max_offset(qs->qconn, consumed);
 1144:   return 0;
 1145: }
 1146: 
 1147: /* Decode HTTP status code.  Returns -1 if no valid status code was
 1148:    decoded. (duplicate from http2.c) */
 1149: static int decode_status_code(const uint8_t *value, size_t len)
 1150: {
 1151:   int i;
 1152:   int res;
 1153: 
 1154:   if(len != 3) {
 1155:     return -1;
 1156:   }
 1157: 
 1158:   res = 0;
 1159: 
 1160:   for(i = 0; i < 3; ++i) {
 1161:     char c = value[i];
 1162: 
 1163:     if(c < '0' || c > '9') {
 1164:       return -1;
 1165:     }
 1166: 
 1167:     res *= 10;
 1168:     res += c - '0';
 1169:   }
 1170: 
 1171:   return res;
 1172: }
 1173: 
 1174: static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
 1175:                              void *user_data, void *stream_user_data)
 1176: {
 1177:   struct Curl_easy *data = stream_user_data;
 1178:   struct HTTP *stream = data->req.protop;
 1179:   CURLcode result = CURLE_OK;
 1180:   (void)conn;
 1181:   (void)stream_id;
 1182:   (void)user_data;
 1183: 
 1184:   /* add a CRLF only if we've received some headers */
 1185:   if(stream->firstheader) {
 1186:     result = write_data(data, stream, "\r\n", 2);
 1187:     if(result) {
 1188:       return -1;
 1189:     }
 1190:   }
 1191:   return 0;
 1192: }
 1193: 
 1194: static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
 1195:                              int32_t token, nghttp3_rcbuf *name,
 1196:                              nghttp3_rcbuf *value, uint8_t flags,
 1197:                              void *user_data, void *stream_user_data)
 1198: {
 1199:   nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
 1200:   nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
 1201:   struct Curl_easy *data = stream_user_data;
 1202:   struct HTTP *stream = data->req.protop;
 1203:   CURLcode result = CURLE_OK;
 1204:   (void)conn;
 1205:   (void)stream_id;
 1206:   (void)token;
 1207:   (void)flags;
 1208:   (void)user_data;
 1209: 
 1210:   if(h3name.len == sizeof(":status") - 1 &&
 1211:      !memcmp(":status", h3name.base, h3name.len)) {
 1212:     char line[14]; /* status line is always 13 characters long */
 1213:     size_t ncopy;
 1214:     int status = decode_status_code(h3val.base, h3val.len);
 1215:     DEBUGASSERT(status != -1);
 1216:     ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
 1217:     result = write_data(data, stream, line, ncopy);
 1218:     if(result) {
 1219:       return -1;
 1220:     }
 1221:   }
 1222:   else {
 1223:     /* store as a HTTP1-style header */
 1224:     result = write_data(data, stream, h3name.base, h3name.len);
 1225:     if(result) {
 1226:       return -1;
 1227:     }
 1228:     result = write_data(data, stream, ": ", 2);
 1229:     if(result) {
 1230:       return -1;
 1231:     }
 1232:     result = write_data(data, stream, h3val.base, h3val.len);
 1233:     if(result) {
 1234:       return -1;
 1235:     }
 1236:     result = write_data(data, stream, "\r\n", 2);
 1237:     if(result) {
 1238:       return -1;
 1239:     }
 1240:   }
 1241: 
 1242:   stream->firstheader = TRUE;
 1243:   return 0;
 1244: }
 1245: 
 1246: static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
 1247:                                    uint64_t app_error_code,
 1248:                                    void *user_data,
 1249:                                    void *stream_user_data)
 1250: {
 1251:   (void)conn;
 1252:   (void)stream_id;
 1253:   (void)app_error_code;
 1254:   (void)user_data;
 1255:   (void)stream_user_data;
 1256:   return 0;
 1257: }
 1258: 
 1259: static nghttp3_conn_callbacks ngh3_callbacks = {
 1260:   cb_h3_acked_stream_data, /* acked_stream_data */
 1261:   cb_h3_stream_close,
 1262:   cb_h3_recv_data,
 1263:   cb_h3_deferred_consume,
 1264:   NULL, /* begin_headers */
 1265:   cb_h3_recv_header,
 1266:   cb_h3_end_headers,
 1267:   NULL, /* begin_trailers */
 1268:   cb_h3_recv_header,
 1269:   NULL, /* end_trailers */
 1270:   NULL, /* http_begin_push_promise */
 1271:   NULL, /* http_recv_push_promise */
 1272:   NULL, /* http_end_push_promise */
 1273:   NULL, /* http_cancel_push */
 1274:   cb_h3_send_stop_sending,
 1275:   NULL, /* push_stream */
 1276:   NULL, /* end_stream */
 1277: };
 1278: 
 1279: static int init_ngh3_conn(struct quicsocket *qs)
 1280: {
 1281:   CURLcode result;
 1282:   int rc;
 1283:   int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
 1284: 
 1285:   if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
 1286:     failf(qs->conn->data, "too few available QUIC streams");
 1287:     return CURLE_QUIC_CONNECT_ERROR;
 1288:   }
 1289: 
 1290:   nghttp3_conn_settings_default(&qs->h3settings);
 1291: 
 1292:   rc = nghttp3_conn_client_new(&qs->h3conn,
 1293:                                &ngh3_callbacks,
 1294:                                &qs->h3settings,
 1295:                                nghttp3_mem_default(),
 1296:                                qs);
 1297:   if(rc) {
 1298:     result = CURLE_OUT_OF_MEMORY;
 1299:     goto fail;
 1300:   }
 1301: 
 1302:   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL);
 1303:   if(rc) {
 1304:     result = CURLE_QUIC_CONNECT_ERROR;
 1305:     goto fail;
 1306:   }
 1307: 
 1308:   rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id);
 1309:   if(rc) {
 1310:     result = CURLE_QUIC_CONNECT_ERROR;
 1311:     goto fail;
 1312:   }
 1313: 
 1314:   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL);
 1315:   if(rc) {
 1316:     result = CURLE_QUIC_CONNECT_ERROR;
 1317:     goto fail;
 1318:   }
 1319: 
 1320:   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL);
 1321:   if(rc) {
 1322:     result = CURLE_QUIC_CONNECT_ERROR;
 1323:     goto fail;
 1324:   }
 1325: 
 1326:   rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id,
 1327:                                        qpack_dec_stream_id);
 1328:   if(rc) {
 1329:     result = CURLE_QUIC_CONNECT_ERROR;
 1330:     goto fail;
 1331:   }
 1332: 
 1333:   return CURLE_OK;
 1334:   fail:
 1335: 
 1336:   return result;
 1337: }
 1338: 
 1339: static Curl_recv ngh3_stream_recv;
 1340: static Curl_send ngh3_stream_send;
 1341: 
 1342: static size_t drain_overflow_buffer(struct HTTP *stream)
 1343: {
 1344:   size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len);
 1345:   if(ncopy > 0) {
 1346:     memcpy(stream->mem, stream->overflow_buf, ncopy);
 1347:     stream->len -= ncopy;
 1348:     stream->mem += ncopy;
 1349:     stream->memlen += ncopy;
 1350:     stream->overflow_buflen -= ncopy;
 1351:     memmove(stream->overflow_buf, stream->overflow_buf + ncopy,
 1352:             stream->overflow_buflen);
 1353:   }
 1354:   return ncopy;
 1355: }
 1356: 
 1357: /* incoming data frames on the h3 stream */
 1358: static ssize_t ngh3_stream_recv(struct connectdata *conn,
 1359:                                 int sockindex,
 1360:                                 char *buf,
 1361:                                 size_t buffersize,
 1362:                                 CURLcode *curlcode)
 1363: {
 1364:   curl_socket_t sockfd = conn->sock[sockindex];
 1365:   struct HTTP *stream = conn->data->req.protop;
 1366:   struct quicsocket *qs = conn->quic;
 1367: 
 1368:   if(!stream->memlen) {
 1369:     /* remember where to store incoming data for this stream and how big the
 1370:        buffer is */
 1371:     stream->mem = buf;
 1372:     stream->len = buffersize;
 1373:   }
 1374:   /* else, there's data in the buffer already */
 1375: 
 1376:   /* if there's data in the overflow buffer from a previous call, copy as much
 1377:      as possible to the receive buffer before receiving more */
 1378:   drain_overflow_buffer(stream);
 1379: 
 1380:   if(ng_process_ingress(conn, sockfd, qs)) {
 1381:     *curlcode = CURLE_RECV_ERROR;
 1382:     return -1;
 1383:   }
 1384:   if(ng_flush_egress(conn, sockfd, qs)) {
 1385:     *curlcode = CURLE_SEND_ERROR;
 1386:     return -1;
 1387:   }
 1388: 
 1389:   if(stream->memlen) {
 1390:     ssize_t memlen = stream->memlen;
 1391:     /* data arrived */
 1392:     *curlcode = CURLE_OK;
 1393:     /* reset to allow more data to come */
 1394:     stream->memlen = 0;
 1395:     stream->mem = buf;
 1396:     stream->len = buffersize;
 1397:     /* extend the stream window with the data we're consuming and send out
 1398:        any additional packets to tell the server that we can receive more */
 1399:     extend_stream_window(qs->qconn, stream);
 1400:     if(ng_flush_egress(conn, sockfd, qs)) {
 1401:       *curlcode = CURLE_SEND_ERROR;
 1402:       return -1;
 1403:     }
 1404:     return memlen;
 1405:   }
 1406: 
 1407:   if(stream->closed) {
 1408:     *curlcode = CURLE_OK;
 1409:     return 0;
 1410:   }
 1411: 
 1412:   infof(conn->data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
 1413:   *curlcode = CURLE_AGAIN;
 1414:   return -1;
 1415: }
 1416: 
 1417: /* this amount of data has now been acked on this stream */
 1418: static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
 1419:                                    size_t datalen, void *user_data,
 1420:                                    void *stream_user_data)
 1421: {
 1422:   struct Curl_easy *data = stream_user_data;
 1423:   struct HTTP *stream = data->req.protop;
 1424:   (void)conn;
 1425:   (void)stream_id;
 1426:   (void)user_data;
 1427: 
 1428:   if(!data->set.postfields) {
 1429:     stream->h3out->used -= datalen;
 1430:     H3BUGF(infof(data,
 1431:                  "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n",
 1432:                  datalen, stream->h3out->used));
 1433:     DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
 1434:   }
 1435:   return 0;
 1436: }
 1437: 
 1438: static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
 1439:                                   nghttp3_vec *vec, size_t veccnt,
 1440:                                   uint32_t *pflags, void *user_data,
 1441:                                   void *stream_user_data)
 1442: {
 1443:   struct Curl_easy *data = stream_user_data;
 1444:   size_t nread;
 1445:   struct HTTP *stream = data->req.protop;
 1446:   (void)conn;
 1447:   (void)stream_id;
 1448:   (void)user_data;
 1449:   (void)veccnt;
 1450: 
 1451:   if(data->set.postfields) {
 1452:     vec[0].base = data->set.postfields;
 1453:     vec[0].len = data->state.infilesize;
 1454:     *pflags = NGHTTP3_DATA_FLAG_EOF;
 1455:     return 1;
 1456:   }
 1457: 
 1458:   nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
 1459:   if(nread > 0) {
 1460:     /* nghttp3 wants us to hold on to the data until it tells us it is okay to
 1461:        delete it. Append the data at the end of the h3out buffer. Since we can
 1462:        only return consecutive data, copy the amount that fits and the next
 1463:        part comes in next invoke. */
 1464:     struct h3out *out = stream->h3out;
 1465:     if(nread + out->windex > H3_SEND_SIZE)
 1466:       nread = H3_SEND_SIZE - out->windex;
 1467: 
 1468:     memcpy(&out->buf[out->windex], stream->upload_mem, nread);
 1469:     out->windex += nread;
 1470:     out->used += nread;
 1471: 
 1472:     /* that's the chunk we return to nghttp3 */
 1473:     vec[0].base = &out->buf[out->windex];
 1474:     vec[0].len = nread;
 1475: 
 1476:     if(out->windex == H3_SEND_SIZE)
 1477:       out->windex = 0; /* wrap */
 1478:     stream->upload_mem += nread;
 1479:     stream->upload_len -= nread;
 1480:     if(data->state.infilesize != -1) {
 1481:       stream->upload_left -= nread;
 1482:       if(!stream->upload_left)
 1483:         *pflags = NGHTTP3_DATA_FLAG_EOF;
 1484:     }
 1485:     H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)\n",
 1486:                  nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
 1487:                  out->used));
 1488:   }
 1489:   if(stream->upload_done && !stream->upload_len &&
 1490:      (stream->upload_left <= 0)) {
 1491:     H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n"));
 1492:     *pflags = NGHTTP3_DATA_FLAG_EOF;
 1493:     return 0;
 1494:   }
 1495:   else if(!nread) {
 1496:     return NGHTTP3_ERR_WOULDBLOCK;
 1497:   }
 1498:   return 1;
 1499: }
 1500: 
 1501: /* Index where :authority header field will appear in request header
 1502:    field list. */
 1503: #define AUTHORITY_DST_IDX 3
 1504: 
 1505: static CURLcode http_request(struct connectdata *conn, const void *mem,
 1506:                              size_t len)
 1507: {
 1508:   struct HTTP *stream = conn->data->req.protop;
 1509:   size_t nheader;
 1510:   size_t i;
 1511:   size_t authority_idx;
 1512:   char *hdbuf = (char *)mem;
 1513:   char *end, *line_end;
 1514:   struct quicsocket *qs = conn->quic;
 1515:   CURLcode result = CURLE_OK;
 1516:   struct Curl_easy *data = conn->data;
 1517:   nghttp3_nv *nva = NULL;
 1518:   int64_t stream3_id;
 1519:   int rc;
 1520:   struct h3out *h3out = NULL;
 1521: 
 1522:   rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
 1523:   if(rc) {
 1524:     failf(conn->data, "can get bidi streams");
 1525:     result = CURLE_SEND_ERROR;
 1526:     goto fail;
 1527:   }
 1528: 
 1529:   stream->stream3_id = stream3_id;
 1530:   stream->h3req = TRUE; /* senf off! */
 1531: 
 1532:   /* Calculate number of headers contained in [mem, mem + len). Assumes a
 1533:      correctly generated HTTP header field block. */
 1534:   nheader = 0;
 1535:   for(i = 1; i < len; ++i) {
 1536:     if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
 1537:       ++nheader;
 1538:       ++i;
 1539:     }
 1540:   }
 1541:   if(nheader < 2)
 1542:     goto fail;
 1543: 
 1544:   /* We counted additional 2 \r\n in the first and last line. We need 3
 1545:      new headers: :method, :path and :scheme. Therefore we need one
 1546:      more space. */
 1547:   nheader += 1;
 1548:   nva = malloc(sizeof(nghttp3_nv) * nheader);
 1549:   if(!nva) {
 1550:     result = CURLE_OUT_OF_MEMORY;
 1551:     goto fail;
 1552:   }
 1553: 
 1554:   /* Extract :method, :path from request line
 1555:      We do line endings with CRLF so checking for CR is enough */
 1556:   line_end = memchr(hdbuf, '\r', len);
 1557:   if(!line_end) {
 1558:     result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */
 1559:     goto fail;
 1560:   }
 1561: 
 1562:   /* Method does not contain spaces */
 1563:   end = memchr(hdbuf, ' ', line_end - hdbuf);
 1564:   if(!end || end == hdbuf)
 1565:     goto fail;
 1566:   nva[0].name = (unsigned char *)":method";
 1567:   nva[0].namelen = strlen((char *)nva[0].name);
 1568:   nva[0].value = (unsigned char *)hdbuf;
 1569:   nva[0].valuelen = (size_t)(end - hdbuf);
 1570:   nva[0].flags = NGHTTP3_NV_FLAG_NONE;
 1571: 
 1572:   hdbuf = end + 1;
 1573: 
 1574:   /* Path may contain spaces so scan backwards */
 1575:   end = NULL;
 1576:   for(i = (size_t)(line_end - hdbuf); i; --i) {
 1577:     if(hdbuf[i - 1] == ' ') {
 1578:       end = &hdbuf[i - 1];
 1579:       break;
 1580:     }
 1581:   }
 1582:   if(!end || end == hdbuf)
 1583:     goto fail;
 1584:   nva[1].name = (unsigned char *)":path";
 1585:   nva[1].namelen = strlen((char *)nva[1].name);
 1586:   nva[1].value = (unsigned char *)hdbuf;
 1587:   nva[1].valuelen = (size_t)(end - hdbuf);
 1588:   nva[1].flags = NGHTTP3_NV_FLAG_NONE;
 1589: 
 1590:   nva[2].name = (unsigned char *)":scheme";
 1591:   nva[2].namelen = strlen((char *)nva[2].name);
 1592:   if(conn->handler->flags & PROTOPT_SSL)
 1593:     nva[2].value = (unsigned char *)"https";
 1594:   else
 1595:     nva[2].value = (unsigned char *)"http";
 1596:   nva[2].valuelen = strlen((char *)nva[2].value);
 1597:   nva[2].flags = NGHTTP3_NV_FLAG_NONE;
 1598: 
 1599: 
 1600:   authority_idx = 0;
 1601:   i = 3;
 1602:   while(i < nheader) {
 1603:     size_t hlen;
 1604: 
 1605:     hdbuf = line_end + 2;
 1606: 
 1607:     /* check for next CR, but only within the piece of data left in the given
 1608:        buffer */
 1609:     line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
 1610:     if(!line_end || (line_end == hdbuf))
 1611:       goto fail;
 1612: 
 1613:     /* header continuation lines are not supported */
 1614:     if(*hdbuf == ' ' || *hdbuf == '\t')
 1615:       goto fail;
 1616: 
 1617:     for(end = hdbuf; end < line_end && *end != ':'; ++end)
 1618:       ;
 1619:     if(end == hdbuf || end == line_end)
 1620:       goto fail;
 1621:     hlen = end - hdbuf;
 1622: 
 1623:     if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
 1624:       authority_idx = i;
 1625:       nva[i].name = (unsigned char *)":authority";
 1626:       nva[i].namelen = strlen((char *)nva[i].name);
 1627:     }
 1628:     else {
 1629:       nva[i].namelen = (size_t)(end - hdbuf);
 1630:       /* Lower case the header name for HTTP/3 */
 1631:       Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
 1632:       nva[i].name = (unsigned char *)hdbuf;
 1633:     }
 1634:     nva[i].flags = NGHTTP3_NV_FLAG_NONE;
 1635:     hdbuf = end + 1;
 1636:     while(*hdbuf == ' ' || *hdbuf == '\t')
 1637:       ++hdbuf;
 1638:     end = line_end;
 1639: 
 1640: #if 0 /* This should probably go in more or less like this */
 1641:     switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
 1642:                           end - hdbuf)) {
 1643:     case HEADERINST_IGNORE:
 1644:       /* skip header fields prohibited by HTTP/2 specification. */
 1645:       --nheader;
 1646:       continue;
 1647:     case HEADERINST_TE_TRAILERS:
 1648:       nva[i].value = (uint8_t*)"trailers";
 1649:       nva[i].value_len = sizeof("trailers") - 1;
 1650:       break;
 1651:     default:
 1652:       nva[i].value = (unsigned char *)hdbuf;
 1653:       nva[i].value_len = (size_t)(end - hdbuf);
 1654:     }
 1655: #endif
 1656:     nva[i].value = (unsigned char *)hdbuf;
 1657:     nva[i].valuelen = (size_t)(end - hdbuf);
 1658:     nva[i].flags = NGHTTP3_NV_FLAG_NONE;
 1659: 
 1660:     ++i;
 1661:   }
 1662: 
 1663:   /* :authority must come before non-pseudo header fields */
 1664:   if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
 1665:     nghttp3_nv authority = nva[authority_idx];
 1666:     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
 1667:       nva[i] = nva[i - 1];
 1668:     }
 1669:     nva[i] = authority;
 1670:   }
 1671: 
 1672:   /* Warn stream may be rejected if cumulative length of headers is too
 1673:      large. */
 1674: #define MAX_ACC 60000  /* <64KB to account for some overhead */
 1675:   {
 1676:     size_t acc = 0;
 1677:     for(i = 0; i < nheader; ++i)
 1678:       acc += nva[i].namelen + nva[i].valuelen;
 1679: 
 1680:     if(acc > MAX_ACC) {
 1681:       infof(data, "http_request: Warning: The cumulative length of all "
 1682:             "headers exceeds %zu bytes and that could cause the "
 1683:             "stream to be rejected.\n", MAX_ACC);
 1684:     }
 1685:   }
 1686: 
 1687:   switch(data->set.httpreq) {
 1688:   case HTTPREQ_POST:
 1689:   case HTTPREQ_POST_FORM:
 1690:   case HTTPREQ_POST_MIME:
 1691:   case HTTPREQ_PUT: {
 1692:     nghttp3_data_reader data_reader;
 1693:     if(data->state.infilesize != -1)
 1694:       stream->upload_left = data->state.infilesize;
 1695:     else
 1696:       /* data sending without specifying the data amount up front */
 1697:       stream->upload_left = -1; /* unknown, but not zero */
 1698: 
 1699:     data_reader.read_data = cb_h3_readfunction;
 1700: 
 1701:     h3out = calloc(sizeof(struct h3out), 1);
 1702:     if(!h3out) {
 1703:       result = CURLE_OUT_OF_MEMORY;
 1704:       goto fail;
 1705:     }
 1706:     stream->h3out = h3out;
 1707: 
 1708:     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
 1709:                                      nva, nheader, &data_reader,
 1710:                                      conn->data);
 1711:     if(rc) {
 1712:       result = CURLE_SEND_ERROR;
 1713:       goto fail;
 1714:     }
 1715:     break;
 1716:   }
 1717:   default:
 1718:     stream->upload_left = 0; /* nothing left to send */
 1719:     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
 1720:                                      nva, nheader,
 1721:                                      NULL, /* no body! */
 1722:                                      conn->data);
 1723:     if(rc) {
 1724:       result = CURLE_SEND_ERROR;
 1725:       goto fail;
 1726:     }
 1727:     break;
 1728:   }
 1729: 
 1730:   Curl_safefree(nva);
 1731: 
 1732:   infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
 1733:         stream3_id, (void *)data);
 1734: 
 1735:   return CURLE_OK;
 1736: 
 1737: fail:
 1738:   free(nva);
 1739:   return result;
 1740: }
 1741: static ssize_t ngh3_stream_send(struct connectdata *conn,
 1742:                                 int sockindex,
 1743:                                 const void *mem,
 1744:                                 size_t len,
 1745:                                 CURLcode *curlcode)
 1746: {
 1747:   ssize_t sent;
 1748:   struct quicsocket *qs = conn->quic;
 1749:   curl_socket_t sockfd = conn->sock[sockindex];
 1750:   struct HTTP *stream = conn->data->req.protop;
 1751: 
 1752:   if(!stream->h3req) {
 1753:     CURLcode result = http_request(conn, mem, len);
 1754:     if(result) {
 1755:       *curlcode = CURLE_SEND_ERROR;
 1756:       return -1;
 1757:     }
 1758:     sent = len;
 1759:   }
 1760:   else {
 1761:     H3BUGF(infof(conn->data, "ngh3_stream_send() wants to send %zd bytes\n",
 1762:                  len));
 1763:     if(!stream->upload_len) {
 1764:       stream->upload_mem = mem;
 1765:       stream->upload_len = len;
 1766:       (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
 1767:       sent = len;
 1768:     }
 1769:     else {
 1770:       *curlcode = CURLE_AGAIN;
 1771:       return -1;
 1772:     }
 1773:   }
 1774: 
 1775:   if(ng_flush_egress(conn, sockfd, qs)) {
 1776:     *curlcode = CURLE_SEND_ERROR;
 1777:     return -1;
 1778:   }
 1779: 
 1780:   *curlcode = CURLE_OK;
 1781:   return sent;
 1782: }
 1783: 
 1784: static void ng_has_connected(struct connectdata *conn, int tempindex)
 1785: {
 1786:   conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
 1787:   conn->send[FIRSTSOCKET] = ngh3_stream_send;
 1788:   conn->handler = &Curl_handler_http3;
 1789:   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
 1790:   conn->httpversion = 30;
 1791:   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
 1792:   conn->quic = &conn->hequic[tempindex];
 1793:   DEBUGF(infof(conn->data, "ngtcp2 established connection!\n"));
 1794: }
 1795: 
 1796: /*
 1797:  * There can be multiple connection attempts going on in parallel.
 1798:  */
 1799: CURLcode Curl_quic_is_connected(struct connectdata *conn,
 1800:                                 int sockindex,
 1801:                                 bool *done)
 1802: {
 1803:   CURLcode result;
 1804:   struct quicsocket *qs = &conn->hequic[sockindex];
 1805:   curl_socket_t sockfd = conn->tempsock[sockindex];
 1806: 
 1807:   result = ng_process_ingress(conn, sockfd, qs);
 1808:   if(result)
 1809:     return result;
 1810: 
 1811:   result = ng_flush_egress(conn, sockfd, qs);
 1812:   if(result)
 1813:     return result;
 1814: 
 1815:   if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
 1816:     *done = TRUE;
 1817:     ng_has_connected(conn, sockindex);
 1818:   }
 1819: 
 1820:   return result;
 1821: }
 1822: 
 1823: static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
 1824:                                    struct quicsocket *qs)
 1825: {
 1826:   ssize_t recvd;
 1827:   int rv;
 1828:   uint8_t buf[65536];
 1829:   size_t bufsize = sizeof(buf);
 1830:   struct sockaddr_storage remote_addr;
 1831:   socklen_t remote_addrlen;
 1832:   ngtcp2_path path;
 1833:   ngtcp2_tstamp ts = timestamp();
 1834: 
 1835:   for(;;) {
 1836:     remote_addrlen = sizeof(remote_addr);
 1837:     while((recvd = recvfrom(sockfd, buf, bufsize, 0,
 1838:                             (struct sockaddr *)&remote_addr,
 1839:                             &remote_addrlen)) == -1 &&
 1840:           SOCKERRNO == EINTR)
 1841:       ;
 1842:     if(recvd == -1) {
 1843:       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
 1844:         break;
 1845: 
 1846:       failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %d", recvd);
 1847:       return CURLE_RECV_ERROR;
 1848:     }
 1849: 
 1850:     ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr,
 1851:                      qs->local_addrlen, NULL);
 1852:     ngtcp2_addr_init(&path.remote, (uint8_t *)&remote_addr, remote_addrlen,
 1853:                      NULL);
 1854: 
 1855:     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts);
 1856:     if(rv != 0) {
 1857:       /* TODO Send CONNECTION_CLOSE if possible */
 1858:       return CURLE_RECV_ERROR;
 1859:     }
 1860:   }
 1861: 
 1862:   return CURLE_OK;
 1863: }
 1864: 
 1865: static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
 1866:                                 struct quicsocket *qs)
 1867: {
 1868:   int rv;
 1869:   ssize_t sent;
 1870:   ssize_t outlen;
 1871:   uint8_t out[NGTCP2_MAX_PKTLEN_IPV4];
 1872:   size_t pktlen;
 1873:   ngtcp2_path_storage ps;
 1874:   ngtcp2_tstamp ts = timestamp();
 1875:   struct sockaddr_storage remote_addr;
 1876:   ngtcp2_tstamp expiry;
 1877:   ngtcp2_duration timeout;
 1878:   int64_t stream_id;
 1879:   ssize_t veccnt;
 1880:   int fin;
 1881:   nghttp3_vec vec[16];
 1882:   ssize_t ndatalen;
 1883: 
 1884:   switch(qs->local_addr.ss_family) {
 1885:   case AF_INET:
 1886:     pktlen = NGTCP2_MAX_PKTLEN_IPV4;
 1887:     break;
 1888: #ifdef ENABLE_IPV6
 1889:   case AF_INET6:
 1890:     pktlen = NGTCP2_MAX_PKTLEN_IPV6;
 1891:     break;
 1892: #endif
 1893:   default:
 1894:     assert(0);
 1895:   }
 1896: 
 1897:   rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
 1898:   if(rv != 0) {
 1899:     failf(conn->data, "ngtcp2_conn_handle_expiry returned error: %s\n",
 1900:           ngtcp2_strerror(rv));
 1901:     return CURLE_SEND_ERROR;
 1902:   }
 1903: 
 1904:   ngtcp2_path_storage_zero(&ps);
 1905: 
 1906:   for(;;) {
 1907:     outlen = -1;
 1908:     if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
 1909:       veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
 1910:                                           sizeof(vec) / sizeof(vec[0]));
 1911:       if(veccnt < 0) {
 1912:         failf(conn->data, "nghttp3_conn_writev_stream returned error: %s\n",
 1913:               nghttp3_strerror((int)veccnt));
 1914:         return CURLE_SEND_ERROR;
 1915:       }
 1916:       else if(veccnt > 0) {
 1917:         outlen =
 1918:           ngtcp2_conn_writev_stream(qs->qconn, &ps.path,
 1919:                                     out, pktlen, &ndatalen,
 1920:                                     NGTCP2_WRITE_STREAM_FLAG_MORE,
 1921:                                     stream_id, fin,
 1922:                                     (const ngtcp2_vec *)vec, veccnt, ts);
 1923:         if(outlen == 0) {
 1924:           break;
 1925:         }
 1926:         if(outlen < 0) {
 1927:           if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
 1928:              outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
 1929:             rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
 1930:             if(rv != 0) {
 1931:               failf(conn->data,
 1932:                     "nghttp3_conn_block_stream returned error: %s\n",
 1933:                     nghttp3_strerror(rv));
 1934:               return CURLE_SEND_ERROR;
 1935:             }
 1936:             continue;
 1937:           }
 1938:           else if(outlen == NGTCP2_ERR_WRITE_STREAM_MORE) {
 1939:             assert(ndatalen > 0);
 1940:             rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id,
 1941:                                                ndatalen);
 1942:             if(rv != 0) {
 1943:               failf(conn->data,
 1944:                     "nghttp3_conn_add_write_offset returned error: %s\n",
 1945:                     nghttp3_strerror(rv));
 1946:               return CURLE_SEND_ERROR;
 1947:             }
 1948:             continue;
 1949:           }
 1950:           else {
 1951:             failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n",
 1952:                   ngtcp2_strerror((int)outlen));
 1953:             return CURLE_SEND_ERROR;
 1954:           }
 1955:         }
 1956:         else if(ndatalen >= 0) {
 1957:           rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
 1958:           if(rv != 0) {
 1959:             failf(conn->data,
 1960:                   "nghttp3_conn_add_write_offset returned error: %s\n",
 1961:                   nghttp3_strerror(rv));
 1962:             return CURLE_SEND_ERROR;
 1963:           }
 1964:         }
 1965:       }
 1966:     }
 1967:     if(outlen < 0) {
 1968:       outlen = ngtcp2_conn_write_pkt(qs->qconn, &ps.path, out, pktlen, ts);
 1969:       if(outlen < 0) {
 1970:         failf(conn->data, "ngtcp2_conn_write_pkt returned error: %s\n",
 1971:               ngtcp2_strerror((int)outlen));
 1972:         return CURLE_SEND_ERROR;
 1973:       }
 1974:       if(outlen == 0)
 1975:         break;
 1976:     }
 1977: 
 1978:     memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen);
 1979:     while((sent = send(sockfd, out, outlen, 0)) == -1 &&
 1980:           SOCKERRNO == EINTR)
 1981:       ;
 1982: 
 1983:     if(sent == -1) {
 1984:       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
 1985:         /* TODO Cache packet */
 1986:         break;
 1987:       }
 1988:       else {
 1989:         failf(conn->data, "send() returned %zd (errno %d)\n", sent,
 1990:               SOCKERRNO);
 1991:         return CURLE_SEND_ERROR;
 1992:       }
 1993:     }
 1994:   }
 1995: 
 1996:   expiry = ngtcp2_conn_get_expiry(qs->qconn);
 1997:   if(expiry != UINT64_MAX) {
 1998:     if(expiry <= ts) {
 1999:       timeout = NGTCP2_MILLISECONDS;
 2000:     }
 2001:     else {
 2002:       timeout = expiry - ts;
 2003:     }
 2004:     Curl_expire(conn->data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
 2005:   }
 2006: 
 2007:   return CURLE_OK;
 2008: }
 2009: 
 2010: /*
 2011:  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
 2012:  */
 2013: CURLcode Curl_quic_done_sending(struct connectdata *conn)
 2014: {
 2015:   if(conn->handler == &Curl_handler_http3) {
 2016:     /* only for HTTP/3 transfers */
 2017:     struct HTTP *stream = conn->data->req.protop;
 2018:     struct quicsocket *qs = conn->quic;
 2019:     stream->upload_done = TRUE;
 2020:     (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
 2021:   }
 2022: 
 2023:   return CURLE_OK;
 2024: }
 2025: 
 2026: /*
 2027:  * Called from http.c:Curl_http_done when a request completes.
 2028:  */
 2029: void Curl_quic_done(struct Curl_easy *data, bool premature)
 2030: {
 2031:   (void)premature;
 2032:   if(data->conn->handler == &Curl_handler_http3) {
 2033:     /* only for HTTP/3 transfers */
 2034:     struct HTTP *stream = data->req.protop;
 2035:     Curl_safefree(stream->overflow_buf);
 2036:   }
 2037: }
 2038: 
 2039: /*
 2040:  * Called from transfer.c:data_pending to know if we should keep looping
 2041:  * to receive more data from the connection.
 2042:  */
 2043: bool Curl_quic_data_pending(const struct Curl_easy *data)
 2044: {
 2045:   /* We may have received more data than we're able to hold in the receive
 2046:      buffer and allocated an overflow buffer. Since it's possible that
 2047:      there's no more data coming on the socket, we need to keep reading
 2048:      until the overflow buffer is empty. */
 2049:   const struct HTTP *stream = data->req.protop;
 2050:   return stream->overflow_buflen > 0;
 2051: }
 2052: 
 2053: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>