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