/src/nghttp2/lib/nghttp2_buf.h
Line | Count | Source |
1 | | /* |
2 | | * nghttp2 - HTTP/2 C Library |
3 | | * |
4 | | * Copyright (c) 2014 Tatsuhiro Tsujikawa |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining |
7 | | * a copy of this software and associated documentation files (the |
8 | | * "Software"), to deal in the Software without restriction, including |
9 | | * without limitation the rights to use, copy, modify, merge, publish, |
10 | | * distribute, sublicense, and/or sell copies of the Software, and to |
11 | | * permit persons to whom the Software is furnished to do so, subject to |
12 | | * the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be |
15 | | * included in all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
19 | | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
21 | | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
22 | | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
23 | | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | | */ |
25 | | #ifndef NGHTTP2_BUF_H |
26 | | #define NGHTTP2_BUF_H |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | # include <config.h> |
30 | | #endif /* HAVE_CONFIG_H */ |
31 | | |
32 | | #include <nghttp2/nghttp2.h> |
33 | | |
34 | | #include "nghttp2_int.h" |
35 | | #include "nghttp2_mem.h" |
36 | | |
37 | | typedef struct { |
38 | | /* This points to the beginning of the buffer. The effective range |
39 | | of buffer is [begin, end). */ |
40 | | uint8_t *begin; |
41 | | /* This points to the memory one byte beyond the end of the |
42 | | buffer. */ |
43 | | uint8_t *end; |
44 | | /* The position indicator for effective start of the buffer. pos <= |
45 | | last must be hold. */ |
46 | | uint8_t *pos; |
47 | | /* The position indicator for effective one beyond of the end of the |
48 | | buffer. last <= end must be hold. */ |
49 | | uint8_t *last; |
50 | | /* Mark arbitrary position in buffer [begin, end) */ |
51 | | uint8_t *mark; |
52 | | } nghttp2_buf; |
53 | | |
54 | 189k | #define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos)) |
55 | 397k | #define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last)) |
56 | 102k | #define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last)) |
57 | 18.6k | #define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin)) |
58 | | |
59 | | #define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin)) |
60 | | #define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin)) |
61 | | |
62 | | #define nghttp2_buf_shift_right(BUF, AMT) \ |
63 | 167k | do { \ |
64 | 167k | (BUF)->pos += AMT; \ |
65 | 167k | (BUF)->last += AMT; \ |
66 | 167k | } while (0) |
67 | | |
68 | | #define nghttp2_buf_shift_left(BUF, AMT) \ |
69 | | do { \ |
70 | | (BUF)->pos -= AMT; \ |
71 | | (BUF)->last -= AMT; \ |
72 | | } while (0) |
73 | | |
74 | | /* |
75 | | * Initializes the |buf|. No memory is allocated in this function. Use |
76 | | * nghttp2_buf_reserve() to allocate memory. |
77 | | */ |
78 | | void nghttp2_buf_init(nghttp2_buf *buf); |
79 | | |
80 | | /* |
81 | | * Initializes the |buf| and allocates at least |initial| bytes of |
82 | | * memory. |
83 | | * |
84 | | * This function returns 0 if it succeeds, or one of the following |
85 | | * negative error codes: |
86 | | * |
87 | | * NGHTTP2_ERR_NOMEM |
88 | | * Out of memory |
89 | | */ |
90 | | int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem); |
91 | | |
92 | | /* |
93 | | * Frees buffer in |buf|. |
94 | | */ |
95 | | void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem); |
96 | | |
97 | | /* |
98 | | * Extends buffer so that nghttp2_buf_cap() returns at least |
99 | | * |new_cap|. If extensions took place, buffer pointers in |buf| will |
100 | | * change. |
101 | | * |
102 | | * This function returns 0 if it succeeds, or one of the followings |
103 | | * negative error codes: |
104 | | * |
105 | | * NGHTTP2_ERR_NOMEM |
106 | | * Out of memory |
107 | | */ |
108 | | int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem); |
109 | | |
110 | | /* |
111 | | * Resets pos, last, mark member of |buf| to buf->begin. |
112 | | */ |
113 | | void nghttp2_buf_reset(nghttp2_buf *buf); |
114 | | |
115 | | /* |
116 | | * Initializes |buf| using supplied buffer |begin| of length |
117 | | * |len|. Semantically, the application should not call *_reserve() or |
118 | | * nghttp2_free() functions for |buf|. |
119 | | */ |
120 | | void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len); |
121 | | |
122 | | struct nghttp2_buf_chain; |
123 | | |
124 | | typedef struct nghttp2_buf_chain nghttp2_buf_chain; |
125 | | |
126 | | /* Chains 2 buffers */ |
127 | | struct nghttp2_buf_chain { |
128 | | /* Points to the subsequent buffer. NULL if there is no such |
129 | | buffer. */ |
130 | | nghttp2_buf_chain *next; |
131 | | nghttp2_buf buf; |
132 | | }; |
133 | | |
134 | | typedef struct { |
135 | | /* Points to the first buffer */ |
136 | | nghttp2_buf_chain *head; |
137 | | /* Buffer pointer where write occurs. */ |
138 | | nghttp2_buf_chain *cur; |
139 | | /* Memory allocator */ |
140 | | nghttp2_mem *mem; |
141 | | /* The buffer capacity of each buf. This field may be 0 if |
142 | | nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family |
143 | | functions. */ |
144 | | size_t chunk_length; |
145 | | /* The maximum number of nghttp2_buf_chain */ |
146 | | size_t max_chunk; |
147 | | /* The number of nghttp2_buf_chain allocated */ |
148 | | size_t chunk_used; |
149 | | /* The number of nghttp2_buf_chain to keep on reset */ |
150 | | size_t chunk_keep; |
151 | | /* pos offset from begin in each buffers. On initialization and |
152 | | reset, buf->pos and buf->last are positioned at buf->begin + |
153 | | offset. */ |
154 | | size_t offset; |
155 | | } nghttp2_bufs; |
156 | | |
157 | | /* |
158 | | * This is the same as calling nghttp2_bufs_init2 with the given |
159 | | * arguments and offset = 0. |
160 | | */ |
161 | | int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, |
162 | | nghttp2_mem *mem); |
163 | | |
164 | | /* |
165 | | * This is the same as calling nghttp2_bufs_init3 with the given |
166 | | * arguments and chunk_keep = max_chunk. |
167 | | */ |
168 | | int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, |
169 | | size_t max_chunk, size_t offset, nghttp2_mem *mem); |
170 | | |
171 | | /* |
172 | | * Initializes |bufs|. Each buffer size is given in the |
173 | | * |chunk_length|. The maximum number of buffers is given in the |
174 | | * |max_chunk|. On reset, first |chunk_keep| buffers are kept and |
175 | | * remaining buffers are deleted. Each buffer will have bufs->pos and |
176 | | * bufs->last shifted to left by |offset| bytes on creation and reset. |
177 | | * |
178 | | * This function allocates first buffer. bufs->head and bufs->cur |
179 | | * will point to the first buffer after this call. |
180 | | * |
181 | | * This function returns 0 if it succeeds, or one of the following |
182 | | * negative error codes: |
183 | | * |
184 | | * NGHTTP2_ERR_NOMEM |
185 | | * Out of memory. |
186 | | * NGHTTP2_ERR_INVALID_ARGUMENT |
187 | | * chunk_keep is 0; or max_chunk < chunk_keep; or offset is too |
188 | | * long. |
189 | | */ |
190 | | int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, |
191 | | size_t max_chunk, size_t chunk_keep, size_t offset, |
192 | | nghttp2_mem *mem); |
193 | | |
194 | | /* |
195 | | * Frees any related resources to the |bufs|. |
196 | | */ |
197 | | void nghttp2_bufs_free(nghttp2_bufs *bufs); |
198 | | |
199 | | /* |
200 | | * Initializes |bufs| using supplied buffer |begin| of length |len|. |
201 | | * The first buffer bufs->head uses buffer |begin|. The buffer size |
202 | | * is fixed and no extra chunk buffer is allocated. In other |
203 | | * words, max_chunk = chunk_keep = 1. To free the resource allocated |
204 | | * for |bufs|, use nghttp2_bufs_wrap_free(). |
205 | | * |
206 | | * Don't use the function which performs allocation, such as |
207 | | * nghttp2_bufs_realloc(). |
208 | | * |
209 | | * This function returns 0 if it succeeds, or one of the following |
210 | | * negative error codes: |
211 | | * |
212 | | * NGHTTP2_ERR_NOMEM |
213 | | * Out of memory. |
214 | | */ |
215 | | int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len, |
216 | | nghttp2_mem *mem); |
217 | | |
218 | | /* |
219 | | * Initializes |bufs| using supplied |veclen| size of buf vector |
220 | | * |vec|. The number of buffers is fixed and no extra chunk buffer is |
221 | | * allocated. In other words, max_chunk = chunk_keep = |in_len|. To |
222 | | * free the resource allocated for |bufs|, use |
223 | | * nghttp2_bufs_wrap_free(). |
224 | | * |
225 | | * Don't use the function which performs allocation, such as |
226 | | * nghttp2_bufs_realloc(). |
227 | | * |
228 | | * This function returns 0 if it succeeds, or one of the following |
229 | | * negative error codes: |
230 | | * |
231 | | * NGHTTP2_ERR_NOMEM |
232 | | * Out of memory. |
233 | | */ |
234 | | int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec, |
235 | | size_t veclen, nghttp2_mem *mem); |
236 | | |
237 | | /* |
238 | | * Frees any related resource to the |bufs|. This function does not |
239 | | * free supplied buffer provided in nghttp2_bufs_wrap_init(). |
240 | | */ |
241 | | void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs); |
242 | | |
243 | | /* |
244 | | * Reallocates internal buffer using |chunk_length|. The max_chunk, |
245 | | * chunk_keep and offset do not change. After successful allocation |
246 | | * of new buffer, previous buffers are deallocated without copying |
247 | | * anything into new buffers. chunk_used is reset to 1. |
248 | | * |
249 | | * This function returns 0 if it succeeds, or one of the following |
250 | | * negative error codes: |
251 | | * |
252 | | * NGHTTP2_ERR_NOMEM |
253 | | * Out of memory. |
254 | | * NGHTTP2_ERR_INVALID_ARGUMENT |
255 | | * chunk_length < offset |
256 | | */ |
257 | | int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length); |
258 | | |
259 | | /* |
260 | | * Appends the |data| of length |len| to the |bufs|. The write starts |
261 | | * at bufs->cur->buf.last. A new buffers will be allocated to store |
262 | | * all data. |
263 | | * |
264 | | * This function returns 0 if it succeeds, or one of the following |
265 | | * negative error codes: |
266 | | * |
267 | | * NGHTTP2_ERR_NOMEM |
268 | | * Out of memory. |
269 | | * NGHTTP2_ERR_BUFFER_ERROR |
270 | | * Out of buffer space. |
271 | | */ |
272 | | int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len); |
273 | | |
274 | | /* |
275 | | * Appends a single byte |b| to the |bufs|. The write starts at |
276 | | * bufs->cur->buf.last. A new buffers will be allocated to store all |
277 | | * data. |
278 | | * |
279 | | * This function returns 0 if it succeeds, or one of the following |
280 | | * negative error codes: |
281 | | * |
282 | | * NGHTTP2_ERR_NOMEM |
283 | | * Out of memory. |
284 | | * NGHTTP2_ERR_BUFFER_ERROR |
285 | | * Out of buffer space. |
286 | | */ |
287 | | int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b); |
288 | | |
289 | | /* |
290 | | * Behaves like nghttp2_bufs_addb(), but this does not update |
291 | | * buf->last pointer. |
292 | | */ |
293 | | int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b); |
294 | | |
295 | | #define nghttp2_bufs_fast_addb(BUFS, B) \ |
296 | | do { \ |
297 | | *(BUFS)->cur->buf.last++ = B; \ |
298 | | } while (0) |
299 | | |
300 | | #define nghttp2_bufs_fast_addb_hold(BUFS, B) \ |
301 | | do { \ |
302 | | *(BUFS)->cur->buf.last = B; \ |
303 | | } while (0) |
304 | | |
305 | | /* |
306 | | * Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers |
307 | | * will be allocated if necessary. |
308 | | * |
309 | | * This function returns 0 if it succeeds, or one of the following |
310 | | * negative error codes: |
311 | | * |
312 | | * NGHTTP2_ERR_NOMEM |
313 | | * Out of memory. |
314 | | * NGHTTP2_ERR_BUFFER_ERROR |
315 | | * Out of buffer space. |
316 | | */ |
317 | | int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b); |
318 | | |
319 | | /* |
320 | | * Behaves like nghttp2_bufs_orb(), but does not update buf->last |
321 | | * pointer. |
322 | | */ |
323 | | int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b); |
324 | | |
325 | | #define nghttp2_bufs_fast_orb(BUFS, B) \ |
326 | | do { \ |
327 | | uint8_t **p = &(BUFS)->cur->buf.last; \ |
328 | | **p = (uint8_t)(**p | (B)); \ |
329 | | ++(*p); \ |
330 | | } while (0) |
331 | | |
332 | | #define nghttp2_bufs_fast_orb_hold(BUFS, B) \ |
333 | | do { \ |
334 | | uint8_t *p = (BUFS)->cur->buf.last; \ |
335 | | *p = (uint8_t)(*p | (B)); \ |
336 | | } while (0) |
337 | | |
338 | | /* |
339 | | * Copies all data stored in |bufs| to the contiguous buffer. This |
340 | | * function allocates the contiguous memory to store all data in |
341 | | * |bufs| and assigns it to |*out|. |
342 | | * |
343 | | * The contents of |bufs| is left unchanged. |
344 | | * |
345 | | * This function returns the length of copied data and assigns the |
346 | | * pointer to copied data to |*out| if it succeeds, or one of the |
347 | | * following negative error codes: |
348 | | * |
349 | | * NGHTTP2_ERR_NOMEM |
350 | | * Out of memory |
351 | | */ |
352 | | ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out); |
353 | | |
354 | | /* |
355 | | * Copies all data stored in |bufs| to |out|. This function assumes |
356 | | * that the buffer space pointed by |out| has at least |
357 | | * nghttp2_bufs(bufs) bytes. |
358 | | * |
359 | | * The contents of |bufs| is left unchanged. |
360 | | * |
361 | | * This function returns the length of copied data. |
362 | | */ |
363 | | size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out); |
364 | | |
365 | | /* |
366 | | * Resets |bufs| and makes the buffers empty. |
367 | | */ |
368 | | void nghttp2_bufs_reset(nghttp2_bufs *bufs); |
369 | | |
370 | | /* |
371 | | * Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is |
372 | | * NULL, this function allocates new buffers and bufs->cur points to |
373 | | * it. |
374 | | * |
375 | | * This function returns 0 if it succeeds, or one of the following |
376 | | * negative error codes: |
377 | | * |
378 | | * NGHTTP2_ERR_NOMEM |
379 | | * Out of memory |
380 | | * NGHTTP2_ERR_BUFFER_ERROR |
381 | | * Out of buffer space. |
382 | | */ |
383 | | int nghttp2_bufs_advance(nghttp2_bufs *bufs); |
384 | | |
385 | | /* Sets bufs->cur to bufs->head */ |
386 | | #define nghttp2_bufs_rewind(BUFS) \ |
387 | 75.7k | do { \ |
388 | 75.7k | (BUFS)->cur = (BUFS)->head; \ |
389 | 75.7k | } while (0) |
390 | | |
391 | | /* |
392 | | * Move bufs->cur, from the current position, using next member, to |
393 | | * the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf |
394 | | * which satisfies nghttp2_buf_len(buf) == 0. If |
395 | | * nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL, |
396 | | * bufs->cur is unchanged. |
397 | | */ |
398 | | void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs); |
399 | | |
400 | | /* |
401 | | * Returns nonzero if bufs->cur->next is not empty. |
402 | | */ |
403 | | int nghttp2_bufs_next_present(nghttp2_bufs *bufs); |
404 | | |
405 | 97.0k | #define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf) |
406 | | |
407 | | /* |
408 | | * Returns the total buffer length of |bufs|. |
409 | | */ |
410 | | size_t nghttp2_bufs_len(nghttp2_bufs *bufs); |
411 | | |
412 | | #endif /* NGHTTP2_BUF_H */ |