From 6b94663b2455e212009a544ae23bb6a8c55407f8 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 9 Jun 2022 21:34:09 +0200 Subject: refactor(lib, hicn-light, vpp, hiperf): HICN-723 - move infra data structure into the shared lib - new packet cache using double hashing and lookup on prefix suffix - testing updates - authenticated requests using interest manifests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mauro Sardara Co-authored-by: Jordan Augé Co-authored-by: Michele Papalini Co-authored-by: Olivier Roques Co-authored-by: Enrico Loparco Change-Id: Iaddebfe6aa5279ea8553433b0f519578f6b9ccd9 Signed-off-by: Luca Muscariello --- lib/src/CMakeLists.txt | 3 + lib/src/common.c | 73 ++++++++------------ lib/src/ops.c | 4 ++ lib/src/protocol/ah.c | 4 ++ lib/src/protocol/icmp.c | 4 ++ lib/src/protocol/ipv4.c | 25 +++++++ lib/src/protocol/ipv6.c | 25 +++++++ lib/src/protocol/new.c | 5 ++ lib/src/protocol/tcp.c | 29 ++++++++ lib/src/protocol/udp.c | 29 ++++++++ lib/src/util/log.c | 13 +++- lib/src/util/pool.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/util/ring.c | 49 ++++++++++++++ lib/src/util/vector.c | 101 ++++++++++++++++++++++++++++ 14 files changed, 490 insertions(+), 48 deletions(-) create mode 100644 lib/src/util/pool.c create mode 100644 lib/src/util/ring.c create mode 100644 lib/src/util/vector.c (limited to 'lib/src') diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt index ef74127cc..8e81aa442 100644 --- a/lib/src/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -33,6 +33,9 @@ list(APPEND LIBHICN_SOURCE_FILES protocol/new.c util/ip_address.c util/log.c + util/pool.c + util/ring.c + util/vector.c ) if (WIN32) diff --git a/lib/src/common.c b/lib/src/common.c index c4cb8bc3e..362034942 100644 --- a/lib/src/common.c +++ b/lib/src/common.c @@ -54,61 +54,44 @@ get_addr_family (const char *ip_address) /* hashes */ -u32 -cumulative_hash32 (const void *data, size_t len, u32 lastValue) +// FNV-1a 32-bit http://www.isthe.com/chongo/tech/comp/fnv/ +typedef u_int32_t Fnv32_t; +#define FNV_32_PRIME ((Fnv32_t) 0x01000193) +#define FNV1_32_INIT ((Fnv32_t) 0x811c9dc5) +#define FNV1_32A_INIT FNV1_32_INIT + +Fnv32_t +cumulative_hash32 (const void *buf, size_t len, Fnv32_t hval) { - // Standard FNV 32-bit prime: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u32 fnv1a_prime = 0x01000193; - u32 hash = lastValue; - size_t i; - - const char *chardata = data; + unsigned char *bp = (unsigned char *) buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ - for (i = 0; i < len; i++) + /* + * FNV-1a hash each octet in the buffer + */ + while (bp < be) { - hash = hash ^ chardata[i]; - hash = hash * fnv1a_prime; - } - return hash; -} + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t) *bp++; -u32 -hash32 (const void *data, size_t len) -{ - // Standard FNV 32-bit offset: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u32 fnv1a_offset = 0x811C9DC5; - return cumulative_hash32 (data, len, fnv1a_offset); -} - -u64 -cumulative_hash64 (const void *data, size_t len, u64 lastValue) -{ - // Standard FNV 64-bit prime: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u64 fnv1a_prime = 0x00000100000001B3ULL; - u64 hash = lastValue; - const char *chardata = data; - size_t i; - - for (i = 0; i < len; i++) - { - hash = hash ^ chardata[i]; - hash = hash * fnv1a_prime; + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += + (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); +#endif } - return hash; + /* return our new hash value */ + return hval; } -u64 -hash64 (const void *data, size_t len) +u32 +hash32 (const void *data, size_t len) { - // Standard FNV 64-bit offset: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u64 fnv1a_offset = 0xCBF29CE484222325ULL; - return cumulative_hash64 (data, len, fnv1a_offset); + return cumulative_hash32 (data, len, FNV1_32A_INIT); } void diff --git a/lib/src/ops.c b/lib/src/ops.c index 80ffcf3c5..20362d69d 100644 --- a/lib/src/ops.c +++ b/lib/src/ops.c @@ -57,6 +57,10 @@ DECLARE_update_data_pathlabel (none, NONE); DECLARE_reset_data_for_hash (none, NONE); DECLARE_get_lifetime (none, NONE); DECLARE_set_lifetime (none, NONE); +DECLARE_get_source_port (none, NONE); +DECLARE_get_dest_port (none, NONE); +DECLARE_set_source_port (none, NONE); +DECLARE_set_dest_port (none, NONE); DECLARE_update_checksums (none, NONE); DECLARE_verify_checksums (none, NONE); DECLARE_rewrite_interest (none, NONE); diff --git a/lib/src/protocol/ah.c b/lib/src/protocol/ah.c index b3d24161d..c9ed40179 100644 --- a/lib/src/protocol/ah.c +++ b/lib/src/protocol/ah.c @@ -45,6 +45,10 @@ DECLARE_set_data_pathlabel (ah, UNEXPECTED); DECLARE_update_data_pathlabel (ah, UNEXPECTED); DECLARE_get_lifetime (ah, UNEXPECTED); DECLARE_set_lifetime (ah, UNEXPECTED); +DECLARE_get_source_port (ah, UNEXPECTED); +DECLARE_get_dest_port (ah, UNEXPECTED); +DECLARE_set_source_port (ah, UNEXPECTED); +DECLARE_set_dest_port (ah, UNEXPECTED); DECLARE_get_payload_length (ah, UNEXPECTED); DECLARE_set_payload_length (ah, UNEXPECTED); DECLARE_get_payload_type (ah, UNEXPECTED); diff --git a/lib/src/protocol/icmp.c b/lib/src/protocol/icmp.c index 0452e4fbb..1fc6c7d2f 100644 --- a/lib/src/protocol/icmp.c +++ b/lib/src/protocol/icmp.c @@ -38,6 +38,10 @@ DECLARE_set_data_pathlabel (icmp, UNEXPECTED); DECLARE_update_data_pathlabel (icmp, UNEXPECTED); DECLARE_get_lifetime (icmp, UNEXPECTED); DECLARE_set_lifetime (icmp, UNEXPECTED); +DECLARE_get_source_port (icmp, UNEXPECTED); +DECLARE_get_dest_port (icmp, UNEXPECTED); +DECLARE_set_source_port (icmp, UNEXPECTED); +DECLARE_set_dest_port (icmp, UNEXPECTED); DECLARE_get_length (icmp, UNEXPECTED); DECLARE_get_payload_length (icmp, UNEXPECTED); DECLARE_set_payload_length (icmp, UNEXPECTED); diff --git a/lib/src/protocol/ipv4.c b/lib/src/protocol/ipv4.c index 5d445f018..840fbe34b 100644 --- a/lib/src/protocol/ipv4.c +++ b/lib/src/protocol/ipv4.c @@ -227,6 +227,31 @@ ipv4_set_lifetime (hicn_type_t type, hicn_protocol_t *h, return CHILD_OPS (set_lifetime, type, h, lifetime); } +int +ipv4_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + return CHILD_OPS (get_source_port, type, h, source_port); +} + +int +ipv4_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + return CHILD_OPS (get_dest_port, type, h, dest_port); +} + +int +ipv4_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + return CHILD_OPS (set_source_port, type, h, source_port); +} + +int +ipv4_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + return CHILD_OPS (set_dest_port, type, h, dest_port); +} + int ipv4_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) diff --git a/lib/src/protocol/ipv6.c b/lib/src/protocol/ipv6.c index b3a107a13..b3c543249 100644 --- a/lib/src/protocol/ipv6.c +++ b/lib/src/protocol/ipv6.c @@ -211,6 +211,31 @@ ipv6_set_lifetime (hicn_type_t type, hicn_protocol_t *h, return CHILD_OPS (set_lifetime, type, h, lifetime); } +int +ipv6_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + return CHILD_OPS (get_source_port, type, h, source_port); +} + +int +ipv6_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + return CHILD_OPS (get_dest_port, type, h, dest_port); +} + +int +ipv6_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + return CHILD_OPS (set_source_port, type, h, source_port); +} + +int +ipv6_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + return CHILD_OPS (set_dest_port, type, h, dest_port); +} + int ipv6_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) diff --git a/lib/src/protocol/new.c b/lib/src/protocol/new.c index 8c79963ad..07c1d0d76 100644 --- a/lib/src/protocol/new.c +++ b/lib/src/protocol/new.c @@ -22,6 +22,11 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" +DECLARE_get_source_port (new, UNEXPECTED); +DECLARE_get_dest_port (new, UNEXPECTED); +DECLARE_set_source_port (new, UNEXPECTED); +DECLARE_set_dest_port (new, UNEXPECTED); + static int is_interest (u8 flags) { diff --git a/lib/src/protocol/tcp.c b/lib/src/protocol/tcp.c index 8097cfd12..82fc461ea 100644 --- a/lib/src/protocol/tcp.c +++ b/lib/src/protocol/tcp.c @@ -250,6 +250,35 @@ tcp_set_lifetime (hicn_type_t type, hicn_protocol_t *h, return HICN_LIB_ERROR_NONE; } +int +tcp_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + *source_port = ntohs (h->tcp.sport); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + *dest_port = ntohs (h->tcp.dport); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + h->tcp.sport = htons (source_port); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + h->tcp.dport = htons (dest_port); + return HICN_LIB_ERROR_NONE; +} + int tcp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) diff --git a/lib/src/protocol/udp.c b/lib/src/protocol/udp.c index ee46b8e9d..7a14b09c2 100644 --- a/lib/src/protocol/udp.c +++ b/lib/src/protocol/udp.c @@ -142,6 +142,35 @@ udp_set_lifetime (hicn_type_t type, hicn_protocol_t *h, return CHILD_OPS (set_lifetime, type, h, lifetime); } +int +udp_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + *source_port = ntohs (h->udp.src_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + *dest_port = ntohs (h->udp.dst_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + h->udp.src_port = htons (source_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + h->udp.dst_port = htons (dest_port); + return HICN_LIB_ERROR_NONE; +} + int udp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) diff --git a/lib/src/util/log.c b/lib/src/util/log.c index 975762603..91a87e848 100644 --- a/lib/src/util/log.c +++ b/lib/src/util/log.c @@ -30,6 +30,10 @@ log_conf_t log_conf = DEFAULT_LOG_CONF; #define FMT_DATETIME_LEN 20 #define snprintf_nowarn(...) (snprintf (__VA_ARGS__) < 0 ? abort () : (void) 0) +#define COLOR_RED "\033[31m" +#define COLOR_YELLOW "\033[33m" +#define COLOR_RESET "\033[0m" + static char ts[FMT_DATETIME_LEN]; static char * @@ -104,7 +108,7 @@ _log_va (int level, const char *fmt, va_list ap) } else { - __android_log_vprint (ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap); + __android_log_vprint (prio, "HICN FACEMGR", fmt, ap); } #else @@ -112,6 +116,7 @@ _log_va (int level, const char *fmt, va_list ap) if (level > log_conf.log_level) return; + char *color = COLOR_RESET; switch (level) { case LOG_FATAL: @@ -119,9 +124,11 @@ _log_va (int level, const char *fmt, va_list ap) break; case LOG_ERROR: prefix = "ERROR: "; + color = COLOR_RED; break; case LOG_WARN: prefix = "WARNING: "; + color = COLOR_YELLOW; break; case LOG_INFO: prefix = ""; @@ -137,9 +144,9 @@ _log_va (int level, const char *fmt, va_list ap) break; } FILE *f = log_conf.log_file ? log_conf.log_file : stdout; - fprintf (f, "%s %s", timestamp (), prefix); + fprintf (f, "%s%s %s", color, timestamp (), prefix); vfprintf (f, fmt, ap); - fprintf (f, "\n"); + fprintf (f, "%s\n", COLOR_RESET); #ifdef DEBUG fflush (f); #endif diff --git a/lib/src/util/pool.c b/lib/src/util/pool.c new file mode 100644 index 000000000..c6be92ce8 --- /dev/null +++ b/lib/src/util/pool.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file pool.c + * \brief Implementation of fixed-size pool allocator. + * + * NOTE: + * - Ideally, we should have a single realloc per resize, that would encompass + * both the free indices vector and bitmap, by nesting data structures. + * Because of the added complexity, and by lack of evidence of the need for + * this, we currently rely on a simpler implementation. + */ + +#include +#include // calloc + +#include + +#include // XXX + +void +_pool_init (void **pool_ptr, size_t elt_size, size_t init_size, + size_t max_size) +{ + assert (pool_ptr); + assert (elt_size); + + init_size = next_pow2 (init_size); + + if (max_size && init_size > max_size) + goto ERR_MAX_SIZE; + + /* The initial pool size is rounded to the next power of two */ + size_t alloc_size = next_pow2 (init_size); + + pool_hdr_t *ph = calloc (POOL_HDRLEN + alloc_size * elt_size, 1); + if (!ph) + goto ERR_MALLOC; + + ph->elt_size = elt_size; + ph->alloc_size = alloc_size; + ph->max_size = max_size; + + /* Free indices */ + off_t *free_indices; + vector_init (free_indices, init_size, max_size); + for (unsigned i = 0; i < init_size; i++) + free_indices[i] = (init_size - 1) - i; + vector_len (free_indices) = init_size; + ph->free_indices = free_indices; + + /* Free bitmap */ + bitmap_t *fb = ph->free_bitmap; + bitmap_init (fb, init_size, max_size); + bitmap_set_to (fb, init_size); + ph->free_bitmap = fb; + + *pool_ptr = (uint8_t *) ph + POOL_HDRLEN; + + return; + +ERR_MALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +void +_pool_free (void **pool_ptr) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + vector_free (ph->free_indices); + bitmap_free (ph->free_bitmap); + + free (pool_hdr (*pool_ptr)); + *pool_ptr = NULL; +} + +bool +_pool_validate_id (void **pool_ptr, off_t id) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + size_t pool_size = pool_get_alloc_size (*pool_ptr); + if (id >= pool_size || !bitmap_is_unset (ph->free_bitmap, id)) + return false; + + return true; +} + +void +_pool_resize (void **pool_ptr, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + size_t old_size = ph->alloc_size; + size_t new_size = old_size * 2; + + WARN ("pool_resize to %lu", new_size); + + if (ph->max_size && new_size > ph->max_size) + goto ERR_MAX_SIZE; + + /* Double pool storage */ + ph = realloc (ph, POOL_HDRLEN + new_size * elt_size); + if (!ph) + goto ERR_REALLOC; + ph->elt_size = elt_size; + ph->alloc_size = new_size; + + /* + * After resize, the pool will have new free indices, ranging from + * old_size to (new_size - 1) + */ + vector_ensure_pos (ph->free_indices, old_size); + for (unsigned i = 0; i < old_size; i++) + ph->free_indices[i] = new_size - 1 - i; + vector_len (ph->free_indices) = old_size; + + /* We also need to update the bitmap */ + bitmap_ensure_pos (&(ph->free_bitmap), new_size - 1); + bitmap_set_range (ph->free_bitmap, old_size, new_size - 1); + + /* Reassign pool pointer */ + *pool_ptr = (uint8_t *) ph + POOL_HDRLEN; + + return; + +ERR_REALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +off_t +_pool_get (void **pool_ptr, void **elt, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + uint64_t l = vector_len (ph->free_indices); + if (l == 0) + { + _pool_resize (pool_ptr, elt_size); + ph = pool_hdr (*pool_ptr); + l = vector_len (ph->free_indices); + } + off_t free_id = ph->free_indices[l - 1]; + vector_len (ph->free_indices)--; + bitmap_unset (ph->free_bitmap, free_id); + *elt = *pool_ptr + free_id * elt_size; + return free_id; +} + +void +_pool_put (void **pool_ptr, void **elt, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + uint64_t l = vector_len (ph->free_indices); + vector_ensure_pos (ph->free_indices, l); + off_t freed_id = (*elt - *pool_ptr) / elt_size; + ph->free_indices[l] = freed_id; + vector_len (ph->free_indices)++; + bitmap_set (ph->free_bitmap, freed_id); +} diff --git a/lib/src/util/ring.c b/lib/src/util/ring.c new file mode 100644 index 000000000..2c722a842 --- /dev/null +++ b/lib/src/util/ring.c @@ -0,0 +1,49 @@ + +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ring.c + * \brief Implementation of ring buffer. + */ + +#include + +#include + +void +_ring_init (void **ring_ptr, size_t elt_size, size_t max_size) +{ + assert (ring_ptr); + assert (elt_size > 0); + // we use a static array, not a vector (for now) + assert (max_size != 0); + + ring_hdr_t *rh = malloc (RING_HDRLEN + max_size * elt_size); + + rh->roff = 0; + rh->woff = 0; + rh->size = 0; + rh->max_size = max_size; + + *ring_ptr = (uint8_t *) rh + RING_HDRLEN; +} + +void +_ring_free (void **ring_ptr) +{ + free (ring_hdr (*ring_ptr)); + *ring_ptr = NULL; +} diff --git a/lib/src/util/vector.c b/lib/src/util/vector.c new file mode 100644 index 000000000..1f5cd0269 --- /dev/null +++ b/lib/src/util/vector.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file vector.c + * \brief Implementation of resizeable static array + */ + +#include +#include // size_t +#include // calloc +#include + +#include + +#define DEFAULT_VECTOR_SIZE 64 + +int +_vector_init (void **vector_ptr, size_t elt_size, size_t init_size, + size_t max_size) +{ + assert (vector_ptr); + assert (max_size == 0 || init_size < max_size); + + if (init_size == 0) + init_size = DEFAULT_VECTOR_SIZE; + + *vector_ptr = NULL; + int rc = _vector_resize (vector_ptr, elt_size, init_size); + if (rc < 0) + return -1; + + vector_hdr_t *vh = vector_hdr (*vector_ptr); + vh->cur_size = 0; + vh->max_size = max_size; + + return 0; +} + +void +_vector_free (void **vector_ptr) +{ + free (vector_hdr (*vector_ptr)); + *vector_ptr = NULL; +} + +int +_vector_resize (void **vector_ptr, size_t elt_size, off_t pos) +{ + vector_hdr_t *vh; + size_t old_size; + + if (*vector_ptr) + { + vh = vector_hdr (*vector_ptr); + old_size = vh->alloc_size; + } + else + { + vh = NULL; + old_size = 0; + } + + /* Round the allocated size to the next power of 2 of the requested position + */ + size_t new_size = next_pow2 (pos); + + /* Don't grow the vector back */ + if (new_size < old_size) + return 0; + + /* Don't exceed maximum size (for init, check is done beforehand) */ + if (vh && vh->max_size && new_size > vh->max_size) + return -1; + + vh = realloc (vh, VECTOR_HDRLEN + new_size * elt_size); + if (!vh) + return -1; + vh->alloc_size = new_size; + + /* Zero out the newly allocated memory (except headers) */ + memset ((uint8_t *) vh + VECTOR_HDRLEN + old_size * elt_size, 0, + (new_size - old_size) * elt_size); + + /* Reassign vector pointer */ + *vector_ptr = (uint8_t *) vh + VECTOR_HDRLEN; + + return 0; +} -- cgit 1.2.3-korg