Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the QUIC_RSTREAM implementation #19794

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 85 additions & 0 deletions include/internal/quic_sf_list.h
Expand Up @@ -47,18 +47,103 @@ typedef struct sframe_list_st {
size_t num_frames;
/* Offset of data not yet dropped */
uint64_t offset;
/* Is head locked ? */
int head_locked;
} SFRAME_LIST;

/*
* Initializes the stream frame list fl.
*/
void ossl_sframe_list_init(SFRAME_LIST *fl);

/*
* Destroys the stream frame list fl releasing any data
* still present inside it.
*/
void ossl_sframe_list_destroy(SFRAME_LIST *fl);

/*
* Insert a stream frame data into the list.
* The data covers an offset range range (start is inclusive,
mattcaswell marked this conversation as resolved.
Show resolved Hide resolved
* end is exclusive).
* fin should be set if this is the final frame of the stream.
* Returns an error if a frame cannot be inserted - due to
* STREAM_FRAME allocation error, or in case of erroneous
* fin flag (this is an ossl_assert() check so a caller must
* check it on its own too).
*/
int ossl_sframe_list_insert(SFRAME_LIST *fl, UINT_RANGE *range,
OSSL_QRX_PKT *pkt,
const unsigned char *data, int fin);

/*
* Iterator to peek at the contiguous frames at the beginning
* of the frame list fl.
* The *data covers an offset range range (start is inclusive,
mattcaswell marked this conversation as resolved.
Show resolved Hide resolved
* end is exclusive).
* *fin is set if this is the final frame of the stream.
* Opaque iterator *iter can be used to peek at the subsequent
* frame if there is any without any gap before it.
* Returns 1 on success.
* Returns 0 if there is no further contiguous frame. In that
* case *fin is set, if the end of the stream is reached.
*/
int ossl_sframe_list_peek(const SFRAME_LIST *fl, void **iter,
UINT_RANGE *range, const unsigned char **data,
int *fin);

/*
* Drop all frames up to the offset limit.
* Also unlocks the head frame if locked.
* Returns 1 on success.
* Returns 0 when trying to drop frames at offsets that were not
* received yet. (ossl_assert() is used to check, so this is an invalid call.)
*/
int ossl_sframe_list_drop_frames(SFRAME_LIST *fl, uint64_t limit);

/*
* Locks and returns the head frame of fl if it is readable - read offset is
* at the beginning or middle of the frame.
* range is set to encompass the not yet read part of the head frame,
* data pointer is set to appropriate offset within the frame if the read
* offset points in the middle of the frame,
* fin is set to 1 if the head frame is also the tail frame.
* Returns 1 on success, 0 if there is no readable data or the head
* frame is already locked.
*/
int ossl_sframe_list_lock_head(SFRAME_LIST *fl, UINT_RANGE *range,
const unsigned char **data,
int *fin);

/*
* Just returns whether the head frame is locked by previous
* ossl_sframe_list_lock_head() call.
*/
int ossl_sframe_list_is_head_locked(SFRAME_LIST *fl);

/*
* Callback function type to write stream frame data to some
* side storage before the packet containing the frame data
* is released.
* It should return 1 on success or 0 if there is not enough
* space available in the side storage.
*/
typedef int (sframe_list_write_at_cb)(uint64_t logical_offset,
const unsigned char *buf,
size_t buf_len,
void *cb_arg);

/*
* Move the frame data in all the stream frames in the list fl
* from the packets to the side storage using the write_at_cb
* callback.
* Returns 1 if all the calls to the callback return 1.
* If the callback returns 0, the function stops processing further
* frames and returns 0.
*/
int ossl_sframe_list_move_data(SFRAME_LIST *fl,
sframe_list_write_at_cb *write_at_cb,
void *cb_arg);
# endif

#endif
52 changes: 51 additions & 1 deletion include/internal/quic_stream.h
Expand Up @@ -302,9 +302,11 @@ typedef struct quic_rstream_st QUIC_RSTREAM;
* controller and statistics module. They can be NULL for unit testing.
* If they are non-NULL, the `rxfc` is called when receive stream data
* is read by application. `statm` is queried for current rtt.
* `rbuf_size` is the initial size of the ring buffer to be used
* when ossl_quic_rstream_move_to_rbuf() is called.
*/
QUIC_RSTREAM *ossl_quic_rstream_new(QUIC_RXFC *rxfc,
OSSL_STATM *statm);
OSSL_STATM *statm, size_t rbuf_size);

/*
* Frees a QUIC_RSTREAM and any associated storage.
Expand Down Expand Up @@ -351,6 +353,54 @@ int ossl_quic_rstream_peek(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
*/
int ossl_quic_rstream_available(QUIC_RSTREAM *qrs, size_t *avail, int *fin);

/*
* Sets *record to the beginning of the first readable stream data chunk and
* *reclen to the size of the chunk. *fin is set to 1 if the end of the
* chunk is the last of the stream data chunks.
* If there is no record available *record is set to NULL and *rec_len to 0.
* Returns 1 on success (including calls after end of the stream - in that
* case *fin will be set to 1 and *rec_len to 0), 0 on error or if no
* readable stream data chunk is available.
* It is an error to call ossl_quic_rstream_get_record() multiple times
* without calling ossl_quic_rstream_release_record() in between.
*/
int ossl_quic_rstream_get_record(QUIC_RSTREAM *qrs,
const unsigned char **record, size_t *rec_len,
int *fin);

/*
* Releases (possibly partially) the record returned by
* previous ossl_quic_rstream_get_record() call.
* read_len between previously returned *rec_len and SIZE_MAX indicates
* release of the whole record. Otherwise only part of the record is
* released. The remaining part of the record is unlocked, another
* call to ossl_quic_rstream_get_record() is needed to obtain further
* stream data.
* Returns 1 on success, 0 on error.
* It is an error to call ossl_quic_rstream_release_record() multiple
* times without calling ossl_quic_rstream_get_record() in between.
*/
int ossl_quic_rstream_release_record(QUIC_RSTREAM *qrs, size_t read_len);

/*
* Moves received frame data from decrypted packets to ring buffer.
* This should be called when there are too many decrypted packets allocated.
* Returns 1 on success, 0 when it was not possible to release all
* referenced packets due to an insufficient size of the ring buffer.
* Exception is the packet from the record returned previously by
* ossl_quic_rstream_get_record() - that one will be always skipped.
*/
int ossl_quic_rstream_move_to_rbuf(QUIC_RSTREAM *qrs);

/*
* Resizes the internal ring buffer to a new `rbuf_size` size.
* Returns 1 on success, 0 on error.
* Possible error conditions are an allocation failure, trying to resize
* the ring buffer when ossl_quic_rstream_get_record() was called and
* not yet released, or trying to resize the ring buffer to a smaller size
* than currently occupied.
*/
int ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM *qrs, size_t rbuf_size);
# endif

#endif