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 #define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos)) 55 #define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last)) 56 #define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last)) 57 #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 do { \ 64 (BUF)->pos += AMT; \ 65 (BUF)->last += AMT; \ 66 } 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 do { \ 388 (BUFS)->cur = (BUFS)->head; \ 389 } 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 #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 */ 413