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 0 : ulong bufsz ) {
29 0 : *rbuf = (fd_h2_rbuf_t) {
30 0 : .buf0 = (uchar *)buf,
31 0 : .buf1 = (uchar *)buf+bufsz,
32 0 : .lo = (uchar *)buf,
33 0 : .hi = (uchar *)buf,
34 0 : .bufsz = bufsz
35 0 : };
36 0 : return rbuf;
37 0 : }
38 :
39 : /* fd_h2_rbuf_used_sz returns the number of unconsumed bytes in rbuf. */
40 :
41 : FD_FN_PURE static inline ulong
42 0 : fd_h2_rbuf_used_sz( fd_h2_rbuf_t const * rbuf ) {
43 0 : return rbuf->hi_off - rbuf->lo_off;
44 0 : }
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 0 : fd_h2_rbuf_free_sz( fd_h2_rbuf_t const * rbuf ) {
51 0 : long used = (long)fd_h2_rbuf_used_sz( rbuf );
52 0 : return (ulong)fd_long_max( 0L, rbuf->buf1 - rbuf->buf0 - used );
53 0 : }
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 0 : ulong chunk_sz ) {
69 0 : FD_CHECK_CRIT( chunk_sz<=fd_h2_rbuf_free_sz( rbuf ), "out of memory" );
70 0 : uchar * buf0 = rbuf->buf0;
71 0 : uchar * buf1 = rbuf->buf1;
72 0 : uchar * lo = rbuf->lo;
73 0 : uchar * hi = rbuf->hi;
74 0 : rbuf->hi_off += chunk_sz;
75 :
76 0 : if( FD_UNLIKELY( hi+chunk_sz > rbuf->buf1 ) ) {
77 : /* Split copy */
78 0 : 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 0 : ulong part1 = (ulong)( buf1-hi );
83 0 : ulong part2 = (ulong)( chunk_sz-part1 );
84 0 : fd_memcpy( hi, chunk, part1 );
85 0 : fd_memcpy( buf0, (void *)( (ulong)chunk+part1 ), part2 );
86 0 : rbuf->hi = buf0+part2;
87 0 : fd_h2_rbuf_validate_private( rbuf );
88 0 : return;
89 0 : }
90 :
91 : /* One-shot copy */
92 0 : uchar * new_hi = hi+chunk_sz;
93 0 : if( new_hi==buf1 ) new_hi = buf0;
94 0 : fd_memcpy( hi, chunk, chunk_sz );
95 0 : rbuf->hi = new_hi;
96 0 : fd_h2_rbuf_validate_private( rbuf );
97 0 : return;
98 0 : }
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 0 : ulong * split_sz ) {
111 0 : ulong used_sz = fd_h2_rbuf_used_sz( rbuf );
112 0 : uchar * buf0 = rbuf->buf0;
113 0 : uchar * buf1 = rbuf->buf1;
114 0 : uchar * lo = rbuf->lo;
115 0 : uchar * hi = rbuf->hi;
116 0 : uchar * end = lo+used_sz;
117 : /* FIXME make this branchless */
118 0 : if( end<=buf1 ) {
119 0 : *sz = (ulong)( used_sz );
120 0 : *split_sz = 0UL;
121 0 : } else {
122 0 : *sz = (ulong)( buf1 - lo );
123 0 : *split_sz = (ulong)( hi - buf0 );
124 0 : }
125 0 : return lo;
126 0 : }
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 0 : ulong * split_sz ) {
135 0 : ulong free_sz = fd_h2_rbuf_free_sz( rbuf );
136 0 : uchar * buf0 = rbuf->buf0;
137 0 : uchar * buf1 = rbuf->buf1;
138 0 : uchar * lo = rbuf->lo;
139 0 : uchar * hi = rbuf->hi;
140 0 : uchar * end = hi+free_sz;
141 : /* FIXME make this branchless */
142 0 : if( end<=buf1 ) {
143 0 : *sz = (ulong)( free_sz );
144 0 : *split_sz = 0UL;
145 0 : } else {
146 0 : *sz = (ulong)( buf1 - hi );
147 0 : *split_sz = (ulong)( lo - buf0 );
148 0 : }
149 0 : return hi;
150 0 : }
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 0 : ulong n ) {
158 0 : uchar * lo = rbuf->lo;
159 0 : ulong bufsz = rbuf->bufsz;
160 0 : uchar * buf1 = rbuf->buf1;
161 0 : rbuf->lo_off += n;
162 0 : lo += n;
163 0 : if( FD_UNLIKELY( lo>=buf1 ) ) {
164 0 : lo -= bufsz;
165 0 : }
166 0 : rbuf->lo = lo;
167 0 : fd_h2_rbuf_validate_private( rbuf );
168 0 : }
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 0 : ulong n ) {
175 0 : uchar * hi = rbuf->hi;
176 0 : ulong bufsz = rbuf->bufsz;
177 0 : uchar * buf1 = rbuf->buf1;
178 0 : rbuf->hi_off += n;
179 0 : hi += n;
180 0 : if( FD_UNLIKELY( hi>=buf1 ) ) {
181 0 : hi -= bufsz;
182 0 : }
183 0 : rbuf->hi = hi;
184 0 : fd_h2_rbuf_validate_private( rbuf );
185 0 : }
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 0 : ulong n ) {
199 0 : FD_CHECK_CRIT( n<=fd_h2_rbuf_used_sz( rbuf ), "invariant violation" );
200 0 : uchar * lo = rbuf->lo;
201 0 : uchar * buf0 = rbuf->buf0;
202 0 : uchar * buf1 = rbuf->buf1;
203 0 : ulong bufsz = rbuf->bufsz;
204 0 : uchar * ret = lo;
205 0 : rbuf->lo_off += n;
206 0 : uchar * end = lo+n;
207 0 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
208 0 : end -= bufsz;
209 0 : }
210 0 : 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 0 : rbuf->lo = end;
218 0 : fd_h2_rbuf_validate_private( rbuf );
219 0 : return ret;
220 0 : }
221 :
222 : static inline void
223 : fd_h2_rbuf_pop_copy( fd_h2_rbuf_t * rbuf,
224 : void * out,
225 0 : ulong n ) {
226 0 : FD_CHECK_CRIT( n<=fd_h2_rbuf_used_sz( rbuf ), "invariant violation" );
227 0 : uchar * lo = rbuf->lo;
228 0 : uchar * buf0 = rbuf->buf0;
229 0 : uchar * buf1 = rbuf->buf1;
230 0 : ulong bufsz = rbuf->bufsz;
231 0 : rbuf->lo_off += n;
232 0 : uchar * end = lo+n;
233 0 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
234 0 : end -= bufsz;
235 0 : }
236 0 : 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 0 : } else {
242 0 : fd_memcpy( out, lo, n );
243 0 : }
244 0 : rbuf->lo = end;
245 0 : fd_h2_rbuf_validate_private( rbuf );
246 0 : }
247 :
248 : FD_FN_PURE static inline int
249 0 : fd_h2_rbuf_is_empty( fd_h2_rbuf_t const * rbuf ) {
250 0 : return rbuf->lo_off==rbuf->hi_off;
251 0 : }
252 :
253 : static void
254 0 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf ) {
255 0 : ulong used = fd_h2_rbuf_used_sz( rbuf );
256 0 : ulong free = fd_h2_rbuf_free_sz( rbuf );
257 0 : FD_DCHECK_CRIT( used <= rbuf->bufsz, "corrupt h2_rbuf" );
258 0 : FD_DCHECK_CRIT( free <= rbuf->bufsz, "corrupt h2_rbuf" );
259 0 : FD_DCHECK_CRIT( used + free == rbuf->bufsz, "corrupt h2_rbuf" );
260 :
261 0 : ulong used0, used1;
262 0 : uchar * used_p = fd_h2_rbuf_peek_used( rbuf, &used0, &used1 );
263 0 : FD_DCHECK_CRIT( used_p == rbuf->lo, "corrupt h2_rbuf" );
264 0 : FD_DCHECK_CRIT( used0 + used1 == used, "corrupt h2_rbuf" );
265 :
266 0 : ulong free0, free1;
267 0 : uchar * free_p = fd_h2_rbuf_peek_free( rbuf, &free0, &free1 );
268 0 : FD_DCHECK_CRIT( free_p == rbuf->hi, "corrupt h2_rbuf" );
269 0 : FD_DCHECK_CRIT( free0 + free1 == free, "corrupt h2_rbuf" );
270 0 : }
271 :
272 : FD_PROTOTYPES_END
273 :
274 : #endif /* HEADER_fd_src_waltz_h2_fd_h2_rbuf_h */
|