From 28c0c78c9a97e0672ad3002266ce44980ff79cf7 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 26 Dec 2023 06:48:01 -0800 Subject: [PATCH] deps: update ngtcp2 and nghttp3 PR-URL: https://github.com/nodejs/node/pull/51291 Reviewed-By: Stephen Belanger Reviewed-By: Jiawen Geng --- .../nghttp3/lib/includes/nghttp3/nghttp3.h | 795 +++-- deps/ngtcp2/nghttp3/lib/nghttp3_conn.c | 305 +- deps/ngtcp2/nghttp3/lib/nghttp3_conn.h | 10 +- deps/ngtcp2/nghttp3/lib/nghttp3_conv.c | 26 +- deps/ngtcp2/nghttp3/lib/nghttp3_conv.h | 71 +- deps/ngtcp2/nghttp3/lib/nghttp3_err.c | 5 +- deps/ngtcp2/nghttp3/lib/nghttp3_frame.c | 47 +- deps/ngtcp2/nghttp3/lib/nghttp3_frame.h | 57 +- deps/ngtcp2/nghttp3/lib/nghttp3_http.c | 744 +--- deps/ngtcp2/nghttp3/lib/nghttp3_http.h | 63 +- deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c | 38 +- deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h | 4 +- deps/ngtcp2/nghttp3/lib/nghttp3_map.c | 2 + deps/ngtcp2/nghttp3/lib/nghttp3_map.h | 2 + deps/ngtcp2/nghttp3/lib/nghttp3_objalloc.h | 29 +- deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c | 89 +- deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c | 3 +- deps/ngtcp2/nghttp3/lib/nghttp3_stream.c | 108 +- deps/ngtcp2/nghttp3/lib/nghttp3_stream.h | 29 +- deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c | 31 +- deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h | 23 +- deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c | 72 + deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h | 53 + deps/ngtcp2/nghttp3/lib/sfparse.c | 1146 ++++++ deps/ngtcp2/nghttp3/lib/sfparse.h | 409 +++ deps/ngtcp2/ngtcp2.gyp | 23 +- .../ngtcp2/crypto/boringssl/boringssl.c | 116 +- .../crypto/includes/ngtcp2/ngtcp2_crypto.h | 304 +- .../includes/ngtcp2/ngtcp2_crypto_boringssl.h | 16 +- .../includes/ngtcp2/ngtcp2_crypto_picotls.h | 20 +- ...ypto_openssl.h => ngtcp2_crypto_quictls.h} | 59 +- .../includes/ngtcp2/ngtcp2_crypto_wolfssl.h | 16 +- deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c | 112 +- .../{openssl/openssl.c => quictls/quictls.c} | 341 +- deps/ngtcp2/ngtcp2/crypto/shared.c | 190 +- deps/ngtcp2/ngtcp2/crypto/shared.h | 89 +- deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c | 82 +- .../ngtcp2/lib/includes/ngtcp2/ngtcp2.h | 2386 +++++++------ deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c | 20 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c | 8 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c | 1658 ++++++--- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h | 172 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c | 1486 -------- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h | 149 - deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c | 524 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h | 75 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c | 3157 +++++++++-------- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h | 194 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h | 132 + deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c | 95 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h | 82 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c | 66 + deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h | 71 + deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c | 536 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h | 48 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c | 220 ++ deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h | 171 + deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c | 38 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c | 271 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h | 25 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h | 5 + deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c | 2 + deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h | 2 + deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h | 33 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h | 29 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c | 565 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h | 198 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h | 62 + deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c | 14 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h | 4 - deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c | 122 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c | 27 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h | 8 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c | 13 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c | 346 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h | 154 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c | 5 + deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h | 7 + deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c | 44 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h | 53 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h | 68 + deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c | 71 + deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h | 52 + deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c | 45 +- 92 files changed, 10428 insertions(+), 8655 deletions(-) create mode 100644 deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c create mode 100644 deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h create mode 100644 deps/ngtcp2/nghttp3/lib/sfparse.c create mode 100644 deps/ngtcp2/nghttp3/lib/sfparse.h rename deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/{ngtcp2_crypto_openssl.h => ngtcp2_crypto_quictls.h} (63%) rename deps/ngtcp2/ngtcp2/crypto/{openssl/openssl.c => quictls/quictls.c} (73%) delete mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c delete mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h index cd10e4def7019b..77eb1fbf263815 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h @@ -68,6 +68,12 @@ extern "C" { # endif /* !BUILDING_NGHTTP3 */ #endif /* !defined(WIN32) */ +#ifdef _MSC_VER +# define NGHTTP3_ALIGN(N) __declspec(align(N)) +#else /* !_MSC_VER */ +# define NGHTTP3_ALIGN(N) __attribute__((aligned(N))) +#endif /* !_MSC_VER */ + /** * @typedef * @@ -97,166 +103,159 @@ typedef ptrdiff_t nghttp3_ssize; * argument is invalid. */ #define NGHTTP3_ERR_INVALID_ARGUMENT -101 -/** - * @macro - * - * :macro:`NGHTTP3_ERR_NOBUF` indicates that a provided buffer does - * not have enough space to store data. - */ -#define NGHTTP3_ERR_NOBUF -102 /** * @macro * * :macro:`NGHTTP3_ERR_INVALID_STATE` indicates that a requested * operation is not allowed at the current connection state. */ -#define NGHTTP3_ERR_INVALID_STATE -103 +#define NGHTTP3_ERR_INVALID_STATE -102 /** * @macro * * :macro:`NGHTTP3_ERR_WOULDBLOCK` indicates that an operation might * block. */ -#define NGHTTP3_ERR_WOULDBLOCK -104 +#define NGHTTP3_ERR_WOULDBLOCK -103 /** * @macro * * :macro:`NGHTTP3_ERR_STREAM_IN_USE` indicates that a stream ID is * already in use. */ -#define NGHTTP3_ERR_STREAM_IN_USE -105 +#define NGHTTP3_ERR_STREAM_IN_USE -104 /** * @macro * * :macro:`NGHTTP3_ERR_MALFORMED_HTTP_HEADER` indicates that an HTTP * header field is malformed. */ -#define NGHTTP3_ERR_MALFORMED_HTTP_HEADER -107 +#define NGHTTP3_ERR_MALFORMED_HTTP_HEADER -105 /** * @macro * * :macro:`NGHTTP3_ERR_REMOVE_HTTP_HEADER` indicates that an HTTP * header field is discarded. */ -#define NGHTTP3_ERR_REMOVE_HTTP_HEADER -108 +#define NGHTTP3_ERR_REMOVE_HTTP_HEADER -106 /** * @macro * * :macro:`NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING` indicates that HTTP * messaging is malformed. */ -#define NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING -109 +#define NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING -107 /** * @macro * * :macro:`NGHTTP3_ERR_QPACK_FATAL` indicates that a fatal error is - * occurred during QPACK processing and it cannot be recoverable. + * occurred during QPACK processing, and it cannot be recoverable. */ -#define NGHTTP3_ERR_QPACK_FATAL -111 +#define NGHTTP3_ERR_QPACK_FATAL -108 /** * @macro * * :macro:`NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE` indicates that a header * field is too large to process. */ -#define NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE -112 +#define NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE -109 /** * @macro * * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` indicates that a stream is * not found. */ -#define NGHTTP3_ERR_STREAM_NOT_FOUND -114 +#define NGHTTP3_ERR_STREAM_NOT_FOUND -110 /** * @macro * * :macro:`NGHTTP3_ERR_CONN_CLOSING` indicates that a connection is * closing state. */ -#define NGHTTP3_ERR_CONN_CLOSING -116 +#define NGHTTP3_ERR_CONN_CLOSING -111 /** * @macro * * :macro:`NGHTTP3_ERR_STREAM_DATA_OVERFLOW` indicates that the length - * of stream data is too long and causes overflow. + * of stream data is too long, and causes overflow. */ -#define NGHTTP3_ERR_STREAM_DATA_OVERFLOW -117 +#define NGHTTP3_ERR_STREAM_DATA_OVERFLOW -112 /** * @macro * * :macro:`NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED` indicates that a * QPACK decompression failed. */ -#define NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED -402 +#define NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED -401 /** * @macro * * :macro:`NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR` indicates that an * error occurred while reading QPACK encoder stream. */ -#define NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR -403 +#define NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR -402 /** * @macro * * :macro:`NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR` indicates that an * error occurred while reading QPACK decoder stream. */ -#define NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR -404 +#define NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR -403 /** * @macro * * :macro:`NGHTTP3_ERR_H3_FRAME_UNEXPECTED` indicates that an * unexpected HTTP/3 frame is received. */ -#define NGHTTP3_ERR_H3_FRAME_UNEXPECTED -408 +#define NGHTTP3_ERR_H3_FRAME_UNEXPECTED -601 /** * @macro * * :macro:`NGHTTP3_ERR_H3_FRAME_ERROR` indicates that an HTTP/3 frame * is malformed. */ -#define NGHTTP3_ERR_H3_FRAME_ERROR -409 +#define NGHTTP3_ERR_H3_FRAME_ERROR -602 /** * @macro * * :macro:`NGHTTP3_ERR_H3_MISSING_SETTINGS` indicates that an HTTP/3 * SETTINGS frame is missing. */ -#define NGHTTP3_ERR_H3_MISSING_SETTINGS -665 +#define NGHTTP3_ERR_H3_MISSING_SETTINGS -603 /** * @macro * * :macro:`NGHTTP3_ERR_H3_INTERNAL_ERROR` indicates an internal error. */ -#define NGHTTP3_ERR_H3_INTERNAL_ERROR -667 +#define NGHTTP3_ERR_H3_INTERNAL_ERROR -604 /** * @macro * * :macro:`NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM` indicates that a * critical stream is closed. */ -#define NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM -668 +#define NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM -605 /** * @macro * * :macro:`NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR` indicates a general * protocol error. This is typically a catch-all error. */ -#define NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR -669 +#define NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR -606 /** * @macro * * :macro:`NGHTTP3_ERR_H3_ID_ERROR` indicates that an ID related error * occurred. */ -#define NGHTTP3_ERR_H3_ID_ERROR -670 +#define NGHTTP3_ERR_H3_ID_ERROR -607 /** * @macro * * :macro:`NGHTTP3_ERR_H3_SETTINGS_ERROR` indicates that an HTTP/3 * SETTINGS frame is malformed. */ -#define NGHTTP3_ERR_H3_SETTINGS_ERROR -671 +#define NGHTTP3_ERR_H3_SETTINGS_ERROR -608 /** * @macro * @@ -264,7 +263,7 @@ typedef ptrdiff_t nghttp3_ssize; * remote endpoint attempts to create a new stream which is not * allowed. */ -#define NGHTTP3_ERR_H3_STREAM_CREATION_ERROR -672 +#define NGHTTP3_ERR_H3_STREAM_CREATION_ERROR -609 /** * @macro * @@ -479,7 +478,7 @@ typedef void *(*nghttp3_realloc)(void *ptr, size_t size, void *user_data); * per-session memory pool. * * In the following example code, ``my_malloc``, ``my_free``, - * ``my_calloc`` and ``my_realloc`` are the replacement of the + * ``my_calloc``, and ``my_realloc`` are the replacement of the * standard allocators :manpage:`malloc(3)`, :manpage:`free(3)`, * :manpage:`calloc(3)` and :manpage:`realloc(3)` respectively:: * @@ -512,8 +511,8 @@ typedef void *(*nghttp3_realloc)(void *ptr, size_t size, void *user_data); */ typedef struct nghttp3_mem { /** - * :member:`user_data` is an arbitrary user supplied data. This - * is passed to each allocator function. + * :member:`user_data` is an arbitrary user supplied data. This is + * passed to each allocator function. */ void *user_data; /** @@ -559,7 +558,7 @@ typedef struct nghttp3_vec { uint8_t *base; /** * :member:`len` is the number of bytes which the buffer pointed by - * base contains. + * :member:`base` contains. */ size_t len; } nghttp3_vec; @@ -626,8 +625,8 @@ typedef struct nghttp3_buf { uint8_t *end; /** * :member:`pos` pointers to the start of data. Typically, this - * points to the point that next data should be read. Initially, it - * points to :member:`begin`. + * points to the address that next data should be read. Initially, + * it points to :member:`begin`. */ uint8_t *pos; /** @@ -685,7 +684,7 @@ NGHTTP3_EXTERN void nghttp3_buf_reset(nghttp3_buf *buf); /** * @macrosection * - * Flags for header field name/value pair + * Flags for HTTP field name/value pair */ /** @@ -708,8 +707,8 @@ NGHTTP3_EXTERN void nghttp3_buf_reset(nghttp3_buf *buf); * @macro * * :macro:`NGHTTP3_NV_FLAG_NO_COPY_NAME` is set solely by application. - * If this flag is set, the library does not make a copy of header - * field name. This could improve performance. + * If this flag is set, the library does not make a copy of field + * name. This could improve performance. */ #define NGHTTP3_NV_FLAG_NO_COPY_NAME 0x02u @@ -718,25 +717,35 @@ NGHTTP3_EXTERN void nghttp3_buf_reset(nghttp3_buf *buf); * * :macro:`NGHTTP3_NV_FLAG_NO_COPY_VALUE` is set solely by * application. If this flag is set, the library does not make a copy - * of header field value. This could improve performance. + * of field value. This could improve performance. */ #define NGHTTP3_NV_FLAG_NO_COPY_VALUE 0x04u +/** + * @macro + * + * :macro:`NGHTTP3_NV_FLAG_TRY_INDEX` gives a hint to QPACK encoder to + * index an HTTP field which is not indexed by default. This is just + * a hint, and QPACK encoder might not encode the field in various + * reasons. + */ +#define NGHTTP3_NV_FLAG_TRY_INDEX 0x08u + /** * @struct * * :type:`nghttp3_nv` is the name/value pair, which mainly used to - * represent header fields. + * represent HTTP fields. */ typedef struct nghttp3_nv { /** - * :member:`name` is the header field name. + * :member:`name` is the HTTP field name. */ - uint8_t *name; + const uint8_t *name; /** - * :member:`value` is the header field value. + * :member:`value` is the HTTP field value. */ - uint8_t *value; + const uint8_t *value; /** * :member:`namelen` is the length of the |name|, excluding * terminating NULL. @@ -758,8 +767,8 @@ typedef struct nghttp3_nv { /** * @enum * - * :type:`nghttp3_qpack_token` defines HTTP header field name tokens - * to identify field name quickly. It appears in + * :type:`nghttp3_qpack_token` defines HTTP field name tokens to + * identify field name quickly. It appears in * :member:`nghttp3_qpack_nv.token`. */ typedef enum nghttp3_qpack_token { @@ -1005,7 +1014,7 @@ typedef enum nghttp3_qpack_token { */ NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS = 96, - /* Additional header fields for HTTP messaging validation */ + /* Additional HTTP fields for HTTP messaging validation */ /** * :enum:`NGHTTP3_QPACK_TOKEN_HOST` is a token for ``host``. @@ -1053,26 +1062,25 @@ typedef enum nghttp3_qpack_token { /** * @struct * - * :type:`nghttp3_qpack_nv` represents header field name/value pair - * just like :type:`nghttp3_nv`. It is an extended version of - * :type:`nghttp3_nv` and has reference counted buffers and tokens - * which might be useful for applications. + * :type:`nghttp3_qpack_nv` represents HTTP field name/value pair just + * like :type:`nghttp3_nv`. It is an extended version of + * :type:`nghttp3_nv`, and has reference counted buffers and tokens. */ typedef struct nghttp3_qpack_nv { /** - * :member:`name` is the buffer containing header field name. + * :member:`name` is the buffer containing HTTP field name. * NULL-termination is guaranteed. */ nghttp3_rcbuf *name; /** - * :member:`value` is the buffer containing header field value. + * :member:`value` is the buffer containing HTTP field value. * NULL-termination is guaranteed. */ nghttp3_rcbuf *value; /** * :member:`token` is :type:`nghttp3_qpack_token` value of - * :member:`name`. It could be -1 if we have no token for that - * header field name. + * :member:`name`. It could be -1 if we have no token for that HTTP + * field name. */ int32_t token; /** @@ -1085,7 +1093,8 @@ typedef struct nghttp3_qpack_nv { /** * @struct * - * :type:`nghttp3_qpack_encoder` is QPACK encoder. + * :type:`nghttp3_qpack_encoder` is QPACK encoder. The details of + * this structure are intentionally hidden from the public API. */ typedef struct nghttp3_qpack_encoder nghttp3_qpack_encoder; @@ -1096,7 +1105,7 @@ typedef struct nghttp3_qpack_encoder nghttp3_qpack_encoder; * must be non-NULL pointer. |hard_max_dtable_capacity| is the upper * bound of the dynamic table capacity. |mem| is a memory allocator. * This function allocates memory for :type:`nghttp3_qpack_encoder` - * itself and assigns its pointer to |*pencoder| if it succeeds. + * itself, and assigns its pointer to |*pencoder| if it succeeds. * * The maximum dynamic table capacity is still 0. In order to change * the maximum dynamic table capacity, call @@ -1116,21 +1125,22 @@ NGHTTP3_EXTERN int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, * @function * * `nghttp3_qpack_encoder_del` frees memory allocated for |encoder|. - * This function frees memory pointed by |encoder| itself. + * This function also frees memory pointed by |encoder| itself. This + * function does nothing if |encoder| is NULL. */ NGHTTP3_EXTERN void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder); /** * @function * - * `nghttp3_qpack_encoder_encode` encodes the list of header fields + * `nghttp3_qpack_encoder_encode` encodes the list of HTTP fields * |nva|. |nvlen| is the length of |nva|. |stream_id| is the - * identifier of the stream which this header fields belong to. This - * function writes header block prefix, encoded header fields, and - * encoder stream to |pbuf|, |rbuf|, and |ebuf| respectively. The - * :member:`nghttp3_buf.last` will be adjusted when data is written. - * An application should write |pbuf| and |rbuf| to the request stream - * in this order. + * identifier of the stream which these HTTP fields belong to. This + * function writes field section prefix, encoded HTTP field section, + * and encoder stream to |pbuf|, |rbuf|, and |ebuf| respectively. + * Each :member:`nghttp3_buf.last` will be adjusted when data is + * written. An application should write |pbuf| and |rbuf| to the + * request stream in this order. * * The buffer pointed by |pbuf|, |rbuf|, and |ebuf| can be empty * buffer. It is fine to pass a buffer initialized by @@ -1139,7 +1149,7 @@ NGHTTP3_EXTERN void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder); * frees and expands buffer if the current capacity of buffer is not * enough. If :member:`nghttp3_buf.begin` of any buffer is not NULL, * it must be allocated by the same memory allocator passed to - * `nghttp3_qpack_encoder_new()`. + * `nghttp3_qpack_encoder_new`. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1147,7 +1157,7 @@ NGHTTP3_EXTERN void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder); * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory * :macro:`NGHTTP3_ERR_QPACK_FATAL` - * |encoder| is in unrecoverable error state and cannot be used + * |encoder| is in unrecoverable error state, and cannot be used * anymore. */ NGHTTP3_EXTERN int nghttp3_qpack_encoder_encode( @@ -1166,7 +1176,7 @@ NGHTTP3_EXTERN int nghttp3_qpack_encoder_encode( * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory * :macro:`NGHTTP3_ERR_QPACK_FATAL` - * |encoder| is in unrecoverable error state and cannot be used + * |encoder| is in unrecoverable error state, and cannot be used * anymore. * :macro:`NGHTTP3_ERR_QPACK_DECODER_STREAM` * |encoder| is unable to process input because it is malformed. @@ -1178,8 +1188,8 @@ NGHTTP3_EXTERN nghttp3_ssize nghttp3_qpack_encoder_read_decoder( * @function * * `nghttp3_qpack_encoder_set_max_dtable_capacity` sets max dynamic - * table capacity to |max_dtable_capacity|. If |max_dtable_capacity| is - * larger than ``hard_max_dtable_capacity`` parameter of + * table capacity to |max_dtable_capacity|. If |max_dtable_capacity| + * is larger than ``hard_max_dtable_capacity`` parameter of * `nghttp3_qpack_encoder_new`, it is truncated to the latter. */ NGHTTP3_EXTERN void @@ -1200,9 +1210,10 @@ nghttp3_qpack_encoder_set_max_blocked_streams(nghttp3_qpack_encoder *encoder, * @function * * `nghttp3_qpack_encoder_ack_everything` tells |encoder| that all - * encoded header blocks are acknowledged. This function is provided - * for debugging purpose only. In HTTP/3, |encoder| knows this by - * reading decoder stream with `nghttp3_qpack_encoder_read_decoder()`. + * encoded HTTP field sections are acknowledged. This function is + * provided for debugging purpose only. In HTTP/3, |encoder| knows + * this by reading decoder stream with + * `nghttp3_qpack_encoder_read_decoder`. */ NGHTTP3_EXTERN void nghttp3_qpack_encoder_ack_everything(nghttp3_qpack_encoder *encoder); @@ -1220,9 +1231,10 @@ nghttp3_qpack_encoder_get_num_blocked_streams(nghttp3_qpack_encoder *encoder); * @struct * * :type:`nghttp3_qpack_stream_context` is a decoder context for an - * individual stream. Its state is per header block. In order to - * reuse this object for another header block, call - * `nghttp3_qpack_stream_context_reset`. + * individual stream. Its state is per HTTP field section. In order + * to reuse this object for another HTTP field section, call + * `nghttp3_qpack_stream_context_reset`. The details of this + * structure are intentionally hidden from the public API. */ typedef struct nghttp3_qpack_stream_context nghttp3_qpack_stream_context; @@ -1232,8 +1244,8 @@ typedef struct nghttp3_qpack_stream_context nghttp3_qpack_stream_context; * `nghttp3_qpack_stream_context_new` initializes stream context. * |psctx| must be non-NULL pointer. |stream_id| is stream ID. |mem| * is a memory allocator. This function allocates memory for - * :type:`nghttp3_qpack_stream_context` itself and assigns its pointer - * to |*psctx| if it succeeds. + * :type:`nghttp3_qpack_stream_context` itself, and assigns its + * pointer to |*psctx| if it succeeds. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1249,7 +1261,8 @@ nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context **psctx, * @function * * `nghttp3_qpack_stream_context_del` frees memory allocated for - * |sctx|. This function frees memory pointed by |sctx| itself. + * |sctx|. This function frees memory pointed by |sctx| itself. This + * function does nothing if |sctx| is NULL. */ NGHTTP3_EXTERN void nghttp3_qpack_stream_context_del(nghttp3_qpack_stream_context *sctx); @@ -1267,8 +1280,8 @@ nghttp3_qpack_stream_context_get_ricnt(nghttp3_qpack_stream_context *sctx); * @function * * `nghttp3_qpack_stream_context_reset` resets the state of |sctx|. - * Then it can be reused for an another header block in the same - * stream. + * Then it can be reused for decoding an another HTTP field section in + * the same stream. */ NGHTTP3_EXTERN void nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context *sctx); @@ -1276,7 +1289,8 @@ void nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context *sctx); /** * @struct * - * :type:`nghttp3_qpack_decoder` is QPACK decoder. + * :type:`nghttp3_qpack_decoder` is QPACK decoder. The details of + * this structure are intentionally hidden from the public API. */ typedef struct nghttp3_qpack_decoder nghttp3_qpack_decoder; @@ -1288,7 +1302,7 @@ typedef struct nghttp3_qpack_decoder nghttp3_qpack_decoder; * bound of the dynamic table capacity. |max_blocked_streams| is the * maximum number of streams which can be blocked. |mem| is a memory * allocator. This function allocates memory for - * :type:`nghttp3_qpack_decoder` itself and assigns its pointer to + * :type:`nghttp3_qpack_decoder` itself, and assigns its pointer to * |*pdecoder| if it succeeds. * * This function returns 0 if it succeeds, or one of the following @@ -1306,7 +1320,8 @@ NGHTTP3_EXTERN int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder, * @function * * `nghttp3_qpack_decoder_del` frees memory allocated for |decoder|. - * This function frees memory pointed by |decoder| itself. + * This function frees memory pointed by |decoder| itself. This + * function does nothing if |decoder| is NULL. */ NGHTTP3_EXTERN void nghttp3_qpack_decoder_del(nghttp3_qpack_decoder *decoder); @@ -1322,7 +1337,7 @@ NGHTTP3_EXTERN void nghttp3_qpack_decoder_del(nghttp3_qpack_decoder *decoder); * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory. * :macro:`NGHTTP3_ERR_QPACK_FATAL` - * |decoder| is in unrecoverable error state and cannot be used + * |decoder| is in unrecoverable error state, and cannot be used * anymore. * :macro:`NGHTTP3_ERR_QPACK_ENCODER_STREAM` * Could not interpret encoder stream instruction. @@ -1354,7 +1369,7 @@ nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder); /** * @macro * - * :macro:`NGHTTP3_QPACK_DECODE_FLAG_EMIT` indicates that a header + * :macro:`NGHTTP3_QPACK_DECODE_FLAG_EMIT` indicates that an HTTP * field is successfully decoded. */ #define NGHTTP3_QPACK_DECODE_FLAG_EMIT 0x01u @@ -1362,8 +1377,8 @@ nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder); /** * @macro * - * :macro:`NGHTTP3_QPACK_DECODE_FLAG_FINAL` indicates that all header - * fields have been decoded. + * :macro:`NGHTTP3_QPACK_DECODE_FLAG_FINAL` indicates that an entire + * HTTP field section has been decoded. */ #define NGHTTP3_QPACK_DECODE_FLAG_FINAL 0x02u @@ -1380,32 +1395,32 @@ nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder); * * `nghttp3_qpack_decoder_read_request` reads request stream. The * request stream is given as the buffer pointed by |src| of length - * |srclen|. |sctx| is the stream context and it must be created by - * `nghttp3_qpack_stream_context_new()`. |*pflags| must be non-NULL + * |srclen|. |sctx| is the stream context, and it must be created by + * `nghttp3_qpack_stream_context_new`. |*pflags| must be non-NULL * pointer. |nv| must be non-NULL pointer. * * If this function succeeds, it assigns flags to |*pflags|. If * |*pflags| has :macro:`NGHTTP3_QPACK_DECODE_FLAG_EMIT` set, a - * decoded header field is assigned to |nv|. If |*pflags| has - * :macro:`NGHTTP3_QPACK_DECODE_FLAG_FINAL` set, all header fields - * have been successfully decoded. If |*pflags| has + * decoded HTTP field is assigned to |nv|. If |*pflags| has + * :macro:`NGHTTP3_QPACK_DECODE_FLAG_FINAL` set, an entire HTTP field + * section has been successfully decoded. If |*pflags| has * :macro:`NGHTTP3_QPACK_DECODE_FLAG_BLOCKED` set, decoding is blocked * due to required insert count. * - * When a header field is decoded, an application receives it in |nv|. + * When an HTTP field is decoded, an application receives it in |nv|. * :member:`nv->name ` and :member:`nv->value * ` are reference counted buffer, and their * reference counts are already incremented for application use. - * Therefore, when application finishes processing the header field, - * it must call `nghttp3_rcbuf_decref(nv->name) - * ` and `nghttp3_rcbuf_decref(nv->value) - * ` or memory leak might occur. These - * :type:`nghttp3_rcbuf` objects hold the pointer to - * :type:`nghttp3_mem` that is passed to `nghttp3_qpack_decoder_new` - * (or either `nghttp3_conn_client_new` or `nghttp3_conn_server_new` - * if it is used indirectly). As long as these objects are alive, the - * pointed :type:`nghttp3_mem` object must be available. Otherwise, - * `nghttp3_rcbuf_decref` will cause undefined behavior. + * Therefore, when application finishes processing |nv|, it must call + * `nghttp3_rcbuf_decref(nv->name) ` and + * `nghttp3_rcbuf_decref(nv->value) `, or memory + * leak might occur. These :type:`nghttp3_rcbuf` objects hold the + * pointer to :type:`nghttp3_mem` that is passed to + * `nghttp3_qpack_decoder_new` (or either `nghttp3_conn_client_new` or + * `nghttp3_conn_server_new` if it is used indirectly). As long as + * these objects are alive, the pointed :type:`nghttp3_mem` object + * must be available. Otherwise, `nghttp3_rcbuf_decref` will cause + * undefined behavior. * * This function returns the number of bytes read, or one of the * following negative error codes: @@ -1413,12 +1428,12 @@ nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder); * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory. * :macro:`NGHTTP3_ERR_QPACK_FATAL` - * |decoder| is in unrecoverable error state and cannot be used + * |decoder| is in unrecoverable error state, and cannot be used * anymore. * :macro:`NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED` - * Could not interpret header block instruction. + * Could not interpret field line representations. * :macro:`NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE` - * Header field is too large. + * HTTP field is too large. */ NGHTTP3_EXTERN nghttp3_ssize nghttp3_qpack_decoder_read_request( nghttp3_qpack_decoder *decoder, nghttp3_qpack_stream_context *sctx, @@ -1444,7 +1459,7 @@ nghttp3_qpack_decoder_write_decoder(nghttp3_qpack_decoder *decoder, * @function * * `nghttp3_qpack_decoder_get_decoder_streamlen` returns the length of - * decoder stream. + * decoder stream that is currently pending. */ NGHTTP3_EXTERN size_t nghttp3_qpack_decoder_get_decoder_streamlen(nghttp3_qpack_decoder *decoder); @@ -1452,8 +1467,8 @@ nghttp3_qpack_decoder_get_decoder_streamlen(nghttp3_qpack_decoder *decoder); /** * @function * - * `nghttp3_qpack_decoder_cancel_stream` cancels header decoding for - * stream denoted by |stream_id|. + * `nghttp3_qpack_decoder_cancel_stream` cancels HTTP field section + * decoding for stream denoted by |stream_id|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1472,14 +1487,14 @@ nghttp3_qpack_decoder_cancel_stream(nghttp3_qpack_decoder *decoder, * * `nghttp3_qpack_decoder_set_max_dtable_capacity` sets * |max_dtable_capacity| as maximum dynamic table size. - * |max_dtable_capacity| must be equal to or smaller than + * |max_dtable_capacity| must be equal to, or smaller than * ``hard_max_dtable_capacity`` parameter of * `nghttp3_qpack_decoder_new`. Normally, the maximum capacity is * communicated in encoder stream. This function is provided for * debugging and testing purpose. * - * This function returns 0 if it succeeds, or one of the - * following negative error codes: + * This function returns 0 if it succeeds, or one of the following + * negative error codes: * * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` * |max_dtable_capacity| exceeds the upper bound of the dynamic @@ -1535,8 +1550,8 @@ typedef void (*nghttp3_debug_vprintf_callback)(const char *format, * * `nghttp3_set_debug_vprintf_callback` sets a debug output callback * called by the library when built with :macro:`DEBUGBUILD` macro - * defined. If this option is not used, debug log is written into - * standard error output. + * defined. If a callback function is not set by this function, debug + * log is written into standard error output. * * For builds without :macro:`DEBUGBUILD` macro defined, this function * is noop. @@ -1564,7 +1579,7 @@ NGHTTP3_EXTERN void nghttp3_set_debug_vprintf_callback( /** * @macro * - * :macro:`NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID` specifies stream id sent + * :macro:`NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID` specifies stream ID sent * by a server when it initiates graceful shutdown of the connection * via `nghttp3_conn_submit_shutdown_notice`. */ @@ -1573,19 +1588,72 @@ NGHTTP3_EXTERN void nghttp3_set_debug_vprintf_callback( /** * @macro * - * :macro:`NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID` specifies push id sent - * by a client when it initiates graceful shutdown of the connection - * via `nghttp3_conn_submit_shutdown_notice`. + * :macro:`NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID` specifies push ID sent by + * a client when it initiates graceful shutdown of the connection via + * `nghttp3_conn_submit_shutdown_notice`. Note that libnghttp3 does + * not implement HTTP/3 Server Push. */ #define NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID ((1ull << 62) - 1) /** * @struct * - * :type:`nghttp3_conn` represents a single HTTP/3 connection. + * :type:`nghttp3_conn` represents a single HTTP/3 connection. The + * details of this structure are intentionally hidden from the public + * API. */ typedef struct nghttp3_conn nghttp3_conn; +#define NGHTTP3_SETTINGS_V1 1 +#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V1 + +/** + * @struct + * + * :type:`nghttp3_settings` defines HTTP/3 settings. + */ +typedef struct nghttp3_settings { + /** + * :member:`max_field_section_size` specifies the maximum header + * section (block) size. + */ + uint64_t max_field_section_size; + /** + * :member:`qpack_max_dtable_capacity` is the maximum size of QPACK + * dynamic table. + */ + size_t qpack_max_dtable_capacity; + /** + * :member:`qpack_encoder_max_dtable_capacity` is the upper bound of + * QPACK dynamic table capacity that the QPACK encoder is willing to + * use. The effective maximum dynamic table capacity is the minimum + * of this field and the value of the received + * SETTINGS_QPACK_MAX_TABLE_CAPACITY. If this field is set to 0, + * the encoder does not use the dynamic table. + * + * When :type:`nghttp3_settings` is passed to + * :member:`nghttp3_callbacks.recv_settings` callback, this field + * should be ignored. + */ + size_t qpack_encoder_max_dtable_capacity; + /** + * :member:`qpack_blocked_streams` is the maximum number of streams + * which can be blocked while they are being decoded. + */ + size_t qpack_blocked_streams; + /** + * :member:`enable_connect_protocol`, if set to nonzero, enables + * Extended CONNECT Method (see :rfc:`9220`). Client ignores this + * field. + */ + uint8_t enable_connect_protocol; + /** + * :member:`h3_datagram`, if set to nonzero, enables HTTP/3 + * Datagrams (see :rfc:`9297`). + */ + uint8_t h3_datagram; +} nghttp3_settings; + /** * @functypedef * @@ -1607,8 +1675,9 @@ typedef int (*nghttp3_acked_stream_data)(nghttp3_conn *conn, int64_t stream_id, * @functypedef * * :type:`nghttp3_conn_stream_close` is a callback function which is - * invoked when a stream identified by |stream_id| is closed. - * |app_error_code| indicates the reason of this closure. + * invoked when a stream identified by |stream_id| is closed. QUIC + * application error code |app_error_code| indicates the reason of + * this closure. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1625,11 +1694,11 @@ typedef int (*nghttp3_stream_close)(nghttp3_conn *conn, int64_t stream_id, * * :type:`nghttp3_recv_data` is a callback function which is invoked * when a part of request or response body on stream identified by - * |stream_id| is received. |data| points to the received data and + * |stream_id| is received. |data| points to the received data, and * its length is |datalen|. * * The application is responsible for increasing flow control credit - * by |datalen| bytes. + * (say, increasing by |datalen| bytes). * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1646,9 +1715,9 @@ typedef int (*nghttp3_recv_data)(nghttp3_conn *conn, int64_t stream_id, * :type:`nghttp3_deferred_consume` is a callback function which is * invoked when the library consumed |consumed| bytes for a stream * identified by |stream_id|. This callback is used to notify the - * consumed bytes for stream blocked by QPACK decoder. The - * application is responsible for increasing flow control credit by - * |consumed| bytes. + * consumed bytes for stream blocked due to synchronization between + * streams. The application is responsible for increasing flow + * control credit by |consumed| bytes. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1663,11 +1732,11 @@ typedef int (*nghttp3_deferred_consume)(nghttp3_conn *conn, int64_t stream_id, * @functypedef * * :type:`nghttp3_begin_headers` is a callback function which is - * invoked when an incoming header block section is started on a - * stream denoted by |stream_id|. Each header field is passed to - * application by :type:`nghttp3_recv_header` callback. And then - * :type:`nghttp3_end_headers` is called when a whole header block is - * processed. + * invoked when an incoming HTTP field section is started on a stream + * denoted by |stream_id|. Each HTTP field is passed to application + * by :type:`nghttp3_recv_header` callback. And then + * :type:`nghttp3_end_headers` is called when a whole HTTP field + * section is processed. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1682,8 +1751,8 @@ typedef int (*nghttp3_begin_headers)(nghttp3_conn *conn, int64_t stream_id, * @functypedef * * :type:`nghttp3_recv_header` is a callback function which is invoked - * when a header field is received on a stream denoted by |stream_id|. - * |name| contains a field name and |value| contains a field value. + * when an HTTP field is received on a stream denoted by |stream_id|. + * |name| contains a field name, and |value| contains a field value. * |token| is one of token defined in :type:`nghttp3_qpack_token` or * -1 if no token is defined for |name|. |flags| is bitwise OR of * zero or more of :macro:`NGHTTP3_NV_FLAG_* `. @@ -1708,9 +1777,10 @@ typedef int (*nghttp3_recv_header)(nghttp3_conn *conn, int64_t stream_id, * @functypedef * * :type:`nghttp3_end_headers` is a callback function which is invoked - * when an incoming header block has ended. + * when an incoming HTTP field section has ended. * - * If the stream ends with this header block, |fin| is set to nonzero. + * If the stream ends with this HTTP field section, |fin| is set to + * nonzero. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1743,8 +1813,8 @@ typedef int (*nghttp3_end_stream)(nghttp3_conn *conn, int64_t stream_id, * * :type:`nghttp3_stop_sending` is a callback function which is * invoked when the library asks application to send STOP_SENDING to - * the stream identified by |stream_id|. |app_error_code| indicates - * the reason for this action. + * the stream identified by |stream_id|. QUIC application error code + * |app_error_code| indicates the reason for this action. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1761,8 +1831,8 @@ typedef int (*nghttp3_stop_sending)(nghttp3_conn *conn, int64_t stream_id, * * :type:`nghttp3_reset_stream` is a callback function which is * invoked when the library asks application to reset stream - * identified by |stream_id|. |app_error_code| indicates the reason - * for this action. + * identified by |stream_id|. QUIC application error code + * |app_error_code| indicates the reason for this action. * * The implementation of this callback must return 0 if it succeeds. * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the @@ -1779,13 +1849,14 @@ typedef int (*nghttp3_reset_stream)(nghttp3_conn *conn, int64_t stream_id, * * :type:`nghttp3_shutdown` is a callback function which is invoked * when a shutdown is initiated by the remote endpoint. For client, - * |id| contains a stream id of a client initiated stream, for server, - * it contains a push id. All client streams with stream id or pushes - * with push id equal to or larger than |id| are guaranteed to not be - * processed by the remote endpoint. + * |id| contains a stream ID of a client initiated stream, for server, + * it contains a push ID. All client streams with stream ID, or pushes + * with push ID equal to, or larger than |ID| are guaranteed to not be + * processed by the remote endpoint. Note that libnghttp3 does not + * implement Server Push. * * Parameter |id| for client can contain a special value - * :macro:`NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID` and for server it can + * :macro:`NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID`, and for server it can * contain special value * :macro:`NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID`. These values signal * request for graceful shutdown of the connection, triggered by @@ -1804,8 +1875,24 @@ typedef int (*nghttp3_reset_stream)(nghttp3_conn *conn, int64_t stream_id, typedef int (*nghttp3_shutdown)(nghttp3_conn *conn, int64_t id, void *conn_user_data); -#define NGHTTP3_CALLBACKS_VERSION_V1 1 -#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_VERSION_V1 +/** + * @functypedef + * + * :type:`nghttp3_recv_settings` is a callback function which is + * invoked when SETTINGS frame is received. |settings| is a received + * remote HTTP/3 settings. + * + * The implementation of this callback must return 0 if it succeeds. + * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the + * caller immediately. Any values other than 0 is treated as + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp3_recv_settings)(nghttp3_conn *conn, + const nghttp3_settings *settings, + void *conn_user_data); + +#define NGHTTP3_CALLBACKS_V1 1 +#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V1 /** * @struct @@ -1837,32 +1924,38 @@ typedef struct nghttp3_callbacks { nghttp3_deferred_consume deferred_consume; /** * :member:`begin_headers` is a callback function which is invoked - * when a header block has started on a particular stream. + * when an HTTP header field section has started on a particular + * stream. */ nghttp3_begin_headers begin_headers; /** * :member:`recv_header` is a callback function which is invoked - * when a single header field is received on a particular stream. + * when a single HTTP header field is received on a particular + * stream. */ nghttp3_recv_header recv_header; /** * :member:`end_headers` is a callback function which is invoked - * when a header block has ended on a particular stream. + * when an HTTP header field section has ended on a particular + * stream. */ nghttp3_end_headers end_headers; /** * :member:`begin_trailers` is a callback function which is invoked - * when a trailer block has started on a particular stream. + * when an HTTP trailer field section has started on a particular + * stream. */ nghttp3_begin_headers begin_trailers; /** * :member:`recv_trailer` is a callback function which is invoked - * when a single trailer field is received on a particular stream. + * when a single HTTP trailer field is received on a particular + * stream. */ nghttp3_recv_header recv_trailer; /** * :member:`end_trailers` is a callback function which is invoked - * when a trailer block has ended on a particular stream. + * when an HTTP trailer field section has ended on a particular + * stream. */ nghttp3_end_headers end_trailers; /** @@ -1884,52 +1977,16 @@ typedef struct nghttp3_callbacks { nghttp3_reset_stream reset_stream; /** * :member:`shutdown` is a callback function which is invoked when - * the remote endpoint has signalled initiation of connection shutdown. + * the remote endpoint has signalled initiation of connection + * shutdown. */ nghttp3_shutdown shutdown; -} nghttp3_callbacks; - -#define NGHTTP3_SETTINGS_VERSION_V1 1 -#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_VERSION_V1 - -/** - * @struct - * - * :type:`nghttp3_settings` defines HTTP/3 settings. - */ -typedef struct nghttp3_settings { - /** - * :member:`max_field_section_size` specifies the maximum header - * section (block) size. - */ - uint64_t max_field_section_size; - /** - * :member:`qpack_max_dtable_capacity` is the maximum size of QPACK - * dynamic table. - */ - size_t qpack_max_dtable_capacity; - /** - * :member:`qpack_encoder_max_dtable_capacity` is the upper bound of - * QPACK dynamic table capacity that the QPACK encoder is willing to - * use. The effective maximum dynamic table capacity is the minimum - * of this field and the value of the received - * SETTINGS_QPACK_MAX_TABLE_CAPACITY. If this field is set to 0, - * the encoder does not use the dynamic table. - */ - size_t qpack_encoder_max_dtable_capacity; /** - * :member:`qpack_blocked_streams` is the maximum number of streams - * which can be blocked while they are being decoded. + * :member:`recv_settings` is a callback function which is invoked + * when SETTINGS frame is received. */ - size_t qpack_blocked_streams; - /** - * :member:`enable_connect_protocol`, if set to nonzero, enables - * Extended CONNECT Method (see - * https://www.ietf.org/archive/id/draft-ietf-httpbis-h3-websockets-00.html). - * Client ignores this field. - */ - int enable_connect_protocol; -} nghttp3_settings; + nghttp3_recv_settings recv_settings; +} nghttp3_callbacks; /** * @function @@ -1955,10 +2012,16 @@ nghttp3_settings_default_versioned(int settings_version, /** * @function * - * `nghttp3_conn_client_new` creates :type:`nghttp3_conn` and + * `nghttp3_conn_client_new` creates :type:`nghttp3_conn`, and * initializes it for client use. The pointer to the object is stored * in |*pconn|. If |mem| is ``NULL``, the memory allocator returned * by `nghttp3_mem_default` is used. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_client_new_versioned(nghttp3_conn **pconn, int callbacks_version, @@ -1970,10 +2033,16 @@ nghttp3_conn_client_new_versioned(nghttp3_conn **pconn, int callbacks_version, /** * @function * - * `nghttp3_conn_server_new` creates :type:`nghttp3_conn` and + * `nghttp3_conn_server_new` creates :type:`nghttp3_conn`, and * initializes it for server use. The pointer to the object is stored * in |*pconn|. If |mem| is ``NULL``, the memory allocator returned * by `nghttp3_mem_default` is used. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_server_new_versioned(nghttp3_conn **pconn, int callbacks_version, @@ -1985,7 +2054,9 @@ nghttp3_conn_server_new_versioned(nghttp3_conn **pconn, int callbacks_version, /** * @function * - * `nghttp3_conn_del` frees resources allocated for |conn|. + * `nghttp3_conn_del` frees resources allocated for |conn|. This + * function also frees memory pointed by |conn| itself. This function + * does nothing if |conn| is NULL. */ NGHTTP3_EXTERN void nghttp3_conn_del(nghttp3_conn *conn); @@ -2000,8 +2071,8 @@ NGHTTP3_EXTERN void nghttp3_conn_del(nghttp3_conn *conn); * * :macro:`NGHTTP3_ERR_INVALID_STATE` * Control stream has already corresponding stream ID. - * - * TBD + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, int64_t stream_id); @@ -2010,7 +2081,7 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, * @function * * `nghttp3_conn_bind_qpack_streams` binds stream denoted by - * |qenc_stream_id| to outgoing QPACK encoder stream and stream + * |qenc_stream_id| to outgoing QPACK encoder stream, and stream * denoted by |qdec_stream_id| to outgoing QPACK encoder stream. * * This function returns 0 if it succeeds, or one of the following @@ -2019,8 +2090,8 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, * :macro:`NGHTTP3_ERR_INVALID_STATE` * QPACK encoder/decoder stream have already corresponding stream * IDs. - * - * TBD + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, int64_t qenc_stream_id, @@ -2038,6 +2109,18 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, * any control or QPACK unidirectional streams) . See * :type:`nghttp3_recv_data` to handle those bytes. If |fin| is * nonzero, this is the last data from remote endpoint in this stream. + * + * This function returns the number of bytes consumed, or one of the + * following negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` + * User callback failed. + * + * It may return the other error codes. In general, the negative + * error code means that |conn| encountered a connection error, and + * the connection should be closed. */ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, @@ -2048,18 +2131,30 @@ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, * @function * * `nghttp3_conn_writev_stream` stores stream data to send to |vec| of - * length |veccnt| and returns the number of nghttp3_vec object in + * length |veccnt|, and returns the number of nghttp3_vec object in * which it stored data. It stores stream ID to |*pstream_id|. An * application has to call `nghttp3_conn_add_write_offset` to inform * |conn| of the actual number of bytes that underlying QUIC stack * accepted. |*pfin| will be nonzero if this is the last data to * send. If there is no stream to write data or send fin, this * function returns 0, and -1 is assigned to |*pstream_id|. This - * function may return 0 and |*pstream_id| is not -1 and |*pfin| is - * nonzero. It means 0 length data to |*pstream_id| and it is the + * function may return 0, and |*pstream_id| is not -1, and |*pfin| is + * nonzero. It means 0 length data to |*pstream_id|, and it is the * last data to the stream. They must be passed to QUIC stack, and * they are accepted, the application has to call - * `nghttp3_conn_add_write_offset`. + * `nghttp3_conn_add_write_offset` with 0 byte. + * + * This function returns the number of bytes consumed, or one of the + * following negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` + * User callback failed. + * + * It may return the other error codes. In general, the negative + * error code means that |conn| encountered a connection error, and + * the connection should be closed. */ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id, @@ -2081,6 +2176,15 @@ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, * `nghttp3_conn_writev_stream` must be called before calling this * function to get data to send, and those data must be fed into QUIC * stack. + * + * If a stream denoted by |stream_id| is not found, this function + * returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_add_write_offset(nghttp3_conn *conn, int64_t stream_id, size_t n); @@ -2090,6 +2194,15 @@ NGHTTP3_EXTERN int nghttp3_conn_add_write_offset(nghttp3_conn *conn, * * `nghttp3_conn_add_ack_offset` tells |conn| the number of bytes |n| * for stream denoted by |stream_id| QUIC stack has acknowledged. + * + * If a stream denoted by |stream_id| is not found, this function + * returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` + * User callback failed. */ NGHTTP3_EXTERN int nghttp3_conn_add_ack_offset(nghttp3_conn *conn, int64_t stream_id, uint64_t n); @@ -2107,8 +2220,17 @@ NGHTTP3_EXTERN void nghttp3_conn_block_stream(nghttp3_conn *conn, * @function * * `nghttp3_conn_unblock_stream` tells the library that stream - * identified by |stream_id| which was blocked by QUIC flow control is - * unblocked. + * identified by |stream_id| which was blocked by QUIC flow control + * (see `nghttp3_conn_block_stream`) is unblocked. + * + * If a stream denoted by |stream_id| is not found, this function + * returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_unblock_stream(nghttp3_conn *conn, int64_t stream_id); @@ -2148,9 +2270,24 @@ NGHTTP3_EXTERN void nghttp3_conn_shutdown_stream_write(nghttp3_conn *conn, * @function * * `nghttp3_conn_shutdown_stream_read` tells the library that - * read-side of stream denoted by |stream_id| is abruptly closed and + * read-side of stream denoted by |stream_id| is abruptly closed, and * any further incoming data and pending stream data should be * discarded. + * + * If a stream denoted by |stream_id| is not client bidirectional + * stream, this function returns 0. If the stream has already + * shutdown read-side stream, this function returns 0. + * + * This function does not fail if a stream denoted by |stream_id| is + * not found, although it may fail with the other reasons. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. + * :macro:`NGHTTP3_ERR_QPACK_FATAL` + * QPACK decoder stream overflow. */ NGHTTP3_EXTERN int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id); @@ -2159,7 +2296,17 @@ NGHTTP3_EXTERN int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, * @function * * `nghttp3_conn_resume_stream` resumes stream identified by - * |stream_id| which was previously unable to provide data. + * |stream_id| which was previously unable to provide data. See + * :type:`nghttp3_read_data_callback`. + * + * If a stream denoted by |stream_id| is not found, this function + * returns 0. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_resume_stream(nghttp3_conn *conn, int64_t stream_id); @@ -2168,7 +2315,8 @@ NGHTTP3_EXTERN int nghttp3_conn_resume_stream(nghttp3_conn *conn, * @function * * `nghttp3_conn_close_stream` closes stream identified by - * |stream_id|. |app_error_code| is the reason of the closure. + * |stream_id|. QUIC application error code |app_error_code| is the + * reason of the closure. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2213,9 +2361,9 @@ NGHTTP3_EXTERN int nghttp3_conn_close_stream(nghttp3_conn *conn, * :macro:`NGHTTP3_DATA_FLAG_NO_END_STREAM` indicates that sending * side of stream is not closed even if :macro:`NGHTTP3_DATA_FLAG_EOF` * is set. Usually this flag is used to send trailer fields with - * `nghttp3_conn_submit_trailers()`. If - * `nghttp3_conn_submit_trailers()` has been called, regardless of - * this flag, the submitted trailer fields are sent. + * `nghttp3_conn_submit_trailers`. If `nghttp3_conn_submit_trailers` + * has been called, regardless of this flag, the submitted trailer + * fields are sent. */ #define NGHTTP3_DATA_FLAG_NO_END_STREAM 0x02u @@ -2260,8 +2408,8 @@ nghttp3_conn_set_max_concurrent_streams(nghttp3_conn *conn, * :macro:`NGHTTP3_DATA_FLAG_EOF` to |*pflags|. * * If the application is unable to provide data temporarily, return - * :macro:`NGHTTP3_ERR_WOULDBLOCK`. When it is ready to provide - * data, call `nghttp3_conn_resume_stream()`. + * :macro:`NGHTTP3_ERR_WOULDBLOCK`. When it is ready to provide data, + * call `nghttp3_conn_resume_stream`. * * The callback should return the number of objects in |vec| that the * application filled if it succeeds, or @@ -2298,6 +2446,18 @@ typedef struct nghttp3_data_reader { * request body, specify NULL. If |dr| is NULL, it implies the end of * stream. |stream_user_data| is an opaque pointer attached to the * stream. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * |stream_id| identifies unidirectional stream. + * :macro:`NGHTTP3_ERR_CONN_CLOSING` + * Connection is shutting down, and no new stream is allowed. + * :macro:`NGHTTP3_ERR_STREAM_IN_USE` + * Stream has already been opened. + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_submit_request( nghttp3_conn *conn, int64_t stream_id, const nghttp3_nv *nva, size_t nvlen, @@ -2309,6 +2469,14 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_request( * `nghttp3_conn_submit_info` submits HTTP non-final response header * fields on the stream identified by |stream_id|. |nva| of length * |nvlen| specifies HTTP response header fields. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_submit_info(nghttp3_conn *conn, int64_t stream_id, @@ -2323,6 +2491,14 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_info(nghttp3_conn *conn, * |nvlen| specifies HTTP response header fields. |dr| specifies a * response body. If there is no response body, specify NULL. If * |dr| is NULL, it implies the end of stream. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_submit_response(nghttp3_conn *conn, int64_t stream_id, @@ -2337,6 +2513,16 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_response(nghttp3_conn *conn, * stream identified by |stream_id|. |nva| of length |nvlen| * specifies HTTP trailer fields. Calling this function implies the * end of stream. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found + * :macro:`NGHTTP3_ERR_INVALID_STATE` + * Application has already submitted fin to stream. + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_submit_trailers(nghttp3_conn *conn, int64_t stream_id, @@ -2349,6 +2535,12 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_trailers(nghttp3_conn *conn, * `nghttp3_conn_submit_shutdown_notice` notifies the other endpoint * to stop creating new stream. After a couple of RTTs later, call * `nghttp3_conn_shutdown` to start graceful shutdown. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn); @@ -2357,9 +2549,15 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn); * * `nghttp3_conn_shutdown` starts graceful shutdown. It should be * called after `nghttp3_conn_submit_shutdown_notice` and a couple of - * RTT. After calling this function, the local endpoint starts + * RTTs. After calling this function, the local endpoint starts * rejecting new incoming streams. The existing streams are processed - * normally. + * normally. See also `nghttp3_conn_is_drained`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ NGHTTP3_EXTERN int nghttp3_conn_shutdown(nghttp3_conn *conn); @@ -2368,6 +2566,12 @@ NGHTTP3_EXTERN int nghttp3_conn_shutdown(nghttp3_conn *conn); * * `nghttp3_conn_set_stream_user_data` sets |stream_user_data| to the * stream identified by |stream_id|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found. */ NGHTTP3_EXTERN int nghttp3_conn_set_stream_user_data(nghttp3_conn *conn, int64_t stream_id, @@ -2378,7 +2582,9 @@ NGHTTP3_EXTERN int nghttp3_conn_set_stream_user_data(nghttp3_conn *conn, * * `nghttp3_conn_get_frame_payload_left` returns the number of bytes * left to read current frame payload for a stream denoted by - * |stream_id|. If no such stream is found, it returns 0. + * |stream_id|. If no such stream is found, or |stream_id| identifies + * neither client bidirectional stream nor remote control stream, it + * returns 0. */ NGHTTP3_EXTERN uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, int64_t stream_id); @@ -2417,12 +2623,15 @@ NGHTTP3_EXTERN uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, */ #define NGHTTP3_URGENCY_LEVELS (NGHTTP3_URGENCY_LOW + 1) +#define NGHTTP3_PRI_V1 1 +#define NGHTTP3_PRI_VERSION NGHTTP3_PRI_V1 + /** * @struct * * :type:`nghttp3_pri` represents HTTP priority. */ -typedef struct nghttp3_pri { +typedef struct NGHTTP3_ALIGN(8) nghttp3_pri { /** * :member:`urgency` is the urgency of a stream, it must be in * [:macro:`NGHTTP3_URGENCY_HIGH`, :macro:`NGHTTP3_URGENCY_LOW`], @@ -2431,11 +2640,11 @@ typedef struct nghttp3_pri { uint32_t urgency; /** * :member:`inc` indicates that a content can be processed - * incrementally or not. If inc is 0, it cannot be processed - * incrementally. If inc is 1, it can be processed incrementally. + * incrementally or not. If it is 0, it cannot be processed + * incrementally. If it is 1, it can be processed incrementally. * Other value is not permitted. */ - int inc; + uint8_t inc; } nghttp3_pri; /** @@ -2452,26 +2661,25 @@ typedef struct nghttp3_pri { * This function returns 0 if it succeeds, or one of the following * negative error codes: * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * |stream_id| is not a client initiated bidirectional stream ID. * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` * Stream not found. */ -NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, - nghttp3_pri *dest, - int64_t stream_id); +NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority_versioned( + nghttp3_conn *conn, int pri_version, nghttp3_pri *dest, int64_t stream_id); /** * @function * - * `nghttp3_conn_set_stream_priority` updates priority of a stream - * denoted by |stream_id| with the value pointed by |pri|. - * |stream_id| must identify client initiated bidirectional stream. - * - * Both client and server can update stream priority with this - * function. + * `nghttp3_conn_set_client_stream_priority` updates priority of a + * stream denoted by |stream_id| with the value pointed by |data| of + * length |datalen|, which should be a serialized :rfc:`9218` priority + * field value. |stream_id| must identify client initiated + * bidirectional stream. * - * If server updates stream priority with this function, it completely - * overrides stream priority set by client and the attempts to update - * priority by client are ignored. + * This function must not be called if |conn| is initialized as + * server. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2483,20 +2691,37 @@ NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory. */ -NGHTTP3_EXTERN int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, - int64_t stream_id, - const nghttp3_pri *pri); +NGHTTP3_EXTERN int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, + int64_t stream_id, + const uint8_t *data, + size_t datalen); /** * @function * - * `nghttp3_conn_is_remote_qpack_encoder_stream` returns nonzero if a - * stream denoted by |stream_id| is QPACK encoder stream of a remote - * endpoint. + * `nghttp3_conn_set_server_stream_priority` updates priority of a + * stream denoted by |stream_id| with the value pointed by |pri|. + * |stream_id| must identify client initiated bidirectional stream. + * + * This function must not be called if |conn| is initialized as + * client. + * + * This function completely overrides stream priority set by client, + * and any attempts to update priority by client are ignored. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * |stream_id| is not a client initiated bidirectional stream ID. + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found. + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. */ -NGHTTP3_EXTERN int -nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn *conn, - int64_t stream_id); +NGHTTP3_EXTERN int nghttp3_conn_set_server_stream_priority_versioned( + nghttp3_conn *conn, int64_t stream_id, int pri_version, + const nghttp3_pri *pri); /** * @function @@ -2509,11 +2734,11 @@ NGHTTP3_EXTERN uint64_t nghttp3_vec_len(const nghttp3_vec *vec, size_t cnt); /** * @function * - * `nghttp3_check_header_name` returns nonzero if HTTP header field - * name |name| of length |len| is valid according to + * `nghttp3_check_header_name` returns nonzero if HTTP field name + * |name| of length |len| is valid according to * :rfc:`7230#section-3.2`. * - * Because this is a header field name in HTTP/3, the upper cased + * Because this is an HTTP field name in HTTP/3, the upper cased * alphabet is treated as error. */ NGHTTP3_EXTERN int nghttp3_check_header_name(const uint8_t *name, size_t len); @@ -2521,8 +2746,8 @@ NGHTTP3_EXTERN int nghttp3_check_header_name(const uint8_t *name, size_t len); /** * @function * - * `nghttp3_check_header_value` returns nonzero if HTTP header field - * value |value| of length |len| is valid according to + * `nghttp3_check_header_value` returns nonzero if HTTP field value + * |value| of length |len| is valid according to * :rfc:`7230#section-3.2`. */ NGHTTP3_EXTERN int nghttp3_check_header_value(const uint8_t *value, size_t len); @@ -2530,21 +2755,34 @@ NGHTTP3_EXTERN int nghttp3_check_header_value(const uint8_t *value, size_t len); /** * @function * - * `nghttp3_http_parse_priority` parses priority HTTP header field - * stored in the buffer pointed by |value| of length |len|. If it - * successfully processed header field value, it stores the result - * into |*dest|. This function just overwrites what it sees in the - * header field value and does not initialize any field in |*dest|. + * `nghttp3_conn_is_drained` returns nonzero if + * `nghttp3_conn_shutdown` has been called, and there is no active + * remote streams. This function is for server use only. + */ +NGHTTP3_EXTERN int nghttp3_conn_is_drained(nghttp3_conn *conn); + +/** + * @function + * + * `nghttp3_pri_parse_priority` parses Priority header field value + * pointed by |value| of length |len|, and stores the result in the + * object pointed by |dest|. Priority header field is defined in + * :rfc:`9218`. + * + * This function does not initialize the object pointed by |dest| + * before storing the result. It only assigns the values that the + * parser correctly extracted to fields. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` - * The function could not parse the provided value. + * Failed to parse the header field value. */ -NGHTTP3_EXTERN int nghttp3_http_parse_priority(nghttp3_pri *dest, - const uint8_t *value, - size_t len); +NGHTTP3_EXTERN int nghttp3_pri_parse_priority_versioned(int pri_version, + nghttp3_pri *dest, + const uint8_t *value, + size_t len); /** * @macrosection @@ -2562,7 +2800,7 @@ NGHTTP3_EXTERN int nghttp3_http_parse_priority(nghttp3_pri *dest, /** * @struct * - * :type:`nghttp3_info` is what `nghttp3_version()` returns. It holds + * :type:`nghttp3_info` is what `nghttp3_version` returns. It holds * information about the particular nghttp3 version. */ typedef struct nghttp3_info { @@ -2574,7 +2812,7 @@ typedef struct nghttp3_info { int age; /** * :member:`version_num` is the :macro:`NGHTTP3_VERSION_NUM` number - * (since age ==1) + * (since age == 1) */ int version_num; /** @@ -2591,7 +2829,7 @@ typedef struct nghttp3_info { * `nghttp3_version` returns a pointer to a :type:`nghttp3_info` * struct with version information about the run-time library in use. * The |least_version| argument can be set to a 24 bit numerical value - * for the least accepted version number and if the condition is not + * for the least accepted version number, and if the condition is not * met, this function will return a ``NULL``. Pass in 0 to skip the * version checking. */ @@ -2639,6 +2877,33 @@ NGHTTP3_EXTERN int nghttp3_err_is_fatal(int liberr); (CALLBACKS), NGHTTP3_SETTINGS_VERSION, \ (SETTINGS), (MEM), (USER_DATA)) +/* + * `nghttp3_conn_set_server_stream_priority` is a wrapper around + * `nghttp3_conn_set_server_stream_priority_versioned` to set the + * correct struct version. + */ +#define nghttp3_conn_set_server_stream_priority(CONN, STREAM_ID, PRI) \ + nghttp3_conn_set_server_stream_priority_versioned( \ + (CONN), (STREAM_ID), NGHTTP3_PRI_VERSION, (PRI)) + +/* + * `nghttp3_conn_get_stream_priority` is a wrapper around + * `nghttp3_conn_get_stream_priority_versioned` to set the correct + * struct version. + */ +#define nghttp3_conn_get_stream_priority(CONN, DEST, STREAM_ID) \ + nghttp3_conn_get_stream_priority_versioned((CONN), NGHTTP3_PRI_VERSION, \ + (DEST), (STREAM_ID)) + +/* + * `nghttp3_pri_parse_priority` is a wrapper around + * `nghttp3_pri_parse_priority_versioned` to set the correct struct + * version. + */ +#define nghttp3_pri_parse_priority(DEST, VALUE, LEN) \ + nghttp3_pri_parse_priority_versioned(NGHTTP3_PRI_VERSION, (DEST), (VALUE), \ + (LEN)) + #ifdef __cplusplus } #endif diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c index 1fbb72c98af2f2..25aaf685734cb1 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c @@ -33,11 +33,14 @@ #include "nghttp3_err.h" #include "nghttp3_conv.h" #include "nghttp3_http.h" +#include "nghttp3_unreachable.h" /* NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY is the upper bound of the dynamic table capacity that QPACK encoder is willing to use. */ #define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096 +nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent); + /* * conn_remote_stream_uni returns nonzero if |stream_id| is remote * unidirectional stream ID. @@ -56,7 +59,7 @@ static int conn_call_begin_headers(nghttp3_conn *conn, nghttp3_stream *stream) { return 0; } - rv = conn->callbacks.begin_headers(conn, stream->node.nid.id, conn->user_data, + rv = conn->callbacks.begin_headers(conn, stream->node.id, conn->user_data, stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ @@ -74,8 +77,8 @@ static int conn_call_end_headers(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.end_headers(conn, stream->node.nid.id, fin, - conn->user_data, stream->user_data); + rv = conn->callbacks.end_headers(conn, stream->node.id, fin, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -92,8 +95,8 @@ static int conn_call_begin_trailers(nghttp3_conn *conn, return 0; } - rv = conn->callbacks.begin_trailers(conn, stream->node.nid.id, - conn->user_data, stream->user_data); + rv = conn->callbacks.begin_trailers(conn, stream->node.id, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -110,8 +113,8 @@ static int conn_call_end_trailers(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.end_trailers(conn, stream->node.nid.id, fin, - conn->user_data, stream->user_data); + rv = conn->callbacks.end_trailers(conn, stream->node.id, fin, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -127,7 +130,7 @@ static int conn_call_end_stream(nghttp3_conn *conn, nghttp3_stream *stream) { return 0; } - rv = conn->callbacks.end_stream(conn, stream->node.nid.id, conn->user_data, + rv = conn->callbacks.end_stream(conn, stream->node.id, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -144,7 +147,7 @@ static int conn_call_stop_sending(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.stop_sending(conn, stream->node.nid.id, app_error_code, + rv = conn->callbacks.stop_sending(conn, stream->node.id, app_error_code, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -161,7 +164,7 @@ static int conn_call_reset_stream(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.reset_stream(conn, stream->node.nid.id, app_error_code, + rv = conn->callbacks.reset_stream(conn, stream->node.id, app_error_code, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -179,7 +182,7 @@ static int conn_call_deferred_consume(nghttp3_conn *conn, return 0; } - rv = conn->callbacks.deferred_consume(conn, stream->node.nid.id, nconsumed, + rv = conn->callbacks.deferred_consume(conn, stream->node.id, nconsumed, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -188,6 +191,22 @@ static int conn_call_deferred_consume(nghttp3_conn *conn, return 0; } +static int conn_call_recv_settings(nghttp3_conn *conn) { + int rv; + + if (!conn->callbacks.recv_settings) { + return 0; + } + + rv = conn->callbacks.recv_settings(conn, &conn->remote.settings, + conn->user_data); + if (rv != 0) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + + return 0; +} + static int ricnt_less(const nghttp3_pq_entry *lhsx, const nghttp3_pq_entry *rhsx) { nghttp3_stream *lhs = @@ -204,7 +223,7 @@ static int cycle_less(const nghttp3_pq_entry *lhsx, const nghttp3_tnode *rhs = nghttp3_struct_of(rhsx, nghttp3_tnode, pe); if (lhs->cycle == rhs->cycle) { - return lhs->seq < rhs->seq; + return lhs->id < rhs->id; } return rhs->cycle - lhs->cycle <= NGHTTP3_TNODE_MAX_CYCLE_GAP; @@ -264,7 +283,6 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, nghttp3_settings_default(&conn->remote.settings); conn->mem = mem; conn->user_data = user_data; - conn->next_seq = 0; conn->server = server; conn->rx.goaway_id = NGHTTP3_VARINT_MAX + 1; conn->tx.goaway_id = NGHTTP3_VARINT_MAX + 1; @@ -454,12 +472,6 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; } } - } else if (nghttp3_stream_uni(stream_id) && - stream->type == NGHTTP3_STREAM_TYPE_PUSH) { - if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) { - stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; - stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; - } } if (srclen == 0 && !fin) { @@ -603,8 +615,7 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream, } break; default: - /* unreachable */ - assert(0); + nghttp3_unreachable(); } if (nconsumed < 0) { @@ -686,6 +697,11 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, case NGHTTP3_FRAME_SETTINGS: /* SETTINGS frame might be empty. */ if (rstate->left == 0) { + rv = conn_call_recv_settings(conn); + if (rv != 0) { + return rv; + } + nghttp3_stream_read_state_reset(rstate); break; } @@ -735,11 +751,21 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, } break; case NGHTTP3_CTRL_STREAM_STATE_SETTINGS: - for (; p != end;) { + for (;;) { if (rstate->left == 0) { + rv = conn_call_recv_settings(conn); + if (rv != 0) { + return rv; + } + nghttp3_stream_read_state_reset(rstate); break; } + + if (p == end) { + return (nghttp3_ssize)nconsumed; + } + /* Read Identifier */ len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p)); assert(len > 0); @@ -845,6 +871,11 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, break; } + rv = conn_call_recv_settings(conn); + if (rv != 0) { + return rv; + } + nghttp3_stream_read_state_reset(rstate); break; case NGHTTP3_CTRL_STREAM_STATE_GOAWAY: @@ -1013,8 +1044,7 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, nghttp3_stream_read_state_reset(rstate); break; default: - /* unreachable */ - assert(0); + nghttp3_unreachable(); } } @@ -1022,7 +1052,7 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, } static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) { - int bidi = nghttp3_client_stream_bidi(stream->node.nid.id); + int bidi = nghttp3_client_stream_bidi(stream->node.id); int rv; rv = conn_call_deferred_consume(conn, stream, @@ -1032,16 +1062,21 @@ static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) { } if (bidi && conn->callbacks.stream_close) { - rv = conn->callbacks.stream_close(conn, stream->node.nid.id, - stream->error_code, conn->user_data, - stream->user_data); + rv = conn->callbacks.stream_close(conn, stream->node.id, stream->error_code, + conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; } } - rv = nghttp3_map_remove(&conn->streams, - (nghttp3_map_key_type)stream->node.nid.id); + if (conn->server && nghttp3_client_stream_bidi(stream->node.id)) { + assert(conn->remote.bidi.num_streams > 0); + + --conn->remote.bidi.num_streams; + } + + rv = + nghttp3_map_remove(&conn->streams, (nghttp3_map_key_type)stream->node.id); assert(0 == rv); @@ -1058,7 +1093,7 @@ static int conn_process_blocked_stream_data(nghttp3_conn *conn, int rv; size_t len; - assert(nghttp3_client_stream_bidi(stream->node.nid.id)); + assert(nghttp3_client_stream_bidi(stream->node.id)); for (;;) { len = nghttp3_ringbuf_len(&stream->inq); @@ -1149,16 +1184,17 @@ static nghttp3_tnode *stream_get_sched_node(nghttp3_stream *stream) { } static int conn_update_stream_priority(nghttp3_conn *conn, - nghttp3_stream *stream, uint8_t pri) { - assert(nghttp3_client_stream_bidi(stream->node.nid.id)); + nghttp3_stream *stream, + const nghttp3_pri *pri) { + assert(nghttp3_client_stream_bidi(stream->node.id)); - if (stream->node.pri == pri) { + if (nghttp3_pri_eq(&stream->node.pri, pri)) { return 0; } nghttp3_conn_unschedule_stream(conn, stream); - stream->node.pri = pri; + stream->node.pri = *pri; if (nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_schedule_stream(conn, stream); @@ -1286,8 +1322,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = conn_call_begin_trailers(conn, stream); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } if (rv != 0) { @@ -1377,9 +1412,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = 0; break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { @@ -1398,7 +1431,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_PRIORITY) && !(stream->flags & NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED) && !(stream->flags & NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET)) { - rv = conn_update_stream_priority(conn, stream, stream->rx.http.pri); + rv = conn_update_stream_priority(conn, stream, &stream->rx.http.pri); if (rv != 0) { return rv; } @@ -1412,8 +1445,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = conn_call_end_trailers(conn, stream, p == end && fin); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } if (rv != 0) { @@ -1505,7 +1537,7 @@ int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.recv_data(conn, stream->node.nid.id, data, datalen, + rv = conn->callbacks.recv_data(conn, stream->node.id, data, datalen, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -1515,11 +1547,9 @@ int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream, } static nghttp3_pq *conn_get_sched_pq(nghttp3_conn *conn, nghttp3_tnode *tnode) { - uint32_t urgency = nghttp3_pri_uint8_urgency(tnode->pri); + assert(tnode->pri.urgency < NGHTTP3_URGENCY_LEVELS); - assert(urgency < NGHTTP3_URGENCY_LEVELS); - - return &conn->sched[urgency].spq; + return &conn->sched[tnode->pri.urgency].spq; } static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, @@ -1552,8 +1582,7 @@ static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, recv_header = conn->callbacks.recv_trailer; break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } http = &stream->rx.http; @@ -1606,17 +1635,15 @@ static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, break; case 0: if (recv_header) { - rv = recv_header(conn, stream->node.nid.id, nv.token, nv.name, - nv.value, nv.flags, conn->user_data, - stream->user_data); + rv = recv_header(conn, stream->node.id, nv.token, nv.name, nv.value, + nv.flags, conn->user_data, stream->user_data); if (rv != 0) { rv = NGHTTP3_ERR_CALLBACK_FAILURE; } } break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } nghttp3_rcbuf_decref(nv.name); @@ -1684,13 +1711,32 @@ int nghttp3_conn_on_settings_entry_received(nghttp3_conn *conn, if (!conn->server) { break; } - if (ent->value != 0 && ent->value != 1) { + + switch (ent->value) { + case 0: + if (dest->enable_connect_protocol) { + return NGHTTP3_ERR_H3_SETTINGS_ERROR; + } + + break; + case 1: + break; + default: return NGHTTP3_ERR_H3_SETTINGS_ERROR; } - if (ent->value == 0 && dest->enable_connect_protocol) { + + dest->enable_connect_protocol = (uint8_t)ent->value; + break; + case NGHTTP3_SETTINGS_ID_H3_DATAGRAM: + switch (ent->value) { + case 0: + case 1: + break; + default: return NGHTTP3_ERR_H3_SETTINGS_ERROR; } - dest->enable_connect_protocol = (int)ent->value; + + dest->h3_datagram = (uint8_t)ent->value; break; case NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH: case NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS: @@ -1744,7 +1790,7 @@ conn_on_priority_update_stream(nghttp3_conn *conn, return rv; } - stream->node.pri = nghttp3_pri_to_uint8(&fr->pri); + stream->node.pri = fr->pri; stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; return 0; @@ -1756,8 +1802,7 @@ conn_on_priority_update_stream(nghttp3_conn *conn, stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; - return conn_update_stream_priority(conn, stream, - nghttp3_pri_to_uint8(&fr->pri)); + return conn_update_stream_priority(conn, stream, &fr->pri); } int nghttp3_conn_on_priority_update(nghttp3_conn *conn, @@ -1794,7 +1839,7 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream, conn_stream_acked_data, }; - rv = nghttp3_stream_new(&stream, stream_id, conn->next_seq, &callbacks, + rv = nghttp3_stream_new(&stream, stream_id, &callbacks, &conn->out_chunk_objalloc, &conn->stream_objalloc, conn->mem); if (rv != 0) { @@ -1803,14 +1848,17 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream, stream->conn = conn; - rv = nghttp3_map_insert(&conn->streams, - (nghttp3_map_key_type)stream->node.nid.id, stream); + rv = nghttp3_map_insert(&conn->streams, (nghttp3_map_key_type)stream->node.id, + stream); if (rv != 0) { nghttp3_stream_del(stream); return rv; } - ++conn->next_seq; + if (conn->server && nghttp3_client_stream_bidi(stream_id)) { + ++conn->remote.bidi.num_streams; + } + *pstream = stream; return 0; @@ -1897,7 +1945,7 @@ static nghttp3_ssize conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id, int *pfin, nghttp3_vec *vec, size_t veccnt, nghttp3_stream *stream) { int rv; - nghttp3_ssize n; + size_t n; assert(veccnt > 0); @@ -1910,31 +1958,25 @@ static nghttp3_ssize conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id, } } - if (!nghttp3_stream_uni(stream->node.nid.id) && conn->tx.qenc && + if (!nghttp3_stream_uni(stream->node.id) && conn->tx.qenc && !nghttp3_stream_is_blocked(conn->tx.qenc)) { n = nghttp3_stream_writev(conn->tx.qenc, pfin, vec, veccnt); - if (n < 0) { - return n; - } if (n) { - *pstream_id = conn->tx.qenc->node.nid.id; - return n; + *pstream_id = conn->tx.qenc->node.id; + return (nghttp3_ssize)n; } } n = nghttp3_stream_writev(stream, pfin, vec, veccnt); - if (n < 0) { - return n; - } /* We might just want to write stream fin without sending any stream data. */ if (n == 0 && *pfin == 0) { return 0; } - *pstream_id = stream->node.nid.id; + *pstream_id = stream->node.id; - return n; + return (nghttp3_ssize)n; } nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, @@ -1990,7 +2032,7 @@ nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, return ncnt; } - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && !nghttp3_stream_require_schedule(stream)) { nghttp3_conn_unschedule_stream(conn, stream); } @@ -2020,20 +2062,16 @@ nghttp3_stream *nghttp3_conn_get_next_tx_stream(nghttp3_conn *conn) { int nghttp3_conn_add_write_offset(nghttp3_conn *conn, int64_t stream_id, size_t n) { nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id); - int rv; if (stream == NULL) { return 0; } - rv = nghttp3_stream_add_outq_offset(stream, n); - if (rv != 0) { - return rv; - } + nghttp3_stream_add_outq_offset(stream, n); stream->unscheduled_nwrite += n; - if (!nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (!nghttp3_client_stream_bidi(stream->node.id)) { return 0; } @@ -2065,7 +2103,7 @@ static int conn_submit_headers_data(nghttp3_conn *conn, nghttp3_stream *stream, const nghttp3_data_reader *dr) { int rv; nghttp3_nv *nnva; - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; rv = nghttp3_nva_copy(&nnva, nva, nvlen, conn->mem); if (rv != 0) { @@ -2235,7 +2273,7 @@ int nghttp3_conn_submit_trailers(nghttp3_conn *conn, int64_t stream_id, } int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) { - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; int rv; assert(conn->tx.ctrl); @@ -2258,7 +2296,7 @@ int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) { } int nghttp3_conn_shutdown(nghttp3_conn *conn) { - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; int rv; assert(conn->tx.ctrl); @@ -2279,7 +2317,8 @@ int nghttp3_conn_shutdown(nghttp3_conn *conn) { } conn->tx.goaway_id = frent.fr.goaway.id; - conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_QUEUED; + conn->flags |= + NGHTTP3_CONN_FLAG_GOAWAY_QUEUED | NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED; return 0; } @@ -2305,7 +2344,7 @@ void nghttp3_conn_block_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags |= NGHTTP3_STREAM_FLAG_FC_BLOCKED; stream->unscheduled_nwrite = 0; - if (nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (nghttp3_client_stream_bidi(stream->node.id)) { nghttp3_conn_unschedule_stream(conn, stream); } } @@ -2320,7 +2359,7 @@ void nghttp3_conn_shutdown_stream_write(nghttp3_conn *conn, int64_t stream_id) { stream->flags |= NGHTTP3_STREAM_FLAG_SHUT_WR; stream->unscheduled_nwrite = 0; - if (nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (nghttp3_client_stream_bidi(stream->node.id)) { nghttp3_conn_unschedule_stream(conn, stream); } } @@ -2334,7 +2373,7 @@ int nghttp3_conn_unblock_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_FC_BLOCKED; - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_ensure_stream_scheduled(conn, stream); } @@ -2364,7 +2403,7 @@ int nghttp3_conn_resume_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED; - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_ensure_stream_scheduled(conn, stream); } @@ -2381,7 +2420,6 @@ int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id, } if (nghttp3_stream_uni(stream_id) && - stream->type != NGHTTP3_STREAM_TYPE_PUSH && stream->type != NGHTTP3_STREAM_TYPE_UNKNOWN) { return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM; } @@ -2459,18 +2497,34 @@ int nghttp3_conn_set_stream_user_data(nghttp3_conn *conn, int64_t stream_id, uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, int64_t stream_id) { - nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id); + nghttp3_stream *stream; + int uni = 0; + + if (!nghttp3_client_stream_bidi(stream_id)) { + uni = conn_remote_stream_uni(conn, stream_id); + if (!uni) { + return 0; + } + } + stream = nghttp3_conn_find_stream(conn, stream_id); if (stream == NULL) { return 0; } + if (uni && stream->type != NGHTTP3_STREAM_TYPE_CONTROL) { + return 0; + } + return (uint64_t)stream->rstate.left; } -int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, nghttp3_pri *dest, - int64_t stream_id) { +int nghttp3_conn_get_stream_priority_versioned(nghttp3_conn *conn, + int pri_version, + nghttp3_pri *dest, + int64_t stream_id) { nghttp3_stream *stream; + (void)pri_version; assert(conn->server); @@ -2483,19 +2537,20 @@ int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, nghttp3_pri *dest, return NGHTTP3_ERR_STREAM_NOT_FOUND; } - dest->urgency = nghttp3_pri_uint8_urgency(stream->node.pri); - dest->inc = nghttp3_pri_uint8_inc(stream->node.pri); + *dest = stream->node.pri; return 0; } -int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, int64_t stream_id, - const nghttp3_pri *pri) { +int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, + int64_t stream_id, + const uint8_t *data, + size_t datalen) { nghttp3_stream *stream; - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; + uint8_t *buf = NULL; - assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); - assert(pri->inc == 0 || pri->inc == 1); + assert(!conn->server); if (!nghttp3_client_stream_bidi(stream_id)) { return NGHTTP3_ERR_INVALID_ARGUMENT; @@ -2506,29 +2561,55 @@ int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, int64_t stream_id, return NGHTTP3_ERR_STREAM_NOT_FOUND; } - if (conn->server) { - stream->flags |= NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET; + if (datalen) { + buf = nghttp3_mem_malloc(conn->mem, datalen); + if (buf == NULL) { + return NGHTTP3_ERR_NOMEM; + } - return conn_update_stream_priority(conn, stream, nghttp3_pri_to_uint8(pri)); + memcpy(buf, data, datalen); } frent.fr.hd.type = NGHTTP3_FRAME_PRIORITY_UPDATE; frent.fr.priority_update.pri_elem_id = stream_id; - frent.fr.priority_update.pri = *pri; + frent.fr.priority_update.data = buf; + frent.fr.priority_update.datalen = datalen; return nghttp3_stream_frq_add(conn->tx.ctrl, &frent); } -int nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn *conn, - int64_t stream_id) { +int nghttp3_conn_set_server_stream_priority_versioned(nghttp3_conn *conn, + int64_t stream_id, + int pri_version, + const nghttp3_pri *pri) { nghttp3_stream *stream; + (void)pri_version; - if (!conn_remote_stream_uni(conn, stream_id)) { - return 0; + assert(conn->server); + assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); + assert(pri->inc == 0 || pri->inc == 1); + + if (!nghttp3_client_stream_bidi(stream_id)) { + return NGHTTP3_ERR_INVALID_ARGUMENT; } stream = nghttp3_conn_find_stream(conn, stream_id); - return stream && stream->type == NGHTTP3_STREAM_TYPE_QPACK_ENCODER; + if (stream == NULL) { + return NGHTTP3_ERR_STREAM_NOT_FOUND; + } + + stream->flags |= NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET; + + return conn_update_stream_priority(conn, stream, pri); +} + +int nghttp3_conn_is_drained(nghttp3_conn *conn) { + assert(conn->server); + + return (conn->flags & NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED) && + conn->remote.bidi.num_streams == 0 && + nghttp3_stream_outq_write_done(conn->tx.ctrl) && + nghttp3_ringbuf_len(&conn->tx.ctrl->frq) == 0; } void nghttp3_settings_default_versioned(int settings_version, diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h index fa7071e4b1ddb7..74f47583ce825c 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h @@ -62,6 +62,9 @@ /* NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED is set when a QPACK decoder stream has opened. */ #define NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED 0x0008u +/* NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED is set when graceful shutdown + has started. */ +#define NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED 0x0010u /* NGHTTP3_CONN_FLAG_GOAWAY_RECVED indicates that GOAWAY frame has received. */ #define NGHTTP3_CONN_FLAG_GOAWAY_RECVED 0x0020u @@ -73,7 +76,7 @@ typedef struct nghttp3_chunk { nghttp3_opl_entry oplent; } nghttp3_chunk; -nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent); +nghttp3_objalloc_decl(chunk, nghttp3_chunk, oplent); struct nghttp3_conn { nghttp3_objalloc out_chunk_objalloc; @@ -90,7 +93,6 @@ struct nghttp3_conn { void *user_data; int server; uint16_t flags; - uint64_t next_seq; struct { nghttp3_settings settings; @@ -109,6 +111,10 @@ struct nghttp3_conn { initiated bidirectional stream ID the remote endpoint can issue. This field is used on server side only. */ uint64_t max_client_streams; + /* num_streams is the number of client initiated bidirectional + streams that are currently open. This field is for server + use only. */ + size_t num_streams; } bidi; nghttp3_settings settings; } remote; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c index cb340ab5a11363..edd0adc4d0ff0a 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c @@ -29,6 +29,7 @@ #include #include "nghttp3_str.h" +#include "nghttp3_unreachable.h" int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { union { @@ -38,7 +39,7 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { uint64_t n64; } n; - *plen = 1u << (*p >> 6); + *plen = (size_t)(1u << (*p >> 6)); switch (*plen) { case 1: @@ -57,34 +58,25 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { return (int64_t)nghttp3_ntohl64(n.n64); } - assert(0); - abort(); + nghttp3_unreachable(); } int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; } -size_t nghttp3_get_varint_len(const uint8_t *p) { return 1u << (*p >> 6); } +size_t nghttp3_get_varintlen(const uint8_t *p) { + return (size_t)(1u << (*p >> 6)); +} uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n) { n = nghttp3_htonl64(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n) { - n = nghttp3_htonl64(n); - return nghttp3_cpymem(p, ((const uint8_t *)&n) + 2, 6); -} - uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n) { n = htonl(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *nghttp3_put_uint24be(uint8_t *p, uint32_t n) { - n = htonl(n); - return nghttp3_cpymem(p, ((const uint8_t *)&n) + 1, 3); -} - uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n) { n = htons(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); @@ -112,7 +104,7 @@ uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n) { return rv; } -size_t nghttp3_put_varint_len(int64_t n) { +size_t nghttp3_put_varintlen(int64_t n) { if (n < 64) { return 1; } @@ -129,7 +121,3 @@ size_t nghttp3_put_varint_len(int64_t n) { uint64_t nghttp3_ord_stream_id(int64_t stream_id) { return (uint64_t)(stream_id >> 2) + 1; } - -uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri) { - return (uint8_t)((uint32_t)pri->inc << 7 | pri->urgency); -} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h index 23555be7cac027..5522bc735bfd37 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h @@ -50,15 +50,11 @@ # include #endif /* HAVE_SYS_ENDIAN_H */ -#include +#if defined(__APPLE__) +# include +#endif // __APPLE__ -#if defined(HAVE_BSWAP_64) || \ - (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) -# define nghttp3_bswap64 bswap_64 -#else /* !HAVE_BSWAP_64 */ -# define nghttp3_bswap64(N) \ - ((uint64_t)(ntohl((uint32_t)(N))) << 32 | ntohl((uint32_t)((N) >> 32))) -#endif /* !HAVE_BSWAP_64 */ +#include #if defined(HAVE_BE64TOH) || \ (defined(HAVE_DECL_BE64TOH) && HAVE_DECL_BE64TOH > 0) @@ -69,6 +65,17 @@ # define nghttp3_ntohl64(N) (N) # define nghttp3_htonl64(N) (N) # else /* !WORDS_BIGENDIAN */ +# if defined(HAVE_BSWAP_64) || \ + (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) +# define nghttp3_bswap64 bswap_64 +# elif defined(WIN32) +# define nghttp3_bswap64 _byteswap_uint64 +# elif defined(__APPLE__) +# define nghttp3_bswap64 OSSwapInt64 +# else /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ +# define nghttp3_bswap64(N) \ + ((uint64_t)(ntohl((uint32_t)(N))) << 32 | ntohl((uint32_t)((N) >> 32))) +# endif /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ # define nghttp3_ntohl64(N) nghttp3_bswap64(N) # define nghttp3_htonl64(N) nghttp3_bswap64(N) # endif /* !WORDS_BIGENDIAN */ @@ -106,9 +113,9 @@ STIN uint16_t htons(uint16_t hostshort) { STIN uint32_t ntohl(uint32_t netlong) { uint32_t res; unsigned char *p = (unsigned char *)&netlong; - res = *p++ << 24; - res += *p++ << 16; - res += *p++ << 8; + res = (uint32_t)(*p++ << 24); + res += (uint32_t)(*p++ << 16); + res += (uint32_t)(*p++ << 8); res += *p; return res; } @@ -116,7 +123,7 @@ STIN uint32_t ntohl(uint32_t netlong) { STIN uint16_t ntohs(uint16_t netshort) { uint16_t res; unsigned char *p = (unsigned char *)&netshort; - res = *p++ << 8; + res = (uint16_t)(*p++ << 8); res += *p; return res; } @@ -137,10 +144,10 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p); int64_t nghttp3_get_varint_fb(const uint8_t *p); /* - * nghttp3_get_varint_len returns the required number of bytes to read + * nghttp3_get_varintlen returns the required number of bytes to read * variable-length integer starting at |p|. */ -size_t nghttp3_get_varint_len(const uint8_t *p); +size_t nghttp3_get_varintlen(const uint8_t *p); /* * nghttp3_put_uint64be writes |n| in host byte order in |p| in @@ -149,13 +156,6 @@ size_t nghttp3_get_varint_len(const uint8_t *p); */ uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n); -/* - * nghttp3_put_uint48be writes |n| in host byte order in |p| in - * network byte order. It writes only least significant 48 bits. It - * returns the one beyond of the last written position. - */ -uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n); - /* * nghttp3_put_uint32be writes |n| in host byte order in |p| in * network byte order. It returns the one beyond of the last written @@ -163,13 +163,6 @@ uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n); */ uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n); -/* - * nghttp3_put_uint24be writes |n| in host byte order in |p| in - * network byte order. It writes only least significant 24 bits. It - * returns the one beyond of the last written position. - */ -uint8_t *nghttp3_put_uint24be(uint8_t *p, uint32_t n); - /* * nghttp3_put_uint16be writes |n| in host byte order in |p| in * network byte order. It returns the one beyond of the last written @@ -184,10 +177,10 @@ uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n); uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n); /* - * nghttp3_put_varint_len returns the required number of bytes to + * nghttp3_put_varintlen returns the required number of bytes to * encode |n|. */ -size_t nghttp3_put_varint_len(int64_t n); +size_t nghttp3_put_varintlen(int64_t n); /* * nghttp3_ord_stream_id returns the ordinal number of |stream_id|. @@ -200,22 +193,4 @@ uint64_t nghttp3_ord_stream_id(int64_t stream_id); */ #define NGHTTP3_PRI_INC_MASK (1 << 7) -/* - * nghttp3_pri_to_uint8 encodes |pri| into uint8_t variable. - */ -uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri); - -/* - * nghttp3_pri_uint8_urgency extracts urgency from |PRI| which is - * supposed to be constructed by nghttp3_pri_to_uint8. - */ -#define nghttp3_pri_uint8_urgency(PRI) \ - ((uint32_t)((PRI) & ~NGHTTP3_PRI_INC_MASK)) - -/* - * nghttp3_pri_uint8_inc extracts inc from |PRI| which is supposed to - * be constructed by nghttp3_pri_to_uint8. - */ -#define nghttp3_pri_uint8_inc(PRI) (((PRI)&NGHTTP3_PRI_INC_MASK) != 0) - #endif /* NGHTTP3_CONV_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_err.c b/deps/ngtcp2/nghttp3/lib/nghttp3_err.c index 5cf94db852f71f..0d596bfab6d29d 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_err.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_err.c @@ -28,8 +28,6 @@ const char *nghttp3_strerror(int liberr) { switch (liberr) { case NGHTTP3_ERR_INVALID_ARGUMENT: return "ERR_INVALID_ARGUMENT"; - case NGHTTP3_ERR_NOBUF: - return "ERR_NOBUF"; case NGHTTP3_ERR_INVALID_STATE: return "ERR_INVALID_STATE"; case NGHTTP3_ERR_WOULDBLOCK: @@ -104,6 +102,9 @@ uint64_t nghttp3_err_infer_quic_app_error_code(int liberr) { case NGHTTP3_ERR_H3_INTERNAL_ERROR: case NGHTTP3_ERR_NOMEM: case NGHTTP3_ERR_CALLBACK_FAILURE: + case NGHTTP3_ERR_QPACK_FATAL: + case NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE: + case NGHTTP3_ERR_STREAM_DATA_OVERFLOW: return NGHTTP3_H3_INTERNAL_ERROR; case NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM: return NGHTTP3_H3_CLOSED_CRITICAL_STREAM; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c index 38c395ebe16162..923a78f90f826f 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c @@ -38,7 +38,7 @@ uint8_t *nghttp3_frame_write_hd(uint8_t *p, const nghttp3_frame_hd *hd) { } size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd) { - return nghttp3_put_varint_len(hd->type) + nghttp3_put_varint_len(hd->length); + return nghttp3_put_varintlen(hd->type) + nghttp3_put_varintlen(hd->length); } uint8_t *nghttp3_frame_write_settings(uint8_t *p, @@ -61,14 +61,14 @@ size_t nghttp3_frame_write_settings_len(int64_t *ppayloadlen, size_t i; for (i = 0; i < fr->niv; ++i) { - payloadlen += nghttp3_put_varint_len((int64_t)fr->iv[i].id) + - nghttp3_put_varint_len((int64_t)fr->iv[i].value); + payloadlen += nghttp3_put_varintlen((int64_t)fr->iv[i].id) + + nghttp3_put_varintlen((int64_t)fr->iv[i].value); } *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(NGHTTP3_FRAME_SETTINGS) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(NGHTTP3_FRAME_SETTINGS) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } uint8_t *nghttp3_frame_write_goaway(uint8_t *p, @@ -81,12 +81,12 @@ uint8_t *nghttp3_frame_write_goaway(uint8_t *p, size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen, const nghttp3_frame_goaway *fr) { - size_t payloadlen = nghttp3_put_varint_len(fr->id); + size_t payloadlen = nghttp3_put_varintlen(fr->id); *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(NGHTTP3_FRAME_GOAWAY) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(NGHTTP3_FRAME_GOAWAY) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } uint8_t * @@ -94,17 +94,8 @@ nghttp3_frame_write_priority_update(uint8_t *p, const nghttp3_frame_priority_update *fr) { p = nghttp3_frame_write_hd(p, &fr->hd); p = nghttp3_put_varint(p, fr->pri_elem_id); - - assert(fr->pri.urgency <= NGHTTP3_URGENCY_LOW); - - *p++ = 'u'; - *p++ = '='; - *p++ = (uint8_t)('0' + fr->pri.urgency); - - if (fr->pri.inc) { -#define NGHTTP3_PRIORITY_INCREMENTAL ", i" - p = nghttp3_cpymem(p, (const uint8_t *)NGHTTP3_PRIORITY_INCREMENTAL, - sizeof(NGHTTP3_PRIORITY_INCREMENTAL) - 1); + if (fr->datalen) { + p = nghttp3_cpymem(p, fr->data, fr->datalen); } return p; @@ -112,13 +103,12 @@ nghttp3_frame_write_priority_update(uint8_t *p, size_t nghttp3_frame_write_priority_update_len( int64_t *ppayloadlen, const nghttp3_frame_priority_update *fr) { - size_t payloadlen = nghttp3_put_varint_len(fr->pri_elem_id) + sizeof("u=U") - - 1 + (fr->pri.inc ? sizeof(", i") - 1 : 0); + size_t payloadlen = nghttp3_put_varintlen(fr->pri_elem_id) + fr->datalen; *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(fr->hd.type) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(fr->hd.type) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } int nghttp3_nva_copy(nghttp3_nv **pnva, const nghttp3_nv *nva, size_t nvlen, @@ -164,11 +154,11 @@ int nghttp3_nva_copy(nghttp3_nv **pnva, const nghttp3_nv *nva, size_t nvlen, } else { if (nva[i].namelen) { memcpy(data, nva[i].name, nva[i].namelen); + nghttp3_downcase(data, nva[i].namelen); } p->name = data; p->namelen = nva[i].namelen; data[p->namelen] = '\0'; - nghttp3_downcase(p->name, p->namelen); data += nva[i].namelen + 1; } @@ -202,3 +192,12 @@ void nghttp3_frame_headers_free(nghttp3_frame_headers *fr, nghttp3_nva_del(fr->nva, mem); } + +void nghttp3_frame_priority_update_free(nghttp3_frame_priority_update *fr, + const nghttp3_mem *mem) { + if (fr == NULL) { + return; + } + + nghttp3_mem_free(mem, fr->data); +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h index b64bbc4ecb9667..1079673d150ce3 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h @@ -34,26 +34,23 @@ #include "nghttp3_buf.h" -typedef enum nghttp3_frame_type { - NGHTTP3_FRAME_DATA = 0x00, - NGHTTP3_FRAME_HEADERS = 0x01, - NGHTTP3_FRAME_CANCEL_PUSH = 0x03, - NGHTTP3_FRAME_SETTINGS = 0x04, - NGHTTP3_FRAME_PUSH_PROMISE = 0x05, - NGHTTP3_FRAME_GOAWAY = 0x07, - NGHTTP3_FRAME_MAX_PUSH_ID = 0x0d, - /* PRIORITY_UPDATE: - https://tools.ietf.org/html/draft-ietf-httpbis-priority-03 */ - NGHTTP3_FRAME_PRIORITY_UPDATE = 0x0f0700, - NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID = 0x0f0701, -} nghttp3_frame_type; - -typedef enum nghttp3_h2_reserved_type { - NGHTTP3_H2_FRAME_PRIORITY = 0x02, - NGHTTP3_H2_FRAME_PING = 0x06, - NGHTTP3_H2_FRAME_WINDOW_UPDATE = 0x08, - NGHTTP3_H2_FRAME_CONTINUATION = 0x9, -} nghttp3_h2_reserved_type; +#define NGHTTP3_FRAME_DATA 0x00 +#define NGHTTP3_FRAME_HEADERS 0x01 +#define NGHTTP3_FRAME_CANCEL_PUSH 0x03 +#define NGHTTP3_FRAME_SETTINGS 0x04 +#define NGHTTP3_FRAME_PUSH_PROMISE 0x05 +#define NGHTTP3_FRAME_GOAWAY 0x07 +#define NGHTTP3_FRAME_MAX_PUSH_ID 0x0d +/* PRIORITY_UPDATE: https://datatracker.ietf.org/doc/html/rfc9218 */ +#define NGHTTP3_FRAME_PRIORITY_UPDATE 0x0f0700 +#define NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID 0x0f0701 + +/* Frame types that are reserved for HTTP/2, and must not be used in + HTTP/3. */ +#define NGHTTP3_H2_FRAME_PRIORITY 0x02 +#define NGHTTP3_H2_FRAME_PING 0x06 +#define NGHTTP3_H2_FRAME_WINDOW_UPDATE 0x08 +#define NGHTTP3_H2_FRAME_CONTINUATION 0x9 typedef struct nghttp3_frame_hd { int64_t type; @@ -74,6 +71,7 @@ typedef struct nghttp3_frame_headers { #define NGHTTP3_SETTINGS_ID_QPACK_MAX_TABLE_CAPACITY 0x01 #define NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS 0x07 #define NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL 0x08 +#define NGHTTP3_SETTINGS_ID_H3_DATAGRAM 0x33 #define NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH 0x2 #define NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS 0x3 @@ -103,7 +101,17 @@ typedef struct nghttp3_frame_priority_update { NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID. It is undefined otherwise. */ int64_t pri_elem_id; - nghttp3_pri pri; + /* When sending this frame, data should point to the buffer + containing a serialized priority field value and its length is + set to datalen. On reception, pri contains the decoded priority + header value. */ + union { + nghttp3_pri pri; + struct { + uint8_t *data; + size_t datalen; + }; + }; } nghttp3_frame_priority_update; typedef union nghttp3_frame { @@ -212,4 +220,11 @@ void nghttp3_nva_del(nghttp3_nv *nva, const nghttp3_mem *mem); void nghttp3_frame_headers_free(nghttp3_frame_headers *fr, const nghttp3_mem *mem); +/* + * nghttp3_frame_priority_update_free frees memory allocated for |fr|. + * This function should only be called for an outgoing frame. + */ +void nghttp3_frame_priority_update_free(nghttp3_frame_priority_update *fr, + const nghttp3_mem *mem); + #endif /* NGHTTP3_FRAME_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c index 5e06d8c47658e1..963134f13df946 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c @@ -31,6 +31,8 @@ #include "nghttp3_stream.h" #include "nghttp3_macro.h" #include "nghttp3_conv.h" +#include "nghttp3_unreachable.h" +#include "sfparse.h" static uint8_t downcase(uint8_t c) { return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; @@ -105,722 +107,74 @@ static int check_path_flags(nghttp3_http_state *http) { (http->flags & NGHTTP3_HTTP_FLAG_PATH_ASTERISK))); } -/* Generated by genchartbl.py */ -static const int SF_KEY_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */, - 0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */, - 0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, - 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */, - 0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */, - 0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_key(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_KEY_CHARS[*p]; ++p) - ; - - return p - begin; -} - -static nghttp3_ssize sf_parse_integer_or_decimal(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int sign = 1; - int64_t value = 0; - int type = NGHTTP3_SF_VALUE_TYPE_INTEGER; - size_t len = 0; - size_t fpos = 0; - size_t i; - - if (*p == '-') { - if (++p == end) { - return -1; - } - - sign = -1; - } - - if (*p < '0' || '9' < *p) { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - value *= 10; - value += *p - '0'; - - if (++len > 15) { - return -1; - } - - break; - case '.': - if (type != NGHTTP3_SF_VALUE_TYPE_INTEGER) { - goto fin; - } - - if (len > 12) { - return -1; - } - fpos = len; - type = NGHTTP3_SF_VALUE_TYPE_DECIMAL; - - break; - default: - goto fin; - }; - } - -fin: - switch (type) { - case NGHTTP3_SF_VALUE_TYPE_INTEGER: - if (dest) { - dest->type = (uint8_t)type; - dest->i = value * sign; - } - - return p - begin; - case NGHTTP3_SF_VALUE_TYPE_DECIMAL: - if (fpos == len || len - fpos > 3) { - return -1; - } - - if (dest) { - dest->type = (uint8_t)type; - dest->d = (double)value; - for (i = len - fpos; i > 0; --i) { - dest->d /= (double)10; - } - dest->d *= sign; - } - - return p - begin; - default: - assert(0); - abort(); - } -} - -/* Generated by genchartbl.py */ -static const int SF_DQUOTE_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */, - 1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_string(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != '"') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '\\': - if (++p == end) { - return -1; - } - - switch (*p) { - case '"': - case '\\': - break; - default: - return -1; - } - - break; - case '"': - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_STRING; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_DQUOTE_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -/* Generated by genchartbl.py */ -static const int SF_TOKEN_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */, - 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_token(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_TOKEN_CHARS[*p]; ++p) - ; - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_TOKEN; - dest->s.base = begin; - dest->s.len = (size_t)(p - begin); - } - - return p - begin; -} - -/* Generated by genchartbl.py */ -static const int SF_BYTESEQ_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */, - 0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_byteseq(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != ':') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case ':': - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_BYTESEQ; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_BYTESEQ_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -static nghttp3_ssize sf_parse_boolean(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int b; - - if (*p++ != '?') { - return -1; - } - - if (p == end) { - return -1; - } - - switch (*p++) { - case '0': - b = 0; - break; - case '1': - b = 1; - break; - default: - return -1; - } - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN; - dest->b = b; - } - - return p - begin; -} - -static nghttp3_ssize sf_parse_bare_item(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - switch (*begin) { - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return sf_parse_integer_or_decimal(dest, begin, end); - case '"': - return sf_parse_string(dest, begin, end); - case '*': - return sf_parse_token(dest, begin, end); - case ':': - return sf_parse_byteseq(dest, begin, end); - case '?': - return sf_parse_boolean(dest, begin, end); +static int is_ws(uint8_t c) { + switch (c) { + case ' ': + case '\t': + return 1; default: - if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) { - return sf_parse_token(dest, begin, end); - } - return -1; - } -} - -#define sf_discard_sp_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ') { \ - break; \ - } \ - } - -static nghttp3_ssize sf_parse_params(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - for (; p != end && *p == ';';) { - ++p; - - sf_discard_sp_end_err(p, end, -1); - - slen = sf_parse_key(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - } else if (++p == end) { - return -1; - } else { - slen = sf_parse_bare_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - } - } - - return p - begin; -} - -static nghttp3_ssize sf_parse_item(nghttp3_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - slen = sf_parse_bare_item(dest, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - return p - begin; -} - -nghttp3_ssize nghttp3_sf_parse_item(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - return sf_parse_item(dest, begin, end); -} - -static nghttp3_ssize sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - if (*p++ != '(') { - return -1; - } - - for (;;) { - sf_discard_sp_end_err(p, end, -1); - - if (*p == ')') { - ++p; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_INNER_LIST; - } - - return p - begin; - } - - slen = sf_parse_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || (*p != ' ' && *p != ')')) { - return -1; - } - } -} - -nghttp3_ssize nghttp3_sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - return sf_parse_inner_list(dest, begin, end); -} - -static nghttp3_ssize sf_parse_item_or_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - if (*begin == '(') { - return sf_parse_inner_list(dest, begin, end); + return 0; } - - return sf_parse_item(dest, begin, end); } -#define sf_discard_ows(BEGIN, END) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - goto fin; \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - -#define sf_discard_ows_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, size_t valuelen) { - const uint8_t *p = value, *end = value + valuelen; - nghttp3_ssize slen; - nghttp3_sf_value val; nghttp3_pri pri = *dest; - const uint8_t *key; - size_t keylen; + sf_parser sfp; + sf_vec key; + sf_value val; + int rv; - for (; p != end && *p == ' '; ++p) - ; + sf_parser_init(&sfp, value, valuelen); + + for (;;) { + rv = sf_parser_dict(&sfp, &key, &val); + if (rv != 0) { + if (rv == SF_ERR_EOF) { + break; + } - for (; p != end;) { - slen = sf_parse_key(p, end); - if (slen < 0) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - key = p; - keylen = (size_t)slen; - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - val.type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN; - val.b = 1; + if (key.len != 1) { + continue; + } - slen = sf_parse_params(p, end); - if (slen < 0) { + switch (key.base[0]) { + case 'i': + if (val.type != SF_TYPE_BOOLEAN) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - } else if (++p == end) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } else { - slen = sf_parse_item_or_inner_list(&val, p, end); - if (slen < 0) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - } - - p += slen; - - if (keylen == 1) { - switch (key[0]) { - case 'i': - if (val.type != NGHTTP3_SF_VALUE_TYPE_BOOLEAN) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - - pri.inc = val.b; - - break; - case 'u': - if (val.type != NGHTTP3_SF_VALUE_TYPE_INTEGER || - val.i < NGHTTP3_URGENCY_HIGH || NGHTTP3_URGENCY_LOW < val.i) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - pri.urgency = (uint32_t)val.i; + pri.inc = (uint8_t)val.boolean; - break; + break; + case 'u': + if (val.type != SF_TYPE_INTEGER || val.integer < NGHTTP3_URGENCY_HIGH || + NGHTTP3_URGENCY_LOW < val.integer) { + return NGHTTP3_ERR_INVALID_ARGUMENT; } - } - sf_discard_ows(p, end); + pri.urgency = (uint32_t)val.integer; - if (*p++ != ',') { - return NGHTTP3_ERR_INVALID_ARGUMENT; + break; } - - sf_discard_ows_end_err(p, end, NGHTTP3_ERR_INVALID_ARGUMENT); } -fin: *dest = pri; return 0; } +int nghttp3_pri_parse_priority_versioned(int pri_version, nghttp3_pri *dest, + const uint8_t *value, + size_t valuelen) { + (void)pri_version; + + return nghttp3_http_parse_priority(dest, value, valuelen); +} + static int http_request_on_header(nghttp3_http_state *http, nghttp3_qpack_nv *nv, int trailers, int connect_protocol) { @@ -931,11 +285,10 @@ static int http_request_on_header(nghttp3_http_state *http, break; case NGHTTP3_QPACK_TOKEN_PRIORITY: if (!trailers && !(http->flags & NGHTTP3_HTTP_FLAG_BAD_PRIORITY)) { - pri.urgency = nghttp3_pri_uint8_urgency(http->pri); - pri.inc = nghttp3_pri_uint8_inc(http->pri); + pri = http->pri; if (nghttp3_http_parse_priority(&pri, nv->value->base, nv->value->len) == 0) { - http->pri = nghttp3_pri_to_uint8(&pri); + http->pri = pri; http->flags |= NGHTTP3_HTTP_FLAG_PRIORITY; } else { http->flags &= ~NGHTTP3_HTTP_FLAG_PRIORITY; @@ -1637,10 +990,9 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) { case 0: return 1; case 1: - return !(*value == ' ' || *value == '\t'); + return !is_ws(*value); default: - if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || - *(value + len - 1) == '\t') { + if (is_ws(*value) || is_ws(*(value + len - 1))) { return 0; } } @@ -1652,3 +1004,7 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) { } return 1; } + +int nghttp3_pri_eq(const nghttp3_pri *a, const nghttp3_pri *b) { + return a->urgency == b->urgency && a->inc == b->inc; +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.h b/deps/ngtcp2/nghttp3/lib/nghttp3_http.h index 1617348ad14d78..575d9c267e1b68 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.h @@ -150,53 +150,24 @@ int nghttp3_http_on_data_chunk(nghttp3_stream *stream, size_t n); void nghttp3_http_record_request_method(nghttp3_stream *stream, const nghttp3_nv *nva, size_t nvlen); -/* - * RFC 8941 Structured Field Values. - */ -typedef enum nghttp3_sf_value_type { - NGHTTP3_SF_VALUE_TYPE_BOOLEAN, - NGHTTP3_SF_VALUE_TYPE_INTEGER, - NGHTTP3_SF_VALUE_TYPE_DECIMAL, - NGHTTP3_SF_VALUE_TYPE_STRING, - NGHTTP3_SF_VALUE_TYPE_TOKEN, - NGHTTP3_SF_VALUE_TYPE_BYTESEQ, - NGHTTP3_SF_VALUE_TYPE_INNER_LIST, -} nghttp3_sf_value_type; - -/* - * nghttp3_sf_value stores Structured Field Values item. For Inner - * List, only type is set to NGHTTP3_SF_VALUE_TYPE_INNER_LIST. - */ -typedef struct nghttp3_sf_value { - uint8_t type; - union { - int b; - int64_t i; - double d; - struct { - const uint8_t *base; - size_t len; - } s; - }; -} nghttp3_sf_value; - -/* - * nghttp3_sf_parse_item parses the input sequence [|begin|, |end|) - * and stores the parsed an Item in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. +/** + * @function + * + * `nghttp3_http_parse_priority` parses priority HTTP header field + * stored in the buffer pointed by |value| of length |len|. If it + * successfully processed header field value, it stores the result + * into |*dest|. This function just overwrites what it sees in the + * header field value and does not initialize any field in |*dest|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * The function could not parse the provided value. */ -nghttp3_ssize nghttp3_sf_parse_item(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end); +int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, + size_t len); -/* - * nghttp3_sf_parse_inner_list parses the input sequence [|begin|, |end|) - * and stores the parsed an Inner List in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. - */ -nghttp3_ssize nghttp3_sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end); +int nghttp3_pri_eq(const nghttp3_pri *a, const nghttp3_pri *b); #endif /* NGHTTP3_HTTP_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c index adea677abe1f1c..d7420a5d8a1e5d 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c @@ -36,6 +36,8 @@ static nghttp3_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}}; +nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent); + static size_t ksl_nodelen(size_t keylen) { return (sizeof(nghttp3_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) & ~(uintptr_t)0xfu; @@ -722,6 +724,24 @@ void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key, } } +size_t nghttp3_ksl_len(nghttp3_ksl *ksl) { return ksl->n; } + +void nghttp3_ksl_clear(nghttp3_ksl *ksl) { + if (!ksl->head) { + return; + } + +#ifdef NOMEMPOOL + ksl_free_blk(ksl, ksl->head); +#endif /* NOMEMPOOL */ + + ksl->front = ksl->back = ksl->head = NULL; + ksl->n = 0; + + nghttp3_objalloc_clear(&ksl->blkalloc); +} + +#ifndef WIN32 static void ksl_print(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t level) { size_t i; nghttp3_ksl_node *node; @@ -742,23 +762,6 @@ static void ksl_print(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t level) { } } -size_t nghttp3_ksl_len(nghttp3_ksl *ksl) { return ksl->n; } - -void nghttp3_ksl_clear(nghttp3_ksl *ksl) { - if (!ksl->head) { - return; - } - -#ifdef NOMEMPOOL - ksl_free_blk(ksl, ksl->head); -#endif /* NOMEMPOOL */ - - ksl->front = ksl->back = ksl->head = NULL; - ksl->n = 0; - - nghttp3_objalloc_clear(&ksl->blkalloc); -} - void nghttp3_ksl_print(nghttp3_ksl *ksl) { if (!ksl->head) { return; @@ -766,6 +769,7 @@ void nghttp3_ksl_print(nghttp3_ksl *ksl) { ksl_print(ksl, ksl->head, 0); } +#endif /* !WIN32 */ nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl) { nghttp3_ksl_it it; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h index 0bc10e846fe418..d513bdd672c750 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h @@ -108,7 +108,7 @@ struct nghttp3_ksl_blk { }; }; -nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent); +nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent); /* * nghttp3_ksl_compar is a function type which returns nonzero if key @@ -265,12 +265,14 @@ void nghttp3_ksl_clear(nghttp3_ksl *ksl); #define nghttp3_ksl_nth_node(KSL, BLK, N) \ ((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) +#ifndef WIN32 /* * nghttp3_ksl_print prints its internal state in stderr. It assumes * that the key is of type int64_t. This function should be used for * the debugging purpose only. */ void nghttp3_ksl_print(nghttp3_ksl *ksl); +#endif /* !WIN32 */ /* * nghttp3_ksl_it_init initializes |it|. diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_map.c b/deps/ngtcp2/nghttp3/lib/nghttp3_map.c index fcfc31ae41e8e0..b93fdfd3d488f5 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_map.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_map.c @@ -127,6 +127,7 @@ static void map_bucket_set_data(nghttp3_map_bucket *bkt, uint32_t hash, bkt->data = data; } +#ifndef WIN32 void nghttp3_map_print_distance(nghttp3_map *map) { uint32_t i; size_t idx; @@ -146,6 +147,7 @@ void nghttp3_map_print_distance(nghttp3_map *map) { distance(map->tablelen, map->tablelenbits, bkt, idx)); } } +#endif /* !WIN32 */ static int insert(nghttp3_map_bucket *table, uint32_t tablelen, uint32_t tablelenbits, uint32_t hash, diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_map.h b/deps/ngtcp2/nghttp3/lib/nghttp3_map.h index 79dff0286bc3cc..7683cfeef3f33e 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_map.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_map.h @@ -132,6 +132,8 @@ size_t nghttp3_map_size(nghttp3_map *map); int nghttp3_map_each(nghttp3_map *map, int (*func)(void *data, void *ptr), void *ptr); +#ifndef WIN32 void nghttp3_map_print_distance(nghttp3_map *map); +#endif /* !WIN32 */ #endif /* NGHTTP3_MAP_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_objalloc.h b/deps/ngtcp2/nghttp3/lib/nghttp3_objalloc.h index da39447a872b02..02dff285f24060 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_objalloc.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_objalloc.h @@ -66,15 +66,25 @@ void nghttp3_objalloc_free(nghttp3_objalloc *objalloc); void nghttp3_objalloc_clear(nghttp3_objalloc *objalloc); #ifndef NOMEMPOOL -# define nghttp3_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define nghttp3_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ inline static void nghttp3_objalloc_##NAME##_init( \ nghttp3_objalloc *objalloc, size_t nmemb, const nghttp3_mem *mem) { \ nghttp3_objalloc_init( \ objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \ } \ \ - inline static TYPE *nghttp3_objalloc_##NAME##_get( \ - nghttp3_objalloc *objalloc) { \ + TYPE *nghttp3_objalloc_##NAME##_get(nghttp3_objalloc *objalloc); \ + \ + TYPE *nghttp3_objalloc_##NAME##_len_get(nghttp3_objalloc *objalloc, \ + size_t len); \ + \ + inline static void nghttp3_objalloc_##NAME##_release( \ + nghttp3_objalloc *objalloc, TYPE *obj) { \ + nghttp3_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ + } + +# define nghttp3_objalloc_def(NAME, TYPE, OPLENTFIELD) \ + TYPE *nghttp3_objalloc_##NAME##_get(nghttp3_objalloc *objalloc) { \ nghttp3_opl_entry *oplent = nghttp3_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -92,8 +102,8 @@ void nghttp3_objalloc_clear(nghttp3_objalloc *objalloc); return nghttp3_struct_of(oplent, TYPE, OPLENTFIELD); \ } \ \ - inline static TYPE *nghttp3_objalloc_##NAME##_len_get( \ - nghttp3_objalloc *objalloc, size_t len) { \ + TYPE *nghttp3_objalloc_##NAME##_len_get(nghttp3_objalloc *objalloc, \ + size_t len) { \ nghttp3_opl_entry *oplent = nghttp3_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -108,14 +118,9 @@ void nghttp3_objalloc_clear(nghttp3_objalloc *objalloc); } \ \ return nghttp3_struct_of(oplent, TYPE, OPLENTFIELD); \ - } \ - \ - inline static void nghttp3_objalloc_##NAME##_release( \ - nghttp3_objalloc *objalloc, TYPE *obj) { \ - nghttp3_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ } #else /* NOMEMPOOL */ -# define nghttp3_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define nghttp3_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ inline static void nghttp3_objalloc_##NAME##_init( \ nghttp3_objalloc *objalloc, size_t nmemb, const nghttp3_mem *mem) { \ nghttp3_objalloc_init( \ @@ -136,6 +141,8 @@ void nghttp3_objalloc_clear(nghttp3_objalloc *objalloc); nghttp3_objalloc *objalloc, TYPE *obj) { \ nghttp3_mem_free(objalloc->balloc.mem, obj); \ } + +# define nghttp3_objalloc_def(NAME, TYPE, OPLENTFIELD) #endif /* NOMEMPOOL */ #endif /* NGHTTP3_OBJALLOC_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c index ddb3dd6d84bf8a..428c06a82c6bfb 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c @@ -32,6 +32,7 @@ #include "nghttp3_str.h" #include "nghttp3_macro.h" #include "nghttp3_debug.h" +#include "nghttp3_unreachable.h" /* NGHTTP3_QPACK_MAX_QPACK_STREAMS is the maximum number of concurrent nghttp3_qpack_stream object to handle a client which never cancel @@ -1099,7 +1100,7 @@ static void qpack_encoder_remove_stream(nghttp3_qpack_encoder *encoder, /* * reserve_buf_internal ensures that |buf| contains at least * |extra_size| of free space. In other words, if this function - * succeeds, nghttp2_buf_left(buf) >= extra_size holds. |min_size| is + * succeeds, nghttp3_buf_left(buf) >= extra_size holds. |min_size| is * the minimum size of buffer. The allocated buffer has at least * |min_size| bytes. * @@ -1281,6 +1282,19 @@ int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder, return stream && encoder->krcnt < nghttp3_qpack_stream_get_max_cnt(stream); } +static uint32_t qpack_hash_name(const nghttp3_nv *nv) { + /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */ + uint32_t h = 2166136261u; + size_t i; + + for (i = 0; i < nv->namelen; ++i) { + h ^= nv->name[i]; + h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); + } + + return h; +} + /* * qpack_encoder_decide_indexing_mode determines and returns indexing * mode for header field |nv|. |token| is a token of header field @@ -1310,6 +1324,10 @@ qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH: case NGHTTP3_QPACK_TOKEN_LOCATION: case NGHTTP3_QPACK_TOKEN_SET_COOKIE: + if (nv->flags & NGHTTP3_NV_FLAG_TRY_INDEX) { + break; + } + return NGHTTP3_QPACK_INDEXING_MODE_LITERAL; case NGHTTP3_QPACK_TOKEN_HOST: case NGHTTP3_QPACK_TOKEN_TE: @@ -1317,6 +1335,10 @@ qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_PRIORITY: break; default: + if (nv->flags & NGHTTP3_NV_FLAG_TRY_INDEX) { + break; + } + if (token >= 1000) { return NGHTTP3_QPACK_INDEXING_MODE_LITERAL; } @@ -1428,6 +1450,17 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, token = qpack_lookup_token(nv->name, nv->namelen); static_entry = token != -1 && (size_t)token < nghttp3_arraylen(token_stable); + + indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token); + + if (static_entry) { + sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode); + if (sres.index != -1 && sres.name_value_match) { + return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf, + (size_t)sres.index); + } + } + if (static_entry) { hash = token_stable[token].hash; } else { @@ -1444,21 +1477,12 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_PRIORITY: hash = 2498028297u; break; + default: + hash = qpack_hash_name(nv); } } - indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token); - - if (static_entry) { - sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode); - if (sres.index != -1 && sres.name_value_match) { - return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf, - (size_t)sres.index); - } - } - - if (hash && - nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) { + if (nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) { dres = nghttp3_qpack_encoder_lookup_dtable(encoder, nv, token, hash, indexing_mode, encoder->krcnt, allow_blocking); @@ -2552,18 +2576,14 @@ nghttp3_ssize nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder *encoder, (int64_t)encoder->rstate.left); break; default: - /* unreachable */ - assert(0); - break; + nghttp3_unreachable(); } encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE; nghttp3_qpack_read_state_reset(&encoder->rstate); break; default: - /* unreachable */ - assert(0); - break; + nghttp3_unreachable(); } } @@ -2838,24 +2858,26 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, goto fail; } - if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_DUPLICATE) { + switch (decoder->opcode) { + case NGHTTP3_QPACK_ES_OPCODE_DUPLICATE: rv = nghttp3_qpack_decoder_dtable_duplicate_add(decoder); if (rv != 0) { goto fail; } + decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE; nghttp3_qpack_read_state_reset(&decoder->rstate); - break; - } - if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED) { + break; + case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED: decoder->rstate.prefix = 7; decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN; + break; + default: + nghttp3_unreachable(); } - /* Unreachable */ - assert(0); break; case NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN: qpack_read_state_check_huffman(&decoder->rstate, *p); @@ -3010,9 +3032,7 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, rv = nghttp3_qpack_decoder_dtable_literal_add(decoder); break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { goto fail; @@ -3045,9 +3065,7 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, rv = nghttp3_qpack_decoder_dtable_literal_add(decoder); break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { goto fail; @@ -3430,8 +3448,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN; break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } break; case NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN: @@ -3589,8 +3606,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT; @@ -3627,8 +3643,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c index 5e7775f1a5a597..61a7d06cad306f 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c @@ -33,7 +33,8 @@ #include "nghttp3_macro.h" -#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64)) +#if defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_ARM) || defined(_M_ARM64)) unsigned int __popcnt(unsigned int x) { unsigned int c = 0; for (; x; ++c) { diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c index e655a7ec01d10b..6188a141dd123b 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c @@ -35,6 +35,7 @@ #include "nghttp3_str.h" #include "nghttp3_http.h" #include "nghttp3_vec.h" +#include "nghttp3_unreachable.h" /* NGHTTP3_STREAM_MAX_COPY_THRES is the maximum size of buffer which makes a copy to outq. */ @@ -43,13 +44,14 @@ /* NGHTTP3_MIN_RBLEN is the minimum length of nghttp3_ringbuf */ #define NGHTTP3_MIN_RBLEN 4 +nghttp3_objalloc_def(stream, nghttp3_stream, oplent); + int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, - uint64_t seq, const nghttp3_stream_callbacks *callbacks, + const nghttp3_stream_callbacks *callbacks, nghttp3_objalloc *out_chunk_objalloc, nghttp3_objalloc *stream_objalloc, const nghttp3_mem *mem) { nghttp3_stream *stream = nghttp3_objalloc_stream_get(stream_objalloc); - nghttp3_node_id nid; if (stream == NULL) { return NGHTTP3_ERR_NOMEM; @@ -60,10 +62,7 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, stream->out_chunk_objalloc = out_chunk_objalloc; stream->stream_objalloc = stream_objalloc; - nghttp3_tnode_init( - &stream->node, - nghttp3_node_id_init(&nid, NGHTTP3_NODE_ID_TYPE_STREAM, stream_id), seq, - NGHTTP3_DEFAULT_URGENCY); + nghttp3_tnode_init(&stream->node, stream_id); nghttp3_ringbuf_init(&stream->frq, 0, sizeof(nghttp3_frame_entry), mem); nghttp3_ringbuf_init(&stream->chunks, 0, sizeof(nghttp3_buf), mem); @@ -77,7 +76,7 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, stream->tx.offset = 0; stream->rx.http.status_code = -1; stream->rx.http.content_length = -1; - stream->rx.http.pri = NGHTTP3_DEFAULT_URGENCY; + stream->rx.http.pri.urgency = NGHTTP3_DEFAULT_URGENCY; stream->error_code = NGHTTP3_H3_NO_ERROR; if (callbacks) { @@ -146,6 +145,9 @@ static void delete_frq(nghttp3_ringbuf *frq, const nghttp3_mem *mem) { case NGHTTP3_FRAME_HEADERS: nghttp3_frame_headers_free(&frent->fr.headers, mem); break; + case NGHTTP3_FRAME_PRIORITY_UPDATE: + nghttp3_frame_priority_update_free(&frent->fr.priority_update, mem); + break; default: break; } @@ -188,7 +190,7 @@ nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint, if (rvint->left == 0) { assert(rvint->acc == 0); - rvint->left = nghttp3_get_varint_len(src); + rvint->left = nghttp3_get_varintlen(src); if (rvint->left <= srclen) { rvint->acc = nghttp3_get_varint(&nread, src); rvint->left = 0; @@ -248,7 +250,7 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { int data_eof; int rv; - for (; nghttp3_ringbuf_len(frq) && !nghttp3_stream_outq_is_full(stream) && + for (; nghttp3_ringbuf_len(frq) && stream->unsent_bytes < NGHTTP3_MIN_UNSENT_BYTES;) { frent = nghttp3_ringbuf_get(frq, 0); @@ -289,6 +291,8 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { if (rv != 0) { return rv; } + nghttp3_frame_priority_update_free(&frent->fr.priority_update, + stream->mem); break; default: /* TODO Not implemented */ @@ -308,7 +312,7 @@ static void typed_buf_shared_init(nghttp3_typed_buf *tbuf, } int nghttp3_stream_write_stream_type(nghttp3_stream *stream) { - size_t len = nghttp3_put_varint_len((int64_t)stream->type); + size_t len = nghttp3_put_varintlen((int64_t)stream->type); nghttp3_buf *chunk; nghttp3_typed_buf tbuf; int rv; @@ -351,10 +355,18 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream, iv[2].id = NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS; iv[2].value = local_settings->qpack_blocked_streams; + if (local_settings->h3_datagram) { + iv[fr.settings.niv].id = NGHTTP3_SETTINGS_ID_H3_DATAGRAM; + iv[fr.settings.niv].value = 1; + + ++fr.settings.niv; + } + if (local_settings->enable_connect_protocol) { + iv[fr.settings.niv].id = NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL; + iv[fr.settings.niv].value = 1; + ++fr.settings.niv; - iv[3].id = NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL; - iv[3].value = 1; } len = nghttp3_frame_write_settings_len(&fr.settings.hd.length, &fr.settings); @@ -453,8 +465,8 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, nghttp3_buf_wrap_init(&pbuf, raw_pbuf, sizeof(raw_pbuf)); - rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, - stream->node.nid.id, nva, nvlen); + rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, stream->node.id, + nva, nvlen); if (rv != 0) { goto fail; } @@ -574,8 +586,8 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, *peof = 0; - sveccnt = read_data(conn, stream->node.nid.id, vec, nghttp3_arraylen(vec), - &flags, conn->user_data, stream->user_data); + sveccnt = read_data(conn, stream->node.id, vec, nghttp3_arraylen(vec), &flags, + conn->user_data, stream->user_data); if (sveccnt < 0) { if (sveccnt == NGHTTP3_ERR_WOULDBLOCK) { stream->flags |= NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED; @@ -691,11 +703,6 @@ int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream) { return nghttp3_stream_outq_add(stream, &tbuf); } -int nghttp3_stream_outq_is_full(nghttp3_stream *stream) { - /* TODO Verify that the limit is reasonable. */ - return nghttp3_ringbuf_len(&stream->outq) >= 1024; -} - int nghttp3_stream_outq_add(nghttp3_stream *stream, const nghttp3_typed_buf *tbuf) { nghttp3_ringbuf *outq = &stream->outq; @@ -809,11 +816,11 @@ int nghttp3_stream_require_schedule(nghttp3_stream *stream) { !(stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED)); } -nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, - nghttp3_vec *vec, size_t veccnt) { +size_t nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, + nghttp3_vec *vec, size_t veccnt) { nghttp3_ringbuf *outq = &stream->outq; size_t len = nghttp3_ringbuf_len(outq); - size_t i; + size_t i = stream->outq_idx; uint64_t offset = stream->outq_offset; size_t buflen; nghttp3_vec *vbegin = vec, *vend = vec + veccnt; @@ -821,25 +828,27 @@ nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, assert(veccnt > 0); - for (i = stream->outq_idx; i < len; ++i) { + if (i < len) { tbuf = nghttp3_ringbuf_get(outq, i); buflen = nghttp3_buf_len(&tbuf->buf); - if (offset >= buflen) { - offset -= buflen; - continue; + + if (offset < buflen) { + vec->base = tbuf->buf.pos + offset; + vec->len = (size_t)(buflen - offset); + ++vec; + } else { + /* This is the only case that satisfies offset >= buflen */ + assert(0 == offset); + assert(0 == buflen); } - vec->base = tbuf->buf.pos + offset; - vec->len = (size_t)(buflen - offset); - ++vec; ++i; - break; - } - for (; i < len && vec != vend; ++i, ++vec) { - tbuf = nghttp3_ringbuf_get(outq, i); - vec->base = tbuf->buf.pos; - vec->len = nghttp3_buf_len(&tbuf->buf); + for (; i < len && vec != vend; ++i, ++vec) { + tbuf = nghttp3_ringbuf_get(outq, i); + vec->base = tbuf->buf.pos; + vec->len = nghttp3_buf_len(&tbuf->buf); + } } /* TODO Rework this if we have finished implementing HTTP @@ -847,10 +856,10 @@ nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, *pfin = nghttp3_ringbuf_len(&stream->frq) == 0 && i == len && (stream->flags & NGHTTP3_STREAM_FLAG_WRITE_END_STREAM); - return vec - vbegin; + return (size_t)(vec - vbegin); } -int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) { +void nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) { nghttp3_ringbuf *outq = &stream->outq; size_t i; size_t len = nghttp3_ringbuf_len(outq); @@ -874,8 +883,6 @@ int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) { stream->unsent_bytes -= n; stream->outq_idx = i; stream->outq_offset = offset; - - return 0; } int nghttp3_stream_outq_write_done(nghttp3_stream *stream) { @@ -885,8 +892,8 @@ int nghttp3_stream_outq_write_done(nghttp3_stream *stream) { return len == 0 || stream->outq_idx >= len; } -static int stream_pop_outq_entry(nghttp3_stream *stream, - nghttp3_typed_buf *tbuf) { +static void stream_pop_outq_entry(nghttp3_stream *stream, + nghttp3_typed_buf *tbuf) { nghttp3_ringbuf *chunks = &stream->chunks; nghttp3_buf *chunk; @@ -915,13 +922,10 @@ static int stream_pop_outq_entry(nghttp3_stream *stream, } break; default: - assert(0); - abort(); + nghttp3_unreachable(); }; nghttp3_ringbuf_pop_front(&stream->outq); - - return 0; } int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n) { @@ -940,7 +944,7 @@ int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n) { if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN) { nack = nghttp3_min(offset, (uint64_t)buflen) - stream->ack_done; if (stream->callbacks.acked_data) { - rv = stream->callbacks.acked_data(stream, stream->node.nid.id, nack, + rv = stream->callbacks.acked_data(stream, stream->node.id, nack, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -950,10 +954,7 @@ int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n) { } if (offset >= buflen) { - rv = stream_pop_outq_entry(stream, tbuf); - if (rv != 0) { - return rv; - } + stream_pop_outq_entry(stream, tbuf); offset -= buflen; ++npopped; @@ -1221,8 +1222,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, case NGHTTP3_HTTP_STATE_RESP_END: return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; default: - assert(0); - abort(); + nghttp3_unreachable(); } } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h index 06292738a17e93..03a57697b232b3 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h @@ -50,13 +50,13 @@ #define NGHTTP3_STREAM_MIN_WRITELEN 800 /* nghttp3_stream_type is unidirectional stream type. */ -typedef enum nghttp3_stream_type { - NGHTTP3_STREAM_TYPE_CONTROL = 0x00, - NGHTTP3_STREAM_TYPE_PUSH = 0x01, - NGHTTP3_STREAM_TYPE_QPACK_ENCODER = 0x02, - NGHTTP3_STREAM_TYPE_QPACK_DECODER = 0x03, - NGHTTP3_STREAM_TYPE_UNKNOWN = UINT64_MAX, -} nghttp3_stream_type; +typedef uint64_t nghttp3_stream_type; + +#define NGHTTP3_STREAM_TYPE_CONTROL 0x00 +#define NGHTTP3_STREAM_TYPE_PUSH 0x01 +#define NGHTTP3_STREAM_TYPE_QPACK_ENCODER 0x02 +#define NGHTTP3_STREAM_TYPE_QPACK_DECODER 0x03 +#define NGHTTP3_STREAM_TYPE_UNKNOWN UINT64_MAX typedef enum nghttp3_ctrl_stream_state { NGHTTP3_CTRL_STREAM_STATE_FRAME_TYPE, @@ -195,9 +195,8 @@ typedef struct nghttp3_http_state { /* recv_content_length is the number of body bytes received so far. */ int64_t recv_content_length; + nghttp3_pri pri; uint32_t flags; - /* pri is a stream priority produced by nghttp3_pri_to_uint8. */ - uint8_t pri; } nghttp3_http_state; struct nghttp3_stream { @@ -257,7 +256,7 @@ struct nghttp3_stream { }; }; -nghttp3_objalloc_def(stream, nghttp3_stream, oplent); +nghttp3_objalloc_decl(stream, nghttp3_stream, oplent); typedef struct nghttp3_frame_entry { nghttp3_frame fr; @@ -272,7 +271,7 @@ typedef struct nghttp3_frame_entry { } nghttp3_frame_entry; int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, - uint64_t seq, const nghttp3_stream_callbacks *callbacks, + const nghttp3_stream_callbacks *callbacks, nghttp3_objalloc *out_chunk_objalloc, nghttp3_objalloc *stream_objalloc, const nghttp3_mem *mem); @@ -293,13 +292,11 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream); int nghttp3_stream_write_stream_type(nghttp3_stream *stream); -nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, - nghttp3_vec *vec, size_t veccnt); +size_t nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, + nghttp3_vec *vec, size_t veccnt); int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream); -int nghttp3_stream_outq_is_full(nghttp3_stream *stream); - int nghttp3_stream_outq_add(nghttp3_stream *stream, const nghttp3_typed_buf *tbuf); @@ -331,7 +328,7 @@ nghttp3_buf *nghttp3_stream_get_chunk(nghttp3_stream *stream); int nghttp3_stream_is_blocked(nghttp3_stream *stream); -int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n); +void nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n); /* * nghttp3_stream_outq_write_done returns nonzero if all contents in diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c index 36e738c3469aca..d9c5e598699512 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c @@ -31,26 +31,12 @@ #include "nghttp3_conn.h" #include "nghttp3_conv.h" -nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid, - nghttp3_node_id_type type, int64_t id) { - nid->type = type; - nid->id = id; - return nid; -} - -int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b) { - return a->type == b->type && a->id == b->id; -} - -void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid, - uint64_t seq, uint8_t pri) { - assert(nghttp3_pri_uint8_urgency(pri) < NGHTTP3_URGENCY_LEVELS); - +void nghttp3_tnode_init(nghttp3_tnode *tnode, int64_t id) { tnode->pe.index = NGHTTP3_PQ_BAD_INDEX; - tnode->nid = *nid; - tnode->seq = seq; + tnode->id = id; tnode->cycle = 0; - tnode->pri = pri; + tnode->pri.urgency = NGHTTP3_DEFAULT_URGENCY; + tnode->pri.inc = 0; } void nghttp3_tnode_free(nghttp3_tnode *tnode) { (void)tnode; } @@ -86,12 +72,11 @@ int nghttp3_tnode_schedule(nghttp3_tnode *tnode, nghttp3_pq *pq, uint64_t penalty = nwrite / NGHTTP3_STREAM_MIN_WRITELEN; if (tnode->pe.index == NGHTTP3_PQ_BAD_INDEX) { - tnode->cycle = pq_get_first_cycle(pq) + - ((nwrite == 0 || !nghttp3_pri_uint8_inc(tnode->pri)) - ? 0 - : nghttp3_max(1, penalty)); + tnode->cycle = + pq_get_first_cycle(pq) + + ((nwrite == 0 || !tnode->pri.inc) ? 0 : nghttp3_max(1, penalty)); } else if (nwrite > 0) { - if (!nghttp3_pri_uint8_inc(tnode->pri) || nghttp3_pq_size(pq) == 1) { + if (!tnode->pri.inc || nghttp3_pq_size(pq) == 1) { return 0; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h index f71dcf5ee31ad6..1abc1e62519381 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h @@ -35,33 +35,16 @@ #define NGHTTP3_TNODE_MAX_CYCLE_GAP (1llu << 24) -typedef enum nghttp3_node_id_type { - NGHTTP3_NODE_ID_TYPE_STREAM = 0x00, - NGHTTP3_NODE_ID_TYPE_PUSH = 0x01, -} nghttp3_node_id_type; - -typedef struct nghttp3_node_id { - nghttp3_node_id_type type; - int64_t id; -} nghttp3_node_id; - -nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid, - nghttp3_node_id_type type, int64_t id); - -int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b); - typedef struct nghttp3_tnode { nghttp3_pq_entry pe; size_t num_children; - nghttp3_node_id nid; - uint64_t seq; + int64_t id; uint64_t cycle; /* pri is a stream priority produced by nghttp3_pri_to_uint8. */ - uint8_t pri; + nghttp3_pri pri; } nghttp3_tnode; -void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid, - uint64_t seq, uint8_t pri); +void nghttp3_tnode_init(nghttp3_tnode *tnode, int64_t id); void nghttp3_tnode_free(nghttp3_tnode *tnode); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c new file mode 100644 index 00000000000000..6fea89b802b12d --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c @@ -0,0 +1,72 @@ +/* + * nghttp3 + * + * Copyright (c) 2022 nghttp3 contributors + * Copyright (c) 2022 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nghttp3_unreachable.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + +void nghttp3_unreachable_fail(const char *file, int line, const char *func) { + char *buf; + size_t buflen; + int rv; + +#define NGHTTP3_UNREACHABLE_TEMPLATE "%s:%d %s: Unreachable.\n" + + rv = snprintf(NULL, 0, NGHTTP3_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + + /* here we explicitly use system malloc */ + buflen = (size_t)rv + 1; + buf = malloc(buflen); + if (buf == NULL) { + abort(); + } + + rv = snprintf(buf, buflen, NGHTTP3_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + +#ifndef WIN32 + while (write(STDERR_FILENO, buf, (size_t)rv) == -1 && errno == EINTR) + ; +#else /* WIN32 */ + _write(_fileno(stderr), buf, (unsigned int)rv); +#endif /* WIN32 */ + + free(buf); + + abort(); +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h new file mode 100644 index 00000000000000..6360f52d3aa857 --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h @@ -0,0 +1,53 @@ +/* + * nghttp3 + * + * Copyright (c) 2022 nghttp3 contributors + * Copyright (c) 2022 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGHTTP3_UNREACHABLE_H +#define NGHTTP3_UNREACHABLE_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#ifdef __FILE_NAME__ +# define NGHTTP3_FILE_NAME __FILE_NAME__ +#else /* !__FILE_NAME__ */ +# define NGHTTP3_FILE_NAME "(file)" +#endif /* !__FILE_NAME__ */ + +#define nghttp3_unreachable() \ + nghttp3_unreachable_fail(NGHTTP3_FILE_NAME, __LINE__, __func__) + +#ifdef _MSC_VER +__declspec(noreturn) +#endif /* _MSC_VER */ + void nghttp3_unreachable_fail(const char *file, int line, const char *func) +#ifndef _MSC_VER + __attribute__((noreturn)) +#endif /* !_MSC_VER */ + ; + +#endif /* NGHTTP3_UNREACHABLE_H */ diff --git a/deps/ngtcp2/nghttp3/lib/sfparse.c b/deps/ngtcp2/nghttp3/lib/sfparse.c new file mode 100644 index 00000000000000..efa2850c9d661d --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/sfparse.c @@ -0,0 +1,1146 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "sfparse.h" + +#include +#include +#include + +#define SF_STATE_DICT 0x08u +#define SF_STATE_LIST 0x10u +#define SF_STATE_ITEM 0x18u + +#define SF_STATE_INNER_LIST 0x04u + +#define SF_STATE_BEFORE 0x00u +#define SF_STATE_BEFORE_PARAMS 0x01u +#define SF_STATE_PARAMS 0x02u +#define SF_STATE_AFTER 0x03u + +#define SF_STATE_OP_MASK 0x03u + +#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) +#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ + (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) +#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ + (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) + +#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) +#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) +#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) + +#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) +#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) +#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) + +#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) +#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) +#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) + +#define SF_STATE_INITIAL 0x00u + +#define DIGIT_CASES \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +#define LCALPHA_CASES \ + case 'a': \ + case 'b': \ + case 'c': \ + case 'd': \ + case 'e': \ + case 'f': \ + case 'g': \ + case 'h': \ + case 'i': \ + case 'j': \ + case 'k': \ + case 'l': \ + case 'm': \ + case 'n': \ + case 'o': \ + case 'p': \ + case 'q': \ + case 'r': \ + case 's': \ + case 't': \ + case 'u': \ + case 'v': \ + case 'w': \ + case 'x': \ + case 'y': \ + case 'z' + +#define UCALPHA_CASES \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'E': \ + case 'F': \ + case 'G': \ + case 'H': \ + case 'I': \ + case 'J': \ + case 'K': \ + case 'L': \ + case 'M': \ + case 'N': \ + case 'O': \ + case 'P': \ + case 'Q': \ + case 'R': \ + case 'S': \ + case 'T': \ + case 'U': \ + case 'V': \ + case 'W': \ + case 'X': \ + case 'Y': \ + case 'Z' + +#define ALPHA_CASES \ + UCALPHA_CASES: \ + LCALPHA_CASES + +#define X20_21_CASES \ + case ' ': \ + case '!' + +#define X23_5B_CASES \ + case '#': \ + case '$': \ + case '%': \ + case '&': \ + case '\'': \ + case '(': \ + case ')': \ + case '*': \ + case '+': \ + case ',': \ + case '-': \ + case '.': \ + case '/': \ + DIGIT_CASES: \ + case ':': \ + case ';': \ + case '<': \ + case '=': \ + case '>': \ + case '?': \ + case '@': \ + UCALPHA_CASES: \ + case '[' + +#define X5D_7E_CASES \ + case ']': \ + case '^': \ + case '_': \ + case '`': \ + LCALPHA_CASES: \ + case '{': \ + case '|': \ + case '}': \ + case '~' + +static int is_ws(uint8_t c) { + switch (c) { + case ' ': + case '\t': + return 1; + default: + return 0; + } +} + +static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } + +static void parser_discard_ows(sf_parser *sfp) { + for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) + ; +} + +static void parser_discard_sp(sf_parser *sfp) { + for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) + ; +} + +static void parser_set_op_state(sf_parser *sfp, uint32_t op) { + sfp->state &= ~SF_STATE_OP_MASK; + sfp->state |= op; +} + +static void parser_unset_inner_list_state(sf_parser *sfp) { + sfp->state &= ~SF_STATE_INNER_LIST; +} + +static int parser_key(sf_parser *sfp, sf_vec *dest) { + const uint8_t *base; + + switch (*sfp->pos) { + case '*': + LCALPHA_CASES: + break; + default: + return SF_ERR_PARSE_ERROR; + } + + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '_': + case '-': + case '.': + case '*': + DIGIT_CASES: + LCALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->base = (uint8_t *)base; + dest->len = (size_t)(sfp->pos - dest->base); + } + + return 0; +} + +static int parser_number(sf_parser *sfp, sf_value *dest) { + int sign = 1; + int64_t value = 0; + size_t len = 0; + size_t fpos = 0; + + if (*sfp->pos == '-') { + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + sign = -1; + } + + assert(!parser_eof(sfp)); + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (len == 0) { + return SF_ERR_PARSE_ERROR; + } + + if (parser_eof(sfp) || *sfp->pos != '.') { + if (dest) { + dest->type = SF_TYPE_INTEGER; + dest->flags = SF_VALUE_FLAG_NONE; + dest->integer = value * sign; + } + + return 0; + } + + /* decimal */ + + if (len > 12) { + return SF_ERR_PARSE_ERROR; + } + + fpos = len; + + ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (fpos == len || len - fpos > 3) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + dest->type = SF_TYPE_DECIMAL; + dest->flags = SF_VALUE_FLAG_NONE; + dest->decimal.numer = value * sign; + + switch (len - fpos) { + case 1: + dest->decimal.denom = 10; + + break; + case 2: + dest->decimal.denom = 100; + + break; + case 3: + dest->decimal.denom = 1000; + + break; + } + } + + return 0; +} + +static int parser_date(sf_parser *sfp, sf_value *dest) { + int rv; + sf_value val; + + /* The first byte has already been validated by the caller. */ + assert('@' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_number(sfp, &val); + if (rv != 0) { + return rv; + } + + if (val.type != SF_TYPE_INTEGER) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + *dest = val; + dest->type = SF_TYPE_DATE; + } + + return 0; +} + +static int parser_string(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + uint32_t flags = SF_VALUE_FLAG_NONE; + + /* The first byte has already been validated by the caller. */ + assert('"' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + X20_21_CASES: + X23_5B_CASES: + X5D_7E_CASES: + break; + case '\\': + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '"': + case '\\': + flags = SF_VALUE_FLAG_ESCAPED_STRING; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + case '"': + if (dest) { + dest->type = SF_TYPE_STRING; + dest->flags = flags; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; +} + +static int parser_token(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '!': + case '#': + case '$': + case '%': + case '&': + case '\'': + case '*': + case '+': + case '-': + case '.': + case '^': + case '_': + case '`': + case '|': + case '~': + case ':': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->type = SF_TYPE_TOKEN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.base = (uint8_t *)base; + dest->vec.len = (size_t)(sfp->pos - base); + } + + return 0; +} + +static int parser_byteseq(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + assert(':' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '+': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + case '=': + switch ((sfp->pos - base) & 0x3) { + case 0: + case 1: + return SF_ERR_PARSE_ERROR; + case 2: + switch (*(sfp->pos - 1)) { + case 'A': + case 'Q': + case 'g': + case 'w': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != '=') { + return SF_ERR_PARSE_ERROR; + } + + break; + case 3: + switch (*(sfp->pos - 1)) { + case 'A': + case 'E': + case 'I': + case 'M': + case 'Q': + case 'U': + case 'Y': + case 'c': + case 'g': + case 'k': + case 'o': + case 's': + case 'w': + case '0': + case '4': + case '8': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != ':') { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + case ':': + if ((sfp->pos - base) & 0x3) { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; + +fin: + if (dest) { + dest->type = SF_TYPE_BYTESEQ; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; +} + +static int parser_boolean(sf_parser *sfp, sf_value *dest) { + int b; + + /* The first byte has already been validated by the caller. */ + assert('?' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '0': + b = 0; + + break; + case '1': + b = 1; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = b; + } + + return 0; +} + +static int parser_bare_item(sf_parser *sfp, sf_value *dest) { + switch (*sfp->pos) { + case '"': + return parser_string(sfp, dest); + case '-': + DIGIT_CASES: + return parser_number(sfp, dest); + case '@': + return parser_date(sfp, dest); + case ':': + return parser_byteseq(sfp, dest); + case '?': + return parser_boolean(sfp, dest); + case '*': + ALPHA_CASES: + return parser_token(sfp, dest); + default: + return SF_ERR_PARSE_ERROR; + } +} + +static int parser_skip_inner_list(sf_parser *sfp); + +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_BEFORE_PARAMS: + parser_set_op_state(sfp, SF_STATE_PARAMS); + + break; + case SF_STATE_PARAMS: + break; + default: + assert(0); + abort(); + } + + if (parser_eof(sfp) || *sfp->pos != ';') { + parser_set_op_state(sfp, SF_STATE_AFTER); + + return SF_ERR_EOF; + } + + ++sfp->pos; + + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + if (parser_eof(sfp) || *sfp->pos != '=') { + if (dest_value) { + dest_value->type = SF_TYPE_BOOLEAN; + dest_value->flags = SF_VALUE_FLAG_NONE; + dest_value->boolean = 1; + } + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return parser_bare_item(sfp, dest_value); +} + +static int parser_skip_params(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_param(sfp, NULL, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* Technically, we are entering SF_STATE_AFTER, but we will set + another state without reading the state. */ + /* parser_set_op_state(sfp, SF_STATE_AFTER); */ + + /* fall through */ + case SF_STATE_AFTER: + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case ' ': + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case ')': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == ')') { + ++sfp->pos; + + parser_unset_inner_list_state(sfp); + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return SF_ERR_EOF; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return 0; +} + +static int parser_skip_inner_list(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_inner_list(sfp, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +static int parser_next_key_or_item(sf_parser *sfp) { + parser_discard_ows(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + if (*sfp->pos != ',') { + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + parser_discard_ows(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return 0; +} + +static int parser_dict_value(sf_parser *sfp, sf_value *dest) { + int rv; + + if (parser_eof(sfp) || *(sfp->pos) != '=') { + /* Boolean true */ + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = 1; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state) { + case SF_STATE_DICT_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + return parser_dict_value(sfp, dest_value); +} + +int sf_parser_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_LIST_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_LIST_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_item(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_ITEM_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_AFTER: + parser_discard_sp(sfp); + + if (!parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return SF_ERR_EOF; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; + + return 0; +} + +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { + if (datalen == 0) { + sfp->pos = sfp->end = NULL; + } else { + sfp->pos = data; + sfp->end = data + datalen; + } + + sfp->state = SF_STATE_INITIAL; +} + +void sf_unescape(sf_vec *dest, const sf_vec *src) { + const uint8_t *p, *q; + uint8_t *o; + size_t len, slen; + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + len = src->len; + + for (;;) { + q = memchr(p, '\\', len); + if (q == NULL) { + if (len == src->len) { + *dest = *src; + + return; + } + + memcpy(o, p, len); + o += len; + + break; + } + + slen = (size_t)(q - p); + memcpy(o, p, slen); + o += slen; + + p = q + 1; + *o++ = *p++; + len -= slen + 2; + } + + dest->len = (size_t)(o - dest->base); +} + +void sf_base64decode(sf_vec *dest, const sf_vec *src) { + static const int index_tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + uint8_t *o; + const uint8_t *p, *end; + uint32_t n; + size_t i; + int idx; + + assert((src->len & 0x3) == 0); + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + end = src->base + src->len; + + for (; p != end;) { + n = 0; + + for (i = 1; i <= 4; ++i, ++p) { + idx = index_tbl[*p]; + + if (idx == -1) { + assert(i > 2); + + if (i == 3) { + assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); + + *o++ = (uint8_t)(n >> 16); + + goto fin; + } + + assert(*p == '=' && p + 1 == end); + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + + goto fin; + } + + n += (uint32_t)(idx << (24 - i * 6)); + } + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + *o++ = n & 0xffu; + } + +fin: + dest->len = (size_t)(o - dest->base); +} diff --git a/deps/ngtcp2/nghttp3/lib/sfparse.h b/deps/ngtcp2/nghttp3/lib/sfparse.h new file mode 100644 index 00000000000000..1474db1429acea --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/sfparse.h @@ -0,0 +1,409 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SFPARSE_H +#define SFPARSE_H + +/* Define WIN32 when build target is Win32 API (borrowed from + libcurl) */ +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +/* MSVC < 2013 does not have inttypes.h because it is not C99 + compliant. See compiler macros and version number in + https://sourceforge.net/p/predef/wiki/Compilers/ */ +# include +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +# include +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#include + +/** + * @enum + * + * :type:`sf_type` defines value type. + */ +typedef enum sf_type { + /** + * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. + */ + SF_TYPE_BOOLEAN, + /** + * :enum:`SF_TYPE_INTEGER` indicates integer type. + */ + SF_TYPE_INTEGER, + /** + * :enum:`SF_TYPE_DECIMAL` indicates decimal type. + */ + SF_TYPE_DECIMAL, + /** + * :enum:`SF_TYPE_STRING` indicates string type. + */ + SF_TYPE_STRING, + /** + * :enum:`SF_TYPE_TOKEN` indicates token type. + */ + SF_TYPE_TOKEN, + /** + * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. + */ + SF_TYPE_BYTESEQ, + /** + * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. + */ + SF_TYPE_INNER_LIST, + /** + * :enum:`SF_TYPE_DATE` indicates date type. + */ + SF_TYPE_DATE +} sf_type; + +/** + * @macro + * + * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has + * occurred, and it is not possible to continue the processing. + */ +#define SF_ERR_PARSE_ERROR -1 + +/** + * @macro + * + * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. + * The context of this error varies depending on the function that + * returns this error code. + */ +#define SF_ERR_EOF -2 + +/** + * @struct + * + * :type:`sf_vec` stores sequence of bytes. + */ +typedef struct sf_vec { + /** + * :member:`base` points to the beginning of the sequence of bytes. + */ + uint8_t *base; + /** + * :member:`len` is the number of bytes contained in this sequence. + */ + size_t len; +} sf_vec; + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. + */ +#define SF_VALUE_FLAG_NONE 0x0u + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string + * contains escaped character(s). + */ +#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u + +/** + * @struct + * + * :type:`sf_decimal` contains decimal value. + */ +typedef struct sf_decimal { + /** + * :member:`numer` contains numerator of the decimal value. + */ + int64_t numer; + /** + * :member:`denom` contains denominator of the decimal value. + */ + int64_t denom; +} sf_decimal; + +/** + * @struct + * + * :type:`sf_value` stores a Structured Field item. For Inner List, + * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order + * to read the items contained in an inner list, call + * `sf_parser_inner_list`. + */ +typedef struct sf_value { + /** + * :member:`type` is the type of the value contained in this + * particular object. + */ + sf_type type; + /** + * :member:`flags` is bitwise OR of one or more of + * :macro:`SF_VALUE_FLAG_* `. + */ + uint32_t flags; + /** + * @anonunion_start + * + * @sf_value_value + */ + union { + /** + * :member:`boolean` contains boolean value if :member:`type` == + * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 + * indicates false. + */ + int boolean; + /** + * :member:`integer` contains integer value if :member:`type` is + * either :enum:`sf_type.SF_TYPE_INTEGER` or + * :enum:`sf_type.SF_TYPE_DATE`. + */ + int64_t integer; + /** + * :member:`decimal` contains decimal value if :member:`type` == + * :enum:`sf_type.SF_TYPE_DECIMAL`. + */ + sf_decimal decimal; + /** + * :member:`vec` contains sequence of bytes if :member:`type` is + * either :enum:`sf_type.SF_TYPE_STRING`, + * :enum:`sf_type.SF_TYPE_TOKEN`, or + * :enum:`sf_type.SF_TYPE_BYTESEQ`. + * + * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or + * more escaped characters if :member:`flags` has + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the + * string, use `sf_unescape`. + * + * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 + * encoded string. To decode this byte string, use + * `sf_base64decode`. + * + * If :member:`vec.len ` == 0, :member:`vec.base + * ` is guaranteed to be NULL. + */ + sf_vec vec; + /** + * @anonunion_end + */ + }; +} sf_value; + +/** + * @struct + * + * :type:`sf_parser` is the Structured Field Values parser. Use + * `sf_parser_init` to initialize it. + */ +typedef struct sf_parser { + /* all fields are private */ + const uint8_t *pos; + const uint8_t *end; + uint32_t state; +} sf_parser; + +/** + * @function + * + * `sf_parser_init` initializes |sfp| with the given buffer pointed by + * |data| of length |datalen|. + */ +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); + +/** + * @function + * + * `sf_parser_param` reads a parameter. If this function returns 0, + * it stores parameter key and value in |dest_key| and |dest_value| + * respectively, if they are not NULL. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have + * read, and caller can continue to read rest of the values. If it + * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error + * while parsing field value. + */ +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_dict` reads the next dictionary key and value pair. If + * this function returns 0, it stores the key and value in |dest_key| + * and |dest_value| respectively, if they are not NULL. + * + * Caller can optionally read parameters attached to the pair by + * calling `sf_parser_param`. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all key and value + * pairs have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the dictionary have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_list` reads the next list item. If this function + * returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in the + * list have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_item` reads a single item. If this function returns 0, + * it stores the item in |dest| if it is not NULL. + * + * This function is only used for the field value that consists of a + * single item. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should call this function again to make sure that there is + * nothing left to read. If this 2nd function call returns + * :macro:`SF_ERR_EOF`, all data have been processed successfully. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * There is nothing left to read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_item(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_inner_list` reads the next inner list item. If this + * function returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in this + * inner list have been read, and caller can optionally read + * parameters attached to this inner list by calling + * `sf_parser_param`. Then caller can continue to read rest of the + * values. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the inner list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). + * |src| should be the pointer to :member:`sf_value.vec` of type + * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, + * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or + * `sf_parser_param`, otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the unescaped string. + * + * If there is no escape character in |src|, |*src| is assigned to + * |*dest|. This includes the case that :member:`src->len + * ` == 0. + * + * This function sets the length of unescaped string to + * :member:`dest->len `. + */ +void sf_unescape(sf_vec *dest, const sf_vec *src); + +/** + * @function + * + * `sf_base64decode` decodes Base64 encoded string |src| and writes + * the result into |dest|. |src| should be the pointer to + * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` + * produced by either `sf_parser_dict`, `sf_parser_list`, + * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, + * otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the decoded byte string. + * + * If :member:`src->len ` == 0, |*src| is assigned to + * |*dest|. + * + * This function sets the length of decoded byte string to + * :member:`dest->len `. + */ +void sf_base64decode(sf_vec *dest, const sf_vec *src); + +#ifdef __cplusplus +} +#endif + +#endif /* SFPARSE_H */ diff --git a/deps/ngtcp2/ngtcp2.gyp b/deps/ngtcp2/ngtcp2.gyp index e53b7f61ea387b..0f2929b75478f1 100644 --- a/deps/ngtcp2/ngtcp2.gyp +++ b/deps/ngtcp2/ngtcp2.gyp @@ -8,14 +8,15 @@ 'ngtcp2/lib/ngtcp2_addr.c', 'ngtcp2/lib/ngtcp2_balloc.c', 'ngtcp2/lib/ngtcp2_bbr.c', - 'ngtcp2/lib/ngtcp2_bbr2.c', 'ngtcp2/lib/ngtcp2_buf.c', 'ngtcp2/lib/ngtcp2_cc.c', 'ngtcp2/lib/ngtcp2_cid.c', 'ngtcp2/lib/ngtcp2_conn.c', 'ngtcp2/lib/ngtcp2_conv.c', + 'ngtcp2/lib/ngtcp2_conversion.c', 'ngtcp2/lib/ngtcp2_crypto.c', 'ngtcp2/lib/ngtcp2_err.c', + 'ngtcp2/lib/ngtcp2_frame_chain.c', 'ngtcp2/lib/ngtcp2_gaptr.c', 'ngtcp2/lib/ngtcp2_idtr.c', 'ngtcp2/lib/ngtcp2_ksl.c', @@ -38,13 +39,14 @@ 'ngtcp2/lib/ngtcp2_rtb.c', 'ngtcp2/lib/ngtcp2_str.c', 'ngtcp2/lib/ngtcp2_strm.c', + 'ngtcp2/lib/ngtcp2_unreachable.c', 'ngtcp2/lib/ngtcp2_vec.c', 'ngtcp2/lib/ngtcp2_version.c', 'ngtcp2/lib/ngtcp2_window_filter.c', 'ngtcp2/crypto/shared.c' ], - 'ngtcp2_sources_openssl': [ - 'ngtcp2/crypto/openssl/openssl.c' + 'ngtcp2_sources_quictls': [ + 'ngtcp2/crypto/quictls/quictls.c' ], 'ngtcp2_sources_boringssl': [ 'ngtcp2/crypto/boringssl/boringssl.c' @@ -75,8 +77,11 @@ 'nghttp3/lib/nghttp3_str.c', 'nghttp3/lib/nghttp3_stream.c', 'nghttp3/lib/nghttp3_tnode.c', + 'nghttp3/lib/nghttp3_unreachable.c', 'nghttp3/lib/nghttp3_vec.c', - 'nghttp3/lib/nghttp3_version.c' + 'nghttp3/lib/nghttp3_version.c', + # sfparse is also used by nghttp2 and is included by nghttp2.gyp + # 'nghttp3/lib/sfparse.c' ] }, 'targets': [ @@ -100,6 +105,9 @@ '../openssl/openssl.gyp:openssl' ] }], + ['OS!="win"', { + 'defines': ['HAVE_UNISTD_H'] + }], ['OS=="win"', { 'defines': [ 'WIN32', @@ -132,7 +140,7 @@ }, 'sources': [ '<@(ngtcp2_sources)', - '<@(ngtcp2_sources_openssl)', + '<@(ngtcp2_sources_quictls)', ] }, { @@ -144,7 +152,7 @@ ], 'defines': [ 'BUILDING_NGHTTP3', - 'NGHTTP3_STATICLIB' + 'NGHTTP3_STATICLIB', ], 'dependencies': [ 'ngtcp2' @@ -162,6 +170,9 @@ }, }, }], + ['OS!="win"', { + 'defines': ['HAVE_UNISTD_H'] + }], ['OS=="linux" or OS=="android"', { 'defines': [ 'HAVE_ARPA_INET_H', diff --git a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c index 015032d41ca0ce..50b89110e36ff7 100644 --- a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c @@ -92,8 +92,8 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)EVP_aead_aes_128_gcm()); } -static const EVP_AEAD *crypto_ssl_get_aead(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_AEAD *crypto_cipher_id_get_aead(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: return EVP_aead_aes_128_gcm(); case TLS1_CK_AES_256_GCM_SHA384: @@ -105,8 +105,8 @@ static const EVP_AEAD *crypto_ssl_get_aead(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; @@ -117,8 +117,9 @@ static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t +crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; @@ -129,8 +130,9 @@ static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { } } -static const ngtcp2_crypto_boringssl_cipher *crypto_ssl_get_hp(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const ngtcp2_crypto_boringssl_cipher * +crypto_cipher_id_get_hp(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: return &crypto_cipher_aes_128; case TLS1_CK_AES_256_GCM_SHA384: @@ -142,8 +144,8 @@ static const ngtcp2_crypto_boringssl_cipher *crypto_ssl_get_hp(SSL *ssl) { } } -static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_CHACHA20_POLY1305_SHA256: return EVP_sha256(); @@ -154,15 +156,47 @@ static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { } } +static int supported_cipher_id(uint32_t cipher_id) { + switch (cipher_id) { + case TLS1_CK_AES_128_GCM_SHA256: + case TLS1_CK_AES_256_GCM_SHA384: + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return 1; + default: + return 0; + } +} + +static ngtcp2_crypto_ctx *crypto_ctx_cipher_id(ngtcp2_crypto_ctx *ctx, + uint32_t cipher_id) { + ngtcp2_crypto_aead_init(&ctx->aead, + (void *)crypto_cipher_id_get_aead(cipher_id)); + ctx->md.native_handle = (void *)crypto_cipher_id_get_md(cipher_id); + ctx->hp.native_handle = (void *)crypto_cipher_id_get_hp(cipher_id); + ctx->max_encryption = crypto_cipher_id_get_aead_max_encryption(cipher_id); + ctx->max_decryption_failure = + crypto_cipher_id_get_aead_max_decryption_failure(cipher_id); + + return ctx; +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { SSL *ssl = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl)); - ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl); - ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl); - ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl); - ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl); - return ctx; + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + uint32_t cipher_id; + + if (cipher == NULL) { + return NULL; + } + + cipher_id = SSL_CIPHER_get_id(cipher); + + if (!supported_cipher_id(cipher_id)) { + return NULL; + } + + return crypto_ctx_cipher_id(ctx, cipher_id); } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, @@ -394,15 +428,17 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, } } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +int ngtcp2_crypto_read_write_crypto_data( + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + const uint8_t *data, size_t datalen) { SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); int rv; int err; if (SSL_provide_quic_data( - ssl, ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level(crypto_level), + ssl, + ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + encryption_level), data, datalen) != 1) { return -1; } @@ -423,7 +459,10 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, SSL_reset_early_data_reject(ssl); - ngtcp2_conn_early_data_rejected(conn); + rv = ngtcp2_conn_tls_early_data_rejected(conn); + if (rv != 0) { + return -1; + } goto retry; default: @@ -435,7 +474,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, return 0; } - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = SSL_process_quic_post_handshake(ssl); @@ -464,7 +503,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { SSL_get_peer_quic_transport_params(ssl, &tp, &tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -482,33 +521,34 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( enum ssl_encryption_level_t ssl_level) { switch (ssl_level) { case ssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case ssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case ssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case ssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); } } -enum ssl_encryption_level_t ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +enum ssl_encryption_level_t +ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return ssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return ssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return ssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return ssl_encryption_early_data; default: assert(0); @@ -541,7 +581,7 @@ static int set_read_secret(SSL *ssl, enum ssl_encryption_level_t bssl_level, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); (void)cipher; @@ -558,7 +598,7 @@ static int set_write_secret(SSL *ssl, enum ssl_encryption_level_t bssl_level, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); (void)cipher; @@ -574,7 +614,7 @@ static int add_handshake_data(SSL *ssl, enum ssl_encryption_level_t bssl_level, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); int rv; diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h index 4736b51c3cb48d..06427d7a7cac70 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -38,39 +38,16 @@ extern "C" { # include #endif /* WIN32 */ -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_SECRETLEN` is the length of secret - * for Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 - -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_KEYLEN` is the length of key for - * Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_KEYLEN 16 - -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_IVLEN` is the length of IV for - * Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_IVLEN 12 - /** * @function * * `ngtcp2_crypto_ctx_tls` initializes |ctx| by extracting negotiated * ciphers and message digests from native TLS session * |tls_native_handle|. This is used for encrypting/decrypting - * Handshake and Short header packets. + * Handshake and 1-RTT packets. If it is unable to obtain necessary + * data from |tls_native_handle|, this function returns NULL. * - * If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |tls_native_handle| must be * a pointer to SSL object. */ NGTCP2_EXTERN ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, @@ -81,10 +58,11 @@ NGTCP2_EXTERN ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, * * `ngtcp2_crypto_ctx_tls_early` initializes |ctx| by extracting early * ciphers and message digests from native TLS session - * |tls_native_handle|. This is used for encrypting/decrypting 0RTT - * packets. + * |tls_native_handle|. This is used for encrypting/decrypting 0-RTT + * packets. If it is unable to obtain necessary data from + * |tls_native_handle|, this function returns NULL. * - * If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |tls_native_handle| must be * a pointer to SSL object. */ NGTCP2_EXTERN ngtcp2_crypto_ctx * @@ -96,7 +74,7 @@ ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, void *tls_native_handle); * `ngtcp2_crypto_md_init` initializes |md| with the provided * |md_native_handle| which is an underlying message digest object. * - * If libngtcp2_crypto_openssl is linked, |md_native_handle| must be a + * If libngtcp2_crypto_quictls is linked, |md_native_handle| must be a * pointer to EVP_MD. * * If libngtcp2_crypto_gnutls is linked, |md_native_handle| must be @@ -134,10 +112,12 @@ ngtcp2_crypto_aead_noncelen(const ngtcp2_crypto_aead *aead); /** * @function * - * `ngtcp2_crypto_hkdf_extract` performs HKDF extract operation. The - * result is the length of |md| and is stored to the buffer pointed by - * |dest|. The caller is responsible to specify the buffer that can - * store the output. + * `ngtcp2_crypto_hkdf_extract` performs HKDF extract operation. + * + * The length of output is `ngtcp2_crypto_md_hashlen(md) + * `. The output is stored in the buffer + * pointed by |dest|. The caller is responsible to specify the buffer + * that has enough capacity to store the output. * * This function returns 0 if it succeeds, or -1. */ @@ -150,7 +130,7 @@ ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, * @function * * `ngtcp2_crypto_hkdf_expand` performs HKDF expand operation. The - * result is |destlen| bytes long and is stored to the buffer pointed + * result is |destlen| bytes long, and is stored in the buffer pointed * by |dest|. * * This function returns 0 if it succeeds, or -1. @@ -166,7 +146,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, * @function * * `ngtcp2_crypto_hkdf` performs HKDF operation. The result is - * |destlen| bytes long and is stored to the buffer pointed by |dest|. + * |destlen| bytes long, and is stored in the buffer pointed by + * |dest|. * * This function returns 0 if it succeeds, or -1. */ @@ -176,41 +157,6 @@ NGTCP2_EXTERN int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *salt, size_t saltlen, const uint8_t *info, size_t infolen); -/** - * @function - * - * `ngtcp2_crypto_hkdf_expand_label` performs HKDF expand label. The - * result is |destlen| bytes long and is stored to the buffer pointed - * by |dest|. - * - * This function returns 0 if it succeeds, or -1. - */ -NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, - const ngtcp2_crypto_md *md, - const uint8_t *secret, - size_t secretlen, - const uint8_t *label, - size_t labellen); - -/** - * @enum - * - * :type:`ngtcp2_crypto_side` indicates which side the application - * implements; client or server. - */ -typedef enum ngtcp2_crypto_side { - /** - * :enum:`NGTCP2_CRYPTO_SIDE_CLIENT` indicates that the application - * is client. - */ - NGTCP2_CRYPTO_SIDE_CLIENT, - /** - * :enum:`NGTCP2_CRYPTO_SIDE_SERVER` indicates that the application - * is server. - */ - NGTCP2_CRYPTO_SIDE_SERVER -} ngtcp2_crypto_side; - /** * @function * @@ -225,11 +171,10 @@ ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead); * * `ngtcp2_crypto_encrypt` encrypts |plaintext| of length * |plaintextlen| and writes the ciphertext into the buffer pointed by - * |dest|. The length of ciphertext is plaintextlen + + * |dest|. The length of ciphertext is |plaintextlen| + * :member:`aead->max_overhead ` * bytes long. |dest| must have enough capacity to store the - * ciphertext. It is allowed to specify the same value to |dest| and - * |plaintext|. + * ciphertext. |dest| and |plaintext| may point to the same buffer. * * This function returns 0 if it succeeds, or -1. */ @@ -263,11 +208,10 @@ ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, * * `ngtcp2_crypto_decrypt` decrypts |ciphertext| of length * |ciphertextlen| and writes the plaintext into the buffer pointed by - * |dest|. The length of plaintext is ciphertextlen - + * |dest|. The length of plaintext is |ciphertextlen| - * :member:`aead->max_overhead ` * bytes long. |dest| must have enough capacity to store the - * plaintext. It is allowed to specify the same value to |dest| and - * |ciphertext|. + * plaintext. |dest| and |ciphertext| may point to the same buffer. * * This function returns 0 if it succeeds, or -1. */ @@ -299,7 +243,7 @@ ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, /** * @function * - * `ngtcp2_crypto_hp_mask` generates mask which is used in packet + * `ngtcp2_crypto_hp_mask` generates a mask which is used in packet * header encryption. The mask is written to the buffer pointed by * |dest|. The sample is passed as |sample| which is * :macro:`NGTCP2_HP_SAMPLELEN` bytes long. The length of mask must @@ -333,15 +277,14 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @function * - * `ngtcp2_crypto_derive_and_install_rx_key` derives the rx keys from - * |secret| and installs new keys to |conn|. + * `ngtcp2_crypto_derive_and_install_rx_key` derives the decryption + * keying materials from |secret|, and installs them to |conn|. * - * If |key| is not NULL, the derived packet protection key for - * decryption is written to the buffer pointed by |key|. If |iv| is - * not NULL, the derived packet protection IV for decryption is - * written to the buffer pointed by |iv|. If |hp| is not NULL, the - * derived header protection key for decryption is written to the - * buffer pointed by |hp|. + * If |key| is not NULL, the derived packet protection key is written + * to the buffer pointed by |key|. If |iv| is not NULL, the derived + * packet protection IV is written to the buffer pointed by |iv|. If + * |hp| is not NULL, the derived header protection key is written to + * the buffer pointed by |hp|. * * |secretlen| specifies the length of |secret|. * @@ -351,44 +294,44 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * `ngtcp2_crypto_packet_protection_ivlen(ctx->aead) * ` where ctx is obtained by * `ngtcp2_crypto_ctx_tls` (or `ngtcp2_crypto_ctx_tls_early` if - * |level| == :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`). + * |level| == + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`). * * In the first call of this function, it calls * `ngtcp2_conn_set_crypto_ctx` (or `ngtcp2_conn_set_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to set - * negotiated AEAD and message digest algorithm. After the successful - * call of this function, application can use + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to + * set negotiated AEAD and message digest algorithm. After the + * successful call of this function, application can use * `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to get - * :type:`ngtcp2_crypto_ctx`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to + * get :type:`ngtcp2_crypto_ctx`. * * If |conn| is initialized as client, and |level| is - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_APPLICATION`, this + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_1RTT`, this * function retrieves a remote QUIC transport parameters extension - * from an object obtained by `ngtcp2_conn_get_tls_native_handle` and + * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and * sets it to |conn| by calling - * `ngtcp2_conn_decode_remote_transport_params`. + * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key( ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp, - ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen); + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen); /** * @function * - * `ngtcp2_crypto_derive_and_install_tx_key` derives the tx keys from - * |secret| and installs new keys to |conn|. + * `ngtcp2_crypto_derive_and_install_tx_key` derives the encryption + * keying materials from |secret|, and installs new keys to |conn|. * - * If |key| is not NULL, the derived packet protection key for - * encryption is written to the buffer pointed by |key|. If |iv| is - * not NULL, the derived packet protection IV for encryption is - * written to the buffer pointed by |iv|. If |hp| is not NULL, the - * derived header protection key for encryption is written to the - * buffer pointed by |hp|. + * If |key| is not NULL, the derived packet protection key is written + * to the buffer pointed by |key|. If |iv| is not NULL, the derived + * packet protection IV is written to the buffer pointed by |iv|. If + * |hp| is not NULL, the derived header protection key is written to + * the buffer pointed by |hp|. * * |secretlen| specifies the length of |secret|. * @@ -398,58 +341,59 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key( * `ngtcp2_crypto_packet_protection_ivlen(ctx->aead) * ` where ctx is obtained by * `ngtcp2_crypto_ctx_tls` (or `ngtcp2_crypto_ctx_tls_early` if - * |level| == :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`). + * |level| == + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`). * * In the first call of this function, it calls * `ngtcp2_conn_set_crypto_ctx` (or `ngtcp2_conn_set_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to set - * negotiated AEAD and message digest algorithm. After the successful - * call of this function, application can use + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to + * set negotiated AEAD and message digest algorithm. After the + * successful call of this function, application can use * `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to get - * :type:`ngtcp2_crypto_ctx`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to + * get :type:`ngtcp2_crypto_ctx`. * * If |conn| is initialized as server, and |level| is - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_APPLICATION`, this + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_1RTT`, this * function retrieves a remote QUIC transport parameters extension - * from an object obtained by `ngtcp2_conn_get_tls_native_handle` and + * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and * sets it to |conn| by calling - * `ngtcp2_conn_decode_remote_transport_params`. + * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key( ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp, - ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen); + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen); /** * @function * * `ngtcp2_crypto_update_key` updates traffic keying materials. * - * The new traffic secret for decryption is written to the buffer - * pointed by |rx_secret|. The length of secret is |secretlen| bytes, - * and |rx_secret| must point to the buffer which has enough capacity. + * The new decryption traffic secret is written to the buffer pointed + * by |rx_secret|. The length of secret is |secretlen| bytes, and + * |rx_secret| must point to the buffer which has enough capacity. * - * The new traffic secret for encryption is written to the buffer - * pointed by |tx_secret|. The length of secret is |secretlen| bytes, - * and |tx_secret| must point to the buffer which has enough capacity. + * The new encryption traffic secret is written to the buffer pointed + * by |tx_secret|. The length of secret is |secretlen| bytes, and + * |tx_secret| must point to the buffer which has enough capacity. * - * The derived packet protection key for decryption is written to the - * buffer pointed by |rx_key|. The derived packet protection IV for - * decryption is written to the buffer pointed by |rx_iv|. - * |rx_aead_ctx| must be constructed with |rx_key|. + * The derived decryption packet protection key is written to the + * buffer pointed by |rx_key|. The derived decryption packet + * protection IV is written to the buffer pointed by |rx_iv|. + * |rx_aead_ctx| is initialized with the derived key and IV. * - * The derived packet protection key for encryption is written to the - * buffer pointed by |tx_key|. The derived packet protection IV for - * encryption is written to the buffer pointed by |tx_iv|. - * |tx_aead_ctx| must be constructed with |rx_key|. + * The derived encryption packet protection key is written to the + * buffer pointed by |tx_key|. The derived encryption packet + * protection IV is written to the buffer pointed by |tx_iv|. + * |tx_aead_ctx| is initialized with the derived key and IV. * - * |current_rx_secret| and |current_tx_secret| are the current traffic - * secrets for decryption and encryption. |secretlen| specifies the - * length of |rx_secret| and |tx_secret|. + * |current_rx_secret| and |current_tx_secret| are the current + * decryption and encryption traffic secrets respectively. They share + * the same length with |rx_secret| and |tx_secret|. * * The length of packet protection key and header protection key is * `ngtcp2_crypto_aead_keylen(ctx->aead) `, @@ -488,7 +432,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( * @function * * `ngtcp2_crypto_client_initial_cb` installs initial secrets and - * encryption keys and sets QUIC transport parameters. + * encryption keys, and sets QUIC transport parameters. * * This function can be directly passed to * :member:`ngtcp2_callbacks.client_initial` field. It is only used @@ -507,8 +451,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, * response to incoming Retry packet. * * This function can be directly passed to - * :member:`ngtcp2_callbacks.recv_retry` field. It is only used - * by client. + * :member:`ngtcp2_callbacks.recv_retry` field. It is only used by + * client. * * This function returns 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`. @@ -525,8 +469,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, * transport parameters. * * This function can be directly passed to - * :member:`ngtcp2_callbacks.recv_client_initial` field. It is - * only used by server. + * :member:`ngtcp2_callbacks.recv_client_initial` field. It is only + * used by server. * * This function returns 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`. @@ -539,21 +483,21 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, * @function * * `ngtcp2_crypto_read_write_crypto_data` reads CRYPTO data |data| of - * length |datalen| in encryption level |crypto_level| and may feed - * outgoing CRYPTO data to |conn|. This function can drive handshake. - * This function can be also used after handshake completes. It is - * allowed to call this function with |datalen| == 0. In this case, - * no additional read operation is done. + * length |datalen| in an encryption level |encryption_level|, and may + * feed outgoing CRYPTO data to |conn|. This function can drive + * handshake. This function can be also used after handshake + * completes. It is allowed to call this function with |datalen| == + * 0. In this case, no additional read operation is done. * * This function returns 0 if it succeeds, or a negative error code. * The generic error code is -1 if a specific error code is not * suitable. The error codes less than -10000 are specific to - * underlying TLS implementation. For OpenSSL, the error codes are - * defined in *ngtcp2_crypto_openssl.h*. + * underlying TLS implementation. For quictls, the error codes are + * defined in *ngtcp2_crypto_quictls.h*. */ NGTCP2_EXTERN int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen); /** @@ -570,17 +514,17 @@ ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, * codes. */ NGTCP2_EXTERN int ngtcp2_crypto_recv_crypto_data_cb( - ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, uint64_t offset, - const uint8_t *data, size_t datalen, void *user_data); + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + uint64_t offset, const uint8_t *data, size_t datalen, void *user_data); /** * @function * * `ngtcp2_crypto_generate_stateless_reset_token` generates a * stateless reset token using HKDF extraction using the given |cid| - * and static key |secret| as input. The token will be written to - * the buffer pointed by |token| and it must have a capacity of at - * least :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` bytes. + * and |secret| as input. The token will be written to the buffer + * pointed by |token|, and it must have a capacity of at least + * :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` bytes. * * This function returns 0 if it succeeds, or -1. */ @@ -644,12 +588,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token( * :macro:`NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN` bytes long. The * successfully generated token starts with * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY`. |secret| of length - * |secretlen| is an initial keying material to generate keys to - * encrypt the token. |version| is QUIC version. |remote_addr| of - * length |remote_addrlen| is an address of client. |retry_scid| is a - * Source Connection ID chosen by server and set in Retry packet. - * |odcid| is a Destination Connection ID in Initial packet sent by - * client. |ts| is the timestamp when the token is generated. + * |secretlen| is a keying material to generate keys to encrypt the + * token. |version| is QUIC version. |remote_addr| of length + * |remote_addrlen| is an address of client. |retry_scid| is a Source + * Connection ID chosen by server, and set in Retry packet. |odcid| + * is a Destination Connection ID in Initial packet sent by client. + * |ts| is the timestamp when the token is generated. * * This function returns the length of generated token if it succeeds, * or -1. @@ -664,16 +608,16 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_retry_token( * * `ngtcp2_crypto_verify_retry_token` verifies Retry token stored in * the buffer pointed by |token| of length |tokenlen|. |secret| of - * length |secretlen| is an initial keying material to generate keys - * to decrypt the token. |version| is QUIC version of the Initial - * packet that contains this token. |remote_addr| of length - * |remote_addrlen| is an address of client. |dcid| is a Destination - * Connection ID in Initial packet sent by client. |timeout| is the - * period during which the token is valid. |ts| is the current - * timestamp. When validation succeeds, the extracted Destination - * Connection ID (which is the Destination Connection ID in Initial - * packet sent by client that triggered Retry packet) is stored to the - * buffer pointed by |odcid|. + * length |secretlen| is a keying material to generate keys to decrypt + * the token. |version| is QUIC version of the Initial packet that + * contains this token. |remote_addr| of length |remote_addrlen| is + * an address of client. |dcid| is a Destination Connection ID in + * Initial packet sent by client. |timeout| is the period during + * which the token is valid. |ts| is the current timestamp. When + * validation succeeds, the extracted Destination Connection ID (which + * is the Destination Connection ID in Initial packet sent by client + * that triggered Retry packet) is stored in the buffer pointed by + * |odcid|. * * This function returns 0 if it succeeds, or -1. */ @@ -692,10 +636,9 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_retry_token( * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes long. The * successfully generated token starts with * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`. |secret| of length - * |secretlen| is an initial keying material to generate keys to - * encrypt the token. |remote_addr| of length |remote_addrlen| is an - * address of client. |ts| is the timestamp when the token is - * generated. + * |secretlen| is a keying material to generate keys to encrypt the + * token. |remote_addr| of length |remote_addrlen| is an address of + * client. |ts| is the timestamp when the token is generated. * * This function returns the length of generated token if it succeeds, * or -1. @@ -710,8 +653,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token( * * `ngtcp2_crypto_verify_regular_token` verifies a regular token * stored in the buffer pointed by |token| of length |tokenlen|. - * |secret| of length |secretlen| is an initial keying material to - * generate keys to decrypt the token. |remote_addr| of length + * |secret| of length |secretlen| is a keying material to generate + * keys to decrypt the token. |remote_addr| of length * |remote_addrlen| is an address of client. |timeout| is the period * during which the token is valid. |ts| is the current timestamp. * @@ -750,9 +693,12 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_write_connection_close( * @function * * `ngtcp2_crypto_write_retry` writes Retry packet to the buffer - * pointed by |dest| of length |destlen|. |odcid| specifies Original - * Destination Connection ID. |token| specifies Retry Token, and - * |tokenlen| specifies its length. + * pointed by |dest| of length |destlen|. |dcid| is the Connection ID + * which appeared in a packet as a Source Connection ID sent by + * client. |scid| is a server chosen Source Connection ID. |odcid| + * specifies Original Destination Connection ID which appeared in a + * packet as a Destination Connection ID sent by client. |token| + * specifies Retry Token, and |tokenlen| specifies its length. * * This function wraps around `ngtcp2_pkt_write_retry` for easier use. * @@ -783,7 +729,7 @@ ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, * * `ngtcp2_crypto_aead_ctx_decrypt_init` initializes |aead_ctx| with * new AEAD cipher context object for decryption which is constructed - * to use |key| as encryption key. |aead| specifies AEAD cipher to + * to use |key| as decryption key. |aead| specifies AEAD cipher to * use. |noncelen| is the length of nonce. * * This function returns 0 if it succeeds, or -1. @@ -806,7 +752,8 @@ ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx); /** * @function * - * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given |aead_ctx|. + * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given + * |aead_ctx|. * * This function can be directly passed to * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` field. @@ -845,7 +792,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, * * `ngtcp2_crypto_version_negotiation_cb` installs Initial keys for * |version| which is negotiated or being negotiated. |client_dcid| - * is the destination connection ID in first Initial packet of client. + * is the destination connection ID in first Initial packet from + * client. * * This function can be directly passed to * :member:`ngtcp2_callbacks.version_negotiation` field. @@ -872,7 +820,7 @@ typedef ngtcp2_conn *(*ngtcp2_crypto_get_conn)( * * :type:`ngtcp2_crypto_conn_ref` is a structure to get a pointer to * :type:`ngtcp2_conn`. It is meant to be set to TLS native handle as - * an application specific data (e.g. SSL_set_app_data in OpenSSL). + * an application specific data (e.g. SSL_set_app_data in quictls). */ typedef struct ngtcp2_crypto_conn_ref { /** diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h index 6497c09e79840d..43a3c36f03a382 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h @@ -37,23 +37,23 @@ extern "C" { * @function * * `ngtcp2_crypto_boringssl_from_ssl_encryption_level` translates - * |ssl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for BoringSSL backend. + * |ssl_level| to :type:`ngtcp2_encryption_level`. This function is + * only available for BoringSSL backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( enum ssl_encryption_level_t ssl_level); /** * @function * - * `ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to ssl_encryption_level_t. This function is only - * available for BoringSSL backend. + * `ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level` translates + * |encryption_level| to ssl_encryption_level_t. This function is + * only available for BoringSSL backend. */ NGTCP2_EXTERN enum ssl_encryption_level_t -ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h index d4b551c382fd69..61020bb3a8f376 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h @@ -36,8 +36,8 @@ extern "C" { /** * @struct * - * :type:`ngtcp2_crypto_picotls_ctx` contains per-connection state - * of Picotls objects and must be an object to bet set to + * :type:`ngtcp2_crypto_picotls_ctx` contains per-connection state of + * Picotls objects and must be an object to bet set to * `ngtcp2_conn_set_tls_native_handle`. */ typedef struct ngtcp2_crypto_picotls_ctx { @@ -65,21 +65,21 @@ ngtcp2_crypto_picotls_ctx_init(ngtcp2_crypto_picotls_ctx *cptls); * @function * * `ngtcp2_crypto_picotls_from_epoch` translates |epoch| to - * :type:`ngtcp2_crypto_level`. This function is only available for - * Picotls backend. + * :type:`ngtcp2_encryption_level`. This function is only available + * for Picotls backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_picotls_from_epoch(size_t epoch); /** * @function * - * `ngtcp2_crypto_picotls_from_ngtcp2_crypto_level` translates - * |crypto_level| to epoch. This function is only available for + * `ngtcp2_crypto_picotls_from_ngtcp2_encryption_level` translates + * |encryption_level| to epoch. This function is only available for * Picotls backend. */ -NGTCP2_EXTERN size_t ngtcp2_crypto_picotls_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +NGTCP2_EXTERN size_t ngtcp2_crypto_picotls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function @@ -206,7 +206,7 @@ ngtcp2_crypto_picotls_configure_client_session(ngtcp2_crypto_picotls_ctx *cptls, * * `ngtcp2_crypto_picotls_deconfigure_session` frees the resources * allocated for |cptls| during QUIC connection. It frees the - * following data using :manpage:`free(3)`. + * following data using :manpage:`free(3)`: * * - handshake_properties.max_early_data_size * - handshake_properties.additional_extensions[0].data.base diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h similarity index 63% rename from deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h rename to deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h index 844081bfa8b055..b25c13b81c8b18 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h @@ -22,8 +22,8 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef NGTCP2_CRYPTO_OPENSSL_H -#define NGTCP2_CRYPTO_OPENSSL_H +#ifndef NGTCP2_CRYPTO_QUICTLS_H +#define NGTCP2_CRYPTO_QUICTLS_H #include @@ -36,57 +36,57 @@ extern "C" { /** * @macrosection * - * OpenSSL specific error codes + * quictls specific error codes */ /** * @macro * - * :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP` is the + * :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP` is the * error code which indicates that TLS handshake routine is * interrupted by X509 certificate lookup. See * :macro:`SSL_ERROR_WANT_X509_LOOKUP` error description from * `SSL_do_handshake`. */ -#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP -10001 +#define NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP -10001 /** * @macro * - * :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB` is the + * :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB` is the * error code which indicates that TLS handshake routine is * interrupted by client hello callback. See * :macro:`SSL_ERROR_WANT_CLIENT_HELLO_CB` error description from * `SSL_do_handshake`. */ -#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB -10002 +#define NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB -10002 /** * @function * - * `ngtcp2_crypto_openssl_from_ossl_encryption_level` translates - * |ossl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for OpenSSL backend. + * `ngtcp2_crypto_quictls_from_ossl_encryption_level` translates + * |ossl_level| to :type:`ngtcp2_encryption_level`. This function is + * only available for quictls backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level -ngtcp2_crypto_openssl_from_ossl_encryption_level( +NGTCP2_EXTERN ngtcp2_encryption_level +ngtcp2_crypto_quictls_from_ossl_encryption_level( OSSL_ENCRYPTION_LEVEL ossl_level); /** * @function * - * `ngtcp2_crypto_openssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to OSSL_ENCRYPTION_LEVEL. This function is only - * available for OpenSSL backend. + * `ngtcp2_crypto_quictls_from_ngtcp2_encryption_level` translates + * |encryption_level| to OSSL_ENCRYPTION_LEVEL. This function is only + * available for quictls backend. */ NGTCP2_EXTERN OSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_quictls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function * - * `ngtcp2_crypto_openssl_configure_server_context` configures + * `ngtcp2_crypto_quictls_configure_server_context` configures * |ssl_ctx| for server side QUIC connection. It performs the * following modifications: * @@ -102,12 +102,12 @@ ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( * It returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int -ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx); +ngtcp2_crypto_quictls_configure_server_context(SSL_CTX *ssl_ctx); /** * @function * - * `ngtcp2_crypto_openssl_configure_client_context` configures + * `ngtcp2_crypto_quictls_configure_client_context` configures * |ssl_ctx| for client side QUIC connection. It performs the * following modifications: * @@ -123,10 +123,25 @@ ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx); * It returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int -ngtcp2_crypto_openssl_configure_client_context(SSL_CTX *ssl_ctx); +ngtcp2_crypto_quictls_configure_client_context(SSL_CTX *ssl_ctx); + +/** + * @function + * + * `ngtcp2_crypto_quictls_init` initializes libngtcp2_crypto_quictls + * library. This initialization is optional. For quictls >= 3.0, it + * is highly recommended to call this function before any use of + * libngtcp2_crypto library API to workaround the performance + * regression. Note that calling this function does not solve all + * performance issues introduced in 3.x. For quictls 1.1.1, this + * function does nothing, and always succeeds. + * + * This function returns 0 if it succeeds, or -1. + */ +NGTCP2_EXTERN int ngtcp2_crypto_quictls_init(void); #ifdef __cplusplus } #endif -#endif /* NGTCP2_CRYPTO_OPENSSL_H */ +#endif /* NGTCP2_CRYPTO_QUICTLS_H */ diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h index 3b10802c25b5e8..e1d621adce94d8 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h @@ -39,23 +39,23 @@ extern "C" { * @function * * `ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level` translates - * |wolfssl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for wolfSSL backend. + * |wolfssl_level| to :type:`ngtcp2_encryption_level`. This function + * is only available for wolfSSL backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( WOLFSSL_ENCRYPTION_LEVEL wolfssl_level); /** * @function * - * `ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to WOLFSSL_ENCRYPTION_LEVEL. This function is only - * available for wolfSSL backend. + * `ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level` translates + * |encryption_level| to WOLFSSL_ENCRYPTION_LEVEL. This function is + * only available for wolfSSL backend. */ NGTCP2_EXTERN WOLFSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function diff --git a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c index 32d17adc6c3a35..35bfb7b2f8fa19 100644 --- a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c +++ b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c @@ -68,45 +68,40 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)&ptls_openssl_aes128gcm); } -static const ptls_aead_algorithm_t *crypto_ptls_get_aead(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - - return cs->aead; -} - -static uint64_t crypto_ptls_get_aead_max_encryption(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static uint64_t +crypto_cipher_suite_get_aead_max_encryption(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm || cs->aead == &ptls_openssl_aes256gcm) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return 0; } -static uint64_t crypto_ptls_get_aead_max_decryption_failure(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static uint64_t +crypto_cipher_suite_get_aead_max_decryption_failure(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm || cs->aead == &ptls_openssl_aes256gcm) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return 0; } -static const ptls_cipher_algorithm_t *crypto_ptls_get_hp(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static const ptls_cipher_algorithm_t * +crypto_cipher_suite_get_hp(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm) { return &ptls_openssl_aes128ctr; } @@ -115,29 +110,43 @@ static const ptls_cipher_algorithm_t *crypto_ptls_get_hp(ptls_t *ptls) { return &ptls_openssl_aes256ctr; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return &ptls_openssl_chacha20; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return NULL; } -static const ptls_hash_algorithm_t *crypto_ptls_get_md(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - - return cs->hash; +static int supported_cipher_suite(ptls_cipher_suite_t *cs) { + return cs->aead == &ptls_openssl_aes128gcm || + cs->aead == &ptls_openssl_aes256gcm +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 + || cs->aead == &ptls_openssl_chacha20poly1305 +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ + ; } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { ngtcp2_crypto_picotls_ctx *cptls = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, - (void *)crypto_ptls_get_aead(cptls->ptls)); - ctx->md.native_handle = (void *)crypto_ptls_get_md(cptls->ptls); - ctx->hp.native_handle = (void *)crypto_ptls_get_hp(cptls->ptls); - ctx->max_encryption = crypto_ptls_get_aead_max_encryption(cptls->ptls); + ptls_cipher_suite_t *cs = ptls_get_cipher(cptls->ptls); + + if (cs == NULL) { + return NULL; + } + + if (!supported_cipher_suite(cs)) { + return NULL; + } + + ngtcp2_crypto_aead_init(&ctx->aead, (void *)cs->aead); + ctx->md.native_handle = (void *)cs->hash; + ctx->hp.native_handle = (void *)crypto_cipher_suite_get_hp(cs); + ctx->max_encryption = crypto_cipher_suite_get_aead_max_encryption(cs); ctx->max_decryption_failure = - crypto_ptls_get_aead_max_decryption_failure(cptls->ptls); + crypto_cipher_suite_get_aead_max_decryption_failure(cs); return ctx; } @@ -350,13 +359,14 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +int ngtcp2_crypto_read_write_crypto_data( + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + const uint8_t *data, size_t datalen) { ngtcp2_crypto_picotls_ctx *cptls = ngtcp2_conn_get_tls_native_handle(conn); ptls_buffer_t sendbuf; size_t epoch_offsets[5] = {0}; - size_t epoch = ngtcp2_crypto_picotls_from_ngtcp2_crypto_level(crypto_level); + size_t epoch = + ngtcp2_crypto_picotls_from_ngtcp2_encryption_level(encryption_level); size_t epoch_datalen; size_t i; int rv; @@ -379,7 +389,11 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, if (!ngtcp2_conn_is_server(conn) && cptls->handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { - ngtcp2_conn_early_data_rejected(conn); + rv = ngtcp2_conn_tls_early_data_rejected(conn); + if (rv != 0) { + rv = -1; + goto fin; + } } for (i = 0; i < 4; ++i) { @@ -399,7 +413,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } if (rv == 0) { - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = 0; @@ -432,32 +446,32 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_picotls_from_epoch(size_t epoch) { +ngtcp2_encryption_level ngtcp2_crypto_picotls_from_epoch(size_t epoch) { switch (epoch) { case 0: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case 1: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case 2: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case 3: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); } } -size_t ngtcp2_crypto_picotls_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +size_t ngtcp2_crypto_picotls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return 0; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return 1; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return 2; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return 3; default: assert(0); @@ -543,8 +557,8 @@ int ngtcp2_crypto_picotls_collected_extensions( conn_ref = *ptls_get_data_ptr(ptls); conn = conn_ref->get_conn(conn_ref); - rv = ngtcp2_conn_decode_remote_transport_params(conn, extensions->data.base, - extensions->data.len); + rv = ngtcp2_conn_decode_and_set_remote_transport_params( + conn, extensions->data.base, extensions->data.len); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -561,7 +575,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self, const void *secret) { ngtcp2_crypto_conn_ref *conn_ref = *ptls_get_data_ptr(ptls); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = ngtcp2_crypto_picotls_from_epoch(epoch); + ngtcp2_encryption_level level = ngtcp2_crypto_picotls_from_epoch(epoch); ptls_cipher_suite_t *cipher = ptls_get_cipher(ptls); size_t secretlen = cipher->hash->digest_size; ngtcp2_crypto_picotls_ctx *cptls; @@ -574,7 +588,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self, return -1; } - if (level == NGTCP2_CRYPTO_LEVEL_HANDSHAKE) { + if (level == NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE) { /* libngtcp2 allows an application to change QUIC transport * parameters before installing Handshake tx key. We need to * wait for the key to get the correct local transport @@ -606,7 +620,7 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *ptls, int is_enc, size_t epoch, const void *secret) { ngtcp2_crypto_conn_ref *conn_ref = *ptls_get_data_ptr(ptls); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = ngtcp2_crypto_picotls_from_epoch(epoch); + ngtcp2_encryption_level level = ngtcp2_crypto_picotls_from_epoch(epoch); ptls_cipher_suite_t *cipher = ptls_get_cipher(ptls); size_t secretlen = cipher->hash->digest_size; @@ -660,7 +674,7 @@ int ngtcp2_crypto_picotls_configure_client_session( ngtcp2_crypto_picotls_ctx *cptls, ngtcp2_conn *conn) { ptls_handshake_properties_t *hsprops = &cptls->handshake_properties; - hsprops->client.max_early_data_size = calloc(1, sizeof(uint32_t)); + hsprops->client.max_early_data_size = calloc(1, sizeof(size_t)); if (hsprops->client.max_early_data_size == NULL) { return -1; } diff --git a/deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c similarity index 73% rename from deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c rename to deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c index 466d9e11ca6415..330ca687b44666 100644 --- a/deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -42,6 +42,168 @@ #include "shared.h" +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static int crypto_initialized; +static EVP_CIPHER *crypto_aes_128_gcm; +static EVP_CIPHER *crypto_aes_256_gcm; +static EVP_CIPHER *crypto_chacha20_poly1305; +static EVP_CIPHER *crypto_aes_128_ccm; +static EVP_CIPHER *crypto_aes_128_ctr; +static EVP_CIPHER *crypto_aes_256_ctr; +static EVP_CIPHER *crypto_chacha20; +static EVP_MD *crypto_sha256; +static EVP_MD *crypto_sha384; +static EVP_KDF *crypto_hkdf; + +int ngtcp2_crypto_quictls_init(void) { + crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL); + if (crypto_aes_128_gcm == NULL) { + return -1; + } + + crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL); + if (crypto_aes_256_gcm == NULL) { + return -1; + } + + crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL); + if (crypto_chacha20_poly1305 == NULL) { + return -1; + } + + crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL); + if (crypto_aes_128_ccm == NULL) { + return -1; + } + + crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL); + if (crypto_aes_128_ctr == NULL) { + return -1; + } + + crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL); + if (crypto_aes_256_ctr == NULL) { + return -1; + } + + crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL); + if (crypto_chacha20 == NULL) { + return -1; + } + + crypto_sha256 = EVP_MD_fetch(NULL, "sha256", NULL); + if (crypto_sha256 == NULL) { + return -1; + } + + crypto_sha384 = EVP_MD_fetch(NULL, "sha384", NULL); + if (crypto_sha384 == NULL) { + return -1; + } + + crypto_hkdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + if (crypto_hkdf == NULL) { + return -1; + } + + crypto_initialized = 1; + + return 0; +} + +static const EVP_CIPHER *crypto_aead_aes_128_gcm(void) { + if (crypto_aes_128_gcm) { + return crypto_aes_128_gcm; + } + + return EVP_aes_128_gcm(); +} + +static const EVP_CIPHER *crypto_aead_aes_256_gcm(void) { + if (crypto_aes_256_gcm) { + return crypto_aes_256_gcm; + } + + return EVP_aes_256_gcm(); +} + +static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) { + if (crypto_chacha20_poly1305) { + return crypto_chacha20_poly1305; + } + + return EVP_chacha20_poly1305(); +} + +static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) { + if (crypto_aes_128_ccm) { + return crypto_aes_128_ccm; + } + + return EVP_aes_128_ccm(); +} + +static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) { + if (crypto_aes_128_ctr) { + return crypto_aes_128_ctr; + } + + return EVP_aes_128_ctr(); +} + +static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) { + if (crypto_aes_256_ctr) { + return crypto_aes_256_ctr; + } + + return EVP_aes_256_ctr(); +} + +static const EVP_CIPHER *crypto_cipher_chacha20(void) { + if (crypto_chacha20) { + return crypto_chacha20; + } + + return EVP_chacha20(); +} + +static const EVP_MD *crypto_md_sha256(void) { + if (crypto_sha256) { + return crypto_sha256; + } + + return EVP_sha256(); +} + +static const EVP_MD *crypto_md_sha384(void) { + if (crypto_sha384) { + return crypto_sha384; + } + + return EVP_sha384(); +} + +static EVP_KDF *crypto_kdf_hkdf(void) { + if (crypto_hkdf) { + return crypto_hkdf; + } + + return EVP_KDF_fetch(NULL, "hkdf", NULL); +} +#else /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ +# define crypto_aead_aes_128_gcm EVP_aes_128_gcm +# define crypto_aead_aes_256_gcm EVP_aes_256_gcm +# define crypto_aead_chacha20_poly1305 EVP_chacha20_poly1305 +# define crypto_aead_aes_128_ccm EVP_aes_128_ccm +# define crypto_cipher_aes_128_ctr EVP_aes_128_ctr +# define crypto_cipher_aes_256_ctr EVP_aes_256_ctr +# define crypto_cipher_chacha20 EVP_chacha20 +# define crypto_md_sha256 EVP_sha256 +# define crypto_md_sha384 EVP_sha384 + +int ngtcp2_crypto_quictls_init(void) { return 0; } +#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ + static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) { switch (EVP_CIPHER_nid(aead)) { case NID_aes_128_gcm: @@ -58,18 +220,18 @@ static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) { } ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) { - return ngtcp2_crypto_aead_init(aead, (void *)EVP_aes_128_gcm()); + return ngtcp2_crypto_aead_init(aead, (void *)crypto_aead_aes_128_gcm()); } ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { - md->native_handle = (void *)EVP_sha256(); + md->native_handle = (void *)crypto_md_sha256(); return md; } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { - ngtcp2_crypto_aead_init(&ctx->aead, (void *)EVP_aes_128_gcm()); - ctx->md.native_handle = (void *)EVP_sha256(); - ctx->hp.native_handle = (void *)EVP_aes_128_ctr(); + ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm()); + ctx->md.native_handle = (void *)crypto_md_sha256(); + ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr(); ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -83,26 +245,26 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead, } ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { - return ngtcp2_crypto_aead_init(aead, (void *)EVP_aes_128_gcm()); + return ngtcp2_crypto_aead_init(aead, (void *)crypto_aead_aes_128_gcm()); } -static const EVP_CIPHER *crypto_ssl_get_aead(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_CIPHER *crypto_cipher_id_get_aead(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_gcm(); + return crypto_aead_aes_128_gcm(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); + return crypto_aead_aes_256_gcm(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); + return crypto_aead_chacha20_poly1305(); case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_aes_128_ccm(); + return crypto_aead_aes_128_ccm(); default: return NULL; } } -static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; @@ -115,8 +277,9 @@ static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t +crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; @@ -129,42 +292,75 @@ static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { } } -static const EVP_CIPHER *crypto_ssl_get_hp(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_aes_128_ctr(); + return crypto_cipher_aes_128_ctr(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_ctr(); + return crypto_cipher_aes_256_ctr(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20(); + return crypto_cipher_chacha20(); default: return NULL; } } -static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_CHACHA20_POLY1305_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_sha256(); + return crypto_md_sha256(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_sha384(); + return crypto_md_sha384(); default: return NULL; } } +static int supported_cipher_id(uint32_t cipher_id) { + switch (cipher_id) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + return 1; + default: + return 0; + } +} + +static ngtcp2_crypto_ctx *crypto_ctx_cipher_id(ngtcp2_crypto_ctx *ctx, + uint32_t cipher_id) { + ngtcp2_crypto_aead_init(&ctx->aead, + (void *)crypto_cipher_id_get_aead(cipher_id)); + ctx->md.native_handle = (void *)crypto_cipher_id_get_md(cipher_id); + ctx->hp.native_handle = (void *)crypto_cipher_id_get_hp(cipher_id); + ctx->max_encryption = crypto_cipher_id_get_aead_max_encryption(cipher_id); + ctx->max_decryption_failure = + crypto_cipher_id_get_aead_max_decryption_failure(cipher_id); + + return ctx; +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { SSL *ssl = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl)); - ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl); - ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl); - ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl); - ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl); - return ctx; + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + uint32_t cipher_id; + + if (cipher == NULL) { + return NULL; + } + + cipher_id = (uint32_t)SSL_CIPHER_get_id(cipher); + + if (!supported_cipher_id(cipher_id)) { + return NULL; + } + + return crypto_ctx_cipher_id(ctx, cipher_id); } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, @@ -327,7 +523,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *salt, size_t saltlen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); int mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; OSSL_PARAM params[] = { @@ -342,7 +538,9 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, (size_t)EVP_MD_size(prf), params) <= 0) { rv = -1; @@ -382,7 +580,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, size_t infolen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); int mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; OSSL_PARAM params[] = { @@ -397,7 +595,9 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) { rv = -1; @@ -436,7 +636,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *info, size_t infolen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); OSSL_PARAM params[] = { OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, @@ -451,7 +651,9 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) { rv = -1; @@ -591,15 +793,16 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +int ngtcp2_crypto_read_write_crypto_data( + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + const uint8_t *data, size_t datalen) { SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); int rv; int err; if (SSL_provide_quic_data( - ssl, ngtcp2_crypto_openssl_from_ngtcp2_crypto_level(crypto_level), + ssl, + ngtcp2_crypto_quictls_from_ngtcp2_encryption_level(encryption_level), data, datalen) != 1) { return -1; } @@ -613,9 +816,9 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, case SSL_ERROR_WANT_WRITE: return 0; case SSL_ERROR_WANT_CLIENT_HELLO_CB: - return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB; + return NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB; case SSL_ERROR_WANT_X509_LOOKUP: - return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP; + return NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP; case SSL_ERROR_SSL: return -1; default: @@ -623,7 +826,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } } - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = SSL_process_quic_post_handshake(ssl); @@ -652,7 +855,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { SSL_get_peer_quic_transport_params(ssl, &tp, &tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -670,17 +873,17 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_openssl_from_ossl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_quictls_from_ossl_encryption_level( OSSL_ENCRYPTION_LEVEL ossl_level) { switch (ossl_level) { case ssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case ssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case ssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case ssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); /* if NDEBUG is set */ @@ -688,16 +891,16 @@ ngtcp2_crypto_level ngtcp2_crypto_openssl_from_ossl_encryption_level( } OSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +ngtcp2_crypto_quictls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return ssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return ssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return ssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return ssl_encryption_early_data; default: assert(0); @@ -730,8 +933,8 @@ static int set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *tx_secret, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); + ngtcp2_encryption_level level = + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); if (rx_secret && ngtcp2_crypto_derive_and_install_rx_key(conn, NULL, NULL, NULL, level, @@ -752,8 +955,8 @@ static int add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); + ngtcp2_encryption_level level = + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); int rv; rv = ngtcp2_conn_submit_crypto_data(conn, level, data, datalen); @@ -786,22 +989,26 @@ static SSL_QUIC_METHOD quic_method = { add_handshake_data, flush_flight, send_alert, +#ifdef LIBRESSL_VERSION_NUMBER + NULL, + NULL, +#endif /* LIBRESSL_VERSION_NUMBER */ }; -static void crypto_openssl_configure_context(SSL_CTX *ssl_ctx) { +static void crypto_quictls_configure_context(SSL_CTX *ssl_ctx) { SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_quic_method(ssl_ctx, &quic_method); } -int ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx) { - crypto_openssl_configure_context(ssl_ctx); +int ngtcp2_crypto_quictls_configure_server_context(SSL_CTX *ssl_ctx) { + crypto_quictls_configure_context(ssl_ctx); return 0; } -int ngtcp2_crypto_openssl_configure_client_context(SSL_CTX *ssl_ctx) { - crypto_openssl_configure_context(ssl_ctx); +int ngtcp2_crypto_quictls_configure_client_context(SSL_CTX *ssl_ctx) { + crypto_quictls_configure_context(ssl_ctx); return 0; } diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.c b/deps/ngtcp2/ngtcp2/crypto/shared.c index 78252b852b4fab..162094a375cb8b 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.c +++ b/deps/ngtcp2/ngtcp2/crypto/shared.c @@ -64,11 +64,9 @@ int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, (size_t)(p - info)); } -#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 - -int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, - uint8_t *tx_secret, +int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *initial_secret, + uint32_t version, const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side) { static const uint8_t CLABEL[] = "client in"; @@ -88,16 +86,14 @@ int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, switch (version) { case NGTCP2_PROTO_VER_V1: + default: salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1; saltlen = sizeof(NGTCP2_INITIAL_SALT_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2_DRAFT; - saltlen = sizeof(NGTCP2_INITIAL_SALT_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2; + saltlen = sizeof(NGTCP2_INITIAL_SALT_V2) - 1; break; - default: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_DRAFT; - saltlen = sizeof(NGTCP2_INITIAL_SALT_DRAFT) - 1; } if (ngtcp2_crypto_hkdf_extract(initial_secret, &ctx.md, client_dcid->data, @@ -139,9 +135,9 @@ int ngtcp2_crypto_derive_packet_protection_key( static const uint8_t KEY_LABEL_V1[] = "quic key"; static const uint8_t IV_LABEL_V1[] = "quic iv"; static const uint8_t HP_KEY_LABEL_V1[] = "quic hp"; - static const uint8_t KEY_LABEL_V2_DRAFT[] = "quicv2 key"; - static const uint8_t IV_LABEL_V2_DRAFT[] = "quicv2 iv"; - static const uint8_t HP_KEY_LABEL_V2_DRAFT[] = "quicv2 hp"; + static const uint8_t KEY_LABEL_V2[] = "quicv2 key"; + static const uint8_t IV_LABEL_V2[] = "quicv2 iv"; + static const uint8_t HP_KEY_LABEL_V2[] = "quicv2 hp"; size_t keylen = ngtcp2_crypto_aead_keylen(aead); size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); const uint8_t *key_label; @@ -152,13 +148,13 @@ int ngtcp2_crypto_derive_packet_protection_key( size_t hp_key_labellen; switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: - key_label = KEY_LABEL_V2_DRAFT; - key_labellen = sizeof(KEY_LABEL_V2_DRAFT) - 1; - iv_label = IV_LABEL_V2_DRAFT; - iv_labellen = sizeof(IV_LABEL_V2_DRAFT) - 1; - hp_key_label = HP_KEY_LABEL_V2_DRAFT; - hp_key_labellen = sizeof(HP_KEY_LABEL_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + key_label = KEY_LABEL_V2; + key_labellen = sizeof(KEY_LABEL_V2) - 1; + iv_label = IV_LABEL_V2; + iv_labellen = sizeof(IV_LABEL_V2) - 1; + hp_key_label = HP_KEY_LABEL_V2; + hp_key_labellen = sizeof(HP_KEY_LABEL_V2) - 1; break; default: key_label = KEY_LABEL_V1; @@ -188,14 +184,27 @@ int ngtcp2_crypto_derive_packet_protection_key( return 0; } -int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, +int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen) { static const uint8_t LABEL[] = "quic ku"; + static const uint8_t LABEL_V2[] = "quicv2 ku"; + const uint8_t *label; + size_t labellen; + + switch (version) { + case NGTCP2_PROTO_VER_V2: + label = LABEL_V2; + labellen = sizeof(LABEL_V2) - 1; + break; + default: + label = LABEL; + labellen = sizeof(LABEL) - 1; + } if (ngtcp2_crypto_hkdf_expand_label(dest, secretlen, md, secret, secretlen, - LABEL, sizeof(LABEL) - 1) != 0) { + label, labellen) != 0) { return -1; } @@ -204,7 +213,7 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp_key, - ngtcp2_crypto_level level, + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen) { const ngtcp2_crypto_ctx *ctx; @@ -220,7 +229,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_CRYPTO_LEVEL_EARLY && !ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && !ngtcp2_conn_is_server(conn)) { return 0; } @@ -235,13 +244,16 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - ngtcp2_crypto_ctx_tls_early(&cctx, tls); - ngtcp2_conn_set_early_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_early_crypto_ctx(conn); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + if (ngtcp2_crypto_ctx_tls_early(&cctx, tls) == NULL) { + return -1; + } + + ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); version = ngtcp2_conn_get_client_chosen_version(conn); break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: if (ngtcp2_conn_is_server(conn) && !ngtcp2_conn_get_negotiated_version(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); @@ -250,15 +262,21 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } } /* fall through */ - default: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: ctx = ngtcp2_conn_get_crypto_ctx(conn); version = ngtcp2_conn_get_negotiated_version(conn); if (!ctx->aead.native_handle) { - ngtcp2_crypto_ctx_tls(&cctx, tls); + if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { + return -1; + } + ngtcp2_conn_set_crypto_ctx(conn, &cctx); ctx = ngtcp2_conn_get_crypto_ctx(conn); } + break; + default: + return -1; } aead = &ctx->aead; @@ -280,20 +298,20 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + rv = ngtcp2_conn_install_0rtt_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: rv = ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: if (!ngtcp2_conn_is_server(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { @@ -345,7 +363,7 @@ static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp_key, - ngtcp2_crypto_level level, + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen) { const ngtcp2_crypto_ctx *ctx; @@ -361,7 +379,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_CRYPTO_LEVEL_EARLY && ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && ngtcp2_conn_is_server(conn)) { return 0; } @@ -376,13 +394,16 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - ngtcp2_crypto_ctx_tls_early(&cctx, tls); - ngtcp2_conn_set_early_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_early_crypto_ctx(conn); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + if (ngtcp2_crypto_ctx_tls_early(&cctx, tls) == NULL) { + return -1; + } + + ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); version = ngtcp2_conn_get_client_chosen_version(conn); break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: if (ngtcp2_conn_is_server(conn) && !ngtcp2_conn_get_negotiated_version(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); @@ -391,15 +412,21 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } } /* fall through */ - default: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: ctx = ngtcp2_conn_get_crypto_ctx(conn); version = ngtcp2_conn_get_negotiated_version(conn); if (!ctx->aead.native_handle) { - ngtcp2_crypto_ctx_tls(&cctx, tls); + if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { + return -1; + } + ngtcp2_conn_set_crypto_ctx(conn, &cctx); ctx = ngtcp2_conn_get_crypto_ctx(conn); } + break; + default: + return -1; } aead = &ctx->aead; @@ -421,13 +448,13 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + rv = ngtcp2_conn_install_0rtt_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { @@ -440,7 +467,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { @@ -521,7 +548,7 @@ int ngtcp2_crypto_derive_and_install_initial_key( ngtcp2_conn_set_initial_crypto_ctx(conn, &ctx); if (ngtcp2_crypto_derive_initial_secrets( - version, rx_secret, tx_secret, initial_secret, client_dcid, + rx_secret, tx_secret, initial_secret, version, client_dcid, server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { return -1; @@ -564,16 +591,14 @@ int ngtcp2_crypto_derive_and_install_initial_key( switch (version) { case NGTCP2_PROTO_VER_V1: + default: retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V1; retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2_DRAFT; - retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2; + retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT; - retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } if (ngtcp2_crypto_aead_ctx_encrypt_init(&retry_aead_ctx, &retry_aead, @@ -657,7 +682,7 @@ int ngtcp2_crypto_derive_and_install_vneg_initial_key( } if (ngtcp2_crypto_derive_initial_secrets( - version, rx_secret, tx_secret, initial_secret, client_dcid, + rx_secret, tx_secret, initial_secret, version, client_dcid, server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { return -1; @@ -725,8 +750,8 @@ int ngtcp2_crypto_update_key( size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); uint32_t version = ngtcp2_conn_get_negotiated_version(conn); - if (ngtcp2_crypto_update_traffic_secret(rx_secret, md, current_rx_secret, - secretlen) != 0) { + if (ngtcp2_crypto_update_traffic_secret(rx_secret, version, md, + current_rx_secret, secretlen) != 0) { return -1; } @@ -735,8 +760,8 @@ int ngtcp2_crypto_update_key( return -1; } - if (ngtcp2_crypto_update_traffic_secret(tx_secret, md, current_tx_secret, - secretlen) != 0) { + if (ngtcp2_crypto_update_traffic_secret(tx_secret, version, md, + current_tx_secret, secretlen) != 0) { return -1; } @@ -883,6 +908,7 @@ static size_t crypto_generate_retry_token_aad(uint8_t *dest, uint32_t version, version = ngtcp2_htonl(version); memcpy(p, &version, sizeof(version)); + p += sizeof(version); memcpy(p, sa, (size_t)salen); p += salen; memcpy(p, retry_scid->data, retry_scid->datalen); @@ -907,13 +933,15 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token( ngtcp2_crypto_md md; ngtcp2_crypto_aead_ctx aead_ctx; size_t plaintextlen; - uint8_t aad[sizeof(version) + sizeof(ngtcp2_sockaddr_storage) + - NGTCP2_MAX_CIDLEN]; + uint8_t + aad[sizeof(version) + sizeof(ngtcp2_sockaddr_union) + NGTCP2_MAX_CIDLEN]; size_t aadlen; uint8_t *p = plaintext; ngtcp2_tstamp ts_be = ngtcp2_htonl64(ts); int rv; + assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); + memset(plaintext, 0, sizeof(plaintext)); *p++ = (uint8_t)odcid->datalen; @@ -984,8 +1012,8 @@ int ngtcp2_crypto_verify_retry_token( ngtcp2_crypto_aead_ctx aead_ctx; ngtcp2_crypto_aead aead; ngtcp2_crypto_md md; - uint8_t aad[sizeof(version) + sizeof(ngtcp2_sockaddr_storage) + - NGTCP2_MAX_CIDLEN]; + uint8_t + aad[sizeof(version) + sizeof(ngtcp2_sockaddr_union) + NGTCP2_MAX_CIDLEN]; size_t aadlen; const uint8_t *rand_data; const uint8_t *ciphertext; @@ -994,6 +1022,8 @@ int ngtcp2_crypto_verify_retry_token( int rv; ngtcp2_tstamp gen_ts; + assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); + if (tokenlen != NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN || token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY) { return -1; @@ -1034,7 +1064,9 @@ int ngtcp2_crypto_verify_retry_token( cil = plaintext[0]; - assert(cil == 0 || (cil >= NGTCP2_MIN_CIDLEN && cil <= NGTCP2_MAX_CIDLEN)); + if (cil != 0 && (cil < NGTCP2_MIN_CIDLEN || cil > NGTCP2_MAX_CIDLEN)) { + return -1; + } memcpy(&gen_ts, plaintext + /* cid len = */ 1 + NGTCP2_MAX_CIDLEN, sizeof(gen_ts)); @@ -1055,11 +1087,11 @@ static size_t crypto_generate_regular_token_aad(uint8_t *dest, size_t addrlen; switch (sa->sa_family) { - case AF_INET: + case NGTCP2_AF_INET: addr = (const uint8_t *)&((const ngtcp2_sockaddr_in *)(void *)sa)->sin_addr; addrlen = sizeof(((const ngtcp2_sockaddr_in *)(void *)sa)->sin_addr); break; - case AF_INET6: + case NGTCP2_AF_INET6: addr = (const uint8_t *)&((const ngtcp2_sockaddr_in6 *)(void *)sa)->sin6_addr; addrlen = sizeof(((const ngtcp2_sockaddr_in6 *)(void *)sa)->sin6_addr); @@ -1234,8 +1266,8 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close( ngtcp2_crypto_ctx_initial(&ctx); - if (ngtcp2_crypto_derive_initial_secrets(version, rx_secret, tx_secret, - initial_secret, scid, + if (ngtcp2_crypto_derive_initial_secrets(rx_secret, tx_secret, initial_secret, + version, scid, NGTCP2_CRYPTO_SIDE_SERVER) != 0) { return -1; } @@ -1287,16 +1319,14 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, switch (version) { case NGTCP2_PROTO_VER_V1: + default: key = (const uint8_t *)NGTCP2_RETRY_KEY_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - key = (const uint8_t *)NGTCP2_RETRY_KEY_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + key = (const uint8_t *)NGTCP2_RETRY_KEY_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead, key, noncelen) != @@ -1331,8 +1361,8 @@ int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) { return NGTCP2_ERR_CALLBACK_FAILURE; } - if (ngtcp2_crypto_read_write_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, - NULL, 0) != 0) { + if (ngtcp2_crypto_read_write_crypto_data( + conn, NGTCP2_ENCRYPTION_LEVEL_INITIAL, NULL, 0) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1398,15 +1428,15 @@ void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( } int ngtcp2_crypto_recv_crypto_data_cb(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data) { int rv; (void)offset; (void)user_data; - if (ngtcp2_crypto_read_write_crypto_data(conn, crypto_level, data, datalen) != - 0) { + if (ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, + datalen) != 0) { rv = ngtcp2_conn_get_tls_error(conn); if (rv) { return rv; diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.h b/deps/ngtcp2/ngtcp2/crypto/shared.h index 02b948901ae40e..d69fd21212d7d2 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.h +++ b/deps/ngtcp2/ngtcp2/crypto/shared.h @@ -31,16 +31,6 @@ #include -/** - * @macro - * - * :macro:`NGTCP2_INITIAL_SALT_DRAFT` is a salt value which is used to - * derive initial secret. It is used for QUIC draft versions. - */ -#define NGTCP2_INITIAL_SALT_DRAFT \ - "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \ - "\xa8\x99" - /** * @macro * @@ -54,12 +44,12 @@ /** * @macro * - * :macro:`NGTCP2_INITIAL_SALT_V2_DRAFT` is a salt value which is used to - * derive initial secret. It is used for QUIC v2 draft. + * :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to + * derive initial secret. It is used for QUIC v2. */ -#define NGTCP2_INITIAL_SALT_V2_DRAFT \ - "\xa7\x07\xc2\x03\xa5\x9b\x47\x18\x4a\x1d\x62\xca\x57\x04\x06\xea\x7a\xe3" \ - "\xe5\xd3" +#define NGTCP2_INITIAL_SALT_V2 \ + "\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd" \ + "\x2e\xd9" /* Maximum key usage (encryption) limits */ #define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23) @@ -72,6 +62,30 @@ #define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305 (1ULL << 36) #define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM (2965820ULL) +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_SECRETLEN` is the length of secret + * for Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 + +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_KEYLEN` is the length of key for + * Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_KEYLEN 16 + +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_IVLEN` is the length of IV for + * Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_IVLEN 12 + /** * @function * @@ -86,7 +100,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx); * `ngtcp2_crypto_aead_init` initializes |aead| with the provided * |aead_native_handle| which is an underlying AEAD object. * - * If libngtcp2_crypto_openssl is linked, |aead_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |aead_native_handle| must be * a pointer to EVP_CIPHER. * * If libngtcp2_crypto_gnutls is linked, |aead_native_handle| must be @@ -106,6 +120,25 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead, */ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead); +/** + * @enum + * + * :type:`ngtcp2_crypto_side` indicates which side the application + * implements; client or server. + */ +typedef enum ngtcp2_crypto_side { + /** + * :enum:`NGTCP2_CRYPTO_SIDE_CLIENT` indicates that the application + * is client. + */ + NGTCP2_CRYPTO_SIDE_CLIENT, + /** + * :enum:`NGTCP2_CRYPTO_SIDE_SERVER` indicates that the application + * is server. + */ + NGTCP2_CRYPTO_SIDE_SERVER +} ngtcp2_crypto_side; + /** * @function * @@ -122,9 +155,9 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead); * * This function returns 0 if it succeeds, or -1. */ -int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, - uint8_t *tx_secret, +int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *initial_secret, + uint32_t version, const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side); @@ -168,7 +201,7 @@ int ngtcp2_crypto_derive_packet_protection_key(uint8_t *key, uint8_t *iv, * * This function returns 0 if it succeeds, or -1. */ -int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, +int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen); @@ -181,7 +214,7 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, * pointed by |buf| of length |len|, to the native handle |tls|. * * |tls| points to a implementation dependent TLS session object. If - * libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL + * libngtcp2_crypto_quictls is linked, |tls| must be a pointer to SSL * object. * * This function returns 0 if it succeeds, or -1. @@ -197,7 +230,7 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, * `ngtcp2_conn_set_remote_transport_params`. * * |tls| points to a implementation dependent TLS session object. If - * libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL + * libngtcp2_crypto_quictls is linked, |tls| must be a pointer to SSL * object. * * This function returns 0 if it succeeds, or -1. @@ -347,4 +380,18 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead); */ int ngtcp2_crypto_random(uint8_t *data, size_t datalen); +/** + * @function + * + * `ngtcp2_crypto_hkdf_expand_label` performs HKDF expand label. The + * result is |destlen| bytes long, and is stored to the buffer pointed + * by |dest|. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, + const ngtcp2_crypto_md *md, + const uint8_t *secret, size_t secretlen, + const uint8_t *label, size_t labellen); + #endif /* NGTCP2_SHARED_H */ diff --git a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c index 9a58b9be2b76e9..2b7b5321863915 100644 --- a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c @@ -73,9 +73,8 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)wolfSSL_EVP_aes_128_gcm()); } -static uint64_t crypto_wolfssl_get_aead_max_encryption(WOLFSSL *ssl) { - const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - +static uint64_t +crypto_aead_get_aead_max_encryption(const WOLFSSL_EVP_CIPHER *aead) { if (wolfSSL_quic_aead_is_gcm(aead)) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; } @@ -88,9 +87,8 @@ static uint64_t crypto_wolfssl_get_aead_max_encryption(WOLFSSL *ssl) { return 0; } -static uint64_t crypto_wolfssl_get_aead_max_decryption_failure(WOLFSSL *ssl) { - const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - +static uint64_t +crypto_aead_get_aead_max_decryption_failure(const WOLFSSL_EVP_CIPHER *aead) { if (wolfSSL_quic_aead_is_gcm(aead)) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; } @@ -103,16 +101,30 @@ static uint64_t crypto_wolfssl_get_aead_max_decryption_failure(WOLFSSL *ssl) { return 0; } +static int supported_aead(const WOLFSSL_EVP_CIPHER *aead) { + return wolfSSL_quic_aead_is_gcm(aead) || + wolfSSL_quic_aead_is_chacha20(aead) || wolfSSL_quic_aead_is_ccm(aead); +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { WOLFSSL *ssl = tls_native_handle; + const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - ngtcp2_crypto_aead_init(&ctx->aead, (void *)wolfSSL_quic_get_aead(ssl)); + if (aead == NULL) { + return NULL; + } + + if (!supported_aead(aead)) { + return NULL; + } + + ngtcp2_crypto_aead_init(&ctx->aead, (void *)aead); ctx->md.native_handle = (void *)wolfSSL_quic_get_md(ssl); ctx->hp.native_handle = (void *)wolfSSL_quic_get_hp(ssl); - ctx->max_encryption = crypto_wolfssl_get_aead_max_encryption(ssl); + ctx->max_encryption = crypto_aead_get_aead_max_encryption(aead); ctx->max_decryption_failure = - crypto_wolfssl_get_aead_max_decryption_failure(ssl); + crypto_aead_get_aead_max_decryption_failure(aead); return ctx; } @@ -211,6 +223,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *salt, size_t saltlen) { if (wolfSSL_quic_hkdf_extract(dest, md->native_handle, secret, secretlen, salt, saltlen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf_extract FAILED\n"); return -1; } return 0; @@ -222,6 +235,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, size_t infolen) { if (wolfSSL_quic_hkdf_expand(dest, destlen, md->native_handle, secret, secretlen, info, infolen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf_expand FAILED\n"); return -1; } return 0; @@ -233,6 +247,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *info, size_t infolen) { if (wolfSSL_quic_hkdf(dest, destlen, md->native_handle, secret, secretlen, salt, saltlen, info, infolen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf FAILED\n"); return -1; } return 0; @@ -286,18 +301,19 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, sizeof(PLAINTEXT) - 1) != WOLFSSL_SUCCESS || wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: hp_mask FAILED\n"); return -1; } return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +int ngtcp2_crypto_read_write_crypto_data( + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + const uint8_t *data, size_t datalen) { WOLFSSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); WOLFSSL_ENCRYPTION_LEVEL level = - ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level(crypto_level); + ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level(encryption_level); int rv; int err; @@ -313,9 +329,9 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, if (!ngtcp2_conn_get_handshake_completed(conn)) { rv = wolfSSL_quic_do_handshake(ssl); - DEBUG_MSG("WOLFSSL: do_handshake, rv=%d\n", rv); if (rv <= 0) { err = wolfSSL_get_error(ssl, rv); + DEBUG_MSG("WOLFSSL: do_handshake, rv=%d, err=%d\n", rv, err); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: @@ -328,7 +344,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } DEBUG_MSG("WOLFSSL: handshake done\n"); - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = wolfSSL_process_quic_post_handshake(ssl); @@ -359,7 +375,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { wolfSSL_get_peer_quic_transport_params(ssl, &tp, &tplen); DEBUG_MSG("WOLFSSL: get peer transport params, len=%lu\n", tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { DEBUG_MSG("WOLFSSL: decode peer transport params failed, rv=%d\n", rv); ngtcp2_conn_set_tls_error(conn, rv); @@ -380,17 +396,17 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( WOLFSSL_ENCRYPTION_LEVEL wolfssl_level) { switch (wolfssl_level) { case wolfssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case wolfssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case wolfssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case wolfssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); /* if NDEBUG is set */ @@ -398,16 +414,16 @@ ngtcp2_crypto_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( } WOLFSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return wolfssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return wolfssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return wolfssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return wolfssl_encryption_early_data; default: assert(0); @@ -441,7 +457,7 @@ static int set_encryption_secrets(WOLFSSL *ssl, const uint8_t *tx_secret, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level(wolfssl_level); DEBUG_MSG("WOLFSSL: set encryption secrets, level=%d, rxlen=%lu, txlen=%lu\n", @@ -467,7 +483,7 @@ static int add_handshake_data(WOLFSSL *ssl, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level(wolfssl_level); int rv; @@ -514,11 +530,17 @@ static void crypto_wolfssl_configure_context(WOLFSSL_CTX *ssl_ctx) { int ngtcp2_crypto_wolfssl_configure_server_context(WOLFSSL_CTX *ssl_ctx) { crypto_wolfssl_configure_context(ssl_ctx); +#if PRINTF_DEBUG + wolfSSL_Debugging_ON(); +#endif return 0; } int ngtcp2_crypto_wolfssl_configure_client_context(WOLFSSL_CTX *ssl_ctx) { crypto_wolfssl_configure_context(ssl_ctx); wolfSSL_CTX_UseSessionTicket(ssl_ctx); +#if PRINTF_DEBUG + wolfSSL_Debugging_ON(); +#endif return 0; } diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h index ed71cb3ea0cb37..a8d4b4afd3a470 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h @@ -54,26 +54,13 @@ # ifdef WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN -# endif +# endif /* WIN32_LEAN_AND_MEAN */ # include -# else +# else /* !WIN32 */ # include # include -# endif -#endif - -#ifdef AF_INET -# define NGTCP2_AF_INET AF_INET -#else -# define NGTCP2_AF_INET 2 -#endif - -#ifdef AF_INET6 -# define NGTCP2_AF_INET6 AF_INET6 -#else -# define NGTCP2_AF_INET6 23 -# define NGTCP2_USE_GENERIC_IPV6_SOCKADDR -#endif +# endif /* !WIN32 */ +#endif /* NGTCP2_USE_GENERIC_SOCKADDR */ #include @@ -181,7 +168,7 @@ typedef void *(*ngtcp2_realloc)(void *ptr, size_t size, void *user_data); * * void conn_new() { * ngtcp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb, - * my_realloc_cb}; + * my_realloc_cb}; * * ... * } @@ -223,7 +210,8 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 second. + * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 + * second. */ #define NGTCP2_SECONDS ((ngtcp2_duration)1000000000ULL) @@ -267,34 +255,16 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_PROTO_VER_V2_DRAFT` is the provisional version - * number for QUIC version 2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_PROTO_VER_V2` is the QUIC version 2. See + * :rfc:`9369`. */ -#define NGTCP2_PROTO_VER_V2_DRAFT ((uint32_t)0x709a50c4u) - -/** - * @macro - * - * :macro:`NGTCP2_PROTO_VER_DRAFT_MAX` is the maximum QUIC draft - * version that this library supports. - */ -#define NGTCP2_PROTO_VER_DRAFT_MAX 0xff000020u - -/** - * @macro - * - * :macro:`NGTCP2_PROTO_VER_DRAFT_MIN` is the minimum QUIC draft - * version that this library supports. - */ -#define NGTCP2_PROTO_VER_DRAFT_MIN 0xff00001du +#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6b3343cfu) /** * @macro * * :macro:`NGTCP2_PROTO_VER_MAX` is the highest QUIC version that this - * library supports. + * library supports. Deprecated since v1.1.0. */ #define NGTCP2_PROTO_VER_MAX NGTCP2_PROTO_VER_V1 @@ -302,9 +272,9 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_PROTO_VER_MIN` is the lowest QUIC version that this - * library supports. + * library supports. Deprecated since v1.1.0. */ -#define NGTCP2_PROTO_VER_MIN NGTCP2_PROTO_VER_DRAFT_MIN +#define NGTCP2_PROTO_VER_MIN NGTCP2_PROTO_VER_V1 /** * @macro @@ -324,7 +294,7 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` is the default maximum UDP - * datagram payload size that this endpoint transmits. + * datagram payload size that the local endpoint transmits. */ #define NGTCP2_MAX_UDP_PAYLOAD_SIZE 1200 @@ -362,7 +332,7 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN` is the minimum length - * of random bytes (Unpredictable Bits) in Stateless Reset packet + * of random bytes (Unpredictable Bits) in Stateless Reset packet. */ #define NGTCP2_MIN_STATELESS_RESET_RANDLEN 5 @@ -374,24 +344,6 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_PATH_CHALLENGE_DATALEN 8 -/** - * @macro - * - * :macro:`NGTCP2_RETRY_KEY_DRAFT` is an encryption key to create - * integrity tag of Retry packet. It is used for QUIC draft versions. - */ -#define NGTCP2_RETRY_KEY_DRAFT \ - "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1" - -/** - * @macro - * - * :macro:`NGTCP2_RETRY_NONCE_DRAFT` is nonce used when generating - * integrity tag of Retry packet. It is used for QUIC draft versions. - */ -#define NGTCP2_RETRY_NONCE_DRAFT \ - "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c" - /** * @macro * @@ -404,32 +356,29 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating integrity - * tag of Retry packet. It is used for QUIC v1. + * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating + * integrity tag of Retry packet. It is used for QUIC v1. */ #define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb" /** * @macro * - * :macro:`NGTCP2_RETRY_KEY_V2_DRAFT` is an encryption key to create - * integrity tag of Retry packet. It is used for QUIC v2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_RETRY_KEY_V2` is an encryption key to create + * integrity tag of Retry packet. It is used for QUIC v2. See + * :rfc:`9369`. */ -#define NGTCP2_RETRY_KEY_V2_DRAFT \ - "\xba\x85\x8d\xc7\xb4\x3d\xe5\xdb\xf8\x76\x17\xff\x4a\xb2\x53\xdb" +#define NGTCP2_RETRY_KEY_V2 \ + "\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92" /** * @macro * - * :macro:`NGTCP2_RETRY_NONCE_V2_DRAFT` is nonce used when generating - * integrity tag of Retry packet. It is used for QUIC v2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_RETRY_NONCE_V2` is nonce used when generating + * integrity tag of Retry packet. It is used for QUIC v2. See + * :rfc:`9369`. */ -#define NGTCP2_RETRY_NONCE_V2_DRAFT \ - "\x14\x1b\x99\xc2\x39\xb0\x3e\x78\x5d\x6a\x2e\x9f" +#define NGTCP2_RETRY_NONCE_V2 "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a" /** * @macro @@ -476,14 +425,6 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_MIN_INITIAL_DCIDLEN 8 -/** - * @macro - * - * :macro:`NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT` is the default handshake - * timeout. - */ -#define NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT (10 * NGTCP2_SECONDS) - /** * @macrosection * @@ -525,8 +466,8 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_ECN_MASK 0x3 -#define NGTCP2_PKT_INFO_VERSION_V1 1 -#define NGTCP2_PKT_INFO_VERSION NGTCP2_PKT_INFO_VERSION_V1 +#define NGTCP2_PKT_INFO_V1 1 +#define NGTCP2_PKT_INFO_VERSION NGTCP2_PKT_INFO_V1 /** * @struct @@ -535,12 +476,12 @@ typedef struct ngtcp2_mem { */ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { /** - * :member:`ecn` is ECN marking and when passing - * `ngtcp2_conn_read_pkt()`, and it should be either + * :member:`ecn` is ECN marking, and when it is passed to + * `ngtcp2_conn_read_pkt()`, it should be either * :macro:`NGTCP2_ECN_NOT_ECT`, :macro:`NGTCP2_ECN_ECT_1`, * :macro:`NGTCP2_ECN_ECT_0`, or :macro:`NGTCP2_ECN_CE`. */ - uint32_t ecn; + uint8_t ecn; } ngtcp2_pkt_info; /** @@ -562,190 +503,190 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_ERR_NOBUF` indicates that a provided buffer does not * have enough space to store data. */ -#define NGTCP2_ERR_NOBUF -203 +#define NGTCP2_ERR_NOBUF -202 /** * @macro * * :macro:`NGTCP2_ERR_PROTO` indicates a general protocol error. */ -#define NGTCP2_ERR_PROTO -205 +#define NGTCP2_ERR_PROTO -203 /** * @macro * * :macro:`NGTCP2_ERR_INVALID_STATE` indicates that a requested * operation is not allowed at the current connection state. */ -#define NGTCP2_ERR_INVALID_STATE -206 +#define NGTCP2_ERR_INVALID_STATE -204 /** * @macro * * :macro:`NGTCP2_ERR_ACK_FRAME` indicates that an invalid ACK frame * is received. */ -#define NGTCP2_ERR_ACK_FRAME -207 +#define NGTCP2_ERR_ACK_FRAME -205 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` indicates that there is no * spare stream ID available. */ -#define NGTCP2_ERR_STREAM_ID_BLOCKED -208 +#define NGTCP2_ERR_STREAM_ID_BLOCKED -206 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_IN_USE` indicates that a stream ID is * already in use. */ -#define NGTCP2_ERR_STREAM_IN_USE -209 +#define NGTCP2_ERR_STREAM_IN_USE -207 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED` indicates that stream data * cannot be sent because of flow control. */ -#define NGTCP2_ERR_STREAM_DATA_BLOCKED -210 +#define NGTCP2_ERR_STREAM_DATA_BLOCKED -208 /** * @macro * * :macro:`NGTCP2_ERR_FLOW_CONTROL` indicates flow control error. */ -#define NGTCP2_ERR_FLOW_CONTROL -211 +#define NGTCP2_ERR_FLOW_CONTROL -209 /** * @macro * * :macro:`NGTCP2_ERR_CONNECTION_ID_LIMIT` indicates that the number * of received Connection ID exceeds acceptable limit. */ -#define NGTCP2_ERR_CONNECTION_ID_LIMIT -212 +#define NGTCP2_ERR_CONNECTION_ID_LIMIT -210 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_LIMIT` indicates that a remote endpoint * opens more streams that is permitted. */ -#define NGTCP2_ERR_STREAM_LIMIT -213 +#define NGTCP2_ERR_STREAM_LIMIT -211 /** * @macro * * :macro:`NGTCP2_ERR_FINAL_SIZE` indicates that inconsistent final * size of a stream. */ -#define NGTCP2_ERR_FINAL_SIZE -214 +#define NGTCP2_ERR_FINAL_SIZE -212 /** * @macro * * :macro:`NGTCP2_ERR_CRYPTO` indicates crypto (TLS) related error. */ -#define NGTCP2_ERR_CRYPTO -215 +#define NGTCP2_ERR_CRYPTO -213 /** * @macro * * :macro:`NGTCP2_ERR_PKT_NUM_EXHAUSTED` indicates that packet number * is exhausted. */ -#define NGTCP2_ERR_PKT_NUM_EXHAUSTED -216 +#define NGTCP2_ERR_PKT_NUM_EXHAUSTED -214 /** * @macro * * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` indicates that a * required transport parameter is missing. */ -#define NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM -217 +#define NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM -215 /** * @macro * * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` indicates that a * transport parameter is malformed. */ -#define NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM -218 +#define NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM -216 /** * @macro * * :macro:`NGTCP2_ERR_FRAME_ENCODING` indicates there is an error in * frame encoding. */ -#define NGTCP2_ERR_FRAME_ENCODING -219 +#define NGTCP2_ERR_FRAME_ENCODING -217 /** * @macro * * :macro:`NGTCP2_ERR_DECRYPT` indicates a decryption failure. */ -#define NGTCP2_ERR_DECRYPT -220 +#define NGTCP2_ERR_DECRYPT -218 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_SHUT_WR` indicates no more data can be * sent to a stream. */ -#define NGTCP2_ERR_STREAM_SHUT_WR -221 +#define NGTCP2_ERR_STREAM_SHUT_WR -219 /** * @macro * - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` indicates that a stream was not - * found. + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` indicates that a stream was + * not found. */ -#define NGTCP2_ERR_STREAM_NOT_FOUND -222 +#define NGTCP2_ERR_STREAM_NOT_FOUND -220 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_STATE` indicates that a requested * operation is not allowed at the current stream state. */ -#define NGTCP2_ERR_STREAM_STATE -226 +#define NGTCP2_ERR_STREAM_STATE -221 /** * @macro * * :macro:`NGTCP2_ERR_RECV_VERSION_NEGOTIATION` indicates that Version * Negotiation packet was received. */ -#define NGTCP2_ERR_RECV_VERSION_NEGOTIATION -229 +#define NGTCP2_ERR_RECV_VERSION_NEGOTIATION -222 /** * @macro * * :macro:`NGTCP2_ERR_CLOSING` indicates that connection is in closing * state. */ -#define NGTCP2_ERR_CLOSING -230 +#define NGTCP2_ERR_CLOSING -223 /** * @macro * * :macro:`NGTCP2_ERR_DRAINING` indicates that connection is in * draining state. */ -#define NGTCP2_ERR_DRAINING -231 +#define NGTCP2_ERR_DRAINING -224 /** * @macro * * :macro:`NGTCP2_ERR_TRANSPORT_PARAM` indicates a general transport * parameter error. */ -#define NGTCP2_ERR_TRANSPORT_PARAM -234 +#define NGTCP2_ERR_TRANSPORT_PARAM -225 /** * @macro * * :macro:`NGTCP2_ERR_DISCARD_PKT` indicates a packet was discarded. */ -#define NGTCP2_ERR_DISCARD_PKT -235 +#define NGTCP2_ERR_DISCARD_PKT -226 /** * @macro * * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` indicates that there is no * spare Connection ID available. */ -#define NGTCP2_ERR_CONN_ID_BLOCKED -237 +#define NGTCP2_ERR_CONN_ID_BLOCKED -227 /** * @macro * * :macro:`NGTCP2_ERR_INTERNAL` indicates an internal error. */ -#define NGTCP2_ERR_INTERNAL -238 +#define NGTCP2_ERR_INTERNAL -228 /** * @macro * * :macro:`NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED` indicates that a crypto * buffer exceeded. */ -#define NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED -239 +#define NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED -229 /** * @macro * @@ -753,21 +694,21 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used and a function call * succeeded. */ -#define NGTCP2_ERR_WRITE_MORE -240 +#define NGTCP2_ERR_WRITE_MORE -230 /** * @macro * * :macro:`NGTCP2_ERR_RETRY` indicates that server should send Retry * packet. */ -#define NGTCP2_ERR_RETRY -241 +#define NGTCP2_ERR_RETRY -231 /** * @macro * * :macro:`NGTCP2_ERR_DROP_CONN` indicates that an endpoint should * drop connection immediately. */ -#define NGTCP2_ERR_DROP_CONN -242 +#define NGTCP2_ERR_DROP_CONN -232 /** * @macro * @@ -775,7 +716,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * limit is reached and key update is not available. An endpoint * should drop connection immediately. */ -#define NGTCP2_ERR_AEAD_LIMIT_REACHED -243 +#define NGTCP2_ERR_AEAD_LIMIT_REACHED -233 /** * @macro * @@ -783,41 +724,41 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * could not probe that a path is capable of sending UDP datagram * payload of size at least 1200 bytes. */ -#define NGTCP2_ERR_NO_VIABLE_PATH -244 +#define NGTCP2_ERR_NO_VIABLE_PATH -234 /** * @macro * * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION` indicates that server * should send Version Negotiation packet. */ -#define NGTCP2_ERR_VERSION_NEGOTIATION -245 +#define NGTCP2_ERR_VERSION_NEGOTIATION -235 /** * @macro * * :macro:`NGTCP2_ERR_HANDSHAKE_TIMEOUT` indicates that QUIC * connection is not established before the specified deadline. */ -#define NGTCP2_ERR_HANDSHAKE_TIMEOUT -246 +#define NGTCP2_ERR_HANDSHAKE_TIMEOUT -236 /** * @macro * * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE` indicates the * version negotiation failed. */ -#define NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE -247 +#define NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE -237 /** * @macro * * :macro:`NGTCP2_ERR_IDLE_CLOSE` indicates the connection should be * closed silently because of idle timeout. */ -#define NGTCP2_ERR_IDLE_CLOSE -248 +#define NGTCP2_ERR_IDLE_CLOSE -238 /** * @macro * * :macro:`NGTCP2_ERR_FATAL` indicates that error codes less than this * value is fatal error. When this error is returned, an endpoint - * should drop connection immediately. + * should close connection immediately. */ #define NGTCP2_ERR_FATAL -500 /** @@ -892,7 +833,7 @@ typedef enum ngtcp2_pkt_type { */ NGTCP2_PKT_INITIAL = 0x10, /** - * :enum:`NGTCP2_PKT_0RTT` indicates 0RTT packet. + * :enum:`NGTCP2_PKT_0RTT` indicates 0-RTT packet. */ NGTCP2_PKT_0RTT = 0x11, /** @@ -1061,12 +1002,10 @@ typedef enum ngtcp2_pkt_type { /** * @macro * - * :macro:`NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT` is QUIC transport - * error code ``VERSION_NEGOTIATION_ERROR``. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_VERSION_NEGOTIATION_ERROR` is QUIC transport error + * code ``VERSION_NEGOTIATION_ERROR``. See :rfc:`9368`. */ -#define NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT 0x53f8u +#define NGTCP2_VERSION_NEGOTIATION_ERROR 0x11 /** * @enum @@ -1096,6 +1035,8 @@ typedef enum ngtcp2_path_validation_result { * @typedef * * :type:`ngtcp2_tstamp` is a timestamp with nanosecond resolution. + * ``UINT64_MAX`` is an invalid value, and it is often used to + * indicate that no value is set. */ typedef uint64_t ngtcp2_tstamp; @@ -1103,7 +1044,8 @@ typedef uint64_t ngtcp2_tstamp; * @typedef * * :type:`ngtcp2_duration` is a period of time in nanosecond - * resolution. + * resolution. ``UINT64_MAX`` is an invalid value, and it is often + * used to indicate that no value is set. */ typedef uint64_t ngtcp2_duration; @@ -1178,10 +1120,15 @@ typedef struct ngtcp2_pkt_hd { */ int64_t pkt_num; /** - * :member:`token` contains token for Initial - * packet. + * :member:`token` contains token. Only Initial packet may contain + * token. NULL if no token is present. */ - ngtcp2_vec token; + const uint8_t *token; + /** + * :member:`tokenlen` is the length of :member:`token`. 0 if no + * token is present. + */ + size_t tokenlen; /** * :member:`pkt_numlen` is the number of bytes spent to encode * :member:`pkt_num`. @@ -1197,8 +1144,10 @@ typedef struct ngtcp2_pkt_hd { */ uint32_t version; /** - * :member:`type` is a type of QUIC packet. See - * :type:`ngtcp2_pkt_type`. + * :member:`type` is a type of QUIC packet. This field does not + * have a QUIC packet type defined for a specific QUIC version. + * Instead, it contains version independent packet type defined by + * this library. See :type:`ngtcp2_pkt_type`. */ uint8_t type; /** @@ -1229,25 +1178,6 @@ typedef struct ngtcp2_pkt_stateless_reset { size_t randlen; } ngtcp2_pkt_stateless_reset; -/** - * @enum - * - * :type:`ngtcp2_transport_params_type` defines TLS message type which - * carries transport parameters. - */ -typedef enum ngtcp2_transport_params_type { - /** - * :enum:`NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO` is Client Hello - * TLS message. - */ - NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - /** - * :enum:`NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS` is - * Encrypted Extensions TLS message. - */ - NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS -} ngtcp2_transport_params_type; - /** * @macrosection * @@ -1296,14 +1226,96 @@ typedef enum ngtcp2_transport_params_type { */ #define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39u +#ifdef NGTCP2_USE_GENERIC_SOCKADDR +# ifndef NGTCP2_AF_INET +# error NGTCP2_AF_INET must be defined +# endif /* !NGTCP2_AF_INET */ + +# ifndef NGTCP2_AF_INET6 +# error NGTCP2_AF_INET6 must be defined +# endif /* !NGTCP2_AF_INET6 */ + +typedef unsigned short int ngtcp2_sa_family; +typedef uint16_t ngtcp2_in_port; + +typedef struct ngtcp2_sockaddr { + ngtcp2_sa_family sa_family; + uint8_t sa_data[14]; +} ngtcp2_sockaddr; + +typedef struct ngtcp2_in_addr { + uint32_t s_addr; +} ngtcp2_in_addr; + +typedef struct ngtcp2_sockaddr_in { + ngtcp2_sa_family sin_family; + ngtcp2_in_port sin_port; + ngtcp2_in_addr sin_addr; + uint8_t sin_zero[8]; +} ngtcp2_sockaddr_in; + +typedef struct ngtcp2_in6_addr { + uint8_t in6_addr[16]; +} ngtcp2_in6_addr; + +typedef struct ngtcp2_sockaddr_in6 { + ngtcp2_sa_family sin6_family; + ngtcp2_in_port sin6_port; + uint32_t sin6_flowinfo; + ngtcp2_in6_addr sin6_addr; + uint32_t sin6_scope_id; +} ngtcp2_sockaddr_in6; + +typedef uint32_t ngtcp2_socklen; +#else /* !NGTCP2_USE_GENERIC_SOCKADDR */ +# define NGTCP2_AF_INET AF_INET +# define NGTCP2_AF_INET6 AF_INET6 + /** - * @macro + * @typedef * - * :macro:`NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_DRAFT` is TLS - * extension type of quic_transport_parameters used during draft - * development. + * :type:`ngtcp2_sockaddr` is typedefed to struct sockaddr. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct sockaddr defined in ngtcp2.h. + */ +typedef struct sockaddr ngtcp2_sockaddr; +/** + * @typedef + * + * :type:`ngtcp2_sockaddr_in` is typedefed to struct sockaddr_in. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct sockaddr_in defined in ngtcp2.h. + */ +typedef struct sockaddr_in ngtcp2_sockaddr_in; +/** + * @typedef + * + * :type:`ngtcp2_sockaddr_in6` is typedefed to struct sockaddr_in6. + * If :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed + * to the generic struct sockaddr_in6 defined in ngtcp2.h. + */ +typedef struct sockaddr_in6 ngtcp2_sockaddr_in6; +/** + * @typedef + * + * :type:`ngtcp2_socklen` is typedefed to socklen_t. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * uint32_t. + */ +typedef socklen_t ngtcp2_socklen; +#endif /* !NGTCP2_USE_GENERIC_SOCKADDR */ + +/** + * @struct + * + * :type:`ngtcp2_sockaddr_union` conveniently includes all supported + * address types. */ -#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_DRAFT 0xffa5u +typedef union ngtcp2_sockaddr_union { + ngtcp2_sockaddr sa; + ngtcp2_sockaddr_in in; + ngtcp2_sockaddr_in6 in6; +} ngtcp2_sockaddr_union; /** * @struct @@ -1317,29 +1329,21 @@ typedef struct ngtcp2_preferred_addr { */ ngtcp2_cid cid; /** - * :member:`ipv4_port` is a port of IPv4 address. - */ - uint16_t ipv4_port; - /** - * :member:`ipv6_port` is a port of IPv6 address. + * :member:`ipv4` contains IPv4 address and port. */ - uint16_t ipv6_port; + ngtcp2_sockaddr_in ipv4; /** - * :member:`ipv4_addr` contains IPv4 address in network byte order. + * :member:`ipv6` contains IPv6 address and port. */ - uint8_t ipv4_addr[4]; + ngtcp2_sockaddr_in6 ipv6; /** - * :member:`ipv6_addr` contains IPv6 address in network byte order. - */ - uint8_t ipv6_addr[16]; - /** - * :member:`ipv4_present` indicates that :member:`ipv4_addr` and - * :member:`ipv4_port` contain IPv4 address and port respectively. + * :member:`ipv4_present` indicates that :member:`ipv4` contains + * IPv4 address and port. */ uint8_t ipv4_present; /** - * :member:`ipv6_present` indicates that :member:`ipv6_addr` and - * :member:`ipv6_port` contain IPv6 address and port respectively. + * :member:`ipv6_present` indicates that :member:`ipv6` contains + * IPv6 address and port. */ uint8_t ipv6_present; /** @@ -1352,7 +1356,7 @@ typedef struct ngtcp2_preferred_addr { * @struct * * :type:`ngtcp2_version_info` represents version_information - * structure. + * structure. See :rfc:`9368`. */ typedef struct ngtcp2_version_info { /** @@ -1360,19 +1364,21 @@ typedef struct ngtcp2_version_info { */ uint32_t chosen_version; /** - * :member:`other_versions` points the wire image of other_versions - * field. The each version is therefore in network byte order. + * :member:`available_versions` points the wire image of + * available_versions field. The each version is therefore in + * network byte order. */ - uint8_t *other_versions; + const uint8_t *available_versions; /** - * :member:`other_versionslen` is the number of bytes pointed by - * :member:`other_versions`, not the number of versions included. + * :member:`available_versionslen` is the number of bytes pointed by + * :member:`available_versions`, not the number of versions + * included. */ - size_t other_versionslen; + size_t available_versionslen; } ngtcp2_version_info; -#define NGTCP2_TRANSPORT_PARAMS_VERSION_V1 1 -#define NGTCP2_TRANSPORT_PARAMS_VERSION NGTCP2_TRANSPORT_PARAMS_VERSION_V1 +#define NGTCP2_TRANSPORT_PARAMS_V1 1 +#define NGTCP2_TRANSPORT_PARAMS_VERSION NGTCP2_TRANSPORT_PARAMS_V1 /** * @struct @@ -1382,55 +1388,58 @@ typedef struct ngtcp2_version_info { */ typedef struct ngtcp2_transport_params { /** - * :member:`preferred_address` contains preferred address if - * :member:`preferred_address_present` is nonzero. + * :member:`preferred_addr` contains preferred address if + * :member:`preferred_addr_present` is nonzero. */ - ngtcp2_preferred_addr preferred_address; + ngtcp2_preferred_addr preferred_addr; /** * :member:`original_dcid` is the Destination Connection ID field * from the first Initial packet from client. Server must specify - * this field. It is expected that application knows the original - * Destination Connection ID even if it sends Retry packet, for - * example, by including it in retry token. Otherwise, application - * should not specify this field. + * this field and set :member:`original_dcid_present` to nonzero. + * It is expected that application knows the original Destination + * Connection ID even if it sends Retry packet, for example, by + * including it in retry token. Otherwise, application should not + * specify this field. */ ngtcp2_cid original_dcid; /** * :member:`initial_scid` is the Source Connection ID field from the - * first Initial packet the endpoint sends. Application should not - * specify this field. + * first Initial packet the local endpoint sends. Application + * should not specify this field. If :member:`initial_scid_present` + * is set to nonzero, it indicates this field is set. */ ngtcp2_cid initial_scid; /** * :member:`retry_scid` is the Source Connection ID field from Retry * packet. Only server uses this field. If server application - * received Initial packet with retry token from client and server - * verified its token, server application must set Destination - * Connection ID field from the Initial packet to this field and set - * :member:`retry_scid_present` to nonzero. Server application must - * verify that the Destination Connection ID from Initial packet was - * sent in Retry packet by, for example, including the Connection ID - * in a token, or including it in AAD when encrypting a token. + * received Initial packet with retry token from client, and server + * successfully verified its token, server application must set + * Destination Connection ID field from the Initial packet to this + * field, and set :member:`retry_scid_present` to nonzero. Server + * application must verify that the Destination Connection ID from + * Initial packet was sent in Retry packet by, for example, + * including the Connection ID in a token, or including it in AAD + * when encrypting a token. */ ngtcp2_cid retry_scid; /** * :member:`initial_max_stream_data_bidi_local` is the size of flow * control window of locally initiated stream. This is the number - * of bytes that the remote endpoint can send and the local endpoint - * must ensure that it has enough buffer to receive them. + * of bytes that the remote endpoint can send, and the local + * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_bidi_local; /** * :member:`initial_max_stream_data_bidi_remote` is the size of flow * control window of remotely initiated stream. This is the number - * of bytes that the remote endpoint can send and the local endpoint - * must ensure that it has enough buffer to receive them. + * of bytes that the remote endpoint can send, and the local + * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_bidi_remote; /** * :member:`initial_max_stream_data_uni` is the size of flow control * window of remotely initiated unidirectional stream. This is the - * number of bytes that the remote endpoint can send and the local + * number of bytes that the remote endpoint can send, and the local * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_uni; @@ -1451,12 +1460,13 @@ typedef struct ngtcp2_transport_params { uint64_t initial_max_streams_uni; /** * :member:`max_idle_timeout` is a duration during which sender - * allows quiescent. + * allows quiescent. 0 means no idle timeout. It must not be + * UINT64_MAX. */ ngtcp2_duration max_idle_timeout; /** - * :member:`max_udp_payload_size` is the maximum datagram size that - * the endpoint can receive. + * :member:`max_udp_payload_size` is the maximum UDP payload size + * that the local endpoint can receive. */ uint64_t max_udp_payload_size; /** @@ -1471,14 +1481,16 @@ typedef struct ngtcp2_transport_params { uint64_t ack_delay_exponent; /** * :member:`max_ack_delay` is the maximum acknowledgement delay by - * which the endpoint will delay sending acknowledgements. + * which the local endpoint will delay sending acknowledgements. It + * must be strictly less than (1 << 14) milliseconds. + * Sub-millisecond part is dropped when sending it in a QUIC + * transport parameter. */ ngtcp2_duration max_ack_delay; /** * :member:`max_datagram_frame_size` is the maximum size of DATAGRAM - * frame that this endpoint willingly receives. Specifying 0 - * disables DATAGRAM support. See - * https://datatracker.ietf.org/doc/html/rfc9221 + * frame that the local endpoint willingly receives. Specifying 0 + * disables DATAGRAM support. See :rfc:`9221`. */ uint64_t max_datagram_frame_size; /** @@ -1487,30 +1499,37 @@ typedef struct ngtcp2_transport_params { */ uint8_t stateless_reset_token_present; /** - * :member:`disable_active_migration` is nonzero if the endpoint - * does not support active connection migration. + * :member:`disable_active_migration` is nonzero if the local + * endpoint does not support active connection migration. */ uint8_t disable_active_migration; + /** + * :member:`original_dcid_present` is nonzero if + * :member:`original_dcid` field is set. + */ + uint8_t original_dcid_present; + /** + * :member:`initial_scid_present` is nonzero if + * :member:`initial_scid` field is set. + */ + uint8_t initial_scid_present; /** * :member:`retry_scid_present` is nonzero if :member:`retry_scid` * field is set. */ uint8_t retry_scid_present; /** - * :member:`preferred_address_present` is nonzero if + * :member:`preferred_addr_present` is nonzero if * :member:`preferred_address` is set. */ - uint8_t preferred_address_present; + uint8_t preferred_addr_present; /** * :member:`stateless_reset_token` contains stateless reset token. */ uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN]; /** * :member:`grease_quic_bit` is nonzero if sender supports "Greasing - * the QUIC Bit" extension. See - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-bit-grease. - * Note that the local endpoint always enables greasing QUIC bit - * regardless of this field value. + * the QUIC Bit" extension. See :rfc:`9287`. */ uint8_t grease_quic_bit; /** @@ -1527,44 +1546,15 @@ typedef struct ngtcp2_transport_params { uint8_t version_info_present; } ngtcp2_transport_params; -/** - * @enum - * - * :type:`ngtcp2_pktns_id` defines packet number space identifier. - */ -typedef enum ngtcp2_pktns_id { - /** - * :enum:`NGTCP2_PKTNS_ID_INITIAL` is the Initial packet number - * space. - */ - NGTCP2_PKTNS_ID_INITIAL, - /** - * :enum:`NGTCP2_PKTNS_ID_HANDSHAKE` is the Handshake packet number - * space. - */ - NGTCP2_PKTNS_ID_HANDSHAKE, - /** - * :enum:`NGTCP2_PKTNS_ID_APPLICATION` is the Application data - * packet number space. - */ - NGTCP2_PKTNS_ID_APPLICATION, - /** - * :enum:`NGTCP2_PKTNS_ID_MAX` is defined to get the number of - * packet number spaces. - */ - NGTCP2_PKTNS_ID_MAX -} ngtcp2_pktns_id; - -#define NGTCP2_CONN_STAT_VERSION_V1 1 -#define NGTCP2_CONN_STAT_VERSION NGTCP2_CONN_STAT_VERSION_V1 +#define NGTCP2_CONN_INFO_V1 1 +#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V1 /** * @struct * - * :type:`ngtcp2_conn_stat` holds various connection statistics, and - * computed data for recovery and congestion controller. + * :type:`ngtcp2_conn_info` holds various connection statistics. */ -typedef struct ngtcp2_conn_stat { +typedef struct ngtcp2_conn_info { /** * :member:`latest_rtt` is the latest RTT sample which is not * adjusted by acknowledgement delay. @@ -1583,35 +1573,6 @@ typedef struct ngtcp2_conn_stat { * :member:`rttvar` is a mean deviation of observed RTT. */ ngtcp2_duration rttvar; - /** - * :member:`initial_rtt` is the initial RTT which is used when no - * RTT sample is available. - */ - ngtcp2_duration initial_rtt; - /** - * :member:`first_rtt_sample_ts` is the timestamp when the first RTT - * sample is obtained. - */ - ngtcp2_tstamp first_rtt_sample_ts; - /** - * :member:`pto_count` is the count of successive PTO timer - * expiration. - */ - size_t pto_count; - /** - * :member:`loss_detection_timer` is the deadline of the current - * loss detection timer. - */ - ngtcp2_tstamp loss_detection_timer; - /** - * :member:`last_tx_pkt_ts` corresponds to - * time_of_last_ack_eliciting_packet in :rfc:`9002`. - */ - ngtcp2_tstamp last_tx_pkt_ts[NGTCP2_PKTNS_ID_MAX]; - /** - * :member:`loss_time` corresponds to loss_time in :rfc:`9002`. - */ - ngtcp2_tstamp loss_time[NGTCP2_PKTNS_ID_MAX]; /** * :member:`cwnd` is the size of congestion window. */ @@ -1620,38 +1581,12 @@ typedef struct ngtcp2_conn_stat { * :member:`ssthresh` is slow start threshold. */ uint64_t ssthresh; - /** - * :member:`congestion_recovery_start_ts` is the timestamp when - * congestion recovery started. - */ - ngtcp2_tstamp congestion_recovery_start_ts; /** * :member:`bytes_in_flight` is the number in bytes of all sent * packets which have not been acknowledged. */ uint64_t bytes_in_flight; - /** - * :member:`max_udp_payload_size` is the maximum size of UDP - * datagram payload that this endpoint transmits. It is used by - * congestion controller to compute congestion window. - */ - size_t max_udp_payload_size; - /** - * :member:`delivery_rate_sec` is the current sending rate measured - * in byte per second. - */ - uint64_t delivery_rate_sec; - /** - * :member:`pacing_rate` is the current packet sending rate. If - * pacing is disabled, 0 is set. - */ - double pacing_rate; - /** - * :member:`send_quantum` is the maximum size of a data aggregate - * scheduled and transmitted together. - */ - size_t send_quantum; -} ngtcp2_conn_stat; +} ngtcp2_conn_info; /** * @enum @@ -1668,15 +1603,9 @@ typedef enum ngtcp2_cc_algo { */ NGTCP2_CC_ALGO_CUBIC = 0x01, /** - * :enum:`NGTCP2_CC_ALGO_BBR` represents BBR. If BBR is chosen, - * packet pacing is enabled. + * :enum:`NGTCP2_CC_ALGO_BBR` represents BBR v2. */ - NGTCP2_CC_ALGO_BBR = 0x02, - /** - * :enum:`NGTCP2_CC_ALGO_BBR2` represents BBR v2. If BBR v2 is - * chosen, packet pacing is enabled. - */ - NGTCP2_CC_ALGO_BBR2 = 0x03 + NGTCP2_CC_ALGO_BBR = 0x02 } ngtcp2_cc_algo; /** @@ -1737,27 +1666,30 @@ typedef void (*ngtcp2_qlog_write)(void *user_data, uint32_t flags, const void *data, size_t datalen); /** - * @struct + * @enum * - * :type:`ngtcp2_qlog_settings` is a set of settings for qlog. + * :type:`ngtcp2_token_type` defines the type of token. */ -typedef struct ngtcp2_qlog_settings { +typedef enum ngtcp2_token_type { + /** + * :enum:`NGTCP2_TOKEN_TYPE_UNKNOWN` indicates that the type of + * token is unknown. + */ + NGTCP2_TOKEN_TYPE_UNKNOWN, /** - * :member:`odcid` is Original Destination Connection ID sent by - * client. It is used as group_id and ODCID fields. Client ignores - * this field and uses dcid parameter passed to - * `ngtcp2_conn_client_new()`. + * :enum:`NGTCP2_TOKEN_TYPE_RETRY` indicates that a token comes from + * Retry packet. */ - ngtcp2_cid odcid; + NGTCP2_TOKEN_TYPE_RETRY, /** - * :member:`write` is a callback function to write qlog. Setting - * ``NULL`` disables qlog. + * :enum:`NGTCP2_TOKEN_TYPE_NEW_TOKEN` indicates that a token comes + * from NEW_TOKEN frame. */ - ngtcp2_qlog_write write; -} ngtcp2_qlog_settings; + NGTCP2_TOKEN_TYPE_NEW_TOKEN +} ngtcp2_token_type; -#define NGTCP2_SETTINGS_VERSION_V1 1 -#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_VERSION_V1 +#define NGTCP2_SETTINGS_V1 1 +#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V1 /** * @struct @@ -1766,9 +1698,10 @@ typedef struct ngtcp2_qlog_settings { */ typedef struct ngtcp2_settings { /** - * :member:`qlog` is qlog settings. + * :member:`qlog_write` is a callback function to write qlog. + * Setting ``NULL`` disables qlog. */ - ngtcp2_qlog_settings qlog; + ngtcp2_qlog_write qlog_write; /** * :member:`cc_algo` specifies congestion control algorithm. */ @@ -1789,24 +1722,37 @@ typedef struct ngtcp2_settings { */ ngtcp2_printf log_printf; /** - * :member:`max_udp_payload_size` is the maximum size of UDP - * datagram payload that this endpoint transmits. It is used by - * congestion controller to compute congestion window. + * :member:`max_tx_udp_payload_size` is the maximum size of UDP + * datagram payload that the local endpoint transmits. It is used + * by congestion controller to compute congestion window. */ - size_t max_udp_payload_size; + size_t max_tx_udp_payload_size; /** * :member:`token` is a token from Retry packet or NEW_TOKEN frame. * * Server sets this field if it received the token in Client Initial - * packet and successfully validated. + * packet and successfully validated. It should also set + * :member:`token_type` field. * * Client sets this field if it intends to send token in its Initial * packet. * * `ngtcp2_conn_server_new` and `ngtcp2_conn_client_new` make a copy * of token. + * + * Set NULL if there is no token. */ - ngtcp2_vec token; + const uint8_t *token; + /** + * :member:`tokenlen` is the length of :member:`token`. Set 0 if + * there is no token. + */ + size_t tokenlen; + /** + * :member:`token_type` is the type of token. Server application + * should set this field. + */ + ngtcp2_token_type token_type; /** * :member:`rand_ctx` is an optional random number generator to be * passed to :type:`ngtcp2_rand` callback. @@ -1834,20 +1780,20 @@ typedef struct ngtcp2_settings { */ uint64_t max_stream_window; /** - * :member:`ack_thresh` is the maximum number of unacknowledged - * packets before sending acknowledgement. It triggers the - * immediate acknowledgement. + * :member:`ack_thresh` is the minimum number of the received ACK + * eliciting packets that trigger the immediate acknowledgement from + * the local endpoint. */ size_t ack_thresh; /** - * :member:`no_udp_payload_size_shaping`, if set to nonzero, + * :member:`no_tx_udp_payload_size_shaping`, if set to nonzero, * instructs the library not to limit the UDP payload size to * :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` (which can be extended by - * Path MTU Discovery) and instead use the mininum size among the - * given buffer size, :member:`max_udp_payload_size`, and the - * received max_udp_payload QUIC transport parameter. + * Path MTU Discovery), and instead use the minimum size among the + * given buffer size, :member:`max_tx_udp_payload_size`, and the + * received max_udp_payload_size QUIC transport parameter. */ - int no_udp_payload_size_shaping; + uint8_t no_tx_udp_payload_size_shaping; /** * :member:`handshake_timeout` is the period of time before giving * up QUIC connection establishment. If QUIC handshake is not @@ -1865,10 +1811,13 @@ typedef struct ngtcp2_settings { * of preference. * * On compatible version negotiation, server will negotiate one of - * those versions contained in this array if a client initially - * chooses a less preferred version. This version set corresponds - * to Offered Versions in QUIC Version Negotiation draft, and it should - * be sent in Version Negotiation packet. + * those versions contained in this array if there is some overlap + * between these versions and the versions offered by the client. + * If there is no overlap, but the client chosen version is + * supported by the library, the server chooses the client chosen + * version as the negotiated version. This version set corresponds + * to Offered Versions described in :rfc:`9368`, and it should be + * included in Version Negotiation packet. * * Client uses this field and :member:`original_version` to prevent * version downgrade attack if it reacted upon Version Negotiation @@ -1876,7 +1825,7 @@ typedef struct ngtcp2_settings { * |client_chosen_version| passed to `ngtcp2_conn_client_new` unless * |client_chosen_version| is a reserved version. */ - uint32_t *preferred_versions; + const uint32_t *preferred_versions; /** * :member:`preferred_versionslen` is the number of versions that * are contained in the array pointed by @@ -1884,13 +1833,14 @@ typedef struct ngtcp2_settings { */ size_t preferred_versionslen; /** - * :member:`other_versions` is the array of versions that are set in - * :member:`other_versions ` - * field of outgoing version_information QUIC transport parameter. + * :member:`available_versions` is the array of versions that are + * going to be set in :member:`available_versions + * ` field of outgoing + * version_information QUIC transport parameter. * - * For server, this corresponds to Fully-Deployed Versions in QUIC - * Version Negotiation draft. If this field is set not, it is set - * to :member:`preferred_versions` internally if + * For server, this corresponds to Fully-Deployed Versions described + * in :rfc:`9368`. If this field is not set, it is set to + * :member:`preferred_versions` internally if * :member:`preferred_versionslen` is not zero. If this field is * not set, and :member:`preferred_versionslen` is zero, this field * is set to :macro:`NGTCP2_PROTO_VER_V1` internally. @@ -1902,12 +1852,13 @@ typedef struct ngtcp2_settings { * `ngtcp2_conn_client_new` will be set in this field internally * unless |client_chosen_version| is a reserved version. */ - uint32_t *other_versions; + const uint32_t *available_versions; /** - * :member:`other_versionslen` is the number of versions that are - * contained in the array pointed by :member:`other_versions`. + * :member:`available_versionslen` is the number of versions that + * are contained in the array pointed by + * :member:`available_versions`. */ - size_t other_versionslen; + size_t available_versionslen; /** * :member:`original_version` is the original version that client * initially used to make a connection attempt. If it is set, and @@ -1920,92 +1871,14 @@ typedef struct ngtcp2_settings { * :member:`no_pmtud`, if set to nonzero, disables Path MTU * Discovery. */ - int no_pmtud; + uint8_t no_pmtud; + /** + * :member:`pkt_num` is the initial packet number for each packet + * number space. It must be in range [0, INT32_MAX], inclusive. + */ + uint32_t initial_pkt_num; } ngtcp2_settings; -#ifdef NGTCP2_USE_GENERIC_SOCKADDR -typedef struct ngtcp2_sockaddr { - uint16_t sa_family; - uint8_t sa_data[14]; -} ngtcp2_sockaddr; - -typedef struct ngtcp2_in_addr { - uint32_t s_addr; -} ngtcp2_in_addr; - -typedef struct ngtcp2_sockaddr_in { - uint16_t sin_family; - uint16_t sin_port; - ngtcp2_in_addr sin_addr; - uint8_t sin_zero[8]; -} ngtcp2_sockaddr_in; - -# define NGTCP2_SS_MAXSIZE 128 -# define NGTCP2_SS_ALIGNSIZE (sizeof(uint64_t)) -# define NGTCP2_SS_PAD1SIZE (NGTCP2_SS_ALIGNSIZE - sizeof(uint16_t)) -# define NGTCP2_SS_PAD2SIZE \ - (NGTCP2_SS_MAXSIZE - \ - (sizeof(uint16_t) + NGTCP2_SS_PAD1SIZE + NGTCP2_SS_ALIGNSIZE)) - -typedef struct ngtcp2_sockaddr_storage { - uint16_t ss_family; - uint8_t _ss_pad1[NGTCP2_SS_PAD1SIZE]; - uint64_t _ss_align; - uint8_t _ss_pad2[NGTCP2_SS_PAD2SIZE]; -} ngtcp2_sockaddr_storage; - -# undef NGTCP2_SS_PAD2SIZE -# undef NGTCP2_SS_PAD1SIZE -# undef NGTCP2_SS_ALIGNSIZE -# undef NGTCP2_SS_MAXSIZE - -typedef uint32_t ngtcp2_socklen; -#else -/** - * @typedef - * - * :type:`ngtcp2_sockaddr` is typedefed to struct sockaddr. If - * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to - * the generic struct sockaddr defined in ngtcp2.h. - */ -typedef struct sockaddr ngtcp2_sockaddr; -/** - * @typedef - * - * :type:`ngtcp2_sockaddr_storage` is typedefed to struct - * sockaddr_storage. If :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is - * defined, it is typedefed to the generic struct sockaddr_storage - * defined in ngtcp2.h. - */ -typedef struct sockaddr_storage ngtcp2_sockaddr_storage; -typedef struct sockaddr_in ngtcp2_sockaddr_in; -/** - * @typedef - * - * :type:`ngtcp2_socklen` is typedefed to socklen_t. If - * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to - * uint32_t. - */ -typedef socklen_t ngtcp2_socklen; -#endif - -#if defined(NGTCP2_USE_GENERIC_SOCKADDR) || \ - defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR) -typedef struct ngtcp2_in6_addr { - uint8_t in6_addr[16]; -} ngtcp2_in6_addr; - -typedef struct ngtcp2_sockaddr_in6 { - uint16_t sin6_family; - uint16_t sin6_port; - uint32_t sin6_flowinfo; - ngtcp2_in6_addr sin6_addr; - uint32_t sin6_scope_id; -} ngtcp2_sockaddr_in6; -#else -typedef struct sockaddr_in6 ngtcp2_sockaddr_in6; -#endif - /** * @struct * @@ -2018,7 +1891,8 @@ typedef struct ngtcp2_addr { */ ngtcp2_sockaddr *addr; /** - * :member:`addrlen` is the length of addr. + * :member:`addrlen` is the length of :member:`addr`. It must not + * be longer than sizeof(:type:`ngtcp2_sockaddr_union`). */ ngtcp2_socklen addrlen; } ngtcp2_addr; @@ -2045,7 +1919,7 @@ typedef struct ngtcp2_path { * Note that :type:`ngtcp2_path` is generally passed to * :type:`ngtcp2_conn` by an application, and :type:`ngtcp2_conn` * stores their copies. Unfortunately, there is no way for the - * application to know when :type:`ngtcp2_conn` finishes using a + * application to know when :type:`ngtcp2_conn` finished using a * specific :type:`ngtcp2_path` object in mid connection, which * means that the application cannot free the data pointed by this * field. Therefore, it is advised to use this field only when the @@ -2069,11 +1943,11 @@ typedef struct ngtcp2_path_storage { /** * :member:`local_addrbuf` is a buffer to store local address. */ - ngtcp2_sockaddr_storage local_addrbuf; + ngtcp2_sockaddr_union local_addrbuf; /** * :member:`remote_addrbuf` is a buffer to store remote address. */ - ngtcp2_sockaddr_storage remote_addrbuf; + ngtcp2_sockaddr_union remote_addrbuf; } ngtcp2_path_storage; /** @@ -2160,8 +2034,9 @@ typedef struct ngtcp2_crypto_cipher_ctx { * :type:`ngtcp2_crypto_ctx` is a convenient structure to bind all * crypto related objects in one place. Use * `ngtcp2_crypto_ctx_initial` to initialize this struct for Initial - * packet encryption. For Handshake and 1RTT packets, use - * `ngtcp2_crypto_ctx_tls`. + * packet encryption. For Handshake and 1-RTT packets, use + * `ngtcp2_crypto_ctx_tls`. For 0-RTT packets, use + * `ngtcp2_crypto_ctx_tls_early`. */ typedef struct ngtcp2_crypto_ctx { /** @@ -2191,60 +2066,56 @@ typedef struct ngtcp2_crypto_ctx { /** * @function * - * `ngtcp2_encode_transport_params` encodes |params| in |dest| of + * `ngtcp2_transport_params_encode` encodes |params| in |dest| of * length |destlen|. * * If |dest| is NULL, and |destlen| is zero, this function just * returns the number of bytes required to store the encoded transport * parameters. * - * This function returns the number of written, or one of the + * This function returns the number of bytes written, or one of the * following negative error codes: * * :macro:`NGTCP2_ERR_NOBUF` * Buffer is too small. - * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |exttype| is invalid. */ -NGTCP2_EXTERN ngtcp2_ssize ngtcp2_encode_transport_params_versioned( - uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype, - int transport_params_version, const ngtcp2_transport_params *params); +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_transport_params_encode_versioned( + uint8_t *dest, size_t destlen, int transport_params_version, + const ngtcp2_transport_params *params); /** * @function * - * `ngtcp2_decode_transport_params` decodes transport parameters in + * `ngtcp2_transport_params_decode` decodes transport parameters in * |data| of length |datalen|, and stores the result in the object * pointed by |params|. * - * If the optional parameters are missing, the default value is - * assigned. + * If an optional parameter is missing, the default value is assigned. * * The following fields may point to somewhere inside the buffer * pointed by |data| of length |datalen|: * - * - :member:`ngtcp2_transport_params.version_info.other_versions - * ` + * - :member:`ngtcp2_transport_params.version_info.available_versions + * ` * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` - * The required parameter is missing. * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` * The input is malformed. */ -NGTCP2_EXTERN int ngtcp2_decode_transport_params_versioned( - int transport_params_version, ngtcp2_transport_params *params, - ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen); +NGTCP2_EXTERN int +ngtcp2_transport_params_decode_versioned(int transport_params_version, + ngtcp2_transport_params *params, + const uint8_t *data, size_t datalen); /** * @function * - * `ngtcp2_decode_transport_params_new` decodes transport parameters + * `ngtcp2_transport_params_decode_new` decodes transport parameters * in |data| of length |datalen|, and stores the result in the object * allocated dynamically. The pointer to the allocated object is - * assigned to |*pparams|. Unlike `ngtcp2_decode_transport_params`, + * assigned to |*pparams|. Unlike `ngtcp2_transport_params_decode`, * all direct and indirect fields are also allocated dynamically if * needed. * @@ -2261,22 +2132,21 @@ NGTCP2_EXTERN int ngtcp2_decode_transport_params_versioned( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` - * The required parameter is missing. * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` * The input is malformed. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_decode_transport_params_new( - ngtcp2_transport_params **pparams, ngtcp2_transport_params_type exttype, - const uint8_t *data, size_t datalen, const ngtcp2_mem *mem); +NGTCP2_EXTERN int +ngtcp2_transport_params_decode_new(ngtcp2_transport_params **pparams, + const uint8_t *data, size_t datalen, + const ngtcp2_mem *mem); /** * @function * * `ngtcp2_transport_params_del` frees the |params| which must be - * dynamically allocated by `ngtcp2_decode_transport_params_new`. + * dynamically allocated by `ngtcp2_transport_params_decode_new`. * * |mem| is a memory allocator that allocated |params|. If |mem| is * ``NULL``, the memory allocator returned by `ngtcp2_mem_default()` @@ -2331,15 +2201,16 @@ typedef struct ngtcp2_version_cid { * QUIC version. * * If the given packet is Long header packet, this function extracts - * the version from the packet and assigns it to + * the version from the packet, and assigns it to * :member:`dest->version `. It also * extracts the pointer to the Destination Connection ID and its - * length and assigns them to :member:`dest->dcid + * length, and assigns them to :member:`dest->dcid * ` and :member:`dest->dcidlen * ` respectively. Similarly, it extracts - * the pointer to the Source Connection ID and its length and assigns + * the pointer to the Source Connection ID and its length, and assigns * them to :member:`dest->scid ` and * :member:`dest->scidlen ` respectively. + * |short_dcidlen| is ignored. * * If the given packet is Short header packet, :member:`dest->version * ` will be 0, :member:`dest->scid @@ -2348,7 +2219,7 @@ typedef struct ngtcp2_version_cid { * Because the Short header packet does not have the length of * Destination Connection ID, the caller has to pass the length in * |short_dcidlen|. This function extracts the pointer to the - * Destination Connection ID and assigns it to :member:`dest->dcid + * Destination Connection ID, and assigns it to :member:`dest->dcid * `. |short_dcidlen| is assigned to * :member:`dest->dcidlen `. * @@ -2408,12 +2279,12 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, /** * @function * - * `ngtcp2_pkt_decode_hd_short` decodes QUIC short header packet - * header in |pkt| of length |pktlen|. |dcidlen| is the length of - * DCID in packet header. Short header packet does not encode the - * length of connection ID, thus we need the input from the outside. - * This function only parses the input just before packet number - * field. This function can handle Connection ID up to + * `ngtcp2_pkt_decode_hd_short` decodes QUIC short header in |pkt| of + * length |pktlen|. Short header packet does not encode the length of + * Connection ID, thus we need the input from the outside. |dcidlen| + * is the length of Destination Connection ID in packet header. This + * function only parses the input just before packet number field. + * This function can handle Connection ID up to * :macro:`NGTCP2_MAX_CIDLEN`. Consider to use * `ngtcp2_pkt_decode_version_cid` to get longer Connection ID. It * stores the result in the object pointed by |dest|, and returns the @@ -2461,13 +2332,13 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset( * * `ngtcp2_pkt_write_version_negotiation` writes Version Negotiation * packet in the buffer pointed by |dest| whose length is |destlen|. - * |unused_random| should be generated randomly. |dcid| is the - * destination connection ID which appears in a packet as a source - * connection ID sent by client which caused version negotiation. - * Similarly, |scid| is the source connection ID which appears in a - * packet as a destination connection ID sent by client. |sv| is a - * list of supported versions, and |nsv| specifies the number of - * supported versions included in |sv|. + * |unused_random| should be generated randomly. |dcid| is a + * Connection ID which appeared in a packet as a Source Connection ID + * sent by client which caused version negotiation. Similarly, |scid| + * is a Connection ID which appeared in a packet as a Destination + * Connection ID sent by client. |sv| is a list of supported + * versions, and |nsv| specifies the number of supported versions + * included in |sv|. * * This function returns the number of bytes written to the buffer, or * one of the following negative error codes: @@ -2494,7 +2365,7 @@ typedef struct ngtcp2_conn ngtcp2_conn; * asks TLS stack to produce first TLS cryptographic handshake data. * * This implementation of this callback must get the first handshake - * data from TLS stack and pass it to ngtcp2 library using + * data from TLS stack, and pass it to ngtcp2 library using * `ngtcp2_conn_submit_crypto_data` function. Make sure that before * calling `ngtcp2_conn_submit_crypto_data` function, client * application must create initial packet protection keys and IVs, and @@ -2514,9 +2385,9 @@ typedef int (*ngtcp2_client_initial)(ngtcp2_conn *conn, void *user_data); * Initial packet from client. An server application must implement * this callback, and generate initial keys and IVs for both * transmission and reception. Install them using - * `ngtcp2_conn_install_initial_key`. |dcid| is the destination - * connection ID which client generated randomly. It is used to - * derive initial packet protection keys. + * `ngtcp2_conn_install_initial_key`. |dcid| is the Destination + * Connection ID in Initial packet received from client. It is used + * to derive initial packet protection keys. * * The callback function must return 0 if it succeeds. If an error * occurs, return :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the @@ -2529,45 +2400,42 @@ typedef int (*ngtcp2_recv_client_initial)(ngtcp2_conn *conn, /** * @enum * - * :type:`ngtcp2_crypto_level` is encryption level. + * :type:`ngtcp2_encryption_level` is QUIC encryption level. */ -typedef enum ngtcp2_crypto_level { +typedef enum ngtcp2_encryption_level { /** - * :enum:`NGTCP2_CRYPTO_LEVEL_INITIAL` is Initial Keys encryption + * :enum:`NGTCP2_ENCRYPTION_LEVEL_INITIAL` is Initial encryption * level. */ - NGTCP2_CRYPTO_LEVEL_INITIAL, + NGTCP2_ENCRYPTION_LEVEL_INITIAL, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_HANDSHAKE` is Handshake Keys - * encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE` is Handshake encryption + * level. */ - NGTCP2_CRYPTO_LEVEL_HANDSHAKE, + NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_APPLICATION` is Application Data - * (1-RTT) Keys encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_1RTT` is 1-RTT encryption level. */ - NGTCP2_CRYPTO_LEVEL_APPLICATION, + NGTCP2_ENCRYPTION_LEVEL_1RTT, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_EARLY` is Early Data (0-RTT) Keys - * encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_0RTT` is 0-RTT encryption level. */ - NGTCP2_CRYPTO_LEVEL_EARLY -} ngtcp2_crypto_level; + NGTCP2_ENCRYPTION_LEVEL_0RTT +} ngtcp2_encryption_level; /** * @functypedef * * :type`ngtcp2_recv_crypto_data` is invoked when crypto data is - * received. The received data is pointed to by |data|, and its - * length is |datalen|. The |offset| specifies the offset where - * |data| is positioned. |user_data| is the arbitrary pointer passed - * to `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. The - * ngtcp2 library ensures that the crypto data is passed to the - * application in the increasing order of |offset|. |datalen| is - * always strictly greater than 0. |crypto_level| indicates the - * encryption level where this data is received. Crypto data can - * never be received in - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`. + * received. The received data is pointed by |data|, and its length + * is |datalen|. The |offset| specifies the offset where |data| is + * positioned. |user_data| is the arbitrary pointer passed to + * `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. The ngtcp2 + * library ensures that the crypto data is passed to the application + * in the increasing order of |offset|. |datalen| is always strictly + * greater than 0. |encryption_level| indicates the encryption level + * where this data is received. Crypto data can never be received in + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`. * * The application should provide the given data to TLS stack. * @@ -2591,7 +2459,7 @@ typedef enum ngtcp2_crypto_level { * return immediately. */ typedef int (*ngtcp2_recv_crypto_data)(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data); @@ -2645,9 +2513,9 @@ typedef int (*ngtcp2_recv_version_negotiation)(ngtcp2_conn *conn, * This callback is client use only. * * Application must regenerate packet protection key, IV, and header - * protection key for Initial packets using the destination connection - * ID obtained by :member:`hd->scid ` and install - * them by calling `ngtcp2_conn_install_initial_key()`. + * protection key for Initial packets using the Destination Connection + * ID obtained by :member:`hd->scid `, and install + * them by calling `ngtcp2_conn_install_initial_key`. * * 0-RTT data accepted by the ngtcp2 library will be automatically * retransmitted as 0-RTT data by the library. @@ -2666,12 +2534,12 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * application to encrypt packet payload. The packet payload to * encrypt is passed as |plaintext| of length |plaintextlen|. The * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context - * object which is initialized with encryption key. The nonce is - * passed as |nonce| of length |noncelen|. The Additional + * object which is initialized with the specific encryption key. The + * nonce is passed as |nonce| of length |noncelen|. The Additional * Authenticated Data is passed as |aad| of length |aadlen|. * * The implementation of this callback must encrypt |plaintext| using - * the negotiated cipher suite and write the ciphertext into the + * the negotiated cipher suite, and write the ciphertext into the * buffer pointed by |dest|. |dest| has enough capacity to store the * ciphertext and any additional AEAD tag data. * @@ -2694,12 +2562,12 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * application to decrypt packet payload. The packet payload to * decrypt is passed as |ciphertext| of length |ciphertextlen|. The * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context - * object which is initialized with decryption key. The nonce is - * passed as |nonce| of length |noncelen|. The Additional + * object which is initialized with the specific decryption key. The + * nonce is passed as |nonce| of length |noncelen|. The Additional * Authenticated Data is passed as |aad| of length |aadlen|. * * The implementation of this callback must decrypt |ciphertext| using - * the negotiated cipher suite and write the ciphertext into the + * the negotiated cipher suite, and write the ciphertext into the * buffer pointed by |dest|. |dest| has enough capacity to store the * cleartext. * @@ -2722,12 +2590,12 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * :type:`ngtcp2_hp_mask` is invoked when the ngtcp2 library asks the * application to produce a mask to encrypt or decrypt packet header. * The encryption cipher is |hp|. |hp_ctx| is the cipher context - * object which is initialized with header protection key. The sample - * is passed as |sample| which is :macro:`NGTCP2_HP_SAMPLELEN` bytes - * long. + * object which is initialized with the specific header protection + * key. The sample is passed as |sample| which is + * :macro:`NGTCP2_HP_SAMPLELEN` bytes long. * * The implementation of this callback must produce a mask using the - * header protection cipher suite specified by QUIC specification and + * header protection cipher suite specified by QUIC specification, and * write the result into the buffer pointed by |dest|. The length of * the mask must be at least :macro:`NGTCP2_HP_MASKLEN`. The library * only uses the first :macro:`NGTCP2_HP_MASKLEN` bytes of the @@ -2746,7 +2614,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @macrosection * - * Stream data flags + * STREAM frame data flags */ /** @@ -2767,11 +2635,11 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @macro * - * :macro:`NGTCP2_STREAM_DATA_FLAG_EARLY` indicates that this chunk of - * data contains data received in 0RTT packet and the handshake has + * :macro:`NGTCP2_STREAM_DATA_FLAG_0RTT` indicates that this chunk of + * data contains data received in 0-RTT packet, and the handshake has * not completed yet, which means that the data might be replayed. */ -#define NGTCP2_STREAM_DATA_FLAG_EARLY 0x02u +#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02u /** * @functypedef @@ -2787,9 +2655,9 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * overlap. The data is passed as |data| of length |datalen|. * |datalen| may be 0 if and only if |fin| is nonzero. * - * If :macro:`NGTCP2_STREAM_DATA_FLAG_EARLY` is set in |flags|, it - * indicates that a part of or whole data was received in 0RTT packet - * and a handshake has not completed yet. + * If :macro:`NGTCP2_STREAM_DATA_FLAG_0RTT` is set in |flags|, it + * indicates that a part of or whole data was received in 0-RTT + * packet, and a handshake has not completed yet. * * The callback function must return 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library return @@ -2804,9 +2672,9 @@ typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, uint32_t flags, * @functypedef * * :type:`ngtcp2_stream_open` is a callback function which is called - * when remote stream is opened by peer. This function is not called - * if stream is opened by implicitly (we might reconsider this - * behaviour). + * when remote stream is opened by a remote endpoint. This function + * is not called if stream is opened by implicitly (we might + * reconsider this behaviour later). * * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library @@ -2883,16 +2751,19 @@ typedef int (*ngtcp2_stream_reset)(ngtcp2_conn *conn, int64_t stream_id, * @functypedef * * :type:`ngtcp2_acked_stream_data_offset` is a callback function - * which is called when stream data is acked, and application can free - * the data. The acked range of data is [offset, offset + datalen). - * For a given stream_id, this callback is called sequentially in - * increasing order of |offset| without any overlap. |datalen| is - * normally strictly greater than 0. One exception is that when a - * packet which includes STREAM frame which has fin flag set, and 0 - * length data, this callback is invoked with 0 passed as |datalen|. - * - * If a stream is closed prematurely and stream data is still + * which is called when stream data in range [|offset|, |offset| + + * |datalen|) is acknowledged, and application can free the portion of + * data. For a given |stream_id|, this callback is called + * sequentially in increasing order of |offset| without any overlap. + * |datalen| is normally strictly greater than 0. One exception is + * that when a STREAM frame has fin flag set and 0 length data, this + * callback is invoked with |datalen| == 0. + * + * If a stream is closed prematurely, and stream data is still * in-flight, this callback function is not called for those data. + * After :member:`ngtcp2_callbacks.stream_close` is called for a + * particular stream, |conn| does not touch data for the closed stream + * again, and application can free all unacknowledged stream data. * * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library @@ -2938,7 +2809,7 @@ typedef int (*ngtcp2_extend_max_streams)(ngtcp2_conn *conn, * :type:`ngtcp2_extend_max_stream_data` is a callback function which * is invoked when max stream data is extended. |stream_id| * identifies the stream. |max_data| is a cumulative number of bytes - * the endpoint can send on this stream. + * an endpoint can send on this stream. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -2952,10 +2823,10 @@ typedef int (*ngtcp2_extend_max_stream_data)(ngtcp2_conn *conn, /** * @functypedef * - * :type:`ngtcp2_rand` is a callback function to get randomized byte - * string from application. Application must fill random |destlen| - * bytes to the buffer pointed by |dest|. The generated bytes are - * used only in non-cryptographic context. + * :type:`ngtcp2_rand` is a callback function to get random data of + * length |destlen|. Application must fill random |destlen| bytes to + * the buffer pointed by |dest|. The generated data is used only in + * non-cryptographic context. */ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx); @@ -2965,11 +2836,11 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, * * :type:`ngtcp2_get_new_connection_id` is a callback function to ask * an application for new connection ID. Application must generate - * new unused connection ID with the exact |cidlen| bytes and store it - * in |cid|. It also has to generate stateless reset token into - * |token|. The length of stateless reset token is + * new unused connection ID with the exact |cidlen| bytes, and store + * it in |cid|. It also has to generate a stateless reset token, and + * store it in |token|. The length of stateless reset token is * :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` and it is guaranteed that - * the buffer pointed by |cid| has the sufficient space to store the + * the buffer pointed by |token| has the sufficient space to store the * token. * * The callback function must return 0 if it succeeds. Returning @@ -2985,7 +2856,9 @@ typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid, * * :type:`ngtcp2_remove_connection_id` is a callback function which * notifies the application that connection ID |cid| is no longer used - * by remote endpoint. + * by a remote endpoint. This Connection ID was previously offered by + * a local endpoint, and a remote endpoint could use it as Destination + * Connection ID when sending QUIC packet. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3005,15 +2878,15 @@ typedef int (*ngtcp2_remove_connection_id)(ngtcp2_conn *conn, * |current_tx_secret| of length |secretlen|. They are decryption and * encryption secrets respectively. * - * The application has to generate new secrets and keys for both - * encryption and decryption, and write decryption secret and IV to - * the buffer pointed by |rx_secret| and |rx_iv| respectively. It - * also has to create new AEAD cipher context object with new - * decryption key and initialize |rx_aead_ctx| with it. Similarly, - * write encryption secret and IV to the buffer pointed by |tx_secret| - * and |tx_iv|. Create new AEAD cipher context object with new - * encryption key and initialize |tx_aead_ctx| with it. All given - * buffers have the enough capacity to store secret, key and IV. + * The application must generate new secrets and keys for both + * encryption and decryption. It must write decryption secret and IV + * to the buffer pointed by |rx_secret| and |rx_iv| respectively. It + * also must create new AEAD cipher context object with new decryption + * key and initialize |rx_aead_ctx| with it. Similarly, write + * encryption secret and IV to the buffer pointed by |tx_secret| and + * |tx_iv|. Create new AEAD cipher context object with new encryption + * key and initialize |tx_aead_ctx| with it. All given buffers have + * the enough capacity to store secret, key and IV. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3048,14 +2921,25 @@ typedef int (*ngtcp2_update_key)( */ #define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01u +/** + * @macro + * + * :macro:`NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN` indicates that + * server should send NEW_TOKEN frame for the new remote address. + * This flag is only set for server. + */ +#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u + /** * @functypedef * * :type:`ngtcp2_path_validation` is a callback function which tells - * the application the outcome of path validation. |flags| is zero or + * an application the outcome of path validation. |flags| is zero or * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_* * `. |path| is the path that was - * validated. If |res| is + * validated. |old_path| is the path that is previously used before a + * local endpoint has migrated to |path| if |old_path| is not NULL. + * If |res| is * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_SUCCESS`, * the path validation succeeded. If |res| is * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_FAILURE`, @@ -3067,6 +2951,7 @@ typedef int (*ngtcp2_update_key)( */ typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path, + const ngtcp2_path *old_path, ngtcp2_path_validation_result res, void *user_data); @@ -3087,10 +2972,10 @@ typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags, * from `ngtcp2_conn_get_path()`. Both :member:`dest->local.addr * ` and :member:`dest->remote.addr * ` point to buffers which are at least - * ``sizeof(struct sockaddr_storage)`` bytes long, respectively. If + * sizeof(:type:`ngtcp2_sockaddr_union`) bytes long, respectively. If * an application denies the preferred addresses, just leave |dest| * unmodified (or set :member:`dest->remote.addrlen - * ` to 0) and return 0. + * ` to 0), and return 0. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3110,12 +2995,12 @@ typedef int (*ngtcp2_select_preferred_addr)(ngtcp2_conn *conn, typedef enum ngtcp2_connection_id_status_type { /** * :enum:`NGTCP2_CONNECTION_ID_STATUS_TYPE_ACTIVATE` indicates that - * a local endpoint starts using new destination Connection ID. + * a local endpoint starts using new Destination Connection ID. */ NGTCP2_CONNECTION_ID_STATUS_TYPE_ACTIVATE, /** * :enum:`NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE` indicates - * that a local endpoint stops using a given destination Connection + * that a local endpoint stops using a given Destination Connection * ID. */ NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE @@ -3125,9 +3010,9 @@ typedef enum ngtcp2_connection_id_status_type { * @functypedef * * :type:`ngtcp2_connection_id_status` is a callback function which is - * called when the status of Connection ID changes. + * called when the status of Destination Connection ID changes. * - * |token| is the associated stateless reset token and it is ``NULL`` + * |token| is the associated stateless reset token, and it is ``NULL`` * if no token is present. * * |type| is the one of the value defined in @@ -3138,25 +3023,25 @@ typedef enum ngtcp2_connection_id_status_type { * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_connection_id_status)(ngtcp2_conn *conn, int type, - uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token, - void *user_data); +typedef int (*ngtcp2_connection_id_status)( + ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, + const ngtcp2_cid *cid, const uint8_t *token, void *user_data); /** * @functypedef * * :type:`ngtcp2_recv_new_token` is a callback function which is - * called when new token is received from server. + * called when new token is received from server. This callback is + * client use only. * - * |token| is the received token. + * |token| is the received token of length |tokenlen| bytes long. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const ngtcp2_vec *token, - void *user_data); +typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const uint8_t *token, + size_t tokenlen, void *user_data); /** * @functypedef @@ -3184,7 +3069,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( /** * @macrosection * - * Datagram flags + * DATAGRAM frame flags */ /** @@ -3197,11 +3082,11 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( /** * @macro * - * :macro:`NGTCP2_DATAGRAM_FLAG_EARLY` indicates that DATAGRAM frame - * is received in 0RTT packet and the handshake has not completed yet, + * :macro:`NGTCP2_DATAGRAM_FLAG_0RTT` indicates that DATAGRAM frame is + * received in 0-RTT packet, and the handshake has not completed yet, * which means that the data might be replayed. */ -#define NGTCP2_DATAGRAM_FLAG_EARLY 0x01u +#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01u /** * @functypedef @@ -3210,8 +3095,8 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( * received. |flags| is bitwise-OR of zero or more of * :macro:`NGTCP2_DATAGRAM_FLAG_* `. * - * If :macro:`NGTCP2_DATAGRAM_FLAG_EARLY` is set in |flags|, it - * indicates that DATAGRAM frame was received in 0RTT packet and a + * If :macro:`NGTCP2_DATAGRAM_FLAG_0RTT` is set in |flags|, it + * indicates that DATAGRAM frame was received in 0-RTT packet, and a * handshake has not completed yet. * * The callback function must return 0 if it succeeds, or @@ -3257,8 +3142,8 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, * * :type:`ngtcp2_get_path_challenge_data` is a callback function to * ask an application for new data that is sent in PATH_CHALLENGE - * frame. Application must generate new unpredictable exactly - * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data and + * frame. Application must generate new unpredictable, exactly + * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data, and * store them into the buffer pointed by |data|. * * The callback function must return 0 if it succeeds. Returning @@ -3296,8 +3181,9 @@ typedef int (*ngtcp2_stream_stop_sending)(ngtcp2_conn *conn, int64_t stream_id, * server, it is called once when the version is negotiated. * * The implementation of this callback must install new Initial keys - * for |version|. Use `ngtcp2_conn_install_vneg_initial_key` to - * install keys. + * for |version| and Destination Connection ID |client_dcid| from + * client. Use `ngtcp2_conn_install_vneg_initial_key` to install + * keys. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3317,11 +3203,25 @@ typedef int (*ngtcp2_version_negotiation)(ngtcp2_conn *conn, uint32_t version, * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_crypto_level level, +typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_encryption_level level, void *user_data); -#define NGTCP2_CALLBACKS_VERSION_V1 1 -#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_VERSION_V1 +/** + * @functypedef + * + * :type:`ngtcp2_tls_early_data_rejected` is invoked when early data + * was rejected by server during TLS handshake, or client decided not + * to attempt early data. + * + * The callback function must return 0 if it succeeds. Returning + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return + * immediately. + */ +typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn, + void *user_data); + +#define NGTCP2_CALLBACKS_V1 1 +#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1 /** * @struct @@ -3338,8 +3238,9 @@ typedef struct ngtcp2_callbacks { ngtcp2_client_initial client_initial; /** * :member:`recv_client_initial` is a callback function which is - * invoked when a server receives the first packet from client. - * This callback function must be specified for a server application. + * invoked when a server receives the first Initial packet from + * client. This callback function must be specified for a server + * application. */ ngtcp2_recv_client_initial recv_client_initial; /** @@ -3373,23 +3274,23 @@ typedef struct ngtcp2_callbacks { ngtcp2_decrypt decrypt; /** * :member:`hp_mask` is a callback function which is invoked to get - * a mask to encrypt or decrypt packet header. This callback + * a mask to encrypt or decrypt QUIC packet header. This callback * function must be specified. */ ngtcp2_hp_mask hp_mask; /** * :member:`recv_stream_data` is a callback function which is - * invoked when STREAM data, which includes application data, is + * invoked when stream data, which includes application data, is * received. This callback function is optional. */ ngtcp2_recv_stream_data recv_stream_data; /** * :member:`acked_stream_data_offset` is a callback function which - * is invoked when STREAM data, which includes application data, is + * is invoked when stream data, which includes application data, is * acknowledged by a remote endpoint. It tells an application the - * largest offset of acknowledged STREAM data without a gap so that - * application can free memory for the data. This callback function - * is optional. + * largest offset of acknowledged stream data without a gap so that + * application can free memory for the data up to that offset. This + * callback function is optional. */ ngtcp2_acked_stream_data_offset acked_stream_data_offset; /** @@ -3431,8 +3332,8 @@ typedef struct ngtcp2_callbacks { ngtcp2_extend_max_streams extend_max_local_streams_uni; /** * :member:`rand` is a callback function which is invoked when the - * library needs sequence of random data. This callback function - * must be specified. + * library needs random data. This callback function must be + * specified. */ ngtcp2_rand rand; /** @@ -3450,7 +3351,7 @@ typedef struct ngtcp2_callbacks { /** * :member:`update_key` is a callback function which is invoked when * the library tells an application that it must update keying - * materials and install new keys. This callback function must be + * materials, and install new keys. This callback function must be * specified. */ ngtcp2_update_key update_key; @@ -3463,8 +3364,8 @@ typedef struct ngtcp2_callbacks { /** * :member:`select_preferred_addr` is a callback function which is * invoked when the library asks a client to select preferred - * address presented by a server. This callback function is - * optional. + * address presented by a server. If not set, client ignores + * preferred addresses. This callback function is optional. */ ngtcp2_select_preferred_addr select_preferred_addr; /** @@ -3489,24 +3390,24 @@ typedef struct ngtcp2_callbacks { ngtcp2_extend_max_streams extend_max_remote_streams_uni; /** * :member:`extend_max_stream_data` is callback function which is - * invoked when the maximum offset of STREAM data that a local + * invoked when the maximum offset of stream data that a local * endpoint can send is increased. This callback function is * optional. */ ngtcp2_extend_max_stream_data extend_max_stream_data; /** * :member:`dcid_status` is a callback function which is invoked - * when the new destination Connection ID is activated or the - * activated destination Connection ID is now deactivated. This + * when the new Destination Connection ID is activated, or the + * activated Destination Connection ID is now deactivated. This * callback function is optional. */ ngtcp2_connection_id_status dcid_status; /** * :member:`handshake_confirmed` is a callback function which is * invoked when both endpoints agree that handshake has finished. - * This field is ignored by server because handshake_completed - * indicates the handshake confirmation for server. This callback - * function is optional. + * This field is ignored by server because + * :member:`handshake_completed` also indicates the handshake + * confirmation for server. This callback function is optional. */ ngtcp2_handshake_confirmed handshake_confirmed; /** @@ -3535,20 +3436,20 @@ typedef struct ngtcp2_callbacks { ngtcp2_recv_datagram recv_datagram; /** * :member:`ack_datagram` is a callback function which is invoked - * when a packet containing DATAGRAM frame is acknowledged. This - * callback function is optional. + * when a QUIC packet containing DATAGRAM frame is acknowledged by a + * remote endpoint. This callback function is optional. */ ngtcp2_ack_datagram ack_datagram; /** * :member:`lost_datagram` is a callback function which is invoked - * when a packet containing DATAGRAM frame is declared lost. This - * callback function is optional. + * when a QUIC packet containing DATAGRAM frame is declared lost. + * This callback function is optional. */ ngtcp2_lost_datagram lost_datagram; /** * :member:`get_path_challenge_data` is a callback function which is - * invoked when the library needs new PATH_CHALLENGE data. This - * callback must be specified. + * invoked when the library needs new data sent along with + * PATH_CHALLENGE frame. This callback must be specified. */ ngtcp2_get_path_challenge_data get_path_challenge_data; /** @@ -3568,16 +3469,23 @@ typedef struct ngtcp2_callbacks { * :member:`recv_rx_key` is a callback function which is invoked * when a new key for decrypting packets is installed during QUIC * cryptographic handshake. It is not called for - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_INITIAL`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_INITIAL`. */ ngtcp2_recv_key recv_rx_key; /** * :member:`recv_tx_key` is a callback function which is invoked * when a new key for encrypting packets is installed during QUIC * cryptographic handshake. It is not called for - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_INITIAL`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_INITIAL`. */ ngtcp2_recv_key recv_tx_key; + /** + * :member:`tls_early_data_rejected` is a callback function which is + * invoked when server rejected early data during TLS handshake, or + * client decided not to attempt early data. This callback function + * is only used by client. + */ + ngtcp2_tls_early_data_rejected tls_early_data_rejected; } ngtcp2_callbacks; /** @@ -3591,7 +3499,7 @@ typedef struct ngtcp2_callbacks { * * The primary use case of this function is for server to send * CONNECTION_CLOSE frame in Initial packet to close connection - * without committing the state when validating Retry token fails. + * without committing any state when validating Retry token fails. * * This function returns the number of bytes written if it succeeds, * or one of the following negative error codes: @@ -3613,11 +3521,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( * @function * * `ngtcp2_pkt_write_retry` writes Retry packet in the buffer pointed - * by |dest| whose length is |destlen|. |dcid| is the destination - * connection ID which appeared in a packet as a source connection ID - * sent by client. |scid| is a server chosen source connection ID. - * |odcid| specifies Original Destination Connection ID which appeared - * in a packet as a destination connection ID sent by client. |token| + * by |dest| whose length is |destlen|. |dcid| is the Connection ID + * which appeared in a packet as a Source Connection ID sent by + * client. |scid| is a server chosen Source Connection ID. |odcid| + * specifies Original Destination Connection ID which appeared in a + * packet as a Destination Connection ID sent by client. |token| * specifies Retry Token, and |tokenlen| specifies its length. |aead| * must be AEAD_AES_128_GCM. |aead_ctx| must be initialized with * :macro:`NGTCP2_RETRY_KEY` as an encryption key. @@ -3644,17 +3552,14 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry( * * `ngtcp2_accept` is used by server implementation, and decides * whether packet |pkt| of length |pktlen| from client is acceptable - * for the very initial packet to a connection. + * for the very first packet to a connection. * - * If |dest| is not ``NULL`` and the function returns 0, or - * :macro:`NGTCP2_ERR_RETRY`, the decoded packet header is stored to - * the object pointed by |dest|. + * If |dest| is not ``NULL`` and the function returns 0, the decoded + * packet header is stored in the object pointed by |dest|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_RETRY` - * Retry packet should be sent. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` * The packet is not acceptable for the very first packet to a new * connection; or the function failed to parse the packet header. @@ -3666,17 +3571,21 @@ NGTCP2_EXTERN int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, * @function * * `ngtcp2_conn_client_new` creates new :type:`ngtcp2_conn`, and - * initializes it as client. |dcid| is randomized destination - * connection ID. |scid| is source connection ID. - * |client_chosen_version| is a QUIC version that a client chooses. - * |path| is the network path where this QUIC connection is being - * established and must not be ``NULL``. |callbacks|, |settings|, and - * |params| must not be ``NULL``, and the function make a copy of each - * of them. |params| is local QUIC transport parameters and sent to a - * remote endpoint during handshake. |user_data| is the arbitrary - * pointer which is passed to the user-defined callback functions. If - * |mem| is ``NULL``, the memory allocator returned by - * `ngtcp2_mem_default()` is used. + * initializes it as client. On success, it stores the pointer to the + * newly allocated object in |*pconn|. |dcid| is a randomized + * Destination Connection ID which must be longer than or equal to + * :macro:`NGTCP2_MIN_INITIAL_DCIDLEN`. |scid| is a Source Connection + * ID chosen by client. |client_chosen_version| is a QUIC version + * that a client chooses. |path| is the network path where this QUIC + * connection is being established, and must not be ``NULL``. + * |callbacks|, |settings|, and |params| must not be ``NULL``, and the + * function makes a copy of each of them. |params| is a local QUIC + * transport parameters, and sent to a remote endpoint during + * handshake. |user_data| is the arbitrary pointer which is passed to + * the user-defined callback functions. If |mem| is ``NULL``, the + * memory allocator returned by `ngtcp2_mem_default()` is used. + * + * Call `ngtcp2_conn_del` to free memory allocated for |*pconn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3696,16 +3605,22 @@ NGTCP2_EXTERN int ngtcp2_conn_client_new_versioned( * @function * * `ngtcp2_conn_server_new` creates new :type:`ngtcp2_conn`, and - * initializes it as server. |dcid| is a destination connection ID. - * |scid| is a source connection ID. |path| is the network path where - * this QUIC connection is being established and must not be ``NULL``. - * |client_chosen_version| is a QUIC version that a client chooses. - * |callbacks|, |settings|, and |params| must not be ``NULL``, and the - * function make a copy of each of them. |params| is local QUIC - * transport parameters and sent to a remote endpoint during - * handshake. |user_data| is the arbitrary pointer which is passed to - * the user-defined callback functions. If |mem| is ``NULL``, the - * memory allocator returned by `ngtcp2_mem_default()` is used. + * initializes it as server. On success, it stores the pointer to the + * newly allocated object in |*pconn|. |dcid| is a Destination + * Connection ID, and is usually the Connection ID that appears in + * client Initial packet as Source Connection ID. |scid| is a Source + * Connection ID chosen by server. |path| is the network path where + * this QUIC connection is being established, and must not be + * ``NULL``. |client_chosen_version| is a QUIC version that a client + * chooses. |callbacks|, |settings|, and |params| must not be + * ``NULL``, and the function makes a copy of each of them. |params| + * is a local QUIC transport parameters, and sent to a remote endpoint + * during handshake. |user_data| is the arbitrary pointer which is + * passed to the user-defined callback functions. If |mem| is + * ``NULL``, the memory allocator returned by `ngtcp2_mem_default()` + * is used. + * + * Call `ngtcp2_conn_del` to free memory allocated for |*pconn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3741,19 +3656,31 @@ NGTCP2_EXTERN void ngtcp2_conn_del(ngtcp2_conn *conn); * This function must not be called from inside the callback * functions. * - * This function returns 0 if it succeeds, or negative error codes. - * If :macro:`NGTCP2_ERR_RETRY` is returned, application must be a - * server and it must perform address validation by sending Retry - * packet and discard the connection state. If - * :macro:`NGTCP2_ERR_DROP_CONN` is returned, server application must - * drop the connection silently (without sending any CONNECTION_CLOSE - * frame) and discard connection state. If - * :macro:`NGTCP2_ERR_DRAINING` is returned, a connection has entered - * the draining state, and no further packet transmission is allowed. - * If :macro:`NGTCP2_ERR_CRYPTO` is returned, the error happened in - * TLS stack and `ngtcp2_conn_get_tls_alert` returns TLS alert if set. - * - * If any other negative errors are returned, call + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_RETRY` + * Server must perform address validation by sending Retry packet + * (see `ngtcp2_crypto_write_retry` and `ngtcp2_pkt_write_retry`), + * and discard the connection state. Client application does not + * get this error code. + * :macro:`NGTCP2_ERR_DROP_CONN` + * Server application must drop the connection silently (without + * sending any CONNECTION_CLOSE frame), and discard connection + * state. Client application does not get this error code. + * :macro:`NGTCP2_ERR_DRAINING` + * A connection has entered the draining state, and no further + * packet transmission is allowed. + * :macro:`NGTCP2_ERR_CLOSING` + * A connection has entered the closing state, and no further + * packet transmission is allowed. Calling + * `ngtcp2_conn_write_connection_close` makes a connection enter + * this state. + * :macro:`NGTCP2_ERR_CRYPTO` + * An error happened in TLS stack. `ngtcp2_conn_get_tls_alert` + * returns TLS alert if set. + * + * If any other negative error is returned, call * `ngtcp2_conn_write_connection_close` to get terminal packet, and * sending it makes QUIC connection enter the closing state. */ @@ -3767,8 +3694,8 @@ ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, * @function * * `ngtcp2_conn_write_pkt` is equivalent to calling - * `ngtcp2_conn_writev_stream` with -1 as stream_id, no stream data, and - * :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` as flags. + * `ngtcp2_conn_writev_stream` with -1 as |stream_id|, no stream data, + * and :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` as flags. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -3777,18 +3704,18 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( /** * @function * - * `ngtcp2_conn_handshake_completed` tells |conn| that the TLS stack - * declares TLS handshake completion. This does not mean QUIC + * `ngtcp2_conn_tls_handshake_completed` tells |conn| that the TLS + * stack declares TLS handshake completion. This does not mean QUIC * handshake has completed. The library needs extra conditions to be * met. */ -NGTCP2_EXTERN void ngtcp2_conn_handshake_completed(ngtcp2_conn *conn); +NGTCP2_EXTERN void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_handshake_completed` returns nonzero if QUIC handshake - * has completed. + * `ngtcp2_conn_get_handshake_completed` returns nonzero if QUIC + * handshake has completed. */ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); @@ -3797,11 +3724,11 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * * `ngtcp2_conn_install_initial_key` installs packet protection keying * materials for Initial packets. |rx_aead_ctx| is AEAD cipher - * context object and must be initialized with a decryption key. + * context object, and must be initialized with a decryption key. * |rx_iv| is IV of length |rx_ivlen| for decryption. |rx_hp_ctx| is * a packet header protection cipher context object for decryption. * Similarly, |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for - * encrypting outgoing packets and are the same length with the + * encrypting outgoing packets, and are the same length with the * decryption counterpart . If they have already been set, they are * overwritten. * @@ -3810,14 +3737,16 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|, * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. - * - * After receiving Retry packet, the DCID most likely changes. In - * that case, client application must generate these keying materials - * again based on new DCID and install them again. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. + * + * After receiving Retry packet, a Destination Connection ID that + * client sends in Initial packet most likely changes. In that case, + * client application must generate these keying materials again based + * on new Destination Connection ID, and install them again with this + * function. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3837,11 +3766,11 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( * `ngtcp2_conn_install_vneg_initial_key` installs packet protection * keying materials for Initial packets on compatible version * negotiation for |version|. |rx_aead_ctx| is AEAD cipher context - * object and must be initialized with a decryption key. |rx_iv| is + * object, and must be initialized with a decryption key. |rx_iv| is * IV of length |rx_ivlen| for decryption. |rx_hp_ctx| is a packet * header protection cipher context object for decryption. Similarly, * |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for encrypting outgoing - * packets and are the same length with the decryption counterpart . + * packets, and are the same length with the decryption counterpart. * If they have already been set, they are overwritten. * * |ivlen| must be the minimum length of AEAD nonce, or 8 bytes if @@ -3849,10 +3778,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( * * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|, * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3880,10 +3809,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_vneg_initial_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx|, - * and |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * and |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` + * and :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be + * called to delete these objects when they are no longer used. If + * this function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3908,10 +3837,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_handshake_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3926,19 +3855,19 @@ NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key( /** * @function * - * `ngtcp2_conn_install_early_key` installs packet protection AEAD + * `ngtcp2_conn_install_0rtt_key` installs packet protection AEAD * cipher context object |aead_ctx|, IV |iv| of length |ivlen|, and * packet header protection cipher context object |hp_ctx| to encrypt - * (for client) or decrypt (for server) 0RTT packets. + * (for client) or decrypt (for server) 0-RTT packets. * * |ivlen| must be the minimum length of AEAD nonce, or 8 bytes if * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3946,7 +3875,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key( * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_conn_install_early_key( +NGTCP2_EXTERN int ngtcp2_conn_install_0rtt_key( ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx); @@ -3954,7 +3883,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key( * @function * * `ngtcp2_conn_install_rx_key` installs packet protection keying - * materials for decrypting Short header packets. |secret| of length + * materials for decrypting 1-RTT packets. |secret| of length * |secretlen| is the decryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with a decryption key. @@ -3965,10 +3894,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3985,7 +3914,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( * @function * * `ngtcp2_conn_install_tx_key` installs packet protection keying - * materials for encrypting Short header packets. |secret| of length + * materials for encrypting 1-RTT packets. |secret| of length * |secretlen| is the encryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with an encryption key. @@ -3996,10 +3925,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4035,10 +3964,12 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, * is defined as NGTCP2_ERR_* macro, such as * :macro:`NGTCP2_ERR_DECRYPT`). In general, error code should be * propagated via return value, but sometimes ngtcp2 API is called - * inside callback function of TLS stack and it does not allow to + * inside callback function of TLS stack, and it does not allow to * return ngtcp2 error code directly. In this case, implementation * can set the error code (e.g., * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM`) using this function. + * + * See also `ngtcp2_conn_get_tls_error`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr); @@ -4055,7 +3986,9 @@ NGTCP2_EXTERN int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_set_tls_alert` sets a TLS alert |alert| generated by a - * local endpoint to |conn|. + * TLS stack of a local endpoint to |conn|. + * + * See also `ngtcp2_conn_get_tls_alert`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_alert(ngtcp2_conn *conn, uint8_t alert); @@ -4073,8 +4006,10 @@ NGTCP2_EXTERN uint8_t ngtcp2_conn_get_tls_alert(ngtcp2_conn *conn); * * `ngtcp2_conn_set_keep_alive_timeout` sets keep-alive timeout. If * nonzero value is given, after a connection is idle at least in a - * given amount of time, a keep-alive packet is sent. If 0 is set, - * keep-alive functionality is disabled and this is the default. + * given amount of time, a keep-alive packet is sent. If UINT64_MAX + * is set, keep-alive functionality is disabled, and this is the + * default. Specifying 0 in |timeout| is reserved for a future + * extension, and for now it is treated as if UINT64_MAX is given. */ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, ngtcp2_duration timeout); @@ -4082,18 +4017,19 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_expiry` returns the next expiry time. + * `ngtcp2_conn_get_expiry` returns the next expiry time. It returns + * ``UINT64_MAX`` if there is no next expiry. * - * Call `ngtcp2_conn_handle_expiry()` and `ngtcp2_conn_write_pkt` (or - * `ngtcp2_conn_writev_stream`) if expiry time is passed. + * Call `ngtcp2_conn_handle_expiry` and then + * `ngtcp2_conn_writev_stream` (or `ngtcp2_conn_writev_datagram`) when + * the expiry time has passed. */ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_handle_expiry` handles expired timer. It does nothing - * if timer is not expired. + * `ngtcp2_conn_handle_expiry` handles expired timer. */ NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -4108,9 +4044,9 @@ NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_decode_remote_transport_params` decodes QUIC transport - * parameters from the buffer pointed by |data| of length |datalen|, - * and sets the result to |conn|. + * `ngtcp2_conn_decode_and_set_remote_transport_params` decodes QUIC + * transport parameters from the buffer pointed by |data| of length + * |datalen|, and sets the result to |conn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4126,9 +4062,8 @@ NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn); * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` * User callback failed */ -NGTCP2_EXTERN int -ngtcp2_conn_decode_remote_transport_params(ngtcp2_conn *conn, - const uint8_t *data, size_t datalen); +NGTCP2_EXTERN int ngtcp2_conn_decode_and_set_remote_transport_params( + ngtcp2_conn *conn, const uint8_t *data, size_t datalen); /** * @function @@ -4143,36 +4078,77 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_early_remote_transport_params` sets |params| as - * transport parameters previously received from a server. The - * parameters are used to send early data. QUIC requires that client - * application should remember transport parameters along with a - * session ticket. - * - * At least following fields should be set: - * - * - initial_max_stream_id_bidi - * - initial_max_stream_id_uni - * - initial_max_stream_data_bidi_local - * - initial_max_stream_data_bidi_remote - * - initial_max_stream_data_uni - * - initial_max_data - * - active_connection_id_limit - * - max_datagram_frame_size (if DATAGRAM extension was negotiated) - * - * The following fields are ignored: - * - * - ack_delay_exponent - * - max_ack_delay - * - initial_scid - * - original_dcid - * - preferred_address and preferred_address_present - * - retry_scid and retry_scid_present - * - stateless_reset_token and stateless_reset_token_present - */ -NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params_versioned( - ngtcp2_conn *conn, int transport_params_version, - const ngtcp2_transport_params *params); + * `ngtcp2_conn_encode_0rtt_transport_params` encodes the QUIC + * transport parameters that are used for 0-RTT data in the buffer + * pointed by |dest| of length |destlen|. It includes at least the + * following fields: + * + * - :member:`ngtcp2_transport_params.initial_max_streams_bidi` + * - :member:`ngtcp2_transport_params.initial_max_streams_uni` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_local` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_remote` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_uni` + * - :member:`ngtcp2_transport_params.initial_max_data` + * - :member:`ngtcp2_transport_params.active_connection_id_limit` + * - :member:`ngtcp2_transport_params.max_datagram_frame_size` + * + * If |conn| is initialized as server, the following additional fields + * are also included: + * + * - :member:`ngtcp2_transport_params.max_idle_timeout` + * - :member:`ngtcp2_transport_params.max_udp_payload_size` + * - :member:`ngtcp2_transport_params.disable_active_migration` + * + * If |conn| is initialized as client, these parameters are + * synthesized from the remote transport parameters received from + * server. Otherwise, it is the local transport parameters that are + * set by the local endpoint. + * + * This function returns the number of bytes written, or one of the + * following negative error codes: + * + * :macro:`NGTCP2_ERR_NOBUF` + * Buffer is too small. + */ +NGTCP2_EXTERN +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen); + +/** + * @function + * + * `ngtcp2_conn_decode_and_set_0rtt_transport_params` decodes QUIC + * transport parameters from |data| of length |datalen|, which is + * assumed to be the parameters received from the server in the + * previous connection, and sets it to |conn|. These parameters are + * used to send 0-RTT data. QUIC requires that client application + * should remember transport parameters along with a session ticket. + * + * At least following fields should be included: + * + * - :member:`ngtcp2_transport_params.initial_max_streams_bidi` + * - :member:`ngtcp2_transport_params.initial_max_streams_uni` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_local` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_remote` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_uni` + * - :member:`ngtcp2_transport_params.initial_max_data` + * - :member:`ngtcp2_transport_params.active_connection_id_limit` + * - :member:`ngtcp2_transport_params.max_datagram_frame_size` (if + * DATAGRAM extension was negotiated) + * + * This function must only be used by client. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_NOMEM` + * Out of memory. + * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` + * The input is malformed. + */ +NGTCP2_EXTERN int ngtcp2_conn_decode_and_set_0rtt_transport_params( + ngtcp2_conn *conn, const uint8_t *data, size_t datalen); /** * @function @@ -4182,7 +4158,7 @@ NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params_versioned( * Although the local transport parameters are passed to * `ngtcp2_conn_server_new`, server might want to update them after * ALPN is chosen. In that case, server can update the transport - * parameter with this function. Server must call this function + * parameters with this function. Server must call this function * before calling `ngtcp2_conn_install_tx_handshake_key`. * * This function returns 0 if it succeeds, or one of the following @@ -4208,11 +4184,9 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_encode_local_transport_params` encodes the local QUIC - * transport parameters in |dest| of length |destlen|. This is - * equivalent to calling `ngtcp2_conn_get_local_transport_params` and - * then `ngtcp2_encode_transport_params`. + * transport parameters in |dest| of length |destlen|. * - * This function returns the number of written, or one of the + * This function returns the number of bytes written, or one of the * following negative error codes: * * :macro:`NGTCP2_ERR_NOBUF` @@ -4226,16 +4200,16 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params( * * `ngtcp2_conn_open_bidi_stream` opens new bidirectional stream. The * |stream_user_data| is the user data specific to the stream. The - * open stream ID is stored in |*pstream_id|. + * stream ID of the opened stream is stored in |*pstream_id|. * * Application can call this function before handshake completes. For - * 0RTT packet, application can call this function after calling - * `ngtcp2_conn_set_early_remote_transport_params`. For 1RTT packet, - * application can call this function after calling - * `ngtcp2_conn_decode_remote_transport_params` and + * 0-RTT packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_0rtt_transport_params`. For 1-RTT + * packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_remote_transport_params` and * `ngtcp2_conn_install_tx_key`. If ngtcp2 crypto support library is * used, application can call this function after calling - * `ngtcp2_crypto_derive_and_install_tx_key` for 1RTT packet. + * `ngtcp2_crypto_derive_and_install_tx_key` for 1-RTT packet. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4243,7 +4217,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params( * :macro:`NGTCP2_ERR_NOMEM` * Out of memory * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` - * The remote peer does not allow |stream_id| yet. + * The remote endpoint does not allow |stream_id| yet. */ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -4254,16 +4228,16 @@ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, * * `ngtcp2_conn_open_uni_stream` opens new unidirectional stream. The * |stream_user_data| is the user data specific to the stream. The - * open stream ID is stored in |*pstream_id|. + * stream ID of the opened stream is stored in |*pstream_id|. * * Application can call this function before handshake completes. For - * 0RTT packet, application can call this function after calling - * `ngtcp2_conn_set_early_remote_transport_params`. For 1RTT packet, - * application can call this function after calling - * `ngtcp2_conn_decode_remote_transport_params` and + * 0-RTT packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_0rtt_transport_params`. For 1-RTT + * packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_remote_transport_params` and * `ngtcp2_conn_install_tx_key`. If ngtcp2 crypto support library is * used, application can call this function after calling - * `ngtcp2_crypto_derive_and_install_tx_key` for 1RTT packet. + * `ngtcp2_crypto_derive_and_install_tx_key` for 1-RTT packet. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4271,7 +4245,7 @@ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, * :macro:`NGTCP2_ERR_NOMEM` * Out of memory * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` - * The remote peer does not allow |stream_id| yet. + * The remote endpoint does not allow |stream_id| yet. */ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -4280,14 +4254,23 @@ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_shutdown_stream` closes stream denoted by |stream_id| - * abruptly. |app_error_code| is one of application error codes, and - * indicates the reason of shutdown. Successful call of this function - * does not immediately erase the state of the stream. The actual - * deletion is done when the remote endpoint sends acknowledgement. - * Calling this function is equivalent to call + * `ngtcp2_conn_shutdown_stream` closes a stream denoted by + * |stream_id| abruptly. |app_error_code| is one of application error + * codes, and indicates the reason of shutdown. Successful call of + * this function does not immediately erase the state of the stream. + * The actual deletion is done when the remote endpoint sends + * acknowledgement. Calling this function is equivalent to call * `ngtcp2_conn_shutdown_stream_read`, and - * `ngtcp2_conn_shutdown_stream_write` sequentially. + * `ngtcp2_conn_shutdown_stream_write` sequentially with the following + * differences. If |stream_id| refers to a local unidirectional + * stream, this function only shutdowns write side of the stream. If + * |stream_id| refers to a remote unidirectional stream, this function + * only shutdowns read side of the stream. + * + * |flags| is currently unused, and should be set to 0. + * + * This function returns 0 if a stream denoted by |stream_id| is not + * found. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4295,46 +4278,62 @@ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ -NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, +NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, uint64_t app_error_code); /** * @function * - * `ngtcp2_conn_shutdown_stream_write` closes write-side of stream + * `ngtcp2_conn_shutdown_stream_write` closes write-side of a stream * denoted by |stream_id| abruptly. |app_error_code| is one of * application error codes, and indicates the reason of shutdown. If - * this function succeeds, no application data is sent to the remote - * endpoint. It discards all data which has not been acknowledged - * yet. + * this function succeeds, no further application data is sent to the + * remote endpoint. It discards all data which has not been + * acknowledged yet. + * + * |flags| is currently unused, and should be set to 0. + * + * This function returns 0 if a stream denoted by |stream_id| is not + * found. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a remote unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, + uint32_t flags, int64_t stream_id, uint64_t app_error_code); /** * @function * - * `ngtcp2_conn_shutdown_stream_read` closes read-side of stream + * `ngtcp2_conn_shutdown_stream_read` closes read-side of a stream * denoted by |stream_id| abruptly. |app_error_code| is one of * application error codes, and indicates the reason of shutdown. If - * this function succeeds, no application data is forwarded to an - * application layer. + * this function succeeds, no further application data is forwarded to + * an application layer. + * + * |flags| is currently unused, and should be set to 0. + * + * This function returns 0 if a stream denoted by |stream_id| is not + * found. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a local unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, + uint32_t flags, int64_t stream_id, uint64_t app_error_code); @@ -4355,15 +4354,15 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * @macro * * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` indicates that more data may - * come and should be coalesced into the same packet if possible. + * come, and should be coalesced into the same packet if possible. */ #define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01u /** * @macro * - * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that the passed - * data is the final part of a stream. + * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that a passed data + * is the final part of a stream. */ #define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u @@ -4384,20 +4383,21 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * @function * * `ngtcp2_conn_writev_stream` writes a packet containing stream data - * of stream denoted by |stream_id|. The buffer of the packet is + * of a stream denoted by |stream_id|. The buffer of the packet is * pointed by |dest| of length |destlen|. This function performs QUIC * handshake as well. * * |destlen| should be at least - * :member:`ngtcp2_settings.max_udp_payload_size`. + * :member:`ngtcp2_settings.max_tx_udp_payload_size`. * * Specifying -1 to |stream_id| means no new stream data to send. * * If |path| is not ``NULL``, this function stores the network path - * with which the packet should be sent. Each addr field must point - * to the buffer which should be at least ``sizeof(struct - * sockaddr_storage)`` bytes long. The assignment might not be done - * if nothing is written to |dest|. + * with which the packet should be sent. Each addr field + * (:member:`ngtcp2_path.local` and :member:`ngtcp2_path.remote`) must + * point to the buffer which should be at least + * sizeof(:type:`sockaddr_union`) bytes long. The assignment might + * not be done if nothing is written to |dest|. * * If |pi| is not ``NULL``, this function stores packet metadata in it * if it succeeds. The metadata includes ECN markings. When calling @@ -4405,7 +4405,10 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * :macro:`NGTCP2_ERR_WRITE_MORE`, caller must pass the same |pi| to * this function. * - * If the all given data is encoded as STREAM frame in |dest|, and if + * Stream data is specified as vector of data |datav|. |datavcnt| + * specifies the number of :type:`ngtcp2_vec` that |datav| includes. + * + * If all given data is encoded as STREAM frame in |dest|, and if * |flags| & :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` is nonzero, fin * flag is set to outgoing STREAM frame. Otherwise, fin flag in * STREAM frame is not set. @@ -4422,49 +4425,67 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * The number of data encoded in STREAM frame is stored in |*pdatalen| * if it is not ``NULL``. The caller must keep the portion of data * covered by |*pdatalen| bytes in tact until - * :type:`ngtcp2_acked_stream_data_offset` indicates that they are - * acknowledged by a remote endpoint or the stream is closed. - * - * If |flags| equals to :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE`, this - * function produces a single payload of UDP packet. If the given - * stream data is small (e.g., few bytes), the packet might be - * severely under filled. Too many small packet might increase - * overall packet processing costs. Unless there are retransmissions, - * by default, application can only send 1 STREAM frame in one QUIC - * packet. In order to include more than 1 STREAM frame in one QUIC - * packet, specify :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` in |flags|. - * This is analogous to ``MSG_MORE`` flag in :manpage:`send(2)`. If - * the :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used, there are 4 + * :member:`ngtcp2_callbacks.acked_stream_data_offset` indicates that + * they are acknowledged by a remote endpoint or the stream is closed. + * + * If the given stream data is small (e.g., few bytes), the packet + * might be severely under filled. Too many small packet might + * increase overall packet processing costs. Unless there are + * retransmissions, by default, application can only send 1 STREAM + * frame in one QUIC packet. In order to include more than 1 STREAM + * frame in one QUIC packet, specify + * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` in |flags|. This is + * analogous to ``MSG_MORE`` flag in :manpage:`send(2)`. If the + * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used, there are 4 * outcomes: * * - The function returns the written length of packet just like * without :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. This is because - * packet is nearly full and the library decided to make a complete - * packet. |*pdatalen| might be -1 or >= 0. + * packet is nearly full, and the library decided to make a complete + * packet. |*pdatalen| might be -1 or >= 0. It may return 0 which + * indicates that no packet transmission is possible at the moment + * for some reason. * * - The function returns :macro:`NGTCP2_ERR_WRITE_MORE`. In this - * case, |*pdatalen| >= 0 is asserted. This indicates that - * application can call this function with different stream data (or - * `ngtcp2_conn_writev_datagram` if it has data to send in + * case, |*pdatalen| >= 0 is asserted. It indicates that + * application can still call this function with different stream + * data (or `ngtcp2_conn_writev_datagram` if it has data to send in * unreliable datagram) to pack them into the same packet. * Application has to specify the same |conn|, |path|, |pi|, |dest|, * |destlen|, and |ts| parameters, otherwise the behaviour is * undefined. The application can change |flags|. * - * - The function returns :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED` which - * indicates that stream is blocked because of flow control. - * - * - The other error might be returned just like without - * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. + * - The function returns one of the following negative error codes: + * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`, + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`, or + * :macro:`NGTCP2_ERR_STREAM_SHUT_WR`. In this case, |*pdatalen| == + * -1 is asserted. Application can still write the stream data of + * the other streams by calling this function (or + * `ngtcp2_conn_writev_datagram` if it has data to send in + * unreliable datagram) to pack them into the same packet. + * Application has to specify the same |conn|, |path|, |pi|, |dest|, + * |destlen|, and |ts| parameters, otherwise the behaviour is + * undefined. The application can change |flags|. * - * When application sees :macro:`NGTCP2_ERR_WRITE_MORE`, it must not - * call other ngtcp2 API functions (application can still call - * `ngtcp2_conn_write_connection_close` to handle error from this - * function). Just keep calling `ngtcp2_conn_writev_stream`, - * `ngtcp2_conn_write_pkt`, or `ngtcp2_conn_writev_datagram` until it - * returns a positive number (which indicates a complete packet is - * ready). If there is no stream data to include, call this function - * with |stream_id| as -1 to stop coalescing and write a packet. + * - The other negative error codes might be returned just like + * without :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. These errors + * should be treated as a connection error. + * + * When application uses :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` at + * least once, it must not call other ngtcp2 API functions + * (application can still call `ngtcp2_conn_write_connection_close` to + * handle error from this function. It can also call + * `ngtcp2_conn_shutdown_stream_read`, + * `ngtcp2_conn_shutdown_stream_write`, and + * `ngtcp2_conn_shutdown_stream`), just keep calling this function (or + * `ngtcp2_conn_writev_datagram`) until it returns 0, a positive + * number (which indicates a complete packet is ready), or the error + * codes other than :macro:`NGTCP2_ERR_WRITE_MORE`, + * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`, + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`, and + * :macro:`NGTCP2_ERR_STREAM_SHUT_WR`. If there is no stream data to + * include, call this function with |stream_id| as -1 to stop + * coalescing and write a packet. * * This function returns 0 if it cannot write any frame because buffer * is too small, or packet is congestion limited. Application should @@ -4473,11 +4494,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * This function must not be called from inside the callback * functions. * - * If pacing is enabled, `ngtcp2_conn_update_pkt_tx_time` must be - * called after this function. Application may call this function - * multiple times before calling `ngtcp2_conn_update_pkt_tx_time`. - * Packet pacing is enabled if BBR congestion controller algorithm is - * used. + * `ngtcp2_conn_update_pkt_tx_time` must be called after this + * function. Application may call this function multiple times before + * calling `ngtcp2_conn_update_pkt_tx_time`. * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -4501,12 +4520,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * Application can call this function to pack more stream data * into the same packet. See above to know how it works. * - * In general, if the error code which satisfies - * `ngtcp2_err_is_fatal(err) ` != 0 is returned, - * the application should just close the connection by calling - * `ngtcp2_conn_write_connection_close` or just delete the QUIC - * connection using `ngtcp2_conn_del`. It is undefined to call the - * other library functions. + * If any other negative error is returned, call + * `ngtcp2_conn_write_connection_close` to get terminal packet, and + * sending it makes QUIC connection enter the closing state. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -4531,10 +4547,23 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * @macro * * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_MORE` indicates that more data - * may come and should be coalesced into the same packet if possible. + * may come, and should be coalesced into the same packet if possible. */ #define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u +/** + * @function + * + * `ngtcp2_conn_write_datagram` is just like + * `ngtcp2_conn_writev_datagram`. The only difference is that it + * conveniently accepts a single buffer. + */ +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( + ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, + ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, + uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen, + ngtcp2_tstamp ts); + /** * @function * @@ -4544,25 +4573,28 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * as well. * * |destlen| should be at least - * :member:`ngtcp2_settings.max_udp_payload_size`. + * :member:`ngtcp2_settings.max_tx_udp_payload_size`. * * For |path| and |pi| parameters, refer to * `ngtcp2_conn_writev_stream`. * + * Stream data is specified as vector of data |datav|. |datavcnt| + * specifies the number of :type:`ngtcp2_vec` that |datav| includes. + * * If the given data is written to the buffer, nonzero value is * assigned to |*paccepted| if it is not NULL. The data in DATAGRAM * frame cannot be fragmented; writing partial data is not possible. * * |dgram_id| is an opaque identifier which should uniquely identify - * the given DATAGRAM. It is passed to :type:`ngtcp2_ack_datagram` - * callback when a packet that contains DATAGRAM frame is - * acknowledged. It is passed to :type:`ngtcp2_lost_datagram` - * callback when a packet that contains DATAGRAM frame is declared - * lost. If an application uses neither of those callbacks, it can - * sets 0 to this parameter. + * the given DATAGRAM data. It is passed to + * :member:`ngtcp2_callbacks.ack_datagram` callback when a packet that + * contains DATAGRAM frame is acknowledged. It is also passed to + * :member:`ngtcp2_callbacks.lost_datagram` callback when a packet + * that contains DATAGRAM frame is declared lost. If an application + * uses neither of those callbacks, it can sets 0 to this parameter. * - * This function might write other frames other than DATAGRAM, just - * like `ngtcp2_conn_writev_stream`. + * This function might write other frames other than DATAGRAM frame, + * just like `ngtcp2_conn_writev_stream`. * * If the function returns 0, it means that no more data cannot be * sent because of congestion control limit; or, data does not fit @@ -4593,10 +4625,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * When application sees :macro:`NGTCP2_ERR_WRITE_MORE`, it must not * call other ngtcp2 API functions (application can still call * `ngtcp2_conn_write_connection_close` to handle error from this - * function). Just keep calling `ngtcp2_conn_writev_datagram`, - * `ngtcp2_conn_writev_stream` or `ngtcp2_conn_write_pkt` until it - * returns a positive number (which indicates a complete packet is - * ready). + * function. It can also call `ngtcp2_conn_shutdown_stream_read`, + * `ngtcp2_conn_shutdown_stream_write`, and + * `ngtcp2_conn_shutdown_stream`). Just keep calling this function + * (or `ngtcp2_conn_writev_stream`) until it returns a positive number + * (which indicates a complete packet is ready). * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -4617,12 +4650,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * The provisional DATAGRAM frame size exceeds the maximum * DATAGRAM frame size that a remote endpoint can receive. * - * In general, if the error code which satisfies - * `ngtcp2_err_is_fatal(err) ` != 0 is returned, - * the application should just close the connection by calling - * `ngtcp2_conn_write_connection_close` or just delete the QUIC - * connection using `ngtcp2_conn_del`. It is undefined to call the - * other library functions. + * If any other negative error is returned, call + * `ngtcp2_conn_write_connection_close` to get terminal packet, and + * sending it makes QUIC connection enter the closing state. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -4633,30 +4663,37 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( /** * @function * - * `ngtcp2_conn_is_in_closing_period` returns nonzero if |conn| is in - * the closing period. + * `ngtcp2_conn_in_closing_period` returns nonzero if |conn| is in the + * closing period. */ -NGTCP2_EXTERN int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_is_in_draining_period` returns nonzero if |conn| is in + * `ngtcp2_conn_in_draining_period` returns nonzero if |conn| is in * the draining period. */ -NGTCP2_EXTERN int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_extend_max_stream_offset` extends stream's max stream - * data value by |datalen|. + * `ngtcp2_conn_extend_max_stream_offset` extends the maximum stream + * data that a remote endpoint can send by |datalen|. |stream_id| + * specifies the stream ID. This function only extends stream-level + * flow control window. + * + * This function returns 0 if a stream denoted by |stream_id| is not + * found. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a local unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, @@ -4666,7 +4703,8 @@ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_offset` extends max data offset by - * |datalen|. + * |datalen|. This function only extends connection-level flow + * control window. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, uint64_t datalen); @@ -4675,12 +4713,13 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_streams_bidi` extends the number of maximum - * local bidirectional streams that a remote endpoint can open by |n|. + * remote bidirectional streams that a remote endpoint can open by + * |n|. * * The library does not increase maximum stream limit automatically. * The exception is when a stream is closed without - * :type:`ngtcp2_stream_open` callback being called. In this case, - * stream limit is increased automatically. + * :member:`ngtcp2_callbacks.stream_open` callback being called. In + * this case, stream limit is increased automatically. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, size_t n); @@ -4689,13 +4728,13 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_streams_uni` extends the number of maximum - * local unidirectional streams that a remote endpoint can open by + * remote unidirectional streams that a remote endpoint can open by * |n|. * * The library does not increase maximum stream limit automatically. * The exception is when a stream is closed without - * :type:`ngtcp2_stream_open` callback being called. In this case, - * stream limit is increased automatically. + * :member:`ngtcp2_callbacks.stream_open` callback being called. In + * this case, stream limit is increased automatically. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n); @@ -4703,9 +4742,10 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_dcid` returns the non-NULL pointer to destination - * connection ID. If no destination connection ID is present, the - * return value is not ``NULL``, and its datalen field is 0. + * `ngtcp2_conn_get_dcid` returns the non-NULL pointer to the current + * Destination Connection ID. If no Destination Connection ID is + * present, the return value is not ``NULL``, and its :member:`datalen + * ` field is 0. */ NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn); @@ -4714,7 +4754,9 @@ NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn); * * `ngtcp2_conn_get_client_initial_dcid` returns the non-NULL pointer * to the Destination Connection ID that client sent in its Initial - * packet. + * packet. If the Destination Connection ID is not present, the + * return value is not ``NULL``, and its :member:`datalen + * ` field is 0. */ NGTCP2_EXTERN const ngtcp2_cid * ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); @@ -4722,31 +4764,17 @@ ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_num_scid` returns the number of source connection - * IDs which the local endpoint has provided to the peer and have not - * retired. - */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_num_scid(ngtcp2_conn *conn); - -/** - * @function - * - * `ngtcp2_conn_get_scid` writes the all source connection IDs which - * the local endpoint has provided to the peer and have not retired in - * |dest|. The buffer pointed by |dest| must have - * ``sizeof(ngtcp2_cid) * n`` bytes available, where n is the return - * value of `ngtcp2_conn_get_num_scid()`. + * `ngtcp2_conn_get_scid` writes the all Source Connection IDs which a + * local endpoint has provided to a remote endpoint, and are not + * retired in |dest|. If |dest| is NULL, this function does not write + * anything, and returns the number of Source Connection IDs that + * would otherwise be written to the provided buffer. The buffer + * pointed by |dest| must have sizeof(:type:`ngtcp2_cid`) * n bytes + * available, where n is the return value of `ngtcp2_conn_get_scid` + * with |dest| == NULL. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest); -/** - * @function - * - * `ngtcp2_conn_get_num_active_dcid` returns the number of the active - * destination connection ID. - */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_num_active_dcid(ngtcp2_conn *conn); - /** * @struct * @@ -4763,8 +4791,8 @@ typedef struct ngtcp2_cid_token { */ ngtcp2_cid cid; /** - * :member:`ps` is the path which is associated to this Connection - * ID. + * :member:`ps` is the path which this Connection ID is associated + * with. */ ngtcp2_path_storage ps; /** @@ -4782,10 +4810,15 @@ typedef struct ngtcp2_cid_token { /** * @function * - * `ngtcp2_conn_get_active_dcid` writes the all active destination - * connection IDs and tokens to |dest|. The buffer pointed by |dest| - * must have ``sizeof(ngtcp2_cid_token) * n`` bytes available, where n - * is the return value of `ngtcp2_conn_get_num_active_dcid()`. + * `ngtcp2_conn_get_active_dcid` writes the all active Destination + * Connection IDs and their tokens to |dest|. Before handshake + * completes, this function returns 0. If |dest| is NULL, this + * function does not write anything, and returns the number of + * Destination Connection IDs that would otherwise be written to the + * provided buffer. The buffer pointed by |dest| must have + * sizeof(:type:`ngtcp2_cid_token`) * n bytes available, where n is + * the return value of `ngtcp2_conn_get_active_dcid` with |dest| == + * NULL. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest); @@ -4801,7 +4834,8 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_negotiated_version` returns the negotiated version. + * `ngtcp2_conn_get_negotiated_version` returns the negotiated + * version. * * Until the version is negotiated, this function returns 0. */ @@ -4810,44 +4844,59 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_early_data_rejected` tells |conn| that early data was - * rejected by a server. |conn| discards the following connection - * states: + * `ngtcp2_conn_tls_early_data_rejected` tells |conn| that early data + * was rejected by a server during TLS handshake, or client decided + * not to attempt early data for some reason. |conn| discards the + * following connection states: * - * - Any opended streams. + * - Any opened streams. * - Stream identifier allocations. * - Max data extended by `ngtcp2_conn_extend_max_offset`. * - Max bidi streams extended by `ngtcp2_conn_extend_max_streams_bidi`. * - Max uni streams extended by `ngtcp2_conn_extend_max_streams_uni`. * * Application which wishes to retransmit early data, it has to open - * streams and send stream data again. + * streams, and send stream data again. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` + * User callback failed + */ +NGTCP2_EXTERN int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn); + +/** + * @function + * + * `ngtcp2_conn_get_tls_early_data_rejected` returns nonzero if + * `ngtcp2_conn_tls_early_data_rejected` has been called. */ -NGTCP2_EXTERN void ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_conn_stat` assigns connection statistics data to - * |*cstat|. + * `ngtcp2_conn_get_conn_info` assigns connection statistics data to + * |*cinfo|. */ -NGTCP2_EXTERN void ngtcp2_conn_get_conn_stat_versioned(ngtcp2_conn *conn, - int conn_stat_version, - ngtcp2_conn_stat *cstat); +NGTCP2_EXTERN void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, + int conn_info_version, + ngtcp2_conn_info *cinfo); /** * @function * - * `ngtcp2_conn_submit_crypto_data` submits crypto stream data |data| - * of length |datalen| to the library for transmission. The - * encryption level is given in |crypto_level|. + * `ngtcp2_conn_submit_crypto_data` submits crypto data |data| of + * length |datalen| to the library for transmission. + * |encryption_level| specifies the encryption level of data. * * The library makes a copy of the buffer pointed by |data| of length * |datalen|. Application can discard |data|. */ NGTCP2_EXTERN int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, const size_t datalen); /** @@ -4874,7 +4923,8 @@ NGTCP2_EXTERN int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_set_local_addr` sets local endpoint address |addr| to - * the current path of |conn|. + * the current path of |conn|. This function is provided for testing + * purpose only. */ NGTCP2_EXTERN void ngtcp2_conn_set_local_addr(ngtcp2_conn *conn, const ngtcp2_addr *addr); @@ -4898,34 +4948,34 @@ NGTCP2_EXTERN const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_max_udp_payload_size` returns the maximum UDP + * `ngtcp2_conn_get_max_tx_udp_payload_size` returns the maximum UDP * payload size that this local endpoint would send. This is the - * value of :member:`ngtcp2_settings.max_udp_payload_size` that is + * value of :member:`ngtcp2_settings.max_tx_udp_payload_size` that is * passed to `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_max_udp_payload_size(ngtcp2_conn *conn); +NGTCP2_EXTERN size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_path_max_udp_payload_size` returns the maximum UDP - * payload size for the current path. If - * :member:`ngtcp2_settings.no_udp_payload_size_shaping` is set to + * `ngtcp2_conn_get_path_max_tx_udp_payload_size` returns the maximum + * UDP payload size for the current path. If + * :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping` is set to * nonzero, this function is equivalent to - * `ngtcp2_conn_get_max_udp_payload_size`. Otherwise, it returns the - * maximum UDP payload size that is probed for the current path. + * `ngtcp2_conn_get_max_tx_udp_payload_size`. Otherwise, it returns + * the maximum UDP payload size that is probed for the current path. */ NGTCP2_EXTERN size_t -ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn); +ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn); /** * @function * * `ngtcp2_conn_initiate_immediate_migration` starts connection - * migration to the given |path|. - * Only client can initiate migration. This function does - * immediate migration; it does not probe peer reachability from a new - * local address. + * migration to the given |path|. Only client can initiate migration. + * This function does immediate migration; while the path validation + * is nonetheless performed, this function does not wait for it to + * succeed. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4936,7 +4986,8 @@ ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn); * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` * No unused connection ID is available. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |local_addr| equals the current local address. + * :member:`local ` field of |path| equals the + * current local address. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ @@ -4949,7 +5000,7 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_immediate_migration( * `ngtcp2_conn_initiate_migration` starts connection migration to the * given |path|. Only client can initiate migration. Unlike * `ngtcp2_conn_initiate_immediate_migration`, this function starts a - * path validation with a new path and migrate to the new path after + * path validation with a new path, and migrate to the new path after * successful path validation. * * This function returns 0 if it succeeds, or one of the following @@ -4961,7 +5012,8 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_immediate_migration( * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` * No unused connection ID is available. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |local_addr| equals the current local address. + * :member:`local ` field of |path| equals the + * current local address. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ @@ -4969,19 +5021,12 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts); -/** - * @function - * - * `ngtcp2_conn_get_max_local_streams_uni` returns the cumulative - * number of streams which local endpoint can open. - */ -NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_local_streams_uni(ngtcp2_conn *conn); - /** * @function * * `ngtcp2_conn_get_max_data_left` returns the number of bytes that - * this local endpoint can send in this connection. + * this local endpoint can send in this connection without violating + * connection-level flow control. */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); @@ -4990,7 +5035,8 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); * * `ngtcp2_conn_get_max_stream_data_left` returns the number of bytes * that this local endpoint can send to a stream identified by - * |stream_id|. If no such stream is found, this function returns 0. + * |stream_id| without violating stream-level flow control. If no + * such stream is found, this function returns 0. */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn, int64_t stream_id); @@ -5046,7 +5092,7 @@ ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_crypto_ctx` sets |ctx| for Handshake/1RTT packet + * `ngtcp2_conn_set_crypto_ctx` sets |ctx| for Handshake/1-RTT packet * encryption. The passed data will be passed to * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and * :type:`ngtcp2_hp_mask` callbacks. @@ -5057,114 +5103,113 @@ NGTCP2_EXTERN void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set by - * `ngtcp2_conn_set_tls_native_handle()`. + * `ngtcp2_conn_get_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` + * object for Handshake/1-RTT packet encryption. */ -NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_tls_native_handle` sets TLS native handle - * |tls_native_handle| to |conn|. Internally, it is used as an opaque - * pointer. + * `ngtcp2_conn_set_0rtt_crypto_ctx` sets |ctx| for 0-RTT packet + * encryption. The passed data will be passed to + * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and + * :type:`ngtcp2_hp_mask` callbacks. */ -NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, - void *tls_native_handle); +NGTCP2_EXTERN void +ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, + const ngtcp2_crypto_ctx *ctx); /** * @function * - * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry - * integrity tag verification. |aead| must be AEAD_AES_128_GCM. - * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as - * encryption key. This function must be called if |conn| is - * initialized as client. Server does not verify the tag and has no - * need to call this function. - * - * If this function succeeds, |conn| takes ownership of |aead_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` will be called to delete this - * object when it is no longer used. If this function fails, the - * caller is responsible to delete it. + * `ngtcp2_conn_get_0rtt_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` + * object for 0-RTT packet encryption. */ -NGTCP2_EXTERN void -ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead, - const ngtcp2_crypto_aead_ctx *aead_ctx); +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` - * object for Handshake/1RTT packet encryption. + * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set + * by `ngtcp2_conn_set_tls_native_handle`. */ -NGTCP2_EXTERN const ngtcp2_crypto_ctx * -ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn); +NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_early_crypto_ctx` sets |ctx| for 0RTT packet - * encryption. The passed data will be passed to - * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and - * :type:`ngtcp2_hp_mask` callbacks. + * `ngtcp2_conn_set_tls_native_handle` sets TLS native handle + * |tls_native_handle| to |conn|. Internally, it is used as an opaque + * pointer. */ -NGTCP2_EXTERN void -ngtcp2_conn_set_early_crypto_ctx(ngtcp2_conn *conn, - const ngtcp2_crypto_ctx *ctx); +NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, + void *tls_native_handle); /** * @function * - * `ngtcp2_conn_get_early_crypto_ctx` returns - * :type:`ngtcp2_crypto_ctx` object for 0RTT packet encryption. + * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry + * integrity tag verification. |aead| must be AEAD_AES_128_GCM. + * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as + * encryption key. This function must be called if |conn| is + * initialized as client. Server does not verify the tag, and has no + * need to call this function. + * + * |conn| takes ownership of |aead_ctx|. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` will be called to + * delete this object when it is no longer used. */ -NGTCP2_EXTERN const ngtcp2_crypto_ctx * -ngtcp2_conn_get_early_crypto_ctx(ngtcp2_conn *conn); +NGTCP2_EXTERN void +ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx); /** * @enum * - * :type:`ngtcp2_connection_close_error_code_type` defines connection - * error code type. + * :type:`ngtcp2_ccerr_type` defines connection error type. */ -typedef enum ngtcp2_connection_close_error_code_type { +typedef enum ngtcp2_ccerr_type { /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT` - * indicates the error code is QUIC transport error code. + * :enum:`NGTCP2_CCERR_TYPE_TRANSPORT` indicates the QUIC transport + * error, and the error code is QUIC transport error code. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, + NGTCP2_CCERR_TYPE_TRANSPORT, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION` - * indicates the error code is application error code. + * :enum:`NGTCP2_CCERR_TYPE_APPLICATION` indicates an application + * error, and the error code is application error code. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION, + NGTCP2_CCERR_TYPE_APPLICATION, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION` - * is a special case of QUIC transport error, and it indicates that - * client receives Version Negotiation packet. + * :enum:`NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION` is a special case + * of QUIC transport error, and it indicates that client receives + * Version Negotiation packet. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION, + NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE` - * is a special case of QUIC transport error, and it indicates that - * connection is closed because of idle timeout. + * :enum:`NGTCP2_CCERR_TYPE_IDLE_CLOSE` is a special case of QUIC + * transport error, and it indicates that connection is closed + * because of idle timeout. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE -} ngtcp2_connection_close_error_code_type; + NGTCP2_CCERR_TYPE_IDLE_CLOSE +} ngtcp2_ccerr_type; /** * @struct * - * :type:`ngtcp2_connection_close_error` contains connection - * error code, its type, and the optional reason phrase. + * :type:`ngtcp2_ccerr` contains connection error code, its type, a + * frame type that caused this error, and the optional reason phrase. */ -typedef struct ngtcp2_connection_close_error { +typedef struct ngtcp2_ccerr { /** - * :member:`type` is the type of :member:`error_code`. + * :member:`type` is the type of this error. */ - ngtcp2_connection_close_error_code_type type; + ngtcp2_ccerr_type type; /** * :member:`error_code` is the error code for connection closure. + * Its interpretation depends on :member:`type`. */ uint64_t error_code; /** @@ -5179,109 +5224,106 @@ typedef struct ngtcp2_connection_close_error { * received from a remote endpoint, it is truncated to at most 1024 * bytes. */ - uint8_t *reason; + const uint8_t *reason; /** * :member:`reasonlen` is the length of data pointed by * :member:`reason`. */ size_t reasonlen; -} ngtcp2_connection_close_error; +} ngtcp2_ccerr; /** * @function * - * `ngtcp2_connection_close_error_default` initializes |ccerr| with - * the default values. It sets the following fields: + * `ngtcp2_ccerr_default` initializes |ccerr| with the default values. + * It sets the following fields: * - * - :member:`type ` = - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT` - * - :member:`error_code ` = + * - :member:`type ` = + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT` + * - :member:`error_code ` = * :macro:`NGTCP2_NO_ERROR`. - * - :member:`frame_type ` = - * 0 - * - :member:`reason ` = NULL - * - :member:`reasonlen ` = 0 + * - :member:`frame_type ` = 0 + * - :member:`reason ` = NULL + * - :member:`reasonlen ` = 0 */ -NGTCP2_EXTERN void -ngtcp2_connection_close_error_default(ngtcp2_connection_close_error *ccerr); +NGTCP2_EXTERN void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` to |error_code|. - * |reason| is the reason phrase of length |reasonlen|. This function - * does not make a copy of the reason phrase. + * `ngtcp2_ccerr_set_transport_error` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` to + * |error_code|. |reason| is the reason phrase of length |reasonlen|. + * This function does not make a copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_transport_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error_liberr` sets - * type and error_code based on |liberr|. + * `ngtcp2_ccerr_set_liberr` sets type and error_code based on + * |liberr|. + * + * |reason| is the reason phrase of length |reasonlen|. This function + * does not make a copy of the reason phrase. * * If |liberr| is :macro:`NGTCP2_ERR_RECV_VERSION_NEGOTIATION`, - * :member:`ccerr->type ` is set - * to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION`, - * and :member:`ccerr->error_code - * ` to - * :macro:`NGTCP2_NO_ERROR`. If |liberr| is - * :macro:`NGTCP2_ERR_IDLE_CLOSE`, :member:`ccerr->type - * ` is set to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE`, - * and :member:`ccerr->error_code - * ` to - * :macro:`NGTCP2_NO_ERROR`. Otherwise, :member:`ccerr->type - * ` is set to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` is set to an error code - * inferred by |liberr| (see - * `ngtcp2_err_infer_quic_transport_error_code`). |reason| is the - * reason phrase of length |reasonlen|. This function does not make a - * copy of the reason phrase. + * :member:`ccerr->type ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION`, + * and :member:`ccerr->error_code ` to + * :macro:`NGTCP2_NO_ERROR`. + * + * If |liberr| is :macro:`NGTCP2_ERR_IDLE_CLOSE`, :member:`ccerr->type + * ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_IDLE_CLOSE`, and + * :member:`ccerr->error_code ` to + * :macro:`NGTCP2_NO_ERROR`. + * + * Otherwise, :member:`ccerr->type ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` is set to an + * error code inferred by |liberr| (see + * `ngtcp2_err_infer_quic_transport_error_code`). */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error_liberr( - ngtcp2_connection_close_error *ccerr, int liberr, const uint8_t *reason, - size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error_tls_alert` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` to bitwise-OR of - * :macro:`NGTCP2_CRYPTO_ERROR` and |tls_alert|. |reason| is the + * `ngtcp2_ccerr_set_tls_alert` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` to bitwise-OR + * of :macro:`NGTCP2_CRYPTO_ERROR` and |tls_alert|. |reason| is the * reason phrase of length |reasonlen|. This function does not make a * copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error_tls_alert( - ngtcp2_connection_close_error *ccerr, uint8_t tls_alert, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_tls_alert(ngtcp2_ccerr *ccerr, + uint8_t tls_alert, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_application_error` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION`, - * and :member:`ccerr->error_code - * ` to |error_code|. - * |reason| is the reason phrase of length |reasonlen|. This function - * does not make a copy of the reason phrase. + * `ngtcp2_ccerr_set_application_error` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, and + * :member:`ccerr->error_code ` to + * |error_code|. |reason| is the reason phrase of length |reasonlen|. + * This function does not make a copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen); /** * @function @@ -5295,20 +5337,20 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( * * If |path| is not ``NULL``, this function stores the network path * with which the packet should be sent. Each addr field must point - * to the buffer which should be at least ``sizeof(struct - * sockaddr_storage)`` bytes long. The assignment might not be done - * if nothing is written to |dest|. + * to the buffer which should be at least + * sizeof(:type:`ngtcp2_sockaddr_union`) bytes long. The assignment + * might not be done if nothing is written to |dest|. * * If |pi| is not ``NULL``, this function stores packet metadata in it * if it succeeds. The metadata includes ECN markings. * - * If :member:`ccerr->type ` == - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * this function sends CONNECTION_CLOSE (type 0x1c) frame. If - * :member:`ccerr->type ` == - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION`, - * it sends CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does - * not produce any data, and returns 0. + * If :member:`ccerr->type ` == + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, this + * function sends CONNECTION_CLOSE (type 0x1c) frame. If + * :member:`ccerr->type ` == + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, it sends + * CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does not produce + * any data, and returns 0. * * This function must not be called from inside the callback * functions. @@ -5325,7 +5367,8 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( * :macro:`NGTCP2_ERR_NOBUF` * Buffer is too small * :macro:`NGTCP2_ERR_INVALID_STATE` - * The current state does not allow sending CONNECTION_CLOSE. + * The current state does not allow sending CONNECTION_CLOSE + * frame. * :macro:`NGTCP2_ERR_PKT_NUM_EXHAUSTED` * Packet number is exhausted, and cannot send any more packet. * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` @@ -5334,23 +5377,22 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - const ngtcp2_connection_close_error *ccerr, ngtcp2_tstamp ts); + const ngtcp2_ccerr *ccerr, ngtcp2_tstamp ts); /** * @function * - * `ngtcp2_conn_get_connection_close_error` stores the received - * connection close error in |ccerr|. + * `ngtcp2_conn_get_ccerr` returns the received connection close + * error. If no connection error is received, it returns + * :type:`ngtcp2_ccerr` that is initialized by `ngtcp2_ccerr_default`. */ -NGTCP2_EXTERN void -ngtcp2_conn_get_connection_close_error(ngtcp2_conn *conn, - ngtcp2_connection_close_error *ccerr); +NGTCP2_EXTERN const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_is_local_stream` returns nonzero if |stream_id| denotes the - * stream which a local endpoint issues. + * `ngtcp2_conn_is_local_stream` returns nonzero if |stream_id| + * denotes a locally initiated stream. */ NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id); @@ -5367,7 +5409,7 @@ NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_after_retry` returns nonzero if |conn| as a client has - * received Retry packet from server and successfully validated it. + * received Retry packet from server, and successfully validated it. */ NGTCP2_EXTERN int ngtcp2_conn_after_retry(ngtcp2_conn *conn); @@ -5391,12 +5433,11 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_update_pkt_tx_time` sets the time instant of the next - * packet transmission. This function is noop if packet pacing is - * disabled. If packet pacing is enabled, this function must be - * called after (multiple invocation of) `ngtcp2_conn_writev_stream`. - * If packet aggregation (e.g., packet batching, GSO) is used, call - * this function after all aggregated datagrams are sent, which - * indicates multiple invocation of `ngtcp2_conn_writev_stream`. + * packet transmission to pace packets. This function must be called + * after (multiple invocation of) `ngtcp2_conn_writev_stream`. If + * packet aggregation (e.g., packet batching, GSO) is used, call this + * function after all aggregated datagrams are sent, which indicates + * multiple invocation of `ngtcp2_conn_writev_stream`. */ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -5405,8 +5446,7 @@ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_get_send_quantum` returns the maximum number of bytes - * that can be sent in one go without packet spacing. If packet - * pacing is disabled, this function returns SIZE_MAX. + * that can be sent in one go without packet spacing. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn); @@ -5427,8 +5467,8 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, * * `ngtcp2_strerror` returns the text representation of |liberr|. * |liberr| must be one of ngtcp2 library error codes (which is - * defined as NGTCP2_ERR_* macro, such as - * :macro:`NGTCP2_ERR_DECRYPT`). + * defined as :macro:`NGTCP2_ERR_* ` + * macros). */ NGTCP2_EXTERN const char *ngtcp2_strerror(int liberr); @@ -5437,8 +5477,8 @@ NGTCP2_EXTERN const char *ngtcp2_strerror(int liberr); * * `ngtcp2_err_is_fatal` returns nonzero if |liberr| is a fatal error. * |liberr| must be one of ngtcp2 library error codes (which is - * defined as NGTCP2_ERR_* macro, such as - * :macro:`NGTCP2_ERR_DECRYPT`). + * defined as :macro:`NGTCP2_ERR_* ` + * macros). */ NGTCP2_EXTERN int ngtcp2_err_is_fatal(int liberr); @@ -5448,7 +5488,7 @@ NGTCP2_EXTERN int ngtcp2_err_is_fatal(int liberr); * `ngtcp2_err_infer_quic_transport_error_code` returns a QUIC * transport error code which corresponds to |liberr|. |liberr| must * be one of ngtcp2 library error codes (which is defined as - * NGTCP2_ERR_* macro, such as :macro:`NGTCP2_ERR_DECRYPT`). + * :macro:`NGTCP2_ERR_* ` macros). */ NGTCP2_EXTERN uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr); @@ -5501,7 +5541,7 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps); * @function * * `ngtcp2_settings_default` initializes |settings| with the default - * values. First this function fills |settings| with 0 and set the + * values. First this function fills |settings| with 0, and set the * default value to the following fields: * * * :type:`cc_algo ` = @@ -5509,10 +5549,10 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps); * * :type:`initial_rtt ` = * :macro:`NGTCP2_DEFAULT_INITIAL_RTT` * * :type:`ack_thresh ` = 2 - * * :type:`max_udp_payload_size - * ` = 1452 + * * :type:`max_tx_udp_payload_size + * ` = 1452 * * :type:`handshake_timeout ` = - * :macro:`NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT`. + * ``UINT64_MAX`` */ NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version, ngtcp2_settings *settings); @@ -5521,7 +5561,7 @@ NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version, * @function * * `ngtcp2_transport_params_default` initializes |params| with the - * default values. First this function fills |params| with 0 and set + * default values. First this function fills |params| with 0, and set * the default value to the following fields: * * * :type:`max_udp_payload_size @@ -5564,7 +5604,7 @@ NGTCP2_EXTERN const ngtcp2_mem *ngtcp2_mem_default(void); /** * @struct * - * :type:`ngtcp2_info` is what `ngtcp2_version()` returns. It holds + * :type:`ngtcp2_info` is what `ngtcp2_version` returns. It holds * information about the particular ngtcp2 version. */ typedef struct ngtcp2_info { @@ -5576,12 +5616,12 @@ typedef struct ngtcp2_info { int age; /** * :member:`version_num` is the :macro:`NGTCP2_VERSION_NUM` number - * (since age ==1) + * (since :member:`age` ==1) */ int version_num; /** * :member:`version_str` points to the :macro:`NGTCP2_VERSION` - * string (since age ==1) + * string (since :member:`age` ==1) */ const char *version_str; /* -------- the above fields all exist when age == 1 */ @@ -5590,10 +5630,10 @@ typedef struct ngtcp2_info { /** * @function * - * `ngtcp2_version` returns a pointer to a ngtcp2_info struct with - * version information about the run-time library in use. The + * `ngtcp2_version` returns a pointer to a :type:`ngtcp2_info` struct + * with version information about the run-time library in use. The * |least_version| argument can be set to a 24 bit numerical value for - * the least accepted version number and if the condition is not met, + * the least accepted version number, and if the condition is not met, * this function will return a ``NULL``. Pass in 0 to skip the * version checking. */ @@ -5628,12 +5668,12 @@ NGTCP2_EXTERN int ngtcp2_path_eq(const ngtcp2_path *a, const ngtcp2_path *b); /** * @function * - * `ngtcp2_is_supported_version` returns nonzero if the library supports - * QUIC version |version|. + * `ngtcp2_is_supported_version` returns nonzero if the library + * supports QUIC version |version|. */ NGTCP2_EXTERN int ngtcp2_is_supported_version(uint32_t version); -/* +/** * @function * * `ngtcp2_is_reserved_version` returns nonzero if |version| is a @@ -5649,9 +5689,9 @@ NGTCP2_EXTERN int ngtcp2_is_reserved_version(uint32_t version); * |preferred_versions| of |preferred_versionslen| elements specifies * the preference of versions, which is sorted in the order of * preference. All versions included in |preferred_versions| must be - * supported by the library, that is, passing a version to - * `ngtcp2_is_supported_version` must return nonzero. This function - * is intended to be used by client when it receives Version + * supported by the library, that is, passing any version in the array + * to `ngtcp2_is_supported_version` must return nonzero. This + * function is intended to be used by client when it receives Version * Negotiation packet. If no version is selected, this function * returns 0. */ @@ -5703,6 +5743,17 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (DEST), (DESTLEN), \ (PDATALEN), (FLAGS), (STREAM_ID), (DATAV), (DATAVCNT), (TS)) +/* + * `ngtcp2_conn_write_datagram` is a wrapper around + * `ngtcp2_conn_write_datagram_versioned` to set the correct struct + * version. + */ +#define ngtcp2_conn_write_datagram(CONN, PATH, PI, DEST, DESTLEN, PACCEPTED, \ + FLAGS, DGRAM_ID, DATA, DATALEN, TS) \ + ngtcp2_conn_write_datagram_versioned( \ + (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (DEST), (DESTLEN), \ + (PACCEPTED), (FLAGS), (DGRAM_ID), (DATA), (DATALEN), (TS)) + /* * `ngtcp2_conn_writev_datagram` is a wrapper around * `ngtcp2_conn_writev_datagram_versioned` to set the correct struct @@ -5726,22 +5777,22 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CCERR), (TS)) /* - * `ngtcp2_encode_transport_params` is a wrapper around - * `ngtcp2_encode_transport_params_versioned` to set the correct + * `ngtcp2_transport_params_encode` is a wrapper around + * `ngtcp2_transport_params_encode_versioned` to set the correct * struct version. */ -#define ngtcp2_encode_transport_params(DEST, DESTLEN, EXTTYPE, PARAMS) \ - ngtcp2_encode_transport_params_versioned( \ - (DEST), (DESTLEN), (EXTTYPE), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) +#define ngtcp2_transport_params_encode(DEST, DESTLEN, PARAMS) \ + ngtcp2_transport_params_encode_versioned( \ + (DEST), (DESTLEN), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) /* - * `ngtcp2_decode_transport_params` is a wrapper around - * `ngtcp2_decode_transport_params_versioned` to set the correct + * `ngtcp2_transport_params_decode` is a wrapper around + * `ngtcp2_transport_params_decode_versioned` to set the correct * struct version. */ -#define ngtcp2_decode_transport_params(PARAMS, EXTTYPE, DATA, DATALEN) \ - ngtcp2_decode_transport_params_versioned( \ - NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS), (EXTTYPE), (DATA), (DATALEN)) +#define ngtcp2_transport_params_decode(PARAMS, DATA, DATALEN) \ + ngtcp2_transport_params_decode_versioned(NGTCP2_TRANSPORT_PARAMS_VERSION, \ + (PARAMS), (DATA), (DATALEN)) /* * `ngtcp2_conn_client_new` is a wrapper around @@ -5767,15 +5818,6 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CALLBACKS), NGTCP2_SETTINGS_VERSION, (SETTINGS), \ NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS), (MEM), (USER_DATA)) -/* - * `ngtcp2_conn_set_early_remote_transport_params` is a wrapper around - * `ngtcp2_conn_set_early_remote_transport_params_versioned` to set - * the correct struct version. - */ -#define ngtcp2_conn_set_early_remote_transport_params(CONN, PARAMS) \ - ngtcp2_conn_set_early_remote_transport_params_versioned( \ - (CONN), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) - /* * `ngtcp2_conn_set_local_transport_params` is a wrapper around * `ngtcp2_conn_set_local_transport_params_versioned` to set the @@ -5795,12 +5837,12 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (PARAMS)) /* - * `ngtcp2_conn_get_conn_stat` is a wrapper around - * `ngtcp2_conn_get_conn_stat_versioned` to set the correct struct + * `ngtcp2_conn_get_conn_info` is a wrapper around + * `ngtcp2_conn_get_conn_info_versioned` to set the correct struct * version. */ -#define ngtcp2_conn_get_conn_stat(CONN, CSTAT) \ - ngtcp2_conn_get_conn_stat_versioned((CONN), NGTCP2_CONN_STAT_VERSION, (CSTAT)) +#define ngtcp2_conn_get_conn_info(CONN, CINFO) \ + ngtcp2_conn_get_conn_info_versioned((CONN), NGTCP2_CONN_INFO_VERSION, (CINFO)) /* * `ngtcp2_settings_default` is a wrapper around diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c index 02c45de90d112a..d4778d66accf31 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c @@ -27,6 +27,9 @@ #include #include "ngtcp2_macro.h" +#include "ngtcp2_tstamp.h" + +ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent); static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num, ngtcp2_tstamp tstamp) { @@ -66,7 +69,7 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log, rv = ngtcp2_ringbuf_init(&acktr->acks, 32, sizeof(ngtcp2_acktr_ack_entry), mem); if (rv != 0) { - return rv; + goto fail_acks_init; } ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem); @@ -78,6 +81,10 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log, acktr->rx_npkt = 0; return 0; + +fail_acks_init: + ngtcp2_objalloc_free(&acktr->objalloc); + return rv; } void ngtcp2_acktr_free(ngtcp2_acktr *acktr) { @@ -286,16 +293,16 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) { return; } - min_ack = largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = largest_ack - (int64_t)fr->first_ack_range; if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) { acktr_on_ack(acktr, rb, j); return; } - for (i = 0; i < fr->num_blks && j < nacks; ++i) { - largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; - min_ack = largest_ack - (int64_t)fr->blks[i].blklen; + for (i = 0; i < fr->rangecnt && j < nacks; ++i) { + largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2; + min_ack = largest_ack - (int64_t)fr->ranges[i].len; for (;;) { if (ent->pkt_num > largest_ack) { @@ -326,8 +333,7 @@ void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) { int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr, ngtcp2_duration max_ack_delay, ngtcp2_tstamp ts) { - return acktr->first_unacked_ts != UINT64_MAX && - acktr->first_unacked_ts + max_ack_delay <= ts; + return ngtcp2_tstamp_elapsed(acktr->first_unacked_ts, max_ack_delay, ts); } void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h index 1b00d64fe62cb6..809fb692adc3c8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h @@ -65,7 +65,7 @@ typedef struct ngtcp2_acktr_entry { }; } ngtcp2_acktr_entry; -ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent); +ngtcp2_objalloc_decl(acktr_entry, ngtcp2_acktr_entry, oplent); /* * ngtcp2_acktr_entry_objalloc_new allocates memory for ent, and @@ -124,7 +124,8 @@ typedef struct ngtcp2_acktr { /* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added first time after the last outgoing ACK frame. */ ngtcp2_tstamp first_unacked_ts; - /* rx_npkt is the number of packets received without sending ACK. */ + /* rx_npkt is the number of ACK eliciting packets received without + sending ACK. */ size_t rx_npkt; } ngtcp2_acktr; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c index daab5dd7ce664b..f389abe76d71c8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c @@ -27,6 +27,8 @@ #include #include +#include "ngtcp2_unreachable.h" + ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr, ngtcp2_socklen addrlen) { dest->addrlen = addrlen; @@ -66,8 +68,7 @@ static int sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) { memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0; } default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -109,8 +110,7 @@ uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) { return flags; } default: - assert(0); - abort(); + ngtcp2_unreachable(); } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h index f1d7f7bdc70ea9..8e3a9f591d9977 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h @@ -38,8 +38,10 @@ */ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src); -/* - * ngtcp2_addr_eq returns nonzero if |a| equals |b|. +/** + * @function + * + * `ngtcp2_addr_eq` returns nonzero if |a| equals |b|. */ int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c index 0816d69b816c52..27c4667c03924a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c @@ -9,7 +9,7 @@ * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to - * the following conditions + * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. @@ -25,668 +25,1426 @@ #include "ngtcp2_bbr.h" #include +#include #include "ngtcp2_log.h" #include "ngtcp2_macro.h" #include "ngtcp2_mem.h" #include "ngtcp2_rcvry.h" #include "ngtcp2_rst.h" +#include "ngtcp2_conn_stat.h" -static const double pacing_gain_cycle[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; +#define NGTCP2_BBR_MAX_BW_FILTERLEN 2 -#define NGTCP2_BBR_GAIN_CYCLELEN \ - (sizeof(pacing_gain_cycle) / sizeof(pacing_gain_cycle[0])) +#define NGTCP2_BBR_EXTRA_ACKED_FILTERLEN 10 + +#define NGTCP2_BBR_STARTUP_PACING_GAIN_H 277 + +#define NGTCP2_BBR_STARTUP_CWND_GAIN_H 200 + +#define NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H 50 + +#define NGTCP2_BBR_BETA_NUMER 7 +#define NGTCP2_BBR_BETA_DENOM 10 + +#define NGTCP2_BBR_LOSS_THRESH_NUMER 2 +#define NGTCP2_BBR_LOSS_THRESH_DENOM 100 + +#define NGTCP2_BBR_HEADROOM_NUMER 15 +#define NGTCP2_BBR_HEADROOM_DENOM 100 + +#define NGTCP2_BBR_PROBE_RTT_INTERVAL (5 * NGTCP2_SECONDS) +#define NGTCP2_BBR_MIN_RTT_FILTERLEN (10 * NGTCP2_SECONDS) -#define NGTCP2_BBR_HIGH_GAIN 2.89 #define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS) -#define NGTCP2_RTPROP_FILTERLEN (10 * NGTCP2_SECONDS) -#define NGTCP2_BBR_BTL_BW_FILTERLEN 10 -static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, +#define NGTCP2_BBR_PACING_MARGIN_PERCENT 1 + +static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp initial_ts); + +static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr); + +static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr); + +static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr); + +static void bbr_init_full_pipe(ngtcp2_cc_bbr *bbr); + +static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t pacing_gain_h); + +static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_enter_startup(ngtcp2_cc_bbr *bbr); + +static void bbr_check_startup_done(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack); + +static void bbr_update_on_ack(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc, + +static void bbr_update_model_and_state(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc, + +static void bbr_update_control_parameters(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack); -static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_init_round_counting(ngtcp2_bbr_cc *cc); -static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack); -static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); -static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc, + +static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + +static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - double pacing_gain); -static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat); -static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts); -static void bbr_enter_startup(ngtcp2_bbr_cc *cc); -static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc); -static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc); -static void bbr_enter_drain(ngtcp2_bbr_cc *cc); -static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr); + +static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr); + +static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack); + +static void bbr_start_round(ngtcp2_cc_bbr *bbr); + +static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr); + +static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static void bbr_enter_drain(ngtcp2_cc_bbr *bbr); + +static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); -static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); -static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_start_probe_bw_down(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_start_probe_bw_cruise(ngtcp2_cc_bbr *bbr); + +static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr); + +static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static int bbr_check_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_duration interval, ngtcp2_tstamp ts); + +static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat); -static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static int bbr_check_time_to_probe_bw(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr); + +static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static int is_inflight_too_high(const ngtcp2_rs *rs); + +static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_rs *rs, ngtcp2_tstamp ts); + +static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + +static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_rs *rs, + const ngtcp2_cc_pkt *pkt); + +static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static void bbr_check_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc); -static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static void bbr_enter_probe_rtt(ngtcp2_cc_bbr *bbr); + +static void bbr_handle_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); - -void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log) { - cc->ccb.log = log; - cc->rst = rst; - cc->rand = rand; - cc->rand_ctx = *rand_ctx; - cc->initial_cwnd = cstat->cwnd; - bbr_init(cc, cstat, initial_ts); -} - -void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc) { (void)cc; } - -int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem) { - ngtcp2_bbr_cc *bbr_cc; - - bbr_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr_cc)); - if (bbr_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_bbr_cc_init(bbr_cc, cstat, rst, initial_ts, rand, rand_ctx, log); - - cc->ccb = &bbr_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_bbr_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_bbr_cc_congestion_event; - cc->on_spurious_congestion = ngtcp2_cc_bbr_cc_on_spurious_congestion; - cc->on_persistent_congestion = ngtcp2_cc_bbr_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_bbr_cc_on_ack_recv; - cc->on_pkt_sent = ngtcp2_cc_bbr_cc_on_pkt_sent; - cc->new_rtt_sample = ngtcp2_cc_bbr_cc_new_rtt_sample; - cc->reset = ngtcp2_cc_bbr_cc_reset; - cc->event = ngtcp2_cc_bbr_cc_event; - return 0; -} +static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); + +static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t bw, + uint64_t gain_h); + +static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t inflight); + +static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + uint64_t bw, uint64_t gain_h); + +static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static uint64_t min_pipe_cwnd(size_t max_udp_payload_size); + +static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr); + +static void bbr_modulate_cwnd_for_recovery(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_time); + +static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); + +static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp initial_ts) { + ngtcp2_window_filter_init(&bbr->max_bw_filter, NGTCP2_BBR_MAX_BW_FILTERLEN); + ngtcp2_window_filter_init(&bbr->extra_acked_filter, + NGTCP2_BBR_EXTRA_ACKED_FILTERLEN); + + bbr->min_rtt = UINT64_MAX; + bbr->min_rtt_stamp = initial_ts; + /* remark: Use UINT64_MAX instead of 0 for consistency. */ + bbr->probe_rtt_done_stamp = UINT64_MAX; + bbr->probe_rtt_round_done = 0; + bbr->prior_cwnd = 0; + bbr->idle_restart = 0; + bbr->extra_acked_interval_start = initial_ts; + bbr->extra_acked_delivered = 0; + + bbr_reset_congestion_signals(bbr); + bbr_reset_lower_bounds(bbr); + bbr_init_round_counting(bbr); + bbr_init_full_pipe(bbr); + bbr_init_pacing_rate(bbr, cstat); + bbr_enter_startup(bbr); + + cstat->send_quantum = cstat->max_tx_udp_payload_size * 10; + + /* Missing in documentation */ + bbr->loss_round_start = 0; + bbr->loss_round_delivered = UINT64_MAX; + + bbr->rounds_since_bw_probe = 0; + + bbr->max_bw = 0; + bbr->bw = 0; + + bbr->cycle_count = 0; + + bbr->extra_acked = 0; + + bbr->bytes_lost_in_round = 0; + bbr->loss_events_in_round = 0; -void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr_cc, ccb); + bbr->offload_budget = 0; - ngtcp2_bbr_cc_free(bbr_cc); - ngtcp2_mem_free(mem, bbr_cc); + bbr->probe_up_cnt = UINT64_MAX; + bbr->cycle_stamp = UINT64_MAX; + bbr->ack_phase = 0; + bbr->bw_probe_wait = 0; + bbr->bw_probe_samples = 0; + bbr->bw_probe_up_rounds = 0; + bbr->bw_probe_up_acks = 0; + + bbr->inflight_hi = UINT64_MAX; + bbr->bw_hi = UINT64_MAX; + + bbr->probe_rtt_expired = 0; + bbr->probe_rtt_min_delay = UINT64_MAX; + bbr->probe_rtt_min_stamp = initial_ts; + + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + + bbr->max_inflight = 0; + + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->congestion_recovery_next_round_delivered = 0; + + bbr->prior_inflight_lo = 0; + bbr->prior_inflight_hi = 0; + bbr->prior_bw_lo = 0; } -void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)pkt; - (void)ts; +static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) { + bbr->loss_in_round = 0; + bbr->bw_latest = 0; + bbr->inflight_latest = 0; } -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time) { - return cstat->congestion_recovery_start_ts != UINT64_MAX && - sent_time <= cstat->congestion_recovery_start_ts; +static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) { + bbr->bw_lo = UINT64_MAX; + bbr->inflight_lo = UINT64_MAX; } -void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); +static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr) { + bbr->next_round_delivered = 0; + bbr->round_start = 0; + bbr->round_count = 0; +} - if (cc->in_loss_recovery || cc->congestion_recovery_start_ts != UINT64_MAX || - in_congestion_recovery(cstat, sent_ts)) { +static void bbr_init_full_pipe(ngtcp2_cc_bbr *bbr) { + bbr->filled_pipe = 0; + bbr->full_bw = 0; + bbr->full_bw_count = 0; +} + +static void bbr_check_startup_full_bandwidth(ngtcp2_cc_bbr *bbr) { + if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { return; } - cc->congestion_recovery_start_ts = ts; -} + if (bbr->max_bw * 100 >= bbr->full_bw * 125) { + bbr->full_bw = bbr->max_bw; + bbr->full_bw_count = 0; + } -void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)ts; + ++bbr->full_bw_count; - cc->congestion_recovery_start_ts = UINT64_MAX; - cstat->congestion_recovery_start_ts = UINT64_MAX; + if (bbr->full_bw_count >= 3) { + bbr->filled_pipe = 1; - if (cc->in_loss_recovery) { - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; - bbr_restore_cwnd(cc, cstat); + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr filled pipe, full_bw=%" PRIu64, bbr->full_bw); } } -void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)ts; +static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack) { + if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { + return; + } - cstat->congestion_recovery_start_ts = UINT64_MAX; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; + if (bbr->loss_events_in_round <= 3) { + return; + } - bbr_save_cwnd(cc, cstat); - cstat->cwnd = 2 * cstat->max_udp_payload_size; -} + /* loss_thresh = 2% */ + if (bbr->bytes_lost_in_round * 100 <= ack->prior_bytes_in_flight * 2) { + return; + } -void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); + bbr->filled_pipe = 1; +} - bbr_update_on_ack(bbr_cc, cstat, ack, ts); +static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + cstat->pacing_interval = NGTCP2_MILLISECONDS * 100 / + NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd; } -void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)pkt; +static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t pacing_gain_h) { + ngtcp2_duration interval; + + if (bbr->bw == 0) { + return; + } + + interval = NGTCP2_SECONDS * 100 * 100 / pacing_gain_h / bbr->bw / + (100 - NGTCP2_BBR_PACING_MARGIN_PERCENT); - bbr_on_transmit(bbr_cc, cstat); + if (bbr->filled_pipe || interval < cstat->pacing_interval) { + cstat->pacing_interval = interval; + } } -void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)ts; +static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain_h); } -void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - bbr_init(bbr_cc, cstat, ts); +static void bbr_enter_startup(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter Startup"); + + bbr->state = NGTCP2_BBR_STATE_STARTUP; + bbr->pacing_gain_h = NGTCP2_BBR_STARTUP_PACING_GAIN_H; + bbr->cwnd_gain_h = NGTCP2_BBR_STARTUP_CWND_GAIN_H; } -void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)event; - (void)ts; +static void bbr_check_startup_done(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack) { + bbr_check_startup_full_bandwidth(bbr); + bbr_check_startup_high_loss(bbr, ack); + + if (bbr->state == NGTCP2_BBR_STATE_STARTUP && bbr->filled_pipe) { + bbr_enter_drain(bbr); + } +} + +static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + bbr_handle_restart_from_idle(bbr, cstat, ts); } -static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, +static void bbr_update_on_ack(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_model_and_state(cc, cstat, ack, ts); - bbr_update_control_parameters(cc, cstat, ack); + bbr_update_model_and_state(bbr, cstat, ack, ts); + bbr_update_control_parameters(bbr, cstat, ack); } -static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc, +static void bbr_update_model_and_state(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_btl_bw(cc, cstat, ack); - bbr_check_cycle_phase(cc, cstat, ack, ts); - bbr_check_full_pipe(cc); - bbr_check_drain(cc, cstat, ts); - bbr_update_rtprop(cc, cstat, ts); - bbr_check_probe_rtt(cc, cstat, ts); + bbr_update_latest_delivery_signals(bbr, cstat); + bbr_update_congestion_signals(bbr, cstat, ack); + bbr_update_ack_aggregation(bbr, cstat, ack, ts); + bbr_check_startup_done(bbr, ack); + bbr_check_drain(bbr, cstat, ts); + bbr_update_probe_bw_cycle_phase(bbr, cstat, ack, ts); + bbr_update_min_rtt(bbr, ack, ts); + bbr_check_probe_rtt(bbr, cstat, ts); + bbr_advance_latest_delivery_signals(bbr, cstat); + bbr_bound_bw_for_model(bbr); } -static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc, +static void bbr_update_control_parameters(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack) { - bbr_set_pacing_rate(cc, cstat); - bbr_set_send_quantum(cc, cstat); - bbr_set_cwnd(cc, cstat, ack); + bbr_set_pacing_rate(bbr, cstat); + bbr_set_send_quantum(bbr, cstat); + bbr_set_cwnd(bbr, cstat, ack); } -static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - bbr_handle_restart_from_idle(cc, cstat); +static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + bbr_handle_lost_packet(cc, cstat, pkt, ts); } -static void bbr_init_round_counting(ngtcp2_bbr_cc *cc) { - cc->next_round_delivered = 0; - cc->round_start = 0; - cc->round_count = 0; -} - -static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack) { - if (ack->pkt_delivered >= cc->next_round_delivered) { - cc->next_round_delivered = cc->rst->delivered; - ++cc->round_count; - cc->round_start = 1; +static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + bbr->loss_round_start = 0; + bbr->bw_latest = ngtcp2_max(bbr->bw_latest, cstat->delivery_rate_sec); + bbr->inflight_latest = + ngtcp2_max(bbr->inflight_latest, bbr->rst->rs.delivered); - return; + if (bbr->rst->rs.prior_delivered >= bbr->loss_round_delivered) { + bbr->loss_round_delivered = bbr->rst->delivered; + bbr->loss_round_start = 1; } +} - cc->round_start = 0; +static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + if (bbr->loss_round_start) { + bbr->bw_latest = cstat->delivery_rate_sec; + bbr->inflight_latest = bbr->rst->rs.delivered; + } } -static void bbr_handle_recovery(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (cc->in_loss_recovery) { - if (ack->pkt_delivered >= cc->congestion_recovery_next_round_delivered) { - cc->packet_conservation = 0; - } +static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + bbr_update_max_bw(bbr, cstat, ack); + + if (ack->bytes_lost) { + bbr->bytes_lost_in_round += ack->bytes_lost; + ++bbr->loss_events_in_round; - if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) { - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; - bbr_restore_cwnd(cc, cstat); + if (!bbr->loss_in_round) { + bbr->loss_in_round = 1; + bbr->loss_round_delivered = bbr->rst->delivered; } + } + if (!bbr->loss_round_start) { return; } - if (cc->congestion_recovery_start_ts != UINT64_MAX) { - cc->in_loss_recovery = 1; - bbr_save_cwnd(cc, cstat); - cstat->cwnd = cstat->bytes_in_flight + - ngtcp2_max(ack->bytes_delivered, cstat->max_udp_payload_size); + bbr_adapt_lower_bounds_from_congestion(bbr, cstat); - cstat->congestion_recovery_start_ts = cc->congestion_recovery_start_ts; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->packet_conservation = 1; - cc->congestion_recovery_next_round_delivered = cc->rst->delivered; + bbr->loss_in_round = 0; +} + +static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + if (bbr_is_in_probe_bw_state(bbr)) { + return; + } + + if (bbr->loss_in_round) { + bbr_init_lower_bounds(bbr, cstat); + bbr_loss_lower_bounds(bbr); } } -static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_round(cc, ack); - bbr_handle_recovery(cc, cstat, ack); +static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + if (bbr->bw_lo == UINT64_MAX) { + bbr->bw_lo = bbr->max_bw; + } - if (cstat->delivery_rate_sec < cc->btl_bw && cc->rst->rs.is_app_limited) { - return; + if (bbr->inflight_lo == UINT64_MAX) { + bbr->inflight_lo = cstat->cwnd; } +} - ngtcp2_window_filter_update(&cc->btl_bw_filter, cstat->delivery_rate_sec, - cc->round_count); +static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr) { + bbr->bw_lo = ngtcp2_max(bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / + NGTCP2_BBR_BETA_DENOM); + bbr->inflight_lo = ngtcp2_max(bbr->inflight_latest, + bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / + NGTCP2_BBR_BETA_DENOM); +} - cc->btl_bw = ngtcp2_window_filter_get_best(&cc->btl_bw_filter); +static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) { + bbr->bw = ngtcp2_min(bbr->max_bw, bbr->bw_lo); + bbr->bw = ngtcp2_min(bbr->bw, bbr->bw_hi); } -static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - cc->rtprop_expired = ts > cc->rtprop_stamp + NGTCP2_RTPROP_FILTERLEN; +static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + bbr_update_round(bbr, ack); - /* Need valid RTT sample */ - if (cstat->latest_rtt && - (cstat->latest_rtt <= cc->rt_prop || cc->rtprop_expired)) { - cc->rt_prop = cstat->latest_rtt; - cc->rtprop_stamp = ts; + if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) { + ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec, + bbr->cycle_count); - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr update RTprop=%" PRIu64, cc->rt_prop); + bbr->max_bw = ngtcp2_window_filter_get_best(&bbr->max_bw_filter); } } -static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - double nominal_bandwidth = - (double)cc->initial_cwnd / (double)NGTCP2_MILLISECONDS; +static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack) { + if (ack->pkt_delivered >= bbr->next_round_delivered) { + bbr_start_round(bbr); - cstat->pacing_rate = cc->pacing_gain * nominal_bandwidth; -} + ++bbr->round_count; + ++bbr->rounds_since_bw_probe; + bbr->round_start = 1; -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - double pacing_gain) { - double rate = pacing_gain * (double)cc->btl_bw / NGTCP2_SECONDS; + bbr->bytes_lost_in_round = 0; + bbr->loss_events_in_round = 0; + + bbr->rst->is_cwnd_limited = 0; - if (cc->filled_pipe || rate > cstat->pacing_rate) { - cstat->pacing_rate = rate; + return; } + + bbr->round_start = 0; } -static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - bbr_set_pacing_rate_with_gain(cc, cstat, cc->pacing_gain); +static void bbr_start_round(ngtcp2_cc_bbr *bbr) { + bbr->next_round_delivered = bbr->rst->delivered; } -static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - uint64_t send_quantum; - (void)cc; +static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) { + switch (bbr->state) { + case NGTCP2_BBR_STATE_PROBE_BW_DOWN: + case NGTCP2_BBR_STATE_PROBE_BW_CRUISE: + case NGTCP2_BBR_STATE_PROBE_BW_REFILL: + case NGTCP2_BBR_STATE_PROBE_BW_UP: + return 1; + default: + return 0; + } +} - if (cstat->pacing_rate < 1.2 * 1024 * 1024 / 8 / NGTCP2_SECONDS) { - cstat->send_quantum = cstat->max_udp_payload_size; - } else if (cstat->pacing_rate < 24.0 * 1024 * 1024 / 8 / NGTCP2_SECONDS) { - cstat->send_quantum = cstat->max_udp_payload_size * 2; - } else { - send_quantum = - (uint64_t)(cstat->pacing_rate * (double)(cstat->min_rtt == UINT64_MAX - ? NGTCP2_MILLISECONDS - : cstat->min_rtt)); - cstat->send_quantum = (size_t)ngtcp2_min(send_quantum, 64 * 1024); +static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + ngtcp2_duration interval = ts - bbr->extra_acked_interval_start; + uint64_t expected_delivered = bbr->bw * interval / NGTCP2_SECONDS; + uint64_t extra; + + if (bbr->extra_acked_delivered <= expected_delivered) { + bbr->extra_acked_delivered = 0; + bbr->extra_acked_interval_start = ts; + expected_delivered = 0; } - cstat->send_quantum = - ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10); + bbr->extra_acked_delivered += ack->bytes_delivered; + extra = bbr->extra_acked_delivered - expected_delivered; + extra = ngtcp2_min(extra, cstat->cwnd); + + ngtcp2_window_filter_update(&bbr->extra_acked_filter, extra, + bbr->round_count); + + bbr->extra_acked = ngtcp2_window_filter_get_best(&bbr->extra_acked_filter); } -static uint64_t bbr_inflight(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - double gain) { - uint64_t quanta = 3 * cstat->send_quantum; - double estimated_bdp; +static void bbr_enter_drain(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter Drain"); + + bbr->state = NGTCP2_BBR_STATE_DRAIN; + bbr->pacing_gain_h = 100 * 100 / NGTCP2_BBR_STARTUP_CWND_GAIN_H; + bbr->cwnd_gain_h = NGTCP2_BBR_STARTUP_CWND_GAIN_H; +} - if (cc->rt_prop == UINT64_MAX) { - /* no valid RTT samples yet */ - return cc->initial_cwnd; +static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->state == NGTCP2_BBR_STATE_DRAIN && + cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->bw, 100)) { + bbr_enter_probe_bw(bbr, ts); } +} - estimated_bdp = (double)cc->btl_bw * (double)cc->rt_prop / NGTCP2_SECONDS; +static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + bbr_start_probe_bw_down(bbr, ts); +} - return (uint64_t)(gain * estimated_bdp) + quanta; +static void bbr_start_probe_bw_down(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_DOWN"); + + bbr_reset_congestion_signals(bbr); + + bbr->probe_up_cnt = UINT64_MAX; + + bbr_pick_probe_wait(bbr); + + bbr->cycle_stamp = ts; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING; + + bbr_start_round(bbr); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_DOWN; + bbr->pacing_gain_h = 90; + bbr->cwnd_gain_h = 200; } -static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - cc->target_cwnd = bbr_inflight(cc, cstat, cc->cwnd_gain); +static void bbr_start_probe_bw_cruise(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr start ProbeBW_CRUISE"); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_CRUISE; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = 200; } -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (ack->bytes_lost > 0) { - if (cstat->cwnd > ack->bytes_lost) { - cstat->cwnd -= ack->bytes_lost; - cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_udp_payload_size); - } else { - cstat->cwnd = cstat->max_udp_payload_size; - } +static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr start ProbeBW_REFILL"); + + bbr_reset_lower_bounds(bbr); + + bbr->bw_probe_up_rounds = 0; + bbr->bw_probe_up_acks = 0; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_REFILLING; + + bbr_start_round(bbr); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_REFILL; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = 200; +} + +static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_UP"); + + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING; + + bbr_start_round(bbr); + + bbr->cycle_stamp = ts; + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_UP; + bbr->pacing_gain_h = 125; + bbr->cwnd_gain_h = 225; + + bbr_raise_inflight_hi_slope(bbr, cstat); +} + +static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + if (!bbr->filled_pipe) { + return; } - if (cc->packet_conservation) { - cstat->cwnd = - ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); + bbr_adapt_upper_bounds(bbr, cstat, ack, ts); + + if (!bbr_is_in_probe_bw_state(bbr)) { + return; + } + + switch (bbr->state) { + case NGTCP2_BBR_STATE_PROBE_BW_DOWN: + if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { + return; + } + + if (bbr_check_time_to_cruise(bbr, cstat, ts)) { + bbr_start_probe_bw_cruise(bbr); + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_CRUISE: + if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { + return; + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_REFILL: + if (bbr->round_start) { + bbr->bw_probe_samples = 1; + bbr_start_probe_bw_up(bbr, cstat, ts); + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_UP: + if (bbr_has_elapsed_in_phase(bbr, bbr->min_rtt, ts) && + cstat->bytes_in_flight > bbr_inflight(bbr, cstat, bbr->max_bw, 125)) { + bbr_start_probe_bw_down(bbr, ts); + } + + break; + default: + break; } } -static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - if (!cc->in_loss_recovery && cc->state != NGTCP2_BBR_STATE_PROBE_RTT) { - cc->prior_cwnd = cstat->cwnd; - return; +static int bbr_check_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + (void)ts; + + if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) { + return 0; } - cc->prior_cwnd = ngtcp2_max(cc->prior_cwnd, cstat->cwnd); + if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->max_bw, 100)) { + return 1; + } + + return 0; } -static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - cstat->cwnd = ngtcp2_max(cstat->cwnd, cc->prior_cwnd); +static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_duration interval, + ngtcp2_tstamp ts) { + return ts > bbr->cycle_stamp + interval; } -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { - return max_udp_payload_size * 4; +static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t headroom; + uint64_t mpcwnd; + if (bbr->inflight_hi == UINT64_MAX) { + return UINT64_MAX; + } + + headroom = ngtcp2_max(cstat->max_tx_udp_payload_size, + bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER / + NGTCP2_BBR_HEADROOM_DENOM); + mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + if (bbr->inflight_hi > headroom) { + return ngtcp2_max(bbr->inflight_hi - headroom, mpcwnd); + } + + return mpcwnd; } -static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat) { - if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) { - cstat->cwnd = - ngtcp2_min(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); +static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t growth_this_round = cstat->max_tx_udp_payload_size + << bbr->bw_probe_up_rounds; + + bbr->bw_probe_up_rounds = ngtcp2_min(bbr->bw_probe_up_rounds + 1, 30); + bbr->probe_up_cnt = ngtcp2_max(cstat->cwnd / growth_this_round, 1) * + cstat->max_tx_udp_payload_size; +} + +static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + uint64_t delta; + + if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) { + return; + } + + bbr->bw_probe_up_acks += ack->bytes_delivered; + + if (bbr->bw_probe_up_acks >= bbr->probe_up_cnt) { + delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt; + bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt; + bbr->inflight_hi += delta * cstat->max_tx_udp_payload_size; + } + + if (bbr->round_start) { + bbr_raise_inflight_hi_slope(bbr, cstat); } } -static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_target_cwnd(cc, cstat); - bbr_modulate_cwnd_for_recovery(cc, cstat, ack); - - if (!cc->packet_conservation) { - if (cc->filled_pipe) { - cstat->cwnd = - ngtcp2_min(cstat->cwnd + ack->bytes_delivered, cc->target_cwnd); - } else if (cstat->cwnd < cc->target_cwnd || - cc->rst->delivered < cc->initial_cwnd) { - cstat->cwnd += ack->bytes_delivered; +static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING && + bbr->round_start) { + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK; + } + + if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING && + bbr->round_start) { + if (bbr_is_in_probe_bw_state(bbr) && !bbr->rst->rs.is_app_limited) { + bbr_advance_max_bw_filter(bbr); } + } - cstat->cwnd = - ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); + if (!bbr_check_inflight_too_high(bbr, cstat, ts)) { + /* bbr->bw_hi never be updated */ + if (bbr->inflight_hi == UINT64_MAX /* || bbr->bw_hi == UINT64_MAX */) { + return; + } + + if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) { + bbr->inflight_hi = bbr->rst->rs.tx_in_flight; + } + + if (cstat->delivery_rate_sec > bbr->bw_hi) { + bbr->bw_hi = cstat->delivery_rate_sec; + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { + bbr_probe_inflight_hi_upward(bbr, cstat, ack); + } + } +} + +static int bbr_check_time_to_probe_bw(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) || + bbr_is_reno_coexistence_probe_time(bbr, cstat)) { + bbr_start_probe_bw_refill(bbr); + + return 1; } - bbr_modulate_cwnd_for_probe_rtt(cc, cstat); + return 0; } -static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts) { - cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN; - cc->prior_cwnd = 0; - cc->target_cwnd = 0; - cc->btl_bw = 0; - cc->rt_prop = UINT64_MAX; - cc->rtprop_stamp = initial_ts; - cc->cycle_stamp = UINT64_MAX; - cc->probe_rtt_done_stamp = UINT64_MAX; - cc->cycle_index = 0; - cc->rtprop_expired = 0; - cc->idle_restart = 0; - cc->packet_conservation = 0; - cc->probe_rtt_round_done = 0; +static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) { + uint8_t rand; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->congestion_recovery_next_round_delivered = 0; - cc->in_loss_recovery = 0; + bbr->rand(&rand, 1, &bbr->rand_ctx); - cstat->send_quantum = cstat->max_udp_payload_size * 10; + bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256); - ngtcp2_window_filter_init(&cc->btl_bw_filter, NGTCP2_BBR_BTL_BW_FILTERLEN); + bbr->rand(&rand, 1, &bbr->rand_ctx); - bbr_init_round_counting(cc); - bbr_init_full_pipe(cc); - bbr_init_pacing_rate(cc, cstat); - bbr_enter_startup(cc); + bbr->bw_probe_wait = + 2 * NGTCP2_SECONDS + (ngtcp2_tstamp)(NGTCP2_SECONDS * rand / 255); } -static void bbr_enter_startup(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_STARTUP; - cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN; - cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN; +static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t reno_rounds = + bbr_target_inflight(bbr, cstat) / cstat->max_tx_udp_payload_size; + + return bbr->rounds_since_bw_probe >= ngtcp2_min(reno_rounds, 63); } -static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc) { - cc->filled_pipe = 0; - cc->full_bw = 0; - cc->full_bw_count = 0; +static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t bdp = bbr_inflight(bbr, cstat, bbr->bw, 100); + + return ngtcp2_min(bdp, cstat->cwnd); } -static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc) { - if (cc->filled_pipe || !cc->round_start || cc->rst->rs.is_app_limited) { - /* no need to check for a full pipe now. */ - return; +static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (is_inflight_too_high(&bbr->rst->rs)) { + if (bbr->bw_probe_samples) { + bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts); + } + + return 1; } - /* cc->btl_bw still growing? */ - if (cc->btl_bw * 100 >= cc->full_bw * 125) { - /* record new baseline level */ - cc->full_bw = cc->btl_bw; - cc->full_bw_count = 0; + return 0; +} + +static int is_inflight_too_high(const ngtcp2_rs *rs) { + return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM > + rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER; +} + +static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_rs *rs, + ngtcp2_tstamp ts) { + bbr->bw_probe_samples = 0; + + if (!rs->is_app_limited) { + bbr->inflight_hi = ngtcp2_max( + rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * + NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { + bbr_start_probe_bw_down(bbr, ts); + } +} + +static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + ngtcp2_rs rs = {0}; + + if (!bbr->bw_probe_samples) { return; } - /* another round w/o much growth */ - ++cc->full_bw_count; - if (cc->full_bw_count >= 3) { - cc->filled_pipe = 1; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr filled pipe, btl_bw=%" PRIu64, cc->btl_bw); + + rs.tx_in_flight = pkt->tx_in_flight; + /* bbr->rst->lost is not incremented for pkt yet */ + rs.lost = bbr->rst->lost + pkt->pktlen - pkt->lost; + rs.is_app_limited = pkt->is_app_limited; + + if (is_inflight_too_high(&rs)) { + rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt); + + bbr_handle_inflight_too_high(bbr, cstat, &rs, ts); } } -static void bbr_enter_drain(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_DRAIN; - /* pace slowly */ - cc->pacing_gain = 1.0 / NGTCP2_BBR_HIGH_GAIN; - /* maintain cwnd */ - cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN; +static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_rs *rs, + const ngtcp2_cc_pkt *pkt) { + uint64_t inflight_prev, lost_prev, lost_prefix; + (void)bbr; + + assert(rs->tx_in_flight >= pkt->pktlen); + + inflight_prev = rs->tx_in_flight - pkt->pktlen; + + assert(rs->lost >= pkt->pktlen); + + lost_prev = rs->lost - pkt->pktlen; + + if (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER < + lost_prev * NGTCP2_BBR_LOSS_THRESH_DENOM) { + return inflight_prev; + } + + lost_prefix = (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER - + lost_prev * NGTCP2_BBR_LOSS_THRESH_DENOM) / + (NGTCP2_BBR_LOSS_THRESH_DENOM - NGTCP2_BBR_LOSS_THRESH_NUMER); + + return inflight_prev + lost_prefix; } -static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cc->state == NGTCP2_BBR_STATE_STARTUP && cc->filled_pipe) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit Startup and enter Drain"); +static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + int min_rtt_expired; + + bbr->probe_rtt_expired = + ts > bbr->probe_rtt_min_stamp + NGTCP2_BBR_PROBE_RTT_INTERVAL; - bbr_enter_drain(cc); + if (ack->rtt != UINT64_MAX && + (ack->rtt < bbr->probe_rtt_min_delay || bbr->probe_rtt_expired)) { + bbr->probe_rtt_min_delay = ack->rtt; + bbr->probe_rtt_min_stamp = ts; } - if (cc->state == NGTCP2_BBR_STATE_DRAIN && - cstat->bytes_in_flight <= bbr_inflight(cc, cstat, 1.0)) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit Drain and enter ProbeBW"); + min_rtt_expired = ts > bbr->min_rtt_stamp + NGTCP2_BBR_MIN_RTT_FILTERLEN; - /* we estimate queue is drained */ - bbr_enter_probe_bw(cc, ts); + if (bbr->probe_rtt_min_delay < bbr->min_rtt || min_rtt_expired) { + bbr->min_rtt = bbr->probe_rtt_min_delay; + bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; + + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr update min_rtt=%" PRIu64, bbr->min_rtt); } } -static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - uint8_t rand; +static void bbr_check_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->state != NGTCP2_BBR_STATE_PROBE_RTT && bbr->probe_rtt_expired && + !bbr->idle_restart) { + bbr_enter_probe_rtt(bbr); + bbr_save_cwnd(bbr, cstat); + + bbr->probe_rtt_done_stamp = UINT64_MAX; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING; - cc->state = NGTCP2_BBR_STATE_PROBE_BW; - cc->pacing_gain = 1; - cc->cwnd_gain = 2; + bbr_start_round(bbr); + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + bbr_handle_probe_rtt(bbr, cstat, ts); + } - assert(cc->rand); + if (bbr->rst->rs.delivered) { + bbr->idle_restart = 0; + } +} - cc->rand(&rand, 1, &cc->rand_ctx); +static void bbr_enter_probe_rtt(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter ProbeRTT"); - cc->cycle_index = NGTCP2_BBR_GAIN_CYCLELEN - 1 - (size_t)(rand * 7 / 256); - bbr_advance_cycle_phase(cc, ts); + bbr->state = NGTCP2_BBR_STATE_PROBE_RTT; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H; } -static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - if (cc->state == NGTCP2_BBR_STATE_PROBE_BW && - bbr_is_next_cycle_phase(cc, cstat, ack, ts)) { - bbr_advance_cycle_phase(cc, ts); +static void bbr_handle_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + bbr_mark_connection_app_limited(bbr, cstat); + + if (bbr->probe_rtt_done_stamp == UINT64_MAX && + cstat->bytes_in_flight <= bbr_probe_rtt_cwnd(bbr, cstat)) { + bbr->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; + bbr->probe_rtt_round_done = 0; + + bbr_start_round(bbr); + + return; + } + + if (bbr->probe_rtt_done_stamp != UINT64_MAX) { + if (bbr->round_start) { + bbr->probe_rtt_round_done = 1; + } + + if (bbr->probe_rtt_round_done) { + bbr_check_probe_rtt_done(bbr, cstat, ts); + } } } -static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - cc->cycle_stamp = ts; - cc->cycle_index = (cc->cycle_index + 1) & (NGTCP2_BBR_GAIN_CYCLELEN - 1); - cc->pacing_gain = pacing_gain_cycle[cc->cycle_index]; +static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->probe_rtt_done_stamp != UINT64_MAX && + ts > bbr->probe_rtt_done_stamp) { + bbr->probe_rtt_min_stamp = ts; + bbr_restore_cwnd(bbr, cstat); + bbr_exit_probe_rtt(bbr, ts); + } } -static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - int is_full_length = (ts - cc->cycle_stamp) > cc->rt_prop; +static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight; - if (cc->pacing_gain > 1) { - return is_full_length && (ack->bytes_lost > 0 || - ack->prior_bytes_in_flight >= - bbr_inflight(cc, cstat, cc->pacing_gain)); + if (app_limited) { + bbr->rst->app_limited = app_limited; + } else { + bbr->rst->app_limited = cstat->max_tx_udp_payload_size; } +} - if (cc->pacing_gain < 1) { - return is_full_length || - ack->prior_bytes_in_flight <= bbr_inflight(cc, cstat, 1); - } +static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + bbr_reset_lower_bounds(bbr); - return is_full_length; + if (bbr->filled_pipe) { + bbr_start_probe_bw_down(bbr, ts); + bbr_start_probe_bw_cruise(bbr); + } else { + bbr_enter_startup(bbr); + } } -static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat) { - if (cstat->bytes_in_flight == 0 && cc->rst->app_limited) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr restart from idle"); +static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (cstat->bytes_in_flight == 0 && bbr->rst->app_limited) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr restart from idle"); - cc->idle_restart = 1; + bbr->idle_restart = 1; + bbr->extra_acked_interval_start = ts; - if (cc->state == NGTCP2_BBR_STATE_PROBE_BW) { - bbr_set_pacing_rate_with_gain(cc, cstat, 1); + if (bbr_is_in_probe_bw_state(bbr)) { + bbr_set_pacing_rate_with_gain(bbr, cstat, 100); + } else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + bbr_check_probe_rtt_done(bbr, cstat, ts); } } } -static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cc->state != NGTCP2_BBR_STATE_PROBE_RTT && cc->rtprop_expired && - !cc->idle_restart) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr enter ProbeRTT"); +static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t bw, + uint64_t gain_h) { + uint64_t bdp; - bbr_enter_probe_rtt(cc); - bbr_save_cwnd(cc, cstat); - cc->probe_rtt_done_stamp = UINT64_MAX; + if (bbr->min_rtt == UINT64_MAX) { + return bbr->initial_cwnd; } - if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) { - bbr_handle_probe_rtt(cc, cstat, ts); + bdp = bw * bbr->min_rtt / NGTCP2_SECONDS; + + return (uint64_t)(bdp * gain_h / 100); +} + +static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { + return max_udp_payload_size * 4; +} + +static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t inflight) { + bbr_update_offload_budget(bbr, cstat); + + inflight = ngtcp2_max(inflight, bbr->offload_budget); + inflight = + ngtcp2_max(inflight, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { + inflight += 2 * cstat->max_tx_udp_payload_size; } - cc->idle_restart = 0; + return inflight; } -static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_PROBE_RTT; - cc->pacing_gain = 1; - cc->cwnd_gain = 1; +static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + uint64_t bw, uint64_t gain_h) { + uint64_t inflight = bbr_bdp_multiple(bbr, bw, gain_h); + + return bbr_quantization_budget(bbr, cstat, inflight); } -static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - uint64_t app_limited = cc->rst->delivered + cstat->bytes_in_flight; +static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t inflight; + + /* Not documented */ + /* bbr_update_aggregation_budget(bbr); */ + + inflight = + bbr_bdp_multiple(bbr, bbr->bw, bbr->cwnd_gain_h) + bbr->extra_acked; + bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight); +} - /* Ignore low rate samples during NGTCP2_BBR_STATE_PROBE_RTT. */ - cc->rst->app_limited = app_limited ? app_limited : 1; +static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + bbr->offload_budget = 3 * cstat->send_quantum; +} - if (cc->probe_rtt_done_stamp == UINT64_MAX && - cstat->bytes_in_flight <= min_pipe_cwnd(cstat->max_udp_payload_size)) { - cc->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; - cc->probe_rtt_round_done = 0; - cc->next_round_delivered = cc->rst->delivered; +static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr) { + ++bbr->cycle_count; +} +static void bbr_modulate_cwnd_for_recovery(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + if (ack->bytes_lost > 0) { + if (cstat->cwnd > ack->bytes_lost) { + cstat->cwnd -= ack->bytes_lost; + cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_tx_udp_payload_size); + } else { + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; + } + } + + if (bbr->packet_conservation) { + cstat->cwnd = + ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); + } +} + +static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR_STATE_PROBE_RTT) { + bbr->prior_cwnd = cstat->cwnd; return; } - if (cc->probe_rtt_done_stamp != UINT64_MAX) { - if (cc->round_start) { - cc->probe_rtt_round_done = 1; + bbr->prior_cwnd = ngtcp2_max(bbr->prior_cwnd, cstat->cwnd); +} + +static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + cstat->cwnd = ngtcp2_max(cstat->cwnd, bbr->prior_cwnd); +} + +static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t probe_rtt_cwnd = + bbr_bdp_multiple(bbr, bbr->bw, NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H); + uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + return ngtcp2_max(probe_rtt_cwnd, mpcwnd); +} + +static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t probe_rtt_cwnd; + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat); + + cstat->cwnd = ngtcp2_min(cstat->cwnd, probe_rtt_cwnd); + } +} + +static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + uint64_t mpcwnd; + + bbr_update_max_inflight(bbr, cstat); + bbr_modulate_cwnd_for_recovery(bbr, cstat, ack); + + if (!bbr->packet_conservation) { + if (bbr->filled_pipe) { + cstat->cwnd += ack->bytes_delivered; + cstat->cwnd = ngtcp2_min(cstat->cwnd, bbr->max_inflight); + } else if (cstat->cwnd < bbr->max_inflight || + bbr->rst->delivered < bbr->initial_cwnd) { + cstat->cwnd += ack->bytes_delivered; + } + + mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + cstat->cwnd = ngtcp2_max(cstat->cwnd, mpcwnd); + } + + bbr_bound_cwnd_for_probe_rtt(bbr, cstat); + bbr_bound_cwnd_for_model(bbr, cstat); +} + +static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t cap = UINT64_MAX; + uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + if (bbr_is_in_probe_bw_state(bbr) && + bbr->state != NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { + cap = bbr->inflight_hi; + } else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT || + bbr->state == NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { + cap = bbr_inflight_with_headroom(bbr, cstat); + } + + cap = ngtcp2_min(cap, bbr->inflight_lo); + cap = ngtcp2_max(cap, mpcwnd); + + cstat->cwnd = ngtcp2_min(cstat->cwnd, cap); +} + +static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + size_t floor, send_quantum; + (void)bbr; + + if (cstat->pacing_interval > (NGTCP2_SECONDS * 8 * 10 / 12) >> 20) { + floor = cstat->max_tx_udp_payload_size; + } else { + floor = 2 * cstat->max_tx_udp_payload_size; + } + + if (cstat->pacing_interval) { + send_quantum = (size_t)(NGTCP2_MILLISECONDS / cstat->pacing_interval); + send_quantum = ngtcp2_min(send_quantum, 64 * 1024); + } else { + send_quantum = 64 * 1024; + } + + cstat->send_quantum = ngtcp2_max(send_quantum, floor); +} + +static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_time) { + return cstat->congestion_recovery_start_ts != UINT64_MAX && + sent_time <= cstat->congestion_recovery_start_ts; +} + +static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + if (bbr->in_loss_recovery) { + if (ts - cstat->congestion_recovery_start_ts >= cstat->smoothed_rtt) { + bbr->packet_conservation = 0; } - if (cc->probe_rtt_round_done && ts > cc->probe_rtt_done_stamp) { - cc->rtprop_stamp = ts; - bbr_restore_cwnd(cc, cstat); - bbr_exit_probe_rtt(cc, ts); + if (ack->largest_pkt_sent_ts != UINT64_MAX && + !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) { + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + bbr_restore_cwnd(bbr, cstat); } + + return; + } + + if (bbr->congestion_recovery_start_ts != UINT64_MAX) { + bbr->in_loss_recovery = 1; + bbr_save_cwnd(bbr, cstat); + cstat->cwnd = + cstat->bytes_in_flight + + ngtcp2_max(ack->bytes_delivered, cstat->max_tx_udp_payload_size); + + cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts; + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->packet_conservation = 1; + bbr->congestion_recovery_next_round_delivered = bbr->rst->delivered; + bbr->prior_inflight_hi = bbr->inflight_hi; + bbr->prior_inflight_lo = bbr->inflight_lo; + bbr->prior_bw_lo = bbr->bw_lo; } } -static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - if (cc->filled_pipe) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit ProbeRTT and enter ProbeBW"); +static void bbr_cc_on_pkt_lost(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_update_on_loss(bbr, cstat, pkt, ts); +} - bbr_enter_probe_bw(cc, ts); +static void bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + if (bbr->in_loss_recovery || + bbr->congestion_recovery_start_ts != UINT64_MAX || + in_congestion_recovery(cstat, sent_ts)) { return; } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit ProbeRTT and enter Startup"); + bbr->congestion_recovery_start_ts = ts; +} + +static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + (void)ts; + + bbr->congestion_recovery_start_ts = UINT64_MAX; + cstat->congestion_recovery_start_ts = UINT64_MAX; + + if (bbr->in_loss_recovery) { + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + bbr_restore_cwnd(bbr, cstat); + bbr->full_bw_count = 0; + bbr->loss_in_round = 0; + bbr->inflight_lo = ngtcp2_max(bbr->inflight_lo, bbr->prior_inflight_lo); + bbr->inflight_hi = ngtcp2_max(bbr->inflight_hi, bbr->prior_inflight_hi); + bbr->bw_lo = ngtcp2_max(bbr->bw_lo, bbr->prior_bw_lo); + } +} + +static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + (void)ts; + + cstat->congestion_recovery_start_ts = UINT64_MAX; + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + + bbr_save_cwnd(bbr, cstat); + cstat->cwnd = cstat->bytes_in_flight + cstat->max_tx_udp_payload_size; + cstat->cwnd = + ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); +} + +static void bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_handle_recovery(bbr, cstat, ack, ts); + bbr_update_on_ack(bbr, cstat, ack, ts); +} + +static void bbr_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_on_transmit(bbr, cstat, pkt->sent_ts); +} + +static void bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_on_init(bbr, cstat, ts); +} - bbr_enter_startup(cc); +void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log, + ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, + ngtcp2_tstamp initial_ts, ngtcp2_rand rand, + const ngtcp2_rand_ctx *rand_ctx) { + memset(bbr, 0, sizeof(*bbr)); + + bbr->cc.log = log; + bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost; + bbr->cc.congestion_event = bbr_cc_congestion_event; + bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion; + bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion; + bbr->cc.on_ack_recv = bbr_cc_on_ack_recv; + bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent; + bbr->cc.reset = bbr_cc_reset; + + bbr->rst = rst; + bbr->rand = rand; + bbr->rand_ctx = *rand_ctx; + bbr->initial_cwnd = cstat->cwnd; + + bbr_on_init(bbr, cstat, initial_ts); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h index 7311f051e187bc..0017be35010e66 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h @@ -39,118 +39,108 @@ typedef struct ngtcp2_rst ngtcp2_rst; typedef enum ngtcp2_bbr_state { NGTCP2_BBR_STATE_STARTUP, NGTCP2_BBR_STATE_DRAIN, - NGTCP2_BBR_STATE_PROBE_BW, + NGTCP2_BBR_STATE_PROBE_BW_DOWN, + NGTCP2_BBR_STATE_PROBE_BW_CRUISE, + NGTCP2_BBR_STATE_PROBE_BW_REFILL, + NGTCP2_BBR_STATE_PROBE_BW_UP, NGTCP2_BBR_STATE_PROBE_RTT, } ngtcp2_bbr_state; +typedef enum ngtcp2_bbr_ack_phase { + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING, + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING, + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK, + NGTCP2_BBR_ACK_PHASE_ACKS_REFILLING, +} ngtcp2_bbr_ack_phase; + /* - * ngtcp2_bbr_cc is BBR congestion controller, described in - * https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00 + * ngtcp2_cc_bbr is BBR v2 congestion controller, described in + * https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control-01 */ -typedef struct ngtcp2_bbr_cc { - ngtcp2_cc_base ccb; +typedef struct ngtcp2_cc_bbr { + ngtcp2_cc cc; - /* The max filter used to estimate BBR.BtlBw. */ - ngtcp2_window_filter btl_bw_filter; uint64_t initial_cwnd; ngtcp2_rst *rst; ngtcp2_rand rand; ngtcp2_rand_ctx rand_ctx; - /* BBR variables */ + /* max_bw_filter for tracking the maximum recent delivery rate + samples for estimating max_bw. */ + ngtcp2_window_filter max_bw_filter; - /* The dynamic gain factor used to scale BBR.BtlBw to - produce BBR.pacing_rate. */ - double pacing_gain; - /* The dynamic gain factor used to scale the estimated BDP to produce a - congestion window (cwnd). */ - double cwnd_gain; - uint64_t full_bw; - /* packet.delivered value denoting the end of a packet-timed round trip. */ - uint64_t next_round_delivered; - /* Count of packet-timed round trips. */ - uint64_t round_count; - uint64_t prior_cwnd; - /* target_cwnd is the upper bound on the volume of data BBR - allows in flight. */ - uint64_t target_cwnd; - /* BBR's estimated bottleneck bandwidth available to the - transport flow, estimated from the maximum delivery rate sample in a - sliding window. */ - uint64_t btl_bw; - /* BBR's estimated two-way round-trip propagation delay of - the path, estimated from the windowed minimum recent round-trip delay - sample. */ - ngtcp2_duration rt_prop; - /* The wall clock time at which the current BBR.RTProp - sample was obtained. */ - ngtcp2_tstamp rtprop_stamp; - ngtcp2_tstamp cycle_stamp; + ngtcp2_window_filter extra_acked_filter; + + ngtcp2_duration min_rtt; + ngtcp2_tstamp min_rtt_stamp; ngtcp2_tstamp probe_rtt_done_stamp; - /* congestion_recovery_start_ts is the time when congestion recovery - period started.*/ - ngtcp2_tstamp congestion_recovery_start_ts; - uint64_t congestion_recovery_next_round_delivered; - size_t full_bw_count; - size_t cycle_index; - ngtcp2_bbr_state state; - /* A boolean that records whether BBR estimates that it has ever fully - utilized its available bandwidth ("filled the pipe"). */ - int filled_pipe; - /* A boolean that BBR sets to true once per packet-timed round trip, - on ACKs that advance BBR.round_count. */ - int round_start; - int rtprop_expired; - int idle_restart; - int packet_conservation; int probe_rtt_round_done; - /* in_loss_recovery becomes nonzero when BBR enters loss recovery - period. */ - int in_loss_recovery; -} ngtcp2_bbr_cc; - -int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem); - -void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *bbr_cc, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log); - -void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc); - -void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + uint64_t prior_cwnd; + int idle_restart; + ngtcp2_tstamp extra_acked_interval_start; + uint64_t extra_acked_delivered; -void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts); + /* Congestion signals */ + int loss_in_round; + uint64_t bw_latest; + uint64_t inflight_latest; -void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + /* Lower bounds */ + uint64_t bw_lo; + uint64_t inflight_lo; -void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *cc, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + /* Round counting */ + uint64_t next_round_delivered; + int round_start; + uint64_t round_count; -void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); + /* Full pipe */ + int filled_pipe; + uint64_t full_bw; + size_t full_bw_count; -void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt); + /* Pacing rate */ + uint64_t pacing_gain_h; -void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + ngtcp2_bbr_state state; + uint64_t cwnd_gain_h; + + int loss_round_start; + uint64_t loss_round_delivered; + uint64_t rounds_since_bw_probe; + uint64_t max_bw; + uint64_t bw; + uint64_t cycle_count; + uint64_t extra_acked; + uint64_t bytes_lost_in_round; + size_t loss_events_in_round; + uint64_t offload_budget; + uint64_t probe_up_cnt; + ngtcp2_tstamp cycle_stamp; + ngtcp2_bbr_ack_phase ack_phase; + ngtcp2_duration bw_probe_wait; + int bw_probe_samples; + size_t bw_probe_up_rounds; + uint64_t bw_probe_up_acks; + uint64_t inflight_hi; + uint64_t bw_hi; + int probe_rtt_expired; + ngtcp2_duration probe_rtt_min_delay; + ngtcp2_tstamp probe_rtt_min_stamp; + int in_loss_recovery; + int packet_conservation; + uint64_t max_inflight; + ngtcp2_tstamp congestion_recovery_start_ts; + uint64_t congestion_recovery_next_round_delivered; -void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + uint64_t prior_inflight_lo; + uint64_t prior_inflight_hi; + uint64_t prior_bw_lo; +} ngtcp2_cc_bbr; -void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts); +void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log, + ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, + ngtcp2_tstamp initial_ts, ngtcp2_rand rand, + const ngtcp2_rand_ctx *rand_ctx); #endif /* NGTCP2_BBR_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c deleted file mode 100644 index 585ea11e8e29a5..00000000000000 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c +++ /dev/null @@ -1,1486 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2021 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "ngtcp2_bbr2.h" - -#include - -#include "ngtcp2_log.h" -#include "ngtcp2_macro.h" -#include "ngtcp2_mem.h" -#include "ngtcp2_rcvry.h" -#include "ngtcp2_rst.h" - -#define NGTCP2_BBR_MAX_BW_FILTERLEN 2 - -#define NGTCP2_BBR_EXTRA_ACKED_FILTERLEN 10 - -#define NGTCP2_BBR_STARTUP_PACING_GAIN ((double)2.77) - -#define NGTCP2_BBR_STARTUP_CWND_GAIN 2 - -#define NGTCP2_BBR_PROBE_RTT_CWND_GAIN ((double)0.5) - -#define NGTCP2_BBR_BETA_NUMER 7 -#define NGTCP2_BBR_BETA_DENOM 10 - -#define NGTCP2_BBR_LOSS_THRESH_NUMER 2 -#define NGTCP2_BBR_LOSS_THRESH_DENOM 100 - -#define NGTCP2_BBR_HEADROOM_NUMER 15 -#define NGTCP2_BBR_HEADROOM_DENOM 100 - -#define NGTCP2_BBR_PROBE_RTT_INTERVAL (5 * NGTCP2_SECONDS) -#define NGTCP2_BBR_MIN_RTT_FILTERLEN (10 * NGTCP2_SECONDS) - -#define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS) - -#define NGTCP2_BBR_PACING_MARGIN_PERCENT 1 - -static void bbr_on_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts); - -static void bbr_on_transmit(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_reset_congestion_signals(ngtcp2_bbr2_cc *bbr); - -static void bbr_reset_lower_bounds(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_round_counting(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_full_pipe(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - double pacing_gain); - -static void bbr_set_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_enter_startup(ngtcp2_bbr2_cc *bbr); - -static void bbr_check_startup_done(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack); - -static void bbr_update_on_ack(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); - -static void bbr_update_model_and_state(ngtcp2_bbr2_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_update_control_parameters(ngtcp2_bbr2_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_update_on_loss(ngtcp2_bbr2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); - -static void bbr_update_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_advance_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_update_congestion_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_init_lower_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_loss_lower_bounds(ngtcp2_bbr2_cc *bbr); - -static void bbr_bound_bw_for_model(ngtcp2_bbr2_cc *bbr); - -static void bbr_update_max_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_update_round(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack); - -static void bbr_start_round(ngtcp2_bbr2_cc *bbr); - -static int bbr_is_in_probe_bw_state(ngtcp2_bbr2_cc *bbr); - -static void bbr_update_ack_aggregation(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_enter_drain(ngtcp2_bbr2_cc *bbr); - -static void bbr_check_drain(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_enter_probe_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_start_probe_bw_down(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_start_probe_bw_cruise(ngtcp2_bbr2_cc *bbr); - -static void bbr_start_probe_bw_refill(ngtcp2_bbr2_cc *bbr); - -static void bbr_start_probe_bw_up(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_update_probe_bw_cycle_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static int bbr_check_time_to_cruise(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); - -static int bbr_has_elapsed_in_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_duration interval, ngtcp2_tstamp ts); - -static uint64_t bbr_inflight_with_headroom(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_raise_inflight_hi_slope(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_probe_inflight_hi_upward(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_adapt_upper_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); - -static int bbr_check_time_to_probe_bw(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_pick_probe_wait(ngtcp2_bbr2_cc *bbr); - -static int bbr_is_reno_coexistence_probe_time(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static uint64_t bbr_target_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static int bbr_check_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static int is_inflight_too_high(const ngtcp2_rs *rs); - -static void bbr_handle_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, ngtcp2_tstamp ts); - -static void bbr_handle_lost_packet(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); - -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_bbr2_cc *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt); - -static void bbr_update_min_rtt(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_check_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_enter_probe_rtt(ngtcp2_bbr2_cc *bbr); - -static void bbr_handle_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_check_probe_rtt_done(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); - -static void bbr_mark_connection_app_limited(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_exit_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_handle_restart_from_idle(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static uint64_t bbr_bdp_multiple(ngtcp2_bbr2_cc *bbr, uint64_t bw, double gain); - -static uint64_t bbr_quantization_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - uint64_t inflight); - -static uint64_t bbr_inflight(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - uint64_t bw, double gain); - -static void bbr_update_max_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_update_offload_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size); - -static void bbr_advance_max_bw_filter(ngtcp2_bbr2_cc *bbr); - -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_save_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_restore_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static uint64_t bbr_probe_rtt_cwnd(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_set_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_bound_cwnd_for_model(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_set_send_quantum(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time); - -static void bbr_handle_recovery(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_on_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts) { - ngtcp2_window_filter_init(&bbr->max_bw_filter, NGTCP2_BBR_MAX_BW_FILTERLEN); - ngtcp2_window_filter_init(&bbr->extra_acked_filter, - NGTCP2_BBR_EXTRA_ACKED_FILTERLEN); - - bbr->min_rtt = UINT64_MAX; - bbr->min_rtt_stamp = initial_ts; - /* remark: Use UINT64_MAX instead of 0 for consistency. */ - bbr->probe_rtt_done_stamp = UINT64_MAX; - bbr->probe_rtt_round_done = 0; - bbr->prior_cwnd = 0; - bbr->idle_restart = 0; - bbr->extra_acked_interval_start = initial_ts; - bbr->extra_acked_delivered = 0; - - bbr_reset_congestion_signals(bbr); - bbr_reset_lower_bounds(bbr); - bbr_init_round_counting(bbr); - bbr_init_full_pipe(bbr); - bbr_init_pacing_rate(bbr, cstat); - bbr_enter_startup(bbr); - - cstat->send_quantum = cstat->max_udp_payload_size * 10; - - /* Missing in documentation */ - bbr->loss_round_start = 0; - bbr->loss_round_delivered = UINT64_MAX; - - bbr->rounds_since_bw_probe = 0; - - bbr->max_bw = 0; - bbr->bw = 0; - - bbr->cycle_count = 0; - - bbr->extra_acked = 0; - - bbr->bytes_lost_in_round = 0; - bbr->loss_events_in_round = 0; - - bbr->offload_budget = 0; - - bbr->probe_up_cnt = UINT64_MAX; - bbr->cycle_stamp = UINT64_MAX; - bbr->ack_phase = 0; - bbr->bw_probe_wait = 0; - bbr->bw_probe_samples = 0; - bbr->bw_probe_up_rounds = 0; - bbr->bw_probe_up_acks = 0; - - bbr->inflight_hi = UINT64_MAX; - bbr->bw_hi = UINT64_MAX; - - bbr->probe_rtt_expired = 0; - bbr->probe_rtt_min_delay = UINT64_MAX; - bbr->probe_rtt_min_stamp = initial_ts; - - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - - bbr->max_inflight = 0; - - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->congestion_recovery_next_round_delivered = 0; - - bbr->prior_inflight_lo = 0; - bbr->prior_inflight_hi = 0; - bbr->prior_bw_lo = 0; -} - -static void bbr_reset_congestion_signals(ngtcp2_bbr2_cc *bbr) { - bbr->loss_in_round = 0; - bbr->bw_latest = 0; - bbr->inflight_latest = 0; -} - -static void bbr_reset_lower_bounds(ngtcp2_bbr2_cc *bbr) { - bbr->bw_lo = UINT64_MAX; - bbr->inflight_lo = UINT64_MAX; -} - -static void bbr_init_round_counting(ngtcp2_bbr2_cc *bbr) { - bbr->next_round_delivered = 0; - bbr->round_start = 0; - bbr->round_count = 0; -} - -static void bbr_init_full_pipe(ngtcp2_bbr2_cc *bbr) { - bbr->filled_pipe = 0; - bbr->full_bw = 0; - bbr->full_bw_count = 0; -} - -static void bbr_check_startup_full_bandwidth(ngtcp2_bbr2_cc *bbr) { - if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { - return; - } - - if (bbr->max_bw * 100 >= bbr->full_bw * 125) { - bbr->full_bw = bbr->max_bw; - bbr->full_bw_count = 0; - } - - ++bbr->full_bw_count; - - if (bbr->full_bw_count >= 3) { - bbr->filled_pipe = 1; - - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 filled pipe, full_bw=%" PRIu64, bbr->full_bw); - } -} - -static void bbr_check_startup_high_loss(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack) { - if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { - return; - } - - if (bbr->loss_events_in_round <= 3) { - return; - } - - /* loss_thresh = 2% */ - if (bbr->bytes_lost_in_round * 100 <= ack->prior_bytes_in_flight * 2) { - return; - } - - bbr->filled_pipe = 1; -} - -static void bbr_init_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - double nominal_bandwidth = (double)bbr->initial_cwnd; - - cstat->pacing_rate = NGTCP2_BBR_STARTUP_PACING_GAIN * nominal_bandwidth / - (double)NGTCP2_MILLISECONDS; -} - -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - double pacing_gain) { - double rate = pacing_gain * (double)bbr->bw * - (100 - NGTCP2_BBR_PACING_MARGIN_PERCENT) / 100 / NGTCP2_SECONDS; - - if (bbr->filled_pipe || rate > cstat->pacing_rate) { - cstat->pacing_rate = rate; - } -} - -static void bbr_set_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain); -} - -static void bbr_enter_startup(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter Startup"); - - bbr->state = NGTCP2_BBR2_STATE_STARTUP; - bbr->pacing_gain = NGTCP2_BBR_STARTUP_PACING_GAIN; - bbr->cwnd_gain = NGTCP2_BBR_STARTUP_CWND_GAIN; -} - -static void bbr_check_startup_done(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack) { - bbr_check_startup_full_bandwidth(bbr); - bbr_check_startup_high_loss(bbr, ack); - - if (bbr->state == NGTCP2_BBR2_STATE_STARTUP && bbr->filled_pipe) { - bbr_enter_drain(bbr); - } -} - -static void bbr_on_transmit(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - bbr_handle_restart_from_idle(bbr, cstat, ts); -} - -static void bbr_update_on_ack(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_model_and_state(bbr, cstat, ack, ts); - bbr_update_control_parameters(bbr, cstat, ack); -} - -static void bbr_update_model_and_state(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - bbr_update_latest_delivery_signals(bbr, cstat); - bbr_update_congestion_signals(bbr, cstat, ack); - bbr_update_ack_aggregation(bbr, cstat, ack, ts); - bbr_check_startup_done(bbr, ack); - bbr_check_drain(bbr, cstat, ts); - bbr_update_probe_bw_cycle_phase(bbr, cstat, ack, ts); - bbr_update_min_rtt(bbr, ack, ts); - bbr_check_probe_rtt(bbr, cstat, ts); - bbr_advance_latest_delivery_signals(bbr, cstat); - bbr_bound_bw_for_model(bbr); -} - -static void bbr_update_control_parameters(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_set_pacing_rate(bbr, cstat); - bbr_set_send_quantum(bbr, cstat); - bbr_set_cwnd(bbr, cstat, ack); -} - -static void bbr_update_on_loss(ngtcp2_bbr2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - bbr_handle_lost_packet(cc, cstat, pkt, ts); -} - -static void bbr_update_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - bbr->loss_round_start = 0; - bbr->bw_latest = ngtcp2_max(bbr->bw_latest, cstat->delivery_rate_sec); - bbr->inflight_latest = - ngtcp2_max(bbr->inflight_latest, bbr->rst->rs.delivered); - - if (bbr->rst->rs.prior_delivered >= bbr->loss_round_delivered) { - bbr->loss_round_delivered = bbr->rst->delivered; - bbr->loss_round_start = 1; - } -} - -static void bbr_advance_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (bbr->loss_round_start) { - bbr->bw_latest = cstat->delivery_rate_sec; - bbr->inflight_latest = bbr->rst->rs.delivered; - } -} - -static void bbr_update_congestion_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_max_bw(bbr, cstat, ack); - - if (ack->bytes_lost) { - bbr->bytes_lost_in_round += ack->bytes_lost; - ++bbr->loss_events_in_round; - - if (!bbr->loss_in_round) { - bbr->loss_in_round = 1; - bbr->loss_round_delivered = bbr->rst->delivered; - } - } - - if (!bbr->loss_round_start) { - return; - } - - bbr_adapt_lower_bounds_from_congestion(bbr, cstat); - - bbr->loss_in_round = 0; -} - -static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (!bbr->filled_pipe || bbr_is_in_probe_bw_state(bbr)) { - return; - } - - if (bbr->loss_in_round) { - bbr_init_lower_bounds(bbr, cstat); - bbr_loss_lower_bounds(bbr); - } -} - -static void bbr_init_lower_bounds(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (bbr->bw_lo == UINT64_MAX) { - bbr->bw_lo = bbr->max_bw; - } - - if (bbr->inflight_lo == UINT64_MAX) { - bbr->inflight_lo = cstat->cwnd; - } -} - -static void bbr_loss_lower_bounds(ngtcp2_bbr2_cc *bbr) { - bbr->bw_lo = ngtcp2_max(bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / - NGTCP2_BBR_BETA_DENOM); - bbr->inflight_lo = ngtcp2_max(bbr->inflight_latest, - bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / - NGTCP2_BBR_BETA_DENOM); -} - -static void bbr_bound_bw_for_model(ngtcp2_bbr2_cc *bbr) { - bbr->bw = ngtcp2_min(bbr->max_bw, bbr->bw_lo); - bbr->bw = ngtcp2_min(bbr->bw, bbr->bw_hi); -} - -static void bbr_update_max_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_round(bbr, ack); - bbr_handle_recovery(bbr, cstat, ack); - - if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) { - ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec, - bbr->cycle_count); - - bbr->max_bw = ngtcp2_window_filter_get_best(&bbr->max_bw_filter); - } -} - -static void bbr_update_round(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack) { - if (ack->pkt_delivered >= bbr->next_round_delivered) { - bbr_start_round(bbr); - - ++bbr->round_count; - ++bbr->rounds_since_bw_probe; - bbr->round_start = 1; - - bbr->bytes_lost_in_round = 0; - bbr->loss_events_in_round = 0; - - bbr->rst->is_cwnd_limited = 0; - - return; - } - - bbr->round_start = 0; -} - -static void bbr_start_round(ngtcp2_bbr2_cc *bbr) { - bbr->next_round_delivered = bbr->rst->delivered; -} - -static int bbr_is_in_probe_bw_state(ngtcp2_bbr2_cc *bbr) { - switch (bbr->state) { - case NGTCP2_BBR2_STATE_PROBE_BW_DOWN: - case NGTCP2_BBR2_STATE_PROBE_BW_CRUISE: - case NGTCP2_BBR2_STATE_PROBE_BW_REFILL: - case NGTCP2_BBR2_STATE_PROBE_BW_UP: - return 1; - default: - return 0; - } -} - -static void bbr_update_ack_aggregation(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - ngtcp2_duration interval = ts - bbr->extra_acked_interval_start; - uint64_t expected_delivered = bbr->bw * interval / NGTCP2_SECONDS; - uint64_t extra; - - if (bbr->extra_acked_delivered <= expected_delivered) { - bbr->extra_acked_delivered = 0; - bbr->extra_acked_interval_start = ts; - expected_delivered = 0; - } - - bbr->extra_acked_delivered += ack->bytes_delivered; - extra = bbr->extra_acked_delivered - expected_delivered; - extra = ngtcp2_min(extra, cstat->cwnd); - - ngtcp2_window_filter_update(&bbr->extra_acked_filter, extra, - bbr->round_count); - - bbr->extra_acked = ngtcp2_window_filter_get_best(&bbr->extra_acked_filter); -} - -static void bbr_enter_drain(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter Drain"); - - bbr->state = NGTCP2_BBR2_STATE_DRAIN; - bbr->pacing_gain = 1. / NGTCP2_BBR_STARTUP_CWND_GAIN; - bbr->cwnd_gain = NGTCP2_BBR_STARTUP_CWND_GAIN; -} - -static void bbr_check_drain(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->state == NGTCP2_BBR2_STATE_DRAIN && - cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->bw, 1.0)) { - bbr_enter_probe_bw(bbr, ts); - } -} - -static void bbr_enter_probe_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - bbr_start_probe_bw_down(bbr, ts); -} - -static void bbr_start_probe_bw_down(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_DOWN"); - - bbr_reset_congestion_signals(bbr); - - bbr->probe_up_cnt = UINT64_MAX; - - bbr_pick_probe_wait(bbr); - - bbr->cycle_stamp = ts; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING; - - bbr_start_round(bbr); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_DOWN; - bbr->pacing_gain = 0.9; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_cruise(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_CRUISE"); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_CRUISE; - bbr->pacing_gain = 1.0; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_refill(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_REFILL"); - - bbr_reset_lower_bounds(bbr); - - bbr->bw_probe_up_rounds = 0; - bbr->bw_probe_up_acks = 0; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_REFILLING; - - bbr_start_round(bbr); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_REFILL; - bbr->pacing_gain = 1.0; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_up(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 start ProbeBW_UP"); - - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING; - - bbr_start_round(bbr); - - bbr->cycle_stamp = ts; - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_UP; - bbr->pacing_gain = 1.25; - bbr->cwnd_gain = 2; - - bbr_raise_inflight_hi_slope(bbr, cstat); -} - -static void bbr_update_probe_bw_cycle_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - if (!bbr->filled_pipe) { - return; - } - - bbr_adapt_upper_bounds(bbr, cstat, ack, ts); - - if (!bbr_is_in_probe_bw_state(bbr)) { - return; - } - - switch (bbr->state) { - case NGTCP2_BBR2_STATE_PROBE_BW_DOWN: - if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { - return; - } - - if (bbr_check_time_to_cruise(bbr, cstat, ts)) { - bbr_start_probe_bw_cruise(bbr); - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_CRUISE: - if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { - return; - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_REFILL: - if (bbr->round_start) { - bbr->bw_probe_samples = 1; - bbr_start_probe_bw_up(bbr, cstat, ts); - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_UP: - if (bbr_has_elapsed_in_phase(bbr, bbr->min_rtt, ts) && - cstat->bytes_in_flight > bbr_inflight(bbr, cstat, bbr->max_bw, 1.25)) { - bbr_start_probe_bw_down(bbr, ts); - } - - break; - default: - break; - } -} - -static int bbr_check_time_to_cruise(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ts; - - if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) { - return 0; - } - - if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->max_bw, 1.0)) { - return 1; - } - - return 0; -} - -static int bbr_has_elapsed_in_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_duration interval, - ngtcp2_tstamp ts) { - return ts > bbr->cycle_stamp + interval; -} - -static uint64_t bbr_inflight_with_headroom(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t headroom; - uint64_t mpcwnd; - if (bbr->inflight_hi == UINT64_MAX) { - return UINT64_MAX; - } - - headroom = ngtcp2_max(cstat->max_udp_payload_size, - bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER / - NGTCP2_BBR_HEADROOM_DENOM); - mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - if (bbr->inflight_hi > headroom) { - return ngtcp2_max(bbr->inflight_hi - headroom, mpcwnd); - } - - return mpcwnd; -} - -static void bbr_raise_inflight_hi_slope(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t growth_this_round = cstat->max_udp_payload_size - << bbr->bw_probe_up_rounds; - - bbr->bw_probe_up_rounds = ngtcp2_min(bbr->bw_probe_up_rounds + 1, 30); - bbr->probe_up_cnt = ngtcp2_max(cstat->cwnd / growth_this_round, 1) * - cstat->max_udp_payload_size; -} - -static void bbr_probe_inflight_hi_upward(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - uint64_t delta; - - if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) { - return; - } - - bbr->bw_probe_up_acks += ack->bytes_delivered; - - if (bbr->bw_probe_up_acks >= bbr->probe_up_cnt) { - delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt; - bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt; - bbr->inflight_hi += delta * cstat->max_udp_payload_size; - } - - if (bbr->round_start) { - bbr_raise_inflight_hi_slope(bbr, cstat); - } -} - -static void bbr_adapt_upper_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - if (bbr->ack_phase == NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING && - bbr->round_start) { - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_FEEDBACK; - } - - if (bbr->ack_phase == NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING && - bbr->round_start) { - if (bbr_is_in_probe_bw_state(bbr) && !bbr->rst->rs.is_app_limited) { - bbr_advance_max_bw_filter(bbr); - } - } - - if (!bbr_check_inflight_too_high(bbr, cstat, ts)) { - /* bbr->bw_hi never be updated */ - if (bbr->inflight_hi == UINT64_MAX /* || bbr->bw_hi == UINT64_MAX */) { - return; - } - - if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) { - bbr->inflight_hi = bbr->rst->rs.tx_in_flight; - } - - if (cstat->delivery_rate_sec > bbr->bw_hi) { - bbr->bw_hi = cstat->delivery_rate_sec; - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - bbr_probe_inflight_hi_upward(bbr, cstat, ack); - } - } -} - -static int bbr_check_time_to_probe_bw(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) || - bbr_is_reno_coexistence_probe_time(bbr, cstat)) { - bbr_start_probe_bw_refill(bbr); - - return 1; - } - - return 0; -} - -static void bbr_pick_probe_wait(ngtcp2_bbr2_cc *bbr) { - uint8_t rand; - - bbr->rand(&rand, 1, &bbr->rand_ctx); - - bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256); - - bbr->rand(&rand, 1, &bbr->rand_ctx); - - bbr->bw_probe_wait = 2 * NGTCP2_SECONDS + - (ngtcp2_tstamp)((double)rand / 255. * NGTCP2_SECONDS); -} - -static int bbr_is_reno_coexistence_probe_time(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t reno_rounds = - bbr_target_inflight(bbr, cstat) / cstat->max_udp_payload_size; - - return bbr->rounds_since_bw_probe >= ngtcp2_min(reno_rounds, 63); -} - -static uint64_t bbr_target_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t bdp = bbr_inflight(bbr, cstat, bbr->bw, 1.0); - - return ngtcp2_min(bdp, cstat->cwnd); -} - -static int bbr_check_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (is_inflight_too_high(&bbr->rst->rs)) { - if (bbr->bw_probe_samples) { - bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts); - } - - return 1; - } - - return 0; -} - -static int is_inflight_too_high(const ngtcp2_rs *rs) { - return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM > - rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER; -} - -static void bbr_handle_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, - ngtcp2_tstamp ts) { - bbr->bw_probe_samples = 0; - - if (!rs->is_app_limited) { - bbr->prior_inflight_hi = bbr->inflight_hi; - - bbr->inflight_hi = ngtcp2_max( - rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * - NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - bbr_start_probe_bw_down(bbr, ts); - } -} - -static void bbr_handle_lost_packet(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_rs rs = {0}; - - if (!bbr->bw_probe_samples) { - return; - } - - rs.tx_in_flight = pkt->tx_in_flight; - rs.lost = bbr->rst->lost - pkt->lost; - rs.is_app_limited = pkt->is_app_limited; - - if (is_inflight_too_high(&rs)) { - rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt); - - bbr_handle_inflight_too_high(bbr, cstat, &rs, ts); - } -} - -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_bbr2_cc *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt) { - uint64_t inflight_prev, lost_prefix; - (void)bbr; - - assert(rs->tx_in_flight >= pkt->pktlen); - - inflight_prev = rs->tx_in_flight - pkt->pktlen; - - assert(rs->lost >= pkt->pktlen); - - /* bbr->rst->lost is not incremented for pkt yet */ - - if (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER < - rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM) { - return inflight_prev; - } - - lost_prefix = (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER - - rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM) / - (NGTCP2_BBR_LOSS_THRESH_DENOM - NGTCP2_BBR_LOSS_THRESH_NUMER); - - return inflight_prev + lost_prefix; -} - -static void bbr_update_min_rtt(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - int min_rtt_expired; - - bbr->probe_rtt_expired = - ts > bbr->probe_rtt_min_stamp + NGTCP2_BBR_PROBE_RTT_INTERVAL; - - if (ack->rtt != UINT64_MAX && - (ack->rtt < bbr->probe_rtt_min_delay || bbr->probe_rtt_expired)) { - bbr->probe_rtt_min_delay = ack->rtt; - bbr->probe_rtt_min_stamp = ts; - } - - min_rtt_expired = ts > bbr->min_rtt_stamp + NGTCP2_BBR_MIN_RTT_FILTERLEN; - - if (bbr->probe_rtt_min_delay < bbr->min_rtt || min_rtt_expired) { - bbr->min_rtt = bbr->probe_rtt_min_delay; - bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; - - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 update min_rtt=%" PRIu64, bbr->min_rtt); - } -} - -static void bbr_check_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->state != NGTCP2_BBR2_STATE_PROBE_RTT && bbr->probe_rtt_expired && - !bbr->idle_restart) { - bbr_enter_probe_rtt(bbr); - bbr_save_cwnd(bbr, cstat); - - bbr->probe_rtt_done_stamp = UINT64_MAX; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING; - - bbr_start_round(bbr); - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr_handle_probe_rtt(bbr, cstat, ts); - } - - if (bbr->rst->rs.delivered) { - bbr->idle_restart = 0; - } -} - -static void bbr_enter_probe_rtt(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter ProbeRTT"); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_RTT; - bbr->pacing_gain = 1; - bbr->cwnd_gain = NGTCP2_BBR_PROBE_RTT_CWND_GAIN; -} - -static void bbr_handle_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - bbr_mark_connection_app_limited(bbr, cstat); - - if (bbr->probe_rtt_done_stamp == UINT64_MAX && - cstat->bytes_in_flight <= bbr_probe_rtt_cwnd(bbr, cstat)) { - bbr->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; - bbr->probe_rtt_round_done = 0; - - bbr_start_round(bbr); - - return; - } - - if (bbr->probe_rtt_done_stamp != UINT64_MAX) { - if (bbr->round_start) { - bbr->probe_rtt_round_done = 1; - } - - if (bbr->probe_rtt_round_done) { - bbr_check_probe_rtt_done(bbr, cstat, ts); - } - } -} - -static void bbr_check_probe_rtt_done(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->probe_rtt_done_stamp != UINT64_MAX && - ts > bbr->probe_rtt_done_stamp) { - bbr->probe_rtt_min_stamp = ts; - bbr_restore_cwnd(bbr, cstat); - bbr_exit_probe_rtt(bbr, ts); - } -} - -static void bbr_mark_connection_app_limited(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight; - - if (app_limited) { - bbr->rst->app_limited = app_limited; - } else { - bbr->rst->app_limited = cstat->max_udp_payload_size; - } -} - -static void bbr_exit_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - bbr_reset_lower_bounds(bbr); - - if (bbr->filled_pipe) { - bbr_start_probe_bw_down(bbr, ts); - bbr_start_probe_bw_cruise(bbr); - } else { - bbr_enter_startup(bbr); - } -} - -static void bbr_handle_restart_from_idle(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cstat->bytes_in_flight == 0 && bbr->rst->app_limited) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 restart from idle"); - - bbr->idle_restart = 1; - bbr->extra_acked_interval_start = ts; - - if (bbr_is_in_probe_bw_state(bbr)) { - bbr_set_pacing_rate_with_gain(bbr, cstat, 1); - } else if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr_check_probe_rtt_done(bbr, cstat, ts); - } - } -} - -static uint64_t bbr_bdp_multiple(ngtcp2_bbr2_cc *bbr, uint64_t bw, - double gain) { - uint64_t bdp; - - if (bbr->min_rtt == UINT64_MAX) { - return bbr->initial_cwnd; - } - - bdp = bw * bbr->min_rtt / NGTCP2_SECONDS; - - return (uint64_t)(gain * (double)bdp); -} - -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { - return max_udp_payload_size * 4; -} - -static uint64_t bbr_quantization_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - uint64_t inflight) { - bbr_update_offload_budget(bbr, cstat); - - inflight = ngtcp2_max(inflight, bbr->offload_budget); - inflight = ngtcp2_max(inflight, min_pipe_cwnd(cstat->max_udp_payload_size)); - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - inflight += 2 * cstat->max_udp_payload_size; - } - - return inflight; -} - -static uint64_t bbr_inflight(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - uint64_t bw, double gain) { - uint64_t inflight = bbr_bdp_multiple(bbr, bw, gain); - - return bbr_quantization_budget(bbr, cstat, inflight); -} - -static void bbr_update_max_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t inflight; - - /* Not documented */ - /* bbr_update_aggregation_budget(bbr); */ - - inflight = bbr_bdp_multiple(bbr, bbr->bw, bbr->cwnd_gain) + bbr->extra_acked; - bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight); -} - -static void bbr_update_offload_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - bbr->offload_budget = 3 * cstat->send_quantum; -} - -static void bbr_advance_max_bw_filter(ngtcp2_bbr2_cc *bbr) { - ++bbr->cycle_count; -} - -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (ack->bytes_lost > 0) { - if (cstat->cwnd > ack->bytes_lost) { - cstat->cwnd -= ack->bytes_lost; - cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_udp_payload_size); - } else { - cstat->cwnd = cstat->max_udp_payload_size; - } - } - - if (bbr->packet_conservation) { - cstat->cwnd = - ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); - } -} - -static void bbr_save_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr->prior_cwnd = cstat->cwnd; - return; - } - - bbr->prior_cwnd = ngtcp2_max(bbr->prior_cwnd, cstat->cwnd); -} - -static void bbr_restore_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - cstat->cwnd = ngtcp2_max(cstat->cwnd, bbr->prior_cwnd); -} - -static uint64_t bbr_probe_rtt_cwnd(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t probe_rtt_cwnd = - bbr_bdp_multiple(bbr, bbr->bw, NGTCP2_BBR_PROBE_RTT_CWND_GAIN); - uint64_t mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - return ngtcp2_max(probe_rtt_cwnd, mpcwnd); -} - -static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t probe_rtt_cwnd; - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat); - - cstat->cwnd = ngtcp2_min(cstat->cwnd, probe_rtt_cwnd); - } -} - -static void bbr_set_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - uint64_t mpcwnd; - - bbr_update_max_inflight(bbr, cstat); - bbr_modulate_cwnd_for_recovery(bbr, cstat, ack); - - if (!bbr->packet_conservation) { - if (bbr->filled_pipe) { - cstat->cwnd += ack->bytes_delivered; - cstat->cwnd = ngtcp2_min(cstat->cwnd, bbr->max_inflight); - } else if (cstat->cwnd < bbr->max_inflight || - bbr->rst->delivered < bbr->initial_cwnd) { - cstat->cwnd += ack->bytes_delivered; - } - - mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - cstat->cwnd = ngtcp2_max(cstat->cwnd, mpcwnd); - } - - bbr_bound_cwnd_for_probe_rtt(bbr, cstat); - bbr_bound_cwnd_for_model(bbr, cstat); -} - -static void bbr_bound_cwnd_for_model(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t cap = UINT64_MAX; - uint64_t mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - if (bbr_is_in_probe_bw_state(bbr) && - bbr->state != NGTCP2_BBR2_STATE_PROBE_BW_CRUISE) { - cap = bbr->inflight_hi; - } else if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT || - bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_CRUISE) { - cap = bbr_inflight_with_headroom(bbr, cstat); - } - - cap = ngtcp2_min(cap, bbr->inflight_lo); - cap = ngtcp2_max(cap, mpcwnd); - - cstat->cwnd = ngtcp2_min(cstat->cwnd, cap); -} - -static void bbr_set_send_quantum(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - size_t send_quantum = - (size_t)(cstat->pacing_rate * (double)(bbr->min_rtt == UINT64_MAX - ? NGTCP2_MILLISECONDS - : bbr->min_rtt)); - (void)bbr; - - cstat->send_quantum = ngtcp2_min(send_quantum, 64 * 1024); - cstat->send_quantum = - ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10); -} - -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time) { - return cstat->congestion_recovery_start_ts != UINT64_MAX && - sent_time <= cstat->congestion_recovery_start_ts; -} - -static void bbr_handle_recovery(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (bbr->in_loss_recovery) { - if (ack->pkt_delivered >= bbr->congestion_recovery_next_round_delivered) { - bbr->packet_conservation = 0; - } - - if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) { - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - bbr_restore_cwnd(bbr, cstat); - } - - return; - } - - if (bbr->congestion_recovery_start_ts != UINT64_MAX) { - bbr->in_loss_recovery = 1; - bbr_save_cwnd(bbr, cstat); - cstat->cwnd = cstat->bytes_in_flight + - ngtcp2_max(ack->bytes_delivered, cstat->max_udp_payload_size); - - cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts; - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->packet_conservation = 1; - bbr->congestion_recovery_next_round_delivered = bbr->rst->delivered; - bbr->prior_inflight_lo = bbr->inflight_lo; - bbr->prior_bw_lo = bbr->bw_lo; - } -} - -static void bbr2_cc_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log) { - bbr->ccb.log = log; - bbr->rst = rst; - bbr->rand = rand; - bbr->rand_ctx = *rand_ctx; - bbr->initial_cwnd = cstat->cwnd; - - bbr_on_init(bbr, cstat, initial_ts); -} - -static void bbr2_cc_free(ngtcp2_bbr2_cc *bbr) { (void)bbr; } - -static void bbr2_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)pkt; - (void)ts; -} - -static void bbr2_cc_on_pkt_lost(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_update_on_loss(bbr, cstat, pkt, ts); -} - -static void bbr2_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - if (!bbr->filled_pipe || bbr->in_loss_recovery || - bbr->congestion_recovery_start_ts != UINT64_MAX || - in_congestion_recovery(cstat, sent_ts)) { - return; - } - - bbr->congestion_recovery_start_ts = ts; -} - -static void bbr2_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - (void)ts; - - bbr->congestion_recovery_start_ts = UINT64_MAX; - cstat->congestion_recovery_start_ts = UINT64_MAX; - - if (bbr->in_loss_recovery) { - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - bbr_restore_cwnd(bbr, cstat); - bbr->full_bw_count = 0; - bbr->loss_in_round = 0; - bbr->inflight_lo = ngtcp2_max(bbr->inflight_lo, bbr->prior_inflight_lo); - bbr->inflight_hi = ngtcp2_max(bbr->inflight_hi, bbr->prior_inflight_hi); - bbr->bw_lo = ngtcp2_max(bbr->bw_lo, bbr->prior_bw_lo); - } -} - -static void bbr2_cc_on_persistent_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - (void)ts; - - cstat->congestion_recovery_start_ts = UINT64_MAX; - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - - bbr_save_cwnd(bbr, cstat); - cstat->cwnd = cstat->bytes_in_flight + cstat->max_udp_payload_size; - cstat->cwnd = - ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); -} - -static void bbr2_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_update_on_ack(bbr, cstat, ack, ts); -} - -static void bbr2_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_on_transmit(bbr, cstat, pkt->sent_ts); -} - -static void bbr2_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)ts; -} - -static void bbr2_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_on_init(bbr, cstat, ts); -} - -static void bbr2_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)event; - (void)ts; -} - -int ngtcp2_cc_bbr2_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem) { - ngtcp2_bbr2_cc *bbr; - - bbr = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr2_cc)); - if (bbr == NULL) { - return NGTCP2_ERR_NOMEM; - } - - bbr2_cc_init(bbr, cstat, rst, initial_ts, rand, rand_ctx, log); - - cc->ccb = &bbr->ccb; - cc->on_pkt_acked = bbr2_cc_on_pkt_acked; - cc->on_pkt_lost = bbr2_cc_on_pkt_lost; - cc->congestion_event = bbr2_cc_congestion_event; - cc->on_spurious_congestion = bbr2_cc_on_spurious_congestion; - cc->on_persistent_congestion = bbr2_cc_on_persistent_congestion; - cc->on_ack_recv = bbr2_cc_on_ack_recv; - cc->on_pkt_sent = bbr2_cc_on_pkt_sent; - cc->new_rtt_sample = bbr2_cc_new_rtt_sample; - cc->reset = bbr2_cc_reset; - cc->event = bbr2_cc_event; - - return 0; -} - -void ngtcp2_cc_bbr2_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr2_cc, ccb); - - bbr2_cc_free(bbr); - ngtcp2_mem_free(mem, bbr); -} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h deleted file mode 100644 index 50dc05a5f26121..00000000000000 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2021 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGTCP2_BBR2_H -#define NGTCP2_BBR2_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "ngtcp2_cc.h" -#include "ngtcp2_window_filter.h" - -typedef struct ngtcp2_rst ngtcp2_rst; - -typedef enum ngtcp2_bbr2_state { - NGTCP2_BBR2_STATE_STARTUP, - NGTCP2_BBR2_STATE_DRAIN, - NGTCP2_BBR2_STATE_PROBE_BW_DOWN, - NGTCP2_BBR2_STATE_PROBE_BW_CRUISE, - NGTCP2_BBR2_STATE_PROBE_BW_REFILL, - NGTCP2_BBR2_STATE_PROBE_BW_UP, - NGTCP2_BBR2_STATE_PROBE_RTT, -} ngtcp2_bbr2_state; - -typedef enum ngtcp2_bbr2_ack_phase { - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING, - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING, - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_FEEDBACK, - NGTCP2_BBR2_ACK_PHASE_ACKS_REFILLING, -} ngtcp2_bbr2_ack_phase; - -/* - * ngtcp2_bbr2_cc is BBR v2 congestion controller, described in - * https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control-01 - */ -typedef struct ngtcp2_bbr2_cc { - ngtcp2_cc_base ccb; - - uint64_t initial_cwnd; - ngtcp2_rst *rst; - ngtcp2_rand rand; - ngtcp2_rand_ctx rand_ctx; - - /* max_bw_filter for tracking the maximum recent delivery rate - samples for estimating max_bw. */ - ngtcp2_window_filter max_bw_filter; - - ngtcp2_window_filter extra_acked_filter; - - ngtcp2_duration min_rtt; - ngtcp2_tstamp min_rtt_stamp; - ngtcp2_tstamp probe_rtt_done_stamp; - int probe_rtt_round_done; - uint64_t prior_cwnd; - int idle_restart; - ngtcp2_tstamp extra_acked_interval_start; - uint64_t extra_acked_delivered; - - /* Congestion signals */ - int loss_in_round; - uint64_t bw_latest; - uint64_t inflight_latest; - - /* Lower bounds */ - uint64_t bw_lo; - uint64_t inflight_lo; - - /* Round counting */ - uint64_t next_round_delivered; - int round_start; - uint64_t round_count; - - /* Full pipe */ - int filled_pipe; - uint64_t full_bw; - size_t full_bw_count; - - /* Pacing rate */ - double pacing_gain; - - ngtcp2_bbr2_state state; - double cwnd_gain; - - int loss_round_start; - uint64_t loss_round_delivered; - uint64_t rounds_since_bw_probe; - uint64_t max_bw; - uint64_t bw; - uint64_t cycle_count; - uint64_t extra_acked; - uint64_t bytes_lost_in_round; - size_t loss_events_in_round; - uint64_t offload_budget; - uint64_t probe_up_cnt; - ngtcp2_tstamp cycle_stamp; - ngtcp2_bbr2_ack_phase ack_phase; - ngtcp2_duration bw_probe_wait; - int bw_probe_samples; - size_t bw_probe_up_rounds; - uint64_t bw_probe_up_acks; - uint64_t inflight_hi; - uint64_t bw_hi; - int probe_rtt_expired; - ngtcp2_duration probe_rtt_min_delay; - ngtcp2_tstamp probe_rtt_min_stamp; - int in_loss_recovery; - int packet_conservation; - uint64_t max_inflight; - ngtcp2_tstamp congestion_recovery_start_ts; - uint64_t congestion_recovery_next_round_delivered; - - uint64_t prior_inflight_lo; - uint64_t prior_inflight_hi; - uint64_t prior_bw_lo; -} ngtcp2_bbr2_cc; - -int ngtcp2_cc_bbr2_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem); - -void ngtcp2_cc_bbr2_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -#endif /* NGTCP2_BBR2_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c index 1ee7d96b04776e..6369887c28671b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c @@ -25,6 +25,7 @@ #include "ngtcp2_cc.h" #include +#include #if defined(_MSC_VER) # include @@ -34,6 +35,11 @@ #include "ngtcp2_macro.h" #include "ngtcp2_mem.h" #include "ngtcp2_rcvry.h" +#include "ngtcp2_conn_stat.h" + +/* NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN is the window length of + delivery rate filter driven by ACK clocking. */ +#define NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN 10 uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) { uint64_t n = 2 * max_udp_payload_size; @@ -56,45 +62,26 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, return pkt; } -static void reno_cc_reset(ngtcp2_reno_cc *cc) { - cc->max_delivery_rate_sec = 0; - cc->target_cwnd = 0; - cc->pending_add = 0; -} - -void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log) { - cc->ccb.log = log; - reno_cc_reset(cc); +static void reno_cc_reset(ngtcp2_cc_reno *reno) { + ngtcp2_window_filter_init(&reno->delivery_rate_sec_filter, + NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN); + reno->ack_count = 0; + reno->target_cwnd = 0; + reno->pending_add = 0; } -void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc) { (void)cc; } - -int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem) { - ngtcp2_reno_cc *reno_cc; - - reno_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_reno_cc)); - if (reno_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_reno_cc_init(reno_cc, log); - - cc->ccb = &reno_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_reno_cc_congestion_event; - cc->on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_reno_cc_on_ack_recv; - cc->reset = ngtcp2_cc_reno_cc_reset; - - return 0; -} +void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) { + memset(reno, 0, sizeof(*reno)); -void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_reno_cc *reno_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_reno_cc, ccb); + reno->cc.log = log; + reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked; + reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event; + reno->cc.on_persistent_congestion = + ngtcp2_cc_reno_cc_on_persistent_congestion; + reno->cc.on_ack_recv = ngtcp2_cc_reno_cc_on_ack_recv; + reno->cc.reset = ngtcp2_cc_reno_cc_reset; - ngtcp2_reno_cc_free(reno_cc); - ngtcp2_mem_free(mem, reno_cc); + reno_cc_reset(reno); } static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, @@ -103,10 +90,10 @@ static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, sent_time <= cstat->congestion_recovery_start_ts; } -void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t m; (void)ts; @@ -114,28 +101,28 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, return; } - if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { + if (reno->target_cwnd && reno->target_cwnd < cstat->cwnd) { return; } if (cstat->cwnd < cstat->ssthresh) { cstat->cwnd += pkt->pktlen; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, pkt->pkt_num, cstat->cwnd); return; } - m = cstat->max_udp_payload_size * pkt->pktlen + cc->pending_add; - cc->pending_add = m % cstat->cwnd; + m = cstat->max_tx_udp_payload_size * pkt->pktlen + reno->pending_add; + reno->pending_add = m % cstat->cwnd; cstat->cwnd += m / cstat->cwnd; } -void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t min_cwnd; if (in_congestion_recovery(cstat, sent_ts)) { @@ -144,123 +131,109 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, cstat->congestion_recovery_start_ts = ts; cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS; - min_cwnd = 2 * cstat->max_udp_payload_size; + min_cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->cwnd = ngtcp2_max(cstat->cwnd, min_cwnd); cstat->ssthresh = cstat->cwnd; - cc->pending_add = 0; + reno->pending_add = 0; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "reduce cwnd because of packet loss cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ccx; + (void)cc; (void)ts; - cstat->cwnd = 2 * cstat->max_udp_payload_size; + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->congestion_recovery_start_ts = UINT64_MAX; } -void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t target_cwnd, initcwnd; + uint64_t max_delivery_rate_sec; (void)ack; (void)ts; - /* TODO Use sliding window for min rtt measurement */ - /* TODO Use sliding window */ - cc->max_delivery_rate_sec = - ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + ++reno->ack_count; - if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) { - target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS; - initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_udp_payload_size); - cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + ngtcp2_window_filter_update(&reno->delivery_rate_sec_filter, + cstat->delivery_rate_sec, reno->ack_count); - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + max_delivery_rate_sec = + ngtcp2_window_filter_get_best(&reno->delivery_rate_sec_filter); + + if (cstat->min_rtt != UINT64_MAX && max_delivery_rate_sec) { + target_cwnd = max_delivery_rate_sec * cstat->smoothed_rtt / NGTCP2_SECONDS; + initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size); + reno->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 - " min_rtt=%" PRIu64, - cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); + " smoothed_rtt=%" PRIu64, + reno->target_cwnd, max_delivery_rate_sec, + cstat->smoothed_rtt); } } -void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); (void)cstat; (void)ts; - reno_cc_reset(cc); -} - -static void cubic_cc_reset(ngtcp2_cubic_cc *cc) { - cc->max_delivery_rate_sec = 0; - cc->target_cwnd = 0; - cc->w_last_max = 0; - cc->w_tcp = 0; - cc->origin_point = 0; - cc->epoch_start = UINT64_MAX; - cc->k = 0; - - cc->prior.cwnd = 0; - cc->prior.ssthresh = 0; - cc->prior.w_last_max = 0; - cc->prior.w_tcp = 0; - cc->prior.origin_point = 0; - cc->prior.epoch_start = UINT64_MAX; - cc->prior.k = 0; - - cc->rtt_sample_count = 0; - cc->current_round_min_rtt = UINT64_MAX; - cc->last_round_min_rtt = UINT64_MAX; - cc->window_end = -1; -} - -void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log) { - cc->ccb.log = log; - cubic_cc_reset(cc); + reno_cc_reset(reno); } -void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc) { (void)cc; } - -int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem) { - ngtcp2_cubic_cc *cubic_cc; - - cubic_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_cubic_cc)); - if (cubic_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_cubic_cc_init(cubic_cc, log); - - cc->ccb = &cubic_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_cubic_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_cubic_cc_congestion_event; - cc->on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion; - cc->on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv; - cc->on_pkt_sent = ngtcp2_cc_cubic_cc_on_pkt_sent; - cc->new_rtt_sample = ngtcp2_cc_cubic_cc_new_rtt_sample; - cc->reset = ngtcp2_cc_cubic_cc_reset; - cc->event = ngtcp2_cc_cubic_cc_event; - - return 0; +static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) { + ngtcp2_window_filter_init(&cubic->delivery_rate_sec_filter, + NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN); + cubic->ack_count = 0; + cubic->target_cwnd = 0; + cubic->w_last_max = 0; + cubic->w_tcp = 0; + cubic->origin_point = 0; + cubic->epoch_start = UINT64_MAX; + cubic->k = 0; + + cubic->prior.cwnd = 0; + cubic->prior.ssthresh = 0; + cubic->prior.w_last_max = 0; + cubic->prior.w_tcp = 0; + cubic->prior.origin_point = 0; + cubic->prior.epoch_start = UINT64_MAX; + cubic->prior.k = 0; + + cubic->rtt_sample_count = 0; + cubic->current_round_min_rtt = UINT64_MAX; + cubic->last_round_min_rtt = UINT64_MAX; + cubic->window_end = -1; } -void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_cubic_cc *cubic_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_cubic_cc, ccb); - - ngtcp2_cubic_cc_free(cubic_cc); - ngtcp2_mem_free(mem, cubic_cc); +void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log) { + memset(cubic, 0, sizeof(*cubic)); + + cubic->cc.log = log; + cubic->cc.on_pkt_acked = ngtcp2_cc_cubic_cc_on_pkt_acked; + cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event; + cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion; + cubic->cc.on_persistent_congestion = + ngtcp2_cc_cubic_cc_on_persistent_congestion; + cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv; + cubic->cc.on_pkt_sent = ngtcp2_cc_cubic_cc_on_pkt_sent; + cubic->cc.new_rtt_sample = ngtcp2_cc_cubic_cc_new_rtt_sample; + cubic->cc.reset = ngtcp2_cc_cubic_cc_reset; + cubic->cc.event = ngtcp2_cc_cubic_cc_event; + + cubic_cc_reset(cubic); } -static uint64_t ngtcp2_cbrt(uint64_t n) { +uint64_t ngtcp2_cbrt(uint64_t n) { int d; uint64_t a; @@ -269,26 +242,23 @@ static uint64_t ngtcp2_cbrt(uint64_t n) { } #if defined(_MSC_VER) -# if defined(_M_X64) - d = (int)__lzcnt64(n); -# elif defined(_M_ARM64) { unsigned long index; - d = sizeof(uint64_t) * CHAR_BIT; +# if defined(_WIN64) if (_BitScanReverse64(&index, n)) { - d = d - 1 - index; + d = 61 - index; } +# else /* !defined(_WIN64) */ + if (_BitScanReverse(&index, (unsigned int)(n >> 32))) { + d = 31 - index; + } else { + d = 32 + 31 - _BitScanReverse(&index, (unsigned int)n); + } +# endif /* !defined(_WIN64) */ } -# else - if ((n >> 32) != 0) { - d = __lzcnt((unsigned int)(n >> 32)); - } else { - d = 32 + __lzcnt((unsigned int)n); - } -# endif -#else +#else /* !defined(_MSC_VER) */ d = __builtin_clzll(n); -#endif +#endif /* !defined(_MSC_VER) */ a = 1ULL << ((64 - d) / 3 + 1); for (; a * a * a > n;) { @@ -303,42 +273,41 @@ static uint64_t ngtcp2_cbrt(uint64_t n) { #define NGTCP2_HS_MIN_ETA (4 * NGTCP2_MILLISECONDS) #define NGTCP2_HS_MAX_ETA (16 * NGTCP2_MILLISECONDS) -void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); - ngtcp2_duration t, min_rtt, eta; - uint64_t target; + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); + ngtcp2_duration t, eta; + uint64_t target, cwnd_thres; uint64_t tx, kx, time_delta, delta; uint64_t add, tcp_add; uint64_t m; - if (pkt->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && cc->window_end != -1 && - cc->window_end <= pkt->pkt_num) { - cc->window_end = -1; + if (pkt->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && cubic->window_end != -1 && + cubic->window_end <= pkt->pkt_num) { + cubic->window_end = -1; } if (in_congestion_recovery(cstat, pkt->sent_ts)) { return; } - if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { - return; - } - if (cstat->cwnd < cstat->ssthresh) { /* slow-start */ - cstat->cwnd += pkt->pktlen; + if (cubic->target_cwnd == 0 || cubic->target_cwnd > cstat->cwnd) { + cstat->cwnd += pkt->pktlen; + } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, pkt->pkt_num, cstat->cwnd); - if (cc->last_round_min_rtt != UINT64_MAX && - cc->current_round_min_rtt != UINT64_MAX && - cstat->cwnd >= NGTCP2_HS_MIN_SSTHRESH * cstat->max_udp_payload_size && - cc->rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE) { - eta = cc->last_round_min_rtt / 8; + if (cubic->last_round_min_rtt != UINT64_MAX && + cubic->current_round_min_rtt != UINT64_MAX && + cstat->cwnd >= + NGTCP2_HS_MIN_SSTHRESH * cstat->max_tx_udp_payload_size && + cubic->rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE) { + eta = cubic->last_round_min_rtt / 8; if (eta < NGTCP2_HS_MIN_ETA) { eta = NGTCP2_HS_MIN_ETA; @@ -346,11 +315,11 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, eta = NGTCP2_HS_MAX_ETA; } - if (cc->current_round_min_rtt >= cc->last_round_min_rtt + eta) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + if (cubic->current_round_min_rtt >= cubic->last_round_min_rtt + eta) { + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "HyStart++ exit slow start"); - cc->w_last_max = cstat->cwnd; + cubic->w_last_max = cstat->cwnd; cstat->ssthresh = cstat->cwnd; } } @@ -360,34 +329,32 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, /* congestion avoidance */ - if (cc->epoch_start == UINT64_MAX) { - cc->epoch_start = ts; - if (cstat->cwnd < cc->w_last_max) { - cc->k = ngtcp2_cbrt((cc->w_last_max - cstat->cwnd) * 10 / 4 / - cstat->max_udp_payload_size); - cc->origin_point = cc->w_last_max; + if (cubic->epoch_start == UINT64_MAX) { + cubic->epoch_start = ts; + if (cstat->cwnd < cubic->w_last_max) { + cubic->k = ngtcp2_cbrt((cubic->w_last_max - cstat->cwnd) * 10 / 4 / + cstat->max_tx_udp_payload_size); + cubic->origin_point = cubic->w_last_max; } else { - cc->k = 0; - cc->origin_point = cstat->cwnd; + cubic->k = 0; + cubic->origin_point = cstat->cwnd; } - cc->w_tcp = cstat->cwnd; + cubic->w_tcp = cstat->cwnd; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "cubic-ca epoch_start=%" PRIu64 " k=%" PRIu64 " origin_point=%" PRIu64, - cc->epoch_start, cc->k, cc->origin_point); + cubic->epoch_start, cubic->k, cubic->origin_point); - cc->pending_add = 0; - cc->pending_w_add = 0; + cubic->pending_add = 0; + cubic->pending_w_add = 0; } - min_rtt = cstat->min_rtt == UINT64_MAX ? cstat->initial_rtt : cstat->min_rtt; + t = ts - cubic->epoch_start; - t = ts + min_rtt - cc->epoch_start; - - tx = (t << 4) / NGTCP2_SECONDS; - kx = (cc->k << 4); + tx = (t << 10) / NGTCP2_SECONDS; + kx = (cubic->k << 10); if (tx > kx) { time_delta = tx - kx; @@ -395,210 +362,229 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, time_delta = kx - tx; } - delta = cstat->max_udp_payload_size * - ((((time_delta * time_delta) >> 4) * time_delta) >> 8) * 4 / 10; + delta = cstat->max_tx_udp_payload_size * + ((((time_delta * time_delta) >> 10) * time_delta) >> 10) * 4 / 10; + delta >>= 10; if (tx > kx) { - target = cc->origin_point + delta; + target = cubic->origin_point + delta; + } else { + target = cubic->origin_point - delta; + } + + cwnd_thres = + (target * (((t + cstat->smoothed_rtt) << 10) / NGTCP2_SECONDS)) >> 10; + if (cwnd_thres < cstat->cwnd) { + target = cstat->cwnd; + } else if (2 * cwnd_thres > 3 * cstat->cwnd) { + target = cstat->cwnd * 3 / 2; } else { - target = cc->origin_point - delta; + target = cwnd_thres; } if (target > cstat->cwnd) { - m = cc->pending_add + cstat->max_udp_payload_size * (target - cstat->cwnd); + m = cubic->pending_add + + cstat->max_tx_udp_payload_size * (target - cstat->cwnd); add = m / cstat->cwnd; - cc->pending_add = m % cstat->cwnd; + cubic->pending_add = m % cstat->cwnd; } else { - m = cc->pending_add + cstat->max_udp_payload_size; + m = cubic->pending_add + cstat->max_tx_udp_payload_size; add = m / (100 * cstat->cwnd); - cc->pending_add = m % (100 * cstat->cwnd); + cubic->pending_add = m % (100 * cstat->cwnd); } - m = cc->pending_w_add + cstat->max_udp_payload_size * pkt->pktlen; + m = cubic->pending_w_add + cstat->max_tx_udp_payload_size * pkt->pktlen; - cc->w_tcp += m / cstat->cwnd; - cc->pending_w_add = m % cstat->cwnd; + cubic->w_tcp += m / cstat->cwnd; + cubic->pending_w_add = m % cstat->cwnd; - if (cc->w_tcp > cstat->cwnd) { - tcp_add = - cstat->max_udp_payload_size * (cc->w_tcp - cstat->cwnd) / cstat->cwnd; + if (cubic->w_tcp > cstat->cwnd) { + tcp_add = cstat->max_tx_udp_payload_size * (cubic->w_tcp - cstat->cwnd) / + cstat->cwnd; if (tcp_add > add) { add = tcp_add; } } - cstat->cwnd += add; + if (cubic->target_cwnd == 0 || cubic->target_cwnd > cstat->cwnd) { + cstat->cwnd += add; + } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, cubic-ca cwnd=%" PRIu64 " t=%" PRIu64 " k=%" PRIi64 " time_delta=%" PRIu64 " delta=%" PRIu64 " target=%" PRIu64 " w_tcp=%" PRIu64, - pkt->pkt_num, cstat->cwnd, t, cc->k, time_delta >> 4, delta, - target, cc->w_tcp); + pkt->pkt_num, cstat->cwnd, t, cubic->k, time_delta >> 4, + delta, target, cubic->w_tcp); } -void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); uint64_t min_cwnd; if (in_congestion_recovery(cstat, sent_ts)) { return; } - if (cc->prior.cwnd < cstat->cwnd) { - cc->prior.cwnd = cstat->cwnd; - cc->prior.ssthresh = cstat->ssthresh; - cc->prior.w_last_max = cc->w_last_max; - cc->prior.w_tcp = cc->w_tcp; - cc->prior.origin_point = cc->origin_point; - cc->prior.epoch_start = cc->epoch_start; - cc->prior.k = cc->k; + if (cubic->prior.cwnd < cstat->cwnd) { + cubic->prior.cwnd = cstat->cwnd; + cubic->prior.ssthresh = cstat->ssthresh; + cubic->prior.w_last_max = cubic->w_last_max; + cubic->prior.w_tcp = cubic->w_tcp; + cubic->prior.origin_point = cubic->origin_point; + cubic->prior.epoch_start = cubic->epoch_start; + cubic->prior.k = cubic->k; } cstat->congestion_recovery_start_ts = ts; - cc->epoch_start = UINT64_MAX; - if (cstat->cwnd < cc->w_last_max) { - cc->w_last_max = cstat->cwnd * 17 / 10 / 2; + cubic->epoch_start = UINT64_MAX; + if (cstat->cwnd < cubic->w_last_max) { + cubic->w_last_max = cstat->cwnd * 17 / 10 / 2; } else { - cc->w_last_max = cstat->cwnd; + cubic->w_last_max = cstat->cwnd; } - min_cwnd = 2 * cstat->max_udp_payload_size; + min_cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->ssthresh = cstat->cwnd * 7 / 10; cstat->ssthresh = ngtcp2_max(cstat->ssthresh, min_cwnd); cstat->cwnd = cstat->ssthresh; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "reduce cwnd because of packet loss cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)ts; - if (cstat->cwnd >= cc->prior.cwnd) { + if (cstat->cwnd >= cubic->prior.cwnd) { return; } cstat->congestion_recovery_start_ts = UINT64_MAX; - cstat->cwnd = cc->prior.cwnd; - cstat->ssthresh = cc->prior.ssthresh; - cc->w_last_max = cc->prior.w_last_max; - cc->w_tcp = cc->prior.w_tcp; - cc->origin_point = cc->prior.origin_point; - cc->epoch_start = cc->prior.epoch_start; - cc->k = cc->prior.k; - - cc->prior.cwnd = 0; - cc->prior.ssthresh = 0; - cc->prior.w_last_max = 0; - cc->prior.w_tcp = 0; - cc->prior.origin_point = 0; - cc->prior.epoch_start = UINT64_MAX; - cc->prior.k = 0; - - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + cstat->cwnd = cubic->prior.cwnd; + cstat->ssthresh = cubic->prior.ssthresh; + cubic->w_last_max = cubic->prior.w_last_max; + cubic->w_tcp = cubic->prior.w_tcp; + cubic->origin_point = cubic->prior.origin_point; + cubic->epoch_start = cubic->prior.epoch_start; + cubic->k = cubic->prior.k; + + cubic->prior.cwnd = 0; + cubic->prior.ssthresh = 0; + cubic->prior.w_last_max = 0; + cubic->prior.w_tcp = 0; + cubic->prior.origin_point = 0; + cubic->prior.epoch_start = UINT64_MAX; + cubic->prior.k = 0; + + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "spurious congestion is detected and congestion state is " "restored cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ccx; + (void)cc; (void)ts; - cstat->cwnd = 2 * cstat->max_udp_payload_size; + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->congestion_recovery_start_ts = UINT64_MAX; } -void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); uint64_t target_cwnd, initcwnd; + uint64_t max_delivery_rate_sec; (void)ack; (void)ts; - /* TODO Use sliding window for min rtt measurement */ - /* TODO Use sliding window */ - cc->max_delivery_rate_sec = - ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + ++cubic->ack_count; + + ngtcp2_window_filter_update(&cubic->delivery_rate_sec_filter, + cstat->delivery_rate_sec, cubic->ack_count); + + max_delivery_rate_sec = + ngtcp2_window_filter_get_best(&cubic->delivery_rate_sec_filter); - if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) { - target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS; - initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_udp_payload_size); - cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + if (cstat->min_rtt != UINT64_MAX && max_delivery_rate_sec) { + target_cwnd = max_delivery_rate_sec * cstat->smoothed_rtt / NGTCP2_SECONDS; + initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size); + cubic->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 - " min_rtt=%" PRIu64, - cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); + " smoothed_rtt=%" PRIu64, + cubic->target_cwnd, max_delivery_rate_sec, + cstat->smoothed_rtt); } } -void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)cstat; - if (pkt->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || cc->window_end != -1) { + if (pkt->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || cubic->window_end != -1) { return; } - cc->window_end = pkt->pkt_num; - cc->last_round_min_rtt = cc->current_round_min_rtt; - cc->current_round_min_rtt = UINT64_MAX; - cc->rtt_sample_count = 0; + cubic->window_end = pkt->pkt_num; + cubic->last_round_min_rtt = cubic->current_round_min_rtt; + cubic->current_round_min_rtt = UINT64_MAX; + cubic->rtt_sample_count = 0; } -void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)ts; - if (cc->window_end == -1) { + if (cubic->window_end == -1) { return; } - cc->current_round_min_rtt = - ngtcp2_min(cc->current_round_min_rtt, cstat->latest_rtt); - ++cc->rtt_sample_count; + cubic->current_round_min_rtt = + ngtcp2_min(cubic->current_round_min_rtt, cstat->latest_rtt); + ++cubic->rtt_sample_count; } -void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)cstat; (void)ts; - cubic_cc_reset(cc); + cubic_cc_reset(cubic); } -void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); ngtcp2_tstamp last_ts; - if (event != NGTCP2_CC_EVENT_TYPE_TX_START || cc->epoch_start == UINT64_MAX) { + if (event != NGTCP2_CC_EVENT_TYPE_TX_START || + cubic->epoch_start == UINT64_MAX) { return; } last_ts = cstat->last_tx_pkt_ts[NGTCP2_PKTNS_ID_APPLICATION]; - if (last_ts == UINT64_MAX || last_ts <= cc->epoch_start) { + if (last_ts == UINT64_MAX || last_ts <= cubic->epoch_start) { return; } assert(ts >= last_ts); - cc->epoch_start += ts - last_ts; + cubic->epoch_start += ts - last_ts; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h index 6d9e0c2459ece4..524bcdb7e4bf86 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h @@ -31,24 +31,14 @@ #include +#include "ngtcp2_pktns_id.h" +#include "ngtcp2_window_filter.h" + #define NGTCP2_LOSS_REDUCTION_FACTOR_BITS 1 #define NGTCP2_PERSISTENT_CONGESTION_THRESHOLD 3 typedef struct ngtcp2_log ngtcp2_log; - -/** - * @struct - * - * :type:`ngtcp2_cc_base` is the base structure of custom congestion - * control algorithm. It must be the first field of custom congestion - * controller. - */ -typedef struct ngtcp2_cc_base { - /** - * :member:`log` is ngtcp2 library internal logger. - */ - ngtcp2_log *log; -} ngtcp2_cc_base; +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; /** * @struct @@ -117,10 +107,10 @@ typedef struct ngtcp2_cc_ack { */ uint64_t pkt_delivered; /** - * :member:`largest_acked_sent_ts` is the time when the largest - * acknowledged packet was sent. + * :member:`largest_pkt_sent_ts` is the time when the largest + * acknowledged packet was sent. It is UINT64_MAX if it is unknown. */ - ngtcp2_tstamp largest_acked_sent_ts; + ngtcp2_tstamp largest_pkt_sent_ts; /** * :member:`rtt` is the RTT sample. It is UINT64_MAX if no RTT * sample is available. @@ -242,15 +232,14 @@ typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, /** * @struct * - * :type:`ngtcp2_cc` is congestion control algorithm interface to - * allow custom implementation. + * :type:`ngtcp2_cc` is congestion control algorithm interface shared + * by implementations. All callback functions are optional. */ typedef struct ngtcp2_cc { /** - * :member:`ccb` is a pointer to :type:`ngtcp2_cc_base` which - * usually contains a state. + * :member:`log` is ngtcp2 library internal logger. */ - ngtcp2_cc_base *ccb; + ngtcp2_log *log; /** * :member:`on_pkt_acked` is a callback function which is called * when a packet is acknowledged. @@ -313,22 +302,16 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, ngtcp2_tstamp sent_ts, uint64_t lost, uint64_t tx_in_flight, int is_app_limited); -/* ngtcp2_reno_cc is the RENO congestion controller. */ -typedef struct ngtcp2_reno_cc { - ngtcp2_cc_base ccb; - uint64_t max_delivery_rate_sec; +/* ngtcp2_cc_reno is the RENO congestion controller. */ +typedef struct ngtcp2_cc_reno { + ngtcp2_cc cc; + ngtcp2_window_filter delivery_rate_sec_filter; + uint64_t ack_count; uint64_t target_cwnd; uint64_t pending_add; -} ngtcp2_reno_cc; - -int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem); - -void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log); +} ngtcp2_cc_reno; -void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc); +void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log); void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); @@ -347,10 +330,11 @@ void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -/* ngtcp2_cubic_cc is CUBIC congestion controller. */ -typedef struct ngtcp2_cubic_cc { - ngtcp2_cc_base ccb; - uint64_t max_delivery_rate_sec; +/* ngtcp2_cc_cubic is CUBIC congestion controller. */ +typedef struct ngtcp2_cc_cubic { + ngtcp2_cc cc; + ngtcp2_window_filter delivery_rate_sec_filter; + uint64_t ack_count; uint64_t target_cwnd; uint64_t w_last_max; uint64_t w_tcp; @@ -376,16 +360,9 @@ typedef struct ngtcp2_cubic_cc { int64_t window_end; uint64_t pending_add; uint64_t pending_w_add; -} ngtcp2_cubic_cc; +} ngtcp2_cc_cubic; -int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem); - -void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log); - -void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc); +void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cc, ngtcp2_log *log); void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, @@ -418,4 +395,6 @@ void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_cc_event_type event, ngtcp2_tstamp ts); +uint64_t ngtcp2_cbrt(uint64_t n); + #endif /* NGTCP2_CC_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c index a3135680ca160f..f40ab5626109e9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -35,6 +35,11 @@ #include "ngtcp2_addr.h" #include "ngtcp2_path.h" #include "ngtcp2_rcvry.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_net.h" +#include "ngtcp2_conversion.h" +#include "ngtcp2_tstamp.h" +#include "ngtcp2_frame_chain.h" /* NGTCP2_FLOW_WINDOW_RTT_FACTOR is the factor of RTT when flow control window auto-tuning is triggered. */ @@ -46,6 +51,8 @@ packet payload that should be coalesced to a long packet. */ #define NGTCP2_MIN_COALESCED_PAYLOADLEN 128 +ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent); + /* * conn_local_stream returns nonzero if |stream_id| indicates that it * is the stream initiated by local endpoint. @@ -60,12 +67,20 @@ static int conn_local_stream(ngtcp2_conn *conn, int64_t stream_id) { */ static int bidi_stream(int64_t stream_id) { return (stream_id & 0x2) == 0; } +static void conn_update_timestamp(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + assert(conn->log.last_ts <= ts); + assert(conn->qlog.last_ts <= ts); + + conn->log.last_ts = ts; + conn->qlog.last_ts = ts; +} + /* - * conn_is_handshake_completed returns nonzero if QUIC handshake has - * completed. + * conn_is_tls_handshake_completed returns nonzero if TLS handshake + * has completed and 1 RTT keys are available. */ -static int conn_is_handshake_completed(ngtcp2_conn *conn) { - return (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) && +static int conn_is_tls_handshake_completed(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED) && conn->pktns.crypto.rx.ckm && conn->pktns.crypto.tx.ckm; } @@ -118,14 +133,14 @@ static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, } static int conn_call_recv_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen) { int rv; assert(conn->callbacks.recv_crypto_data); - rv = conn->callbacks.recv_crypto_data(conn, crypto_level, offset, data, + rv = conn->callbacks.recv_crypto_data(conn, encryption_level, offset, data, datalen, conn->user_data); switch (rv) { case 0: @@ -267,6 +282,7 @@ static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv, ngtcp2_path_validation_result res) { int rv; uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE; + const ngtcp2_path *old_path = NULL; if (!conn->callbacks.path_validation) { return 0; @@ -276,8 +292,18 @@ static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv, flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR; } - rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, res, - conn->user_data); + if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { + old_path = &pv->fallback_dcid.ps.path; + } + + if (conn->server && old_path && + (ngtcp2_addr_compare(&pv->dcid.ps.path.remote, &old_path->remote) & + (NGTCP2_ADDR_COMPARE_FLAG_ADDR | NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) { + flags |= NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN; + } + + rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, old_path, + res, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -294,10 +320,10 @@ static int conn_call_select_preferred_addr(ngtcp2_conn *conn, } assert(conn->remote.transport_params); - assert(conn->remote.transport_params->preferred_address_present); + assert(conn->remote.transport_params->preferred_addr_present); rv = conn->callbacks.select_preferred_addr( - conn, dest, &conn->remote.transport_params->preferred_address, + conn, dest, &conn->remote.transport_params->preferred_addr, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; @@ -369,7 +395,7 @@ static int conn_call_dcid_status(ngtcp2_conn *conn, } rv = conn->callbacks.dcid_status( - conn, (int)type, dcid->seq, &dcid->cid, + conn, type, dcid->seq, &dcid->cid, (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL, conn->user_data); if (rv != 0) { @@ -505,15 +531,15 @@ conn_call_recv_stateless_reset(ngtcp2_conn *conn, return 0; } -static int conn_call_recv_new_token(ngtcp2_conn *conn, - const ngtcp2_vec *token) { +static int conn_call_recv_new_token(ngtcp2_conn *conn, const uint8_t *token, + size_t tokenlen) { int rv; if (!conn->callbacks.recv_new_token) { return 0; } - rv = conn->callbacks.recv_new_token(conn, token, conn->user_data); + rv = conn->callbacks.recv_new_token(conn, token, tokenlen, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -557,8 +583,8 @@ static int conn_call_recv_datagram(ngtcp2_conn *conn, datalen = 0; } - if (!conn_is_handshake_completed(conn)) { - flags |= NGTCP2_DATAGRAM_FLAG_EARLY; + if (!conn_is_tls_handshake_completed(conn)) { + flags |= NGTCP2_DATAGRAM_FLAG_0RTT; } rv = conn->callbacks.recv_datagram(conn, flags, data, datalen, @@ -605,7 +631,8 @@ static int conn_call_version_negotiation(ngtcp2_conn *conn, uint32_t version, return 0; } -static int conn_call_recv_rx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { +static int conn_call_recv_rx_key(ngtcp2_conn *conn, + ngtcp2_encryption_level level) { int rv; if (!conn->callbacks.recv_rx_key) { @@ -620,7 +647,8 @@ static int conn_call_recv_rx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { return 0; } -static int conn_call_recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { +static int conn_call_recv_tx_key(ngtcp2_conn *conn, + ngtcp2_encryption_level level) { int rv; if (!conn->callbacks.recv_tx_key) { @@ -635,14 +663,10 @@ static int conn_call_recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { return 0; } -static int crypto_offset_less(const ngtcp2_ksl_key *lhs, - const ngtcp2_ksl_key *rhs) { - return *(int64_t *)lhs < *(int64_t *)rhs; -} - static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, - ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, + ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num, + ngtcp2_log *log, ngtcp2_qlog *qlog, + ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { int rv; @@ -650,7 +674,8 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, ngtcp2_gaptr_init(&pktns->rx.pngap, mem); - pktns->tx.last_pkt_num = -1; + pktns->tx.last_pkt_num = initial_pkt_num - 1; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; pktns->rx.max_pkt_num = -1; pktns->rx.max_ack_eliciting_pkt_num = -1; @@ -660,14 +685,12 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, } ngtcp2_strm_init(&pktns->crypto.strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, - NULL, mem); + frc_objalloc, mem); - ngtcp2_ksl_init(&pktns->crypto.tx.frq, crypto_offset_less, sizeof(uint64_t), + ngtcp2_rtb_init(&pktns->rtb, pktns_id, &pktns->crypto.strm, rst, cc, + initial_pkt_num, log, qlog, rtb_entry_objalloc, frc_objalloc, mem); - ngtcp2_rtb_init(&pktns->rtb, pktns_id, &pktns->crypto.strm, rst, cc, log, - qlog, rtb_entry_objalloc, frc_objalloc, mem); - return 0; fail_acktr_init: @@ -677,8 +700,9 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, } static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, - ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, + ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num, + ngtcp2_log *log, ngtcp2_qlog *qlog, + ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { int rv; @@ -687,8 +711,8 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, return NGTCP2_ERR_NOMEM; } - rv = pktns_init(*ppktns, pktns_id, rst, cc, log, qlog, rtb_entry_objalloc, - frc_objalloc, mem); + rv = pktns_init(*ppktns, pktns_id, rst, cc, initial_pkt_num, log, qlog, + rtb_entry_objalloc, frc_objalloc, mem); if (rv != 0) { ngtcp2_mem_free(mem, *ppktns); } @@ -729,9 +753,6 @@ static void delete_buf_chain(ngtcp2_buf_chain *bufchain, } static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { - ngtcp2_frame_chain *frc; - ngtcp2_ksl_it it; - delete_buf_chain(pktns->crypto.tx.data, mem); delete_buffed_pkts(pktns->rx.buffed_pkts, mem); @@ -742,13 +763,6 @@ static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem); - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - ngtcp2_frame_chain_objalloc_del(frc, pktns->rtb.frc_objalloc, mem); - } - - ngtcp2_ksl_free(&pktns->crypto.tx.frq); ngtcp2_rtb_free(&pktns->rtb); ngtcp2_strm_free(&pktns->crypto.strm); ngtcp2_acktr_free(&pktns->acktr); @@ -765,26 +779,6 @@ static void pktns_del(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_mem_free(mem, pktns); } -static void cc_del(ngtcp2_cc *cc, ngtcp2_cc_algo cc_algo, - const ngtcp2_mem *mem) { - switch (cc_algo) { - case NGTCP2_CC_ALGO_RENO: - ngtcp2_cc_reno_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_CUBIC: - ngtcp2_cc_cubic_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_BBR: - ngtcp2_cc_bbr_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_BBR2: - ngtcp2_cc_bbr2_cc_free(cc, mem); - break; - default: - break; - } -} - static int cid_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return ngtcp2_cid_less(lhs, rhs); } @@ -810,13 +804,13 @@ static void conn_reset_conn_stat_cc(ngtcp2_conn *conn, cstat->pto_count = 0; cstat->loss_detection_timer = UINT64_MAX; cstat->cwnd = - ngtcp2_cc_compute_initcwnd(conn->local.settings.max_udp_payload_size); + ngtcp2_cc_compute_initcwnd(conn->local.settings.max_tx_udp_payload_size); cstat->ssthresh = UINT64_MAX; cstat->congestion_recovery_start_ts = UINT64_MAX; cstat->bytes_in_flight = 0; cstat->delivery_rate_sec = 0; - cstat->pacing_rate = 0.0; - cstat->send_quantum = SIZE_MAX; + cstat->pacing_interval = 0; + cstat->send_quantum = 64 * 1024; } /* @@ -896,6 +890,25 @@ ngtcp2_duration ngtcp2_conn_compute_pto(ngtcp2_conn *conn, return conn_compute_pto(conn, pktns); } +/* + * conn_compute_pv_timeout_pto returns path validation timeout using + * the given |pto|. + */ +static ngtcp2_duration conn_compute_pv_timeout_pto(ngtcp2_conn *conn, + ngtcp2_duration pto) { + ngtcp2_duration initial_pto = conn_compute_initial_pto(conn, &conn->pktns); + + return 3 * ngtcp2_max(pto, initial_pto); +} + +/* + * conn_compute_pv_timeout returns path validation timeout. + */ +static ngtcp2_duration conn_compute_pv_timeout(ngtcp2_conn *conn) { + return conn_compute_pv_timeout_pto(conn, + conn_compute_pto(conn, &conn->pktns)); +} + static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint16_t *prtb_entry_flags, ngtcp2_pktns *pktns, const ngtcp2_pkt_hd *hd, ngtcp2_tstamp ts) { @@ -959,7 +972,7 @@ static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_ECN_STATE_FAILED: break; default: - assert(0); + ngtcp2_unreachable(); } } @@ -989,14 +1002,14 @@ static void conn_reset_ecn_validation_state(ngtcp2_conn *conn) { pktns->tx.ecn.validation_pkt_lost = 0; } -/* server_default_other_versions is the default other_versions field - sent by server. */ -static uint8_t server_default_other_versions[] = {0, 0, 0, 1}; +/* server_default_available_versions is the default available_versions + field sent by server. */ +static uint8_t server_default_available_versions[] = {0, 0, 0, 1}; /* - * other_versions_new allocates new buffer, and writes |versions| of - * length |versionslen| in network byte order, suitable for sending in - * other_versions field of version_information QUIC transport + * available_versions_new allocates new buffer, and writes |versions| + * of length |versionslen| in network byte order, suitable for sending + * in available_versions field of version_information QUIC transport * parameter. The pointer to the allocated buffer is assigned to * |*pbuf|. * @@ -1006,8 +1019,8 @@ static uint8_t server_default_other_versions[] = {0, 0, 0, 1}; * NGTCP2_ERR_NOMEM * Out of memory. */ -static int other_versions_new(uint8_t **pbuf, const uint32_t *versions, - size_t versionslen, const ngtcp2_mem *mem) { +static int available_versions_new(uint8_t **pbuf, const uint32_t *versions, + size_t versionslen, const ngtcp2_mem *mem) { size_t i; uint8_t *buf = ngtcp2_mem_malloc(mem, sizeof(uint32_t) * versionslen); @@ -1032,16 +1045,13 @@ conn_set_local_transport_params(ngtcp2_conn *conn, *p = *params; - /* grease_quic_bit is always enabled. */ - p->grease_quic_bit = 1; - if (conn->server) { p->version_info.chosen_version = chosen_version; } else { p->version_info.chosen_version = conn->client_chosen_version; } - p->version_info.other_versions = conn->vneg.other_versions; - p->version_info.other_versionslen = conn->vneg.other_versionslen; + p->version_info.available_versions = conn->vneg.available_versions; + p->version_info.available_versionslen = conn->vneg.available_versionslen; p->version_info_present = 1; } @@ -1059,19 +1069,33 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, uint8_t fixed_bit_byte; size_t i; uint32_t *preferred_versions; + ngtcp2_transport_params paramsbuf; (void)callbacks_version; (void)settings_version; - (void)transport_params_version; + + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); assert(settings->max_window <= NGTCP2_MAX_VARINT); assert(settings->max_stream_window <= NGTCP2_MAX_VARINT); - assert(settings->max_udp_payload_size); - assert(settings->max_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE); + assert(settings->max_tx_udp_payload_size); + assert(settings->max_tx_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE); + assert(settings->initial_pkt_num <= INT32_MAX); + assert(params->active_connection_id_limit >= + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT); assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); assert(params->initial_max_data <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_bidi_local <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_bidi_remote <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_uni <= NGTCP2_MAX_VARINT); + assert((server && params->original_dcid_present) || + (!server && !params->original_dcid_present)); + assert(!params->initial_scid_present); + assert(server || !params->stateless_reset_token_present); + assert(server || !params->preferred_addr_present); + assert(server || !params->retry_scid_present); + assert(params->max_idle_timeout != UINT64_MAX); + assert(params->max_ack_delay < (1 << 14) * NGTCP2_MILLISECONDS); assert(server || callbacks->client_initial); assert(!server || callbacks->recv_client_initial); assert(callbacks->recv_crypto_data); @@ -1097,6 +1121,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_conn; } + (*pconn)->server = server; + ngtcp2_objalloc_frame_chain_init(&(*pconn)->frc_objalloc, 64, mem); ngtcp2_objalloc_rtb_entry_init(&(*pconn)->rtb_entry_objalloc, 64, mem); ngtcp2_objalloc_strm_init(&(*pconn)->strm_objalloc, 64, mem); @@ -1125,7 +1151,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_log_init(&(*pconn)->log, scid, settings->log_printf, settings->initial_ts, user_data); - ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog.write, settings->initial_ts, + ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog_write, settings->initial_ts, user_data); if ((*pconn)->qlog.write) { buf = ngtcp2_mem_malloc(mem, NGTCP2_QLOG_BUFLEN); @@ -1138,17 +1164,16 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.settings = *settings; - if (settings->token.len) { - buf = ngtcp2_mem_malloc(mem, settings->token.len); + if (settings->tokenlen) { + buf = ngtcp2_mem_malloc(mem, settings->tokenlen); if (buf == NULL) { rv = NGTCP2_ERR_NOMEM; goto fail_token; } - memcpy(buf, settings->token.base, settings->token.len); - (*pconn)->local.settings.token.base = buf; + memcpy(buf, settings->token, settings->tokenlen); + (*pconn)->local.settings.token = buf; } else { - (*pconn)->local.settings.token.base = NULL; - (*pconn)->local.settings.token.len = 0; + (*pconn)->local.settings.token = NULL; } if (!(*pconn)->local.settings.original_version) { @@ -1157,8 +1182,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, conn_reset_conn_stat(*pconn, &(*pconn)->cstat); (*pconn)->cstat.initial_rtt = settings->initial_rtt; - (*pconn)->cstat.max_udp_payload_size = - (*pconn)->local.settings.max_udp_payload_size; + (*pconn)->cstat.max_tx_udp_payload_size = + (*pconn)->local.settings.max_tx_udp_payload_size; ngtcp2_rst_init(&(*pconn)->rst); @@ -1166,54 +1191,43 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, switch (settings->cc_algo) { case NGTCP2_CC_ALGO_RENO: - rv = ngtcp2_cc_reno_cc_init(&(*pconn)->cc, &(*pconn)->log, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log); + break; case NGTCP2_CC_ALGO_CUBIC: - rv = ngtcp2_cc_cubic_cc_init(&(*pconn)->cc, &(*pconn)->log, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log); + break; case NGTCP2_CC_ALGO_BBR: - rv = ngtcp2_cc_bbr_cc_init(&(*pconn)->cc, &(*pconn)->log, &(*pconn)->cstat, - &(*pconn)->rst, settings->initial_ts, - callbacks->rand, &settings->rand_ctx, mem); - if (rv != 0) { - goto fail_cc_init; - } - break; - case NGTCP2_CC_ALGO_BBR2: - rv = ngtcp2_cc_bbr2_cc_init(&(*pconn)->cc, &(*pconn)->log, &(*pconn)->cstat, - &(*pconn)->rst, settings->initial_ts, - callbacks->rand, &settings->rand_ctx, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_bbr_init(&(*pconn)->bbr, &(*pconn)->log, &(*pconn)->cstat, + &(*pconn)->rst, settings->initial_ts, callbacks->rand, + &settings->rand_ctx); + break; default: - assert(0); + ngtcp2_unreachable(); } rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_in_pktns_init; } rv = pktns_new(&(*pconn)->hs_pktns, NGTCP2_PKTNS_ID_HANDSHAKE, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_hs_pktns_init; } rv = pktns_init(&(*pconn)->pktns, NGTCP2_PKTNS_ID_APPLICATION, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_pktns_init; } @@ -1271,56 +1285,63 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->vneg.preferred_versionslen = settings->preferred_versionslen; } - if (settings->other_versionslen) { + (*pconn)->local.settings.preferred_versions = NULL; + (*pconn)->local.settings.preferred_versionslen = 0; + + if (settings->available_versionslen) { if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) { - for (i = 0; i < settings->other_versionslen; ++i) { - if (settings->other_versions[i] == client_chosen_version) { + for (i = 0; i < settings->available_versionslen; ++i) { + if (settings->available_versions[i] == client_chosen_version) { break; } } - assert(i < settings->other_versionslen); + assert(i < settings->available_versionslen); } - for (i = 0; i < settings->other_versionslen; ++i) { - assert(ngtcp2_is_reserved_version(settings->other_versions[i]) || - ngtcp2_is_supported_version(settings->other_versions[i])); + for (i = 0; i < settings->available_versionslen; ++i) { + assert(ngtcp2_is_reserved_version(settings->available_versions[i]) || + ngtcp2_is_supported_version(settings->available_versions[i])); } - rv = other_versions_new(&buf, settings->other_versions, - settings->other_versionslen, mem); + rv = available_versions_new(&buf, settings->available_versions, + settings->available_versionslen, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = - sizeof(uint32_t) * settings->other_versionslen; + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = + sizeof(uint32_t) * settings->available_versionslen; } else if (server) { if (settings->preferred_versionslen) { - rv = other_versions_new(&buf, settings->preferred_versions, - settings->preferred_versionslen, mem); + rv = available_versions_new(&buf, settings->preferred_versions, + settings->preferred_versionslen, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = sizeof(uint32_t) * settings->preferred_versionslen; } else { - (*pconn)->vneg.other_versions = server_default_other_versions; - (*pconn)->vneg.other_versionslen = sizeof(server_default_other_versions); + (*pconn)->vneg.available_versions = server_default_available_versions; + (*pconn)->vneg.available_versionslen = + sizeof(server_default_available_versions); } } else if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) { - rv = other_versions_new(&buf, &client_chosen_version, 1, mem); + rv = available_versions_new(&buf, &client_chosen_version, 1, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = sizeof(uint32_t); + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = sizeof(uint32_t); } + (*pconn)->local.settings.available_versions = NULL; + (*pconn)->local.settings.available_versionslen = 0; + (*pconn)->client_chosen_version = client_chosen_version; conn_set_local_transport_params(*pconn, params); @@ -1331,8 +1352,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, } (*pconn)->keep_alive.last_ts = UINT64_MAX; + (*pconn)->keep_alive.timeout = UINT64_MAX; - (*pconn)->server = server; (*pconn)->oscid = *scid; (*pconn)->callbacks = *callbacks; (*pconn)->mem = mem; @@ -1341,16 +1362,22 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX; (*pconn)->tx.last_max_data_ts = UINT64_MAX; (*pconn)->tx.pacing.next_ts = UINT64_MAX; + (*pconn)->tx.last_blocked_offset = UINT64_MAX; (*pconn)->early.discard_started_ts = UINT64_MAX; conn_reset_ecn_validation_state(*pconn); - ngtcp2_qlog_start(&(*pconn)->qlog, server ? &settings->qlog.odcid : dcid, - server); + ngtcp2_qlog_start( + &(*pconn)->qlog, + server ? ((*pconn)->local.transport_params.retry_scid_present + ? &(*pconn)->local.transport_params.retry_scid + : &(*pconn)->local.transport_params.original_dcid) + : dcid, + server); return 0; -fail_other_versions: +fail_available_versions: ngtcp2_mem_free(mem, (*pconn)->vneg.preferred_versions); fail_preferred_versions: fail_seqgap_push: @@ -1363,9 +1390,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, fail_hs_pktns_init: pktns_del((*pconn)->in_pktns, mem); fail_in_pktns_init: - cc_del(&(*pconn)->cc, settings->cc_algo, mem); -fail_cc_init: - ngtcp2_mem_free(mem, (*pconn)->local.settings.token.base); + ngtcp2_mem_free(mem, (uint8_t *)(*pconn)->local.settings.token); fail_token: ngtcp2_mem_free(mem, (*pconn)->qlog.buf.begin); fail_qlog_buf: @@ -1432,7 +1457,7 @@ int ngtcp2_conn_server_new_versioned( (*pconn)->local.bidi.next_stream_id = 1; (*pconn)->local.uni.next_stream_id = 3; - if ((*pconn)->local.settings.token.len) { + if ((*pconn)->local.settings.tokenlen) { /* Usage of token lifts amplification limit */ (*pconn)->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; } @@ -1558,13 +1583,13 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { conn_vneg_crypto_free(conn); ngtcp2_mem_free(conn->mem, conn->vneg.preferred_versions); - if (conn->vneg.other_versions != server_default_other_versions) { - ngtcp2_mem_free(conn->mem, conn->vneg.other_versions); + if (conn->vneg.available_versions != server_default_available_versions) { + ngtcp2_mem_free(conn->mem, conn->vneg.available_versions); } ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base); ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_hp_buf.base); - ngtcp2_mem_free(conn->mem, conn->local.settings.token.base); + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token); ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem); @@ -1575,14 +1600,12 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { pktns_del(conn->hs_pktns, conn->mem); pktns_del(conn->in_pktns, conn->mem); - cc_del(&conn->cc, conn->cc_algo, conn->mem); - ngtcp2_mem_free(conn->mem, conn->qlog.buf.begin); ngtcp2_pmtud_del(conn->pmtud); ngtcp2_pv_del(conn->pv); - ngtcp2_mem_free(conn->mem, conn->rx.ccerr.reason); + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->rx.ccerr.reason); ngtcp2_idtr_free(&conn->remote.uni.idtr); ngtcp2_idtr_free(&conn->remote.bidi.idtr); @@ -1604,8 +1627,8 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { } /* - * conn_ensure_ack_blks makes sure that conn->tx.ack->ack.blks can - * contain at least |n| additional ngtcp2_ack_blk. + * conn_ensure_ack_ranges makes sure that conn->tx.ack->ack.ranges can + * contain at least |n| additional ngtcp2_ack_range. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1613,9 +1636,9 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { * NGTCP2_ERR_NOMEM * Out of memory. */ -static int conn_ensure_ack_blks(ngtcp2_conn *conn, size_t n) { +static int conn_ensure_ack_ranges(ngtcp2_conn *conn, size_t n) { ngtcp2_frame *fr; - size_t max = conn->tx.max_ack_blks; + size_t max = conn->tx.max_ack_ranges; if (n <= max) { return 0; @@ -1626,13 +1649,13 @@ static int conn_ensure_ack_blks(ngtcp2_conn *conn, size_t n) { assert(max >= n); fr = ngtcp2_mem_realloc(conn->mem, conn->tx.ack, - sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_blk) * max); + sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * max); if (fr == NULL) { return NGTCP2_ERR_NOMEM; } conn->tx.ack = fr; - conn->tx.max_ack_blks = max; + conn->tx.max_ack_ranges = max; return 0; } @@ -1646,40 +1669,20 @@ static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) { conn->cstat.smoothed_rtt / 8); } -/* - * conn_create_ack_frame creates ACK frame, and assigns its pointer to - * |*pfr| if there are any received packets to acknowledge. If there - * are no packets to acknowledge, this function returns 0, and |*pfr| - * is untouched. The caller is advised to set |*pfr| to NULL before - * calling this function, and check it after this function returns. - * If |nodelay| is nonzero, delayed ACK timer is ignored. - * - * The memory for ACK frame is dynamically allocated by this function. - * A caller is responsible to free it. - * - * Call ngtcp2_acktr_commit_ack after a created ACK frame is - * successfully serialized into a packet. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, +int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, ngtcp2_pktns *pktns, uint8_t type, ngtcp2_tstamp ts, ngtcp2_duration ack_delay, uint64_t ack_delay_exponent) { /* TODO Measure an actual size of ACK blocks to find the best default value. */ - const size_t initial_max_ack_blks = 8; + const size_t initial_max_ack_ranges = 8; int64_t last_pkt_num; ngtcp2_acktr *acktr = &pktns->acktr; - ngtcp2_ack_blk *blk; + ngtcp2_ack_range *range; ngtcp2_ksl_it it; ngtcp2_acktr_entry *rpkt; ngtcp2_ack *ack; - size_t blk_idx; + size_t range_idx; ngtcp2_tstamp largest_ack_ts; int rv; @@ -1700,11 +1703,11 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, if (conn->tx.ack == NULL) { conn->tx.ack = ngtcp2_mem_malloc( conn->mem, - sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_blk) * initial_max_ack_blks); + sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * initial_max_ack_ranges); if (conn->tx.ack == NULL) { return NGTCP2_ERR_NOMEM; } - conn->tx.max_ack_blks = initial_max_ack_blks; + conn->tx.max_ack_ranges = initial_max_ack_ranges; } ack = &conn->tx.ack->ack; @@ -1717,7 +1720,7 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, } else { ack->type = NGTCP2_FRAME_ACK; } - ack->num_blks = 0; + ack->rangecnt = 0; rpkt = ngtcp2_ksl_it_get(&it); @@ -1725,7 +1728,14 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); largest_ack_ts = rpkt->tstamp; ack->largest_ack = rpkt->pkt_num; - ack->first_ack_blklen = rpkt->len - 1; + ack->first_ack_range = rpkt->len - 1; + + ngtcp2_ksl_it_next(&it); + } else if (rpkt->pkt_num + 1 == pktns->rx.max_pkt_num) { + last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); + largest_ack_ts = pktns->rx.max_pkt_ts; + ack->largest_ack = pktns->rx.max_pkt_num; + ack->first_ack_range = rpkt->len; ngtcp2_ksl_it_next(&it); } else { @@ -1734,7 +1744,7 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, last_pkt_num = pktns->rx.max_pkt_num; largest_ack_ts = pktns->rx.max_pkt_ts; ack->largest_ack = pktns->rx.max_pkt_num; - ack->first_ack_blklen = 0; + ack->first_ack_range = 0; } if (type == NGTCP2_PKT_1RTT) { @@ -1747,21 +1757,21 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, } for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { - if (ack->num_blks == NGTCP2_MAX_ACK_BLKS) { + if (ack->rangecnt == NGTCP2_MAX_ACK_RANGES) { break; } rpkt = ngtcp2_ksl_it_get(&it); - blk_idx = ack->num_blks++; - rv = conn_ensure_ack_blks(conn, ack->num_blks); + range_idx = ack->rangecnt++; + rv = conn_ensure_ack_ranges(conn, ack->rangecnt); if (rv != 0) { return rv; } ack = &conn->tx.ack->ack; - blk = &ack->blks[blk_idx]; - blk->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2); - blk->blklen = rpkt->len - 1; + range = &ack->ranges[range_idx]; + range->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2); + range->len = rpkt->len - 1; last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); } @@ -1888,7 +1898,7 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { */ static uint64_t conn_get_cwnd(ngtcp2_conn *conn) { return conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) - ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_udp_payload_size) + ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_tx_udp_payload_size) : conn->cstat.cwnd; } @@ -1896,12 +1906,12 @@ static uint64_t conn_get_cwnd(ngtcp2_conn *conn) { * conn_cwnd_is_zero returns nonzero if the number of bytes the local * endpoint can sent at this time is zero. */ -static uint64_t conn_cwnd_is_zero(ngtcp2_conn *conn) { +static int conn_cwnd_is_zero(ngtcp2_conn *conn) { uint64_t bytes_in_flight = conn->cstat.bytes_in_flight; uint64_t cwnd = conn_get_cwnd(conn); if (bytes_in_flight >= cwnd) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "cwnd limited bytes_in_flight=%lu cwnd=%lu", bytes_in_flight, cwnd); } @@ -1943,349 +1953,6 @@ static uint64_t conn_retry_early_payloadlen(ngtcp2_conn *conn) { return 0; } -static void conn_cryptofrq_clear(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { - ngtcp2_frame_chain *frc; - ngtcp2_ksl_it it; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - } - ngtcp2_ksl_clear(&pktns->crypto.tx.frq); -} - -/* - * conn_cryptofrq_unacked_offset returns the CRYPTO frame offset by - * taking into account acknowledged offset. If there is no data to - * send, this function returns (uint64_t)-1. - */ -static uint64_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn, - ngtcp2_pktns *pktns) { - ngtcp2_frame_chain *frc; - ngtcp2_crypto *fr; - ngtcp2_range gap; - ngtcp2_rtb *rtb = &pktns->rtb; - ngtcp2_ksl_it it; - uint64_t datalen; - - (void)conn; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - fr = &frc->fr.crypto; - - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset); - - datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - - if (gap.begin <= fr->offset) { - return fr->offset; - } - if (gap.begin < fr->offset + datalen) { - return gap.begin; - } - } - - return (uint64_t)-1; -} - -static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc) { - ngtcp2_frame_chain *frc, *nfrc; - ngtcp2_crypto *fr, *nfr; - uint64_t offset, end_offset; - size_t idx, end_idx; - uint64_t base_offset, end_base_offset; - ngtcp2_range gap; - ngtcp2_rtb *rtb = &pktns->rtb; - ngtcp2_vec *v; - int rv; - ngtcp2_ksl_it it; - - *pfrc = NULL; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it);) { - frc = ngtcp2_ksl_it_get(&it); - fr = &frc->fr.crypto; - - ngtcp2_ksl_remove_hint(&pktns->crypto.tx.frq, &it, &it, &fr->offset); - - idx = 0; - offset = fr->offset; - base_offset = 0; - - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, offset); - if (gap.begin < offset) { - gap.begin = offset; - } - - for (; idx < fr->datacnt && offset < gap.begin; ++idx) { - v = &fr->data[idx]; - if (offset + v->len > gap.begin) { - base_offset = gap.begin - offset; - break; - } - - offset += v->len; - } - - if (idx == fr->datacnt) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - continue; - } - - assert(gap.begin == offset + base_offset); - - end_idx = idx; - end_offset = offset; - end_base_offset = 0; - - for (; end_idx < fr->datacnt; ++end_idx) { - v = &fr->data[end_idx]; - if (end_offset + v->len > gap.end) { - end_base_offset = gap.end - end_offset; - break; - } - - end_offset += v->len; - } - - if (fr->offset == offset && base_offset == 0 && fr->datacnt == end_idx) { - *pfrc = frc; - return 0; - } - - if (fr->datacnt == end_idx) { - memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx)); - - assert(fr->data[0].len > base_offset); - - fr->offset = offset + base_offset; - fr->datacnt = end_idx - idx; - fr->data[0].base += base_offset; - fr->data[0].len -= (size_t)base_offset; - - *pfrc = frc; - return 0; - } - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, fr->datacnt - end_idx, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - nfr->type = NGTCP2_FRAME_CRYPTO; - memcpy(nfr->data, fr->data + end_idx, - sizeof(nfr->data[0]) * (fr->datacnt - end_idx)); - - assert(nfr->data[0].len > end_base_offset); - - nfr->offset = end_offset + end_base_offset; - nfr->datacnt = fr->datacnt - end_idx; - nfr->data[0].base += end_base_offset; - nfr->data[0].len -= (size_t)end_base_offset; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - if (end_base_offset) { - ++end_idx; - } - - memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx)); - - assert(fr->data[0].len > base_offset); - - fr->offset = offset + base_offset; - fr->datacnt = end_idx - idx; - if (end_base_offset) { - assert(fr->data[fr->datacnt - 1].len > end_base_offset); - fr->data[fr->datacnt - 1].len = (size_t)end_base_offset; - } - fr->data[0].base += base_offset; - fr->data[0].len -= (size_t)base_offset; - - *pfrc = frc; - return 0; - } - - return 0; -} -static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, - ngtcp2_pktns *pktns, size_t left) { - ngtcp2_crypto *fr, *nfr; - ngtcp2_frame_chain *frc, *nfrc; - int rv; - size_t nmerged; - uint64_t datalen; - ngtcp2_vec a[NGTCP2_MAX_CRYPTO_DATACNT]; - ngtcp2_vec b[NGTCP2_MAX_CRYPTO_DATACNT]; - size_t acnt, bcnt; - ngtcp2_ksl_it it; - - rv = conn_cryptofrq_unacked_pop(conn, pktns, &frc); - if (rv != 0) { - return rv; - } - if (frc == NULL) { - *pfrc = NULL; - return 0; - } - - fr = &frc->fr.crypto; - datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - - if (datalen > left) { - ngtcp2_vec_copy(a, fr->data, fr->datacnt); - acnt = fr->datacnt; - - bcnt = 0; - ngtcp2_vec_split(a, &acnt, b, &bcnt, left, NGTCP2_MAX_CRYPTO_DATACNT); - - assert(acnt > 0); - assert(bcnt > 0); - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, bcnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - nfr->type = NGTCP2_FRAME_CRYPTO; - nfr->offset = fr->offset + left; - nfr->datacnt = bcnt; - ngtcp2_vec_copy(nfr->data, b, bcnt); - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, acnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - *nfr = *fr; - nfr->datacnt = acnt; - ngtcp2_vec_copy(nfr->data, a, acnt); - - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - - *pfrc = nfrc; - - return 0; - } - - left -= (size_t)datalen; - - ngtcp2_vec_copy(a, fr->data, fr->datacnt); - acnt = fr->datacnt; - - for (; left && ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { - it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); - nfrc = ngtcp2_ksl_it_get(&it); - nfr = &nfrc->fr.crypto; - - if (nfr->offset != fr->offset + datalen) { - assert(fr->offset + datalen < nfr->offset); - break; - } - - rv = conn_cryptofrq_unacked_pop(conn, pktns, &nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - if (nfrc == NULL) { - break; - } - - nfr = &nfrc->fr.crypto; - - nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &nfr->datacnt, left, - NGTCP2_MAX_CRYPTO_DATACNT); - if (nmerged == 0) { - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - break; - } - - datalen += nmerged; - left -= nmerged; - - if (nfr->datacnt == 0) { - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - continue; - } - - nfr->offset += nmerged; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - break; - } - - if (acnt == fr->datacnt) { - assert(acnt > 0); - fr->data[acnt - 1] = a[acnt - 1]; - - *pfrc = frc; - return 0; - } - - assert(acnt > fr->datacnt); - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, acnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - *nfr = *fr; - nfr->datacnt = acnt; - ngtcp2_vec_copy(nfr->data, a, acnt); - - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - - *pfrc = nfrc; - - return 0; -} - /* * conn_verify_dcid verifies that destination connection ID in |hd| is * valid for the connection. If it is successfully verified and the @@ -2341,7 +2008,7 @@ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used, * conn_should_pad_pkt returns nonzero if the packet should be padded. * |type| is the type of packet. |left| is the space left in packet * buffer. |write_datalen| is the number of bytes which will be sent - * in the next, coalesced 0-RTT or 1RTT packet. + * in the next, coalesced 0-RTT packet. */ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, uint64_t write_datalen, int ack_eliciting, @@ -2356,7 +2023,7 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, if (conn->hs_pktns->crypto.tx.ckm && (conn->hs_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) || + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) || !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) { /* If we have something to send in Handshake packet, then add PADDING in Handshake packet. */ @@ -2367,20 +2034,19 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, } else { if (conn->hs_pktns->crypto.tx.ckm && (conn->hs_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) || + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) || !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) { /* If we have something to send in Handshake packet, then add PADDING in Handshake packet. */ min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN; - } else if ((!conn->early.ckm && !conn->pktns.crypto.tx.ckm) || - write_datalen == 0) { - return 1; - } else { - /* If we have something to send in 0RTT or 1RTT packet, then - add PADDING in that packet. Take maximum in case that + } else if (conn->early.ckm && write_datalen > 0) { + /* If we have something to send in 0RTT packet, then add + PADDING in that packet. Take maximum in case that write_datalen includes DATAGRAM which cannot be split. */ min_payloadlen = ngtcp2_max(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); + } else { + return 1; } } } else { @@ -2390,11 +2056,11 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, return 0; } - if (!conn->pktns.crypto.tx.ckm || write_datalen == 0) { + if (!conn->pktns.crypto.tx.ckm) { return 1; } - min_payloadlen = ngtcp2_max(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); + min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN; } /* TODO the next packet type should be taken into account */ @@ -2419,7 +2085,8 @@ static void conn_restart_timer_on_read(ngtcp2_conn *conn, ngtcp2_tstamp ts) { * conn_keep_alive_enabled returns nonzero if keep-alive is enabled. */ static int conn_keep_alive_enabled(ngtcp2_conn *conn) { - return conn->keep_alive.last_ts != UINT64_MAX && conn->keep_alive.timeout; + return conn->keep_alive.last_ts != UINT64_MAX && + conn->keep_alive.timeout != UINT64_MAX; } /* @@ -2427,8 +2094,8 @@ static int conn_keep_alive_enabled(ngtcp2_conn *conn) { * expired. */ static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - return conn_keep_alive_enabled(conn) && - conn->keep_alive.last_ts + conn->keep_alive.timeout <= ts; + return ngtcp2_tstamp_elapsed(conn->keep_alive.last_ts, + conn->keep_alive.timeout, ts); } /* @@ -2436,7 +2103,9 @@ static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { */ static ngtcp2_tstamp conn_keep_alive_expiry(ngtcp2_conn *conn) { if ((conn->flags & NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED) || - !conn_keep_alive_enabled(conn)) { + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || + !conn_keep_alive_enabled(conn) || + conn->keep_alive.last_ts >= UINT64_MAX - conn->keep_alive.timeout) { return UINT64_MAX; } @@ -2467,6 +2136,10 @@ static void conn_update_keep_alive_last_ts(ngtcp2_conn *conn, void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, ngtcp2_duration timeout) { + if (timeout == 0) { + timeout = UINT64_MAX; + } + conn->keep_alive.timeout = timeout; } @@ -2527,7 +2200,7 @@ static uint8_t conn_pkt_flags_short(ngtcp2_conn *conn) { * NGTCP2_PKT_HANDSHAKE_PKT. * * |write_datalen| is the minimum length of application data ready to - * send in subsequent 0RTT or 1RTT packet. + * send in subsequent 0RTT packet. * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -2590,8 +2263,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, cc.hp_ctx = pktns->crypto.tx.hp_ctx; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } cc.aead = pktns->crypto.ctx.aead; @@ -2605,8 +2277,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, version, 0); if (!conn->server && type == NGTCP2_PKT_INITIAL && - conn->local.settings.token.len) { + conn->local.settings.tokenlen) { hd.token = conn->local.settings.token; + hd.tokenlen = conn->local.settings.tokenlen; } ngtcp2_ppe_init(&ppe, dest, destlen, &cc); @@ -2621,9 +2294,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, return 0; } - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, - /* ack_delay = */ 0, - NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); + rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts, + /* ack_delay = */ 0, + NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); if (rv != 0) { ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem); return rv; @@ -2645,12 +2318,12 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, if (!conn->server || type != NGTCP2_PKT_INITIAL || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) { build_pkt: - for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { + for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) { left = ngtcp2_ppe_left(&ppe); - crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); - if (crypto_offset == (size_t)-1) { - conn_cryptofrq_clear(conn, pktns); + crypto_offset = ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm); + if (crypto_offset == (uint64_t)-1) { + ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm); break; } @@ -2659,7 +2332,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, break; } - rv = conn_cryptofrq_pop(conn, &nfrc, pktns, left); + rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, @@ -2673,7 +2346,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -2729,9 +2402,8 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, if (!pkt_empty) { if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { - /* The intention of smaller limit is get more chance to measure - RTT samples in early phase. */ - if (pktns->tx.num_non_ack_pkt >= 1) { + if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts, + conn->cstat.smoothed_rtt, ts)) { lfr.type = NGTCP2_FRAME_PING; rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr); @@ -2739,18 +2411,18 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, assert(rv == NGTCP2_ERR_NOBUF); } else { rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING; - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } - } else { - ++pktns->tx.num_non_ack_pkt; + } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) { + pktns->tx.non_ack_pkt_start_ts = ts; } } else { - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } } } - if (pkt_empty) { + if (pkt_empty && !require_padding) { return 0; } @@ -2762,6 +2434,8 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, require_padding)) { lfr.type = NGTCP2_FRAME_PADDING; lfr.padding.len = ngtcp2_ppe_padding(&ppe); + } else if (pkt_empty) { + return 0; } else { lfr.type = NGTCP2_FRAME_PADDING; lfr.padding.len = ngtcp2_ppe_padding_hp_sample(&ppe); @@ -2872,8 +2546,7 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, ack_delay_exponent = conn->local.transport_params.ack_delay_exponent; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } if (!pktns->crypto.tx.ckm) { @@ -2881,8 +2554,8 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } ackfr = NULL; - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay, - ack_delay_exponent); + rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay, + ack_delay_exponent); if (rv != 0) { return rv; } @@ -2992,11 +2665,11 @@ static ngtcp2_ssize conn_write_handshake_ack_pkts(ngtcp2_conn *conn, ngtcp2_ssize res = 0, nwrite = 0; /* In the most cases, client sends ACK in conn_write_handshake_pkt. - This function is only called when it is CWND limited. It is not - required for client to send ACK for server Initial. This is - because once it gets server Initial, it gets Handshake tx key and - discards Initial key. The only good reason to send ACK is give - server RTT measurement early. */ + This function is only called when it is CWND limited or pacing + limited. It is not required for client to send ACK for server + Initial. This is because once it gets server Initial, it gets + Handshake tx key and discards Initial key. The only good reason + to send ACK is give server RTT measurement early. */ if (conn->server && conn->in_pktns) { nwrite = conn_write_ack_pkt(conn, pi, dest, destlen, NGTCP2_PKT_INITIAL, ts); @@ -3145,13 +2818,14 @@ static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn, } if (nwrite == 0) { - if (conn->server && (conn->in_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->in_pktns->crypto.tx.frq))) { + if (conn->server && + (conn->in_pktns->rtb.probe_pkt_left || + !ngtcp2_strm_streamfrq_empty(&conn->in_pktns->crypto.strm))) { if (cstat->loss_detection_timer != UINT64_MAX && conn_server_tx_left(conn, &conn->dcid.current) < NGTCP2_MAX_UDP_PAYLOAD_SIZE) { ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled due to amplification limit"); cstat->loss_detection_timer = UINT64_MAX; } @@ -3252,11 +2926,19 @@ static int conn_should_send_max_data(ngtcp2_conn *conn) { static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { uint64_t n; size_t len = ngtcp2_ksl_len(&conn->scid.set); + size_t lim; if (len >= NGTCP2_MAX_SCID_POOL_SIZE) { return 0; } + assert(NGTCP2_MAX_SCID_POOL_SIZE >= conn->scid.num_in_flight); + + lim = NGTCP2_MAX_SCID_POOL_SIZE - conn->scid.num_in_flight; + if (lim == 0) { + return 0; + } + assert(conn->remote.transport_params); assert(conn->remote.transport_params->active_connection_id_limit); @@ -3266,7 +2948,9 @@ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { n = conn->remote.transport_params->active_connection_id_limit + conn->scid.num_retired; - return (size_t)ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; + n = ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; + + return (size_t)ngtcp2_min(lim, n); } /* @@ -3338,6 +3022,10 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { sizeof(token)); nfrc->next = pktns->tx.frq; pktns->tx.frq = nfrc; + + assert(NGTCP2_MAX_SCID_POOL_SIZE > conn->scid.num_in_flight); + + ++conn->scid.num_in_flight; } return 0; @@ -3368,7 +3056,7 @@ static int conn_remove_retired_connection_id(ngtcp2_conn *conn, for (; !ngtcp2_pq_empty(&conn->scid.used);) { scid = ngtcp2_struct_of(ngtcp2_pq_top(&conn->scid.used), ngtcp2_scid, pe); - if (scid->retired_ts == UINT64_MAX || scid->retired_ts + timeout >= ts) { + if (!ngtcp2_tstamp_elapsed(scid->retired_ts, timeout, ts)) { break; } @@ -3435,6 +3123,36 @@ static void conn_handle_unconfirmed_key_update_from_remote(ngtcp2_conn *conn, ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed"); } +static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn); + +/* + * strm_should_send_stream_data_blocked returns nonzero if + * STREAM_DATA_BLOCKED frame should be sent to |strm|. + */ +static int strm_should_send_stream_data_blocked(ngtcp2_strm *strm) { + return strm->tx.offset == strm->tx.max_offset && + strm->tx.last_blocked_offset != strm->tx.max_offset; +} + +/* + * conn_should_send_data_blocked returns nonzero if DATA_BLOCKED frame + * should be sent. + */ +static int conn_should_send_data_blocked(ngtcp2_conn *conn) { + return conn->tx.offset == conn->tx.max_offset && + conn->tx.last_blocked_offset != conn->tx.max_offset; +} + +/* + * conn_reset_ppe_pending clears NGTCP2_CONN_FLAG_PPE_PENDING flag and + * nullifies conn->pkt. + */ +static void conn_reset_ppe_pending(ngtcp2_conn *conn) { + conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_PPE_PENDING; + + memset(&conn->pkt, 0, sizeof(conn->pkt)); +} + /* * conn_write_pkt writes a protected packet in the buffer pointed by * |dest| whose length if |destlen|. |type| specifies the type of @@ -3550,8 +3268,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* transport parameter is only valid after handshake completion which means we don't know how many connection ID that remote - peer can accept before handshake completion. */ - if (conn->oscid.datalen && conn_is_handshake_completed(conn)) { + peer can accept before handshake completion. Because server + can use remote transport parameters sending stream data in + 0.5 RTT, it is also allowed to use remote transport + parameters here. */ + if (conn->oscid.datalen && + (conn->server || conn_is_tls_handshake_completed(conn))) { rv = conn_enqueue_new_connection_id(conn); if (rv != 0) { return rv; @@ -3574,7 +3296,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } cc->encrypt = conn->callbacks.encrypt; @@ -3617,6 +3339,32 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, nfrc->fr.max_data.max_data; } + if (stream_blocked && conn_should_send_max_data(conn)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED; + nfrc->fr.data_blocked.offset = conn->tx.max_offset; + nfrc->next = pktns->tx.frq; + pktns->tx.frq = nfrc; + + conn->tx.last_blocked_offset = conn->tx.max_offset; + } + + if (stream_blocked && !ngtcp2_strm_is_tx_queued(vmsg->stream.strm) && + strm_should_send_stream_data_blocked(vmsg->stream.strm)) { + assert(vmsg); + assert(vmsg->type == NGTCP2_VMSG_TYPE_STREAM); + + vmsg->stream.strm->cycle = conn_tx_strmq_first_cycle(conn); + rv = ngtcp2_conn_tx_strmq_push(conn, vmsg->stream.strm); + if (rv != 0) { + return rv; + } + } + ngtcp2_pkt_hd_init(hd, hd_flags, type, &conn->dcid.current.cid, scid, pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), version, 0); @@ -3651,16 +3399,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, pkt_empty = 0; rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING; - require_padding = - !conn->server || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE; + require_padding = require_padding || !conn->server || + destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE; /* We don't retransmit PATH_RESPONSE. */ } } } - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, - conn_compute_ack_delay(conn), - conn->local.transport_params.ack_delay_exponent); + rv = ngtcp2_conn_create_ack_frame( + conn, &ackfr, pktns, type, ts, conn_compute_ack_delay(conn), + conn->local.transport_params.ack_delay_exponent); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); return rv; @@ -3696,29 +3444,17 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_FRAME_STOP_SENDING: strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.stop_sending.stream_id); - if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD)) { + if (strm == NULL || + ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset)) { frc = *pfrc; *pfrc = (*pfrc)->next; ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); continue; } - - if (!(strm->flags & NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED)) { - strm->flags |= NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED; - - rv = conn_call_stream_stop_sending( - conn, (*pfrc)->fr.stop_sending.stream_id, - (*pfrc)->fr.stop_sending.app_error_code, strm->stream_user_data); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } - } - break; case NGTCP2_FRAME_STREAM: - assert(0); - break; + ngtcp2_unreachable(); case NGTCP2_FRAME_MAX_STREAMS_BIDI: if ((*pfrc)->fr.max_streams.max_streams < conn->remote.bidi.max_streams) { @@ -3740,7 +3476,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_FRAME_MAX_STREAM_DATA: strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.max_stream_data.stream_id); - if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) || + if (strm == NULL || + (strm->flags & + (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) || (*pfrc)->fr.max_stream_data.max_stream_data < strm->rx.max_offset) { frc = *pfrc; *pfrc = (*pfrc)->next; @@ -3756,9 +3494,27 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, continue; } break; - case NGTCP2_FRAME_CRYPTO: - assert(0); + case NGTCP2_FRAME_STREAM_DATA_BLOCKED: + strm = ngtcp2_conn_find_stream( + conn, (*pfrc)->fr.stream_data_blocked.stream_id); + if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) || + (*pfrc)->fr.stream_data_blocked.offset != strm->tx.max_offset) { + frc = *pfrc; + *pfrc = (*pfrc)->next; + ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); + continue; + } + break; + case NGTCP2_FRAME_DATA_BLOCKED: + if ((*pfrc)->fr.data_blocked.offset != conn->tx.max_offset) { + frc = *pfrc; + *pfrc = (*pfrc)->next; + ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); + continue; + } break; + case NGTCP2_FRAME_CRYPTO: + ngtcp2_unreachable(); } rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); @@ -3774,13 +3530,14 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, pfrc = &(*pfrc)->next; } - if (rv != NGTCP2_ERR_NOBUF) { - for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { + if (*pfrc == NULL) { + for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) { left = ngtcp2_ppe_left(ppe); - crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); - if (crypto_offset == (size_t)-1) { - conn_cryptofrq_clear(conn, pktns); + crypto_offset = + ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm); + if (crypto_offset == (uint64_t)-1) { + ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm); break; } @@ -3790,7 +3547,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, break; } - rv = conn_cryptofrq_pop(conn, &nfrc, pktns, left); + rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); return rv; @@ -3802,7 +3559,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -3815,79 +3572,114 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } } - /* Write MAX_STREAM_ID after RESET_STREAM so that we can extend stream - ID space in one packet. */ - if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL && - conn->remote.bidi.unsent_max_streams > conn->remote.bidi.max_streams) { - rv = conn_call_extend_max_remote_streams_bidi( - conn, conn->remote.bidi.unsent_max_streams); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } + if (*pfrc == NULL) { + for (; !ngtcp2_pq_empty(&conn->tx.strmq);) { + strm = ngtcp2_conn_tx_strmq_top(conn); - rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } - nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI; - nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams; - *pfrc = nfrc; + if (strm->flags & NGTCP2_STRM_FLAG_SEND_RESET_STREAM) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } - conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams; + nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM; + nfrc->fr.reset_stream.stream_id = strm->stream_id; + nfrc->fr.reset_stream.app_error_code = + strm->tx.reset_stream_app_error_code; + nfrc->fr.reset_stream.final_size = strm->tx.offset; + *pfrc = nfrc; - rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { - pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | - NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | - NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; - pfrc = &(*pfrc)->next; - } - } + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM; - if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL) { - if (conn->remote.uni.unsent_max_streams > conn->remote.uni.max_streams) { - rv = conn_call_extend_max_remote_streams_uni( - conn, conn->remote.uni.unsent_max_streams); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; + rv = + conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; } - rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; + if (strm->flags & NGTCP2_STRM_FLAG_SEND_STOP_SENDING) { + if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) { + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + } else { + rv = conn_call_stream_stop_sending( + conn, strm->stream_id, strm->tx.stop_sending_app_error_code, + strm->stream_user_data); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING; + nfrc->fr.stop_sending.stream_id = strm->stream_id; + nfrc->fr.stop_sending.app_error_code = + strm->tx.stop_sending_app_error_code; + *pfrc = nfrc; + + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, + &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } } - nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI; - nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams; - *pfrc = nfrc; - conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams; + if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) && + strm_should_send_stream_data_blocked(strm)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; + nfrc->fr.stream_data_blocked.stream_id = strm->stream_id; + nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset; + *pfrc = nfrc; + + strm->tx.last_blocked_offset = strm->tx.max_offset; + + rv = + conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } - rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, - &(*pfrc)->fr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { pkt_empty = 0; rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; } - } - } - - if (rv != NGTCP2_ERR_NOBUF) { - for (; !ngtcp2_pq_empty(&conn->tx.strmq);) { - strm = ngtcp2_conn_tx_strmq_top(conn); - if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + if (!(strm->flags & + (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) && conn_should_send_max_stream_data(conn, strm)) { rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); if (rv != 0) { @@ -3922,7 +3714,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, nfrc->fr.max_stream_data.stream_id = strm->stream_id; nfrc->fr.max_stream_data.max_stream_data = strm->rx.unsent_max_offset + delta; - ngtcp2_list_insert(nfrc, pfrc); + *pfrc = nfrc; + + strm->rx.max_offset = strm->rx.unsent_max_offset = + nfrc->fr.max_stream_data.max_stream_data; rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); @@ -3936,8 +3731,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; - strm->rx.max_offset = strm->rx.unsent_max_offset = - nfrc->fr.max_stream_data.max_stream_data; } if (ngtcp2_strm_streamfrq_empty(strm)) { @@ -3949,8 +3742,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (stream_offset == (uint64_t)-1) { ngtcp2_strm_streamfrq_clear(strm); ngtcp2_conn_tx_strmq_pop(conn); - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; continue; } @@ -3976,7 +3767,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -3989,8 +3780,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (ngtcp2_strm_streamfrq_empty(strm)) { ngtcp2_conn_tx_strmq_pop(conn); - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; continue; } @@ -4004,10 +3793,75 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } } - if (rv != NGTCP2_ERR_NOBUF && !send_stream && !send_datagram && + /* Write MAX_STREAMS after RESET_STREAM so that we can extend + stream ID space in one packet. */ + if (*pfrc == NULL && + conn->remote.bidi.unsent_max_streams > conn->remote.bidi.max_streams) { + rv = conn_call_extend_max_remote_streams_bidi( + conn, conn->remote.bidi.unsent_max_streams); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI; + nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams; + *pfrc = nfrc; + + conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + } else { + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } + } + + if (*pfrc == NULL && + conn->remote.uni.unsent_max_streams > conn->remote.uni.max_streams) { + rv = conn_call_extend_max_remote_streams_uni( + conn, conn->remote.uni.unsent_max_streams); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI; + nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams; + *pfrc = nfrc; + + conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + } else { + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } + } + + if (pktns->tx.frq == NULL && !send_stream && !send_datagram && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) && - pktns->rtb.num_retransmittable && pktns->tx.frq == NULL && - pktns->rtb.probe_pkt_left) { + pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) { num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1); if (num_reclaimed < 0) { return rv; @@ -4016,15 +3870,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, goto build_pkt; } - /* We had pktns->rtb.num_retransmittable > 0 but the contents of - those packets have been acknowledged (i.e., retransmission in - another packet). In this case, we don't have to send any - probe packet. */ + /* We had pktns->rtb.num_retransmittable > 0 but we were unable + to reclaim any frame. In this case, we do not have to send + any probe packet. */ if (pktns->rtb.num_pto_eliciting == 0) { pktns->rtb.probe_pkt_left = 0; ngtcp2_conn_set_loss_detection_timer(conn, ts); - /* TODO If packet is empty, we should return now if cwnd is - zero. */ + + if (pkt_empty && conn_cwnd_is_zero(conn) && !require_padding) { + return 0; + } } } } else { @@ -4036,7 +3891,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, left = ngtcp2_ppe_left(ppe); - if (rv != NGTCP2_ERR_NOBUF && send_stream && *pfrc == NULL && + if (*pfrc == NULL && send_stream && (ndatalen = ngtcp2_pkt_stream_max_datalen( vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen, left)) != (size_t)-1 && @@ -4068,7 +3923,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -4093,7 +3948,83 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, send_stream = 0; } - if (rv != NGTCP2_ERR_NOBUF && send_datagram && + if (vmsg && vmsg->type == NGTCP2_VMSG_TYPE_STREAM && + ((stream_blocked && *pfrc == NULL) || + (send_stream && + !(vmsg->stream.strm->flags & NGTCP2_STRM_FLAG_SHUT_WR)))) { + if (conn_should_send_data_blocked(conn)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED; + nfrc->fr.data_blocked.offset = conn->tx.offset; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + /* We cannot add nfrc to pktns->tx.frq here. */ + ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); + } else { + *pfrc = nfrc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + + conn->tx.last_blocked_offset = conn->tx.max_offset; + } + } + + strm = vmsg->stream.strm; + + if (strm_should_send_stream_data_blocked(strm)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; + nfrc->fr.stream_data_blocked.stream_id = strm->stream_id; + nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + /* We cannot add nfrc to pktns->tx.frq here. */ + ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); + + if (!ngtcp2_strm_is_tx_queued(strm)) { + strm->cycle = conn_tx_strmq_first_cycle(conn); + rv = ngtcp2_conn_tx_strmq_push(conn, strm); + if (rv != 0) { + return rv; + } + } + } else { + *pfrc = nfrc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + + strm->tx.last_blocked_offset = strm->tx.max_offset; + } + } + } + + if (*pfrc == NULL && send_datagram && left >= ngtcp2_pkt_datagram_framelen((size_t)datalen)) { if (conn->callbacks.ack_datagram || conn->callbacks.lost_datagram) { rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); @@ -4129,8 +4060,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } pkt_empty = 0; - rtb_entry_flags |= - NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_DATAGRAM; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_DATAGRAM; if (vmsg->datagram.paccepted) { *vmsg->datagram.paccepted = 1; @@ -4140,14 +4072,27 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } if (pkt_empty) { - assert(rv == 0 || NGTCP2_ERR_NOBUF == rv); - if (rv == 0 && stream_blocked && ngtcp2_conn_get_max_data_left(conn)) { + if (*pfrc == NULL && rv == 0 && stream_blocked && + (write_more || !require_padding) && + ngtcp2_conn_get_max_data_left(conn)) { + if (write_more) { + conn->pkt.pfrc = pfrc; + conn->pkt.pkt_empty = pkt_empty; + conn->pkt.rtb_entry_flags = rtb_entry_flags; + conn->pkt.hd_logged = hd_logged; + conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING; + } + return NGTCP2_ERR_STREAM_DATA_BLOCKED; } - keep_alive_expired = conn_keep_alive_expired(conn, ts); + keep_alive_expired = + type == NGTCP2_PKT_1RTT && conn_keep_alive_expired(conn, ts); + + if (conn->pktns.rtb.probe_pkt_left == 0 && !keep_alive_expired && + !require_padding) { + conn_reset_ppe_pending(conn); - if (conn->pktns.rtb.probe_pkt_left == 0 && !keep_alive_expired) { return 0; } } else if (write_more) { @@ -4165,7 +4110,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (ngtcp2_ppe_left(ppe)) { return NGTCP2_ERR_WRITE_MORE; } - } else if (ngtcp2_conn_get_max_data_left(conn) && stream_blocked) { + break; + } + + if (*pfrc == NULL && ngtcp2_conn_get_max_data_left(conn) && + stream_blocked) { return NGTCP2_ERR_STREAM_DATA_BLOCKED; } break; @@ -4178,12 +4127,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, calls ngtcp2_conn_writev_datagram again. */ break; default: - assert(0); + ngtcp2_unreachable(); } } if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { - if (pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT || + if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts, + cstat->smoothed_rtt, ts) || keep_alive_expired || conn->pktns.rtb.probe_pkt_left) { lfr.type = NGTCP2_FRAME_PING; @@ -4197,13 +4147,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (conn->pktns.rtb.probe_pkt_left) { rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PROBE; } - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } - } else { - ++pktns->tx.num_non_ack_pkt; + } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) { + pktns->tx.non_ack_pkt_start_ts = ts; } } else { - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } /* TODO Push STREAM frame back to ngtcp2_strm if there is an error @@ -4212,8 +4162,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* Making full sized packet will help GSO a bit */ ngtcp2_ppe_left(ppe) < 10) { lfr.padding.len = ngtcp2_ppe_padding(ppe); - } else { + } else if (type == NGTCP2_PKT_1RTT) { lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen); + } else { + lfr.padding.len = ngtcp2_ppe_padding_hp_sample(ppe); } if (lfr.padding.len) { @@ -4285,7 +4237,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts); } - conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_PPE_PENDING; + conn_reset_ppe_pending(conn); if (pktns->rtb.probe_pkt_left && (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { @@ -4360,8 +4312,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( break; default: /* We don't support 0-RTT packet in this function. */ - assert(0); - abort(); + ngtcp2_unreachable(); } cc.aead = pktns->crypto.ctx.aead; @@ -4448,7 +4399,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( if (((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) && (!path || ngtcp2_path_eq(&conn->dcid.current.ps.path, path))) { - if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE)) { + if (pi && (conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE || + !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE))) { conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, &hd, ts); } @@ -4479,8 +4431,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( nwrite); } } - } else if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) && - conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { + } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { conn_handle_tx_ecn(conn, pi, NULL, pktns, &hd, ts); } @@ -4488,7 +4439,17 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( conn_update_keep_alive_last_ts(conn, ts); } - conn->tx.pacing.pktlen += (size_t)nwrite; + if (!padded) { + switch (fr->type) { + case NGTCP2_FRAME_ACK: + case NGTCP2_FRAME_ACK_ECN: + break; + default: + conn->tx.pacing.pktlen += (size_t)nwrite; + } + } else { + conn->tx.pacing.pktlen += (size_t)nwrite; + } ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); @@ -4529,11 +4490,11 @@ static int conn_handshake_remnants_left(ngtcp2_conn *conn) { ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; - return !conn_is_handshake_completed(conn) || + return !conn_is_tls_handshake_completed(conn) || (in_pktns && (in_pktns->rtb.num_pto_eliciting || - ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) || + !ngtcp2_strm_streamfrq_empty(&in_pktns->crypto.strm))) || (hs_pktns && (hs_pktns->rtb.num_pto_eliciting || - ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq))); + !ngtcp2_strm_streamfrq_empty(&hs_pktns->crypto.strm))); } /* @@ -4684,14 +4645,14 @@ static int conn_start_pmtud(ngtcp2_conn *conn) { assert(!conn->local.settings.no_pmtud); assert(!conn->pmtud); - assert(conn_is_handshake_completed(conn)); + assert(conn_is_tls_handshake_completed(conn)); assert(conn->remote.transport_params); assert(conn->remote.transport_params->max_udp_payload_size >= NGTCP2_MAX_UDP_PAYLOAD_SIZE); - hard_max_udp_payload_size = - (size_t)ngtcp2_min(conn->remote.transport_params->max_udp_payload_size, - (uint64_t)conn->local.settings.max_udp_payload_size); + hard_max_udp_payload_size = (size_t)ngtcp2_min( + conn->remote.transport_params->max_udp_payload_size, + (uint64_t)conn->local.settings.max_tx_udp_payload_size); rv = ngtcp2_pmtud_new(&conn->pmtud, conn->dcid.current.max_udp_payload_size, hard_max_udp_payload_size, @@ -4850,9 +4811,9 @@ static size_t conn_shape_udp_payload(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, } payloadlen = - ngtcp2_min(payloadlen, conn->local.settings.max_udp_payload_size); + ngtcp2_min(payloadlen, conn->local.settings.max_tx_udp_payload_size); - if (conn->local.settings.no_udp_payload_size_shaping) { + if (conn->local.settings.no_tx_udp_payload_size_shaping) { return payloadlen; } @@ -4885,10 +4846,6 @@ static int conn_on_path_validation_failed(ngtcp2_conn *conn, ngtcp2_pv *pv, } } - if (pv->flags & NGTCP2_PV_FLAG_MTU_PROBE) { - return NGTCP2_ERR_NO_VIABLE_PATH; - } - if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { ngtcp2_dcid_copy(&conn->dcid.current, &pv->fallback_dcid); conn_reset_congestion_state(conn, ts); @@ -4918,7 +4875,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, ngtcp2_tstamp expiry; ngtcp2_pv *pv = conn->pv; ngtcp2_frame lfr; - ngtcp2_duration timeout; + ngtcp2_duration timeout, initial_pto; uint8_t flags; uint64_t tx_left; int rv; @@ -4953,8 +4910,9 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, lfr.type = NGTCP2_FRAME_PATH_CHALLENGE; + initial_pto = conn_compute_initial_pto(conn, &conn->pktns); timeout = conn_compute_pto(conn, &conn->pktns); - timeout = ngtcp2_max(timeout, 3 * conn->cstat.initial_rtt); + timeout = ngtcp2_max(timeout, initial_pto); expiry = ts + timeout * (1ULL << pv->round); destlen = ngtcp2_min(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); @@ -5216,75 +5174,6 @@ uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { return strm->cycle; } -int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc) { - ngtcp2_frame_chain **first = pfrc; - ngtcp2_frame_chain *frc; - ngtcp2_stream *sfr; - ngtcp2_strm *strm; - int rv; - int streamfrq_empty; - - if (*pfrc == NULL) { - return 0; - } - - for (; *pfrc;) { - switch ((*pfrc)->fr.type) { - case NGTCP2_FRAME_STREAM: - frc = *pfrc; - - *pfrc = frc->next; - frc->next = NULL; - sfr = &frc->fr.stream; - - strm = ngtcp2_conn_find_stream(conn, sfr->stream_id); - if (!strm) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - break; - } - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); - rv = ngtcp2_strm_streamfrq_push(strm, frc); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - if (!ngtcp2_strm_is_tx_queued(strm)) { - strm->cycle = conn_tx_strmq_first_cycle(conn); - rv = ngtcp2_conn_tx_strmq_push(conn, strm); - if (rv != 0) { - return rv; - } - } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } - break; - case NGTCP2_FRAME_CRYPTO: - frc = *pfrc; - - *pfrc = frc->next; - frc->next = NULL; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &frc->fr.crypto.offset, frc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - break; - default: - pfrc = &(*pfrc)->next; - } - } - - *pfrc = pktns->tx.frq; - pktns->tx.frq = *first; - - return 0; -} - /* * conn_on_retry is called when Retry packet is received. The * function decodes the data in the buffer pointed by |pkt| whose @@ -5312,7 +5201,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_rtb *rtb = &conn->pktns.rtb; ngtcp2_rtb *in_rtb; uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1]; - ngtcp2_vec *token; + uint8_t *token; if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { return 0; @@ -5340,7 +5229,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data, retry.odcid.datalen)); - if (retry.token.len == 0) { + if (retry.tokenlen == 0) { return NGTCP2_ERR_PROTO; } @@ -5376,19 +5265,19 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return rv; } - token = &conn->local.settings.token; - - ngtcp2_mem_free(conn->mem, token->base); - token->base = NULL; - token->len = 0; + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token); + conn->local.settings.token = NULL; + conn->local.settings.tokenlen = 0; - token->base = ngtcp2_mem_malloc(conn->mem, retry.token.len); - if (token->base == NULL) { + token = ngtcp2_mem_malloc(conn->mem, retry.tokenlen); + if (token == NULL) { return NGTCP2_ERR_NOMEM; } - token->len = retry.token.len; - ngtcp2_cpymem(token->base, retry.token.base, retry.token.len); + ngtcp2_cpymem(token, retry.token, retry.tokenlen); + + conn->local.settings.token = token; + conn->local.settings.tokenlen = retry.tokenlen; reset_conn_stat_recovery(&conn->cstat); conn_reset_congestion_state(conn, ts); @@ -5423,7 +5312,6 @@ int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) { int rv; - ngtcp2_frame_chain *frc = NULL; ngtcp2_ssize num_acked; ngtcp2_conn_stat *cstat = &conn->cstat; @@ -5431,7 +5319,7 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, return NGTCP2_ERR_PROTO; } - rv = ngtcp2_pkt_validate_ack(fr); + rv = ngtcp2_pkt_validate_ack(fr, conn->local.settings.initial_pkt_num); if (rv != 0) { return rv; } @@ -5443,7 +5331,6 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, if (num_acked < 0) { /* TODO assert this */ assert(ngtcp2_err_is_fatal((int)num_acked)); - ngtcp2_frame_chain_list_objalloc_del(frc, &conn->frc_objalloc, conn->mem); return (int)num_acked; } @@ -5778,10 +5665,10 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp, * NGTCP2_ERR_CRYPTO * TLS backend reported error */ -static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - ngtcp2_strm *strm, - uint64_t rx_offset) { +static int +conn_emit_pending_crypto_data(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *strm, uint64_t rx_offset) { size_t datalen; const uint8_t *data; int rv; @@ -5801,7 +5688,8 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, offset = rx_offset; rx_offset += datalen; - rv = conn_call_recv_crypto_data(conn, crypto_level, offset, data, datalen); + rv = conn_call_recv_crypto_data(conn, encryption_level, offset, data, + datalen); if (rv != 0) { return rv; } @@ -5816,13 +5704,13 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, */ static int conn_recv_connection_close(ngtcp2_conn *conn, ngtcp2_connection_close *fr) { - ngtcp2_connection_close_error *ccerr = &conn->rx.ccerr; + ngtcp2_ccerr *ccerr = &conn->rx.ccerr; conn->state = NGTCP2_CS_DRAINING; if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) { - ccerr->type = NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT; + ccerr->type = NGTCP2_CCERR_TYPE_TRANSPORT; } else { - ccerr->type = NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION; + ccerr->type = NGTCP2_CCERR_TYPE_APPLICATION; } ccerr->error_code = fr->error_code; ccerr->frame_type = fr->frame_type; @@ -5834,16 +5722,14 @@ static int conn_recv_connection_close(ngtcp2_conn *conn, } if (ccerr->reason == NULL) { - ccerr->reason = ngtcp2_mem_malloc( - conn->mem, NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN); + ccerr->reason = ngtcp2_mem_malloc(conn->mem, NGTCP2_CCERR_MAX_REASONLEN); if (ccerr->reason == NULL) { return NGTCP2_ERR_NOMEM; } } - ccerr->reasonlen = - ngtcp2_min(fr->reasonlen, NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN); - ngtcp2_cpymem(ccerr->reason, fr->reason, ccerr->reasonlen); + ccerr->reasonlen = ngtcp2_min(fr->reasonlen, NGTCP2_CCERR_MAX_REASONLEN); + ngtcp2_cpymem((uint8_t *)ccerr->reason, fr->reason, ccerr->reasonlen); return 0; } @@ -5872,7 +5758,9 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, const ngtcp2_path *path, static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn_reset_conn_stat_cc(conn, &conn->cstat); - conn->cc.reset(&conn->cc, &conn->cstat, ts); + if (conn->cc.reset) { + conn->cc.reset(&conn->cc, &conn->cstat, ts); + } if (conn->hs_pktns) { ngtcp2_rtb_reset_cc_state(&conn->hs_pktns->rtb, @@ -5887,7 +5775,6 @@ static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, ngtcp2_tstamp ts) { int rv; - ngtcp2_duration pto, timeout; ngtcp2_pv *pv = conn->pv, *npv; uint8_t ent_flags; @@ -5904,53 +5791,52 @@ static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, if (!(pv->flags & NGTCP2_PV_FLAG_DONT_CARE)) { if (!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE)) { - if (pv->dcid.seq != conn->dcid.current.seq) { - assert(conn->dcid.current.cid.datalen); + assert(!conn->server); + assert(pv->dcid.seq != conn->dcid.current.seq); + assert(conn->dcid.current.cid.datalen); - rv = conn_retire_dcid(conn, &conn->dcid.current, ts); - if (rv != 0) { - return rv; - } - ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid); + rv = conn_retire_dcid(conn, &conn->dcid.current, ts); + if (rv != 0) { + return rv; } + ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid); + conn_reset_congestion_state(conn, ts); conn_reset_ecn_validation_state(conn); } - if (ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path)) { - conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; - } + assert(ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path)); - rv = conn_call_path_validation(conn, pv, - NGTCP2_PATH_VALIDATION_RESULT_SUCCESS); - if (rv != 0) { - return rv; - } + conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; if (!conn->local.settings.no_pmtud) { ngtcp2_conn_stop_pmtud(conn); - if (!(pv->flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { + if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { rv = conn_start_pmtud(conn); if (rv != 0) { return rv; } } } + + if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { + rv = conn_call_path_validation(conn, pv, + NGTCP2_PATH_VALIDATION_RESULT_SUCCESS); + if (rv != 0) { + return rv; + } + } } if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { - pto = conn_compute_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, pv->fallback_pto); - if (ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED) { assert(conn->server); /* Validate path again */ - rv = ngtcp2_pv_new(&npv, &pv->dcid, timeout, - NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE | - NGTCP2_PV_FLAG_MTU_PROBE, - &conn->log, conn->mem); + rv = ngtcp2_pv_new(&npv, &pv->dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log, + conn->mem); if (rv != 0) { return rv; } @@ -5959,7 +5845,8 @@ static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, ngtcp2_dcid_copy(&npv->fallback_dcid, &pv->fallback_dcid); npv->fallback_pto = pv->fallback_pto; } else { - rv = ngtcp2_pv_new(&npv, &pv->fallback_dcid, timeout, + rv = ngtcp2_pv_new(&npv, &pv->fallback_dcid, + conn_compute_pv_timeout_pto(conn, pv->fallback_pto), NGTCP2_PV_FLAG_DONT_CARE, &conn->log, conn->mem); if (rv != 0) { return rv; @@ -5999,8 +5886,7 @@ static size_t pkt_num_bits(size_t pkt_numlen) { case 4: return 32; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -6019,17 +5905,7 @@ static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) { static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, int ack_eliciting, ngtcp2_tstamp ts) { int rv; - - if (ack_eliciting && pktns->rx.max_ack_eliciting_pkt_num + 1 != pkt_num) { - ngtcp2_acktr_immediate_ack(&pktns->acktr); - } - if (pktns->rx.max_pkt_num < pkt_num) { - pktns->rx.max_pkt_num = pkt_num; - pktns->rx.max_pkt_ts = ts; - } - if (ack_eliciting && pktns->rx.max_ack_eliciting_pkt_num < pkt_num) { - pktns->rx.max_ack_eliciting_pkt_num = pkt_num; - } + ngtcp2_range r; rv = ngtcp2_gaptr_push(&pktns->rx.pngap, (uint64_t)pkt_num, 1); if (rv != 0) { @@ -6040,6 +5916,30 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, ngtcp2_gaptr_drop_first_gap(&pktns->rx.pngap); } + if (ack_eliciting) { + if (pktns->rx.max_ack_eliciting_pkt_num != -1) { + if (pkt_num < pktns->rx.max_ack_eliciting_pkt_num) { + ngtcp2_acktr_immediate_ack(&pktns->acktr); + } else if (pkt_num > pktns->rx.max_ack_eliciting_pkt_num) { + r = ngtcp2_gaptr_get_first_gap_after( + &pktns->rx.pngap, (uint64_t)pktns->rx.max_ack_eliciting_pkt_num); + + if (r.begin < (uint64_t)pkt_num) { + ngtcp2_acktr_immediate_ack(&pktns->acktr); + } + } + } + + if (pktns->rx.max_ack_eliciting_pkt_num < pkt_num) { + pktns->rx.max_ack_eliciting_pkt_num = pkt_num; + } + } + + if (pktns->rx.max_pkt_num < pkt_num) { + pktns->rx.max_pkt_num = pkt_num; + pktns->rx.max_pkt_ts = ts; + } + return 0; } @@ -6047,9 +5947,9 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, * verify_token verifies |hd| contains |token| in its token field. It * returns 0 if it succeeds, or NGTCP2_ERR_PROTO. */ -static int verify_token(const ngtcp2_vec *token, const ngtcp2_pkt_hd *hd) { - if (token->len == hd->token.len && - ngtcp2_cmemeq(token->base, hd->token.base, token->len)) { +static int verify_token(const uint8_t *token, size_t tokenlen, + const ngtcp2_pkt_hd *hd) { + if (tokenlen == hd->tokenlen && ngtcp2_cmemeq(token, hd->token, tokenlen)) { return 0; } return NGTCP2_ERR_PROTO; @@ -6071,34 +5971,80 @@ static void pktns_increase_ecn_counts(ngtcp2_pktns *pktns, } /* - * vneg_other_versions_includes returns nonzero if |other_versions| of - * length |other_versionslen| includes |version|. |other_versions| is - * the wire image of other_versions field of version_information - * transport parameter, and each version is encoded in network byte - * order. + * vneg_available_versions_includes returns nonzero if + * |available_versions| of length |available_versionslen| includes + * |version|. |available_versions| is the wire image of + * available_versions field of version_information transport + * parameter, and each version is encoded in network byte order. */ -static int vneg_other_versions_includes(const uint8_t *other_versions, - size_t other_versionslen, - uint32_t version) { +static int vneg_available_versions_includes(const uint8_t *available_versions, + size_t available_versionslen, + uint32_t version) { size_t i; + uint32_t v; + + assert(!(available_versionslen & 0x3)); + + if (available_versionslen == 0) { + return 0; + } + + for (i = 0; i < available_versionslen; i += sizeof(uint32_t)) { + available_versions = ngtcp2_get_uint32(&v, available_versions); + + if (version == v) { + return 1; + } + } + + return 0; +} + +/* + * conn_verify_fixed_bit verifies that fixed bit in |hd| is + * acceptable. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_INVALID_ARGUMENT + * Clearing fixed bit is not permitted. + */ +static int conn_verify_fixed_bit(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd) { + if (!(hd->flags & NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR)) { + return 0; + } - assert(!(other_versionslen & 0x3)); + if (conn->server) { + switch (hd->type) { + case NGTCP2_PKT_INITIAL: + case NGTCP2_PKT_0RTT: + case NGTCP2_PKT_HANDSHAKE: + /* TODO we cannot determine whether a token comes from NEW_TOKEN + frame or Retry packet. RFC 9287 requires that a token from + NEW_TOKEN. */ + if (!(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && + (conn->local.settings.token_type != NGTCP2_TOKEN_TYPE_NEW_TOKEN || + !conn->local.settings.tokenlen)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } - if (other_versionslen == 0) { - return 0; + break; + } } - for (i = 0; i < other_versionslen; i += sizeof(uint32_t)) { - if (version == ngtcp2_get_uint32(&other_versions[i])) { - return 1; - } + /* TODO we have no information that we enabled grease_quic_bit in + the previous connection. */ + if (!conn->local.transport_params.grease_quic_bit) { + return NGTCP2_ERR_INVALID_ARGUMENT; } return 0; } -static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *strm, const ngtcp2_crypto *fr); +static int conn_recv_crypto(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *strm, const ngtcp2_stream *fr); static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, const ngtcp2_pkt_info *pi, const uint8_t *pkt, @@ -6164,7 +6110,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_decrypt decrypt; ngtcp2_pktns *pktns; ngtcp2_strm *crypto; - ngtcp2_crypto_level crypto_level; + ngtcp2_encryption_level encryption_level; int invalid_reserved_bits = 0; if (pktlen == 0) { @@ -6210,7 +6156,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, /* Receiving Version Negotiation packet after getting Handshake packet from server is invalid. */ - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6244,9 +6190,13 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + /* Receiving Retry packet after getting Initial packet from server is invalid. */ - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6285,9 +6235,13 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + /* Quoted from spec: if subsequent packets of those types include a different Source Connection ID, they MUST be discarded. */ - if ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) && + if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && !ngtcp2_cid_eq(&conn->dcid.current.cid, &hd.scid)) { ngtcp2_log_rx_pkt_hd(&conn->log, &hd); ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, @@ -6305,7 +6259,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { if (conn->early.ckm) { ngtcp2_ssize nread2; /* TODO Avoid to parse header twice. */ @@ -6351,15 +6305,16 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen); return NGTCP2_ERR_DISCARD_PKT; } - if (conn->local.settings.token.len) { - rv = verify_token(&conn->local.settings.token, &hd); + if (conn->local.settings.tokenlen) { + rv = verify_token(conn->local.settings.token, + conn->local.settings.tokenlen, &hd); if (rv != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because token is invalid"); return NGTCP2_ERR_DISCARD_PKT; } } - if ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) == 0) { + if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) == 0) { /* Set rcid here so that it is available to callback. If this packet is discarded later in this function and no packet is processed in this connection attempt so far, connection @@ -6372,7 +6327,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } } } else { - if (hd.token.len != 0) { + if (hd.tokenlen != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because token is not empty"); return NGTCP2_ERR_DISCARD_PKT; @@ -6380,9 +6335,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, if (hd.version != conn->client_chosen_version && !conn->negotiated_version && conn->vneg.version != hd.version) { - if (!vneg_other_versions_includes(conn->vneg.other_versions, - conn->vneg.other_versionslen, - hd.version)) { + if (!vneg_available_versions_includes(conn->vneg.available_versions, + conn->vneg.available_versionslen, + hd.version)) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6402,7 +6357,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->in_pktns; crypto = &pktns->crypto.strm; - crypto_level = NGTCP2_CRYPTO_LEVEL_INITIAL; + encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL; if (hd.version == conn->client_chosen_version) { ckm = pktns->crypto.rx.ckm; @@ -6441,7 +6396,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->hs_pktns; crypto = &pktns->crypto.strm; - crypto_level = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; ckm = pktns->crypto.rx.ckm; hp_ctx = &pktns->crypto.rx.hp_ctx; @@ -6543,8 +6498,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, switch (hd.type) { case NGTCP2_PKT_INITIAL: - if (!conn->server || ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) && - !ngtcp2_cid_eq(&conn->rcid, &hd.dcid))) { + if (!conn->server || + ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && + !ngtcp2_cid_eq(&conn->rcid, &hd.dcid))) { rv = conn_verify_dcid(conn, NULL, &hd); if (rv != 0) { if (ngtcp2_err_is_fatal(rv)) { @@ -6568,7 +6524,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } break; default: - assert(0); + ngtcp2_unreachable(); } if (payloadlen == 0) { @@ -6580,8 +6536,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } if (hd.type == NGTCP2_PKT_INITIAL && - !(conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED)) { - conn->flags |= NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED; + !(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED)) { + conn->flags |= NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED; if (!conn->server) { conn->dcid.current.cid = hd.scid; } @@ -6623,7 +6579,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, break; case NGTCP2_FRAME_CRYPTO: if (!conn->server && !conn->negotiated_version && - ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt)) { + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt)) { conn->negotiated_version = hd.version; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, @@ -6631,7 +6587,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn->negotiated_version); } - rv = conn_recv_crypto(conn, crypto_level, crypto, &fr->crypto); + rv = conn_recv_crypto(conn, encryption_level, crypto, &fr->stream); if (rv != 0) { return rv; } @@ -6653,9 +6609,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_qlog_write_frame(&conn->qlog, fr); } - if (conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) { - /* Successful processing of Handshake packet from client verifies - source address. */ + if (hd.type == NGTCP2_PKT_HANDSHAKE) { + /* Successful processing of Handshake packet from a remote + endpoint validates its source address. */ conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; } @@ -6740,7 +6696,7 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn, if ((pkt[0] & NGTCP2_HEADER_FORM_BIT) && pktlen > 4) { /* Not a Version Negotiation packet */ - version = ngtcp2_get_uint32(&pkt[1]); + ngtcp2_get_uint32(&version, &pkt[1]); if (ngtcp2_pkt_get_type_long(version, pkt[0]) == NGTCP2_PKT_INITIAL) { if (conn->server) { if (is_unrecoverable_error((int)nread)) { @@ -6863,7 +6819,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, int rv; uint64_t offset; uint32_t sdflags; - int handshake_completed = conn_is_handshake_completed(conn); + int handshake_completed = conn_is_tls_handshake_completed(conn); if (!strm->rx.rob) { return 0; @@ -6892,7 +6848,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; } if (!handshake_completed) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_EARLY; + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; } rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, datalen); @@ -6909,8 +6865,9 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, * |rx_offset_base| is the offset in the entire TLS handshake stream. * fr->offset specifies the offset in each encryption level. * |max_rx_offset| is, if it is nonzero, the maximum offset in the - * entire TLS handshake stream that |fr| can carry. |crypto_level| is - * the encryption level where this data is received. + * entire TLS handshake stream that |fr| can carry. + * |encryption_level| is the encryption level where this data is + * received. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -6926,8 +6883,9 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, * NGTCP2_ERR_CALLBACK_FAILURE * User-defined callback function failed. */ -static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *crypto, const ngtcp2_crypto *fr) { +static int conn_recv_crypto(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *crypto, const ngtcp2_stream *fr) { uint64_t fr_end_offset; uint64_t rx_offset; int rv; @@ -6947,8 +6905,9 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, if (fr_end_offset <= rx_offset) { if (conn->server && !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT) && - crypto_level == NGTCP2_CRYPTO_LEVEL_INITIAL) { - /* recovery draft: Speeding Up Handshake Completion + encryption_level == NGTCP2_ENCRYPTION_LEVEL_INITIAL) { + /* https://datatracker.ietf.org/doc/html/rfc9002#section-6.2.3: + Speeding Up Handshake Completion When a server receives an Initial packet containing duplicate CRYPTO data, it can assume the client did not receive all of @@ -6979,17 +6938,16 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, uint64_t offset = rx_offset; rx_offset += datalen; - rv = ngtcp2_strm_update_rx_offset(crypto, rx_offset); - if (rv != 0) { - return rv; - } + ngtcp2_strm_update_rx_offset(crypto, rx_offset); - rv = conn_call_recv_crypto_data(conn, crypto_level, offset, data, datalen); + rv = conn_call_recv_crypto_data(conn, encryption_level, offset, data, + datalen); if (rv != 0) { return rv; } - rv = conn_emit_pending_crypto_data(conn, crypto_level, crypto, rx_offset); + rv = conn_emit_pending_crypto_data(conn, encryption_level, crypto, + rx_offset); if (rv != 0) { return rv; } @@ -7106,14 +7064,15 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return rv; } + if (!bidi) { + ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); + strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED; + } + rv = conn_call_stream_open(conn, strm); if (rv != 0) { return rv; } - - if (!bidi) { - ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); - } } fr_end_offset = fr->offset + datalen; @@ -7144,7 +7103,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return NGTCP2_ERR_FINAL_SIZE; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } @@ -7170,7 +7129,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return 0; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } } @@ -7186,10 +7145,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { datalen -= ncut; rx_offset += datalen; - rv = ngtcp2_strm_update_rx_offset(strm, rx_offset); - if (rv != 0) { - return rv; - } + ngtcp2_strm_update_rx_offset(strm, rx_offset); } else { data = NULL; datalen = 0; @@ -7206,8 +7162,8 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { if (fin) { sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; } - if (!conn_is_handshake_completed(conn)) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_EARLY; + if (!conn_is_tls_handshake_completed(conn)) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; } rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, (size_t)datalen); @@ -7242,25 +7198,16 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { */ static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { - int rv; - ngtcp2_frame_chain *frc; - ngtcp2_pktns *pktns = &conn->pktns; + strm->flags |= NGTCP2_STRM_FLAG_SEND_RESET_STREAM; + strm->tx.reset_stream_app_error_code = app_error_code; - rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc); - if (rv != 0) { - return rv; + if (ngtcp2_strm_is_tx_queued(strm)) { + return 0; } - frc->fr.type = NGTCP2_FRAME_RESET_STREAM; - frc->fr.reset_stream.stream_id = strm->stream_id; - frc->fr.reset_stream.app_error_code = app_error_code; - frc->fr.reset_stream.final_size = strm->tx.offset; - - /* TODO This prepends RESET_STREAM to pktns->tx.frq. */ - frc->next = pktns->tx.frq; - pktns->tx.frq = frc; + strm->cycle = conn_tx_strmq_first_cycle(conn); - return 0; + return ngtcp2_conn_tx_strmq_push(conn, strm); } /* @@ -7275,24 +7222,16 @@ static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, */ static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { - int rv; - ngtcp2_frame_chain *frc; - ngtcp2_pktns *pktns = &conn->pktns; + strm->flags |= NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + strm->tx.stop_sending_app_error_code = app_error_code; - rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc); - if (rv != 0) { - return rv; + if (ngtcp2_strm_is_tx_queued(strm)) { + return 0; } - frc->fr.type = NGTCP2_FRAME_STOP_SENDING; - frc->fr.stop_sending.stream_id = strm->stream_id; - frc->fr.stop_sending.app_error_code = app_error_code; - - /* TODO This prepends STOP_SENDING to pktns->tx.frq. */ - frc->next = pktns->tx.frq; - pktns->tx.frq = frc; + strm->cycle = conn_tx_strmq_first_cycle(conn); - return 0; + return ngtcp2_conn_tx_strmq_push(conn, strm); } /* @@ -7427,7 +7366,7 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn, return NGTCP2_ERR_FINAL_SIZE; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } @@ -7458,7 +7397,8 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn, ngtcp2_conn_extend_max_offset(conn, datalen); strm->rx.last_offset = fr->final_size; - strm->flags |= NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_RECV_RST; + strm->flags |= + NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_RESET_STREAM_RECVED; ngtcp2_strm_set_app_error_code(strm, fr->app_error_code); @@ -7547,19 +7487,14 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn, /* No RESET_STREAM is required if we have sent FIN and all data have been acknowledged. */ if (!ngtcp2_strm_is_all_tx_data_fin_acked(strm) && - !(strm->flags & NGTCP2_STRM_FLAG_SENT_RST)) { + !(strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) { rv = conn_reset_stream(conn, strm, fr->app_error_code); if (rv != 0) { return rv; } } - strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; - - if (ngtcp2_strm_is_tx_queued(strm) && !ngtcp2_strm_streamfrq_empty(strm)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } + strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_RESET_STREAM; ngtcp2_strm_streamfrq_clear(strm); @@ -8042,11 +7977,11 @@ static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) { return NGTCP2_ERR_PROTO; } - if (fr->token.len == 0) { + if (fr->tokenlen == 0) { return NGTCP2_ERR_FRAME_ENCODING; } - return conn_call_recv_new_token(conn, &fr->token); + return conn_call_recv_new_token(conn, fr->token, fr->tokenlen); } /* @@ -8087,6 +8022,144 @@ static int conn_recv_streams_blocked_uni(ngtcp2_conn *conn, return 0; } +/* + * conn_recv_stream_data_blocked processes the incoming + * STREAM_DATA_BLOCKED frame |fr|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_STREAM_STATE + * STREAM_DATA_BLOCKED is received for a local stream which is not + * initiated; or it is received for a local unidirectional stream. + * NGTCP2_ERR_STREAM_LIMIT + * STREAM_DATA_BLOCKED has remote stream ID which is strictly + * greater than the allowed limit. + * NGTCP2_ERR_FLOW_CONTROL + * STREAM_DATA_BLOCKED frame violates flow control limit. + * NGTCP2_ERR_FINAL_SIZE + * The offset is strictly larger than it is permitted. + * NGTCP2_ERR_NOMEM + * Out of memory. + * NGTCP2_ERR_CALLBACK_FAILURE + * User-defined callback function failed. + */ +static int conn_recv_stream_data_blocked(ngtcp2_conn *conn, + ngtcp2_stream_data_blocked *fr) { + int rv; + ngtcp2_strm *strm; + ngtcp2_idtr *idtr; + int local_stream = conn_local_stream(conn, fr->stream_id); + int bidi = bidi_stream(fr->stream_id); + uint64_t datalen; + + if (bidi) { + if (local_stream) { + if (conn->local.bidi.next_stream_id <= fr->stream_id) { + return NGTCP2_ERR_STREAM_STATE; + } + } else if (conn->remote.bidi.max_streams < + ngtcp2_ord_stream_id(fr->stream_id)) { + return NGTCP2_ERR_STREAM_LIMIT; + } + + idtr = &conn->remote.bidi.idtr; + } else { + if (local_stream) { + return NGTCP2_ERR_STREAM_STATE; + } + if (conn->remote.uni.max_streams < ngtcp2_ord_stream_id(fr->stream_id)) { + return NGTCP2_ERR_STREAM_LIMIT; + } + + idtr = &conn->remote.uni.idtr; + } + + strm = ngtcp2_conn_find_stream(conn, fr->stream_id); + if (strm == NULL) { + if (local_stream) { + return 0; + } + + rv = ngtcp2_idtr_open(idtr, fr->stream_id); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + assert(rv == NGTCP2_ERR_STREAM_IN_USE); + return 0; + } + + /* Frame is received before we create ngtcp2_strm object. */ + strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc); + if (strm == NULL) { + return NGTCP2_ERR_NOMEM; + } + rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL); + if (rv != 0) { + ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm); + return rv; + } + + if (!bidi) { + ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); + strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED; + } + + rv = conn_call_stream_open(conn, strm); + if (rv != 0) { + return rv; + } + } + + if (strm->rx.max_offset < fr->offset) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + if (fr->offset <= strm->rx.last_offset) { + return 0; + } + + if (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) { + return NGTCP2_ERR_FINAL_SIZE; + } + + datalen = fr->offset - strm->rx.last_offset; + if (datalen) { + if (conn_max_data_violated(conn, datalen)) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + conn->rx.offset += datalen; + + if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) { + ngtcp2_conn_extend_max_offset(conn, datalen); + } + } + + strm->rx.last_offset = fr->offset; + + return 0; +} + +/* + * conn_recv_data_blocked processes the incoming DATA_BLOCKED frame + * |fr|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_FLOW_CONTROL + * It violates connection-level flow control limit. + */ +static int conn_recv_data_blocked(ngtcp2_conn *conn, ngtcp2_data_blocked *fr) { + if (conn->rx.max_offset < fr->offset) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + return 0; +} + /* * conn_select_preferred_addr asks a client application to select a * server address from preferred addresses received from server. If a @@ -8103,7 +8176,6 @@ static int conn_recv_streams_blocked_uni(ngtcp2_conn *conn, static int conn_select_preferred_addr(ngtcp2_conn *conn) { ngtcp2_path_storage ps; int rv; - ngtcp2_duration pto, initial_pto, timeout; ngtcp2_pv *pv; ngtcp2_dcid *dcid; @@ -8129,12 +8201,8 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0); ngtcp2_dcid_set_path(dcid, &ps.path); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - - rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_PREFERRED_ADDR, - &conn->log, conn->mem); + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_PREFERRED_ADDR, &conn->log, conn->mem); if (rv != 0) { /* TODO Call ngtcp2_dcid_free here if it is introduced */ return rv; @@ -8180,7 +8248,7 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) { assert(conn->remote.transport_params); - if (conn->remote.transport_params->preferred_address_present) { + if (conn->remote.transport_params->preferred_addr_present) { rv = conn_select_preferred_addr(conn); if (rv != 0) { return rv; @@ -8225,6 +8293,8 @@ static int conn_key_phase_changed(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) { !(hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE); } +static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts); + /* * conn_prepare_key_update installs new updated keys. */ @@ -8241,12 +8311,12 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && tx_ckm->use_count >= pktns->crypto.ctx.max_encryption && - ngtcp2_conn_initiate_key_update(conn, ts) != 0) { + conn_initiate_key_update(conn, ts) != 0) { return NGTCP2_ERR_AEAD_LIMIT_REACHED; } if ((conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) || - (confirmed_ts != UINT64_MAX && confirmed_ts + pto > ts)) { + ngtcp2_tstamp_not_elapsed(confirmed_ts, pto, ts)) { return 0; } @@ -8369,7 +8439,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, ngtcp2_dcid dcid, *bound_dcid, *last; ngtcp2_pv *pv; int rv; - ngtcp2_duration pto, initial_pto, timeout; + ngtcp2_duration pto; int require_new_cid; int local_addr_eq; uint32_t remote_addr_cmp; @@ -8427,10 +8497,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "non-probing packet was received from new remote address"); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb); for (i = 0; i < len; ++i) { @@ -8482,13 +8548,16 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, dcid.bytes_recv = 0; dcid.flags &= (uint8_t)~NGTCP2_DCID_FLAG_PATH_VALIDATED; } + + ngtcp2_dcid_set_path(&dcid, path); } - ngtcp2_dcid_set_path(&dcid, path); dcid.bytes_recv += dgramlen; - rv = ngtcp2_pv_new(&pv, &dcid, timeout, NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, - &conn->log, conn->mem); + pto = conn_compute_pto(conn, &conn->pktns); + + rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto), + NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log, conn->mem); if (rv != 0) { return rv; } @@ -8507,11 +8576,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, if (!local_addr_eq || (remote_addr_cmp & (NGTCP2_ADDR_COMPARE_FLAG_ADDR | NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) { conn_reset_congestion_state(conn, ts); - } else { - /* For NAT rebinding, keep max_udp_payload_size since client most - likely does not send a padded PATH_CHALLENGE. */ - dcid.max_udp_payload_size = ngtcp2_max( - dcid.max_udp_payload_size, conn->dcid.current.max_udp_payload_size); } ngtcp2_dcid_copy(&conn->dcid.current, &dcid); @@ -8706,6 +8770,61 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi, return 0; } +/* + * conn_allow_path_change_under_disable_active_migration returns + * nonzero if a packet from |path| is acceptable under + * disable_active_migration is on. + */ +static int +conn_allow_path_change_under_disable_active_migration(ngtcp2_conn *conn, + const ngtcp2_path *path) { + uint32_t remote_addr_cmp; + const ngtcp2_preferred_addr *paddr; + ngtcp2_addr addr; + + assert(conn->server); + assert(conn->local.transport_params.disable_active_migration); + + /* If local address does not change, it must be passive migration + (NAT rebinding). */ + if (ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local)) { + remote_addr_cmp = + ngtcp2_addr_compare(&conn->dcid.current.ps.path.remote, &path->remote); + + return (remote_addr_cmp | NGTCP2_ADDR_COMPARE_FLAG_PORT) == + NGTCP2_ADDR_COMPARE_FLAG_PORT; + } + + /* If local address changes, it must be one of the preferred + addresses. */ + + if (!conn->local.transport_params.preferred_addr_present) { + return 0; + } + + paddr = &conn->local.transport_params.preferred_addr; + + if (paddr->ipv4_present) { + ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv4, + sizeof(paddr->ipv4)); + + if (ngtcp2_addr_eq(&addr, &path->local)) { + return 1; + } + } + + if (paddr->ipv6_present) { + ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv6, + sizeof(paddr->ipv6)); + + if (ngtcp2_addr_eq(&addr, &path->local)) { + return 1; + } + } + + return 0; +} + /* * conn_recv_pkt processes a packet contained in the buffer pointed by * |pkt| of length |pktlen|. |pkt| may contain multiple QUIC packets. @@ -8769,6 +8888,15 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, int new_cid_used = 0; int path_challenge_recved = 0; + if (conn->server && conn->local.transport_params.disable_active_migration && + !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) && + !conn_allow_path_change_under_disable_active_migration(conn, path)) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet is discarded because active migration is disabled"); + + return NGTCP2_ERR_DISCARD_PKT; + } + if (pkt[0] & NGTCP2_HEADER_FORM_BIT) { nread = ngtcp2_pkt_decode_hd_long(&hd, pkt, pktlen); if (nread < 0) { @@ -8788,6 +8916,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + pktlen = (size_t)nread + hd.len; /* Quoted from spec: if subsequent packets of those types include @@ -8854,6 +8986,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + pktns = &conn->pktns; aead = &pktns->crypto.ctx.aead; hp = &pktns->crypto.ctx.hp; @@ -9020,7 +9156,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } } else { rv = conn_verify_dcid(conn, &new_cid_used, &hd); @@ -9118,8 +9254,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, non_probing_pkt = 1; break; case NGTCP2_FRAME_CRYPTO: - rv = conn_recv_crypto(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION, - &pktns->crypto.strm, &fr->crypto); + rv = conn_recv_crypto(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT, + &pktns->crypto.strm, &fr->stream); if (rv != 0) { return rv; } @@ -9221,8 +9357,18 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } non_probing_pkt = 1; break; + case NGTCP2_FRAME_STREAM_DATA_BLOCKED: + rv = conn_recv_stream_data_blocked(conn, &fr->stream_data_blocked); + if (rv != 0) { + return rv; + } + non_probing_pkt = 1; + break; case NGTCP2_FRAME_DATA_BLOCKED: - /* TODO Not implemented yet */ + rv = conn_recv_data_blocked(conn, &fr->data_blocked); + if (rv != 0) { + return rv; + } non_probing_pkt = 1; break; case NGTCP2_FRAME_DATAGRAM: @@ -9468,7 +9614,7 @@ static int conn_sync_stream_data_limit(ngtcp2_conn *conn) { static int conn_handshake_completed(ngtcp2_conn *conn) { int rv; - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED; + conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; rv = conn_call_handshake_completed(conn); if (rv != 0) { @@ -9637,8 +9783,8 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, } } - if (conn_is_handshake_completed(conn) && - !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (conn_is_tls_handshake_completed(conn) && + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { rv = conn_handshake_completed(conn); if (rv != 0) { return rv; @@ -9658,27 +9804,22 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, } /* - * Client ServerHello might not fit into single Initial packet - * (e.g., resuming session with client authentication). If we get - * Client Initial which does not increase offset or it is 0RTT - * packet buffered, perform address validation in order to buffer + * Client Hello might not fit into single Initial packet (e.g., + * resuming session with client authentication). If we get Client + * Initial which does not increase offset or it is 0RTT packet + * buffered, perform address validation in order to buffer * validated data only. */ if (ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0) { if (conn->in_pktns->crypto.strm.rx.rob && ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob)) { /* Address has been validated with token */ - if (conn->local.settings.token.len) { + if (conn->local.settings.tokenlen) { return nread; } return NGTCP2_ERR_RETRY; } - if (conn->in_pktns->rx.buffed_pkts) { - /* 0RTT is buffered, force retry */ - return NGTCP2_ERR_RETRY; - } - /* If neither CRYPTO frame nor 0RTT packet is processed, just - drop connection. */ + /* If CRYPTO frame is not processed, just drop connection. */ return NGTCP2_ERR_DROP_CONN; } @@ -9711,7 +9852,7 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, conn_discard_initial_state(conn, ts); } - if (!conn_is_handshake_completed(conn)) { + if (!conn_is_tls_handshake_completed(conn)) { /* If server hits amplification limit, it cancels loss detection timer. If server receives a packet from client, the limit is increased and server can send more. If server has @@ -9814,8 +9955,9 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, const ngtcp2_pkt_info zero_pi = {0}; (void)pkt_info_version; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING)); + + conn_update_timestamp(conn, ts); ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu", pktlen); @@ -9840,7 +9982,6 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: nread = conn_read_handshake(conn, path, pi, pkt, pktlen, ts); if (nread < 0) { return (int)nread; @@ -9858,7 +9999,6 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, break; case NGTCP2_CS_SERVER_INITIAL: case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: - case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: if (!ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "ignore packet from unknown path during handshake"); @@ -9899,8 +10039,7 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, } break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts); @@ -9979,7 +10118,7 @@ static int conn_validate_early_transport_params_limits(ngtcp2_conn *conn) { /* * conn_write_handshake writes QUIC handshake packets to the buffer * pointed by |dest| of length |destlen|. |write_datalen| specifies - * the expected length of 0RTT or 1RTT packet payload. Specify 0 to + * the expected length of 0RTT packet payload. Specify 0 to * |write_datalen| if there is no such data. * * This function returns the number of bytes written to the buffer, or @@ -10054,7 +10193,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (!conn_handshake_probe_left(conn) && conn_cwnd_is_zero(conn)) { destlen = 0; } else { - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { pending_early_datalen = conn_retry_early_payloadlen(conn); if (pending_early_datalen) { write_datalen = pending_early_datalen; @@ -10072,7 +10211,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, destlen -= (size_t)nwrite; } - if (!conn_is_handshake_completed(conn)) { + if (!conn_is_tls_handshake_completed(conn)) { if (!(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) { nwrite = conn_retransmit_retry_early(conn, pi, dest, destlen, NGTCP2_WRITE_PKT_FLAG_NONE, ts); @@ -10094,6 +10233,10 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, return res; } + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { + return res; + } + if (!(conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED)) { return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; } @@ -10117,10 +10260,10 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, assert(conn->remote.transport_params); - if (conn->remote.transport_params->preferred_address_present) { + if (conn->remote.transport_params->preferred_addr_present) { assert(!ngtcp2_ringbuf_full(&conn->dcid.unused.rb)); - paddr = &conn->remote.transport_params->preferred_address; + paddr = &conn->remote.transport_params->preferred_addr; dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused.rb); ngtcp2_dcid_init(dcid, 1, &paddr->cid, paddr->stateless_reset_token); @@ -10245,19 +10388,10 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, switch (vmsg->type) { case NGTCP2_VMSG_TYPE_STREAM: datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); - send_stream = - conn_retry_early_payloadlen(conn) == 0 && - /* 0 length STREAM frame is allowed */ - (datalen == 0 || - (datalen > 0 && - (vmsg->stream.strm->tx.max_offset - vmsg->stream.strm->tx.offset) && - (conn->tx.max_offset - conn->tx.offset))); + send_stream = conn_retry_early_payloadlen(conn) == 0; if (send_stream) { - write_datalen = - conn_enforce_flow_control(conn, vmsg->stream.strm, datalen); - write_datalen = - ngtcp2_min(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); - write_datalen += NGTCP2_STREAM_OVERHEAD; + write_datalen = ngtcp2_min(datalen + NGTCP2_STREAM_OVERHEAD, + NGTCP2_MIN_COALESCED_PAYLOADLEN); if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { wflags |= NGTCP2_WRITE_PKT_FLAG_MORE; @@ -10302,8 +10436,6 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_get_type_long(version, dest[0]) == NGTCP2_PKT_INITIAL) { wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING; conn->pkt.require_padding = 1; - } else { - conn->pkt.require_padding = 0; } } else { assert(!conn->pktns.crypto.rx.ckm); @@ -10325,11 +10457,17 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, early_spktlen = conn_write_pkt(conn, pi, dest, destlen, vmsg, NGTCP2_PKT_0RTT, wflags, ts); - if (early_spktlen < 0) { switch (early_spktlen) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: - return spktlen; + if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) { + if (spktlen) { + return spktlen; + } + + break; + } + /* fall through */ case NGTCP2_ERR_WRITE_MORE: conn->pkt.hs_spktlen = spktlen; break; @@ -10340,16 +10478,16 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, return spktlen + early_spktlen; } -void ngtcp2_conn_handshake_completed(ngtcp2_conn *conn) { - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; +void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn) { + conn->flags |= NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED; if (conn->server) { conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED; } } int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn) { - return conn_is_handshake_completed(conn) && - (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED); + return conn_is_tls_handshake_completed(conn) && + (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED); } int ngtcp2_conn_sched_ack(ngtcp2_conn *conn, ngtcp2_acktr *acktr, @@ -10391,14 +10529,17 @@ int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) { case NGTCP2_PKT_0RTT: /* 0-RTT packet may arrive before Initial packet due to re-ordering. ngtcp2 does not buffer 0RTT packet unless the - very first Initial packet is received or token is received. */ - return NGTCP2_ERR_RETRY; + very first Initial packet is received or token is received. + Previously, we returned NGTCP2_ERR_RETRY here, so that client + can resend 0RTT data. But it incurs 1RTT already and + diminishes the value of 0RTT. Therefore, we just discard the + packet here for now. */ default: return NGTCP2_ERR_INVALID_ARGUMENT; } if (pktlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE || - (p->token.len == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN)) { + (p->tokenlen == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN)) { return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -10526,7 +10667,7 @@ int ngtcp2_conn_install_rx_handshake_key( pktns->crypto.rx.hp_ctx = *hp_ctx; - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_HANDSHAKE); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; @@ -10565,7 +10706,7 @@ int ngtcp2_conn_install_tx_handshake_key( } } - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_HANDSHAKE); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; @@ -10578,10 +10719,10 @@ int ngtcp2_conn_install_tx_handshake_key( return 0; } -int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, - const ngtcp2_crypto_aead_ctx *aead_ctx, - const uint8_t *iv, size_t ivlen, - const ngtcp2_crypto_cipher_ctx *hp_ctx) { +int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { int rv; assert(ivlen >= 8); @@ -10599,9 +10740,9 @@ int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, conn->flags |= NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED; if (conn->server) { - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_EARLY); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT); } else { - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_EARLY); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT); } if (rv != 0) { ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); @@ -10650,7 +10791,7 @@ int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, } } - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; @@ -10696,7 +10837,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, conn_discard_early_key(conn); } - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; @@ -10709,7 +10850,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, return 0; } -int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { +static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts; ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); @@ -10719,7 +10860,7 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) || !conn->crypto.key_update.new_tx_ckm || !conn->crypto.key_update.new_rx_ckm || - (confirmed_ts != UINT64_MAX && confirmed_ts + 3 * pto > ts)) { + ngtcp2_tstamp_not_elapsed(confirmed_ts, 3 * pto, ts)) { return NGTCP2_ERR_INVALID_STATE; } @@ -10728,6 +10869,12 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 0; } +int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + conn_update_timestamp(conn, ts); + + return conn_initiate_key_update(conn, ts); +} + /* * conn_retire_stale_bound_dcid retires stale destination connection * ID in conn->dcid.bound to keep some unused destination connection @@ -10751,7 +10898,7 @@ static int conn_retire_stale_bound_dcid(ngtcp2_conn *conn, assert(dcid->cid.datalen); - if (dcid->bound_ts + timeout > ts) { + if (ngtcp2_tstamp_not_elapsed(dcid->bound_ts, timeout, ts)) { ++i; continue; } @@ -10846,8 +10993,10 @@ ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { } static ngtcp2_tstamp conn_handshake_expiry(ngtcp2_conn *conn) { - if (conn_is_handshake_completed(conn) || - conn->local.settings.handshake_timeout == UINT64_MAX) { + if (conn_is_tls_handshake_completed(conn) || + conn->local.settings.handshake_timeout == UINT64_MAX || + conn->local.settings.initial_ts >= + UINT64_MAX - conn->local.settings.handshake_timeout) { return UINT64_MAX; } @@ -10874,7 +11023,13 @@ ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) { int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; - ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_duration pto; + + conn_update_timestamp(conn, ts); + + pto = conn_compute_pto(conn, &conn->pktns); + + assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING)); if (ngtcp2_conn_get_idle_expiry(conn) <= ts) { return NGTCP2_ERR_IDLE_CLOSE; @@ -10919,17 +11074,13 @@ int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } if (conn->server && conn->early.ckm && - conn->early.discard_started_ts != UINT64_MAX) { - if (conn->early.discard_started_ts + 3 * pto <= ts) { - conn_discard_early_key(conn); - } + ngtcp2_tstamp_elapsed(conn->early.discard_started_ts, 3 * pto, ts)) { + conn_discard_early_key(conn); } - if (!conn_is_handshake_completed(conn) && - conn->local.settings.handshake_timeout != UINT64_MAX && - conn->local.settings.initial_ts + - conn->local.settings.handshake_timeout <= - ts) { + if (!conn_is_tls_handshake_completed(conn) && + ngtcp2_tstamp_elapsed(conn->local.settings.initial_ts, + conn->local.settings.handshake_timeout, ts)) { return NGTCP2_ERR_HANDSHAKE_TIMEOUT; } @@ -10940,8 +11091,7 @@ static void acktr_cancel_expired_ack_delay_timer(ngtcp2_acktr *acktr, ngtcp2_duration max_ack_delay, ngtcp2_tstamp ts) { if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && - acktr->first_unacked_ts != UINT64_MAX && - acktr->first_unacked_ts + max_ack_delay <= ts) { + ngtcp2_tstamp_elapsed(acktr->first_unacked_ts, max_ack_delay, ts)) { acktr->flags |= NGTCP2_ACKTR_FLAG_CANCEL_TIMER; } } @@ -11006,19 +11156,21 @@ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) { * select_preferred_version selects the most preferred version. * |fallback_version| is chosen if no preference is made, or * |preferred_versions| does not include any of |chosen_version| or - * |other_versions|. |chosen_version| is treated as an extra other - * version. + * |available_versions|. |chosen_version| is treated as an extra + * other version. */ static uint32_t select_preferred_version(const uint32_t *preferred_versions, size_t preferred_versionslen, uint32_t chosen_version, - const uint8_t *other_versions, - size_t other_versionslen, + const uint8_t *available_versions, + size_t available_versionslen, uint32_t fallback_version) { size_t i, j; + const uint8_t *p; + uint32_t v; if (!preferred_versionslen || - (!other_versionslen && chosen_version == fallback_version)) { + (!available_versionslen && chosen_version == fallback_version)) { return fallback_version; } @@ -11026,12 +11178,13 @@ static uint32_t select_preferred_version(const uint32_t *preferred_versions, if (preferred_versions[i] == chosen_version) { return chosen_version; } - for (j = 0; j < other_versionslen; j += sizeof(uint32_t)) { - if (preferred_versions[i] != ngtcp2_get_uint32(&other_versions[j])) { - continue; - } + for (j = 0, p = available_versions; j < available_versionslen; + j += sizeof(uint32_t)) { + p = ngtcp2_get_uint32(&v, p); - return preferred_versions[i]; + if (preferred_versions[i] == v) { + return v; + } } } @@ -11054,6 +11207,10 @@ static uint32_t select_preferred_version(const uint32_t *preferred_versions, static int conn_client_validate_transport_params(ngtcp2_conn *conn, const ngtcp2_transport_params *params) { + if (!params->original_dcid_present) { + return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + } + if (!ngtcp2_cid_eq(&conn->rcid, ¶ms->original_dcid)) { return NGTCP2_ERR_TRANSPORT_PARAM; } @@ -11069,8 +11226,7 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, return NGTCP2_ERR_TRANSPORT_PARAM; } - if (params->preferred_address_present && - conn->dcid.current.cid.datalen == 0) { + if (params->preferred_addr_present && conn->dcid.current.cid.datalen == 0) { return NGTCP2_ERR_TRANSPORT_PARAM; } @@ -11079,21 +11235,31 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } - assert(vneg_other_versions_includes(conn->vneg.other_versions, - conn->vneg.other_versionslen, - conn->negotiated_version)); - } else if (conn->client_chosen_version != conn->negotiated_version || - conn->client_chosen_version != - conn->local.settings.original_version) { + assert(vneg_available_versions_includes(conn->vneg.available_versions, + conn->vneg.available_versionslen, + conn->negotiated_version)); + } else if (conn->client_chosen_version != conn->negotiated_version) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } /* When client reacted upon Version Negotiation */ if (conn->local.settings.original_version != conn->client_chosen_version) { - assert(params->version_info_present); + if (!params->version_info_present) { + assert(conn->client_chosen_version == conn->negotiated_version); + + /* QUIC v1 is treated specially. If version_info is missing, no + further validation is necessary. See + https://datatracker.ietf.org/doc/html/rfc9368#section-8 + */ + if (conn->client_chosen_version == NGTCP2_PROTO_VER_V1) { + return 0; + } + + return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; + } - /* Server choose original version after Version Negotiation. - Draft does not say this particular case, but this smells like + /* Server choose original version after Version Negotiation. RFC + 9368 does not say this particular case, but this smells like misbehaved server because server should accept original_version in the original connection. */ if (conn->local.settings.original_version == @@ -11102,7 +11268,7 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, } /* Check version downgrade on incompatible version negotiation. */ - if (params->version_info.other_versionslen == 0) { + if (params->version_info.available_versionslen == 0) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11110,8 +11276,8 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, select_preferred_version(conn->vneg.preferred_versions, conn->vneg.preferred_versionslen, params->version_info.chosen_version, - params->version_info.other_versions, - params->version_info.other_versionslen, + params->version_info.available_versions, + params->version_info.available_versionslen, /* fallback_version = */ 0)) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11128,8 +11294,8 @@ ngtcp2_conn_server_negotiate_version(ngtcp2_conn *conn, return select_preferred_version( conn->vneg.preferred_versions, conn->vneg.preferred_versionslen, - version_info->chosen_version, version_info->other_versions, - version_info->other_versionslen, version_info->chosen_version); + version_info->chosen_version, version_info->available_versions, + version_info->available_versionslen, version_info->chosen_version); } int ngtcp2_conn_set_remote_transport_params( @@ -11145,7 +11311,11 @@ int ngtcp2_conn_set_remote_transport_params( return 0; } - /* Assume that ngtcp2_decode_transport_params sets default value if + if (!params->initial_scid_present) { + return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + } + + /* Assume that ngtcp2_transport_params_decode sets default value if active_connection_id_limit is omitted. */ if (params->active_connection_id_limit < NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) { @@ -11164,7 +11334,20 @@ int ngtcp2_conn_set_remote_transport_params( } if (conn->server) { + if (params->original_dcid_present || + params->stateless_reset_token_present || + params->preferred_addr_present || params->retry_scid_present) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (params->version_info_present) { + if (!vneg_available_versions_includes( + params->version_info.available_versions, + params->version_info.available_versionslen, + params->version_info.chosen_version)) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (params->version_info.chosen_version != conn->client_chosen_version) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11195,11 +11378,7 @@ int ngtcp2_conn_set_remote_transport_params( } } - ngtcp2_log_remote_tp(&conn->log, - conn->server - ? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO - : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - params); + ngtcp2_log_remote_tp(&conn->log, params); ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, NGTCP2_QLOG_SIDE_REMOTE); @@ -11231,17 +11410,13 @@ int ngtcp2_conn_set_remote_transport_params( return 0; } -int ngtcp2_conn_decode_remote_transport_params(ngtcp2_conn *conn, - const uint8_t *data, - size_t datalen) { +int ngtcp2_conn_decode_and_set_remote_transport_params(ngtcp2_conn *conn, + const uint8_t *data, + size_t datalen) { ngtcp2_transport_params params; int rv; - rv = ngtcp2_decode_transport_params( - ¶ms, - conn->server ? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO - : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - data, datalen); + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); if (rv != 0) { return rv; } @@ -11258,20 +11433,72 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn) { return conn->remote.transport_params; } -void ngtcp2_conn_set_early_remote_transport_params_versioned( - ngtcp2_conn *conn, int transport_params_version, - const ngtcp2_transport_params *params) { +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen) { + ngtcp2_transport_params params, *src; + + if (conn->server) { + src = &conn->local.transport_params; + } else { + assert(conn->remote.transport_params); + + src = conn->remote.transport_params; + } + + ngtcp2_transport_params_default(¶ms); + + params.initial_max_streams_bidi = src->initial_max_streams_bidi; + params.initial_max_streams_uni = src->initial_max_streams_uni; + params.initial_max_stream_data_bidi_local = + src->initial_max_stream_data_bidi_local; + params.initial_max_stream_data_bidi_remote = + src->initial_max_stream_data_bidi_remote; + params.initial_max_stream_data_uni = src->initial_max_stream_data_uni; + params.initial_max_data = src->initial_max_data; + params.active_connection_id_limit = src->active_connection_id_limit; + params.max_datagram_frame_size = src->max_datagram_frame_size; + + if (conn->server) { + params.max_idle_timeout = src->max_idle_timeout; + params.max_udp_payload_size = src->max_udp_payload_size; + params.disable_active_migration = src->disable_active_migration; + } + + return ngtcp2_transport_params_encode(dest, destlen, ¶ms); +} + +int ngtcp2_conn_decode_and_set_0rtt_transport_params(ngtcp2_conn *conn, + const uint8_t *data, + size_t datalen) { + ngtcp2_transport_params params; + int rv; + + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); + if (rv != 0) { + return rv; + } + + return ngtcp2_conn_set_0rtt_remote_transport_params(conn, ¶ms); +} + +int ngtcp2_conn_set_0rtt_remote_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params) { ngtcp2_transport_params *p; - (void)transport_params_version; assert(!conn->server); assert(!conn->remote.transport_params); /* Assume that all pointer fields in p are NULL */ p = ngtcp2_mem_calloc(conn->mem, 1, sizeof(*p)); + if (p == NULL) { + return NGTCP2_ERR_NOMEM; + } conn->remote.transport_params = p; + ngtcp2_transport_params_default(conn->remote.transport_params); + p->initial_max_streams_bidi = params->initial_max_streams_bidi; p->initial_max_streams_uni = params->initial_max_streams_uni; p->initial_max_stream_data_bidi_local = @@ -11280,18 +11507,17 @@ void ngtcp2_conn_set_early_remote_transport_params_versioned( params->initial_max_stream_data_bidi_remote; p->initial_max_stream_data_uni = params->initial_max_stream_data_uni; p->initial_max_data = params->initial_max_data; + /* we might hit garbage, then set the sane default. */ p->active_connection_id_limit = ngtcp2_max(NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT, params->active_connection_id_limit); - p->max_idle_timeout = params->max_idle_timeout; - if (!params->max_udp_payload_size) { - p->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; - } else { + p->max_datagram_frame_size = params->max_datagram_frame_size; + + /* we might hit garbage, then set the sane default. */ + if (params->max_udp_payload_size) { p->max_udp_payload_size = ngtcp2_max(NGTCP2_MAX_UDP_PAYLOAD_SIZE, params->max_udp_payload_size); } - p->disable_active_migration = params->disable_active_migration; - p->max_datagram_frame_size = params->max_datagram_frame_size; /* These parameters are treated specially. If server accepts early data, it must not set values for these parameters that are @@ -11318,14 +11544,21 @@ void ngtcp2_conn_set_early_remote_transport_params_versioned( ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, conn->server, NGTCP2_QLOG_SIDE_REMOTE); + + return 0; } int ngtcp2_conn_set_local_transport_params_versioned( ngtcp2_conn *conn, int transport_params_version, const ngtcp2_transport_params *params) { - (void)transport_params_version; + ngtcp2_transport_params paramsbuf; + + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); assert(conn->server); + assert(params->active_connection_id_limit >= + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT); assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) { @@ -11345,24 +11578,20 @@ int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) { assert(1 == ngtcp2_ksl_len(&conn->scid.set)); - if (params->active_connection_id_limit == 0) { - params->active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; - } - params->initial_scid = conn->oscid; + params->initial_scid_present = 1; if (conn->oscid.datalen == 0) { - params->preferred_address_present = 0; + params->preferred_addr_present = 0; } - if (conn->server && params->preferred_address_present) { + if (conn->server && params->preferred_addr_present) { scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); if (scident == NULL) { return NGTCP2_ERR_NOMEM; } - ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid); + ngtcp2_scid_init(scident, 1, ¶ms->preferred_addr.cid); rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident); if (rv != 0) { @@ -11396,11 +11625,8 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn) { ngtcp2_ssize ngtcp2_conn_encode_local_transport_params(ngtcp2_conn *conn, uint8_t *dest, size_t destlen) { - return ngtcp2_encode_transport_params( - dest, destlen, - conn->server ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS - : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - &conn->local.transport_params); + return ngtcp2_transport_params_encode(dest, destlen, + &conn->local.transport_params); } int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -11485,7 +11711,6 @@ static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize nwrite; - int undersized; nwrite = ngtcp2_conn_write_vmsg(conn, path, pkt_info_version, pi, dest, destlen, vmsg, ts); @@ -11497,20 +11722,11 @@ static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn, conn->rst.is_cwnd_limited = 1; } - if (vmsg == NULL && cstat->bytes_in_flight < cstat->cwnd && - conn->tx.strmq_nretrans == 0) { - if (conn->local.settings.no_udp_payload_size_shaping) { - undersized = (size_t)nwrite < conn->local.settings.max_udp_payload_size; - } else { - undersized = (size_t)nwrite < conn->dcid.current.max_udp_payload_size; - } - - if (undersized) { - conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight; + if (nwrite == 0 && cstat->bytes_in_flight < cstat->cwnd) { + conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight; - if (conn->rst.app_limited == 0) { - conn->rst.app_limited = cstat->max_udp_payload_size; - } + if (conn->rst.app_limited == 0) { + conn->rst.app_limited = cstat->max_tx_udp_payload_size; } } @@ -11566,6 +11782,21 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( destlen, pvmsg, ts); } +ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( + ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, + ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, + uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen, + ngtcp2_tstamp ts) { + ngtcp2_vec datav; + + datav.len = datalen; + datav.base = (uint8_t *)data; + + return ngtcp2_conn_writev_datagram_versioned(conn, path, pkt_info_version, pi, + dest, destlen, paccepted, flags, + dgram_id, &datav, 1, ts); +} + ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, @@ -11584,8 +11815,12 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( } datalen = ngtcp2_vec_len_varint(datav, datavcnt); - if (datalen == -1 || (uint64_t)datalen > SIZE_MAX) { - return NGTCP2_ERR_INVALID_STATE; + if (datalen == -1 +#if UINT64_MAX > SIZE_MAX + || (uint64_t)datalen > SIZE_MAX +#endif /* UINT64_MAX > SIZE_MAX */ + ) { + return NGTCP2_ERR_INVALID_ARGUMENT; } if (conn->remote.transport_params->max_datagram_frame_size < @@ -11617,15 +11852,12 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize res = 0; uint64_t server_tx_left; - uint64_t datalen; - uint64_t write_datalen = 0; int64_t prev_in_pkt_num = -1; ngtcp2_ksl_it it; ngtcp2_rtb_entry *rtbent; (void)pkt_info_version; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); if (path) { ngtcp2_path_copy(path, &conn->dcid.current.ps.path); @@ -11638,14 +11870,15 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, pi->ecn = NGTCP2_ECN_NOT_ECT; } - if (!conn_pacing_pkt_tx_allowed(conn, ts)) { - return 0; - } - switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + } + nwrite = conn_client_write_handshake(conn, pi, dest, destlen, vmsg, ts); /* We might be unable to write a packet because of depletion of congestion window budget, perhaps due to packet loss that @@ -11675,14 +11908,28 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, break; case NGTCP2_CS_SERVER_INITIAL: case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: - case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { + server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); + if (server_tx_left == 0) { + return 0; + } + + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + } + + return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + } + if (!ppe_pending) { if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); if (server_tx_left == 0) { if (cstat->loss_detection_timer != UINT64_MAX) { ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled due to amplification limit"); cstat->loss_detection_timer = UINT64_MAX; } @@ -11693,40 +11940,16 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); } - if (vmsg) { - switch (vmsg->type) { - case NGTCP2_VMSG_TYPE_STREAM: - datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); - if (datalen == 0 || (datalen > 0 && - (vmsg->stream.strm->tx.max_offset - - vmsg->stream.strm->tx.offset) && - (conn->tx.max_offset - conn->tx.offset))) { - write_datalen = - conn_enforce_flow_control(conn, vmsg->stream.strm, datalen); - write_datalen = - ngtcp2_min(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); - write_datalen += NGTCP2_STREAM_OVERHEAD; - } - break; - case NGTCP2_VMSG_TYPE_DATAGRAM: - write_datalen = - ngtcp2_vec_len(vmsg->datagram.data, vmsg->datagram.datacnt) + - NGTCP2_DATAGRAM_OVERHEAD; - break; - default: - assert(0); - } - - if (conn->in_pktns && write_datalen > 0) { - it = ngtcp2_rtb_head(&conn->in_pktns->rtb); - if (!ngtcp2_ksl_it_end(&it)) { - rtbent = ngtcp2_ksl_it_get(&it); - prev_in_pkt_num = rtbent->hd.pkt_num; - } + if (conn->in_pktns) { + it = ngtcp2_rtb_head(&conn->in_pktns->rtb); + if (!ngtcp2_ksl_it_end(&it)) { + rtbent = ngtcp2_ksl_it_get(&it); + prev_in_pkt_num = rtbent->hd.pkt_num; } } - nwrite = conn_write_handshake(conn, pi, dest, destlen, write_datalen, ts); + nwrite = conn_write_handshake(conn, pi, dest, destlen, + /* write_datalen = */ 0, ts); if (nwrite < 0) { return nwrite; } @@ -11735,7 +11958,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, dest += nwrite; destlen -= (size_t)nwrite; - if (conn->in_pktns && write_datalen > 0) { + if (conn->in_pktns && nwrite > 0) { it = ngtcp2_rtb_head(&conn->in_pktns->rtb); if (!ngtcp2_ksl_it_end(&it)) { rtbent = ngtcp2_ksl_it_get(&it); @@ -11748,12 +11971,27 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } } } - if (conn->state != NGTCP2_CS_POST_HANDSHAKE && - conn->pktns.crypto.tx.ckm == NULL) { + if (conn->pktns.crypto.tx.ckm == NULL) { return res; } break; case NGTCP2_CS_POST_HANDSHAKE: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + if (conn->server && + !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { + server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); + if (server_tx_left == 0) { + return 0; + } + + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + } + + return conn_write_ack_pkt(conn, pi, dest, origlen, NGTCP2_PKT_1RTT, ts); + } + break; case NGTCP2_CS_CLOSING: return NGTCP2_ERR_CLOSING; @@ -11788,7 +12026,6 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, if (ppe_pending) { res = conn->pkt.hs_spktlen; - conn->pkt.hs_spktlen = 0; if (conn->pkt.require_padding) { wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING; } @@ -11827,35 +12064,44 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } if (conn->pmtud && + (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) && (!conn->hs_pktns || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) == 0)) { + ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) { nwrite = conn_write_pmtud_probe(conn, pi, dest, origdestlen, ts); if (nwrite) { goto fin; } } } + } - if (conn->server && - !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { - server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); - origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); - destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); + if (conn->server && + !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { + server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); - if (server_tx_left == 0 && - conn->cstat.loss_detection_timer != UINT64_MAX) { - ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, - "loss detection timer canceled due to amplification limit"); - conn->cstat.loss_detection_timer = UINT64_MAX; - } + if (server_tx_left == 0 && + conn->cstat.loss_detection_timer != UINT64_MAX) { + ngtcp2_log_info( + &conn->log, NGTCP2_LOG_EVENT_LDC, + "loss detection timer canceled due to amplification limit"); + conn->cstat.loss_detection_timer = UINT64_MAX; } } } if (res == 0) { if (conn_handshake_remnants_left(conn)) { - if (conn_handshake_probe_left(conn)) { + if (conn_handshake_probe_left(conn) || + /* Allow exceeding CWND if an Handshake packet needs to be + sent in order to avoid dead lock. In some situation, + typically for client, 1 RTT packets may occupy in-flight + bytes (e.g., some large requests and PMTUD), and + Handshake packet loss shrinks CWND, and we may get in the + situation that we are unable to send Handshake packet. */ + (conn->hs_pktns->rtb.num_pto_eliciting == 0 && + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) { destlen = origlen; } nwrite = conn_write_handshake_pkts(conn, pi, dest, destlen, @@ -11867,6 +12113,11 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, res = nwrite; dest += nwrite; destlen -= (size_t)nwrite; + } else if (destlen == 0) { + res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + if (res) { + return res; + } } } } @@ -11894,16 +12145,24 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } fin: - conn->pkt.hs_spktlen = 0; - if (nwrite >= 0) { res += nwrite; return res; } - /* NGTCP2_CONN_FLAG_PPE_PENDING is set in conn_write_pkt above. - ppe_pending cannot be used here. */ - if (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) { + + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) { + if (res) { + return res; + } + + break; + } + /* fall through */ + case NGTCP2_ERR_WRITE_MORE: conn->pkt.hs_spktlen = res; + break; } return nwrite; @@ -11989,9 +12248,6 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt( ngtcp2_ssize nwrite; uint64_t server_tx_left; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - if (conn_check_pkt_num_exhausted(conn)) { return NGTCP2_ERR_PKT_NUM_EXHAUSTED; } @@ -12054,9 +12310,6 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( ngtcp2_frame fr; uint64_t server_tx_left; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - if (conn_check_pkt_num_exhausted(conn)) { return NGTCP2_ERR_PKT_NUM_EXHAUSTED; } @@ -12135,11 +12388,9 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( return res; } -static void -connection_close_error_init(ngtcp2_connection_close_error *ccerr, - ngtcp2_connection_close_error_code_type type, - uint64_t error_code, const uint8_t *reason, - size_t reasonlen) { +static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type, + uint64_t error_code, const uint8_t *reason, + size_t reasonlen) { ccerr->type = type; ccerr->error_code = error_code; ccerr->frame_type = 0; @@ -12147,72 +12398,63 @@ connection_close_error_init(ngtcp2_connection_close_error *ccerr, ccerr->reasonlen = reasonlen; } -void ngtcp2_connection_close_error_default( - ngtcp2_connection_close_error *ccerr) { - connection_close_error_init(ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, - NGTCP2_NO_ERROR, NULL, 0); +void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, NGTCP2_NO_ERROR, NULL, 0); } -void ngtcp2_connection_close_error_set_transport_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen) { - connection_close_error_init(ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, - error_code, reason, reasonlen); +void ngtcp2_ccerr_set_transport_error(ngtcp2_ccerr *ccerr, uint64_t error_code, + const uint8_t *reason, size_t reasonlen) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, error_code, reason, reasonlen); } -void ngtcp2_connection_close_error_set_transport_error_liberr( - ngtcp2_connection_close_error *ccerr, int liberr, const uint8_t *reason, - size_t reasonlen) { +void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr, + const uint8_t *reason, size_t reasonlen) { switch (liberr) { case NGTCP2_ERR_RECV_VERSION_NEGOTIATION: - connection_close_error_init( - ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION, - NGTCP2_NO_ERROR, reason, reasonlen); + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION, NGTCP2_NO_ERROR, + reason, reasonlen); return; case NGTCP2_ERR_IDLE_CLOSE: - connection_close_error_init( - ccerr, NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE, - NGTCP2_NO_ERROR, reason, reasonlen); + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_IDLE_CLOSE, NGTCP2_NO_ERROR, reason, + reasonlen); return; }; - ngtcp2_connection_close_error_set_transport_error( + ngtcp2_ccerr_set_transport_error( ccerr, ngtcp2_err_infer_quic_transport_error_code(liberr), reason, reasonlen); } -void ngtcp2_connection_close_error_set_transport_error_tls_alert( - ngtcp2_connection_close_error *ccerr, uint8_t tls_alert, - const uint8_t *reason, size_t reasonlen) { - ngtcp2_connection_close_error_set_transport_error( - ccerr, NGTCP2_CRYPTO_ERROR | tls_alert, reason, reasonlen); +void ngtcp2_ccerr_set_tls_alert(ngtcp2_ccerr *ccerr, uint8_t tls_alert, + const uint8_t *reason, size_t reasonlen) { + ngtcp2_ccerr_set_transport_error(ccerr, NGTCP2_CRYPTO_ERROR | tls_alert, + reason, reasonlen); } -void ngtcp2_connection_close_error_set_application_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen) { - connection_close_error_init( - ccerr, NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION, error_code, - reason, reasonlen); +void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_APPLICATION, error_code, reason, + reasonlen); } ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - const ngtcp2_connection_close_error *ccerr, ngtcp2_tstamp ts) { + const ngtcp2_ccerr *ccerr, ngtcp2_tstamp ts) { (void)pkt_info_version; + conn_update_timestamp(conn, ts); + switch (ccerr->type) { - case NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT: + case NGTCP2_CCERR_TYPE_TRANSPORT: return ngtcp2_conn_write_connection_close_pkt( conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason, ccerr->reasonlen, ts); - case NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION: + case NGTCP2_CCERR_TYPE_APPLICATION: return ngtcp2_conn_write_application_close_pkt( conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason, ccerr->reasonlen, ts); @@ -12221,51 +12463,46 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( } } -int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn) { +int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_CLOSING; } -int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn) { +int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_DRAINING; } int ngtcp2_conn_close_stream(ngtcp2_conn *conn, ngtcp2_strm *strm) { int rv; - rv = ngtcp2_map_remove(&conn->strms, (ngtcp2_map_key_type)strm->stream_id); + rv = conn_call_stream_close(conn, strm); if (rv != 0) { - assert(rv != NGTCP2_ERR_INVALID_ARGUMENT); return rv; } - rv = conn_call_stream_close(conn, strm); + rv = ngtcp2_map_remove(&conn->strms, (ngtcp2_map_key_type)strm->stream_id); if (rv != 0) { - goto fin; + assert(rv != NGTCP2_ERR_INVALID_ARGUMENT); + return rv; } if (ngtcp2_strm_is_tx_queued(strm)) { ngtcp2_pq_remove(&conn->tx.strmq, &strm->pe); - if (!ngtcp2_strm_streamfrq_empty(strm)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } } -fin: ngtcp2_strm_free(strm); ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm); - return rv; + return 0; } int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm) { if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RDWR) == NGTCP2_STRM_FLAG_SHUT_RDWR && - ((strm->flags & NGTCP2_STRM_FLAG_RECV_RST) || + ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) || ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) && - (((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) && - (strm->flags & NGTCP2_STRM_FLAG_RST_ACKED)) || + (((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) && + (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_ACKED)) || ngtcp2_strm_is_all_tx_data_fin_acked(strm))) { return ngtcp2_conn_close_stream(conn, strm); } @@ -12286,14 +12523,14 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { ngtcp2_strm_set_app_error_code(strm, app_error_code); - if ((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) || + if ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) || ngtcp2_strm_is_all_tx_data_fin_acked(strm)) { return 0; } /* Set this flag so that we don't accidentally send DATA to this stream. */ - strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; + strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_RESET_STREAM; ngtcp2_strm_streamfrq_clear(strm); @@ -12312,6 +12549,8 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, */ static int conn_shutdown_stream_read(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { + ngtcp2_strm_set_app_error_code(strm, app_error_code); + if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) { return 0; } @@ -12322,44 +12561,54 @@ static int conn_shutdown_stream_read(ngtcp2_conn *conn, ngtcp2_strm *strm, /* Extend connection flow control window for the amount of data which are not passed to application. */ - if (!(strm->flags & - (NGTCP2_STRM_FLAG_STOP_SENDING | NGTCP2_STRM_FLAG_RECV_RST))) { + if (!(strm->flags & (NGTCP2_STRM_FLAG_STOP_SENDING | + NGTCP2_STRM_FLAG_RESET_STREAM_RECVED))) { ngtcp2_conn_extend_max_offset(conn, strm->rx.last_offset - ngtcp2_strm_rx_offset(strm)); } strm->flags |= NGTCP2_STRM_FLAG_STOP_SENDING; - ngtcp2_strm_set_app_error_code(strm, app_error_code); return conn_stop_sending(conn, strm, app_error_code); } -int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, int64_t stream_id, - uint64_t app_error_code) { +int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { int rv; ngtcp2_strm *strm; + (void)flags; strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; } - rv = conn_shutdown_stream_read(conn, strm, app_error_code); - if (rv != 0) { - return rv; + if (bidi_stream(stream_id) || !conn_local_stream(conn, stream_id)) { + rv = conn_shutdown_stream_read(conn, strm, app_error_code); + if (rv != 0) { + return rv; + } } - rv = conn_shutdown_stream_write(conn, strm, app_error_code); - if (rv != 0) { - return rv; + if (bidi_stream(stream_id) || conn_local_stream(conn, stream_id)) { + rv = conn_shutdown_stream_write(conn, strm, app_error_code); + if (rv != 0) { + return rv; + } } return 0; } -int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, +int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { ngtcp2_strm *strm; + (void)flags; + + if (!bidi_stream(stream_id) && !conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { @@ -12369,9 +12618,15 @@ int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, return conn_shutdown_stream_write(conn, strm, app_error_code); } -int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, +int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { ngtcp2_strm *strm; + (void)flags; + + if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { @@ -12421,6 +12676,10 @@ int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t datalen) { ngtcp2_strm *strm; + if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } + strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; @@ -12469,10 +12728,6 @@ static int delete_strms_pq_each(void *data, void *ptr) { if (ngtcp2_strm_is_tx_queued(s)) { ngtcp2_pq_remove(&conn->tx.strmq, &s->pe); - if (!ngtcp2_strm_streamfrq_empty(s)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } } ngtcp2_strm_free(s); @@ -12494,6 +12749,7 @@ static void conn_discard_early_data_state(ngtcp2_conn *conn) { ngtcp2_map_clear(&conn->strms); conn->tx.offset = 0; + conn->tx.last_blocked_offset = UINT64_MAX; conn->rx.unsent_max_offset = conn->rx.max_offset = conn->local.transport_params.initial_max_data; @@ -12519,14 +12775,28 @@ static void conn_discard_early_data_state(ngtcp2_conn *conn) { } } -void ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { +int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn) { if (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) { - return; + return 0; } conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED; conn_discard_early_data_state(conn); + + if (conn->callbacks.tls_early_data_rejected) { + return conn->callbacks.tls_early_data_rejected(conn, conn->user_data); + } + + if (conn->early.ckm) { + conn_discard_early_key(conn); + } + + return 0; +} + +int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0; } int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, @@ -12550,7 +12820,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, /* Ignore RTT sample if adjusting ack_delay causes the sample less than min_rtt before handshake confirmation. */ ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " ack_delay=%" PRIu64, rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS, @@ -12573,7 +12843,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, } ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64 " rttvar=%" PRIu64 " ack_delay=%" PRIu64, cstat->latest_rtt / NGTCP2_MILLISECONDS, @@ -12584,12 +12854,19 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, return 0; } -void ngtcp2_conn_get_conn_stat_versioned(ngtcp2_conn *conn, - int conn_stat_version, - ngtcp2_conn_stat *cstat) { - (void)conn_stat_version; +void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, + int conn_info_version, + ngtcp2_conn_info *cinfo) { + const ngtcp2_conn_stat *cstat = &conn->cstat; + (void)conn_info_version; - *cstat = conn->cstat; + cinfo->latest_rtt = cstat->latest_rtt; + cinfo->min_rtt = cstat->min_rtt; + cinfo->smoothed_rtt = cstat->smoothed_rtt; + cinfo->rttvar = cstat->rttvar; + cinfo->cwnd = cstat->cwnd; + cinfo->ssthresh = cstat->ssthresh; + cinfo->bytes_in_flight = cstat->bytes_in_flight; } static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, @@ -12597,14 +12874,13 @@ static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns) { ngtcp2_pktns *const ns[] = {conn->hs_pktns, &conn->pktns}; ngtcp2_conn_stat *cstat = &conn->cstat; - ngtcp2_duration *loss_time = cstat->loss_time; - ngtcp2_tstamp earliest_loss_time = loss_time[NGTCP2_PKTNS_ID_INITIAL]; + ngtcp2_duration *loss_time = cstat->loss_time + 1; + ngtcp2_tstamp earliest_loss_time = cstat->loss_time[NGTCP2_PKTNS_ID_INITIAL]; ngtcp2_pktns *pktns = conn->in_pktns; size_t i; - for (i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) { - if (ns[i] == NULL || ns[i]->rtb.num_pto_eliciting == 0 || - loss_time[i] >= earliest_loss_time) { + for (i = 0; i < ngtcp2_arraylen(ns); ++i) { + if (ns[i] == NULL || loss_time[i] >= earliest_loss_time) { continue; } @@ -12672,7 +12948,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if (earliest_loss_time != UINT64_MAX) { cstat->loss_detection_timer = earliest_loss_time; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss_detection_timer=%" PRIu64 " nonzero crypto loss time", cstat->loss_detection_timer); return; @@ -12686,7 +12962,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { if (cstat->loss_detection_timer != UINT64_MAX) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled"); cstat->loss_detection_timer = UINT64_MAX; cstat->pto_count = 0; @@ -12699,7 +12975,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { timeout = cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64, cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS); } @@ -12712,9 +12988,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_tstamp earliest_loss_time; ngtcp2_pktns *loss_pktns = NULL; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - switch (conn->state) { case NGTCP2_CS_CLOSING: case NGTCP2_CS_DRAINING: @@ -12731,7 +13004,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn_get_loss_time_and_pktns(conn, &earliest_loss_time, &loss_pktns); - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer fired"); if (earliest_loss_time != UINT64_MAX) { @@ -12745,7 +13018,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 0; } - if (!conn->server && !conn_is_handshake_completed(conn)) { + if (!conn->server && !conn_is_tls_handshake_completed(conn)) { if (hs_pktns->crypto.tx.ckm) { hs_pktns->rtb.probe_pkt_left = 1; } else { @@ -12762,7 +13035,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { hs_pktns->rtb.probe_pkt_left = 1; } } else if (hs_pktns && hs_pktns->rtb.num_pto_eliciting) { - hs_pktns->rtb.probe_pkt_left = 1; + hs_pktns->rtb.probe_pkt_left = 2; } else { conn->pktns.rtb.probe_pkt_left = 2; } @@ -12770,7 +13043,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ++cstat->pto_count; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "pto_count=%zu", + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu", cstat->pto_count); ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -12807,27 +13080,27 @@ static int conn_buffer_crypto_data(ngtcp2_conn *conn, const uint8_t **pdata, } int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, const size_t datalen) { ngtcp2_pktns *pktns; ngtcp2_frame_chain *frc; - ngtcp2_crypto *fr; + ngtcp2_stream *fr; int rv; if (datalen == 0) { return 0; } - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: assert(conn->in_pktns); pktns = conn->in_pktns; break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: assert(conn->hs_pktns); pktns = conn->hs_pktns; break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: pktns = &conn->pktns; break; default: @@ -12844,15 +13117,18 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, return rv; } - fr = &frc->fr.crypto; + fr = &frc->fr.stream; fr->type = NGTCP2_FRAME_CRYPTO; + fr->flags = 0; + fr->fin = 0; + fr->stream_id = 0; fr->offset = pktns->crypto.tx.offset; fr->datacnt = 1; fr->data[0].len = datalen; fr->data[0].base = (uint8_t *)data; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &fr->offset, frc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); return rv; @@ -12868,14 +13144,13 @@ int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, const uint8_t *token, size_t tokenlen) { int rv; ngtcp2_frame_chain *nfrc; - ngtcp2_vec tokenv = {(uint8_t *)token, tokenlen}; assert(conn->server); assert(token); assert(tokenlen); rv = ngtcp2_frame_chain_new_token_objalloc_new( - &nfrc, &tokenv, &conn->frc_objalloc, conn->mem); + &nfrc, token, tokenlen, &conn->frc_objalloc, conn->mem); if (rv != 0) { return rv; } @@ -12902,16 +13177,11 @@ int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm) { return ngtcp2_pq_push(&conn->tx.strmq, &strm->pe); } -static int conn_has_uncommited_preferred_address_cid(ngtcp2_conn *conn) { +static int conn_has_uncommitted_preferred_addr_cid(ngtcp2_conn *conn) { return conn->server && !(conn->flags & NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED) && conn->oscid.datalen && - conn->local.transport_params.preferred_address_present; -} - -size_t ngtcp2_conn_get_num_scid(ngtcp2_conn *conn) { - return ngtcp2_ksl_len(&conn->scid.set) + - (size_t)conn_has_uncommited_preferred_address_cid(conn); + conn->local.transport_params.preferred_addr_present; } size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { @@ -12919,27 +13189,28 @@ size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { ngtcp2_ksl_it it; ngtcp2_scid *scid; + if (dest == NULL) { + return ngtcp2_ksl_len(&conn->scid.set) + + (size_t)conn_has_uncommitted_preferred_addr_cid(conn); + } + for (it = ngtcp2_ksl_begin(&conn->scid.set); !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { scid = ngtcp2_ksl_it_get(&it); *dest++ = scid->cid; } - if (conn_has_uncommited_preferred_address_cid(conn)) { - *dest++ = conn->local.transport_params.preferred_address.cid; + if (conn_has_uncommitted_preferred_addr_cid(conn)) { + *dest++ = conn->local.transport_params.preferred_addr.cid; } return (size_t)(dest - origdest); } -size_t ngtcp2_conn_get_num_active_dcid(ngtcp2_conn *conn) { +static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) { size_t n = 1; /* for conn->dcid.current */ ngtcp2_pv *pv = conn->pv; - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { - return 0; - } - if (pv) { if (pv->dcid.seq != conn->dcid.current.seq) { ++n; @@ -12973,10 +13244,14 @@ size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) { ngtcp2_dcid *dcid; size_t len, i; - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { return 0; } + if (dest == NULL) { + return conn_get_num_active_dcid(conn); + } + copy_dcid_to_cid_token(dest, &conn->dcid.current); ++dest; @@ -13019,13 +13294,13 @@ const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn) { return &conn->dcid.current.ps.path; } -size_t ngtcp2_conn_get_max_udp_payload_size(ngtcp2_conn *conn) { - return conn->local.settings.max_udp_payload_size; +size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn) { + return conn->local.settings.max_tx_udp_payload_size; } -size_t ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn) { - if (conn->local.settings.no_udp_payload_size_shaping) { - return ngtcp2_conn_get_max_udp_payload_size(conn); +size_t ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn) { + if (conn->local.settings.no_tx_udp_payload_size_shaping) { + return ngtcp2_conn_get_max_tx_udp_payload_size(conn); } return conn->dcid.current.max_udp_payload_size; @@ -13056,11 +13331,11 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; ngtcp2_dcid *dcid; + ngtcp2_pv *pv; assert(!conn->server); - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); rv = conn_initiate_migration_precheck(conn, &path->local); if (rv != 0) { @@ -13087,35 +13362,33 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, ngtcp2_dcid_copy(&conn->dcid.current, dcid); ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb); - rv = conn_call_activate_dcid(conn, &conn->dcid.current); - if (rv != 0) { - return rv; - } - conn_reset_congestion_state(conn, ts); conn_reset_ecn_validation_state(conn); - if (!conn->local.settings.no_pmtud) { - rv = conn_start_pmtud(conn); - if (rv != 0) { - return rv; - } + /* TODO It might be better to add a new flag which indicates that a + connection should be closed if this path validation failed. The + current design allows an application to continue, by migrating + into yet another path. */ + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); + if (rv != 0) { + return rv; } - return 0; + conn->pv = pv; + + return conn_call_activate_dcid(conn, &conn->dcid.current); } int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts) { int rv; ngtcp2_dcid *dcid; - ngtcp2_duration pto, initial_pto, timeout; ngtcp2_pv *pv; assert(!conn->server); - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); rv = conn_initiate_migration_precheck(conn, &path->local); if (rv != 0) { @@ -13132,12 +13405,8 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0); ngtcp2_dcid_set_path(dcid, path); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - - rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_NONE, &conn->log, - conn->mem); + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); if (rv != 0) { return rv; } @@ -13148,10 +13417,6 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, return conn_call_activate_dcid(conn, &pv->dcid); } -uint64_t ngtcp2_conn_get_max_local_streams_uni(ngtcp2_conn *conn) { - return conn->local.uni.max_streams; -} - uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) { return conn->tx.max_offset - conn->tx.offset; } @@ -13200,7 +13465,7 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { /* TODO Remote max_idle_timeout becomes effective after handshake completion. */ - if (!conn_is_handshake_completed(conn) || + if (!conn_is_tls_handshake_completed(conn) || conn->remote.transport_params->max_idle_timeout == 0 || (conn->local.transport_params.max_idle_timeout && conn->local.transport_params.max_idle_timeout < @@ -13214,16 +13479,23 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { return UINT64_MAX; } - trpto = 3 * conn_compute_pto(conn, conn_is_handshake_completed(conn) + trpto = 3 * conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) ? &conn->pktns : conn->hs_pktns); - return conn->idle_ts + ngtcp2_max(idle_timeout, trpto); + idle_timeout = ngtcp2_max(idle_timeout, trpto); + + if (conn->idle_ts >= UINT64_MAX - idle_timeout) { + return UINT64_MAX; + } + + return conn->idle_ts + idle_timeout; } ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn) { - return conn_compute_pto( - conn, conn_is_handshake_completed(conn) ? &conn->pktns : conn->hs_pktns); + return conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) + ? &conn->pktns + : conn->hs_pktns); } void ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn, @@ -13257,12 +13529,12 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn) { return &conn->pktns.crypto.ctx; } -void ngtcp2_conn_set_early_crypto_ctx(ngtcp2_conn *conn, - const ngtcp2_crypto_ctx *ctx) { +void ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, + const ngtcp2_crypto_ctx *ctx) { conn->early.ctx = *ctx; } -const ngtcp2_crypto_ctx *ngtcp2_conn_get_early_crypto_ctx(ngtcp2_conn *conn) { +const ngtcp2_crypto_ctx *ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn) { return &conn->early.ctx; } @@ -13275,9 +13547,8 @@ void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, conn->crypto.tls_native_handle = tls_native_handle; } -void ngtcp2_conn_get_connection_close_error( - ngtcp2_conn *conn, ngtcp2_connection_close_error *ccerr) { - *ccerr = conn->rx.ccerr; +const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn) { + return &conn->rx.ccerr; } void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr) { @@ -13320,13 +13591,29 @@ int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id, } void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - if (!(conn->cstat.pacing_rate > 0) || conn->tx.pacing.pktlen == 0) { + ngtcp2_duration pacing_interval; + ngtcp2_duration wait; + + conn_update_timestamp(conn, ts); + + if (conn->tx.pacing.pktlen == 0) { return; } - conn->tx.pacing.next_ts = - ts + (ngtcp2_duration)((double)conn->tx.pacing.pktlen / - conn->cstat.pacing_rate); + if (conn->cstat.pacing_interval) { + pacing_interval = conn->cstat.pacing_interval; + } else { + /* 1.25 is the under-utilization avoidance factor described in + https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */ + pacing_interval = (conn->cstat.first_rtt_sample_ts == UINT64_MAX + ? NGTCP2_MILLISECONDS + : conn->cstat.smoothed_rtt) * + 100 / 125 / conn->cstat.cwnd; + } + + wait = (ngtcp2_duration)(conn->tx.pacing.pktlen * pacing_interval); + + conn->tx.pacing.next_ts = ts + wait; conn->tx.pacing.pktlen = 0; } @@ -13338,15 +13625,14 @@ int ngtcp2_conn_track_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq) { size_t i; if (conn->dcid.retire_unacked.len >= - sizeof(conn->dcid.retire_unacked.seqs) / - sizeof(conn->dcid.retire_unacked.seqs[0])) { + ngtcp2_arraylen(conn->dcid.retire_unacked.seqs)) { return NGTCP2_ERR_CONNECTION_ID_LIMIT; } /* Make sure that we do not have a duplicate */ for (i = 0; i < conn->dcid.retire_unacked.len; ++i) { if (conn->dcid.retire_unacked.seqs[i] == seq) { - assert(0); + ngtcp2_unreachable(); } } @@ -13399,20 +13685,35 @@ void ngtcp2_settings_default_versioned(int settings_version, settings->cc_algo = NGTCP2_CC_ALGO_CUBIC; settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT; settings->ack_thresh = 2; - settings->max_udp_payload_size = 1500 - 48; - settings->handshake_timeout = NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT; + settings->max_tx_udp_payload_size = 1500 - 48; + settings->handshake_timeout = UINT64_MAX; } void ngtcp2_transport_params_default_versioned( int transport_params_version, ngtcp2_transport_params *params) { - (void)transport_params_version; - - memset(params, 0, sizeof(*params)); - params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; - params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; - params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; - params->active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + size_t len; + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_VERSION: + len = sizeof(*params); + + break; + default: + ngtcp2_unreachable(); + } + + memset(params, 0, len); + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_VERSION: + params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; + params->active_connection_id_limit = + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; + params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; + + break; + } } /* The functions prefixed with ngtcp2_pkt_ are usually put inside diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h index b1c6564175d482..4ed67876bc3749 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -43,7 +43,6 @@ #include "ngtcp2_pq.h" #include "ngtcp2_cc.h" #include "ngtcp2_bbr.h" -#include "ngtcp2_bbr2.h" #include "ngtcp2_pv.h" #include "ngtcp2_pmtud.h" #include "ngtcp2_cid.h" @@ -51,16 +50,15 @@ #include "ngtcp2_ppe.h" #include "ngtcp2_qlog.h" #include "ngtcp2_rst.h" +#include "ngtcp2_conn_stat.h" typedef enum { /* Client specific handshake states */ NGTCP2_CS_CLIENT_INITIAL, NGTCP2_CS_CLIENT_WAIT_HANDSHAKE, - NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED, /* Server specific handshake states */ NGTCP2_CS_SERVER_INITIAL, NGTCP2_CS_SERVER_WAIT_HANDSHAKE, - NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED, /* Shared by both client and server */ NGTCP2_CS_POST_HANDSHAKE, NGTCP2_CS_CLOSING, @@ -111,18 +109,14 @@ typedef enum { to put the sane limit.*/ #define NGTCP2_MAX_SCID_POOL_SIZE 8 -/* NGTCP2_MAX_NON_ACK_TX_PKT is the maximum number of continuous non - ACK-eliciting packets. */ -#define NGTCP2_MAX_NON_ACK_TX_PKT 3 - /* NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS is the maximum number of ECN marked packets sent in NGTCP2_ECN_STATE_TESTING period. */ #define NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS 10 -/* NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN is the maximum length - of reason phrase to remember. If the received reason phrase is - longer than this value, it is truncated. */ -#define NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN 1024 +/* NGTCP2_CCERR_MAX_REASONLEN is the maximum length of reason phrase + to remember. If the received reason phrase is longer than this + value, it is truncated. */ +#define NGTCP2_CCERR_MAX_REASONLEN 1024 /* NGTCP2_WRITE_PKT_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_WRITE_PKT_FLAG_NONE 0x00u @@ -142,8 +136,8 @@ typedef union ngtcp2_max_frame { ngtcp2_frame fr; struct { ngtcp2_ack ack; - /* ack includes 1 ngtcp2_ack_blk. */ - ngtcp2_ack_blk blks[NGTCP2_MAX_ACK_BLKS - 1]; + /* ack includes 1 ngtcp2_ack_range. */ + ngtcp2_ack_range ranges[NGTCP2_MAX_ACK_RANGES - 1]; } ackfr; } ngtcp2_max_frame; @@ -158,17 +152,17 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, /* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_CONN_FLAG_NONE 0x00u -/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when TLS stack declares - that TLS handshake has completed. The condition of this +/* NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED is set when TLS stack + declares that TLS handshake has completed. The condition of this declaration varies between TLS implementations and this flag does not indicate the completion of QUIC handshake. Some implementations declare TLS handshake completion as server when they write off Server Finished and before deriving application rx secret. */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x01u -/* NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED is set if connection ID is - negotiated. This is only used for client. */ -#define NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED 0x02u +#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01u +/* NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED is set when the first + Initial packet has successfully been processed. */ +#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02u /* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport parameters are received. */ #define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04u @@ -187,9 +181,9 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, /* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint confirmed completion of handshake. */ #define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80u -/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED is set when the - library transitions its state to "post handshake". */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED 0x0100u +/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when the library + transitions its state to "post handshake". */ +#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100u /* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early handshake retransmission has done when server receives overlapping Initial crypto data. */ @@ -221,23 +215,15 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, endpoint has initiated key update. */ #define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000u -typedef struct ngtcp2_crypto_data { - ngtcp2_buf buf; - /* pkt_type is the type of packet to send data in buf. If it is 0, - it must be sent in Short packet. Otherwise, it is sent the long - packet type denoted by pkt_type. */ - uint8_t pkt_type; -} ngtcp2_crypto_data; - typedef struct ngtcp2_pktns { struct { /* last_pkt_num is the packet number which the local endpoint sent last time.*/ int64_t last_pkt_num; ngtcp2_frame_chain *frq; - /* num_non_ack_pkt is the number of continuous non ACK-eliciting - packets. */ - size_t num_non_ack_pkt; + /* non_ack_pkt_start_ts is the timestamp since the local endpoint + starts sending continuous non ACK-eliciting packets. */ + ngtcp2_tstamp non_ack_pkt_start_ts; struct { /* ect0 is the number of QUIC packets, not UDP datagram, which @@ -307,8 +293,6 @@ typedef struct ngtcp2_pktns { struct { struct { - /* frq contains crypto data sorted by their offset. */ - ngtcp2_ksl frq; /* offset is the offset of crypto stream in this packet number space. */ uint64_t offset; @@ -344,6 +328,19 @@ typedef enum ngtcp2_ecn_state { NGTCP2_ECN_STATE_CAPABLE, } ngtcp2_ecn_state; +/* ngtcp2_early_transport_params is the values remembered by client + from the previous session. */ +typedef struct ngtcp2_early_transport_params { + uint64_t initial_max_streams_bidi; + uint64_t initial_max_streams_uni; + uint64_t initial_max_stream_data_bidi_local; + uint64_t initial_max_stream_data_bidi_remote; + uint64_t initial_max_stream_data_uni; + uint64_t initial_max_data; + uint64_t active_connection_id_limit; + uint64_t max_datagram_frame_size; +} ngtcp2_early_transport_params; + ngtcp2_static_ringbuf_def(dcid_bound, NGTCP2_MAX_BOUND_DCID_POOL_SIZE, sizeof(ngtcp2_dcid)); ngtcp2_static_ringbuf_def(dcid_unused, NGTCP2_MAX_DCID_POOL_SIZE, @@ -353,7 +350,7 @@ ngtcp2_static_ringbuf_def(dcid_retired, NGTCP2_MAX_DCID_RETIRED_SIZE, ngtcp2_static_ringbuf_def(path_challenge, 4, sizeof(ngtcp2_path_challenge_entry)); -ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent); +ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent); struct ngtcp2_conn { ngtcp2_objalloc frc_objalloc; @@ -421,25 +418,28 @@ struct ngtcp2_conn { /* num_retired is the number of retired Connection ID still included in set. */ size_t num_retired; + /* num_in_flight is the number of NEW_CONNECTION_ID frames that + are in-flight and not acknowledged yet. */ + size_t num_in_flight; } scid; struct { /* strmq contains ngtcp2_strm which has frames to send. */ ngtcp2_pq strmq; - /* strmq_nretrans is the number of entries in strmq which has - stream data to resent. */ - size_t strmq_nretrans; /* ack is ACK frame. The underlying buffer is reused. */ ngtcp2_frame *ack; - /* max_ack_blks is the number of additional ngtcp2_ack_blk which - ack can contain. */ - size_t max_ack_blks; + /* max_ack_ranges is the number of additional ngtcp2_ack_range + which ack can contain. */ + size_t max_ack_ranges; /* offset is the offset the local endpoint has sent to the remote endpoint. */ uint64_t offset; /* max_offset is the maximum offset that local endpoint can send. */ uint64_t max_offset; + /* last_blocked_offset is the largest offset where the + transmission of stream data is blocked. */ + uint64_t last_blocked_offset; /* last_max_data_ts is the timestamp when last MAX_DATA frame is sent. */ ngtcp2_tstamp last_max_data_ts; @@ -482,7 +482,7 @@ struct ngtcp2_conn { /* path_challenge stores received PATH_CHALLENGE data. */ ngtcp2_static_ringbuf_path_challenge path_challenge; /* ccerr is the received connection close error. */ - ngtcp2_connection_close_error ccerr; + ngtcp2_ccerr ccerr; } rx; struct { @@ -497,16 +497,7 @@ struct ngtcp2_conn { ngtcp2_conn_set_early_remote_transport_params(). Server does not use this field. Server must not set values for these parameters that are smaller than the remembered values. */ - struct { - uint64_t initial_max_streams_bidi; - uint64_t initial_max_streams_uni; - uint64_t initial_max_stream_data_bidi_local; - uint64_t initial_max_stream_data_bidi_remote; - uint64_t initial_max_stream_data_uni; - uint64_t initial_max_data; - uint64_t active_connection_id_limit; - uint64_t max_datagram_frame_size; - } transport_params; + ngtcp2_early_transport_params transport_params; } early; struct { @@ -658,14 +649,14 @@ struct ngtcp2_conn { array pointed by preferred_versions. This field is only used by server. */ size_t preferred_versionslen; - /* other_versions is the versions that the local endpoint sends in - version_information transport parameter. This is the wire - image of other_versions field of version_information transport - parameter. */ - uint8_t *other_versions; - /* other_versionslen is the length of data pointed by - other_versions field. */ - size_t other_versionslen; + /* available_versions is the versions that the local endpoint + sends in version_information transport parameter. This is the + wire image of available_versions field of version_information + transport parameter. */ + uint8_t *available_versions; + /* available_versionslen is the length of data pointed by + available_versions field. */ + size_t available_versionslen; } vneg; ngtcp2_map strms; @@ -676,7 +667,12 @@ struct ngtcp2_conn { ngtcp2_qlog qlog; ngtcp2_rst rst; ngtcp2_cc_algo cc_algo; - ngtcp2_cc cc; + union { + ngtcp2_cc cc; + ngtcp2_cc_reno reno; + ngtcp2_cc_cubic cubic; + ngtcp2_cc_bbr bbr; + }; const ngtcp2_mem *mem; /* idle_ts is the time instant when idle timer started. */ ngtcp2_tstamp idle_ts; @@ -913,19 +909,6 @@ ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn); */ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts); -/* - * ngtcp2_conn_resched_frames reschedules frames linked from |*pfrc| - * for retransmission. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc); - uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn); /** @@ -1112,4 +1095,65 @@ void ngtcp2_conn_stop_pmtud(ngtcp2_conn *conn); int ngtcp2_conn_set_remote_transport_params( ngtcp2_conn *conn, const ngtcp2_transport_params *params); +/** + * @function + * + * `ngtcp2_conn_set_0rtt_remote_transport_params` sets |params| as + * transport parameters previously received from a server. The + * parameters are used to send early data. QUIC requires that client + * application should remember transport parameters along with a + * session ticket. + * + * At least following fields should be set: + * + * - initial_max_stream_id_bidi + * - initial_max_stream_id_uni + * - initial_max_stream_data_bidi_local + * - initial_max_stream_data_bidi_remote + * - initial_max_stream_data_uni + * - initial_max_data + * - active_connection_id_limit + * - max_datagram_frame_size (if DATAGRAM extension was negotiated) + * + * The following fields are ignored: + * + * - ack_delay_exponent + * - max_ack_delay + * - initial_scid + * - original_dcid + * - preferred_address and preferred_address_present + * - retry_scid and retry_scid_present + * - stateless_reset_token and stateless_reset_token_present + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_NOMEM` + * Out of memory. + */ +int ngtcp2_conn_set_0rtt_remote_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params); + +/* + * ngtcp2_conn_create_ack_frame creates ACK frame, and assigns its + * pointer to |*pfr| if there are any received packets to acknowledge. + * If there are no packets to acknowledge, this function returns 0, + * and |*pfr| is untouched. The caller is advised to set |*pfr| to + * NULL before calling this function, and check it after this function + * returns. + * + * Call ngtcp2_acktr_commit_ack after a created ACK frame is + * successfully serialized into a packet. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + */ +int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, + ngtcp2_pktns *pktns, uint8_t type, + ngtcp2_tstamp ts, ngtcp2_duration ack_delay, + uint64_t ack_delay_exponent); + #endif /* NGTCP2_CONN_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h new file mode 100644 index 00000000000000..1a93867aab3cae --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h @@ -0,0 +1,132 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_CONN_STAT_H +#define NGTCP2_CONN_STAT_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/** + * @struct + * + * :type:`ngtcp2_conn_stat` holds various connection statistics, and + * computed data for recovery and congestion controller. + */ +typedef struct ngtcp2_conn_stat { + /** + * :member:`latest_rtt` is the latest RTT sample which is not + * adjusted by acknowledgement delay. + */ + ngtcp2_duration latest_rtt; + /** + * :member:`min_rtt` is the minimum RTT seen so far. It is not + * adjusted by acknowledgement delay. + */ + ngtcp2_duration min_rtt; + /** + * :member:`smoothed_rtt` is the smoothed RTT. + */ + ngtcp2_duration smoothed_rtt; + /** + * :member:`rttvar` is a mean deviation of observed RTT. + */ + ngtcp2_duration rttvar; + /** + * :member:`initial_rtt` is the initial RTT which is used when no + * RTT sample is available. + */ + ngtcp2_duration initial_rtt; + /** + * :member:`first_rtt_sample_ts` is the timestamp when the first RTT + * sample is obtained. + */ + ngtcp2_tstamp first_rtt_sample_ts; + /** + * :member:`pto_count` is the count of successive PTO timer + * expiration. + */ + size_t pto_count; + /** + * :member:`loss_detection_timer` is the deadline of the current + * loss detection timer. + */ + ngtcp2_tstamp loss_detection_timer; + /** + * :member:`last_tx_pkt_ts` corresponds to + * time_of_last_ack_eliciting_packet in :rfc:`9002`. + */ + ngtcp2_tstamp last_tx_pkt_ts[NGTCP2_PKTNS_ID_MAX]; + /** + * :member:`loss_time` corresponds to loss_time in :rfc:`9002`. + */ + ngtcp2_tstamp loss_time[NGTCP2_PKTNS_ID_MAX]; + /** + * :member:`cwnd` is the size of congestion window. + */ + uint64_t cwnd; + /** + * :member:`ssthresh` is slow start threshold. + */ + uint64_t ssthresh; + /** + * :member:`congestion_recovery_start_ts` is the timestamp when + * congestion recovery started. + */ + ngtcp2_tstamp congestion_recovery_start_ts; + /** + * :member:`bytes_in_flight` is the number in bytes of all sent + * packets which have not been acknowledged. + */ + uint64_t bytes_in_flight; + /** + * :member:`max_tx_udp_payload_size` is the maximum size of UDP + * datagram payload that this endpoint transmits. It is used by + * congestion controller to compute congestion window. + */ + size_t max_tx_udp_payload_size; + /** + * :member:`delivery_rate_sec` is the current sending rate measured + * in byte per second. + */ + uint64_t delivery_rate_sec; + /** + * :member:`pacing_interval` is the inverse of pacing rate, which is + * the current packet sending rate computed by a congestion + * controller. 0 if a congestion controller does not set pacing + * interval. Even if this value is set to 0, the library paces + * packets. + */ + ngtcp2_duration pacing_interval; + /** + * :member:`send_quantum` is the maximum size of a data aggregate + * scheduled and transmitted together. + */ + size_t send_quantum; +} ngtcp2_conn_stat; + +#endif /* NGTCP2_CONN_STAT_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c index dcf72e4d0ec980..336721772b4e4c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c @@ -30,40 +30,51 @@ #include "ngtcp2_str.h" #include "ngtcp2_pkt.h" #include "ngtcp2_net.h" +#include "ngtcp2_unreachable.h" -uint64_t ngtcp2_get_uint64(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p) { uint64_t n; - memcpy(&n, p, 8); - return ngtcp2_ntohl64(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohl64(n); + return p + sizeof(n); } -uint64_t ngtcp2_get_uint48(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p) { uint64_t n = 0; memcpy(((uint8_t *)&n) + 2, p, 6); - return ngtcp2_ntohl64(n); + *dest = ngtcp2_ntohl64(n); + return p + 6; } -uint32_t ngtcp2_get_uint32(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p) { uint32_t n; - memcpy(&n, p, 4); - return ngtcp2_ntohl(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohl(n); + return p + sizeof(n); } -uint32_t ngtcp2_get_uint24(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p) { uint32_t n = 0; memcpy(((uint8_t *)&n) + 1, p, 3); - return ngtcp2_ntohl(n); + *dest = ngtcp2_ntohl(n); + return p + 3; } -uint16_t ngtcp2_get_uint16(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) { uint16_t n; - memcpy(&n, p, 2); - return ngtcp2_ntohs(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohs(n); + return p + sizeof(n); } -uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) { +const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p) { + memcpy(dest, p, sizeof(*dest)); + return p + sizeof(*dest); +} + +static uint64_t get_uvarint(size_t *plen, const uint8_t *p) { union { - char b[8]; + uint8_t n8; uint16_t n16; uint32_t n32; uint64_t n64; @@ -76,36 +87,55 @@ uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) { return *p; case 2: memcpy(&n, p, 2); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohs(n.n16); case 4: memcpy(&n, p, 4); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohl(n.n32); case 8: memcpy(&n, p, 8); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohl64(n.n64); default: - assert(0); + ngtcp2_unreachable(); } +} + +const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p) { + size_t len; - return 0; + *dest = get_uvarint(&len, p); + + return p + len; +} + +const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p) { + size_t len; + + *dest = (int64_t)get_uvarint(&len, p); + + return p + len; } int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen) { + uint32_t l; + uint16_t s; + switch (pkt_numlen) { case 1: return *p; case 2: - return (int64_t)ngtcp2_get_uint16(p); + ngtcp2_get_uint16(&s, p); + return (int64_t)s; case 3: - return (int64_t)ngtcp2_get_uint24(p); + ngtcp2_get_uint24(&l, p); + return (int64_t)l; case 4: - return (int64_t)ngtcp2_get_uint32(p); + ngtcp2_get_uint32(&l, p); + return (int64_t)l; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -134,7 +164,11 @@ uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n) { return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n) { +uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n) { + return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n)); +} + +uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) { uint8_t *rv; if (n < 64) { *p++ = (uint8_t)n; @@ -156,7 +190,7 @@ uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n) { return rv; } -uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n) { +uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n) { uint8_t *rv; assert(n < 1073741824); @@ -182,16 +216,15 @@ uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len) { ngtcp2_put_uint32be(p, (uint32_t)pkt_num); return p + 4; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } -size_t ngtcp2_get_varint_len(const uint8_t *p) { +size_t ngtcp2_get_uvarintlen(const uint8_t *p) { return (size_t)(1u << (*p >> 6)); } -size_t ngtcp2_put_varint_len(uint64_t n) { +size_t ngtcp2_put_uvarintlen(uint64_t n) { if (n < 64) { return 1; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h index 99746fdb4cefb7..ef089a971a37f1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h @@ -33,45 +33,61 @@ /* * ngtcp2_get_uint64 reads 8 bytes from |p| as 64 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 8. */ -uint64_t ngtcp2_get_uint64(const uint8_t *p); +const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p); /* * ngtcp2_get_uint48 reads 6 bytes from |p| as 48 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 6. */ -uint64_t ngtcp2_get_uint48(const uint8_t *p); +const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p); /* * ngtcp2_get_uint32 reads 4 bytes from |p| as 32 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 4. */ -uint32_t ngtcp2_get_uint32(const uint8_t *p); +const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p); /* * ngtcp2_get_uint24 reads 3 bytes from |p| as 24 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 3. */ -uint32_t ngtcp2_get_uint24(const uint8_t *p); +const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p); /* * ngtcp2_get_uint16 reads 2 bytes from |p| as 16 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 2. */ -uint16_t ngtcp2_get_uint16(const uint8_t *p); +const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p); /* - * ngtcp2_get_varint reads variable-length integer from |p|, and - * returns it in host byte order. The number of bytes read is stored - * in |*plen|. + * ngtcp2_get_uint16be reads 2 bytes from |p| as 16 bits unsigned + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| as is. It returns |p| + 2. */ -uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p); +const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p); + +/* + * ngtcp2_get_uvarint reads variable-length unsigned integer from |p|, + * and stores it in the buffer pointed by |dest| in host byte order. + * It returns |p| plus the number of bytes read from |p|. + */ +const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p); + +/* + * ngtcp2_get_varint reads variable-length unsigned integer from |p|, + * and casts it to the signed integer, and stores it in the buffer + * pointed by |dest| in host byte order. No information should be + * lost in this cast, because the variable-length integer is 62 + * bits. It returns |p| plus the number of bytes read from |p|. + */ +const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p); /* * ngtcp2_get_pkt_num reads encoded packet number from |p|. The @@ -115,18 +131,24 @@ uint8_t *ngtcp2_put_uint24be(uint8_t *p, uint32_t n); uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n); /* - * ngtcp2_put_varint writes |n| in |p| using variable-length integer + * ngtcp2_put_uint16 writes |n| as is in |p|. It returns the one + * beyond of the last written position. + */ +uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n); + +/* + * ngtcp2_put_uvarint writes |n| in |p| using variable-length integer * encoding. It returns the one beyond of the last written position. */ -uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n); +uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n); /* - * ngtcp2_put_varint30 writes |n| in |p| using variable-length integer - * encoding. |n| must be strictly less than 1073741824. The function - * always encodes |n| in 4 bytes. It returns the one beyond of the - * last written position. + * ngtcp2_put_uvarint30 writes |n| in |p| using variable-length + * integer encoding. |n| must be strictly less than 1073741824. The + * function always encodes |n| in 4 bytes. It returns the one beyond + * of the last written position. */ -uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n); +uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n); /* * ngtcp2_put_pkt_num encodes |pkt_num| using |len| bytes. It @@ -135,16 +157,16 @@ uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n); uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len); /* - * ngtcp2_get_varint_len returns the required number of bytes to read + * ngtcp2_get_uvarintlen returns the required number of bytes to read * variable-length integer starting at |p|. */ -size_t ngtcp2_get_varint_len(const uint8_t *p); +size_t ngtcp2_get_uvarintlen(const uint8_t *p); /* - * ngtcp2_put_varint_len returns the required number of bytes to + * ngtcp2_put_uvarintlen returns the required number of bytes to * encode |n|. */ -size_t ngtcp2_put_varint_len(uint64_t n); +size_t ngtcp2_put_uvarintlen(uint64_t n); /* * ngtcp2_nth_server_bidi_id returns |n|-th server bidirectional diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c new file mode 100644 index 00000000000000..eb85687a068449 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c @@ -0,0 +1,66 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_conversion.h" + +#include +#include + +static void transport_params_copy(int transport_params_version, + ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src) { + assert(transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION); + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_V1: + memcpy(dest, src, + offsetof(ngtcp2_transport_params, version_info_present) + + sizeof(src->version_info_present)); + + break; + } +} + +const ngtcp2_transport_params * +ngtcp2_transport_params_convert_to_latest(ngtcp2_transport_params *dest, + int transport_params_version, + const ngtcp2_transport_params *src) { + if (transport_params_version == NGTCP2_TRANSPORT_PARAMS_VERSION) { + return src; + } + + ngtcp2_transport_params_default(dest); + + transport_params_copy(transport_params_version, dest, src); + + return dest; +} + +void ngtcp2_transport_params_convert_to_old( + int transport_params_version, ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src) { + assert(transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION); + + transport_params_copy(transport_params_version, dest, src); +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h new file mode 100644 index 00000000000000..3457a8f2053aba --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h @@ -0,0 +1,71 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_CONVERSION_H +#define NGTCP2_CONVERSION_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* + * ngtcp2_transport_params_convert_to_latest converts |src| of version + * |transport_params_version| to the latest version + * NGTCP2_TRANSPORT_PARAMS_VERSION. + * + * |dest| must point to the latest version. |src| may be the older + * version, and if so, it may have fewer fields. Accessing those + * fields causes undefined behavior. + * + * If |transport_params_version| == NGTCP2_TRANSPORT_PARAMS_VERSION, + * no conversion is made, and |src| is returned. Otherwise, first + * |dest| is initialized via ngtcp2_transport_params_default, and then + * all valid fields in |src| are copied into |dest|. Finally, |dest| + * is returned. + */ +const ngtcp2_transport_params * +ngtcp2_transport_params_convert_to_latest(ngtcp2_transport_params *dest, + int transport_params_version, + const ngtcp2_transport_params *src); + +/* + * ngtcp2_transport_params_convert_to_old converts |src| of the latest + * version to |dest| of version |transport_params_version|. + * + * |transport_params_version| must not be the latest version + * NGTCP2_TRANSPORT_PARAMS_VERSION. + * + * |dest| points to the older version, and it may have fewer fields. + * Accessing those fields causes undefined behavior. + * + * This function copies all valid fields in version + * |transport_params_version| from |src| to |dest|. + */ +void ngtcp2_transport_params_convert_to_old(int transport_params_version, + ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src); + +#endif /* NGTCP2_CONVERSION_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c index f7592f885b4cb2..2c00af5ea53d99 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c @@ -31,6 +31,7 @@ #include "ngtcp2_conv.h" #include "ngtcp2_conn.h" #include "ngtcp2_net.h" +#include "ngtcp2_conversion.h" int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, size_t secretlen, @@ -107,8 +108,8 @@ void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen, * which has variable integer in its parameter. */ static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) { - size_t valuelen = ngtcp2_put_varint_len(param); - return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(valuelen) + valuelen; + size_t valuelen = ngtcp2_put_uvarintlen(param); + return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(valuelen) + valuelen; } /* @@ -117,9 +118,9 @@ static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) { */ static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id, uint64_t value) { - p = ngtcp2_put_varint(p, id); - p = ngtcp2_put_varint(p, ngtcp2_put_varint_len(value)); - return ngtcp2_put_varint(p, value); + p = ngtcp2_put_uvarint(p, id); + p = ngtcp2_put_uvarint(p, ngtcp2_put_uvarintlen(value)); + return ngtcp2_put_uvarint(p, value); } /* @@ -128,7 +129,7 @@ static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id, */ static size_t cid_paramlen(ngtcp2_transport_param_id id, const ngtcp2_cid *cid) { - return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(cid->datalen) + + return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(cid->datalen) + cid->datalen; } @@ -141,8 +142,8 @@ static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id, assert(cid->datalen == 0 || cid->datalen >= NGTCP2_MIN_CIDLEN); assert(cid->datalen <= NGTCP2_MAX_CIDLEN); - p = ngtcp2_put_varint(p, id); - p = ngtcp2_put_varint(p, cid->datalen); + p = ngtcp2_put_uvarint(p, id); + p = ngtcp2_put_uvarint(p, cid->datalen); if (cid->datalen) { p = ngtcp2_cpymem(p, cid->data, cid->datalen); } @@ -151,52 +152,52 @@ static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id, static const uint8_t empty_address[16]; -ngtcp2_ssize ngtcp2_encode_transport_params_versioned( - uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype, - int transport_params_version, const ngtcp2_transport_params *params) { +ngtcp2_ssize ngtcp2_transport_params_encode_versioned( + uint8_t *dest, size_t destlen, int transport_params_version, + const ngtcp2_transport_params *params) { uint8_t *p; size_t len = 0; /* For some reason, gcc 7.3.0 requires this initialization. */ size_t preferred_addrlen = 0; size_t version_infolen = 0; - (void)transport_params_version; + const ngtcp2_sockaddr_in *sa_in; + const ngtcp2_sockaddr_in6 *sa_in6; + ngtcp2_transport_params paramsbuf; - switch (exttype) { - case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO: - break; - case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS: + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); + + if (params->original_dcid_present) { len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID, ¶ms->original_dcid); + } - if (params->stateless_reset_token_present) { - len += - ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) + - ngtcp2_put_varint_len(NGTCP2_STATELESS_RESET_TOKENLEN) + - NGTCP2_STATELESS_RESET_TOKENLEN; - } - if (params->preferred_address_present) { - assert(params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN); - assert(params->preferred_address.cid.datalen <= NGTCP2_MAX_CIDLEN); - preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ + - 16 /* ipv6Address */ + 2 /* ipv6Port */ - + 1 + - params->preferred_address.cid.datalen /* CID */ + - NGTCP2_STATELESS_RESET_TOKENLEN; - len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + - ngtcp2_put_varint_len(preferred_addrlen) + preferred_addrlen; - } - if (params->retry_scid_present) { - len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, - ¶ms->retry_scid); - } - break; - default: - return NGTCP2_ERR_INVALID_ARGUMENT; + if (params->stateless_reset_token_present) { + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) + + ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) + + NGTCP2_STATELESS_RESET_TOKENLEN; + } + + if (params->preferred_addr_present) { + assert(params->preferred_addr.cid.datalen >= NGTCP2_MIN_CIDLEN); + assert(params->preferred_addr.cid.datalen <= NGTCP2_MAX_CIDLEN); + preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ + + 16 /* ipv6Address */ + 2 /* ipv6Port */ + + 1 + params->preferred_addr.cid.datalen /* CID */ + + NGTCP2_STATELESS_RESET_TOKENLEN; + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + + ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen; + } + if (params->retry_scid_present) { + len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, + ¶ms->retry_scid); } - len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, - ¶ms->initial_scid); + if (params->initial_scid_present) { + len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, + ¶ms->initial_scid); + } if (params->initial_max_stream_data_bidi_local) { len += varint_paramlen( @@ -235,8 +236,8 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->disable_active_migration) { len += - ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) + - ngtcp2_put_varint_len(0); + ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) + + ngtcp2_put_uvarintlen(0); } if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) { len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY, @@ -257,14 +258,14 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( params->max_datagram_frame_size); } if (params->grease_quic_bit) { - len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) + - ngtcp2_put_varint_len(0); + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) + + ngtcp2_put_uvarintlen(0); } if (params->version_info_present) { - version_infolen = sizeof(uint32_t) + params->version_info.other_versionslen; - len += ngtcp2_put_varint_len( - NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT) + - ngtcp2_put_varint_len(version_infolen) + version_infolen; + version_infolen = + sizeof(uint32_t) + params->version_info.available_versionslen; + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION) + + ngtcp2_put_uvarintlen(version_infolen) + version_infolen; } if (dest == NULL && destlen == 0) { @@ -277,58 +278,59 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( p = dest; - if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (params->original_dcid_present) { p = write_cid_param( p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID, ¶ms->original_dcid); + } + + if (params->stateless_reset_token_present) { + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN); + p = ngtcp2_put_uvarint(p, sizeof(params->stateless_reset_token)); + p = ngtcp2_cpymem(p, params->stateless_reset_token, + sizeof(params->stateless_reset_token)); + } - if (params->stateless_reset_token_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN); - p = ngtcp2_put_varint(p, sizeof(params->stateless_reset_token)); - p = ngtcp2_cpymem(p, params->stateless_reset_token, - sizeof(params->stateless_reset_token)); + if (params->preferred_addr_present) { + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS); + p = ngtcp2_put_uvarint(p, preferred_addrlen); + + if (params->preferred_addr.ipv4_present) { + sa_in = ¶ms->preferred_addr.ipv4; + p = ngtcp2_cpymem(p, &sa_in->sin_addr, sizeof(sa_in->sin_addr)); + p = ngtcp2_put_uint16(p, sa_in->sin_port); + } else { + p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in->sin_addr)); + p = ngtcp2_put_uint16(p, 0); } - if (params->preferred_address_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS); - p = ngtcp2_put_varint(p, preferred_addrlen); - - if (params->preferred_address.ipv4_present) { - p = ngtcp2_cpymem(p, params->preferred_address.ipv4_addr, - sizeof(params->preferred_address.ipv4_addr)); - p = ngtcp2_put_uint16be(p, params->preferred_address.ipv4_port); - } else { - p = ngtcp2_cpymem(p, empty_address, - sizeof(params->preferred_address.ipv4_addr)); - p = ngtcp2_put_uint16be(p, 0); - } - - if (params->preferred_address.ipv6_present) { - p = ngtcp2_cpymem(p, params->preferred_address.ipv6_addr, - sizeof(params->preferred_address.ipv6_addr)); - p = ngtcp2_put_uint16be(p, params->preferred_address.ipv6_port); - } else { - p = ngtcp2_cpymem(p, empty_address, - sizeof(params->preferred_address.ipv6_addr)); - p = ngtcp2_put_uint16be(p, 0); - } - - *p++ = (uint8_t)params->preferred_address.cid.datalen; - if (params->preferred_address.cid.datalen) { - p = ngtcp2_cpymem(p, params->preferred_address.cid.data, - params->preferred_address.cid.datalen); - } - p = ngtcp2_cpymem( - p, params->preferred_address.stateless_reset_token, - sizeof(params->preferred_address.stateless_reset_token)); + + if (params->preferred_addr.ipv6_present) { + sa_in6 = ¶ms->preferred_addr.ipv6; + p = ngtcp2_cpymem(p, &sa_in6->sin6_addr, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_put_uint16(p, sa_in6->sin6_port); + } else { + p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_put_uint16(p, 0); } - if (params->retry_scid_present) { - p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, - ¶ms->retry_scid); + + *p++ = (uint8_t)params->preferred_addr.cid.datalen; + if (params->preferred_addr.cid.datalen) { + p = ngtcp2_cpymem(p, params->preferred_addr.cid.data, + params->preferred_addr.cid.datalen); } + p = ngtcp2_cpymem(p, params->preferred_addr.stateless_reset_token, + sizeof(params->preferred_addr.stateless_reset_token)); } - p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, - ¶ms->initial_scid); + if (params->retry_scid_present) { + p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, + ¶ms->retry_scid); + } + + if (params->initial_scid_present) { + p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, + ¶ms->initial_scid); + } if (params->initial_max_stream_data_bidi_local) { p = write_varint_param( @@ -375,8 +377,8 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->disable_active_migration) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION); - p = ngtcp2_put_varint(p, 0); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION); + p = ngtcp2_put_uvarint(p, 0); } if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) { @@ -402,17 +404,17 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->grease_quic_bit) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT); - p = ngtcp2_put_varint(p, 0); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT); + p = ngtcp2_put_uvarint(p, 0); } if (params->version_info_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT); - p = ngtcp2_put_varint(p, version_infolen); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION); + p = ngtcp2_put_uvarint(p, version_infolen); p = ngtcp2_put_uint32be(p, params->version_info.chosen_version); - if (params->version_info.other_versionslen) { - p = ngtcp2_cpymem(p, params->version_info.other_versions, - params->version_info.other_versionslen); + if (params->version_info.available_versionslen) { + p = ngtcp2_cpymem(p, params->version_info.available_versions, + params->version_info.available_versionslen); } } @@ -423,49 +425,46 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( /* * decode_varint decodes a single varint from the buffer pointed by - * |p| of length |end - p|. If it decodes an integer successfully, it - * stores the integer in |*pdest| and returns 0. Otherwise it returns - * -1. + * |*pp| of length |end - *pp|. If it decodes an integer + * successfully, it stores the integer in |*pdest|, increment |*pp| by + * the number of bytes read from |*pp|, and returns 0. Otherwise it + * returns -1. */ -static ngtcp2_ssize decode_varint(uint64_t *pdest, const uint8_t *p, - const uint8_t *end) { +static int decode_varint(uint64_t *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; size_t len; if (p == end) { return -1; } - len = ngtcp2_get_varint_len(p); + len = ngtcp2_get_uvarintlen(p); if ((uint64_t)(end - p) < len) { return -1; } - *pdest = ngtcp2_get_varint(&len, p); + *pp = ngtcp2_get_uvarint(pdest, p); - return (ngtcp2_ssize)len; + return 0; } /* * decode_varint_param decodes length prefixed value from the buffer - * pointed by |p| of length |end - p|. The length and value are + * pointed by |*pp| of length |end - *pp|. The length and value are * encoded in varint form. If it decodes a value successfully, it - * stores the value in |*pdest| and returns 0. Otherwise it returns - * -1. + * stores the value in |*pdest|, increment |*pp| by the number of + * bytes read from |*pp|, and returns 0. Otherwise it returns -1. */ -static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, - const uint8_t *end) { - const uint8_t *begin = p; - ngtcp2_ssize nread; +static int decode_varint_param(uint64_t *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; uint64_t valuelen; - size_t n; - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return -1; } - p += nread; - if (p == end) { return -1; } @@ -474,36 +473,35 @@ static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, return -1; } - if (ngtcp2_get_varint_len(p) != valuelen) { + if (ngtcp2_get_uvarintlen(p) != valuelen) { return -1; } - *pdest = ngtcp2_get_varint(&n, p); + *pp = ngtcp2_get_uvarint(pdest, p); - p += valuelen; - - return (ngtcp2_ssize)(p - begin); + return 0; } /* * decode_cid_param decodes length prefixed ngtcp2_cid from the buffer - * pointed by |p| of length |end - p|. The length is encoded in + * pointed by |*pp| of length |end - *pp|. The length is encoded in * varint form. If it decodes a value successfully, it stores the - * value in |*pdest| and returns the number of bytes read. Otherwise - * it returns -1. + * value in |*pdest|, increment |*pp| by the number of read from + * |*pp|, and returns the number of bytes read. Otherwise it returns + * the one of the negative error code: + * + * NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM + * Could not decode Connection ID. */ -static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p, - const uint8_t *end) { - const uint8_t *begin = p; +static int decode_cid_param(ngtcp2_cid *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; uint64_t valuelen; - ngtcp2_ssize nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; - if ((valuelen != 0 && valuelen < NGTCP2_MIN_CIDLEN) || valuelen > NGTCP2_MAX_CIDLEN || (size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; @@ -513,28 +511,35 @@ static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p, p += valuelen; - return (ngtcp2_ssize)(p - begin); + *pp = p; + + return 0; } -int ngtcp2_decode_transport_params_versioned( - int transport_params_version, ngtcp2_transport_params *params, - ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) { - const uint8_t *p, *end; +int ngtcp2_transport_params_decode_versioned(int transport_params_version, + ngtcp2_transport_params *dest, + const uint8_t *data, + size_t datalen) { + const uint8_t *p, *end, *lend; size_t len; uint64_t param_type; uint64_t valuelen; - ngtcp2_ssize nread; - int initial_scid_present = 0; - int original_dcid_present = 0; - size_t i; - (void)transport_params_version; + int rv; + ngtcp2_sockaddr_in *sa_in; + ngtcp2_sockaddr_in6 *sa_in6; + uint32_t version; + ngtcp2_transport_params *params, paramsbuf; - if (datalen == 0) { - return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + if (transport_params_version == NGTCP2_TRANSPORT_PARAMS_VERSION) { + params = dest; + } else { + params = ¶msbuf; } /* Set default values */ memset(params, 0, sizeof(*params)); + params->original_dcid_present = 0; + params->initial_scid_present = 0; params->initial_max_streams_bidi = 0; params->initial_max_streams_uni = 0; params->initial_max_stream_data_bidi_local = 0; @@ -543,7 +548,7 @@ int ngtcp2_decode_transport_params_versioned( params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; params->stateless_reset_token_present = 0; - params->preferred_address_present = 0; + params->preferred_addr_present = 0; params->disable_active_migration = 0; params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; params->max_idle_timeout = 0; @@ -560,87 +565,66 @@ int ngtcp2_decode_transport_params_versioned( end = data + datalen; for (; (size_t)(end - p) >= 2;) { - nread = decode_varint(¶m_type, p, end); - if (nread < 0) { + if (decode_varint(¶m_type, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; switch (param_type) { case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: - nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_local, - p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_bidi_local, &p, + end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: - nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_remote, - p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_bidi_remote, &p, + end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI: - nread = decode_varint_param(¶ms->initial_max_stream_data_uni, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_uni, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA: - nread = decode_varint_param(¶ms->initial_max_data, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_data, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI: - nread = decode_varint_param(¶ms->initial_max_streams_bidi, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_streams_bidi, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI: - nread = decode_varint_param(¶ms->initial_max_streams_uni, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_streams_uni, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT: - nread = decode_varint_param(¶ms->max_idle_timeout, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_idle_timeout, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } params->max_idle_timeout *= NGTCP2_MILLISECONDS; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE: - nread = decode_varint_param(¶ms->max_udp_payload_size, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_udp_payload_size, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - p += nread; if ((size_t)valuelen != sizeof(params->stateless_reset_token)) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -648,28 +632,23 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - memcpy(params->stateless_reset_token, p, - sizeof(params->stateless_reset_token)); + p = ngtcp2_get_bytes(params->stateless_reset_token, p, + sizeof(params->stateless_reset_token)); params->stateless_reset_token_present = 1; - p += sizeof(params->stateless_reset_token); break; case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT: - nread = decode_varint_param(¶ms->ack_delay_exponent, p, end); - if (nread < 0 || params->ack_delay_exponent > 20) { + if (decode_varint_param(¶ms->ack_delay_exponent, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; - break; - case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (params->ack_delay_exponent > 20) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + break; + case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS: + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -680,143 +659,128 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - memcpy(params->preferred_address.ipv4_addr, p, - sizeof(params->preferred_address.ipv4_addr)); - p += sizeof(params->preferred_address.ipv4_addr); - params->preferred_address.ipv4_port = ngtcp2_get_uint16(p); - p += sizeof(uint16_t); + sa_in = ¶ms->preferred_addr.ipv4; - if (params->preferred_address.ipv4_port || - memcmp(empty_address, params->preferred_address.ipv4_addr, - sizeof(params->preferred_address.ipv4_addr)) != 0) { - params->preferred_address.ipv4_present = 1; + p = ngtcp2_get_bytes(&sa_in->sin_addr, p, sizeof(sa_in->sin_addr)); + p = ngtcp2_get_uint16be(&sa_in->sin_port, p); + + if (sa_in->sin_port || memcmp(empty_address, &sa_in->sin_addr, + sizeof(sa_in->sin_addr)) != 0) { + sa_in->sin_family = NGTCP2_AF_INET; + params->preferred_addr.ipv4_present = 1; } - memcpy(params->preferred_address.ipv6_addr, p, - sizeof(params->preferred_address.ipv6_addr)); - p += sizeof(params->preferred_address.ipv6_addr); - params->preferred_address.ipv6_port = ngtcp2_get_uint16(p); - p += sizeof(uint16_t); + sa_in6 = ¶ms->preferred_addr.ipv6; + + p = ngtcp2_get_bytes(&sa_in6->sin6_addr, p, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_get_uint16be(&sa_in6->sin6_port, p); - if (params->preferred_address.ipv6_port || - memcmp(empty_address, params->preferred_address.ipv6_addr, - sizeof(params->preferred_address.ipv6_addr)) != 0) { - params->preferred_address.ipv6_present = 1; + if (sa_in6->sin6_port || memcmp(empty_address, &sa_in6->sin6_addr, + sizeof(sa_in6->sin6_addr)) != 0) { + sa_in6->sin6_family = NGTCP2_AF_INET6; + params->preferred_addr.ipv6_present = 1; } /* cid */ - params->preferred_address.cid.datalen = *p++; - len += params->preferred_address.cid.datalen; + params->preferred_addr.cid.datalen = *p++; + len += params->preferred_addr.cid.datalen; if (valuelen != len || - params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN || - params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) { + params->preferred_addr.cid.datalen > NGTCP2_MAX_CIDLEN || + params->preferred_addr.cid.datalen < NGTCP2_MIN_CIDLEN) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - if (params->preferred_address.cid.datalen) { - memcpy(params->preferred_address.cid.data, p, - params->preferred_address.cid.datalen); - p += params->preferred_address.cid.datalen; + if (params->preferred_addr.cid.datalen) { + p = ngtcp2_get_bytes(params->preferred_addr.cid.data, p, + params->preferred_addr.cid.datalen); } /* stateless reset token */ - memcpy(params->preferred_address.stateless_reset_token, p, - sizeof(params->preferred_address.stateless_reset_token)); - p += sizeof(params->preferred_address.stateless_reset_token); - params->preferred_address_present = 1; + p = ngtcp2_get_bytes( + params->preferred_addr.stateless_reset_token, p, + sizeof(params->preferred_addr.stateless_reset_token)); + params->preferred_addr_present = 1; break; case NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION: - nread = decode_varint(&valuelen, p, end); - if (nread < 0 || valuelen != 0) { + if (decode_varint(&valuelen, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (valuelen != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; params->disable_active_migration = 1; break; case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - nread = decode_cid_param(¶ms->original_dcid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->original_dcid, &p, end); + if (rv != 0) { + return rv; } - original_dcid_present = 1; - p += nread; + params->original_dcid_present = 1; break; case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - nread = decode_cid_param(¶ms->retry_scid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->retry_scid, &p, end); + if (rv != 0) { + return rv; } params->retry_scid_present = 1; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID: - nread = decode_cid_param(¶ms->initial_scid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->initial_scid, &p, end); + if (rv != 0) { + return rv; } - initial_scid_present = 1; - p += nread; + params->initial_scid_present = 1; break; case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY: - nread = decode_varint_param(¶ms->max_ack_delay, p, end); - if (nread < 0 || params->max_ack_delay >= 16384) { + if (decode_varint_param(¶ms->max_ack_delay, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (params->max_ack_delay >= 16384) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } params->max_ack_delay *= NGTCP2_MILLISECONDS; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT: - nread = decode_varint_param(¶ms->active_connection_id_limit, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->active_connection_id_limit, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: - nread = decode_varint_param(¶ms->max_datagram_frame_size, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_datagram_frame_size, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT: - nread = decode_varint(&valuelen, p, end); - if (nread < 0 || valuelen != 0) { + if (decode_varint(&valuelen, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (valuelen != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; params->grease_quic_bit = 1; break; - case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT: - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION: + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (valuelen < sizeof(uint32_t) || (valuelen & 0x3)) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - params->version_info.chosen_version = ngtcp2_get_uint32(p); + p = ngtcp2_get_uint32(¶ms->version_info.chosen_version, p); if (params->version_info.chosen_version == 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += sizeof(uint32_t); if (valuelen > sizeof(uint32_t)) { - params->version_info.other_versions = (uint8_t *)p; - params->version_info.other_versionslen = + params->version_info.available_versions = (uint8_t *)p; + params->version_info.available_versionslen = (size_t)valuelen - sizeof(uint32_t); - for (i = sizeof(uint32_t); i < valuelen; - i += sizeof(uint32_t), p += sizeof(uint32_t)) { - if (ngtcp2_get_uint32(p) == 0) { + for (lend = p + (valuelen - sizeof(uint32_t)); p != lend;) { + p = ngtcp2_get_uint32(&version, p); + if (version == 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } } @@ -825,11 +789,9 @@ int ngtcp2_decode_transport_params_versioned( break; default: /* Ignore unknown parameter */ - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -842,10 +804,9 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - if (!initial_scid_present || - (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS && - !original_dcid_present)) { - return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + if (transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION) { + ngtcp2_transport_params_convert_to_old(transport_params_version, dest, + params); } return 0; @@ -859,7 +820,7 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, uint8_t *p; if (src->version_info_present) { - len += src->version_info.other_versionslen; + len += src->version_info.available_versionslen; } dest = ngtcp2_mem_malloc(mem, len); @@ -869,11 +830,11 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, *dest = *src; - if (src->version_info_present && src->version_info.other_versionslen) { + if (src->version_info_present && src->version_info.available_versionslen) { p = (uint8_t *)dest + sizeof(*dest); - memcpy(p, src->version_info.other_versions, - src->version_info.other_versionslen); - dest->version_info.other_versions = p; + memcpy(p, src->version_info.available_versions, + src->version_info.available_versionslen); + dest->version_info.available_versions = p; } *pdest = dest; @@ -881,14 +842,13 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, return 0; } -int ngtcp2_decode_transport_params_new(ngtcp2_transport_params **pparams, - ngtcp2_transport_params_type exttype, +int ngtcp2_transport_params_decode_new(ngtcp2_transport_params **pparams, const uint8_t *data, size_t datalen, const ngtcp2_mem *mem) { int rv; ngtcp2_transport_params params; - rv = ngtcp2_decode_transport_params(¶ms, exttype, data, datalen); + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); if (rv < 0) { return rv; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h index 9a9d95f5b9fe82..b78429bb38f582 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h @@ -43,30 +43,30 @@ /* ngtcp2_transport_param_id is the registry of QUIC transport parameter ID. */ -typedef enum ngtcp2_transport_param_id { - NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID = 0x0000, - NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT = 0x0001, - NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN = 0x0002, - NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE = 0x0003, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA = 0x0004, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0x0005, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 0x0006, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI = 0x0007, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI = 0x0008, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI = 0x0009, - NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT = 0x000a, - NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY = 0x000b, - NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION = 0x000c, - NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS = 0x000d, - NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT = 0x000e, - NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f, - NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010, - /* https://datatracker.ietf.org/doc/html/rfc9221 */ - NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE = 0x0020, - NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT = 0x2ab2, - /* https://quicwg.org/quic-v2/draft-ietf-quic-v2.html */ - NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT = 0xff73db, -} ngtcp2_transport_param_id; +typedef uint64_t ngtcp2_transport_param_id; + +#define NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID 0x00 +#define NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT 0x01 +#define NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN 0x02 +#define NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE 0x03 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA 0x04 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08 +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09 +#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0a +#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0b +#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0c +#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0d +#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0e +#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0f +#define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10 +/* https://datatracker.ietf.org/doc/html/rfc9221 */ +#define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20 +#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2ab2 +/* https://datatracker.ietf.org/doc/html/rfc9368 */ +#define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11 /* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c index 8f676da3ef0a13..5e4794cd72e7d4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c @@ -137,6 +137,9 @@ uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) { case NGTCP2_ERR_INVALID_ARGUMENT: case NGTCP2_ERR_NOMEM: case NGTCP2_ERR_CALLBACK_FAILURE: + case NGTCP2_ERR_HANDSHAKE_TIMEOUT: + case NGTCP2_ERR_PKT_NUM_EXHAUSTED: + case NGTCP2_ERR_INTERNAL: return NGTCP2_INTERNAL_ERROR; case NGTCP2_ERR_STREAM_STATE: return NGTCP2_STREAM_STATE_ERROR; @@ -147,7 +150,7 @@ uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) { case NGTCP2_ERR_NO_VIABLE_PATH: return NGTCP2_NO_VIABLE_PATH; case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE: - return NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT; + return NGTCP2_VERSION_NEGOTIATION_ERROR; default: return NGTCP2_PROTOCOL_VIOLATION; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c new file mode 100644 index 00000000000000..41c2a6a755cc8a --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c @@ -0,0 +1,220 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_frame_chain.h" + +#include +#include + +ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent); + +int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) { + *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, + ngtcp2_objalloc *objalloc) { + *pfrc = ngtcp2_objalloc_frame_chain_get(objalloc); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, + const ngtcp2_mem *mem) { + *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain) + extralen); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, + size_t datacnt, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream); + + if (datacnt > 1) { + need = sizeof(ngtcp2_vec) * (datacnt - 1); + + if (need > avail) { + return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); + } + } + + return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); +} + +int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, + const uint8_t *token, + size_t tokenlen, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token); + int rv; + uint8_t *p; + ngtcp2_frame *fr; + + if (tokenlen > avail) { + rv = ngtcp2_frame_chain_extralen_new(pfrc, tokenlen - avail, mem); + } else { + rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); + } + if (rv != 0) { + return rv; + } + + fr = &(*pfrc)->fr; + fr->type = NGTCP2_FRAME_NEW_TOKEN; + + p = (uint8_t *)fr + sizeof(ngtcp2_new_token); + memcpy(p, token, tokenlen); + + fr->new_token.token = p; + fr->new_token.tokenlen = tokenlen; + + return 0; +} + +void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + + if (frc == NULL) { + return; + } + + binder = frc->binder; + if (binder && --binder->refcount == 0) { + ngtcp2_mem_free(mem, binder); + } + + ngtcp2_mem_free(mem, frc); +} + +void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + + if (frc == NULL) { + return; + } + + switch (frc->fr.type) { + case NGTCP2_FRAME_CRYPTO: + case NGTCP2_FRAME_STREAM: + if (frc->fr.stream.datacnt && + sizeof(ngtcp2_vec) * (frc->fr.stream.datacnt - 1) > + sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream)) { + ngtcp2_frame_chain_del(frc, mem); + + return; + } + + break; + case NGTCP2_FRAME_NEW_TOKEN: + if (frc->fr.new_token.tokenlen > + sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token)) { + ngtcp2_frame_chain_del(frc, mem); + + return; + } + + break; + } + + binder = frc->binder; + if (binder && --binder->refcount == 0) { + ngtcp2_mem_free(mem, binder); + } + + frc->binder = NULL; + + ngtcp2_objalloc_frame_chain_release(objalloc, frc); +} + +void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { + frc->next = NULL; + frc->binder = NULL; +} + +void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain *next; + + for (; frc; frc = next) { + next = frc->next; + + ngtcp2_frame_chain_objalloc_del(frc, objalloc, mem); + } +} + +int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, + const ngtcp2_mem *mem) { + *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder)); + if (*pbinder == NULL) { + return NGTCP2_ERR_NOMEM; + } + + return 0; +} + +int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + int rv; + + assert(b->binder == NULL); + + if (a->binder == NULL) { + rv = ngtcp2_frame_chain_binder_new(&binder, mem); + if (rv != 0) { + return rv; + } + + a->binder = binder; + ++a->binder->refcount; + } + + b->binder = a->binder; + ++b->binder->refcount; + + return 0; +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h new file mode 100644 index 00000000000000..656fa5b799450e --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h @@ -0,0 +1,171 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_FRAME_CHAIN_H +#define NGTCP2_FRAME_CHAIN_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include "ngtcp2_pkt.h" +#include "ngtcp2_objalloc.h" + +/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is + set. */ +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u +/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information + which a frame carries has been acknowledged. */ +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u + +/* + * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to + * share the acknowledgement state. In general, all + * ngtcp2_frame_chains bound to the same binder must have the same + * information. + */ +typedef struct ngtcp2_frame_chain_binder { + size_t refcount; + /* flags is bitwise OR of zero or more of + NGTCP2_FRAME_CHAIN_BINDER_FLAG_*. */ + uint32_t flags; +} ngtcp2_frame_chain_binder; + +int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, + const ngtcp2_mem *mem); + +typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; + +/* + * ngtcp2_frame_chain chains frames in a single packet. + */ +struct ngtcp2_frame_chain { + union { + struct { + ngtcp2_frame_chain *next; + ngtcp2_frame_chain_binder *binder; + ngtcp2_frame fr; + }; + + ngtcp2_opl_entry oplent; + }; +}; + +ngtcp2_objalloc_decl(frame_chain, ngtcp2_frame_chain, oplent); + +/* + * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using + * new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL + * a->binder. |b| must not have non-NULL b->binder. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory + */ +int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, + const ngtcp2_mem *mem); + +/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that + a ngtcp2_stream can include. */ +#define NGTCP2_MAX_STREAM_DATACNT 256 + +/* + * ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and + * assigns its pointer to |*pfrc|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + */ +int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_objalloc_new behaves like + * ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object. + */ +int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, + ngtcp2_objalloc *objalloc); + +/* + * ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new, + * but it allocates extra memory |extralen| in order to extend + * ngtcp2_frame. + */ +int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_stream_datacnt_objalloc_new works like + * ngtcp2_frame_chain_new, but it allocates enough data to store + * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream + * object. If no additional space is required, + * ngtcp2_frame_chain_objalloc_new is called internally. + */ +int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, + size_t datacnt, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, + const uint8_t *token, + size_t tokenlen, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the + * memory pointed by |frc|. + */ +void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse. + * It might just delete |frc| depending on the frame type and the size + * of |frc|. + */ +void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_init initializes |frc|. + */ +void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc); + +/* + * ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain + * linked from |frc| to |objalloc| for reuse. Depending on the frame type + * and its size, ngtcp2_frame_chain might be deleted instead. + */ +void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +#endif /* NGTCP2_FRAME_CHAIN_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c index 0bd424cb0bc1f1..0ccc048b5b16b1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c @@ -35,6 +35,8 @@ static ngtcp2_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}}; +ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent); + static size_t ksl_nodelen(size_t keylen) { return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) & ~(uintptr_t)0xfu; @@ -714,6 +716,24 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key, } } +size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl) { return ksl->n; } + +void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) { + if (!ksl->head) { + return; + } + +#ifdef NOMEMPOOL + ksl_free_blk(ksl, ksl->head); +#endif /* NOMEMPOOL */ + + ksl->front = ksl->back = ksl->head = NULL; + ksl->n = 0; + + ngtcp2_objalloc_clear(&ksl->blkalloc); +} + +#ifndef WIN32 static void ksl_print(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t level) { size_t i; ngtcp2_ksl_node *node; @@ -734,23 +754,6 @@ static void ksl_print(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t level) { } } -size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl) { return ksl->n; } - -void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) { - if (!ksl->head) { - return; - } - -#ifdef NOMEMPOOL - ksl_free_blk(ksl, ksl->head); -#endif /* NOMEMPOOL */ - - ksl->front = ksl->back = ksl->head = NULL; - ksl->n = 0; - - ngtcp2_objalloc_clear(&ksl->blkalloc); -} - void ngtcp2_ksl_print(ngtcp2_ksl *ksl) { if (!ksl->head) { return; @@ -758,6 +761,7 @@ void ngtcp2_ksl_print(ngtcp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); } +#endif /* !WIN32 */ ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) { ngtcp2_ksl_it it; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h index 312a151d4aa9ec..7e08f15cdae6e8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h @@ -106,7 +106,7 @@ struct ngtcp2_ksl_blk { }; }; -ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent); +ngtcp2_objalloc_decl(ksl_blk, ngtcp2_ksl_blk, oplent); /* * ngtcp2_ksl_compar is a function type which returns nonzero if key @@ -263,12 +263,14 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl); #define ngtcp2_ksl_nth_node(KSL, BLK, N) \ ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) +#ifndef WIN32 /* * ngtcp2_ksl_print prints its internal state in stderr. It assumes * that the key is of type int64_t. This function should be used for * the debugging purpose only. */ void ngtcp2_ksl_print(ngtcp2_ksl *ksl); +#endif /* !WIN32 */ /* * ngtcp2_ksl_it_init initializes |it|. diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c index ee37ff3517b2bc..760bd60a9aff76 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c @@ -35,6 +35,8 @@ #include "ngtcp2_vec.h" #include "ngtcp2_macro.h" #include "ngtcp2_conv.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_net.h" void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, ngtcp2_printf log_printf, ngtcp2_tstamp ts, @@ -45,6 +47,7 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, log->scid[0] = '\0'; } log->log_printf = log_printf; + log->events = 0xff; log->ts = log->last_ts = ts; log->user_data = user_data; } @@ -65,7 +68,7 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, * Source Connection ID in hex string. * * : - * Event. pkt=packet, frm=frame, rcv=recovery, cry=crypto, + * Event. pkt=packet, frm=frame, ldc=loss-detection, cry=crypto, * con=connection(catch all) * * # Frame event @@ -138,7 +141,7 @@ static const char *strerrorcode(uint64_t error_code) { return "CRYPTO_BUFFER_EXCEEDED"; case NGTCP2_KEY_UPDATE_ERROR: return "KEY_UPDATE_ERROR"; - case NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT: + case NGTCP2_VERSION_NEGOTIATION_ERROR: return "VERSION_NEGOTIATION_ERROR"; default: if (0x100u <= error_code && error_code <= 0x1ffu) { @@ -202,12 +205,14 @@ static const char *strevent(ngtcp2_log_event ev) { return "pkt"; case NGTCP2_LOG_EVENT_FRM: return "frm"; - case NGTCP2_LOG_EVENT_RCV: - return "rcv"; + case NGTCP2_LOG_EVENT_LDC: + return "ldc"; case NGTCP2_LOG_EVENT_CRY: return "cry"; case NGTCP2_LOG_EVENT_PTV: return "ptv"; + case NGTCP2_LOG_EVENT_CCA: + return "cca"; case NGTCP2_LOG_EVENT_NONE: default: return "non"; @@ -220,8 +225,8 @@ static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream *fr, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " STREAM(0x%02x) id=0x%" PRIx64 " fin=%d offset=%" PRIu64 - " len=%" PRIu64 " uni=%d"), + (NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 + " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin, fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt), (fr->stream_id & 0x2) != 0); @@ -233,36 +238,37 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, size_t i; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) largest_ack=%" PRId64 + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64 " ack_delay=%" PRIu64 "(%" PRIu64 - ") ack_block_count=%zu"), + ") ack_range_count=%zu"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack, fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay, - fr->num_blks); + fr->rangecnt); largest_ack = fr->largest_ack; - min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = fr->largest_ack - (int64_t)fr->first_ack_range; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64 - "] block_count=%" PRIu64), + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 + "..%" PRId64 "] len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack, - fr->first_ack_blklen); + fr->first_ack_range); - for (i = 0; i < fr->num_blks; ++i) { - const ngtcp2_ack_blk *blk = &fr->blks[i]; - largest_ack = min_ack - (int64_t)blk->gap - 2; - min_ack = largest_ack - (int64_t)blk->blklen; + for (i = 0; i < fr->rangecnt; ++i) { + const ngtcp2_ack_range *range = &fr->ranges[i]; + largest_ack = min_ack - (int64_t)range->gap - 2; + min_ack = largest_ack - (int64_t)range->len; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64 - "] gap=%" PRIu64 " block_count=%" PRIu64), + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 + "..%" PRId64 "] gap=%" PRIu64 + " len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, - min_ack, blk->gap, blk->blklen); + min_ack, range->gap, range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) ect0=%" PRIu64 + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64 " ect1=%" PRIu64 " ce=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->ecn.ect0, fr->ecn.ect1, fr->ecn.ce); @@ -271,7 +277,8 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_padding *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PADDING(0x%02x) len=%zu"), + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len); } @@ -280,7 +287,7 @@ static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " RESET_STREAM(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size); @@ -293,9 +300,10 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, size_t reasonlen = ngtcp2_min(sizeof(reason) - 1, fr->reasonlen); log->log_printf(log->user_data, - (NGTCP2_LOG_PKT - " CONNECTION_CLOSE(0x%02x) error_code=%s(0x%" PRIx64 ") " - "frame_type=%" PRIx64 " reason_len=%zu reason=[%s]"), + (NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64 + ") error_code=%s(0x%" PRIx64 ") " + "frame_type=%" PRIx64 + " reason_len=%zu reason=[%s]"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code) @@ -306,16 +314,18 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_data *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_DATA(0x%02x) max_data=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64 ") max_data=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data); } static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_stream_data *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64 + ") id=0x%" PRIx64 " max_stream_data=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, fr->max_stream_data); @@ -323,31 +333,33 @@ static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_streams *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02x) max_streams=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); } static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_ping *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02x)"), + log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type); } static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_data_blocked *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02x) offset=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64 ") offset=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset); } static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream_data_blocked *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02x) id=0x%" PRIx64 - " offset=%" PRIu64), + (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64 + ") id=0x%" PRIx64 " offset=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, fr->offset); } @@ -357,7 +369,7 @@ static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02x) max_streams=%" PRIu64), + (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); } @@ -369,7 +381,7 @@ static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02x) seq=%" PRIu64 + (NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64 " cid=0x%s retire_prior_to=%" PRIu64 " stateless_reset_token=0x%s"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq, @@ -383,7 +395,7 @@ static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stop_sending *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " STOP_SENDING(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64 ") id=0x%" PRIx64 " app_error_code=%s(0x%" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, strapperrorcode(fr->app_error_code), fr->app_error_code); @@ -395,7 +407,8 @@ static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[sizeof(fr->data) * 2 + 1]; log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02x) data=0x%s"), + log->user_data, + (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data))); } @@ -406,18 +419,19 @@ static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[sizeof(fr->data) * 2 + 1]; log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02x) data=0x%s"), + log->user_data, + (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data))); } static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, - const ngtcp2_crypto *fr, const char *dir) { - log->log_printf( - log->user_data, - (NGTCP2_LOG_PKT " CRYPTO(0x%02x) offset=%" PRIu64 " len=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset, - ngtcp2_vec_len(fr->data, fr->datacnt)); + const ngtcp2_stream *fr, const char *dir) { + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64 + " len=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset, + ngtcp2_vec_len(fr->data, fr->datacnt)); } static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -427,38 +441,41 @@ static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[128 + 1 + 1]; uint8_t *p; - if (fr->token.len > 64) { - p = ngtcp2_encode_hex(buf, fr->token.base, 64); + if (fr->tokenlen > 64) { + p = ngtcp2_encode_hex(buf, fr->token, 64); p[128] = '*'; p[129] = '\0'; } else { - p = ngtcp2_encode_hex(buf, fr->token.base, fr->token.len); + p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen); } log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02x) token=0x%s len=%zu"), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->token.len); + log->user_data, + (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu"), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen); } static void log_fr_retire_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_retire_connection_id *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02x) seq=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq); } static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_handshake_done *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02x)"), + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type); } static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_datagram *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " DATAGRAM(0x%02x) len=%" PRIu64), + (NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, ngtcp2_vec_len(fr->data, fr->datacnt)); } @@ -519,7 +536,7 @@ static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log_fr_path_response(log, hd, &fr->path_response, dir); break; case NGTCP2_FRAME_CRYPTO: - log_fr_crypto(log, hd, &fr->crypto, dir); + log_fr_crypto(log, hd, &fr->stream, dir); break; case NGTCP2_FRAME_NEW_TOKEN: log_fr_new_token(log, hd, &fr->new_token, dir); @@ -535,13 +552,13 @@ static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log_fr_datagram(log, hd, &fr->datagram, dir); break; default: - assert(0); + ngtcp2_unreachable(); } } void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr) { - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -550,7 +567,7 @@ void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr) { - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -561,7 +578,7 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const uint32_t *sv, size_t nsv) { size_t i; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -576,7 +593,7 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { ngtcp2_pkt_hd shd; ngtcp2_pkt_hd *hd = &shd; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -592,82 +609,94 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { sr->randlen); } -void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, +void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params) { uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1]; uint8_t addr[16 * 2 + 7 + 1]; uint8_t cid[NGTCP2_MAX_CIDLEN * 2 + 1]; size_t i; + const ngtcp2_sockaddr_in *sa_in; + const ngtcp2_sockaddr_in6 *sa_in6; + const uint8_t *p; + uint32_t version; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_CRY)) { return; } - if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - if (params->stateless_reset_token_present) { - log->log_printf(log->user_data, - (NGTCP2_LOG_TP " stateless_reset_token=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - token, params->stateless_reset_token, - sizeof(params->stateless_reset_token))); - } + if (params->stateless_reset_token_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " stateless_reset_token=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(token, params->stateless_reset_token, + sizeof(params->stateless_reset_token))); + } + + if (params->preferred_addr_present) { + if (params->preferred_addr.ipv4_present) { + sa_in = ¶ms->preferred_addr.ipv4; - if (params->preferred_address_present) { log->log_printf(log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_ipv4( - addr, params->preferred_address.ipv4_addr)); - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"), - NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv4_port); + addr, (const uint8_t *)&sa_in->sin_addr)); + log->log_printf(log->user_data, + (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"), + NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in->sin_port)); + } + + if (params->preferred_addr.ipv6_present) { + sa_in6 = ¶ms->preferred_addr.ipv6; log->log_printf(log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_ipv6( - addr, params->preferred_address.ipv6_addr)); - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"), - NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv6_port); - + addr, (const uint8_t *)&sa_in6->sin6_addr)); log->log_printf(log->user_data, - (NGTCP2_LOG_TP " preferred_address.cid=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - cid, params->preferred_address.cid.data, - params->preferred_address.cid.datalen)); - log->log_printf( - log->user_data, - (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - token, params->preferred_address.stateless_reset_token, - sizeof(params->preferred_address.stateless_reset_token))); + (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"), + NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in6->sin6_port)); } + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " preferred_address.cid=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->preferred_addr.cid.data, + params->preferred_addr.cid.datalen)); + log->log_printf( + log->user_data, + (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex( + token, params->preferred_addr.stateless_reset_token, + sizeof(params->preferred_addr.stateless_reset_token))); + } + + if (params->original_dcid_present) { log->log_printf( log->user_data, (NGTCP2_LOG_TP " original_destination_connection_id=0x%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_hex(cid, params->original_dcid.data, params->original_dcid.datalen)); + } - if (params->retry_scid_present) { - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data, - params->retry_scid.datalen)); - } + if (params->retry_scid_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data, + params->retry_scid.datalen)); } - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data, - params->initial_scid.datalen)); + if (params->initial_scid_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data, + params->initial_scid.datalen)); + } log->log_printf( log->user_data, @@ -718,26 +747,28 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, (NGTCP2_LOG_TP " version_information.chosen_version=0x%08x"), NGTCP2_LOG_TP_HD_FIELDS, params->version_info.chosen_version); - assert(!(params->version_info.other_versionslen & 0x3)); + assert(!(params->version_info.available_versionslen & 0x3)); - for (i = 0; i < params->version_info.other_versionslen; + for (i = 0, p = params->version_info.available_versions; + i < params->version_info.available_versionslen; i += sizeof(uint32_t)) { + p = ngtcp2_get_uint32(&version, p); + log->log_printf( log->user_data, - (NGTCP2_LOG_TP " version_information.other_versions[%zu]=0x%08x"), - NGTCP2_LOG_TP_HD_FIELDS, i >> 2, - ngtcp2_get_uint32(¶ms->version_info.other_versions[i])); + (NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x"), + NGTCP2_LOG_TP_HD_FIELDS, i >> 2, version); } } } void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type, uint8_t flags, ngtcp2_tstamp sent_ts) { - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_LDC)) { return; } - ngtcp2_log_info(log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num, strpkttype_type_flags(type, flags), sent_ts); } @@ -747,7 +778,7 @@ static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t dcid[sizeof(hd->dcid.data) * 2 + 1]; uint8_t scid[sizeof(hd->scid.data) * 2 + 1]; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -782,7 +813,7 @@ void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt, int n; char buf[NGTCP2_LOG_BUFLEN]; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & ev)) { return; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h index 029ef1b757ab09..1280ce04d6385a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h @@ -37,6 +37,9 @@ typedef struct ngtcp2_log { /* log_printf is a sink to write log. NULL means no logging output. */ ngtcp2_printf log_printf; + /* events is an event filter. Only events set in this field are + emitted. */ + uint8_t events; /* ts is the time point used to write time delta in the log. */ ngtcp2_tstamp ts; /* last_ts is the most recent time point that this object is @@ -63,27 +66,33 @@ typedef enum ngtcp2_log_event { /** * :enum:`NGTCP2_LOG_EVENT_CON` is a connection (catch-all) event */ - NGTCP2_LOG_EVENT_CON, + NGTCP2_LOG_EVENT_CON = 0x1, /** * :enum:`NGTCP2_LOG_EVENT_PKT` is a packet event. */ - NGTCP2_LOG_EVENT_PKT, + NGTCP2_LOG_EVENT_PKT = 0x2, /** * :enum:`NGTCP2_LOG_EVENT_FRM` is a QUIC frame event. */ - NGTCP2_LOG_EVENT_FRM, + NGTCP2_LOG_EVENT_FRM = 0x4, /** - * :enum:`NGTCP2_LOG_EVENT_RCV` is a congestion and recovery event. + * :enum:`NGTCP2_LOG_EVENT_LDC` is a loss detection and congestion + * control event. */ - NGTCP2_LOG_EVENT_RCV, + NGTCP2_LOG_EVENT_LDC = 0x8, /** * :enum:`NGTCP2_LOG_EVENT_CRY` is a crypto event. */ - NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_EVENT_CRY = 0x10, /** * :enum:`NGTCP2_LOG_EVENT_PTV` is a path validation event. */ - NGTCP2_LOG_EVENT_PTV, + NGTCP2_LOG_EVENT_PTV = 0x20, + /** + * :enum:`NGTCP2_LOG_EVENT_CCA` is a congestion controller algorithm + * event. + */ + NGTCP2_LOG_EVENT_CCA = 0x40, } ngtcp2_log_event; void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, @@ -100,7 +109,7 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr); -void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, +void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params); void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h index e2603aae15dd04..28d3461bef9238 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h @@ -50,4 +50,9 @@ *(PD) = (T); \ } while (0) +/* + * ngtcp2_arraylen returns the number of elements in array |A|. + */ +#define ngtcp2_arraylen(A) (sizeof(A) / sizeof(A[0])) + #endif /* NGTCP2_MACRO_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c index 12bc6e84bd4f0c..33e9fcc018b5db 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c @@ -126,6 +126,7 @@ static void map_bucket_set_data(ngtcp2_map_bucket *bkt, uint32_t hash, bkt->data = data; } +#ifndef WIN32 void ngtcp2_map_print_distance(ngtcp2_map *map) { uint32_t i; size_t idx; @@ -145,6 +146,7 @@ void ngtcp2_map_print_distance(ngtcp2_map *map) { distance(map->tablelen, map->tablelenbits, bkt, idx)); } } +#endif /* !WIN32 */ static int insert(ngtcp2_map_bucket *table, uint32_t tablelen, uint32_t tablelenbits, uint32_t hash, ngtcp2_map_key_type key, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h index a64344a9a301a3..d05b1657489e45 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h @@ -131,6 +131,8 @@ size_t ngtcp2_map_size(ngtcp2_map *map); int ngtcp2_map_each(ngtcp2_map *map, int (*func)(void *data, void *ptr), void *ptr); +#ifndef WIN32 void ngtcp2_map_print_distance(ngtcp2_map *map); +#endif /* !WIN32 */ #endif /* NGTCP2_MAP_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h index b1f28096174605..bf697927351851 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h @@ -52,16 +52,11 @@ # include #endif /* HAVE_SYS_ENDIAN_H */ -#include +#if defined(__APPLE__) +# include +#endif // __APPLE__ -#if defined(HAVE_BSWAP_64) || \ - (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) -# define ngtcp2_bswap64 bswap_64 -#else /* !HAVE_BSWAP_64 */ -# define ngtcp2_bswap64(N) \ - ((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \ - ngtcp2_ntohl((uint32_t)((N) >> 32))) -#endif /* !HAVE_BSWAP_64 */ +#include #if defined(HAVE_BE64TOH) || \ (defined(HAVE_DECL_BE64TOH) && HAVE_DECL_BE64TOH > 0) @@ -72,6 +67,18 @@ # define ngtcp2_ntohl64(N) (N) # define ngtcp2_htonl64(N) (N) # else /* !WORDS_BIGENDIAN */ +# if defined(HAVE_BSWAP_64) || \ + (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) +# define ngtcp2_bswap64 bswap_64 +# elif defined(WIN32) +# define ngtcp2_bswap64 _byteswap_uint64 +# elif defined(__APPLE__) +# define ngtcp2_bswap64 OSSwapInt64 +# else /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ +# define ngtcp2_bswap64(N) \ + ((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \ + ngtcp2_ntohl((uint32_t)((N) >> 32))) +# endif /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ # define ngtcp2_ntohl64(N) ngtcp2_bswap64(N) # define ngtcp2_htonl64(N) ngtcp2_bswap64(N) # endif /* !WORDS_BIGENDIAN */ @@ -109,9 +116,9 @@ STIN uint16_t ngtcp2_htons(uint16_t hostshort) { STIN uint32_t ngtcp2_ntohl(uint32_t netlong) { uint32_t res; unsigned char *p = (unsigned char *)&netlong; - res = *p++ << 24; - res += *p++ << 16; - res += *p++ << 8; + res = (uint32_t)(*p++ << 24); + res += (uint32_t)(*p++ << 16); + res += (uint32_t)(*p++ << 8); res += *p; return res; } @@ -119,7 +126,7 @@ STIN uint32_t ngtcp2_ntohl(uint32_t netlong) { STIN uint16_t ngtcp2_ntohs(uint16_t netshort) { uint16_t res; unsigned char *p = (unsigned char *)&netshort; - res = *p++ << 8; + res = (uint16_t)(*p++ << 8); res += *p; return res; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h index f1bbd3a5c9405c..ea73e788317681 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h @@ -65,15 +65,25 @@ void ngtcp2_objalloc_free(ngtcp2_objalloc *objalloc); void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); #ifndef NOMEMPOOL -# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define ngtcp2_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \ } \ \ - inline static TYPE *ngtcp2_objalloc_##NAME##_get( \ - ngtcp2_objalloc *objalloc) { \ + TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc); \ + \ + TYPE *ngtcp2_objalloc_##NAME##_len_get(ngtcp2_objalloc *objalloc, \ + size_t len); \ + \ + inline static void ngtcp2_objalloc_##NAME##_release( \ + ngtcp2_objalloc *objalloc, TYPE *obj) { \ + ngtcp2_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ + } + +# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ + TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc) { \ ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -91,8 +101,8 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \ } \ \ - inline static TYPE *ngtcp2_objalloc_##NAME##_len_get( \ - ngtcp2_objalloc *objalloc, size_t len) { \ + TYPE *ngtcp2_objalloc_##NAME##_len_get(ngtcp2_objalloc *objalloc, \ + size_t len) { \ ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -107,14 +117,9 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); } \ \ return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \ - } \ - \ - inline static void ngtcp2_objalloc_##NAME##_release( \ - ngtcp2_objalloc *objalloc, TYPE *obj) { \ - ngtcp2_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ } #else /* NOMEMPOOL */ -# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define ngtcp2_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ @@ -135,6 +140,8 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); ngtcp2_objalloc *objalloc, TYPE *obj) { \ ngtcp2_mem_free(objalloc->balloc.mem, obj); \ } + +# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) #endif /* NOMEMPOOL */ #endif /* NGTCP2_OBJALLOC_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c index 62fef7d6005ed6..12f7daeaf242a9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -33,6 +33,7 @@ #include "ngtcp2_cid.h" #include "ngtcp2_mem.h" #include "ngtcp2_vec.h" +#include "ngtcp2_unreachable.h" int ngtcp2_pkt_chain_new(ngtcp2_pkt_chain **ppc, const ngtcp2_path *path, const ngtcp2_pkt_info *pi, const uint8_t *pkt, @@ -91,7 +92,7 @@ int ngtcp2_pkt_decode_version_cid(ngtcp2_version_cid *dest, const uint8_t *data, return NGTCP2_ERR_INVALID_ARGUMENT; } - version = ngtcp2_get_uint32(&data[1]); + ngtcp2_get_uint32(&version, &data[1]); supported_version = ngtcp2_is_supported_version(version); @@ -155,15 +156,13 @@ void ngtcp2_pkt_hd_init(ngtcp2_pkt_hd *hd, uint8_t flags, uint8_t type, ngtcp2_cid_zero(&hd->scid); } hd->pkt_num = pkt_num; - hd->token.base = NULL; - hd->token.len = 0; + hd->token = NULL; + hd->tokenlen = 0; hd->pkt_numlen = pkt_numlen; hd->version = version; hd->len = len; } -static int has_mask(uint8_t b, uint8_t mask) { return (b & mask) == mask; } - ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) { uint8_t type; @@ -186,7 +185,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, return NGTCP2_ERR_INVALID_ARGUMENT; } - version = ngtcp2_get_uint32(&pkt[1]); + ngtcp2_get_uint32(&version, &pkt[1]); if (version == 0) { type = NGTCP2_PKT_VERSION_NEGOTIATION; @@ -218,7 +217,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } } @@ -254,22 +253,20 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, if (type == NGTCP2_PKT_INITIAL) { /* Token Length */ - ntokenlen = ngtcp2_get_varint_len(p); + ntokenlen = ngtcp2_get_uvarintlen(p); len += ntokenlen - 1; if (pktlen < len) { return NGTCP2_ERR_INVALID_ARGUMENT; } - vi = ngtcp2_get_varint(&ntokenlen, p); + p = ngtcp2_get_uvarint(&vi, p); if (pktlen - len < vi) { return NGTCP2_ERR_INVALID_ARGUMENT; } tokenlen = (size_t)vi; len += tokenlen; - p += ntokenlen; - if (tokenlen) { token = p; } @@ -288,7 +285,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, } /* Length */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (pktlen < len) { @@ -308,8 +305,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, ngtcp2_cid_init(&dest->scid, p, scil); p += scil; - dest->token.base = (uint8_t *)token; - dest->token.len = tokenlen; + dest->token = token; + dest->tokenlen = tokenlen; p += ntokenlen + tokenlen; switch (type) { @@ -324,12 +321,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, break; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (vi > SIZE_MAX) { return NGTCP2_ERR_INVALID_ARGUMENT; } dest->len = (size_t)vi; - p += n; } assert((size_t)(p - pkt) == len); @@ -373,8 +369,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest, const uint8_t *pkt, dest->len = 0; dest->pkt_num = 0; dest->pkt_numlen = 0; - dest->token.base = NULL; - dest->token.len = 0; + dest->token = NULL; + dest->tokenlen = 0; assert((size_t)(p - pkt) == len); @@ -393,7 +389,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen, } if (hd->type == NGTCP2_PKT_INITIAL) { - len += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; + len += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen; } if (outlen < len) { @@ -422,14 +418,14 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen, } if (hd->type == NGTCP2_PKT_INITIAL) { - p = ngtcp2_put_varint(p, hd->token.len); - if (hd->token.len) { - p = ngtcp2_cpymem(p, hd->token.base, hd->token.len); + p = ngtcp2_put_uvarint(p, hd->tokenlen); + if (hd->tokenlen) { + p = ngtcp2_cpymem(p, hd->token, hd->tokenlen); } } if (hd->type != NGTCP2_PKT_RETRY) { - p = ngtcp2_put_varint30(p, (uint32_t)hd->len); + p = ngtcp2_put_uvarint30(p, (uint32_t)hd->len); p = ngtcp2_put_pkt_num(p, hd->pkt_num, hd->pkt_numlen); } @@ -475,15 +471,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, uint8_t type; if (payloadlen == 0) { - return 0; + return NGTCP2_ERR_FRAME_ENCODING; } type = payload[0]; switch (type) { case NGTCP2_FRAME_PADDING: - return (ngtcp2_ssize)ngtcp2_pkt_decode_padding_frame(&dest->padding, - payload, payloadlen); + return ngtcp2_pkt_decode_padding_frame(&dest->padding, payload, payloadlen); case NGTCP2_FRAME_RESET_STREAM: return ngtcp2_pkt_decode_reset_stream_frame(&dest->reset_stream, payload, payloadlen); @@ -529,7 +524,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, return ngtcp2_pkt_decode_path_response_frame(&dest->path_response, payload, payloadlen); case NGTCP2_FRAME_CRYPTO: - return ngtcp2_pkt_decode_crypto_frame(&dest->crypto, payload, payloadlen); + return ngtcp2_pkt_decode_crypto_frame(&dest->stream, payload, payloadlen); case NGTCP2_FRAME_NEW_TOKEN: return ngtcp2_pkt_decode_new_token_frame(&dest->new_token, payload, payloadlen); @@ -544,9 +539,15 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, return ngtcp2_pkt_decode_datagram_frame(&dest->datagram, payload, payloadlen); default: - if (has_mask(type, NGTCP2_FRAME_STREAM)) { + if ((type & ~(NGTCP2_FRAME_STREAM - 1)) == NGTCP2_FRAME_STREAM) { return ngtcp2_pkt_decode_stream_frame(&dest->stream, payload, payloadlen); } + + /* For frame types > 0xff, use ngtcp2_get_uvarintlen and + ngtcp2_get_uvarint to get a frame type, and then switch over + it. Verify that payloadlen >= ngtcp2_get_uvarintlen(payload) + before calling ngtcp2_get_uvarint(payload). */ + return NGTCP2_ERR_FRAME_ENCODING; } } @@ -570,7 +571,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -585,7 +586,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, return NGTCP2_ERR_FRAME_ENCODING; } - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -601,14 +602,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, return NGTCP2_ERR_FRAME_ENCODING; } - ndatalen = ngtcp2_get_varint_len(p); + ndatalen = ngtcp2_get_uvarintlen(p); len += ndatalen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&ndatalen, p); + /* p = */ ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -623,12 +624,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, dest->type = NGTCP2_FRAME_STREAM; dest->flags = (uint8_t)(type & ~NGTCP2_FRAME_STREAM); dest->fin = (type & NGTCP2_STREAM_FIN_BIT) != 0; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); if (type & NGTCP2_STREAM_OFF_BIT) { - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->offset, p); } else { dest->offset = 0; } @@ -656,12 +655,12 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, const uint8_t *payload, size_t payloadlen) { - size_t num_blks, max_num_blks; - size_t nnum_blks; + size_t rangecnt, max_rangecnt; + size_t nrangecnt; size_t len = 1 + 1 + 1 + 1 + 1; const uint8_t *p; size_t i, j; - ngtcp2_ack_blk *blk; + ngtcp2_ack_range *range; size_t n; uint8_t type; uint64_t vi; @@ -675,7 +674,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p = payload + 1; /* Largest Acknowledged */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -685,7 +684,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; /* ACK Delay */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -694,26 +693,24 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; - /* ACK Block Count */ - nnum_blks = ngtcp2_get_varint_len(p); - len += nnum_blks - 1; + /* ACK Range Count */ + nrangecnt = ngtcp2_get_uvarintlen(p); + len += nrangecnt - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&nnum_blks, p); + p = ngtcp2_get_uvarint(&vi, p); if (vi > SIZE_MAX / (1 + 1) || payloadlen - len < vi * (1 + 1)) { return NGTCP2_ERR_FRAME_ENCODING; } - num_blks = (size_t)vi; - len += num_blks * (1 + 1); - - p += nnum_blks; + rangecnt = (size_t)vi; + len += rangecnt * (1 + 1); - /* First ACK Block */ - n = ngtcp2_get_varint_len(p); + /* First ACK Range */ + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -722,10 +719,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; - for (i = 0; i < num_blks; ++i) { - /* Gap, and Additional ACK Block */ + for (i = 0; i < rangecnt; ++i) { + /* Gap, and Additional ACK Range */ for (j = 0; j < 2; ++j) { - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -743,7 +740,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, } for (i = 0; i < 3; ++i) { - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -754,44 +751,34 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, } } - /* TODO We might not decode all blocks. It could be very large. */ - max_num_blks = ngtcp2_min(NGTCP2_MAX_ACK_BLKS, num_blks); + /* TODO We might not decode all ranges. It could be very large. */ + max_rangecnt = ngtcp2_min(NGTCP2_MAX_ACK_RANGES, rangecnt); p = payload + 1; dest->type = type; - dest->largest_ack = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->ack_delay = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_varint(&dest->largest_ack, p); + p = ngtcp2_get_uvarint(&dest->ack_delay, p); /* This value will be assigned in the upper layer. */ dest->ack_delay_unscaled = 0; - p += n; - dest->num_blks = max_num_blks; - p += nnum_blks; - dest->first_ack_blklen = ngtcp2_get_varint(&n, p); - p += n; + dest->rangecnt = max_rangecnt; + p += nrangecnt; + p = ngtcp2_get_uvarint(&dest->first_ack_range, p); - for (i = 0; i < max_num_blks; ++i) { - blk = &dest->blks[i]; - blk->gap = ngtcp2_get_varint(&n, p); - p += n; - blk->blklen = ngtcp2_get_varint(&n, p); - p += n; + for (i = 0; i < max_rangecnt; ++i) { + range = &dest->ranges[i]; + p = ngtcp2_get_uvarint(&range->gap, p); + p = ngtcp2_get_uvarint(&range->len, p); } - for (i = max_num_blks; i < num_blks; ++i) { - p += ngtcp2_get_varint_len(p); - p += ngtcp2_get_varint_len(p); + for (i = max_rangecnt; i < rangecnt; ++i) { + p += ngtcp2_get_uvarintlen(p); + p += ngtcp2_get_uvarintlen(p); } if (type == NGTCP2_FRAME_ACK_ECN) { - dest->ecn.ect0 = ngtcp2_get_varint(&n, p); - p += n; - - dest->ecn.ect1 = ngtcp2_get_varint(&n, p); - p += n; - - dest->ecn.ce = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->ecn.ect0, p); + p = ngtcp2_get_uvarint(&dest->ecn.ect1, p); + p = ngtcp2_get_uvarint(&dest->ecn.ce, p); } assert((size_t)(p - payload) == len); @@ -799,9 +786,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, return (ngtcp2_ssize)len; } -size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, - const uint8_t *payload, - size_t payloadlen) { +ngtcp2_ssize ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, + const uint8_t *payload, + size_t payloadlen) { const uint8_t *p, *ep; assert(payloadlen > 0); @@ -815,7 +802,7 @@ size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, dest->type = NGTCP2_FRAME_PADDING; dest->len = (size_t)(p - payload); - return dest->len; + return (ngtcp2_ssize)dest->len; } ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, @@ -831,19 +818,19 @@ ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -852,12 +839,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, p = payload + 1; dest->type = NGTCP2_FRAME_RESET_STREAM; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->app_error_code = ngtcp2_get_varint(&n, p); - p += n; - dest->final_size = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->app_error_code, p); + p = ngtcp2_get_uvarint(&dest->final_size, p); assert((size_t)(p - payload) == len); @@ -882,7 +866,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -893,7 +877,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( if (type == NGTCP2_FRAME_CONNECTION_CLOSE) { ++len; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -902,13 +886,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p += n; } - nreasonlen = ngtcp2_get_varint_len(p); + nreasonlen = ngtcp2_get_uvarintlen(p); len += nreasonlen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&nreasonlen, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -918,11 +902,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p = payload + 1; dest->type = type; - dest->error_code = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->error_code, p); if (type == NGTCP2_FRAME_CONNECTION_CLOSE) { - dest->frame_type = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->frame_type, p); } else { dest->frame_type = 0; } @@ -953,7 +935,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_data_frame(ngtcp2_max_data *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -961,8 +943,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_data_frame(ngtcp2_max_data *dest, } dest->type = NGTCP2_FRAME_MAX_DATA; - dest->max_data = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_data, p); assert((size_t)(p - payload) == len); @@ -981,7 +962,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -990,7 +971,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1000,10 +981,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p = payload + 1; dest->type = NGTCP2_FRAME_MAX_STREAM_DATA; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->max_stream_data = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->max_stream_data, p); assert((size_t)(p - payload) == len); @@ -1023,7 +1002,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1031,8 +1010,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, } dest->type = payload[0]; - dest->max_streams = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_streams, p); assert((size_t)(p - payload) == len); @@ -1062,7 +1040,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_data_blocked_frame(ngtcp2_data_blocked *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1070,8 +1048,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_data_blocked_frame(ngtcp2_data_blocked *dest, } dest->type = NGTCP2_FRAME_DATA_BLOCKED; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->offset, p); assert((size_t)(p - payload) == len); @@ -1092,7 +1069,7 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1101,7 +1078,7 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1111,10 +1088,8 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p = payload + 1; dest->type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->offset, p); assert((size_t)(p - payload) == len); @@ -1133,7 +1108,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_streams_blocked_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1141,8 +1116,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_streams_blocked_frame( } dest->type = payload[0]; - dest->max_streams = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_streams, p); assert((size_t)(p - payload) == len); @@ -1162,7 +1136,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1170,7 +1144,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1191,14 +1165,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p = payload + 1; dest->type = NGTCP2_FRAME_NEW_CONNECTION_ID; - dest->seq = ngtcp2_get_varint(&n, p); - p += n; - dest->retire_prior_to = ngtcp2_get_varint(&n, p); - p += n + 1; + p = ngtcp2_get_uvarint(&dest->seq, p); + p = ngtcp2_get_uvarint(&dest->retire_prior_to, p); + ++p; ngtcp2_cid_init(&dest->cid, p, cil); p += cil; - memcpy(dest->stateless_reset_token, p, NGTCP2_STATELESS_RESET_TOKENLEN); - p += NGTCP2_STATELESS_RESET_TOKENLEN; + p = ngtcp2_get_bytes(dest->stateless_reset_token, p, + NGTCP2_STATELESS_RESET_TOKENLEN); assert((size_t)(p - payload) == len); @@ -1218,14 +1191,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1235,10 +1208,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, p = payload + 1; dest->type = NGTCP2_FRAME_STOP_SENDING; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->app_error_code = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->app_error_code, p); assert((size_t)(p - payload) == len); @@ -1287,7 +1258,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest, return (ngtcp2_ssize)len; } -ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, +ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_stream *dest, const uint8_t *payload, size_t payloadlen) { size_t len = 1 + 1 + 1; @@ -1303,7 +1274,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1312,14 +1283,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p += n; - ndatalen = ngtcp2_get_varint_len(p); + ndatalen = ngtcp2_get_uvarintlen(p); len += ndatalen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&ndatalen, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1330,8 +1301,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p = payload + 1; dest->type = NGTCP2_FRAME_CRYPTO; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + dest->flags = 0; + dest->fin = 0; + dest->stream_id = 0; + p = ngtcp2_get_uvarint(&dest->offset, p); dest->data[0].len = datalen; p += ndatalen; if (dest->data[0].len) { @@ -1363,14 +1336,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1378,10 +1351,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, len += datalen; dest->type = NGTCP2_FRAME_NEW_TOKEN; - dest->token.len = datalen; - p += n; - dest->token.base = (uint8_t *)p; - p += dest->token.len; + dest->tokenlen = datalen; + dest->token = (uint8_t *)p; + p += dest->tokenlen; assert((size_t)(p - payload) == len); @@ -1402,7 +1374,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1410,8 +1382,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, } dest->type = NGTCP2_FRAME_RETIRE_CONNECTION_ID; - dest->seq = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->seq, p); assert((size_t)(p - payload) == len); @@ -1457,14 +1428,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, return NGTCP2_ERR_FRAME_ENCODING; } - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1473,8 +1444,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, len += datalen; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } dest->type = type; @@ -1482,19 +1452,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, if (datalen == 0) { dest->datacnt = 0; dest->data = NULL; - - if (type == NGTCP2_FRAME_DATAGRAM_LEN) { - p += n; - } } else { dest->datacnt = 1; dest->data = dest->rdata; dest->rdata[0].len = datalen; - if (type == NGTCP2_FRAME_DATAGRAM_LEN) { - p += n; - } - dest->rdata[0].base = (uint8_t *)p; p += datalen; } @@ -1551,7 +1513,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen, return ngtcp2_pkt_encode_path_response_frame(out, outlen, &fr->path_response); case NGTCP2_FRAME_CRYPTO: - return ngtcp2_pkt_encode_crypto_frame(out, outlen, &fr->crypto); + return ngtcp2_pkt_encode_crypto_frame(out, outlen, &fr->stream); case NGTCP2_FRAME_NEW_TOKEN: return ngtcp2_pkt_encode_new_token_frame(out, outlen, &fr->new_token); case NGTCP2_FRAME_RETIRE_CONNECTION_ID: @@ -1582,16 +1544,16 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, if (fr->offset) { flags |= NGTCP2_STREAM_OFF_BIT; - len += ngtcp2_put_varint_len(fr->offset); + len += ngtcp2_put_uvarintlen(fr->offset); } - len += ngtcp2_put_varint_len((uint64_t)fr->stream_id); + len += ngtcp2_put_uvarintlen((uint64_t)fr->stream_id); for (i = 0; i < fr->datacnt; ++i) { datalen += fr->data[i].len; } - len += ngtcp2_put_varint_len(datalen); + len += ngtcp2_put_uvarintlen(datalen); len += datalen; if (outlen < len) { @@ -1604,13 +1566,13 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, fr->flags = flags; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); if (fr->offset) { - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, fr->offset); } - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, datalen); for (i = 0; i < fr->datacnt; ++i) { assert(fr->data[i].len); @@ -1625,24 +1587,24 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_ack_frame(uint8_t *out, size_t outlen, ngtcp2_ack *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->largest_ack) + - ngtcp2_put_varint_len(fr->ack_delay) + - ngtcp2_put_varint_len(fr->num_blks) + - ngtcp2_put_varint_len(fr->first_ack_blklen); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->largest_ack) + + ngtcp2_put_uvarintlen(fr->ack_delay) + + ngtcp2_put_uvarintlen(fr->rangecnt) + + ngtcp2_put_uvarintlen(fr->first_ack_range); uint8_t *p; size_t i; - const ngtcp2_ack_blk *blk; + const ngtcp2_ack_range *range; - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - len += ngtcp2_put_varint_len(blk->gap); - len += ngtcp2_put_varint_len(blk->blklen); + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + len += ngtcp2_put_uvarintlen(range->gap); + len += ngtcp2_put_uvarintlen(range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - len += ngtcp2_put_varint_len(fr->ecn.ect0) + - ngtcp2_put_varint_len(fr->ecn.ect1) + - ngtcp2_put_varint_len(fr->ecn.ce); + len += ngtcp2_put_uvarintlen(fr->ecn.ect0) + + ngtcp2_put_uvarintlen(fr->ecn.ect1) + + ngtcp2_put_uvarintlen(fr->ecn.ce); } if (outlen < len) { @@ -1651,22 +1613,22 @@ ngtcp2_ssize ngtcp2_pkt_encode_ack_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, (uint64_t)fr->largest_ack); - p = ngtcp2_put_varint(p, fr->ack_delay); - p = ngtcp2_put_varint(p, fr->num_blks); - p = ngtcp2_put_varint(p, fr->first_ack_blklen); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, (uint64_t)fr->largest_ack); + p = ngtcp2_put_uvarint(p, fr->ack_delay); + p = ngtcp2_put_uvarint(p, fr->rangecnt); + p = ngtcp2_put_uvarint(p, fr->first_ack_range); - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - p = ngtcp2_put_varint(p, blk->gap); - p = ngtcp2_put_varint(p, blk->blklen); + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + p = ngtcp2_put_uvarint(p, range->gap); + p = ngtcp2_put_uvarint(p, range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - p = ngtcp2_put_varint(p, fr->ecn.ect0); - p = ngtcp2_put_varint(p, fr->ecn.ect1); - p = ngtcp2_put_varint(p, fr->ecn.ce); + p = ngtcp2_put_uvarint(p, fr->ecn.ect0); + p = ngtcp2_put_uvarint(p, fr->ecn.ect1); + p = ngtcp2_put_uvarint(p, fr->ecn.ce); } assert((size_t)(p - out) == len); @@ -1688,9 +1650,9 @@ ngtcp2_ssize ngtcp2_pkt_encode_padding_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, const ngtcp2_reset_stream *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->app_error_code) + - ngtcp2_put_varint_len(fr->final_size); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->app_error_code) + + ngtcp2_put_uvarintlen(fr->final_size); uint8_t *p; if (outlen < len) { @@ -1700,9 +1662,9 @@ ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_RESET_STREAM; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->app_error_code); - p = ngtcp2_put_varint(p, fr->final_size); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->app_error_code); + p = ngtcp2_put_uvarint(p, fr->final_size); assert((size_t)(p - out) == len); @@ -1712,11 +1674,11 @@ ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, const ngtcp2_connection_close *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->error_code) + + size_t len = 1 + ngtcp2_put_uvarintlen(fr->error_code) + (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE - ? ngtcp2_put_varint_len(fr->frame_type) + ? ngtcp2_put_uvarintlen(fr->frame_type) : 0) + - ngtcp2_put_varint_len(fr->reasonlen) + fr->reasonlen; + ngtcp2_put_uvarintlen(fr->reasonlen) + fr->reasonlen; uint8_t *p; if (outlen < len) { @@ -1725,12 +1687,12 @@ ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->error_code); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->error_code); if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) { - p = ngtcp2_put_varint(p, fr->frame_type); + p = ngtcp2_put_uvarint(p, fr->frame_type); } - p = ngtcp2_put_varint(p, fr->reasonlen); + p = ngtcp2_put_uvarint(p, fr->reasonlen); if (fr->reasonlen) { p = ngtcp2_cpymem(p, fr->reason, fr->reasonlen); } @@ -1742,7 +1704,7 @@ ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, const ngtcp2_max_data *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_data); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_data); uint8_t *p; if (outlen < len) { @@ -1752,7 +1714,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_MAX_DATA; - p = ngtcp2_put_varint(p, fr->max_data); + p = ngtcp2_put_uvarint(p, fr->max_data); assert((size_t)(p - out) == len); @@ -1762,8 +1724,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, const ngtcp2_max_stream_data *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->max_stream_data); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->max_stream_data); uint8_t *p; if (outlen < len) { @@ -1773,8 +1735,8 @@ ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_MAX_STREAM_DATA; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->max_stream_data); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->max_stream_data); assert((size_t)(p - out) == len); @@ -1783,7 +1745,7 @@ ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_streams_frame(uint8_t *out, size_t outlen, const ngtcp2_max_streams *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_streams); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_streams); uint8_t *p; if (outlen < len) { @@ -1792,8 +1754,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_streams_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->max_streams); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->max_streams); assert((size_t)(p - out) == len); @@ -1816,7 +1778,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_ping_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, const ngtcp2_data_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->offset); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->offset); uint8_t *p; if (outlen < len) { @@ -1826,7 +1788,7 @@ ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_DATA_BLOCKED; - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, fr->offset); assert((size_t)(p - out) == len); @@ -1835,8 +1797,8 @@ ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( uint8_t *out, size_t outlen, const ngtcp2_stream_data_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->offset); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->offset); uint8_t *p; if (outlen < len) { @@ -1846,8 +1808,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( p = out; *p++ = NGTCP2_FRAME_STREAM_DATA_BLOCKED; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->offset); assert((size_t)(p - out) == len); @@ -1857,7 +1819,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( ngtcp2_ssize ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, const ngtcp2_streams_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_streams); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_streams); uint8_t *p; if (outlen < len) { @@ -1866,8 +1828,8 @@ ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->max_streams); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->max_streams); assert((size_t)(p - out) == len); @@ -1877,8 +1839,8 @@ ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, const ngtcp2_new_connection_id *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->seq) + - ngtcp2_put_varint_len(fr->retire_prior_to) + 1 + + size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq) + + ngtcp2_put_uvarintlen(fr->retire_prior_to) + 1 + fr->cid.datalen + NGTCP2_STATELESS_RESET_TOKENLEN; uint8_t *p; @@ -1889,8 +1851,8 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_NEW_CONNECTION_ID; - p = ngtcp2_put_varint(p, fr->seq); - p = ngtcp2_put_varint(p, fr->retire_prior_to); + p = ngtcp2_put_uvarint(p, fr->seq); + p = ngtcp2_put_uvarint(p, fr->retire_prior_to); *p++ = (uint8_t)fr->cid.datalen; p = ngtcp2_cpymem(p, fr->cid.data, fr->cid.datalen); p = ngtcp2_cpymem(p, fr->stateless_reset_token, @@ -1904,8 +1866,8 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, const ngtcp2_stop_sending *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->app_error_code); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->app_error_code); uint8_t *p; if (outlen < len) { @@ -1915,8 +1877,8 @@ ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_STOP_SENDING; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->app_error_code); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->app_error_code); assert((size_t)(p - out) == len); @@ -1964,19 +1926,19 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen, } ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, - const ngtcp2_crypto *fr) { + const ngtcp2_stream *fr) { size_t len = 1; uint8_t *p; size_t i; size_t datalen = 0; - len += ngtcp2_put_varint_len(fr->offset); + len += ngtcp2_put_uvarintlen(fr->offset); for (i = 0; i < fr->datacnt; ++i) { datalen += fr->data[i].len; } - len += ngtcp2_put_varint_len(datalen); + len += ngtcp2_put_uvarintlen(datalen); len += datalen; if (outlen < len) { @@ -1987,8 +1949,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, *p++ = NGTCP2_FRAME_CRYPTO; - p = ngtcp2_put_varint(p, fr->offset); - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, fr->offset); + p = ngtcp2_put_uvarint(p, datalen); for (i = 0; i < fr->datacnt; ++i) { assert(fr->data[i].base); @@ -2002,10 +1964,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, const ngtcp2_new_token *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->token.len) + fr->token.len; + size_t len = 1 + ngtcp2_put_uvarintlen(fr->tokenlen) + fr->tokenlen; uint8_t *p; - assert(fr->token.len); + assert(fr->tokenlen); if (outlen < len) { return NGTCP2_ERR_NOBUF; @@ -2015,8 +1977,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, *p++ = NGTCP2_FRAME_NEW_TOKEN; - p = ngtcp2_put_varint(p, fr->token.len); - p = ngtcp2_cpymem(p, fr->token.base, fr->token.len); + p = ngtcp2_put_uvarint(p, fr->tokenlen); + p = ngtcp2_cpymem(p, fr->token, fr->tokenlen); assert((size_t)(p - out) == len); @@ -2025,7 +1987,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_retire_connection_id_frame( uint8_t *out, size_t outlen, const ngtcp2_retire_connection_id *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->seq); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq); uint8_t *p; if (outlen < len) { @@ -2036,7 +1998,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_retire_connection_id_frame( *p++ = NGTCP2_FRAME_RETIRE_CONNECTION_ID; - p = ngtcp2_put_varint(p, fr->seq); + p = ngtcp2_put_uvarint(p, fr->seq); assert((size_t)(p - out) == len); @@ -2062,7 +2024,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen, uint64_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt); uint64_t len = 1 + - (fr->type == NGTCP2_FRAME_DATAGRAM ? 0 : ngtcp2_put_varint_len(datalen)) + + (fr->type == NGTCP2_FRAME_DATAGRAM ? 0 : ngtcp2_put_uvarintlen(datalen)) + datalen; uint8_t *p; size_t i; @@ -2076,9 +2038,9 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; + *p++ = (uint8_t)fr->type; if (fr->type == NGTCP2_FRAME_DATAGRAM_LEN) { - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, datalen); } for (i = 0; i < fr->datacnt; ++i) { @@ -2109,7 +2071,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_negotiation( p = dest; - *p++ = 0x80 | unused_random; + *p++ = 0xc0 | unused_random; p = ngtcp2_put_uint32be(p, 0); *p++ = (uint8_t)dcidlen; if (dcidlen) { @@ -2136,8 +2098,8 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest, assert((payloadlen % sizeof(uint32_t)) == 0); - for (; payload != end; payload += sizeof(uint32_t)) { - *dest++ = ngtcp2_get_uint32(payload); + for (; payload != end;) { + payload = ngtcp2_get_uint32(dest++, payload); } return payloadlen / sizeof(uint32_t); @@ -2169,9 +2131,9 @@ int ngtcp2_pkt_decode_retry(ngtcp2_pkt_retry *dest, const uint8_t *payload, return NGTCP2_ERR_INVALID_ARGUMENT; } - dest->token.base = (uint8_t *)payload; - dest->token.len = (size_t)(payloadlen - NGTCP2_RETRY_TAGLEN); - ngtcp2_cpymem(dest->tag, payload + dest->token.len, NGTCP2_RETRY_TAGLEN); + dest->token = (uint8_t *)payload; + dest->tokenlen = (size_t)(payloadlen - NGTCP2_RETRY_TAGLEN); + ngtcp2_cpymem(dest->tag, payload + dest->tokenlen, NGTCP2_RETRY_TAGLEN); return 0; } @@ -2194,28 +2156,36 @@ int64_t ngtcp2_pkt_adjust_pkt_num(int64_t max_pkt_num, int64_t pkt_num, return cand; } -int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr) { +int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr, int64_t min_pkt_num) { int64_t largest_ack = fr->largest_ack; size_t i; - if (largest_ack < (int64_t)fr->first_ack_blklen) { + if (largest_ack < (int64_t)fr->first_ack_range) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->first_ack_blklen; + largest_ack -= (int64_t)fr->first_ack_range; + + if (largest_ack < min_pkt_num) { + return NGTCP2_ERR_PROTO; + } - for (i = 0; i < fr->num_blks; ++i) { - if (largest_ack < (int64_t)fr->blks[i].gap + 2) { + for (i = 0; i < fr->rangecnt; ++i) { + if (largest_ack < (int64_t)fr->ranges[i].gap + 2) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->blks[i].gap + 2; + largest_ack -= (int64_t)fr->ranges[i].gap + 2; - if (largest_ack < (int64_t)fr->blks[i].blklen) { + if (largest_ack < (int64_t)fr->ranges[i].len) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->blks[i].blklen; + largest_ack -= (int64_t)fr->ranges[i].len; + + if (largest_ack < min_pkt_num) { + return NGTCP2_ERR_PROTO; + } } return 0; @@ -2285,16 +2255,14 @@ ngtcp2_ssize ngtcp2_pkt_write_retry( switch (version) { case NGTCP2_PROTO_VER_V1: + default: nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } /* OpenSSL does not like NULL plaintext. */ @@ -2377,16 +2345,14 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t version, const ngtcp2_pkt_retry *retry, switch (version) { case NGTCP2_PROTO_VER_V1: + default: nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } /* OpenSSL does not like NULL plaintext. */ @@ -2405,8 +2371,8 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t version, const ngtcp2_pkt_retry *retry, size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, uint64_t len, size_t left) { - size_t n = 1 /* type */ + ngtcp2_put_varint_len((uint64_t)stream_id) + - (offset ? ngtcp2_put_varint_len(offset) : 0); + size_t n = 1 /* type */ + ngtcp2_put_uvarintlen((uint64_t)stream_id) + + (offset ? ngtcp2_put_uvarintlen(offset) : 0); if (left <= n) { return (size_t)-1; @@ -2436,7 +2402,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, } size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { - size_t n = 1 /* type */ + ngtcp2_put_varint_len(offset); + size_t n = 1 /* type */ + ngtcp2_put_uvarintlen(offset); /* CRYPTO frame must contain nonzero length data. Return -1 if there is no space to write crypto data. */ @@ -2468,17 +2434,16 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { } size_t ngtcp2_pkt_datagram_framelen(size_t len) { - return 1 /* type */ + ngtcp2_put_varint_len(len) + len; + return 1 /* type */ + ngtcp2_put_uvarintlen(len) + len; } int ngtcp2_is_supported_version(uint32_t version) { switch (version) { case NGTCP2_PROTO_VER_V1: - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: return 1; default: - return NGTCP2_PROTO_VER_DRAFT_MIN <= version && - version <= NGTCP2_PROTO_VER_DRAFT_MAX; + return 0; } } @@ -2491,15 +2456,15 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { uint8_t pkt_type = (uint8_t)((c & NGTCP2_LONG_TYPE_MASK) >> 4); switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: switch (pkt_type) { - case NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT: + case NGTCP2_PKT_TYPE_INITIAL_V2: return NGTCP2_PKT_INITIAL; - case NGTCP2_PKT_TYPE_0RTT_V2_DRAFT: + case NGTCP2_PKT_TYPE_0RTT_V2: return NGTCP2_PKT_0RTT; - case NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT: + case NGTCP2_PKT_TYPE_HANDSHAKE_V2: return NGTCP2_PKT_HANDSHAKE; - case NGTCP2_PKT_TYPE_RETRY_V2_DRAFT: + case NGTCP2_PKT_TYPE_RETRY_V2: return NGTCP2_PKT_RETRY; default: return 0; @@ -2509,8 +2474,6 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { return 0; } - /* QUIC v1 and draft versions share the same numeric packet - types. */ switch (pkt_type) { case NGTCP2_PKT_TYPE_INITIAL_V1: return NGTCP2_PKT_INITIAL; @@ -2528,27 +2491,24 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { uint8_t ngtcp2_pkt_versioned_type(uint32_t version, uint32_t pkt_type) { switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: switch (pkt_type) { case NGTCP2_PKT_INITIAL: - return NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT; + return NGTCP2_PKT_TYPE_INITIAL_V2; case NGTCP2_PKT_0RTT: - return NGTCP2_PKT_TYPE_0RTT_V2_DRAFT; + return NGTCP2_PKT_TYPE_0RTT_V2; case NGTCP2_PKT_HANDSHAKE: - return NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT; + return NGTCP2_PKT_TYPE_HANDSHAKE_V2; case NGTCP2_PKT_RETRY: - return NGTCP2_PKT_TYPE_RETRY_V2_DRAFT; + return NGTCP2_PKT_TYPE_RETRY_V2; default: - assert(0); - abort(); + ngtcp2_unreachable(); } default: /* Assume that unsupported versions share the numeric long packet types with QUIC v1 in order to send a packet to elicit Version Negotiation packet. */ - /* QUIC v1 and draft versions share the same numeric packet - types. */ switch (pkt_type) { case NGTCP2_PKT_INITIAL: return NGTCP2_PKT_TYPE_INITIAL_V1; @@ -2559,8 +2519,7 @@ uint8_t ngtcp2_pkt_versioned_type(uint32_t version, uint32_t pkt_type) { case NGTCP2_PKT_RETRY: return NGTCP2_PKT_TYPE_RETRY_V1; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h index 2f7838a08a5625..b1bec97c31a08c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h @@ -88,9 +88,9 @@ client stream ID. */ #define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3ffffffffffffffell) -/* NGTCP2_MAX_NUM_ACK_BLK is the maximum number of Additional ACK - blocks which this library can create, or decode. */ -#define NGTCP2_MAX_ACK_BLKS 32 +/* NGTCP2_MAX_NUM_ACK_RANGES is the maximum number of Additional ACK + ranges which this library can create, or decode. */ +#define NGTCP2_MAX_ACK_RANGES 32 /* NGTCP2_MAX_PKT_NUM is the maximum packet number. */ #define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1)) @@ -124,62 +124,67 @@ v1. */ #define NGTCP2_PKT_TYPE_RETRY_V1 0x3 -/* NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT is Initial long header packet type - for QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT 0x1 -/* NGTCP2_PKT_TYPE_0RTT_V2_DRAFT is 0RTT long header packet type for - QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_0RTT_V2_DRAFT 0x2 -/* NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT is Handshake long header packet - type for QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT 0x3 -/* NGTCP2_PKT_TYPE_RETRY_V2_DRAFT is Retry long header packet type for - QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_RETRY_V2_DRAFT 0x0 +/* NGTCP2_PKT_TYPE_INITIAL_V2 is Initial long header packet type for + QUIC v2. */ +#define NGTCP2_PKT_TYPE_INITIAL_V2 0x1 +/* NGTCP2_PKT_TYPE_0RTT_V2 is 0RTT long header packet type for QUIC + v2. */ +#define NGTCP2_PKT_TYPE_0RTT_V2 0x2 +/* NGTCP2_PKT_TYPE_HANDSHAKE_V2 is Handshake long header packet type + for QUIC v2. */ +#define NGTCP2_PKT_TYPE_HANDSHAKE_V2 0x3 +/* NGTCP2_PKT_TYPE_RETRY_V2 is Retry long header packet type for QUIC + v2. */ +#define NGTCP2_PKT_TYPE_RETRY_V2 0x0 typedef struct ngtcp2_pkt_retry { ngtcp2_cid odcid; - ngtcp2_vec token; + uint8_t *token; + size_t tokenlen; uint8_t tag[NGTCP2_RETRY_TAGLEN]; } ngtcp2_pkt_retry; -typedef enum { - NGTCP2_FRAME_PADDING = 0x00, - NGTCP2_FRAME_PING = 0x01, - NGTCP2_FRAME_ACK = 0x02, - NGTCP2_FRAME_ACK_ECN = 0x03, - NGTCP2_FRAME_RESET_STREAM = 0x04, - NGTCP2_FRAME_STOP_SENDING = 0x05, - NGTCP2_FRAME_CRYPTO = 0x06, - NGTCP2_FRAME_NEW_TOKEN = 0x07, - NGTCP2_FRAME_STREAM = 0x08, - NGTCP2_FRAME_MAX_DATA = 0x10, - NGTCP2_FRAME_MAX_STREAM_DATA = 0x11, - NGTCP2_FRAME_MAX_STREAMS_BIDI = 0x12, - NGTCP2_FRAME_MAX_STREAMS_UNI = 0x13, - NGTCP2_FRAME_DATA_BLOCKED = 0x14, - NGTCP2_FRAME_STREAM_DATA_BLOCKED = 0x15, - NGTCP2_FRAME_STREAMS_BLOCKED_BIDI = 0x16, - NGTCP2_FRAME_STREAMS_BLOCKED_UNI = 0x17, - NGTCP2_FRAME_NEW_CONNECTION_ID = 0x18, - NGTCP2_FRAME_RETIRE_CONNECTION_ID = 0x19, - NGTCP2_FRAME_PATH_CHALLENGE = 0x1a, - NGTCP2_FRAME_PATH_RESPONSE = 0x1b, - NGTCP2_FRAME_CONNECTION_CLOSE = 0x1c, - NGTCP2_FRAME_CONNECTION_CLOSE_APP = 0x1d, - NGTCP2_FRAME_HANDSHAKE_DONE = 0x1e, - NGTCP2_FRAME_DATAGRAM = 0x30, - NGTCP2_FRAME_DATAGRAM_LEN = 0x31, -} ngtcp2_frame_type; - +#define NGTCP2_FRAME_PADDING 0x00 +#define NGTCP2_FRAME_PING 0x01 +#define NGTCP2_FRAME_ACK 0x02 +#define NGTCP2_FRAME_ACK_ECN 0x03 +#define NGTCP2_FRAME_RESET_STREAM 0x04 +#define NGTCP2_FRAME_STOP_SENDING 0x05 +#define NGTCP2_FRAME_CRYPTO 0x06 +#define NGTCP2_FRAME_NEW_TOKEN 0x07 +#define NGTCP2_FRAME_STREAM 0x08 +#define NGTCP2_FRAME_MAX_DATA 0x10 +#define NGTCP2_FRAME_MAX_STREAM_DATA 0x11 +#define NGTCP2_FRAME_MAX_STREAMS_BIDI 0x12 +#define NGTCP2_FRAME_MAX_STREAMS_UNI 0x13 +#define NGTCP2_FRAME_DATA_BLOCKED 0x14 +#define NGTCP2_FRAME_STREAM_DATA_BLOCKED 0x15 +#define NGTCP2_FRAME_STREAMS_BLOCKED_BIDI 0x16 +#define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17 +#define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18 +#define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19 +#define NGTCP2_FRAME_PATH_CHALLENGE 0x1a +#define NGTCP2_FRAME_PATH_RESPONSE 0x1b +#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1c +#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1d +#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1e +#define NGTCP2_FRAME_DATAGRAM 0x30 +#define NGTCP2_FRAME_DATAGRAM_LEN 0x31 + +/* ngtcp2_stream represents STREAM and CRYPTO frames. */ typedef struct ngtcp2_stream { - uint8_t type; + uint64_t type; /** * flags of decoded STREAM frame. This gets ignored when encoding - * STREAM frame. + * STREAM frame. CRYPTO frame does not include this field, and must + * set it to 0. */ uint8_t flags; + /* CRYPTO frame does not include this field, and must set it to + 0. */ uint8_t fin; + /* CRYPTO frame does not include this field, and must set it to + 0. */ int64_t stream_id; uint64_t offset; /* datacnt is the number of elements that data contains. Although @@ -190,13 +195,13 @@ typedef struct ngtcp2_stream { ngtcp2_vec data[1]; } ngtcp2_stream; -typedef struct ngtcp2_ack_blk { +typedef struct ngtcp2_ack_range { uint64_t gap; - uint64_t blklen; -} ngtcp2_ack_blk; + uint64_t len; +} ngtcp2_ack_range; typedef struct ngtcp2_ack { - uint8_t type; + uint64_t type; int64_t largest_ack; uint64_t ack_delay; /** @@ -209,13 +214,13 @@ typedef struct ngtcp2_ack { uint64_t ect1; uint64_t ce; } ecn; - uint64_t first_ack_blklen; - size_t num_blks; - ngtcp2_ack_blk blks[1]; + uint64_t first_ack_range; + size_t rangecnt; + ngtcp2_ack_range ranges[1]; } ngtcp2_ack; typedef struct ngtcp2_padding { - uint8_t type; + uint64_t type; /** * The length of contiguous PADDING frames. */ @@ -223,14 +228,14 @@ typedef struct ngtcp2_padding { } ngtcp2_padding; typedef struct ngtcp2_reset_stream { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t app_error_code; uint64_t final_size; } ngtcp2_reset_stream; typedef struct ngtcp2_connection_close { - uint8_t type; + uint64_t type; uint64_t error_code; uint64_t frame_type; size_t reasonlen; @@ -238,7 +243,7 @@ typedef struct ngtcp2_connection_close { } ngtcp2_connection_close; typedef struct ngtcp2_max_data { - uint8_t type; + uint64_t type; /** * max_data is Maximum Data. */ @@ -246,38 +251,38 @@ typedef struct ngtcp2_max_data { } ngtcp2_max_data; typedef struct ngtcp2_max_stream_data { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t max_stream_data; } ngtcp2_max_stream_data; typedef struct ngtcp2_max_streams { - uint8_t type; + uint64_t type; uint64_t max_streams; } ngtcp2_max_streams; typedef struct ngtcp2_ping { - uint8_t type; + uint64_t type; } ngtcp2_ping; typedef struct ngtcp2_data_blocked { - uint8_t type; + uint64_t type; uint64_t offset; } ngtcp2_data_blocked; typedef struct ngtcp2_stream_data_blocked { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t offset; } ngtcp2_stream_data_blocked; typedef struct ngtcp2_streams_blocked { - uint8_t type; + uint64_t type; uint64_t max_streams; } ngtcp2_streams_blocked; typedef struct ngtcp2_new_connection_id { - uint8_t type; + uint64_t type; uint64_t seq; uint64_t retire_prior_to; ngtcp2_cid cid; @@ -285,48 +290,38 @@ typedef struct ngtcp2_new_connection_id { } ngtcp2_new_connection_id; typedef struct ngtcp2_stop_sending { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t app_error_code; } ngtcp2_stop_sending; typedef struct ngtcp2_path_challenge { - uint8_t type; + uint64_t type; uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; } ngtcp2_path_challenge; typedef struct ngtcp2_path_response { - uint8_t type; + uint64_t type; uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; } ngtcp2_path_response; -typedef struct ngtcp2_crypto { - uint8_t type; - uint64_t offset; - /* datacnt is the number of elements that data contains. Although - the length of data is 1 in this definition, the library may - allocate extra bytes to hold more elements. */ - size_t datacnt; - /* data is the array of ngtcp2_vec which references data. */ - ngtcp2_vec data[1]; -} ngtcp2_crypto; - typedef struct ngtcp2_new_token { - uint8_t type; - ngtcp2_vec token; + uint64_t type; + uint8_t *token; + size_t tokenlen; } ngtcp2_new_token; typedef struct ngtcp2_retire_connection_id { - uint8_t type; + uint64_t type; uint64_t seq; } ngtcp2_retire_connection_id; typedef struct ngtcp2_handshake_done { - uint8_t type; + uint64_t type; } ngtcp2_handshake_done; typedef struct ngtcp2_datagram { - uint8_t type; + uint64_t type; /* dgram_id is an opaque identifier chosen by an application. */ uint64_t dgram_id; /* datacnt is the number of elements that data contains. */ @@ -341,7 +336,7 @@ typedef struct ngtcp2_datagram { } ngtcp2_datagram; typedef union ngtcp2_frame { - uint8_t type; + uint64_t type; ngtcp2_stream stream; ngtcp2_ack ack; ngtcp2_padding padding; @@ -358,7 +353,6 @@ typedef union ngtcp2_frame { ngtcp2_stop_sending stop_sending; ngtcp2_path_challenge path_challenge; ngtcp2_path_response path_response; - ngtcp2_crypto crypto; ngtcp2_new_token new_token; ngtcp2_retire_connection_id retire_connection_id; ngtcp2_handshake_done handshake_done; @@ -454,7 +448,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen, * frame if it succeeds, or one of the following negative error codes: * * :enum:`NGTCP2_ERR_FRAME_ENCODING` - * Frame is badly formatted; or frame type is unknown. + * Frame is badly formatted; or frame type is unknown; or + * |payloadlen| is 0. */ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, size_t payloadlen); @@ -554,9 +549,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, * This function returns the exact number of bytes read to decode * PADDING frames. */ -size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, - const uint8_t *payload, - size_t payloadlen); +ngtcp2_ssize ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, + const uint8_t *payload, + size_t payloadlen); /* * ngtcp2_pkt_decode_reset_stream_frame decodes RESET_STREAM frame @@ -639,11 +634,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, * length |payloadlen|. The result is stored in the object pointed by * |dest|. PING frame must start at payload[0]. This function * finishes when it decodes one PING frame, and returns the exact - * number of bytes read to decode a frame if it succeeds, or one of - * the following negative error codes: - * - * NGTCP2_ERR_FRAME_ENCODING - * Payload is too short to include PING frame. + * number of bytes read to decode a frame. */ ngtcp2_ssize ngtcp2_pkt_decode_ping_frame(ngtcp2_ping *dest, const uint8_t *payload, @@ -773,7 +764,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest, * NGTCP2_ERR_FRAME_ENCODING * Payload is too short to include CRYPTO frame. */ -ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, +ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_stream *dest, const uint8_t *payload, size_t payloadlen); @@ -814,11 +805,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, * object pointed by |dest|. HANDSHAKE_DONE frame must start at * payload[0]. This function finishes when it decodes one * HANDSHAKE_DONE frame, and returns the exact number of bytes read to - * decode a frame if it succeeds, or one of the following negative - * error codes: - * - * NGTCP2_ERR_FRAME_ENCODING - * Payload is too short to include HANDSHAKE_DONE frame. + * decode a frame. */ ngtcp2_ssize ngtcp2_pkt_decode_handshake_done_frame(ngtcp2_handshake_done *dest, const uint8_t *payload, @@ -1076,7 +1063,7 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen, * Buffer does not have enough capacity to write a frame. */ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, - const ngtcp2_crypto *fr); + const ngtcp2_stream *fr); /* * ngtcp2_pkt_encode_new_token_frame encodes NEW_TOKEN frame |fr| into @@ -1142,14 +1129,19 @@ int64_t ngtcp2_pkt_adjust_pkt_num(int64_t max_pkt_num, int64_t pkt_num, /* * ngtcp2_pkt_validate_ack checks that ack is malformed or not. + * |min_pkt_num| is the minimum packet number that an endpoint sends. + * It is an error to receive acknowledgements for a packet less than + * |min_pkt_num|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * NGTCP2_ERR_ACK_FRAME * ACK frame is malformed + * NGTCP2_ERR_PROTO + * |fr| contains a packet number less than |min_pkt_num|. */ -int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr); +int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr, int64_t min_pkt_num); /* * ngtcp2_pkt_stream_max_datalen returns the maximum number of bytes diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h new file mode 100644 index 00000000000000..66b0ee9e6c13cf --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h @@ -0,0 +1,62 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_PKTNS_ID_H +#define NGTCP2_PKTNS_ID_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/** + * @enum + * + * :type:`ngtcp2_pktns_id` defines packet number space identifier. + */ +typedef enum ngtcp2_pktns_id { + /** + * :enum:`NGTCP2_PKTNS_ID_INITIAL` is the Initial packet number + * space. + */ + NGTCP2_PKTNS_ID_INITIAL, + /** + * :enum:`NGTCP2_PKTNS_ID_HANDSHAKE` is the Handshake packet number + * space. + */ + NGTCP2_PKTNS_ID_HANDSHAKE, + /** + * :enum:`NGTCP2_PKTNS_ID_APPLICATION` is the Application data + * packet number space. + */ + NGTCP2_PKTNS_ID_APPLICATION, + /** + * :enum:`NGTCP2_PKTNS_ID_MAX` is defined to get the number of + * packet number spaces. + */ + NGTCP2_PKTNS_ID_MAX +} ngtcp2_pktns_id; + +#endif /* NGTCP2_PKTNS_ID_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c index 26318bb1c8e38c..771ef5e026d12d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c @@ -41,7 +41,7 @@ static size_t mtu_probes[] = { 1492 - 48, /* PPPoE */ }; -static size_t mtu_probeslen = sizeof(mtu_probes) / sizeof(mtu_probes[0]); +#define NGTCP2_MTU_PROBESLEN ngtcp2_arraylen(mtu_probes) int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size, size_t hard_max_udp_payload_size, int64_t tx_pkt_num, @@ -61,7 +61,7 @@ int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size, pmtud->hard_max_udp_payload_size = hard_max_udp_payload_size; pmtud->min_fail_udp_payload_size = SIZE_MAX; - for (; pmtud->mtu_idx < mtu_probeslen; ++pmtud->mtu_idx) { + for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) { if (mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) { continue; } @@ -84,7 +84,7 @@ void ngtcp2_pmtud_del(ngtcp2_pmtud *pmtud) { } size_t ngtcp2_pmtud_probelen(ngtcp2_pmtud *pmtud) { - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); return mtu_probes[pmtud->mtu_idx]; } @@ -107,13 +107,13 @@ int ngtcp2_pmtud_require_probe(ngtcp2_pmtud *pmtud) { } static void pmtud_next_probe(ngtcp2_pmtud *pmtud) { - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); ++pmtud->mtu_idx; pmtud->num_pkts_sent = 0; pmtud->expiry = UINT64_MAX; - for (; pmtud->mtu_idx < mtu_probeslen; ++pmtud->mtu_idx) { + for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) { if (mtu_probes[pmtud->mtu_idx] <= pmtud->max_udp_payload_size || mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) { continue; @@ -129,7 +129,7 @@ void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen) { pmtud->max_udp_payload_size = ngtcp2_max(pmtud->max_udp_payload_size, payloadlen); - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); if (mtu_probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) { return; @@ -156,5 +156,5 @@ void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts) { } int ngtcp2_pmtud_finished(ngtcp2_pmtud *pmtud) { - return pmtud->mtu_idx >= mtu_probeslen; + return pmtud->mtu_idx >= NGTCP2_MTU_PROBESLEN; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c index 5376246bd4caa9..ffba131e02b9a5 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c @@ -55,7 +55,7 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) { ppe->len_offset = 1 + 4 + 1 + hd->dcid.datalen + 1 + hd->scid.datalen; if (hd->type == NGTCP2_PKT_INITIAL) { - ppe->len_offset += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; + ppe->len_offset += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen; } ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN; rv = ngtcp2_pkt_encode_hd_long( @@ -115,7 +115,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { assert(cc->hp_mask); if (ppe->len_offset) { - ngtcp2_put_varint30( + ngtcp2_put_uvarint30( buf->begin + ppe->len_offset, (uint16_t)(payloadlen + ppe->pkt_numlen + cc->aead.max_overhead)); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h index 293cbcaaf6e881..c9da15248a3e2b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h @@ -76,10 +76,6 @@ void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data, fallback DCID. If path validation succeeds, fallback DCID is retired if it does not equal to the current DCID. */ #define NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE 0x04u -/* NGTCP2_PV_FLAG_MTU_PROBE indicates that a validation must probe - least MTU that QUIC requires, which is 1200 bytes. If it fails, a - path is not viable. */ -#define NGTCP2_PV_FLAG_MTU_PROBE 0x08u /* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to server's preferred address. This flag is only used by client. */ #define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c index 69eaeb7367438d..27675347794b2a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c @@ -30,6 +30,8 @@ #include "ngtcp2_vec.h" #include "ngtcp2_conv.h" #include "ngtcp2_net.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_conn_stat.h" void ngtcp2_qlog_init(ngtcp2_qlog *qlog, ngtcp2_qlog_write write, ngtcp2_tstamp ts, void *user_data) { @@ -284,9 +286,9 @@ static uint8_t *write_pkt_hd(uint8_t *p, const ngtcp2_pkt_hd *hd) { p = write_pair(p, "packet_type", qlog_pkt_type(hd)); *p++ = ','; p = write_pair_number(p, "packet_number", (uint64_t)hd->pkt_num); - if (hd->type == NGTCP2_PKT_INITIAL && hd->token.len) { + if (hd->type == NGTCP2_PKT_INITIAL && hd->tokenlen) { p = write_verbatim(p, ",\"token\":{"); - p = write_pair_hex(p, "data", hd->token.base, hd->token.len); + p = write_pair_hex(p, "data", hd->token, hd->tokenlen); *p++ = '}'; } /* TODO Write DCIL and DCID */ @@ -316,7 +318,7 @@ static uint8_t *write_ping_frame(uint8_t *p, const ngtcp2_ping *fr) { static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { int64_t largest_ack, min_ack; size_t i; - const ngtcp2_ack_blk *blk; + const ngtcp2_ack_range *range; /* * {"frame_type":"ack","ack_delay":0000000000000000000,"acked_ranges":[]} @@ -336,7 +338,7 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { p = write_verbatim(p, ",\"acked_ranges\":["); largest_ack = fr->largest_ack; - min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = fr->largest_ack - (int64_t)fr->first_ack_range; *p++ = '['; p = write_number(p, (uint64_t)min_ack); @@ -346,10 +348,10 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { } *p++ = ']'; - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - largest_ack = min_ack - (int64_t)blk->gap - 2; - min_ack = largest_ack - (int64_t)blk->blklen; + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + largest_ack = min_ack - (int64_t)range->gap - 2; + min_ack = largest_ack - (int64_t)range->len; *p++ = ','; *p++ = '['; p = write_number(p, (uint64_t)min_ack); @@ -410,7 +412,7 @@ static uint8_t *write_stop_sending_frame(uint8_t *p, return p; } -static uint8_t *write_crypto_frame(uint8_t *p, const ngtcp2_crypto *fr) { +static uint8_t *write_crypto_frame(uint8_t *p, const ngtcp2_stream *fr) { /* * {"frame_type":"crypto","offset":0000000000000000000,"length":0000000000000000000} */ @@ -432,9 +434,9 @@ static uint8_t *write_new_token_frame(uint8_t *p, const ngtcp2_new_token *fr) { #define NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD 75 p = write_verbatim(p, "{\"frame_type\":\"new_token\","); - p = write_pair_number(p, "length", fr->token.len); + p = write_pair_number(p, "length", fr->tokenlen); p = write_verbatim(p, ",\"token\":{"); - p = write_pair_hex(p, "data", fr->token.base, fr->token.len); + p = write_pair_hex(p, "data", fr->token, fr->tokenlen); *p++ = '}'; *p++ = '}'; @@ -513,45 +515,53 @@ static uint8_t *write_max_streams_frame(uint8_t *p, static uint8_t *write_data_blocked_frame(uint8_t *p, const ngtcp2_data_blocked *fr) { - (void)fr; - /* - * {"frame_type":"data_blocked"} + * {"frame_type":"data_blocked","limit":0000000000000000000} */ -#define NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD 29 +#define NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD 57 - /* TODO log limit */ + p = write_verbatim(p, "{\"frame_type\":\"data_blocked\","); + p = write_pair_number(p, "limit", fr->offset); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"data_blocked\"}"); + return p; } static uint8_t * write_stream_data_blocked_frame(uint8_t *p, const ngtcp2_stream_data_blocked *fr) { - (void)fr; - /* - * {"frame_type":"stream_data_blocked"} + * {"frame_type":"stream_data_blocked","stream_id":0000000000000000000,"limit":0000000000000000000} */ -#define NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD 36 +#define NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD 96 - /* TODO log limit */ + p = write_verbatim(p, "{\"frame_type\":\"stream_data_blocked\","); + p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id); + *p++ = ','; + p = write_pair_number(p, "limit", fr->offset); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"stream_data_blocked\"}"); + return p; } static uint8_t *write_streams_blocked_frame(uint8_t *p, const ngtcp2_streams_blocked *fr) { - (void)fr; - /* - * {"frame_type":"streams_blocked"} + * {"frame_type":"streams_blocked","stream_type":"unidirectional","limit":0000000000000000000} */ -#define NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD 32 +#define NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD 91 - /* TODO Log stream_type and limit */ + p = write_verbatim(p, "{\"frame_type\":\"streams_blocked\",\"stream_type\":"); + if (fr->type == NGTCP2_FRAME_STREAMS_BLOCKED_BIDI) { + p = write_string(p, "bidirectional"); + } else { + p = write_string(p, "unidirectional"); + } + *p++ = ','; + p = write_pair_number(p, "limit", fr->max_streams); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"streams_blocked\"}"); + return p; } static uint8_t * @@ -715,7 +725,7 @@ static void qlog_pkt_write_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, (1 + 50 + NGTCP2_QLOG_PKT_HD_OVERHEAD) if (ngtcp2_buf_left(&qlog->buf) < - NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD + hd->token.len * 2) { + NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD + hd->tokenlen * 2) { return; } @@ -765,7 +775,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { (size_t)(fr->type == NGTCP2_FRAME_ACK_ECN ? NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD : 0) + - NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.num_blks) + 1) { + NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.rangecnt) + 1) { return; } p = write_ack_frame(p, &fr->ack); @@ -788,11 +798,11 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_CRYPTO_FRAME_OVERHEAD + 1) { return; } - p = write_crypto_frame(p, &fr->crypto); + p = write_crypto_frame(p, &fr->stream); break; case NGTCP2_FRAME_NEW_TOKEN: - if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + - fr->new_token.token.len * 2 + 1) { + if (ngtcp2_buf_left(&qlog->buf) < + NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + fr->new_token.tokenlen * 2 + 1) { return; } p = write_new_token_frame(p, &fr->new_token); @@ -897,7 +907,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { p = write_datagram_frame(p, &fr->datagram); break; default: - assert(0); + ngtcp2_unreachable(); } *p++ = ','; @@ -929,6 +939,8 @@ void ngtcp2_qlog_parameters_set_transport_params( uint8_t buf[1024]; uint8_t *p = buf; const ngtcp2_preferred_addr *paddr; + const ngtcp2_sockaddr_in *sa_in; + const ngtcp2_sockaddr_in6 *sa_in6; if (!qlog->write) { return; @@ -996,20 +1008,33 @@ void ngtcp2_qlog_parameters_set_transport_params( *p++ = ','; p = write_pair_number(p, "initial_max_streams_uni", params->initial_max_streams_uni); - if (params->preferred_address_present) { + if (params->preferred_addr_present) { *p++ = ','; - paddr = ¶ms->preferred_address; + paddr = ¶ms->preferred_addr; p = write_string(p, "preferred_address"); *p++ = ':'; *p++ = '{'; - p = write_pair_hex(p, "ip_v4", paddr->ipv4_addr, sizeof(paddr->ipv4_addr)); - *p++ = ','; - p = write_pair_number(p, "port_v4", paddr->ipv4_port); - *p++ = ','; - p = write_pair_hex(p, "ip_v6", paddr->ipv6_addr, sizeof(paddr->ipv6_addr)); - *p++ = ','; - p = write_pair_number(p, "port_v6", paddr->ipv6_port); - *p++ = ','; + + if (paddr->ipv4_present) { + sa_in = &paddr->ipv4; + + p = write_pair_hex(p, "ip_v4", (const uint8_t *)&sa_in->sin_addr, + sizeof(sa_in->sin_addr)); + *p++ = ','; + p = write_pair_number(p, "port_v4", ngtcp2_ntohs(sa_in->sin_port)); + *p++ = ','; + } + + if (paddr->ipv6_present) { + sa_in6 = &paddr->ipv6; + + p = write_pair_hex(p, "ip_v6", (const uint8_t *)&sa_in6->sin6_addr, + sizeof(sa_in6->sin6_addr)); + *p++ = ','; + p = write_pair_number(p, "port_v6", ngtcp2_ntohs(sa_in6->sin6_port)); + *p++ = ','; + } + p = write_pair_cid(p, "connection_id", &paddr->cid); p = write_verbatim(p, ",\"stateless_reset_token\":{"); p = write_pair_hex(p, "data", paddr->stateless_reset_token, @@ -1113,16 +1138,15 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":"); if (ngtcp2_buf_left(&buf) < - NGTCP2_QLOG_PKT_HD_OVERHEAD + hd->token.len * 2 + + NGTCP2_QLOG_PKT_HD_OVERHEAD + hd->tokenlen * 2 + sizeof(",\"retry_token\":{\"data\":\"\"}}}\n") - 1 + - retry->token.len * 2) { + retry->tokenlen * 2) { return; } buf.last = write_pkt_hd(buf.last, hd); buf.last = write_verbatim(buf.last, ",\"retry_token\":{"); - buf.last = - write_pair_hex(buf.last, "data", retry->token.base, retry->token.len); + buf.last = write_pair_hex(buf.last, "data", retry->token, retry->tokenlen); buf.last = write_verbatim(buf.last, "}}}\n"); qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf.pos, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c index 74e488bce76f24..c381c231276d34 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c @@ -31,8 +31,9 @@ #include "ngtcp2_macro.h" -#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64)) -unsigned int __popcnt(unsigned int x) { +#if defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_ARM) || defined(_M_ARM64)) +static unsigned int __popcnt(unsigned int x) { unsigned int c = 0; for (; x; ++c) { x &= x - 1; @@ -63,7 +64,7 @@ void ngtcp2_ringbuf_buf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size, rb->buf = buf; rb->mem = mem; - rb->nmemb = nmemb; + rb->mask = nmemb - 1; rb->size = size; rb->first = 0; rb->len = 0; @@ -78,17 +79,19 @@ void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb) { } void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb) { - rb->first = (rb->first - 1) & (rb->nmemb - 1); - rb->len = ngtcp2_min(rb->nmemb, rb->len + 1); + rb->first = (rb->first - 1) & rb->mask; + if (rb->len < rb->mask + 1) { + ++rb->len; + } return (void *)&rb->buf[rb->first * rb->size]; } void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) { - size_t offset = (rb->first + rb->len) & (rb->nmemb - 1); + size_t offset = (rb->first + rb->len) & rb->mask; - if (rb->len == rb->nmemb) { - rb->first = (rb->first + 1) & (rb->nmemb - 1); + if (rb->len == rb->mask + 1) { + rb->first = (rb->first + 1) & rb->mask; } else { ++rb->len; } @@ -97,7 +100,7 @@ void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) { } void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb) { - rb->first = (rb->first + 1) & (rb->nmemb - 1); + rb->first = (rb->first + 1) & rb->mask; --rb->len; } @@ -107,14 +110,14 @@ void ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf *rb) { } void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len) { - assert(len <= rb->nmemb); + assert(len <= rb->mask + 1); rb->len = len; } void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) { assert(offset < rb->len); - offset = (rb->first + offset) & (rb->nmemb - 1); + offset = (rb->first + offset) & rb->mask; return &rb->buf[offset * rb->size]; } -int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; } +int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->mask + 1; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h index 16635c941032c7..b28a882c4bae84 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h @@ -37,9 +37,9 @@ typedef struct ngtcp2_ringbuf { /* buf points to the underlying buffer. */ uint8_t *buf; const ngtcp2_mem *mem; - /* nmemb is the number of elements that can be stored in this ring - buffer. */ - size_t nmemb; + /* mask is the bit mask to cover all bits for the maximum number of + elements. The maximum number of elements is mask + 1. */ + size_t mask; /* size is the size of each element. */ size_t size; /* first is the offset to the first element. */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c index 9c3d75dc33ae0c..5cac383f7bb166 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c @@ -218,7 +218,7 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, return 0; } -int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { +void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { ngtcp2_rob_gap *g; ngtcp2_rob_data *d; ngtcp2_ksl_it it; @@ -245,13 +245,11 @@ int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { for (; !ngtcp2_ksl_it_end(&it);) { d = ngtcp2_ksl_it_get(&it); if (offset < d->range.begin + rob->chunk) { - return 0; + return; } ngtcp2_ksl_remove_hint(&rob->dataksl, &it, &it, &d->range); ngtcp2_rob_data_del(d, rob->mem); } - - return 0; } size_t ngtcp2_rob_data_at(ngtcp2_rob *rob, const uint8_t **pdest, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h index c7688df4542956..6518d56c539185 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h @@ -152,14 +152,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, /* * ngtcp2_rob_remove_prefix removes gap up to |offset|, exclusive. It * also removes data buffer if it is completely included in |offset|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory */ -int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset); +void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset); /* * ngtcp2_rob_data_at stores the pointer to the buffer of stream diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c index 7b50f98d41ec7b..b8587e3e9dbac8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c @@ -29,6 +29,7 @@ #include "ngtcp2_rtb.h" #include "ngtcp2_cc.h" #include "ngtcp2_macro.h" +#include "ngtcp2_conn_stat.h" void ngtcp2_rs_init(ngtcp2_rs *rs) { rs->interval = UINT64_MAX; @@ -69,8 +70,8 @@ void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, ent->rst.lost = rst->lost; } -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, - uint64_t pkt_delivered) { +void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, + uint64_t pkt_delivered) { ngtcp2_rs *rs = &rst->rs; uint64_t rate; @@ -84,7 +85,7 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, } if (rs->prior_ts == 0) { - return 0; + return; } rs->interval = ngtcp2_max(rs->send_elapsed, rs->ack_elapsed); @@ -94,11 +95,11 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, if (rs->interval < cstat->min_rtt) { rs->interval = UINT64_MAX; - return 0; + return; } if (!rs->interval) { - return 0; + return; } rate = rs->delivered * NGTCP2_SECONDS / rs->interval; @@ -107,8 +108,6 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, ngtcp2_window_filter_update(&rst->wf, rate, rst->round_count); cstat->delivery_rate_sec = ngtcp2_window_filter_get_best(&rst->wf); } - - return 0; } void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h index 488c65575a5589..c9e1e161b7766f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h @@ -34,6 +34,7 @@ #include "ngtcp2_window_filter.h" typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry; +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; /** * @struct @@ -76,8 +77,8 @@ void ngtcp2_rst_init(ngtcp2_rst *rst); void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, const ngtcp2_conn_stat *cstat); -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, - uint64_t pkt_delivered); +void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, + uint64_t pkt_delivered); void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, ngtcp2_tstamp ts); void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c index 644071400a6eb7..b9e0139bddfcac 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -34,220 +34,11 @@ #include "ngtcp2_cc.h" #include "ngtcp2_rcvry.h" #include "ngtcp2_rst.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_tstamp.h" +#include "ngtcp2_frame_chain.h" -int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) { - *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, - ngtcp2_objalloc *objalloc) { - *pfrc = ngtcp2_objalloc_frame_chain_get(objalloc); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, - const ngtcp2_mem *mem) { - *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain) + extralen); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream); - - if (datacnt > 1) { - need = sizeof(ngtcp2_vec) * (datacnt - 1); - - if (need > avail) { - return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); - } - } - - return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); -} - -int ngtcp2_frame_chain_crypto_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_crypto); - - if (datacnt > 1) { - need = sizeof(ngtcp2_vec) * (datacnt - 1); - - if (need > avail) { - return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); - } - } - - return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); -} - -int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, - const ngtcp2_vec *token, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token); - int rv; - uint8_t *p; - ngtcp2_frame *fr; - - if (token->len > avail) { - rv = ngtcp2_frame_chain_extralen_new(pfrc, token->len - avail, mem); - } else { - rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); - } - if (rv != 0) { - return rv; - } - - fr = &(*pfrc)->fr; - fr->type = NGTCP2_FRAME_NEW_TOKEN; - - p = (uint8_t *)fr + sizeof(ngtcp2_new_token); - memcpy(p, token->base, token->len); - - ngtcp2_vec_init(&fr->new_token.token, p, token->len); - - return 0; -} - -void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - - if (frc == NULL) { - return; - } - - binder = frc->binder; - if (binder && --binder->refcount == 0) { - ngtcp2_mem_free(mem, binder); - } - - ngtcp2_mem_free(mem, frc); -} - -void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - - if (frc == NULL) { - return; - } - - switch (frc->fr.type) { - case NGTCP2_FRAME_STREAM: - if (frc->fr.stream.datacnt && - sizeof(ngtcp2_vec) * (frc->fr.stream.datacnt - 1) > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - case NGTCP2_FRAME_CRYPTO: - if (frc->fr.crypto.datacnt && - sizeof(ngtcp2_vec) * (frc->fr.crypto.datacnt - 1) > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_crypto)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - case NGTCP2_FRAME_NEW_TOKEN: - if (frc->fr.new_token.token.len > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - } - - binder = frc->binder; - if (binder && --binder->refcount == 0) { - ngtcp2_mem_free(mem, binder); - } - - frc->binder = NULL; - - ngtcp2_objalloc_frame_chain_release(objalloc, frc); -} - -void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { - frc->next = NULL; - frc->binder = NULL; -} - -void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain *next; - - for (; frc; frc = next) { - next = frc->next; - - ngtcp2_frame_chain_objalloc_del(frc, objalloc, mem); - } -} - -int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, - const ngtcp2_mem *mem) { - *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder)); - if (*pbinder == NULL) { - return NGTCP2_ERR_NOMEM; - } - - return 0; -} - -int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - int rv; - - assert(b->binder == NULL); - - if (a->binder == NULL) { - rv = ngtcp2_frame_chain_binder_new(&binder, mem); - if (rv != 0) { - return rv; - } - - a->binder = binder; - ++a->binder->refcount; - } - - b->binder = a->binder; - ++b->binder->refcount; - - return 0; -} +ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent); static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd, ngtcp2_frame_chain *frc, ngtcp2_tstamp ts, @@ -297,7 +88,7 @@ static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc, - ngtcp2_log *log, ngtcp2_qlog *qlog, + int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { rtb->rtb_entry_objalloc = rtb_entry_objalloc; @@ -315,7 +106,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, rtb->num_pto_eliciting = 0; rtb->probe_pkt_left = 0; rtb->pktns_id = pktns_id; - rtb->cc_pkt_num = 0; + rtb->cc_pkt_num = cc_pkt_num; rtb->cc_bytes_in_flight = 0; rtb->persistent_congestion_start_ts = UINT64_MAX; rtb->num_lost_pkts = 0; @@ -432,7 +223,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, ngtcp2_range gap, range; size_t num_reclaimed = 0; int rv; - int streamfrq_empty; assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE); @@ -487,7 +277,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data, fr->stream.datacnt); - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); rv = ngtcp2_strm_streamfrq_push(strm, nfrc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem); @@ -500,9 +289,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, return rv; } } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } ++num_reclaimed; @@ -510,28 +296,27 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, case NGTCP2_FRAME_CRYPTO: /* Don't resend CRYPTO frame if the whole region it contains has been acknowledged */ - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->crypto.offset); + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->stream.offset); - range.begin = fr->crypto.offset; - range.end = fr->crypto.offset + - ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt); + range.begin = fr->stream.offset; + range.end = fr->stream.offset + + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt); range = ngtcp2_range_intersect(&range, &gap); if (ngtcp2_range_len(&range) == 0) { continue; } - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, fr->crypto.datacnt, rtb->frc_objalloc, rtb->mem); + rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new( + &nfrc, fr->stream.datacnt, rtb->frc_objalloc, rtb->mem); if (rv != 0) { return rv; } nfrc->fr = *fr; - ngtcp2_vec_copy(nfrc->fr.crypto.data, fr->crypto.data, - fr->crypto.datacnt); + ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data, + fr->stream.datacnt); - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &nfrc->fr.crypto.offset, nfrc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem); @@ -543,7 +328,8 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, continue; case NGTCP2_FRAME_NEW_TOKEN: rv = ngtcp2_frame_chain_new_token_objalloc_new( - &nfrc, &fr->new_token.token, rtb->frc_objalloc, rtb->mem); + &nfrc, fr->new_token.token, fr->new_token.tokenlen, rtb->frc_objalloc, + rtb->mem); if (rv != 0) { return rv; } @@ -638,7 +424,7 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " has already been reclaimed on PTO", ent->hd.pkt_num); assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)); @@ -770,6 +556,10 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, for (frc = ent->frc; frc; frc = frc->next) { if (frc->binder) { + if (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK) { + continue; + } + frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK; } @@ -817,8 +607,8 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, case NGTCP2_FRAME_CRYPTO: prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto); rv = ngtcp2_strm_ack_data( - crypto, frc->fr.crypto.offset, - ngtcp2_vec_len(frc->fr.crypto.data, frc->fr.crypto.datacnt)); + crypto, frc->fr.stream.offset, + ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt)); if (rv != 0) { return rv; } @@ -840,7 +630,7 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, pktns = &conn->pktns; break; default: - assert(0); + ngtcp2_unreachable(); } conn_ack_crypto_data(conn, pktns, datalen); @@ -851,7 +641,7 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, if (strm == NULL) { break; } - strm->flags |= NGTCP2_STRM_FLAG_RST_ACKED; + strm->flags |= NGTCP2_STRM_FLAG_RESET_STREAM_ACKED; rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm); if (rv != 0) { return rv; @@ -861,6 +651,12 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, ngtcp2_conn_untrack_retired_dcid_seq(conn, frc->fr.retire_connection_id.seq); break; + case NGTCP2_FRAME_NEW_CONNECTION_ID: + assert(conn->scid.num_in_flight); + + --conn->scid.num_in_flight; + + break; case NGTCP2_FRAME_DATAGRAM: case NGTCP2_FRAME_DATAGRAM_LEN: if (!conn->callbacks.ack_datagram) { @@ -885,12 +681,14 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts); - cc->on_pkt_acked(cc, cstat, - ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, - rtb->pktns_id, ent->ts, ent->rst.lost, - ent->rst.tx_in_flight, - ent->rst.is_app_limited), - ts); + if (cc->on_pkt_acked) { + cc->on_pkt_acked(cc, cstat, + ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, + rtb->pktns_id, ent->ts, ent->rst.lost, + ent->rst.tx_in_flight, + ent->rst.is_app_limited), + ts); + } if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) && (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { @@ -901,7 +699,7 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_ack *fr, size_t ecn_acked, - ngtcp2_tstamp largest_acked_sent_ts, + ngtcp2_tstamp largest_pkt_sent_ts, ngtcp2_tstamp ts) { if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) { return; @@ -928,9 +726,9 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns, } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - if (largest_acked_sent_ts != UINT64_MAX && + if (cc->congestion_event && largest_pkt_sent_ts != UINT64_MAX && fr->ecn.ce > pktns->rx.ecn.ack.ce) { - cc->congestion_event(cc, cstat, largest_acked_sent_ts, ts); + cc->congestion_event(cc, cstat, largest_pkt_sent_ts, ts); } pktns->rx.ecn.ack.ect0 = fr->ecn.ect0; @@ -954,7 +752,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ngtcp2_ksl_it it; ngtcp2_ssize num_acked = 0; ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX; - ngtcp2_tstamp largest_acked_sent_ts = UINT64_MAX; int64_t pkt_num; ngtcp2_cc *cc = rtb->cc; ngtcp2_rtb_entry *acked_ent = NULL; @@ -987,12 +784,12 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, if (ngtcp2_ksl_it_end(&it)) { if (conn && verify_ecn) { conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, - largest_acked_sent_ts, ts); + largest_pkt_sent_ts, ts); } return 0; } - min_ack = largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = largest_ack - (int64_t)fr->first_ack_range; for (; !ngtcp2_ksl_it_end(&it);) { pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it); @@ -1017,9 +814,9 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ++num_acked; } - for (i = 0; i < fr->num_blks;) { - largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; - min_ack = largest_ack - (int64_t)fr->blks[i].blklen; + for (i = 0; i < fr->rangecnt;) { + largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2; + min_ack = largest_ack - (int64_t)fr->ranges[i].len; it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); if (ngtcp2_ksl_it_end(&it)) { @@ -1060,11 +857,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ++ecn_acked; } - assert(largest_acked_sent_ts == UINT64_MAX || - largest_acked_sent_ts <= ent->ts); - - largest_acked_sent_ts = ent->ts; - rv = rtb_process_acked_pkt(rtb, ent, conn); if (rv != 0) { goto fail; @@ -1085,7 +877,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, if (verify_ecn) { conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, - largest_acked_sent_ts, ts); + largest_pkt_sent_ts, ts); } } else { /* For unit tests */ @@ -1113,8 +905,10 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, rtb->rst->lost += cc_ack.bytes_lost; - cc_ack.largest_acked_sent_ts = largest_acked_sent_ts; - cc->on_ack_recv(cc, cstat, &cc_ack, ts); + cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts; + if (cc->on_ack_recv) { + cc->on_ack_recv(cc, cstat, &cc_ack, ts); + } return num_acked; @@ -1133,7 +927,7 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, size_t pkt_thres, ngtcp2_tstamp ts) { ngtcp2_tstamp loss_time; - if (ent->ts + loss_delay <= ts || + if (ngtcp2_tstamp_elapsed(ent->ts, loss_delay, ts) || rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { return 1; } @@ -1189,7 +983,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, ngtcp2_cc *cc = rtb->cc; int rv; uint64_t pkt_thres = - rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; + rtb->cc_bytes_in_flight / cstat->max_tx_udp_payload_size / 2; size_t ecn_pkt_lost = 0; ngtcp2_tstamp start_ts; ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, pktns); @@ -1288,7 +1082,9 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, break; } - cc->congestion_event(cc, cstat, latest_ts, ts); + if (cc->congestion_event) { + cc->congestion_event(cc, cstat, latest_ts, ts); + } loss_window = latest_ts - oldest_ts; /* Persistent congestion situation is only evaluated for app @@ -1300,7 +1096,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, */ if (rtb->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && loss_window > 0) { if (loss_window >= congestion_period) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "persistent congestion loss_window=%" PRIu64 " congestion_period=%" PRIu64, loss_window, congestion_period); @@ -1312,7 +1108,9 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, cstat->rttvar = conn->local.settings.initial_rtt / 2; cstat->first_rtt_sample_ts = UINT64_MAX; - cc->on_persistent_congestion(cc, cstat, ts); + if (cc->on_persistent_congestion) { + cc->on_persistent_congestion(cc, cstat, ts); + } } } @@ -1349,7 +1147,7 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED); - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1389,7 +1187,7 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, return; } - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1435,7 +1233,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, ngtcp2_stream *sfr; ngtcp2_strm *strm; int rv; - int streamfrq_empty; ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, ent->ts); @@ -1445,7 +1242,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " is a probe packet, no retransmission is necessary", ent->hd.pkt_num); @@ -1453,7 +1250,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " is a PMTUD probe packet, no retransmission is necessary", ent->hd.pkt_num); @@ -1467,7 +1264,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, --rtb->num_lost_pmtud_pkts; } - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " was declared lost and has already been retransmitted", ent->hd.pkt_num); @@ -1475,7 +1272,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " has already been reclaimed on PTO", ent->hd.pkt_num); return 0; @@ -1505,7 +1302,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); break; } - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); rv = ngtcp2_strm_streamfrq_push(strm, frc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); @@ -1518,9 +1314,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, return rv; } } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } break; case NGTCP2_FRAME_CRYPTO: frc = *pfrc; @@ -1528,8 +1321,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, *pfrc = frc->next; frc->next = NULL; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &frc->fr.crypto.offset, frc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h index a97805dbaf3bc3..a1ff208b19eac7 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -35,6 +35,7 @@ #include "ngtcp2_ksl.h" #include "ngtcp2_pq.h" #include "ngtcp2_objalloc.h" +#include "ngtcp2_pktns_id.h" typedef struct ngtcp2_conn ngtcp2_conn; typedef struct ngtcp2_pktns ngtcp2_pktns; @@ -43,156 +44,9 @@ typedef struct ngtcp2_qlog ngtcp2_qlog; typedef struct ngtcp2_strm ngtcp2_strm; typedef struct ngtcp2_rst ngtcp2_rst; typedef struct ngtcp2_cc ngtcp2_cc; - -/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is - set. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u -/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information - which a frame carries has been acknowledged. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u - -/* - * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to - * share the acknowledgement state. In general, all - * ngtcp2_frame_chains bound to the same binder must have the same - * information. - */ -typedef struct ngtcp2_frame_chain_binder { - size_t refcount; - /* flags is bitwise OR of zero or more of - NGTCP2_FRAME_CHAIN_BINDER_FLAG_*. */ - uint32_t flags; -} ngtcp2_frame_chain_binder; - -int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, - const ngtcp2_mem *mem); - +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; -/* - * ngtcp2_frame_chain chains frames in a single packet. - */ -struct ngtcp2_frame_chain { - union { - struct { - ngtcp2_frame_chain *next; - ngtcp2_frame_chain_binder *binder; - ngtcp2_frame fr; - }; - - ngtcp2_opl_entry oplent; - }; -}; - -ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent); - -/* - * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using - * new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL - * a->binder. |b| must not have non-NULL b->binder. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory - */ -int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, - const ngtcp2_mem *mem); - -/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that - a ngtcp2_stream can include. */ -#define NGTCP2_MAX_STREAM_DATACNT 256 - -/* NGTCP2_MAX_CRYPTO_DATACNT is the maximum number of ngtcp2_vec that - a ngtcp2_crypto can include. */ -#define NGTCP2_MAX_CRYPTO_DATACNT 8 - -/* - * ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and - * assigns its pointer to |*pfrc|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_objalloc_new behaves like - * ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object. - */ -int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, - ngtcp2_objalloc *objalloc); - -/* - * ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new, - * but it allocates extra memory |extralen| in order to extend - * ngtcp2_frame. - */ -int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_stream_datacnt_objalloc_new works like - * ngtcp2_frame_chain_new, but it allocates enough data to store - * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream - * object. If no additional space is required, - * ngtcp2_frame_chain_objalloc_new is called internally. - */ -int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_crypto_datacnt_objalloc_new works like - * ngtcp2_frame_chain_new, but it allocates enough data to store - * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_crypto - * object. If no additional space is required, - * ngtcp2_frame_chain_objalloc_new is called internally. - */ -int ngtcp2_frame_chain_crypto_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, - const ngtcp2_vec *token, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the - * memory pointed by |frc|. - */ -void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse. - * It might just delete |frc| depending on the frame type and the size - * of |frc|. - */ -void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_init initializes |frc|. - */ -void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc); - -/* - * ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain - * linked from |frc| to |objalloc| for reuse. Depending on the frame type - * and its size, ngtcp2_frame_chain might be deleted instead. - */ -void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - /* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u /* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a @@ -268,7 +122,7 @@ struct ngtcp2_rtb_entry { }; }; -ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent); +ngtcp2_objalloc_decl(rtb_entry, ngtcp2_rtb_entry, oplent); /* * ngtcp2_rtb_entry_new allocates ngtcp2_rtb_entry object, and assigns @@ -347,7 +201,7 @@ typedef struct ngtcp2_rtb { */ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc, - ngtcp2_log *log, ngtcp2_qlog *qlog, + int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c index c1ce64a2e57ac4..a61636d188fae5 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c @@ -38,6 +38,11 @@ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n) { return dest + n; } +const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); + return (uint8_t *)src + n; +} + #define LOWER_XDIGITS "0123456789abcdef" uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h index 04735d6dec5c63..deb75e356d70d4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h @@ -38,6 +38,13 @@ void *ngtcp2_cpymem(void *dest, const void *src, size_t n); * the buffer pointed by |dest|. It returns dest + n; */ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n); + +/* + * ngtcp2_get_bytes copies |n| bytes from |src| to |dest|, and returns + * |src| + |n|. + */ +const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n); + /* * ngtcp2_encode_hex encodes |data| of length |len| in hex string. It * writes additional NULL bytes at the end of the buffer. The buffer diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c index 6f20e866ad51c0..6bbeb8f9f81fc2 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c @@ -30,6 +30,7 @@ #include "ngtcp2_rtb.h" #include "ngtcp2_pkt.h" #include "ngtcp2_vec.h" +#include "ngtcp2_frame_chain.h" static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return *(int64_t *)lhs < *(int64_t *)rhs; @@ -46,9 +47,12 @@ void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, strm->tx.streamfrq = NULL; strm->tx.offset = 0; strm->tx.max_offset = max_tx_offset; + strm->tx.last_blocked_offset = UINT64_MAX; strm->tx.last_max_stream_data_ts = UINT64_MAX; strm->tx.loss_count = 0; strm->tx.last_lost_pkt_num = -1; + strm->tx.stop_sending_app_error_code = 0; + strm->tx.reset_stream_app_error_code = 0; strm->rx.rob = NULL; strm->rx.cont_offset = 0; strm->rx.last_offset = 0; @@ -120,7 +124,7 @@ uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm) { /* strm_rob_heavily_fragmented returns nonzero if the number of gaps in |rob| exceeds the limit. */ static int strm_rob_heavily_fragmented(ngtcp2_rob *rob) { - return ngtcp2_ksl_len(&rob->gapksl) >= 1000; + return ngtcp2_ksl_len(&rob->gapksl) >= 5000; } int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, @@ -134,10 +138,7 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, } if (strm->rx.cont_offset) { - rv = ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset); - if (rv != 0) { - return rv; - } + ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset); } } @@ -148,13 +149,13 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen); } -int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) { +void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) { if (strm->rx.rob == NULL) { strm->rx.cont_offset = offset; - return 0; + return; } - return ngtcp2_rob_remove_prefix(strm->rx.rob, offset); + ngtcp2_rob_remove_prefix(strm->rx.rob, offset); } void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) { @@ -177,7 +178,8 @@ static int strm_streamfrq_init(ngtcp2_strm *strm) { int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) { int rv; - assert(frc->fr.type == NGTCP2_FRAME_STREAM); + assert(frc->fr.type == NGTCP2_FRAME_STREAM || + frc->fr.type == NGTCP2_FRAME_CRYPTO); assert(frc->next == NULL); if (strm->tx.streamfrq == NULL) { @@ -308,7 +310,7 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm, assert(nfr->data[0].len > end_base_offset); - nfr->type = NGTCP2_FRAME_STREAM; + nfr->type = fr->type; nfr->flags = 0; nfr->fin = fr->fin; nfr->stream_id = fr->stream_id; @@ -379,18 +381,16 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, fr = &frc->fr.stream; datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - if (left == 0) { - /* datalen could be zero if 0 length STREAM has been sent */ - if (datalen || ngtcp2_ksl_len(strm->tx.streamfrq) > 1) { - rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem); - return rv; - } - *pfrc = NULL; - return 0; + /* datalen could be zero if 0 length STREAM has been sent */ + if (left == 0 && datalen) { + rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem); + return rv; } + *pfrc = NULL; + return 0; } if (datalen > left) { @@ -412,7 +412,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, } nfr = &nfrc->fr.stream; - nfr->type = NGTCP2_FRAME_STREAM; + nfr->type = fr->type; nfr->flags = 0; nfr->fin = fr->fin; nfr->stream_id = fr->stream_id; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h index 8e3cfe83543509..e8cc531f217ab1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h @@ -49,20 +49,20 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; #define NGTCP2_STRM_FLAG_SHUT_WR 0x02u #define NGTCP2_STRM_FLAG_SHUT_RDWR \ (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR) -/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is sent from - the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is also - set. */ -#define NGTCP2_STRM_FLAG_SENT_RST 0x04u -/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is received - from the remote endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_RD - is also set. */ -#define NGTCP2_STRM_FLAG_RECV_RST 0x08u +/* NGTCP2_STRM_FLAG_RESET_STREAM indicates that RESET_STREAM is sent + from the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is + also set. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04u +/* NGTCP2_STRM_FLAG_RESET_STREAM_RECVED indicates that RESET_STREAM is + received from the remote endpoint. In this case, + NGTCP2_STRM_FLAG_SHUT_RD is also set. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08u /* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent from the local endpoint. */ #define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u -/* NGTCP2_STRM_FLAG_RST_ACKED indicates that the outgoing RST_STREAM - is acknowledged by peer. */ -#define NGTCP2_STRM_FLAG_RST_ACKED 0x20u +/* NGTCP2_STRM_FLAG_RESET_STREAM_ACKED indicates that the outgoing + RESET_STREAM is acknowledged by peer. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20u /* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set is acknowledged by a remote endpoint. */ #define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u @@ -75,9 +75,12 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; In this case, without this flag, we are unable to distinguish assigned value from unassigned one. */ #define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u -/* NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED is set when - stream_stop_sending callback is called. */ -#define NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED 0x200u +/* NGTCP2_STRM_FLAG_SEND_STOP_SENDING is set when STOP_SENDING frame + should be sent. */ +#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200u +/* NGTCP2_STRM_FLAG_SEND_RESET_STREAM is set when RESET_STREAM frame + should be sent. */ +#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400u typedef struct ngtcp2_strm ngtcp2_strm; @@ -96,10 +99,10 @@ struct ngtcp2_strm { remote endpoint acknowledges data in out-of-order. After that, acked_offset is used instead. */ uint64_t cont_acked_offset; - /* streamfrq contains STREAM frame for retransmission. The flow - control credits have been paid when they are transmitted first - time. There are no restriction regarding flow control for - retransmission. */ + /* streamfrq contains STREAM or CRYPTO frame for + retransmission. The flow control credits have been paid + when they are transmitted first time. There are no + restriction regarding flow control for retransmission. */ ngtcp2_ksl *streamfrq; /* offset is the next offset of outgoing data. In other words, it is the number of bytes sent in this stream without @@ -108,6 +111,9 @@ struct ngtcp2_strm { /* max_tx_offset is the maximum offset that local endpoint can send for this stream. */ uint64_t max_offset; + /* last_blocked_offset is the largest offset where the + transmission of stream data is blocked. */ + uint64_t last_blocked_offset; /* last_max_stream_data_ts is the timestamp when last MAX_STREAM_DATA frame is sent. */ ngtcp2_tstamp last_max_stream_data_ts; @@ -123,6 +129,12 @@ struct ngtcp2_strm { is counted to loss_count. It is used to avoid to count multiple STREAM frames in one lost packet. */ int64_t last_lost_pkt_num; + /* stop_sending_app_error_code is the application specific + error code that is sent along with STOP_SENDING. */ + uint64_t stop_sending_app_error_code; + /* reset_stream_app_error_code is the application specific + error code that is sent along with RESET_STREAM. */ + uint64_t reset_stream_app_error_code; } tx; struct { @@ -200,11 +212,8 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, /* * ngtcp2_strm_update_rx_offset tells that data up to offset bytes are * received in order. - * - * NGTCP2_ERR_NOMEM - * Out of memory */ -int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset); +void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset); /* * ngtcp2_strm_shutdown shutdowns |strm|. |flags| should be diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h new file mode 100644 index 00000000000000..9a210a320dc1ca --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h @@ -0,0 +1,68 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_TSTAMP_H +#define NGTCP2_TSTAMP_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* + * ngtcp2_tstamp_elapsed returns nonzero if at least |d| has passed + * since |base|. |ts| expresses a current time, and must not be + * UINT64_MAX. + * + * If |base| is UINT64_MAX, this function returns 0 because UINT64_MAX + * is an invalid timestamp. Otherwise, if |base| + |d| >= UINT64_MAX, + * this function returns 0. + * + * !ngtcp2_tstamp_elapsed() == ngtcp2_tstamp_not_elapsed() does not + * hold when |base| is UINT64_MAX. If you need nonzero if |base| is + * UINT64_MAX, use !ngtcp2_tstamp_elapsed. Otherwise, use + * ngtcp2_tstamp_not_elapsed. + */ +static inline int ngtcp2_tstamp_elapsed(ngtcp2_tstamp base, ngtcp2_duration d, + ngtcp2_tstamp ts) { + return base != UINT64_MAX && base < UINT64_MAX - d && base + d <= ts; +} + +/* + * ngtcp2_tstamp_not_elapsed returns nonzero if |d| has not passed + * since |base|. |ts| expresses a current time, and must not be + * UINT64_MAX. + * + * If |base| is UINT64_MAX, this function returns 0 because UINT64_MAX + * is an invalid timestamp. Otherwise, if |base| + |d| >= UINT64_MAX, + * this function returns nonzero. + */ +static inline int ngtcp2_tstamp_not_elapsed(ngtcp2_tstamp base, + ngtcp2_duration d, + ngtcp2_tstamp ts) { + return base != UINT64_MAX && (base >= UINT64_MAX - d || base + d > ts); +} + +#endif /* NGTCP2_TSTAMP_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c new file mode 100644 index 00000000000000..7c7d9ae78e914d --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c @@ -0,0 +1,71 @@ +/* + * ngtcp2 + * + * Copyright (c) 2022 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_unreachable.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + +void ngtcp2_unreachable_fail(const char *file, int line, const char *func) { + char *buf; + size_t buflen; + int rv; + +#define NGTCP2_UNREACHABLE_TEMPLATE "%s:%d %s: Unreachable.\n" + + rv = snprintf(NULL, 0, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + + /* here we explicitly use system malloc */ + buflen = (size_t)rv + 1; + buf = malloc(buflen); + if (buf == NULL) { + abort(); + } + + rv = snprintf(buf, buflen, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + +#ifndef WIN32 + while (write(STDERR_FILENO, buf, (size_t)rv) == -1 && errno == EINTR) + ; +#else /* WIN32 */ + _write(_fileno(stderr), buf, (unsigned int)rv); +#endif /* WIN32 */ + + free(buf); + + abort(); +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h new file mode 100644 index 00000000000000..a5276fd505463f --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h @@ -0,0 +1,52 @@ +/* + * ngtcp2 + * + * Copyright (c) 2022 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_UNREACHABLE_H +#define NGTCP2_UNREACHABLE_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#ifdef __FILE_NAME__ +# define NGTCP2_FILE_NAME __FILE_NAME__ +#else /* !__FILE_NAME__ */ +# define NGTCP2_FILE_NAME "(file)" +#endif /* !__FILE_NAME__ */ + +#define ngtcp2_unreachable() \ + ngtcp2_unreachable_fail(NGTCP2_FILE_NAME, __LINE__, __func__) + +#ifdef _MSC_VER +__declspec(noreturn) +#endif /* _MSC_VER */ + void ngtcp2_unreachable_fail(const char *file, int line, const char *func) +#ifndef _MSC_VER + __attribute__((noreturn)) +#endif /* !_MSC_VER */ + ; + +#endif /* NGTCP2_UNREACHABLE_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c index 257332e27a2abe..dbc7b668042695 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c @@ -145,7 +145,7 @@ ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst, size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, size_t *psrccnt, size_t left, size_t maxcnt) { size_t orig_left = left; - size_t i; + size_t i = 0; ngtcp2_vec *a, *b; assert(maxcnt); @@ -158,12 +158,7 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, a = &dst[0]; b = &src[0]; - if (left >= b->len) { - *a = *b; - ++*pdstcnt; - left -= b->len; - i = 1; - } else { + if (left < b->len) { a->len = left; a->base = b->base; @@ -172,41 +167,43 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, return left; } - } else { - i = 0; + + *a = *b; + ++*pdstcnt; + left -= b->len; + i = 1; } for (; left && i < *psrccnt; ++i) { a = &dst[*pdstcnt - 1]; b = &src[i]; - if (left >= b->len) { + if (left < b->len) { if (a->base + a->len == b->base) { - a->len += b->len; + a->len += left; } else if (*pdstcnt == maxcnt) { break; } else { - dst[(*pdstcnt)++] = *b; + dst[*pdstcnt].len = left; + dst[*pdstcnt].base = b->base; + ++*pdstcnt; } - left -= b->len; - continue; + + b->len -= left; + b->base += left; + left = 0; + + break; } if (a->base + a->len == b->base) { - a->len += left; + a->len += b->len; } else if (*pdstcnt == maxcnt) { break; } else { - dst[*pdstcnt].len = left; - dst[*pdstcnt].base = b->base; - ++*pdstcnt; + dst[(*pdstcnt)++] = *b; } - - b->len -= left; - b->base += left; - left = 0; - - break; + left -= b->len; } memmove(src, src + i, sizeof(ngtcp2_vec) * (*psrccnt - i));