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