diff --git a/src/context.c b/src/context.c index c4f5d0f7..88eb0e4d 100644 --- a/src/context.c +++ b/src/context.c @@ -1354,7 +1354,7 @@ getdns_context_create_with_extended_memory_functions( result->suffixes = no_suffixes; result->suffixes_len = sizeof(no_suffixes); - gldns_buffer_init_frm_data(&gbuf, result->trust_anchors_spc + gldns_buffer_init_frm_data_v(&gbuf, result->trust_anchors_spc , sizeof(result->trust_anchors_spc)); if (!_getdns_parse_ta_file(NULL, &gbuf)) { @@ -2333,7 +2333,7 @@ getdns_context_set_suffix(getdns_context *context, getdns_list *value) context->suffixes_len = sizeof(no_suffixes); return GETDNS_RETURN_GOOD; } - gldns_buffer_init_frm_data(&gbuf, buf_spc, sizeof(buf_spc)); + gldns_buffer_init_frm_data_v(&gbuf, buf_spc, sizeof(buf_spc)); for (;;) { for ( i = 0 ; !(r = getdns_list_get_bindata(value, i, &bindata)) diff --git a/src/convert.c b/src/convert.c index 5e2c2684..df2ff0e5 100644 --- a/src/convert.c +++ b/src/convert.c @@ -297,7 +297,7 @@ getdns_rr_dict2wire_scan( return GETDNS_RETURN_INVALID_PARAMETER; - gldns_buffer_init_frm_data(&gbuf, *wire, *wire_sz); + gldns_buffer_init_frm_data_v(&gbuf, *wire, *wire_sz); if ((r = _getdns_rr_dict2wire(rr_dict, &gbuf))) return r; @@ -447,7 +447,7 @@ getdns_rr_dict2str_scan( if (!rr_dict || !str || !*str || !str_len) return GETDNS_RETURN_INVALID_PARAMETER; - gldns_buffer_init_frm_data(&gbuf, buf, sizeof(buf_spc)); + gldns_buffer_init_frm_data_v(&gbuf, buf, sizeof(buf_spc)); r = _getdns_rr_dict2wire(rr_dict, &gbuf); if (gldns_buffer_position(&gbuf) > sizeof(buf_spc)) { if (!(buf = GETDNS_XMALLOC( @@ -960,7 +960,7 @@ getdns_msg_dict2wire_scan( if (!msg_dict || !wire || !wire_sz || (!*wire && *wire_sz)) return GETDNS_RETURN_INVALID_PARAMETER; - gldns_buffer_init_frm_data(&gbuf, *wire, *wire_sz); + gldns_buffer_init_frm_data_v(&gbuf, *wire, *wire_sz); if ((r = _getdns_msg_dict2wire_buf(msg_dict, &gbuf))) return r; @@ -1036,7 +1036,7 @@ getdns_msg_dict2str_scan( if (!msg_dict || !str || !*str || !str_len) return GETDNS_RETURN_INVALID_PARAMETER; - gldns_buffer_init_frm_data(&gbuf, buf, sizeof(buf_spc)); + gldns_buffer_init_frm_data_v(&gbuf, buf, sizeof(buf_spc)); r = _getdns_msg_dict2wire_buf(msg_dict, &gbuf); if (gldns_buffer_position(&gbuf) > sizeof(buf_spc)) { if (!(buf = GETDNS_XMALLOC( diff --git a/src/dict.c b/src/dict.c index eba1a728..70fa3836 100644 --- a/src/dict.c +++ b/src/dict.c @@ -1186,7 +1186,7 @@ getdns_pretty_snprint_dict(char *str, size_t size, const getdns_dict *dict) if (!dict) return -1; - gldns_buffer_init_frm_data(&buf, str, size); + gldns_buffer_init_frm_data_v(&buf, str, size); return getdns_pp_dict(&buf, 0, dict, 0) < 0 ? -1 : (int)gldns_buffer_position(&buf); } @@ -1220,7 +1220,7 @@ getdns_pretty_snprint_list(char *str, size_t size, const getdns_list *list) if (!list) return -1; - gldns_buffer_init_frm_data(&buf, str, size); + gldns_buffer_init_frm_data_v(&buf, str, size); return getdns_pp_list(&buf, 0, list, 0, 0) < 0 ? -1 : (int)gldns_buffer_position(&buf); } @@ -1255,7 +1255,7 @@ getdns_snprint_json_dict( if (!dict) return -1; - gldns_buffer_init_frm_data(&buf, str, size); + gldns_buffer_init_frm_data_v(&buf, str, size); return getdns_pp_dict(&buf, 0, dict, pretty ? 1 : 2) < 0 ? -1 : (int)gldns_buffer_position(&buf); } @@ -1290,7 +1290,7 @@ getdns_snprint_json_list( if (!list) return -1; - gldns_buffer_init_frm_data(&buf, str, size); + gldns_buffer_init_frm_data_v(&buf, str, size); return getdns_pp_list(&buf, 0, list, 0, pretty ? 1 : 2) < 0 ? -1 : (int)gldns_buffer_position(&buf); } diff --git a/src/gldns/gbuffer.c b/src/gldns/gbuffer.c index ac70415d..cecfe480 100644 --- a/src/gldns/gbuffer.c +++ b/src/gldns/gbuffer.c @@ -33,6 +33,7 @@ gldns_buffer_new(size_t capacity) buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; + buffer->_vfixed = 0; buffer->_status_err = 0; gldns_buffer_invariant(buffer); @@ -48,6 +49,7 @@ gldns_buffer_new_frm_data(gldns_buffer *buffer, void *data, size_t size) buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_fixed = 0; + buffer->_vfixed = 0; buffer->_data = malloc(size); if(!buffer->_data) { buffer->_status_err = 1; @@ -66,6 +68,17 @@ gldns_buffer_init_frm_data(gldns_buffer *buffer, void *data, size_t size) buffer->_data = data; buffer->_capacity = buffer->_limit = size; buffer->_fixed = 1; + buffer->_vfixed = 0; +} + +void +gldns_buffer_init_frm_data_v(gldns_buffer *buffer, void *data, size_t size) +{ + memset(buffer, 0, sizeof(*buffer)); + buffer->_data = data; + buffer->_capacity = buffer->_limit = size; + buffer->_fixed = 1; + buffer->_vfixed = 1; } int @@ -126,7 +139,7 @@ gldns_buffer_printf(gldns_buffer *buffer, const char *format, ...) if (written == -1) { buffer->_status_err = 1; return -1; - } else if (!buffer->_fixed && (size_t) written >= remaining) { + } else if (!buffer->_vfixed && (size_t) written >= remaining) { if (!gldns_buffer_reserve(buffer, (size_t) written + 1)) { buffer->_status_err = 1; return -1; diff --git a/src/gldns/gbuffer.h b/src/gldns/gbuffer.h index 2db9e250..67539424 100644 --- a/src/gldns/gbuffer.h +++ b/src/gldns/gbuffer.h @@ -145,6 +145,17 @@ struct gldns_buffer /** If the buffer is fixed it cannot be resized */ unsigned _fixed : 1; + /** If the buffer is vfixed, no more than capacity bytes willl be + * written to _data, however the _position counter will be updated + * with the amount that would have been written in consecutive + * writes. This allows for a modus operandi in which a sequence is + * written on a fixed capacity buffer (perhaps with _data on stack). + * When everything could be written, then the _data is immediately + * usable, if not, then a buffer could be allocated sized precisely + * to fit the data for a second attempt. + */ + unsigned _vfixed : 1; + /** The current state of the buffer. If writing to the buffer fails * for any reason, this value is changed. This way, you can perform * multiple writes in sequence and check for success afterwards. */ @@ -162,9 +173,9 @@ INLINE void gldns_buffer_invariant(gldns_buffer *buffer) { assert(buffer != NULL); - assert(buffer->_position <= buffer->_limit || buffer->_fixed); + assert(buffer->_position <= buffer->_limit || buffer->_vfixed); assert(buffer->_limit <= buffer->_capacity); - assert(buffer->_data != NULL || (buffer->_capacity == 0 && buffer->_fixed)); + assert(buffer->_data != NULL || (buffer->_capacity == 0 && buffer->_vfixed)); } #endif @@ -196,6 +207,17 @@ void gldns_buffer_new_frm_data(gldns_buffer *buffer, void *data, size_t size); */ void gldns_buffer_init_frm_data(gldns_buffer *buffer, void *data, size_t size); +/** + * Setup a buffer with the data pointed to. No data copied, no memory allocs. + * The buffer is fixed. Writes beyond size (the capacity) will update the + * position (and not write data. This allows to determine how big the buffer + * should have been to contain all the written data. + * \param[in] buffer pointer to the buffer to put the data in + * \param[in] data the data to encapsulate in the buffer + * \param[in] size the size of the data + */ +void gldns_buffer_init_frm_data_v(gldns_buffer *buffer, void *data, size_t size); + /** * clears the buffer and make it ready for writing. The buffer's limit * is set to the capacity and the position is set to 0. @@ -259,7 +281,7 @@ gldns_buffer_position(gldns_buffer *buffer) INLINE void gldns_buffer_set_position(gldns_buffer *buffer, size_t mark) { - assert(mark <= buffer->_limit || buffer->_fixed); + assert(mark <= buffer->_limit || buffer->_vfixed); buffer->_position = mark; } @@ -273,7 +295,7 @@ gldns_buffer_set_position(gldns_buffer *buffer, size_t mark) INLINE void gldns_buffer_skip(gldns_buffer *buffer, ssize_t count) { - assert(buffer->_position + count <= buffer->_limit || buffer->_fixed); + assert(buffer->_position + count <= buffer->_limit || buffer->_vfixed); buffer->_position += count; } @@ -345,7 +367,7 @@ int gldns_buffer_reserve(gldns_buffer *buffer, size_t amount); INLINE uint8_t * gldns_buffer_at(const gldns_buffer *buffer, size_t at) { - assert(at <= buffer->_limit || buffer->_fixed); + assert(at <= buffer->_limit || buffer->_vfixed); return buffer->_data + at; } @@ -395,6 +417,7 @@ INLINE size_t gldns_buffer_remaining_at(gldns_buffer *buffer, size_t at) { gldns_buffer_invariant(buffer); + assert(at <= buffer->_limit || buffer->_vfixed); return at < buffer->_limit ? buffer->_limit - at : 0; } @@ -447,7 +470,7 @@ gldns_buffer_available(gldns_buffer *buffer, size_t count) INLINE void gldns_buffer_write_at(gldns_buffer *buffer, size_t at, const void *data, size_t count) { - if (!buffer->_fixed) + if (!buffer->_vfixed) assert(gldns_buffer_available_at(buffer, at, count)); else if (gldns_buffer_remaining_at(buffer, at) == 0) return; @@ -504,7 +527,7 @@ gldns_buffer_write_string(gldns_buffer *buffer, const char *str) INLINE void gldns_buffer_write_u8_at(gldns_buffer *buffer, size_t at, uint8_t data) { - if (buffer->_fixed && at + sizeof(data) > buffer->_limit) return; + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(gldns_buffer_available_at(buffer, at, sizeof(data))); buffer->_data[at] = data; } @@ -530,7 +553,7 @@ gldns_buffer_write_u8(gldns_buffer *buffer, uint8_t data) INLINE void gldns_buffer_write_u16_at(gldns_buffer *buffer, size_t at, uint16_t data) { - if (buffer->_fixed && at + sizeof(data) > buffer->_limit) return; + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(gldns_buffer_available_at(buffer, at, sizeof(data))); gldns_write_uint16(buffer->_data + at, data); } @@ -556,7 +579,7 @@ gldns_buffer_write_u16(gldns_buffer *buffer, uint16_t data) INLINE void gldns_buffer_write_u32_at(gldns_buffer *buffer, size_t at, uint32_t data) { - if (buffer->_fixed && at + sizeof(data) > buffer->_limit) return; + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(gldns_buffer_available_at(buffer, at, sizeof(data))); gldns_write_uint32(buffer->_data + at, data); } @@ -570,7 +593,7 @@ gldns_buffer_write_u32_at(gldns_buffer *buffer, size_t at, uint32_t data) INLINE void gldns_buffer_write_u48_at(gldns_buffer *buffer, size_t at, uint64_t data) { - if (buffer->_fixed && at + 6 > buffer->_limit) return; + if (buffer->_vfixed && at + 6 > buffer->_limit) return; assert(gldns_buffer_available_at(buffer, at, 6)); gldns_write_uint48(buffer->_data + at, data); } diff --git a/src/request-internal.c b/src/request-internal.c index 37ba93b4..7b8af65a 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -383,7 +383,7 @@ _getdns_network_req_add_tsig(getdns_network_req *req) #endif tsig_info = _getdns_get_tsig_info(upstream->tsig_alg); - gldns_buffer_init_frm_data(&gbuf, req->response, MAXIMUM_TSIG_SPACE); + gldns_buffer_init_frm_data_v(&gbuf, req->response, MAXIMUM_TSIG_SPACE); gldns_buffer_write(&gbuf, upstream->tsig_dname, upstream->tsig_dname_len); /* Name */ gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */ diff --git a/src/util-internal.c b/src/util-internal.c index c25cf5ce..2bbad80d 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -1510,7 +1510,7 @@ uint8_t *_getdns_list2wire( gldns_buffer gbuf; size_t sz; - gldns_buffer_init_frm_data(&gbuf, buf, *buf_len); + gldns_buffer_init_frm_data_v(&gbuf, buf, *buf_len); _getdns_list2wire_buf(&gbuf, l); if ((sz = gldns_buffer_position(&gbuf)) <= *buf_len) { @@ -1531,7 +1531,7 @@ uint8_t *_getdns_reply2wire( gldns_buffer gbuf; size_t sz; - gldns_buffer_init_frm_data(&gbuf, buf, *buf_len); + gldns_buffer_init_frm_data_v(&gbuf, buf, *buf_len); _getdns_reply2wire_buf(&gbuf, r); if ((sz = gldns_buffer_position(&gbuf)) <= *buf_len) {