123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /*
- * Generic routines to deal with send buffers: a linked list of
- * smallish blocks, with the operations
- *
- * - add an arbitrary amount of data to the end of the list
- * - remove the first N bytes from the list
- * - return a (pointer,length) pair giving some initial data in
- * the list, suitable for passing to a send or write system
- * call
- * - retrieve a larger amount of initial data from the list
- * - return the current size of the buffer chain in bytes
- */
- #include "defs.h"
- #include "misc.h"
- #define BUFFER_MIN_GRANULE 512
- struct bufchain_granule {
- struct bufchain_granule *next;
- char *bufpos, *bufend, *bufmax;
- };
- static void uninitialised_queue_idempotent_callback(IdempotentCallback *ic)
- {
- unreachable("bufchain callback used while uninitialised");
- }
- void bufchain_init(bufchain *ch)
- {
- ch->head = ch->tail = NULL;
- ch->buffersize = 0;
- ch->ic = NULL;
- ch->queue_idempotent_callback = uninitialised_queue_idempotent_callback;
- }
- void bufchain_clear(bufchain *ch)
- {
- struct bufchain_granule *b;
- while (ch->head) {
- b = ch->head;
- ch->head = ch->head->next;
- smemclr(b, sizeof(*b));
- sfree(b);
- }
- ch->tail = NULL;
- ch->buffersize = 0;
- }
- size_t bufchain_size(bufchain *ch)
- {
- return ch->buffersize;
- }
- void bufchain_set_callback_inner(
- bufchain *ch, IdempotentCallback *ic,
- void (*queue_idempotent_callback)(IdempotentCallback *ic))
- {
- ch->queue_idempotent_callback = queue_idempotent_callback;
- ch->ic = ic;
- }
- void bufchain_add(bufchain *ch, const void *data, size_t len)
- {
- const char *buf = (const char *)data;
- if (len == 0) return;
- ch->buffersize += len;
- while (len > 0) {
- if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {
- size_t copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
- memcpy(ch->tail->bufend, buf, copylen);
- buf += copylen;
- len -= copylen;
- ch->tail->bufend += copylen;
- }
- if (len > 0) {
- size_t grainlen =
- max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);
- struct bufchain_granule *newbuf;
- newbuf = smalloc(grainlen);
- newbuf->bufpos = newbuf->bufend =
- (char *)newbuf + sizeof(struct bufchain_granule);
- newbuf->bufmax = (char *)newbuf + grainlen;
- newbuf->next = NULL;
- if (ch->tail)
- ch->tail->next = newbuf;
- else
- ch->head = newbuf;
- ch->tail = newbuf;
- }
- }
- if (ch->ic)
- ch->queue_idempotent_callback(ch->ic);
- }
- void bufchain_consume(bufchain *ch, size_t len)
- {
- struct bufchain_granule *tmp;
- assert(ch->buffersize >= len);
- while (len > 0) {
- int remlen = len;
- assert(ch->head != NULL);
- if (remlen >= ch->head->bufend - ch->head->bufpos) {
- remlen = ch->head->bufend - ch->head->bufpos;
- tmp = ch->head;
- ch->head = tmp->next;
- if (!ch->head)
- ch->tail = NULL;
- smemclr(tmp, sizeof(*tmp));
- sfree(tmp);
- } else
- ch->head->bufpos += remlen;
- ch->buffersize -= remlen;
- len -= remlen;
- }
- }
- ptrlen bufchain_prefix(bufchain *ch)
- {
- return make_ptrlen(ch->head->bufpos, ch->head->bufend - ch->head->bufpos);
- }
- void bufchain_fetch(bufchain *ch, void *data, size_t len)
- {
- struct bufchain_granule *tmp;
- char *data_c = (char *)data;
- tmp = ch->head;
- assert(ch->buffersize >= len);
- while (len > 0) {
- int remlen = len;
- assert(tmp != NULL);
- if (remlen >= tmp->bufend - tmp->bufpos)
- remlen = tmp->bufend - tmp->bufpos;
- memcpy(data_c, tmp->bufpos, remlen);
- tmp = tmp->next;
- len -= remlen;
- data_c += remlen;
- }
- }
- void bufchain_fetch_consume(bufchain *ch, void *data, size_t len)
- {
- bufchain_fetch(ch, data, len);
- bufchain_consume(ch, len);
- }
- bool bufchain_try_fetch(bufchain *ch, void *data, size_t len)
- {
- if (ch->buffersize >= len) {
- bufchain_fetch(ch, data, len);
- return true;
- } else {
- return false;
- }
- }
- bool bufchain_try_consume(bufchain *ch, size_t len)
- {
- if (ch->buffersize >= len) {
- bufchain_consume(ch, len);
- return true;
- } else {
- return false;
- }
- }
- bool bufchain_try_fetch_consume(bufchain *ch, void *data, size_t len)
- {
- if (ch->buffersize >= len) {
- bufchain_fetch_consume(ch, data, len);
- return true;
- } else {
- return false;
- }
- }
- size_t bufchain_fetch_consume_up_to(bufchain *ch, void *data, size_t len)
- {
- if (len > ch->buffersize)
- len = ch->buffersize;
- if (len)
- bufchain_fetch_consume(ch, data, len);
- return len;
- }
|