Line data Source code
1 : #ifndef HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
2 : #define HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
3 :
4 : /* fd_h2_rbuf.h provides a byte oriented unaligend ring buffer. */
5 :
6 : #include "fd_h2_base.h"
7 : #include "../../util/log/fd_log.h"
8 :
9 : struct fd_h2_rbuf {
10 : uchar * buf0; /* points to first byte of buffer */
11 : uchar * buf1; /* points one past last byte of buffer */
12 : uchar * lo; /* in [buf0,buf1) */
13 : uchar * hi; /* in [buf0,buf1) */
14 : ulong lo_off;
15 : ulong hi_off;
16 : ulong bufsz;
17 : };
18 :
19 : FD_PROTOTYPES_BEGIN
20 :
21 : /* fd_h2_rbuf_init initializes an h2_rbuf backed by the given buffer.
22 : On return, h2_rbuf has a read-write interested in buf. bufsz has no
23 : alignment requirements. */
24 :
25 : static inline fd_h2_rbuf_t *
26 : fd_h2_rbuf_init( fd_h2_rbuf_t * rbuf,
27 : void * buf,
28 192 : ulong bufsz ) {
29 192 : *rbuf = (fd_h2_rbuf_t) {
30 192 : .buf0 = (uchar *)buf,
31 192 : .buf1 = (uchar *)buf+bufsz,
32 192 : .lo = (uchar *)buf,
33 192 : .hi = (uchar *)buf,
34 192 : .bufsz = bufsz
35 192 : };
36 192 : return rbuf;
37 192 : }
38 :
39 : /* fd_h2_rbuf_used_sz returns the number of unconsumed bytes in rbuf. */
40 :
41 : FD_FN_PURE static inline ulong
42 1812 : fd_h2_rbuf_used_sz( fd_h2_rbuf_t const * rbuf ) {
43 1812 : return rbuf->hi_off - rbuf->lo_off;
44 1812 : }
45 :
46 : /* fd_h2_rbuf_free_sz returns the number of bytes that can be appended
47 : using fd_h2_rbuf_push. */
48 :
49 : FD_FN_PURE static inline ulong
50 951 : fd_h2_rbuf_free_sz( fd_h2_rbuf_t const * rbuf ) {
51 951 : long used = (long)fd_h2_rbuf_used_sz( rbuf );
52 951 : return (ulong)fd_long_max( 0L, rbuf->buf1 - rbuf->buf0 - used );
53 951 : }
54 :
55 : /* fd_h2_rbuf_validate_private validates invariants of rbuf. */
56 : static void
57 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf );
58 :
59 : /* fd_h2_rbuf_push appends a series of newly received bytes into rbuf.
60 : Returns chunk_sz.
61 :
62 : WARNING: The caller must not pass a chunk_sz larger than
63 : fd_h2_rbuf_free_sz bytes. */
64 :
65 : static inline void
66 : fd_h2_rbuf_push( fd_h2_rbuf_t * rbuf,
67 : void const * chunk,
68 162 : ulong chunk_sz ) {
69 162 : FD_CHECK_CRIT( chunk_sz<=fd_h2_rbuf_free_sz( rbuf ), "out of memory" );
70 162 : uchar * buf0 = rbuf->buf0;
71 162 : uchar * buf1 = rbuf->buf1;
72 162 : uchar * lo = rbuf->lo;
73 162 : uchar * hi = rbuf->hi;
74 162 : rbuf->hi_off += chunk_sz;
75 :
76 162 : if( FD_UNLIKELY( hi+chunk_sz > rbuf->buf1 ) ) {
77 : /* Split copy */
78 3 : if( FD_UNLIKELY( lo>hi ) ) {
79 0 : FD_LOG_CRIT(( "rbuf overflow: buf_sz=%lu lo=%ld hi=%ld chunk_sz=%lu",
80 0 : rbuf->bufsz, rbuf->lo-buf0, rbuf->hi-buf0, chunk_sz ));
81 0 : }
82 3 : ulong part1 = (ulong)( buf1-hi );
83 3 : ulong part2 = (ulong)( chunk_sz-part1 );
84 3 : fd_memcpy( hi, chunk, part1 );
85 3 : fd_memcpy( buf0, (void *)( (ulong)chunk+part1 ), part2 );
86 3 : rbuf->hi = buf0+part2;
87 3 : fd_h2_rbuf_validate_private( rbuf );
88 3 : return;
89 3 : }
90 :
91 : /* One-shot copy */
92 159 : uchar * new_hi = hi+chunk_sz;
93 159 : if( new_hi==buf1 ) new_hi = buf0;
94 159 : fd_memcpy( hi, chunk, chunk_sz );
95 159 : rbuf->hi = new_hi;
96 159 : fd_h2_rbuf_validate_private( rbuf );
97 159 : return;
98 162 : }
99 :
100 : /* fd_h2_rbuf_peek_used returns a pointer to the first contiguous
101 : fragment of unconsumed data. *sz is set to the number of contiguous
102 : bytes starting at rbuf->lo. *split_sz is set to the number of bytes
103 : that are unconsumed, but in a separate fragment. The caller may
104 : mangle bytes in [retval,retval+sz) if it consumes these bytes
105 : immediately afterwards. */
106 :
107 : static inline uchar *
108 : fd_h2_rbuf_peek_used( fd_h2_rbuf_t * rbuf,
109 : ulong * sz,
110 291 : ulong * split_sz ) {
111 291 : ulong used_sz = fd_h2_rbuf_used_sz( rbuf );
112 291 : uchar * buf0 = rbuf->buf0;
113 291 : uchar * buf1 = rbuf->buf1;
114 291 : uchar * lo = rbuf->lo;
115 291 : uchar * hi = rbuf->hi;
116 291 : uchar * end = lo+used_sz;
117 : /* FIXME make this branchless */
118 291 : if( end<=buf1 ) {
119 273 : *sz = (ulong)( used_sz );
120 273 : *split_sz = 0UL;
121 273 : } else {
122 18 : *sz = (ulong)( buf1 - lo );
123 18 : *split_sz = (ulong)( hi - buf0 );
124 18 : }
125 291 : return lo;
126 291 : }
127 :
128 : /* fd_h2_rbuf_peek_free is like fd_h2_rbuf_peek_used, but refers to the
129 : free region. */
130 :
131 : static inline uchar *
132 : fd_h2_rbuf_peek_free( fd_h2_rbuf_t * rbuf,
133 : ulong * sz,
134 276 : ulong * split_sz ) {
135 276 : ulong free_sz = fd_h2_rbuf_free_sz( rbuf );
136 276 : uchar * buf0 = rbuf->buf0;
137 276 : uchar * buf1 = rbuf->buf1;
138 276 : uchar * lo = rbuf->lo;
139 276 : uchar * hi = rbuf->hi;
140 276 : uchar * end = hi+free_sz;
141 : /* FIXME make this branchless */
142 276 : if( end<=buf1 ) {
143 159 : *sz = (ulong)( free_sz );
144 159 : *split_sz = 0UL;
145 159 : } else {
146 117 : *sz = (ulong)( buf1 - hi );
147 117 : *split_sz = (ulong)( lo - buf0 );
148 117 : }
149 276 : return hi;
150 276 : }
151 :
152 : /* fd_h2_rbuf_skip frees n bytes from rbuf. Freeing more bytes than
153 : returned by fd_h2_rbuf_used_sz corrupts the buffer state. */
154 :
155 : static inline void
156 : fd_h2_rbuf_skip( fd_h2_rbuf_t * rbuf,
157 33 : ulong n ) {
158 33 : uchar * lo = rbuf->lo;
159 33 : ulong bufsz = rbuf->bufsz;
160 33 : uchar * buf1 = rbuf->buf1;
161 33 : rbuf->lo_off += n;
162 33 : lo += n;
163 33 : if( FD_UNLIKELY( lo>=buf1 ) ) {
164 3 : lo -= bufsz;
165 3 : }
166 33 : rbuf->lo = lo;
167 33 : fd_h2_rbuf_validate_private( rbuf );
168 33 : }
169 :
170 : /* fd_h2_rbuf_alloc marks the next n free bytes as used. */
171 :
172 : static inline void
173 : fd_h2_rbuf_alloc( fd_h2_rbuf_t * rbuf,
174 3 : ulong n ) {
175 3 : uchar * hi = rbuf->hi;
176 3 : ulong bufsz = rbuf->bufsz;
177 3 : uchar * buf1 = rbuf->buf1;
178 3 : rbuf->hi_off += n;
179 3 : hi += n;
180 3 : if( FD_UNLIKELY( hi>=buf1 ) ) {
181 0 : hi -= bufsz;
182 0 : }
183 3 : rbuf->hi = hi;
184 3 : fd_h2_rbuf_validate_private( rbuf );
185 3 : }
186 :
187 : /* fd_h2_rbuf_pop consumes n bytes from rbuf. n is the number of bytes
188 : to consume. n is assumed to be <= fd_h2_rbuf_used(rbuf). scratch
189 : points to scratch memory with space for n bytes.
190 :
191 : If the bytes are available contiguously in rbuf, returns a pointer to
192 : them. Otherwise, the bytes are copied into scratch. The returned
193 : pointer is valid until the next mutating rbuf operation. */
194 :
195 : static inline uchar *
196 : fd_h2_rbuf_pop( fd_h2_rbuf_t * rbuf,
197 : uchar * scratch,
198 9 : ulong n ) {
199 9 : FD_CHECK_CRIT( n<=fd_h2_rbuf_used_sz( rbuf ), "invariant violation" );
200 9 : uchar * lo = rbuf->lo;
201 9 : uchar * buf0 = rbuf->buf0;
202 9 : uchar * buf1 = rbuf->buf1;
203 9 : ulong bufsz = rbuf->bufsz;
204 9 : uchar * ret = lo;
205 9 : rbuf->lo_off += n;
206 9 : uchar * end = lo+n;
207 9 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
208 0 : end -= bufsz;
209 0 : }
210 9 : if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
211 0 : ulong part0 = (ulong)( buf1-lo );
212 0 : ulong part1 = n-part0;
213 0 : fd_memcpy( scratch, lo, part0 );
214 0 : fd_memcpy( scratch+part0, buf0, part1 );
215 0 : ret = scratch;
216 0 : }
217 9 : rbuf->lo = end;
218 9 : fd_h2_rbuf_validate_private( rbuf );
219 9 : return ret;
220 9 : }
221 :
222 : static inline void
223 : fd_h2_rbuf_pop_copy( fd_h2_rbuf_t * rbuf,
224 : void * out,
225 69 : ulong n ) {
226 69 : FD_CHECK_CRIT( n<=fd_h2_rbuf_used_sz( rbuf ), "invariant violation" );
227 69 : uchar * lo = rbuf->lo;
228 69 : uchar * buf0 = rbuf->buf0;
229 69 : uchar * buf1 = rbuf->buf1;
230 69 : ulong bufsz = rbuf->bufsz;
231 69 : rbuf->lo_off += n;
232 69 : uchar * end = lo+n;
233 69 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
234 0 : end -= bufsz;
235 0 : }
236 69 : if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
237 0 : ulong part0 = (ulong)( buf1-lo );
238 0 : ulong part1 = n-part0;
239 0 : fd_memcpy( out, lo, part0 );
240 0 : fd_memcpy( (void *)( (ulong)out+part0 ), buf0, part1 );
241 69 : } else {
242 69 : fd_memcpy( out, lo, n );
243 69 : }
244 69 : rbuf->lo = end;
245 69 : fd_h2_rbuf_validate_private( rbuf );
246 69 : }
247 :
248 : FD_FN_PURE static inline int
249 114 : fd_h2_rbuf_is_empty( fd_h2_rbuf_t const * rbuf ) {
250 114 : return rbuf->lo_off==rbuf->hi_off;
251 114 : }
252 :
253 : static void
254 276 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf ) {
255 276 : ulong used = fd_h2_rbuf_used_sz( rbuf );
256 276 : ulong free = fd_h2_rbuf_free_sz( rbuf );
257 276 : FD_DCHECK_CRIT( used <= rbuf->bufsz, "corrupt h2_rbuf" );
258 276 : FD_DCHECK_CRIT( free <= rbuf->bufsz, "corrupt h2_rbuf" );
259 276 : FD_DCHECK_CRIT( used + free == rbuf->bufsz, "corrupt h2_rbuf" );
260 :
261 276 : ulong used0, used1;
262 276 : uchar * used_p = fd_h2_rbuf_peek_used( rbuf, &used0, &used1 );
263 276 : FD_DCHECK_CRIT( used_p == rbuf->lo, "corrupt h2_rbuf" );
264 276 : FD_DCHECK_CRIT( used0 + used1 == used, "corrupt h2_rbuf" );
265 :
266 276 : ulong free0, free1;
267 276 : uchar * free_p = fd_h2_rbuf_peek_free( rbuf, &free0, &free1 );
268 276 : FD_DCHECK_CRIT( free_p == rbuf->hi, "corrupt h2_rbuf" );
269 276 : FD_DCHECK_CRIT( free0 + free1 == free, "corrupt h2_rbuf" );
270 276 : }
271 :
272 : FD_PROTOTYPES_END
273 :
274 : #endif /* HEADER_fd_src_waltz_h2_fd_h2_rbuf_h */
|