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, ¶ms);
615 nwrite = ngtcp2_encode_transport_params(
616 paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
617 ¶ms);
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