Path: blob/main/crypto/openssl/ssl/quic/quic_sf_list.c
48262 views
/*1* Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include "internal/uint_set.h"10#include "internal/common.h"11#include "internal/quic_sf_list.h"1213struct stream_frame_st {14struct stream_frame_st *prev, *next;15UINT_RANGE range;16OSSL_QRX_PKT *pkt;17const unsigned char *data;18};1920static void stream_frame_free(SFRAME_LIST *fl, STREAM_FRAME *sf)21{22if (fl->cleanse && sf->data != NULL)23OPENSSL_cleanse((unsigned char *)sf->data,24(size_t)(sf->range.end - sf->range.start));25ossl_qrx_pkt_release(sf->pkt);26OPENSSL_free(sf);27}2829static STREAM_FRAME *stream_frame_new(UINT_RANGE *range, OSSL_QRX_PKT *pkt,30const unsigned char *data)31{32STREAM_FRAME *sf = OPENSSL_zalloc(sizeof(*sf));3334if (sf == NULL)35return NULL;3637if (pkt != NULL)38ossl_qrx_pkt_up_ref(pkt);3940sf->range = *range;41sf->pkt = pkt;42sf->data = data;4344return sf;45}4647void ossl_sframe_list_init(SFRAME_LIST *fl)48{49memset(fl, 0, sizeof(*fl));50}5152void ossl_sframe_list_destroy(SFRAME_LIST *fl)53{54STREAM_FRAME *sf, *next_frame;5556for (sf = fl->head; sf != NULL; sf = next_frame) {57next_frame = sf->next;58stream_frame_free(fl, sf);59}60}6162static int append_frame(SFRAME_LIST *fl, UINT_RANGE *range,63OSSL_QRX_PKT *pkt,64const unsigned char *data)65{66STREAM_FRAME *new_frame;6768if ((new_frame = stream_frame_new(range, pkt, data)) == NULL)69return 0;70new_frame->prev = fl->tail;71if (fl->tail != NULL)72fl->tail->next = new_frame;73fl->tail = new_frame;74++fl->num_frames;75return 1;76}7778int ossl_sframe_list_insert(SFRAME_LIST *fl, UINT_RANGE *range,79OSSL_QRX_PKT *pkt,80const unsigned char *data, int fin)81{82STREAM_FRAME *sf, *new_frame, *prev_frame, *next_frame;83#ifndef NDEBUG84uint64_t curr_end = fl->tail != NULL ? fl->tail->range.end85: fl->offset;8687/* This check for FINAL_SIZE_ERROR is handled by QUIC FC already */88assert((!fin || curr_end <= range->end)89&& (!fl->fin || curr_end >= range->end));90#endif9192if (fl->offset >= range->end)93goto end;9495/* nothing there yet */96if (fl->tail == NULL) {97fl->tail = fl->head = stream_frame_new(range, pkt, data);98if (fl->tail == NULL)99return 0;100101++fl->num_frames;102goto end;103}104105/* optimize insertion at the end */106if (fl->tail->range.start < range->start) {107if (fl->tail->range.end >= range->end)108goto end;109110if (!append_frame(fl, range, pkt, data))111return 0;112goto end;113}114115prev_frame = NULL;116for (sf = fl->head; sf != NULL && sf->range.start < range->start;117sf = sf->next)118prev_frame = sf;119120if (!ossl_assert(sf != NULL))121/* frame list invariant broken */122return 0;123124if (prev_frame != NULL && prev_frame->range.end >= range->end)125goto end;126127/*128* Now we must create a new frame although in the end we might drop it,129* because we will be potentially dropping existing overlapping frames.130*/131new_frame = stream_frame_new(range, pkt, data);132if (new_frame == NULL)133return 0;134135for (next_frame = sf;136next_frame != NULL && next_frame->range.end <= range->end;) {137STREAM_FRAME *drop_frame = next_frame;138139next_frame = next_frame->next;140if (next_frame != NULL)141next_frame->prev = drop_frame->prev;142if (prev_frame != NULL)143prev_frame->next = drop_frame->next;144if (fl->head == drop_frame)145fl->head = next_frame;146if (fl->tail == drop_frame)147fl->tail = prev_frame;148--fl->num_frames;149stream_frame_free(fl, drop_frame);150}151152if (next_frame != NULL) {153/* check whether the new_frame is redundant because there is no gap */154if (prev_frame != NULL155&& next_frame->range.start <= prev_frame->range.end) {156stream_frame_free(fl, new_frame);157goto end;158}159next_frame->prev = new_frame;160} else {161fl->tail = new_frame;162}163164new_frame->next = next_frame;165new_frame->prev = prev_frame;166167if (prev_frame != NULL)168prev_frame->next = new_frame;169else170fl->head = new_frame;171172++fl->num_frames;173174end:175fl->fin = fin || fl->fin;176177return 1;178}179180int ossl_sframe_list_peek(const SFRAME_LIST *fl, void **iter,181UINT_RANGE *range, const unsigned char **data,182int *fin)183{184STREAM_FRAME *sf = *iter;185uint64_t start;186187if (sf == NULL) {188start = fl->offset;189sf = fl->head;190} else {191start = sf->range.end;192sf = sf->next;193}194195range->start = start;196197if (sf == NULL || sf->range.start > start198|| !ossl_assert(start < sf->range.end)) {199range->end = start;200*data = NULL;201*iter = NULL;202/* set fin only if we are at the end */203*fin = sf == NULL ? fl->fin : 0;204return 0;205}206207range->end = sf->range.end;208if (sf->data != NULL)209*data = sf->data + (start - sf->range.start);210else211*data = NULL;212*fin = sf->next == NULL ? fl->fin : 0;213*iter = sf;214return 1;215}216217int ossl_sframe_list_drop_frames(SFRAME_LIST *fl, uint64_t limit)218{219STREAM_FRAME *sf;220221/* offset cannot move back or past the data received */222if (!ossl_assert(limit >= fl->offset)223|| !ossl_assert(fl->tail == NULL224|| limit <= fl->tail->range.end)225|| !ossl_assert(fl->tail != NULL226|| limit == fl->offset))227return 0;228229fl->offset = limit;230231for (sf = fl->head; sf != NULL && sf->range.end <= limit;) {232STREAM_FRAME *drop_frame = sf;233234sf = sf->next;235--fl->num_frames;236stream_frame_free(fl, drop_frame);237}238fl->head = sf;239240if (sf != NULL)241sf->prev = NULL;242else243fl->tail = NULL;244245fl->head_locked = 0;246247return 1;248}249250int ossl_sframe_list_lock_head(SFRAME_LIST *fl, UINT_RANGE *range,251const unsigned char **data,252int *fin)253{254int ret;255void *iter = NULL;256257if (fl->head_locked)258return 0;259260ret = ossl_sframe_list_peek(fl, &iter, range, data, fin);261if (ret)262fl->head_locked = 1;263return ret;264}265266int ossl_sframe_list_is_head_locked(SFRAME_LIST *fl)267{268return fl->head_locked;269}270271int ossl_sframe_list_move_data(SFRAME_LIST *fl,272sframe_list_write_at_cb *write_at_cb,273void *cb_arg)274{275STREAM_FRAME *sf = fl->head, *prev_frame = NULL;276uint64_t limit = fl->offset;277278if (sf == NULL)279return 1;280281if (fl->head_locked)282sf = sf->next;283284for (; sf != NULL; sf = sf->next) {285size_t len;286const unsigned char *data = sf->data;287288if (limit < sf->range.start)289limit = sf->range.start;290291if (data != NULL) {292if (limit > sf->range.start)293data += (size_t)(limit - sf->range.start);294len = (size_t)(sf->range.end - limit);295296if (!write_at_cb(limit, data, len, cb_arg))297/* data did not fit */298return 0;299300if (fl->cleanse)301OPENSSL_cleanse((unsigned char *)sf->data,302(size_t)(sf->range.end - sf->range.start));303304/* release the packet */305sf->data = NULL;306ossl_qrx_pkt_release(sf->pkt);307sf->pkt = NULL;308}309310limit = sf->range.end;311312/* merge contiguous frames */313if (prev_frame != NULL314&& prev_frame->range.end >= sf->range.start) {315prev_frame->range.end = sf->range.end;316prev_frame->next = sf->next;317318if (sf->next != NULL)319sf->next->prev = prev_frame;320else321fl->tail = prev_frame;322323--fl->num_frames;324stream_frame_free(fl, sf);325sf = prev_frame;326continue;327}328329prev_frame = sf;330}331332return 1;333}334335336