]>
git.ipfire.org Git - thirdparty/openssl.git/blob - include/internal/ring_buf.h
69b8df2aa83cdb5c96b57664cf7d741a93e0056d
2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #ifndef OSSL_INTERNAL_RING_BUF_H
11 # define OSSL_INTERNAL_RING_BUF_H
14 # include <openssl/e_os2.h> /* For 'ossl_inline' */
17 * ==================================================================
18 * Byte-wise ring buffer which supports pushing and popping blocks of multiple
19 * bytes at a time. The logical offset of each byte for the purposes of a QUIC
20 * stream is tracked. Bytes can be popped from the ring buffer in two stages;
21 * first they are popped, and then they are culled. Bytes which have been popped
22 * but not yet culled will not be overwritten, and can be restored.
26 size_t alloc
; /* size of buffer allocation in bytes */
29 * Logical offset of the head (where we append to). This is the current size
30 * of the QUIC stream. This increases monotonically.
35 * Logical offset of the cull tail. Data is no longer needed and is
36 * deallocated as the cull tail advances, which occurs as data is
37 * acknowledged. This increases monotonically.
39 uint64_t ctail_offset
;
42 static ossl_inline
int ring_buf_init(struct ring_buf
*r
)
46 r
->head_offset
= r
->ctail_offset
= 0;
50 static ossl_inline
void ring_buf_destroy(struct ring_buf
*r
)
52 OPENSSL_free(r
->start
);
57 static ossl_inline
size_t ring_buf_used(struct ring_buf
*r
)
59 return (size_t)(r
->head_offset
- r
->ctail_offset
);
62 static ossl_inline
size_t ring_buf_avail(struct ring_buf
*r
)
64 return r
->alloc
- ring_buf_used(r
);
67 static ossl_inline
int ring_buf_write_at(struct ring_buf
*r
,
68 uint64_t logical_offset
,
69 const unsigned char *buf
,
73 unsigned char *start
= r
->start
;
76 avail
= ring_buf_avail(r
);
77 if (logical_offset
< r
->ctail_offset
78 || logical_offset
+ buf_len
> r
->head_offset
+ avail
)
81 for (i
= 0; buf_len
> 0 && i
< 2; ++i
) {
82 idx
= logical_offset
% r
->alloc
;
87 memcpy(start
+ idx
, buf
, l
);
88 if (r
->head_offset
< logical_offset
+ l
)
89 r
->head_offset
= logical_offset
+ l
;
101 static ossl_inline
size_t ring_buf_push(struct ring_buf
*r
,
102 const unsigned char *buf
,
105 size_t pushed
= 0, avail
, idx
, l
;
106 unsigned char *start
= r
->start
;
109 avail
= ring_buf_avail(r
);
116 idx
= r
->head_offset
% r
->alloc
;
121 memcpy(start
+ idx
, buf
, l
);
131 static ossl_inline
const unsigned char *ring_buf_get_ptr(const struct ring_buf
*r
,
132 uint64_t logical_offset
,
135 unsigned char *start
= r
->start
;
138 if (logical_offset
>= r
->head_offset
|| logical_offset
< r
->ctail_offset
)
140 idx
= logical_offset
% r
->alloc
;
141 *max_len
= r
->alloc
- idx
;
146 * Retrieves data out of the read side of the ring buffer starting at the given
147 * logical offset. *buf is set to point to a contiguous span of bytes and
148 * *buf_len is set to the number of contiguous bytes. After this function
149 * returns, there may or may not be more bytes available at the logical offset
150 * of (logical_offset + *buf_len) by calling this function again. If the logical
151 * offset is out of the range retained by the ring buffer, returns 0, else
152 * returns 1. A logical offset at the end of the range retained by the ring
153 * buffer is not considered an error and is returned with a *buf_len of 0.
155 * The ring buffer state is not changed.
157 static ossl_inline
int ring_buf_get_buf_at(const struct ring_buf
*r
,
158 uint64_t logical_offset
,
159 const unsigned char **buf
,
162 const unsigned char *start
= r
->start
;
165 if (logical_offset
> r
->head_offset
|| logical_offset
< r
->ctail_offset
)
174 idx
= logical_offset
% r
->alloc
;
175 l
= (size_t)(r
->head_offset
- logical_offset
);
176 if (l
> r
->alloc
- idx
)
184 static ossl_inline
void ring_buf_cpop_range(struct ring_buf
*r
,
185 uint64_t start
, uint64_t end
,
188 assert(end
>= start
);
190 if (start
> r
->ctail_offset
)
193 if (cleanse
&& r
->alloc
> 0 && end
> r
->ctail_offset
) {
194 size_t idx
= r
->ctail_offset
% r
->alloc
;
195 uint64_t cleanse_end
= end
+ 1;
198 if (cleanse_end
> r
->head_offset
)
199 cleanse_end
= r
->head_offset
;
200 l
= (size_t)(cleanse_end
- r
->ctail_offset
);
201 if (l
> r
->alloc
- idx
) {
202 OPENSSL_cleanse((unsigned char *)r
->start
+ idx
, r
->alloc
- idx
);
207 OPENSSL_cleanse((unsigned char *)r
->start
+ idx
, l
);
210 r
->ctail_offset
= end
+ 1;
211 /* Allow culling unpushed data */
212 if (r
->head_offset
< r
->ctail_offset
)
213 r
->head_offset
= r
->ctail_offset
;
216 static ossl_inline
int ring_buf_resize(struct ring_buf
*r
, size_t num_bytes
)
218 struct ring_buf rnew
= {0};
219 const unsigned char *src
= NULL
;
220 size_t src_len
= 0, copied
= 0;
222 if (num_bytes
== r
->alloc
)
225 if (num_bytes
< ring_buf_used(r
))
228 rnew
.start
= OPENSSL_malloc(num_bytes
);
229 if (rnew
.start
== NULL
)
232 rnew
.alloc
= num_bytes
;
233 rnew
.head_offset
= r
->head_offset
- ring_buf_used(r
);
234 rnew
.ctail_offset
= rnew
.head_offset
;
237 if (!ring_buf_get_buf_at(r
, r
->ctail_offset
+ copied
, &src
, &src_len
)) {
238 OPENSSL_free(rnew
.start
);
245 if (ring_buf_push(&rnew
, src
, src_len
) != src_len
) {
246 OPENSSL_free(rnew
.start
);
253 assert(rnew
.head_offset
== r
->head_offset
);
254 rnew
.ctail_offset
= r
->ctail_offset
;
256 OPENSSL_free(r
->start
);
257 memcpy(r
, &rnew
, sizeof(*r
));
261 #endif /* OSSL_INTERNAL_RING_BUF_H */