From 7d78eff88928fd5fa4a7b49cc280470673dc6e16 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 17 Jan 2023 15:21:16 +0100 Subject: [PATCH] MINOR: h3: extend function for QUIC varint encoding Slighty adjust b_quic_enc_int(). This function is used to encode an integer as a QUIC varint in a struct buffer. A new parameter is added to the function API to specify the width of the encoded integer. By default, 0 should be use to ensure that the minimum space is used. Other valid values are 1, 2, 4 or 8. An error is reported if the width is not large enough. This new parameter will be useful when buffer space is reserved prior to encode an unknown integer value. The maximum size of 8 bytes will be reserved and some data can be put after. When finally encoding the integer, the width can be requested to be 8 bytes. With this new parameter, a small refactoring of the function has been conducted to remove some useless internal variables. This should be backported up to 2.7. It will be mostly useful to implement H3 trailers encoding. --- include/haproxy/quic_enc.h | 55 +++++++++++++++++++++----------------- src/h3.c | 28 +++++++++---------- 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/include/haproxy/quic_enc.h b/include/haproxy/quic_enc.h index 45c2b4b4b..4b8560524 100644 --- a/include/haproxy/quic_enc.h +++ b/include/haproxy/quic_enc.h @@ -198,39 +198,44 @@ static inline int quic_enc_int(unsigned char **buf, const unsigned char *end, ui return 1; } -/* Encode a QUIC variable-length integer into buffer. - * Returns 1 if succeeded (there was enough room in buf), 0 if not. +/* Encode a QUIC variable-length integer into buffer. can be + * set to specify the desired output width. By default use 0 for the minimal + * integer size. Other valid values are 1, 2, 4 or 8. + * + * Returns 1 on success else 0. */ -static inline int b_quic_enc_int(struct buffer *b, uint64_t val) +static inline int b_quic_enc_int(struct buffer *b, uint64_t val, int width) { - unsigned int shift; - unsigned char size_bits, *tail, *pos, *wrap; - size_t save_len, len; - size_t data = b_data(b); - size_t size = b_size(b); + char *pos; + int save_width, len; - if (data == size) - return 0; + /* width can only by 0, 1, 2, 4 or 8 */ + BUG_ON(width && (width > 8 || atleast2(width))); - save_len = len = quic_int_getsize(val); + len = quic_int_getsize(val); if (!len) return 0; - shift = (len - 1) * 8; - /* set the bits of byte#0 which gives the length of the encoded integer */ - size_bits = quic_log2(len) << QUIC_VARINT_BYTE_0_SHIFT; - pos = tail = (unsigned char *)b_tail(b); - wrap = (unsigned char *)b_wrap(b); - while (len--) { - *pos++ = val >> shift; - shift -= 8; - if (pos == wrap) - pos -= size; - if (++data == size && len) - return 0; + /* Check that buffer room is sufficient and width big enough if set. */ + if (b_room(b) < len || (width && width < len)) + return 0; + + if (!width) + width = len; + save_width = width; + + pos = b_tail(b); + while (width--) { + /* Encode the shifted integer or 0 if width bigger than integer length. */ + *pos++ = width >= len ? 0 : val >> (width * 8); + + if (pos == b_wrap(b)) + pos = b_orig(b); } - *tail |= size_bits; - b_add(b, save_len); + + /* set the bits of byte#0 which gives the length of the encoded integer */ + *b_tail(b) |= quic_log2(save_width) << QUIC_VARINT_BYTE_0_SHIFT; + b_add(b, save_width); return 1; } diff --git a/src/h3.c b/src/h3.c index e38464081..f30b3d9c7 100644 --- a/src/h3.c +++ b/src/h3.c @@ -1042,17 +1042,17 @@ static int h3_control_send(struct qcs *qcs, void *ctx) quic_int_getsize(h3_settings_max_field_section_size); } - b_quic_enc_int(&pos, H3_UNI_S_T_CTRL); + b_quic_enc_int(&pos, H3_UNI_S_T_CTRL, 0); /* Build a SETTINGS frame */ - b_quic_enc_int(&pos, H3_FT_SETTINGS); - b_quic_enc_int(&pos, frm_len); - b_quic_enc_int(&pos, H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY); - b_quic_enc_int(&pos, h3_settings_qpack_max_table_capacity); - b_quic_enc_int(&pos, H3_SETTINGS_QPACK_BLOCKED_STREAMS); - b_quic_enc_int(&pos, h3_settings_qpack_blocked_streams); + b_quic_enc_int(&pos, H3_FT_SETTINGS, 0); + b_quic_enc_int(&pos, frm_len, 0); + b_quic_enc_int(&pos, H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0); + b_quic_enc_int(&pos, h3_settings_qpack_max_table_capacity, 0); + b_quic_enc_int(&pos, H3_SETTINGS_QPACK_BLOCKED_STREAMS, 0); + b_quic_enc_int(&pos, h3_settings_qpack_blocked_streams, 0); if (h3_settings_max_field_section_size) { - b_quic_enc_int(&pos, H3_SETTINGS_MAX_FIELD_SECTION_SIZE); - b_quic_enc_int(&pos, h3_settings_max_field_section_size); + b_quic_enc_int(&pos, H3_SETTINGS_MAX_FIELD_SECTION_SIZE, 0); + b_quic_enc_int(&pos, h3_settings_max_field_section_size, 0); } res = mux_get_buf(qcs); @@ -1177,7 +1177,7 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx) frame_length_size = quic_int_getsize(b_data(&headers_buf)); res->head += 4 - frame_length_size; b_putchr(res, 0x01); /* h3 HEADERS frame type */ - if (!b_quic_enc_int(res, b_data(&headers_buf))) + if (!b_quic_enc_int(res, b_data(&headers_buf), 0)) ABORT_NOW(); b_add(res, b_data(&headers_buf)); @@ -1252,7 +1252,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx, size_t count) BUG_ON(fsize <= 0); b_putchr(&outbuf, 0x00); /* h3 frame type = DATA */ - b_quic_enc_int(&outbuf, fsize); /* h3 frame length */ + b_quic_enc_int(&outbuf, fsize, 0); /* h3 frame length */ b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize); total += fsize; @@ -1407,9 +1407,9 @@ static int h3_send_goaway(struct h3c *h3c) pos = b_make((char *)data, sizeof(data), 0, 0); - b_quic_enc_int(&pos, H3_FT_GOAWAY); - b_quic_enc_int(&pos, frm_len); - b_quic_enc_int(&pos, h3c->id_goaway); + b_quic_enc_int(&pos, H3_FT_GOAWAY, 0); + b_quic_enc_int(&pos, frm_len, 0); + b_quic_enc_int(&pos, h3c->id_goaway, 0); res = mux_get_buf(qcs); if (!res || b_room(res) < b_data(&pos)) {