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