litespeed-quic/src/liblsquic/lsquic_packet_in.h

177 lines
6.6 KiB
C
Raw Normal View History

/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */
2017-09-22 21:00:03 +00:00
/*
* lsquic_packet_in.h
*/
#ifndef LSQUIC_PACKET_IN_H
#define LSQUIC_PACKET_IN_H 1
2017-09-22 21:00:03 +00:00
struct lsquic_packet_in;
struct lsquic_cid;
2017-09-22 21:00:03 +00:00
struct data_frame
{
const unsigned char *df_data; /* Pointer to data */
uint64_t df_offset; /* Stream offset */
uint16_t df_read_off; /* Read offset */
uint16_t df_size; /* Size of df_data */
signed char df_fin; /* FIN? */
};
2017-09-22 21:00:03 +00:00
typedef struct stream_frame
{
/* Stream frames are stored in a list inside "di nocopy" (if "di nocopy"
* is used).
*/
2017-09-22 21:00:03 +00:00
TAILQ_ENTRY(stream_frame) next_frame;
/* `data_frame.df_data' points somewhere into the packet payload. The
* packet object is reference-counted. When the frame is freed, the
* packet is released via lsquic_packet_in_put().
2017-09-22 21:00:03 +00:00
*/
struct lsquic_packet_in *packet_in;
struct data_frame data_frame;
lsquic_stream_id_t stream_id; /* Parsed from packet */
2017-09-22 21:00:03 +00:00
} stream_frame_t;
#define DF_OFF(frame) (frame)->data_frame.df_offset
#define DF_ROFF(frame) (DF_OFF(frame) + (frame)->data_frame.df_read_off)
#define DF_FIN(frame) (frame)->data_frame.df_fin
#define DF_SIZE(frame) (frame)->data_frame.df_size
#define DF_END(frame) (DF_OFF(frame) + DF_SIZE(frame))
2017-09-22 21:00:03 +00:00
typedef struct lsquic_packet_in
{
TAILQ_ENTRY(lsquic_packet_in) pi_next;
lsquic_time_t pi_received; /* Time received */
lsquic_cid_t pi_dcid;
#define pi_conn_id pi_dcid
2017-09-22 21:00:03 +00:00
lsquic_packno_t pi_packno;
enum quic_ft_bit pi_frame_types;
2017-09-22 21:00:03 +00:00
unsigned short pi_header_sz; /* Points to payload */
unsigned short pi_data_sz; /* Data plus header */
/* A packet may be referred to by one or more frames and packets_in
* list.
*/
unsigned short pi_refcnt;
unsigned short pi_hsk_stream; /* Offset to handshake stream
* frame, only valid if
* PI_HSK_STREAM is set.
*/
enum {
PI_DECRYPTED = (1 << 0),
PI_OWN_DATA = (1 << 1), /* We own pi_data */
PI_CONN_ID = (1 << 2), /* pi_conn_id is set */
PI_HSK_STREAM = (1 << 3), /* Has handshake data (mini only) */
PI_FROM_MINI = (1 << 4), /* Handed off by mini connection */
Latest changes - [API Change] Sendfile-like functionality is gone. The stream no longer opens files and deals with file descriptors. (Among other things, this makes the code more portable.) Three writing functions are provided: lsquic_stream_write lsquic_stream_writev lsquic_stream_writef (NEW) lsquic_stream_writef() is given an abstract reader that has function pointers for size() and read() functions which the user can implement. This is the most flexible way. lsquic_stream_write() and lsquic_stream_writev() are now both implemented as wrappers around lsquic_stream_writef(). - [OPTIMIZATION] When writing to stream, be it within or without the on_write() callback, place data directly into packet buffer, bypassing auxiliary data structures. This reduces amount of memory required, for the amount of data that can be written is limited by the congestion window. To support writes outside the on_write() callback, we keep N outgoing packet buffers per connection which can be written to by any stream. One half of these are reserved for the highest priority stream(s), the other half for all other streams. This way, low-priority streams cannot write instead of high-priority streams and, on the other hand, low-priority streams get a chance to send their packets out. The algorithm is as follows: - When user writes to stream outside of the callback: - If this is the highest priority stream, place it onto the reserved N/2 queue or fail. (The actual size of this queue is dynamic -- MAX(N/2, CWND) -- rather than N/2, allowing high-priority streams to write as much as can be sent.) - If the stream is not the highest priority, try to place the data onto the reserved N/2 queue or fail. - When tick occurs *and* more packets can be scheduled: - Transfer packets from the high N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for highest-priority streams, placing resulting packets directly onto the scheduled queue. - If more scheduling is allowed: - Transfer packets from the low N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for non-highest-priority streams, placing resulting packets directly onto the scheduled queue The number N is currently 20, but it could be varied based on resource usage. - If stream is created due to incoming headers, make headers readable from on_new. - Outgoing packets are no longer marked non-writeable to prevent placing more than one STREAM frame from the same stream into a single packet. This property is maintained via code flow and an explicit check. Packets for stream data are allocated using a special function. - STREAM frame elision is cheaper, as we only perform it if a reset stream has outgoing packets referencing it. - lsquic_packet_out_t is smaller, as stream_rec elements are now inside a union.
2017-10-31 13:35:58 +00:00
#define PIBIT_ENC_LEV_SHIFT 5
PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */
PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */
2018-08-15 19:06:31 +00:00
PI_GQUIC = (1 << 7),
PI_UNUSED_8 = (1 << 8), /* <-- hole, reuse me! */
#define PIBIT_ECN_SHIFT 9
PI_ECN_BIT_0 = (1 << 9),
PI_ECN_BIT_1 = (1 <<10),
#define PIBIT_SPIN_SHIFT 11
PI_SPIN_BIT = (1 <<11),
#define PIBIT_BITS_SHIFT 12
PI_BITS_BIT_0 = (1 <<12),
PI_BITS_BIT_1 = (1 <<13),
/* Square bit and loss bit flags are used for logging */
PI_LOG_QL_BITS = (1 <<14),
PI_SQUARE_BIT = (1 <<15),
PI_LOSS_BIT = (1 <<16),
} pi_flags;
/* pi_token and pi_token_size are set in Initial and Retry packets */
unsigned short pi_token_size; /* Size of the token */
unsigned char pi_token; /* Offset to token */
/* pi_odcid and pi_odcid_len are only set in Retry packets for I-D < 25 */
unsigned char pi_odcid; /* Offset to Original DCID */
unsigned char pi_odcid_len; /* Size of ODCID */
unsigned char pi_scid_off; /* Offset to SCID */
unsigned char pi_scid_len; /* Size of SCID */
unsigned char pi_quic_ver; /* Offset to QUIC version */
unsigned char pi_nonce; /* Offset to nonce */
2018-08-15 19:06:31 +00:00
enum header_type pi_header_type:8;
unsigned char pi_path_id;
2017-09-22 21:00:03 +00:00
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
* packet data, which is NOT TO BE MODIFIED.
*/
unsigned char *pi_data;
} lsquic_packet_in_t;
2017-09-22 21:00:03 +00:00
#define lsquic_packet_in_public_flags(p) ((p)->pi_data[0])
2018-08-15 19:06:31 +00:00
#define lsquic_packet_in_is_gquic_prst(p) \
(((p)->pi_flags & PI_GQUIC) \
&& (lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_RST))
#define lsquic_packet_in_is_verneg(p) \
(((p)->pi_flags & PI_GQUIC) ? \
lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_VERSION : \
(p)->pi_header_type == HETY_VERNEG)
2017-09-22 21:00:03 +00:00
#define lsquic_packet_in_packno_bits(p) \
(((p)->pi_flags >> PIBIT_BITS_SHIFT) & 3)
2017-09-22 21:00:03 +00:00
#define lsquic_packet_in_upref(p) (++(p)->pi_refcnt)
#define lsquic_packet_in_get(p) (lsquic_packet_in_upref(p), (p))
#define lsquic_packet_in_nonce(p) \
((p)->pi_nonce ? (p)->pi_data + (p)->pi_nonce : NULL)
Latest changes - [API Change] Sendfile-like functionality is gone. The stream no longer opens files and deals with file descriptors. (Among other things, this makes the code more portable.) Three writing functions are provided: lsquic_stream_write lsquic_stream_writev lsquic_stream_writef (NEW) lsquic_stream_writef() is given an abstract reader that has function pointers for size() and read() functions which the user can implement. This is the most flexible way. lsquic_stream_write() and lsquic_stream_writev() are now both implemented as wrappers around lsquic_stream_writef(). - [OPTIMIZATION] When writing to stream, be it within or without the on_write() callback, place data directly into packet buffer, bypassing auxiliary data structures. This reduces amount of memory required, for the amount of data that can be written is limited by the congestion window. To support writes outside the on_write() callback, we keep N outgoing packet buffers per connection which can be written to by any stream. One half of these are reserved for the highest priority stream(s), the other half for all other streams. This way, low-priority streams cannot write instead of high-priority streams and, on the other hand, low-priority streams get a chance to send their packets out. The algorithm is as follows: - When user writes to stream outside of the callback: - If this is the highest priority stream, place it onto the reserved N/2 queue or fail. (The actual size of this queue is dynamic -- MAX(N/2, CWND) -- rather than N/2, allowing high-priority streams to write as much as can be sent.) - If the stream is not the highest priority, try to place the data onto the reserved N/2 queue or fail. - When tick occurs *and* more packets can be scheduled: - Transfer packets from the high N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for highest-priority streams, placing resulting packets directly onto the scheduled queue. - If more scheduling is allowed: - Transfer packets from the low N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for non-highest-priority streams, placing resulting packets directly onto the scheduled queue The number N is currently 20, but it could be varied based on resource usage. - If stream is created due to incoming headers, make headers readable from on_new. - Outgoing packets are no longer marked non-writeable to prevent placing more than one STREAM frame from the same stream into a single packet. This property is maintained via code flow and an explicit check. Packets for stream data are allocated using a special function. - STREAM frame elision is cheaper, as we only perform it if a reset stream has outgoing packets referencing it. - lsquic_packet_out_t is smaller, as stream_rec elements are now inside a union.
2017-10-31 13:35:58 +00:00
#define lsquic_packet_in_enc_level(p) \
(((p)->pi_flags >> PIBIT_ENC_LEV_SHIFT) & 0x3)
#define lsquic_packet_in_ecn(p) \
(((p)->pi_flags >> PIBIT_ECN_SHIFT) & 0x3)
#define lsquic_packet_in_spin_bit(p) (((p)->pi_flags & PI_SPIN_BIT) > 0)
/* PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID, and PADDING frames
* are "probing frames", and all other frames are "non-probing frames".
* A packet containing only probing frames is a "probing packet", and a
* packet containing any other frame is a "non-probing packet".
*
* [draft-ietf-quic-transport-20], Section 9.1
*/
#define lsquic_packet_in_non_probing(p) \
(!!((p)->pi_frame_types & ~(QUIC_FTBIT_PATH_CHALLENGE \
|QUIC_FTBIT_PATH_RESPONSE|QUIC_FTBIT_PADDING \
|QUIC_FTBIT_NEW_CONNECTION_ID)))
2017-09-22 21:00:03 +00:00
/* The version iterator is used on a version negotiation packet only.
* The iterator functions return 1 when next version is returned and
* 0 when there are no more versions.
*/
struct ver_iter
{
const struct lsquic_packet_in *packet_in;
unsigned off;
};
int
lsquic_packet_in_ver_first (const lsquic_packet_in_t *packet_in,
struct ver_iter *, lsquic_ver_tag_t *ver_tag);
2017-09-22 21:00:03 +00:00
int
lsquic_packet_in_ver_next (struct ver_iter *, lsquic_ver_tag_t *ver_tag);
2017-09-22 21:00:03 +00:00
Latest changes - [API Change] Sendfile-like functionality is gone. The stream no longer opens files and deals with file descriptors. (Among other things, this makes the code more portable.) Three writing functions are provided: lsquic_stream_write lsquic_stream_writev lsquic_stream_writef (NEW) lsquic_stream_writef() is given an abstract reader that has function pointers for size() and read() functions which the user can implement. This is the most flexible way. lsquic_stream_write() and lsquic_stream_writev() are now both implemented as wrappers around lsquic_stream_writef(). - [OPTIMIZATION] When writing to stream, be it within or without the on_write() callback, place data directly into packet buffer, bypassing auxiliary data structures. This reduces amount of memory required, for the amount of data that can be written is limited by the congestion window. To support writes outside the on_write() callback, we keep N outgoing packet buffers per connection which can be written to by any stream. One half of these are reserved for the highest priority stream(s), the other half for all other streams. This way, low-priority streams cannot write instead of high-priority streams and, on the other hand, low-priority streams get a chance to send their packets out. The algorithm is as follows: - When user writes to stream outside of the callback: - If this is the highest priority stream, place it onto the reserved N/2 queue or fail. (The actual size of this queue is dynamic -- MAX(N/2, CWND) -- rather than N/2, allowing high-priority streams to write as much as can be sent.) - If the stream is not the highest priority, try to place the data onto the reserved N/2 queue or fail. - When tick occurs *and* more packets can be scheduled: - Transfer packets from the high N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for highest-priority streams, placing resulting packets directly onto the scheduled queue. - If more scheduling is allowed: - Transfer packets from the low N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for non-highest-priority streams, placing resulting packets directly onto the scheduled queue The number N is currently 20, but it could be varied based on resource usage. - If stream is created due to incoming headers, make headers readable from on_new. - Outgoing packets are no longer marked non-writeable to prevent placing more than one STREAM frame from the same stream into a single packet. This property is maintained via code flow and an explicit check. Packets for stream data are allocated using a special function. - STREAM frame elision is cheaper, as we only perform it if a reset stream has outgoing packets referencing it. - lsquic_packet_out_t is smaller, as stream_rec elements are now inside a union.
2017-10-31 13:35:58 +00:00
size_t
lsquic_packet_in_mem_used (const struct lsquic_packet_in *);
void
lsquic_scid_from_packet_in (const struct lsquic_packet_in *,
struct lsquic_cid *);
2017-09-22 21:00:03 +00:00
#endif