mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-02-05 09:21:42 +01:00
REORG: quic: Move several inlined functions from quic_conn.h
Move quic_pkt_type(), quic_saddr_cpy(), quic_write_uint32(), max_available_room(), max_stream_data_size(), quic_packet_number_length(), quic_packet_number_encode() and quic_compute_ack_delay_us() to quic_tx.c because only used in this file. Also move quic_ack_delay_ms() and quic_read_uint32() to quic_tx.c because they are used only in this file. Move quic_rx_packet_refinc() and quic_rx_packet_refdec() to quic_rx.h header. Move qc_el_rx_pkts(), qc_el_rx_pkts_del() and qc_list_qel_rx_pkts() to quic_tls.h header.
This commit is contained in:
parent
831764641f
commit
09ab48472c
@ -45,7 +45,7 @@
|
||||
#include <haproxy/quic_enc.h>
|
||||
#include <haproxy/quic_frame.h>
|
||||
#include <haproxy/quic_loss.h>
|
||||
#include <haproxy/quic_rx-t.h>
|
||||
#include <haproxy/quic_rx.h>
|
||||
#include <haproxy/mux_quic.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
@ -85,64 +85,11 @@ void qc_check_close_on_released_mux(struct quic_conn *qc);
|
||||
int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
|
||||
const unsigned char *salt, size_t saltlen);
|
||||
|
||||
/* Return the long packet type matching with <qv> version and <type> */
|
||||
static inline int quic_pkt_type(int type, uint32_t version)
|
||||
{
|
||||
if (version != QUIC_PROTOCOL_VERSION_2)
|
||||
return type;
|
||||
|
||||
switch (type) {
|
||||
case QUIC_PACKET_TYPE_INITIAL:
|
||||
return 1;
|
||||
case QUIC_PACKET_TYPE_0RTT:
|
||||
return 2;
|
||||
case QUIC_PACKET_TYPE_HANDSHAKE:
|
||||
return 3;
|
||||
case QUIC_PACKET_TYPE_RETRY:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int qc_is_listener(struct quic_conn *qc)
|
||||
{
|
||||
return qc->flags & QUIC_FL_CONN_LISTENER;
|
||||
}
|
||||
|
||||
/* Copy <saddr> socket address data into <buf> buffer.
|
||||
* This is the responsibility of the caller to check the output buffer is big
|
||||
* enough to contain these socket address data.
|
||||
* Return the number of bytes copied.
|
||||
*/
|
||||
static inline size_t quic_saddr_cpy(unsigned char *buf,
|
||||
const struct sockaddr_storage *saddr)
|
||||
{
|
||||
void *port, *addr;
|
||||
unsigned char *p;
|
||||
size_t port_len, addr_len;
|
||||
|
||||
p = buf;
|
||||
if (saddr->ss_family == AF_INET6) {
|
||||
port = &((struct sockaddr_in6 *)saddr)->sin6_port;
|
||||
addr = &((struct sockaddr_in6 *)saddr)->sin6_addr;
|
||||
port_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_port;
|
||||
addr_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_addr;
|
||||
}
|
||||
else {
|
||||
port = &((struct sockaddr_in *)saddr)->sin_port;
|
||||
addr = &((struct sockaddr_in *)saddr)->sin_addr;
|
||||
port_len = sizeof ((struct sockaddr_in *)saddr)->sin_port;
|
||||
addr_len = sizeof ((struct sockaddr_in *)saddr)->sin_addr;
|
||||
}
|
||||
memcpy(p, port, port_len);
|
||||
p += port_len;
|
||||
memcpy(p, addr, addr_len);
|
||||
p += addr_len;
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
/* Free the CIDs attached to <conn> QUIC connection. */
|
||||
static inline void free_quic_conn_cids(struct quic_conn *conn)
|
||||
{
|
||||
@ -199,201 +146,6 @@ static inline void quic_connection_id_to_frm_cpy(struct quic_frame *dst,
|
||||
ncid_frm->stateless_reset_token = src->stateless_reset_token;
|
||||
}
|
||||
|
||||
/* Return a 32-bits integer in <val> from QUIC packet with <buf> as address.
|
||||
* Makes <buf> point to the data after this 32-bits value if succeeded.
|
||||
* Note that these 32-bits integers are network bytes ordered.
|
||||
* Returns 0 if failed (not enough data in the buffer), 1 if succeeded.
|
||||
*/
|
||||
static inline int quic_read_uint32(uint32_t *val,
|
||||
const unsigned char **buf,
|
||||
const unsigned char *end)
|
||||
{
|
||||
if (end - *buf < sizeof *val)
|
||||
return 0;
|
||||
|
||||
*val = ntohl(*(uint32_t *)*buf);
|
||||
*buf += sizeof *val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write a 32-bits integer to a buffer with <buf> as address.
|
||||
* Make <buf> point to the data after this 32-buts value if succeeded.
|
||||
* Note that these 32-bits integers are networkg bytes ordered.
|
||||
* Returns 0 if failed (not enough room in the buffer), 1 if succeeded.
|
||||
*/
|
||||
static inline int quic_write_uint32(unsigned char **buf,
|
||||
const unsigned char *end, uint32_t val)
|
||||
{
|
||||
if (end - *buf < sizeof val)
|
||||
return 0;
|
||||
|
||||
*(uint32_t *)*buf = htonl(val);
|
||||
*buf += sizeof val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Return the maximum number of bytes we must use to completely fill a
|
||||
* buffer with <sz> as size for a data field of bytes prefixed by its QUIC
|
||||
* variable-length (may be 0).
|
||||
* Also put in <*len_sz> the size of this QUIC variable-length.
|
||||
* So after returning from this function we have : <*len_sz> + <ret> <= <sz>
|
||||
* (<*len_sz> = { max(i), i + ret <= <sz> }) .
|
||||
*/
|
||||
static inline size_t max_available_room(size_t sz, size_t *len_sz)
|
||||
{
|
||||
size_t sz_sz, ret;
|
||||
size_t diff;
|
||||
|
||||
sz_sz = quic_int_getsize(sz);
|
||||
if (sz <= sz_sz)
|
||||
return 0;
|
||||
|
||||
ret = sz - sz_sz;
|
||||
*len_sz = quic_int_getsize(ret);
|
||||
/* Difference between the two sizes. Note that <sz_sz> >= <*len_sz>. */
|
||||
diff = sz_sz - *len_sz;
|
||||
if (unlikely(diff > 0)) {
|
||||
/* Let's try to take into an account remaining bytes.
|
||||
*
|
||||
* <----------------> <sz_sz>
|
||||
* <--------------><--------> +----> <max_int>
|
||||
* <ret> <len_sz> |
|
||||
* +---------------------------+-----------....
|
||||
* <--------------------------------> <sz>
|
||||
*/
|
||||
size_t max_int = quic_max_int(*len_sz);
|
||||
|
||||
if (max_int + *len_sz <= sz)
|
||||
ret = max_int;
|
||||
else
|
||||
ret = sz - diff;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function computes the maximum data we can put into a buffer with <sz> as
|
||||
* size prefixed with a variable-length field "Length" whose value is the
|
||||
* remaining data length, already filled of <ilen> bytes which must be taken
|
||||
* into an account by "Length" field, and finally followed by the data we want
|
||||
* to put in this buffer prefixed again by a variable-length field.
|
||||
* <sz> is the size of the buffer to fill.
|
||||
* <ilen> the number of bytes already put after the "Length" field.
|
||||
* <dlen> the number of bytes we want to at most put in the buffer.
|
||||
* Also set <*dlen_sz> to the size of the data variable-length we want to put in
|
||||
* the buffer. This is typically this function which must be used to fill as
|
||||
* much as possible a QUIC packet made of only one CRYPTO or STREAM frames.
|
||||
* Returns this computed size if there is enough room in the buffer, 0 if not.
|
||||
*/
|
||||
static inline size_t max_stream_data_size(size_t sz, size_t ilen, size_t dlen)
|
||||
{
|
||||
size_t ret, len_sz, dlen_sz;
|
||||
|
||||
/*
|
||||
* The length of variable-length QUIC integers are powers of two.
|
||||
* Look for the first 3length" field value <len_sz> which match our need.
|
||||
* As we must put <ilen> bytes in our buffer, the minimum value for
|
||||
* <len_sz> is the number of bytes required to encode <ilen>.
|
||||
*/
|
||||
for (len_sz = quic_int_getsize(ilen);
|
||||
len_sz <= QUIC_VARINT_MAX_SIZE;
|
||||
len_sz <<= 1) {
|
||||
if (sz < len_sz + ilen)
|
||||
return 0;
|
||||
|
||||
ret = max_available_room(sz - len_sz - ilen, &dlen_sz);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
/* Check that <*len_sz> matches <ret> value */
|
||||
if (len_sz + ilen + dlen_sz + ret <= quic_max_int(len_sz))
|
||||
return ret < dlen ? ret : dlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the length in bytes of <pn> packet number depending on
|
||||
* <largest_acked_pn> the largest ackownledged packet number.
|
||||
*/
|
||||
static inline size_t quic_packet_number_length(int64_t pn,
|
||||
int64_t largest_acked_pn)
|
||||
{
|
||||
int64_t max_nack_pkts;
|
||||
|
||||
/* About packet number encoding, the RFC says:
|
||||
* The sender MUST use a packet number size able to represent more than
|
||||
* twice as large a range than the difference between the largest
|
||||
* acknowledged packet and packet number being sent.
|
||||
*/
|
||||
max_nack_pkts = 2 * (pn - largest_acked_pn) + 1;
|
||||
if (max_nack_pkts > 0xffffff)
|
||||
return 4;
|
||||
if (max_nack_pkts > 0xffff)
|
||||
return 3;
|
||||
if (max_nack_pkts > 0xff)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Encode <pn> packet number with <pn_len> as length in byte into a buffer with
|
||||
* <buf> as current copy address and <end> as pointer to one past the end of
|
||||
* this buffer. This is the responsibility of the caller to check there is
|
||||
* enough room in the buffer to copy <pn_len> bytes.
|
||||
* Never fails.
|
||||
*/
|
||||
static inline int quic_packet_number_encode(unsigned char **buf,
|
||||
const unsigned char *end,
|
||||
uint64_t pn, size_t pn_len)
|
||||
{
|
||||
if (end - *buf < pn_len)
|
||||
return 0;
|
||||
|
||||
/* Encode the packet number. */
|
||||
switch (pn_len) {
|
||||
case 1:
|
||||
**buf = pn;
|
||||
break;
|
||||
case 2:
|
||||
write_n16(*buf, pn);
|
||||
break;
|
||||
case 3:
|
||||
(*buf)[0] = pn >> 16;
|
||||
(*buf)[1] = pn >> 8;
|
||||
(*buf)[2] = pn;
|
||||
break;
|
||||
case 4:
|
||||
write_n32(*buf, pn);
|
||||
break;
|
||||
}
|
||||
*buf += pn_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns the <ack_delay> field value in milliseconds from <ack_frm> ACK frame for
|
||||
* <conn> QUIC connection. Note that the value of <ack_delay> coming from
|
||||
* ACK frame is in microseconds.
|
||||
*/
|
||||
static inline unsigned int quic_ack_delay_ms(struct qf_ack *ack_frm,
|
||||
struct quic_conn *conn)
|
||||
{
|
||||
return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000;
|
||||
}
|
||||
|
||||
/* Returns the <ack_delay> field value in microsecond to be set in an ACK frame
|
||||
* depending on the time the packet with a new largest packet number was received.
|
||||
*/
|
||||
static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received,
|
||||
struct quic_conn *conn)
|
||||
{
|
||||
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
|
||||
}
|
||||
|
||||
/* Initialize <p> QUIC network path depending on <ipv4> boolean
|
||||
* which is true for an IPv4 path, if not false for an IPv6 path.
|
||||
*/
|
||||
@ -427,76 +179,12 @@ static inline size_t quic_path_prep_data(struct quic_path *path)
|
||||
return path->cwnd - path->prep_in_flight;
|
||||
}
|
||||
|
||||
/* Return the number of bytes which may be sent from <qc> connection when
|
||||
* it has not already been validated. Note that this is the responsibility
|
||||
* of the caller to check that the case with quic_peer_validated_addr().
|
||||
* This latter BUG_ON() if 3 * qc->rx.bytes < qc->tx.prep_bytes.
|
||||
*/
|
||||
static inline size_t quic_may_send_bytes(struct quic_conn *qc)
|
||||
{
|
||||
return 3 * qc->bytes.rx - qc->bytes.prep;
|
||||
}
|
||||
|
||||
/* Return 1 if <pkt> header form is long, 0 if not. */
|
||||
static inline int qc_pkt_long(const struct quic_rx_packet *pkt)
|
||||
{
|
||||
return pkt->type != QUIC_PACKET_TYPE_SHORT;
|
||||
}
|
||||
|
||||
/* Return 1 if there is RX packets for <qel> QUIC encryption level, 0 if not */
|
||||
static inline int qc_el_rx_pkts(struct quic_enc_level *qel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = !eb_is_empty(&qel->rx.pkts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Increment the reference counter of <pkt> */
|
||||
static inline void quic_rx_packet_refinc(struct quic_rx_packet *pkt)
|
||||
{
|
||||
pkt->refcnt++;
|
||||
}
|
||||
|
||||
/* Decrement the reference counter of <pkt> while remaining positive */
|
||||
static inline void quic_rx_packet_refdec(struct quic_rx_packet *pkt)
|
||||
{
|
||||
if (pkt->refcnt)
|
||||
pkt->refcnt--;
|
||||
}
|
||||
|
||||
/* Delete all RX packets for <qel> QUIC encryption level */
|
||||
static inline void qc_el_rx_pkts_del(struct quic_enc_level *qel)
|
||||
{
|
||||
struct eb64_node *node;
|
||||
|
||||
node = eb64_first(&qel->rx.pkts);
|
||||
while (node) {
|
||||
struct quic_rx_packet *pkt =
|
||||
eb64_entry(node, struct quic_rx_packet, pn_node);
|
||||
|
||||
node = eb64_next(node);
|
||||
eb64_delete(&pkt->pn_node);
|
||||
quic_rx_packet_refdec(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qc_list_qel_rx_pkts(struct quic_enc_level *qel)
|
||||
{
|
||||
struct eb64_node *node;
|
||||
|
||||
node = eb64_first(&qel->rx.pkts);
|
||||
while (node) {
|
||||
struct quic_rx_packet *pkt;
|
||||
|
||||
pkt = eb64_entry(node, struct quic_rx_packet, pn_node);
|
||||
fprintf(stderr, "pkt@%p type=%d pn=%llu\n",
|
||||
pkt, pkt->type, (ull)pkt->pn_node.key);
|
||||
node = eb64_next(node);
|
||||
}
|
||||
}
|
||||
|
||||
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
|
||||
|
||||
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
|
||||
|
||||
@ -36,4 +36,17 @@ int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns,
|
||||
int qc_treat_rx_crypto_frms(struct quic_conn *qc, struct quic_enc_level *el,
|
||||
struct ssl_sock_ctx *ctx);
|
||||
|
||||
/* Increment the reference counter of <pkt> */
|
||||
static inline void quic_rx_packet_refinc(struct quic_rx_packet *pkt)
|
||||
{
|
||||
pkt->refcnt++;
|
||||
}
|
||||
|
||||
/* Decrement the reference counter of <pkt> while remaining positive */
|
||||
static inline void quic_rx_packet_refdec(struct quic_rx_packet *pkt)
|
||||
{
|
||||
if (pkt->refcnt)
|
||||
pkt->refcnt--;
|
||||
}
|
||||
|
||||
#endif /* _HAPROXY_QUIC_RX_H */
|
||||
|
||||
@ -1049,6 +1049,57 @@ static inline int quic_tls_has_tx_sec(const struct quic_enc_level *qel)
|
||||
return qel && !!qel->tls_ctx.tx.key;
|
||||
}
|
||||
|
||||
/* Return 1 if there is RX packets for <qel> QUIC encryption level, 0 if not */
|
||||
static inline int qc_el_rx_pkts(struct quic_enc_level *qel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = !eb_is_empty(&qel->rx.pkts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delete all RX packets for <qel> QUIC encryption level */
|
||||
static inline void qc_el_rx_pkts_del(struct quic_enc_level *qel)
|
||||
{
|
||||
struct eb64_node *node;
|
||||
|
||||
node = eb64_first(&qel->rx.pkts);
|
||||
while (node) {
|
||||
struct quic_rx_packet *pkt =
|
||||
eb64_entry(node, struct quic_rx_packet, pn_node);
|
||||
|
||||
node = eb64_next(node);
|
||||
eb64_delete(&pkt->pn_node);
|
||||
quic_rx_packet_refdec(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qc_list_qel_rx_pkts(struct quic_enc_level *qel)
|
||||
{
|
||||
struct eb64_node *node;
|
||||
|
||||
node = eb64_first(&qel->rx.pkts);
|
||||
while (node) {
|
||||
struct quic_rx_packet *pkt;
|
||||
|
||||
pkt = eb64_entry(node, struct quic_rx_packet, pn_node);
|
||||
fprintf(stderr, "pkt@%p type=%d pn=%llu\n",
|
||||
pkt, pkt->type, (ull)pkt->pn_node.key);
|
||||
node = eb64_next(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a boolean if <qc> needs to emit frames for <qel> encryption level. */
|
||||
static inline int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel)
|
||||
{
|
||||
return (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) ||
|
||||
(qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) ||
|
||||
qel->pktns->tx.pto_probe ||
|
||||
!LIST_ISEMPTY(&qel->pktns->tx.frms);
|
||||
}
|
||||
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _PROTO_QUIC_TLS_H */
|
||||
|
||||
|
||||
@ -33,7 +33,6 @@ void qc_txb_release(struct quic_conn *qc);
|
||||
int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf);
|
||||
struct buffer *qc_get_txb(struct quic_conn *qc);
|
||||
|
||||
int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel);
|
||||
int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels);
|
||||
int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx);
|
||||
int qc_may_probe_ipktns(struct quic_conn *qc);
|
||||
@ -86,4 +85,15 @@ static inline void quic_tx_packet_refdec(struct quic_tx_packet *pkt)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of bytes which may be sent from <qc> connection when
|
||||
* it has not already been validated. Note that this is the responsability
|
||||
* of the caller to check that the case with quic_peer_validated_addr().
|
||||
* This latter BUG_ON() if 3 * qc->rx.bytes < qc->tx.prep_bytes.
|
||||
*/
|
||||
static inline size_t quic_may_send_bytes(struct quic_conn *qc)
|
||||
{
|
||||
return 3 * qc->bytes.rx - qc->bytes.prep;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _HAPROXY_QUIC_TX_H */
|
||||
|
||||
@ -940,6 +940,16 @@ static int qc_handle_retire_connection_id_frm(struct quic_conn *qc,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Returns the <ack_delay> field value in milliseconds from <ack_frm> ACK frame for
|
||||
* <conn> QUIC connection. Note that the value of <ack_delay> coming from
|
||||
* ACK frame is in microseconds.
|
||||
*/
|
||||
static inline unsigned int quic_ack_delay_ms(struct qf_ack *ack_frm,
|
||||
struct quic_conn *conn)
|
||||
{
|
||||
return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000;
|
||||
}
|
||||
|
||||
/* Parse all the frames of <pkt> QUIC packet for QUIC connection <qc> and <qel>
|
||||
* as encryption level.
|
||||
* Returns 1 if succeeded, 0 if failed.
|
||||
@ -1670,6 +1680,24 @@ static int qc_try_rm_hp(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a 32-bits integer in <val> from QUIC packet with <buf> as address.
|
||||
* Makes <buf> point to the data after this 32-bits value if succeeded.
|
||||
* Note that these 32-bits integers are network bytes ordered.
|
||||
* Returns 0 if failed (not enough data in the buffer), 1 if succeeded.
|
||||
*/
|
||||
static inline int quic_read_uint32(uint32_t *val,
|
||||
const unsigned char **buf,
|
||||
const unsigned char *end)
|
||||
{
|
||||
if (end - *buf < sizeof *val)
|
||||
return 0;
|
||||
|
||||
*val = ntohl(*(uint32_t *)*buf);
|
||||
*buf += sizeof *val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse a QUIC packet header starting at <pos> position without exceeding <end>.
|
||||
* Version and type are stored in <pkt> packet instance. Type is set to unknown
|
||||
* on two occasions : for unsupported version, in this case version field is
|
||||
|
||||
230
src/quic_tx.c
230
src/quic_tx.c
@ -1429,15 +1429,6 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns a boolean if <qc> needs to emit frames for <qel> encryption level. */
|
||||
int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel)
|
||||
{
|
||||
return (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) ||
|
||||
(qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) ||
|
||||
qel->pktns->tx.pto_probe ||
|
||||
!LIST_ISEMPTY(&qel->pktns->tx.frms);
|
||||
}
|
||||
|
||||
/* Return 1 if <qc> connection may probe the Initial packet number space, 0 if not.
|
||||
* This is not the case if the remote peer address is not validated and if
|
||||
* it cannot send at least QUIC_INITIAL_PACKET_MINLEN bytes.
|
||||
@ -1568,6 +1559,40 @@ int send_stateless_reset(struct listener *l, struct sockaddr_storage *dstaddr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Copy <saddr> socket address data into <buf> buffer.
|
||||
* This is the responsibility of the caller to check the output buffer is big
|
||||
* enough to contain these socket address data.
|
||||
* Return the number of bytes copied.
|
||||
*/
|
||||
static inline size_t quic_saddr_cpy(unsigned char *buf,
|
||||
const struct sockaddr_storage *saddr)
|
||||
{
|
||||
void *port, *addr;
|
||||
unsigned char *p;
|
||||
size_t port_len, addr_len;
|
||||
|
||||
p = buf;
|
||||
if (saddr->ss_family == AF_INET6) {
|
||||
port = &((struct sockaddr_in6 *)saddr)->sin6_port;
|
||||
addr = &((struct sockaddr_in6 *)saddr)->sin6_addr;
|
||||
port_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_port;
|
||||
addr_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_addr;
|
||||
}
|
||||
else {
|
||||
port = &((struct sockaddr_in *)saddr)->sin_port;
|
||||
addr = &((struct sockaddr_in *)saddr)->sin_addr;
|
||||
port_len = sizeof ((struct sockaddr_in *)saddr)->sin_port;
|
||||
addr_len = sizeof ((struct sockaddr_in *)saddr)->sin_addr;
|
||||
}
|
||||
memcpy(p, port, port_len);
|
||||
p += port_len;
|
||||
memcpy(p, addr, addr_len);
|
||||
p += addr_len;
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
/* QUIC server only function.
|
||||
* Add AAD to <add> buffer from <cid> connection ID and <addr> socket address.
|
||||
* This is the responsibility of the caller to check <aad> size is big enough
|
||||
@ -1676,6 +1701,27 @@ static int quic_generate_retry_token(unsigned char *token, size_t len,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Return the long packet type matching with <qv> version and <type> */
|
||||
static inline int quic_pkt_type(int type, uint32_t version)
|
||||
{
|
||||
if (version != QUIC_PROTOCOL_VERSION_2)
|
||||
return type;
|
||||
|
||||
switch (type) {
|
||||
case QUIC_PACKET_TYPE_INITIAL:
|
||||
return 1;
|
||||
case QUIC_PACKET_TYPE_0RTT:
|
||||
return 2;
|
||||
case QUIC_PACKET_TYPE_HANDSHAKE:
|
||||
return 3;
|
||||
case QUIC_PACKET_TYPE_RETRY:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Generate a Retry packet and send it on <fd> socket to <addr> in response to
|
||||
* the Initial <pkt> packet.
|
||||
*
|
||||
@ -1747,6 +1793,163 @@ int send_retry(int fd, struct sockaddr_storage *addr,
|
||||
return !ret;
|
||||
}
|
||||
|
||||
/* Write a 32-bits integer to a buffer with <buf> as address.
|
||||
* Make <buf> point to the data after this 32-buts value if succeeded.
|
||||
* Note that these 32-bits integers are networkg bytes ordered.
|
||||
* Returns 0 if failed (not enough room in the buffer), 1 if succeeded.
|
||||
*/
|
||||
static inline int quic_write_uint32(unsigned char **buf,
|
||||
const unsigned char *end, uint32_t val)
|
||||
{
|
||||
if (end - *buf < sizeof val)
|
||||
return 0;
|
||||
|
||||
*(uint32_t *)*buf = htonl(val);
|
||||
*buf += sizeof val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the maximum number of bytes we must use to completely fill a
|
||||
* buffer with <sz> as size for a data field of bytes prefixed by its QUIC
|
||||
* variable-length (may be 0).
|
||||
* Also put in <*len_sz> the size of this QUIC variable-length.
|
||||
* So after returning from this function we have : <*len_sz> + <ret> <= <sz>
|
||||
* (<*len_sz> = { max(i), i + ret <= <sz> }) .
|
||||
*/
|
||||
static inline size_t max_available_room(size_t sz, size_t *len_sz)
|
||||
{
|
||||
size_t sz_sz, ret;
|
||||
size_t diff;
|
||||
|
||||
sz_sz = quic_int_getsize(sz);
|
||||
if (sz <= sz_sz)
|
||||
return 0;
|
||||
|
||||
ret = sz - sz_sz;
|
||||
*len_sz = quic_int_getsize(ret);
|
||||
/* Difference between the two sizes. Note that <sz_sz> >= <*len_sz>. */
|
||||
diff = sz_sz - *len_sz;
|
||||
if (unlikely(diff > 0)) {
|
||||
/* Let's try to take into an account remaining bytes.
|
||||
*
|
||||
* <----------------> <sz_sz>
|
||||
* <--------------><--------> +----> <max_int>
|
||||
* <ret> <len_sz> |
|
||||
* +---------------------------+-----------....
|
||||
* <--------------------------------> <sz>
|
||||
*/
|
||||
size_t max_int = quic_max_int(*len_sz);
|
||||
|
||||
if (max_int + *len_sz <= sz)
|
||||
ret = max_int;
|
||||
else
|
||||
ret = sz - diff;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function computes the maximum data we can put into a buffer with <sz> as
|
||||
* size prefixed with a variable-length field "Length" whose value is the
|
||||
* remaining data length, already filled of <ilen> bytes which must be taken
|
||||
* into an account by "Length" field, and finally followed by the data we want
|
||||
* to put in this buffer prefixed again by a variable-length field.
|
||||
* <sz> is the size of the buffer to fill.
|
||||
* <ilen> the number of bytes already put after the "Length" field.
|
||||
* <dlen> the number of bytes we want to at most put in the buffer.
|
||||
* Also set <*dlen_sz> to the size of the data variable-length we want to put in
|
||||
* the buffer. This is typically this function which must be used to fill as
|
||||
* much as possible a QUIC packet made of only one CRYPTO or STREAM frames.
|
||||
* Returns this computed size if there is enough room in the buffer, 0 if not.
|
||||
*/
|
||||
static inline size_t max_stream_data_size(size_t sz, size_t ilen, size_t dlen)
|
||||
{
|
||||
size_t ret, len_sz, dlen_sz;
|
||||
|
||||
/*
|
||||
* The length of variable-length QUIC integers are powers of two.
|
||||
* Look for the first 3length" field value <len_sz> which match our need.
|
||||
* As we must put <ilen> bytes in our buffer, the minimum value for
|
||||
* <len_sz> is the number of bytes required to encode <ilen>.
|
||||
*/
|
||||
for (len_sz = quic_int_getsize(ilen);
|
||||
len_sz <= QUIC_VARINT_MAX_SIZE;
|
||||
len_sz <<= 1) {
|
||||
if (sz < len_sz + ilen)
|
||||
return 0;
|
||||
|
||||
ret = max_available_room(sz - len_sz - ilen, &dlen_sz);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
/* Check that <*len_sz> matches <ret> value */
|
||||
if (len_sz + ilen + dlen_sz + ret <= quic_max_int(len_sz))
|
||||
return ret < dlen ? ret : dlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the length in bytes of <pn> packet number depending on
|
||||
* <largest_acked_pn> the largest ackownledged packet number.
|
||||
*/
|
||||
static inline size_t quic_packet_number_length(int64_t pn,
|
||||
int64_t largest_acked_pn)
|
||||
{
|
||||
int64_t max_nack_pkts;
|
||||
|
||||
/* About packet number encoding, the RFC says:
|
||||
* The sender MUST use a packet number size able to represent more than
|
||||
* twice as large a range than the difference between the largest
|
||||
* acknowledged packet and packet number being sent.
|
||||
*/
|
||||
max_nack_pkts = 2 * (pn - largest_acked_pn) + 1;
|
||||
if (max_nack_pkts > 0xffffff)
|
||||
return 4;
|
||||
if (max_nack_pkts > 0xffff)
|
||||
return 3;
|
||||
if (max_nack_pkts > 0xff)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Encode <pn> packet number with <pn_len> as length in byte into a buffer with
|
||||
* <buf> as current copy address and <end> as pointer to one past the end of
|
||||
* this buffer. This is the responsibility of the caller to check there is
|
||||
* enough room in the buffer to copy <pn_len> bytes.
|
||||
* Never fails.
|
||||
*/
|
||||
static inline int quic_packet_number_encode(unsigned char **buf,
|
||||
const unsigned char *end,
|
||||
uint64_t pn, size_t pn_len)
|
||||
{
|
||||
if (end - *buf < pn_len)
|
||||
return 0;
|
||||
|
||||
/* Encode the packet number. */
|
||||
switch (pn_len) {
|
||||
case 1:
|
||||
**buf = pn;
|
||||
break;
|
||||
case 2:
|
||||
write_n16(*buf, pn);
|
||||
break;
|
||||
case 3:
|
||||
(*buf)[0] = pn >> 16;
|
||||
(*buf)[1] = pn >> 8;
|
||||
(*buf)[2] = pn;
|
||||
break;
|
||||
case 4:
|
||||
write_n32(*buf, pn);
|
||||
break;
|
||||
}
|
||||
*buf += pn_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function builds into a buffer at <pos> position a QUIC long packet header,
|
||||
* <end> being one byte past the end of this buffer.
|
||||
* Return 1 if enough room to build this header, 0 if not.
|
||||
@ -2186,6 +2389,15 @@ static void qc_build_cc_frm(struct quic_conn *qc, struct quic_enc_level *qel,
|
||||
|
||||
}
|
||||
|
||||
/* Returns the <ack_delay> field value in microsecond to be set in an ACK frame
|
||||
* depending on the time the packet with a new largest packet number was received.
|
||||
*/
|
||||
static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received,
|
||||
struct quic_conn *conn)
|
||||
{
|
||||
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
|
||||
}
|
||||
|
||||
/* This function builds a clear packet from <pkt> information (its type)
|
||||
* into a buffer with <pos> as position pointer and <qel> as QUIC TLS encryption
|
||||
* level for <conn> QUIC connection and <qel> as QUIC TLS encryption level,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user