diff --git a/configure.ac b/configure.ac index 74709630..4b50c13c 100644 --- a/configure.ac +++ b/configure.ac @@ -1124,17 +1124,16 @@ AH_BOTTOM([ #endif #ifdef GETDNS_ON_WINDOWS -/* On windows it is allowed to increase the FD_SETSIZE - * (and nescessary to make our custom eventloop work) - * See: https://support.microsoft.com/en-us/kb/111855 - */ -#ifndef FD_SETSIZE -#define FD_SETSIZE 1024 -#endif - -#define PRIsz "%Iu" + /* On windows it is allowed to increase the FD_SETSIZE + * (and nescessary to make our custom eventloop work) + * See: https://support.microsoft.com/en-us/kb/111855 + */ +# ifndef FD_SETSIZE +# define FD_SETSIZE 1024 +# endif +# define PRIsz "%Iu" #else -#define PRIsz "%zu" +# define PRIsz "%zu" #endif #include @@ -1171,8 +1170,6 @@ AH_BOTTOM([ #define FD_SET_T #endif - - #ifdef __cplusplus extern "C" { #endif @@ -1227,6 +1224,12 @@ int inet_pton(int af, const char* src, void* dst); const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif +#ifdef USE_WINSOCK +static inline int _gldns_custom_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ int r = vsnprintf(str, size, format, ap); return r == -1 ? _vscprintf(format, ap) : r; } +# define vsnprintf _gldns_custom_vsnprintf +#endif + #ifdef __cplusplus } #endif diff --git a/src/context.c b/src/context.c index 7dab4ecf..66dcf6f9 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_vfixed_frm_data(&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_vfixed_frm_data(&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..11919107 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_vfixed_frm_data(&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_vfixed_frm_data(&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_vfixed_frm_data(&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_vfixed_frm_data(&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..23b42531 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_vfixed_frm_data(&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_vfixed_frm_data(&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_vfixed_frm_data(&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_vfixed_frm_data(&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..04c257fb 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_vfixed_frm_data(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 @@ -120,20 +133,19 @@ gldns_buffer_printf(gldns_buffer *buffer, const char *format, ...) remaining = gldns_buffer_remaining(buffer); va_start(args, format); - written = _gldns_vsnprintf((char*)gldns_buffer_current(buffer), - remaining, format, args); + written = vsnprintf((char *) gldns_buffer_current(buffer), remaining, + format, args); va_end(args); 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; } va_start(args, format); - written = _gldns_vsnprintf( - (char *) gldns_buffer_current(buffer), + written = vsnprintf((char *) gldns_buffer_current(buffer), gldns_buffer_remaining(buffer), format, args); va_end(args); if (written == -1) { diff --git a/src/gldns/gbuffer.h b/src/gldns/gbuffer.h index 2db9e250..1b1eb498 100644 --- a/src/gldns/gbuffer.h +++ b/src/gldns/gbuffer.h @@ -27,21 +27,6 @@ extern "C" { # endif #endif -#ifndef USE_WINSOCK -#define _gldns_vsnprintf vsnprintf -#else -/* Unlike Linux and BSD, vsnprintf on Windows returns -1 on overflow. - * Here it is redefined to always return the amount printed - * if enough space had been available. - */ -INLINE int -_gldns_vsnprintf(char *str, size_t size, const char *format, va_list ap) -{ - int r = vsnprintf(str, size, format, ap); - return r == -1 ? _vscprintf(format, ap) : r; -} -#endif - /* * Copy data allowing for unaligned accesses in network byte order * (big endian). @@ -145,6 +130,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 +158,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->_vfixed && buffer->_capacity == 0)); } #endif @@ -196,6 +192,19 @@ 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 "virtually" fixed. Writes beyond size (the capacity) will + * only update position, but no data will be written beyond capacity. This + * allows to determine how big the buffer should have been to contain all the + * written data, by looking at the position with gldns_buffer_position(), + * similarly to the return value of POSIX's snprintf. + * \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_vfixed_frm_data(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 +268,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 +282,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 +354,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 +404,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 +457,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 +514,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 +540,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 +566,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 +580,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/gldns/wire2str.c b/src/gldns/wire2str.c index 50d00967..2d427d86 100644 --- a/src/gldns/wire2str.c +++ b/src/gldns/wire2str.c @@ -279,7 +279,7 @@ int gldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen) int gldns_str_vprint(char** str, size_t* slen, const char* format, va_list args) { - int w = _gldns_vsnprintf(*str, *slen, format, args); + int w = vsnprintf(*str, *slen, format, args); if(w < 0) { /* error in printout */ return 0; diff --git a/src/request-internal.c b/src/request-internal.c index 37ba93b4..8193acb7 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_vfixed_frm_data(&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..fe05cd83 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_vfixed_frm_data(&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_vfixed_frm_data(&gbuf, buf, *buf_len); _getdns_reply2wire_buf(&gbuf, r); if ((sz = gldns_buffer_position(&gbuf)) <= *buf_len) {