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