diff options
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..3236e9d --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,451 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * 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. + */ +#include "include.h" + + +otc_ext_malloc_t otc_ext_malloc = OT_IFDEF_DBG(otc_dbg_malloc, malloc); +otc_ext_free_t otc_ext_free = OT_IFDEF_DBG(otc_dbg_free, free); + + +/*** + * NAME + * timespec_to_duration_us - + * + * ARGUMENTS + * ts - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +std::chrono::microseconds timespec_to_duration_us(const struct timespec *ts) +{ + auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::microseconds{ts->tv_nsec / 1000}; + + return std::chrono::duration_cast<std::chrono::microseconds>(duration); +} + + +/*** + * NAME + * timespec_to_duration - + * + * ARGUMENTS + * ts - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +std::chrono::nanoseconds timespec_to_duration(const struct timespec *ts) +{ + auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::nanoseconds{ts->tv_nsec}; + + return std::chrono::duration_cast<std::chrono::nanoseconds>(duration); +} + + +/*** + * NAME + * otc_ext_init - + * + * ARGUMENTS + * func_malloc - + * func_free - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void otc_ext_init(otc_ext_malloc_t func_malloc, otc_ext_free_t func_free) +{ + otc_ext_malloc = (func_malloc != nullptr) ? func_malloc : OT_IFDEF_DBG(otc_dbg_malloc, malloc); + otc_ext_free = (func_free != nullptr) ? func_free : OT_IFDEF_DBG(otc_dbg_free, free); +} + + +/*** + * NAME + * otc_text_map_new - + * + * ARGUMENTS + * text_map - + * size - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_text_map *otc_text_map_new(struct otc_text_map *text_map, size_t size) +{ + struct otc_text_map *retptr = text_map; + + if (retptr == nullptr) + retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr))); + + if (retptr != nullptr) { + retptr->count = 0; + retptr->size = size; + retptr->is_dynamic = text_map == nullptr; + + if (size == 0) + /* Do nothing. */; + else if ((retptr->key = OT_CAST_TYPEOF(retptr->key, OTC_DBG_CALLOC(size, sizeof(*(retptr->key))))) == nullptr) + otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0)); + else if ((retptr->value = OT_CAST_TYPEOF(retptr->value, OTC_DBG_CALLOC(size, sizeof(*(retptr->value))))) == nullptr) + otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0)); + } + + return retptr; +} + + +/*** + * NAME + * otc_text_map_add - + * + * ARGUMENTS + * text_map - + * key - + * key_len - + * value - + * value_len - + * flags - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int otc_text_map_add(struct otc_text_map *text_map, const char *key, size_t key_len, const char *value, size_t value_len, otc_text_map_flags_t flags) +{ + int retval = -1; + + if ((text_map == nullptr) || (key == nullptr) || (value == nullptr)) + return retval; + + /* + * Check if it is necessary to increase the number of key/value pairs. + * The number of pairs is increased by half the current number of pairs + * (for example: 8 -> 12 -> 18 -> 27 -> 40 -> 60 ...). + */ + if (text_map->count >= text_map->size) { + typeof(text_map->key) ptr_key; + typeof(text_map->value) ptr_value; + size_t size_add = (text_map->size > 1) ? (text_map->size / 2) : 1; + + if ((ptr_key = OT_CAST_TYPEOF(ptr_key, OTC_DBG_REALLOC(text_map->key, OT_TEXT_MAP_SIZE(key, size_add)))) == nullptr) + return retval; + + text_map->key = ptr_key; + (void)memset(text_map->key + OT_TEXT_MAP_SIZE(key, 0), 0, sizeof(*(text_map->key)) * size_add); + + if ((ptr_value = OT_CAST_TYPEOF(ptr_value, OTC_DBG_REALLOC(text_map->value, OT_TEXT_MAP_SIZE(value, size_add)))) == nullptr) + return retval; + + text_map->value = ptr_value; + (void)memset(text_map->value + OT_TEXT_MAP_SIZE(value, 0), 0, sizeof(*(text_map->value)) * size_add); + + text_map->size += size_add; + } + + text_map->key[text_map->count] = (flags & OTC_TEXT_MAP_DUP_KEY) ? ((key_len > 0) ? OTC_DBG_STRNDUP(key, key_len) : OTC_DBG_STRDUP(key)) : OT_CAST_CONST(char *, key); + text_map->value[text_map->count] = (flags & OTC_TEXT_MAP_DUP_VALUE) ? ((value_len > 0) ? OTC_DBG_STRNDUP(value, value_len) : OTC_DBG_STRDUP(value)) : OT_CAST_CONST(char *, value); + + if ((text_map->key[text_map->count] != nullptr) && (text_map->value[text_map->count] != nullptr)) + retval = text_map->count; + + text_map->count++; + + return retval; +} + + +/*** + * NAME + * otc_text_map_destroy - + * + * ARGUMENTS + * text_map - + * flags - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void otc_text_map_destroy(struct otc_text_map **text_map, otc_text_map_flags_t flags) +{ + if ((text_map == nullptr) || (*text_map == nullptr)) + return; + + if ((*text_map)->key != nullptr) { + if (flags & OTC_TEXT_MAP_FREE_KEY) + for (size_t i = 0; i < (*text_map)->count; i++) + OT_FREE((*text_map)->key[i]); + + OT_FREE_CLEAR((*text_map)->key); + } + + if ((*text_map)->value != nullptr) { + if (flags & OTC_TEXT_MAP_FREE_VALUE) + for (size_t i = 0; i < (*text_map)->count; i++) + OT_FREE((*text_map)->value[i]); + + OT_FREE_CLEAR((*text_map)->value); + } + + if ((*text_map)->is_dynamic) { + OT_FREE_CLEAR(*text_map); + } else { + (*text_map)->count = 0; + (*text_map)->size = 0; + } +} + + +/*** + * NAME + * otc_binary_data_new - + * + * ARGUMENTS + * binary_data - + * data - + * size - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_binary_data *otc_binary_data_new(struct otc_binary_data *binary_data, const void *data, size_t size) +{ + struct otc_binary_data *retptr = binary_data; + + if (retptr == nullptr) + retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr))); + + if (retptr != nullptr) { + retptr->size = size; + retptr->is_dynamic = binary_data == nullptr; + + if ((data == nullptr) || (size == 0)) + /* Do nothing. */; + else if ((retptr->data = OTC_DBG_MALLOC(size)) != nullptr) + (void)memcpy(retptr->data, data, size); + else + otc_binary_data_destroy(&retptr); + } + + return retptr; +} + + +/*** + * NAME + * otc_binary_data_destroy - + * + * ARGUMENTS + * binary_data - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void otc_binary_data_destroy(struct otc_binary_data **binary_data) +{ + if ((binary_data == nullptr) || (*binary_data == nullptr)) + return; + + OT_FREE_CLEAR((*binary_data)->data); + + if ((*binary_data)->is_dynamic) + OT_FREE_CLEAR(*binary_data); + else + (*binary_data)->size = 0; +} + + +/*** + * NAME + * otc_strerror - + * + * ARGUMENTS + * errnum - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +const char *otc_strerror(int errnum) +{ + static __THR char retbuf[1024]; + const char *retptr = retbuf; + + errno = 0; + (void)strerror_r(errnum, retbuf, sizeof(retbuf)); + if (errno != 0) + retptr = "Unknown error"; + + return retptr; +} + + +/*** + * NAME + * otc_file_read - + * + * ARGUMENTS + * filename - + * comment - + * errbuf - + * errbufsiz - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +char *otc_file_read(const char *filename, const char *comment, char *errbuf, int errbufsiz) +{ + struct stat statbuf; + char *retptr = nullptr; + int fd, rc; + + if (filename == nullptr) + return retptr; + + if ((fd = open(filename, O_RDONLY)) == -1) { + (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno)); + } + else if ((rc = fstat(fd, &statbuf)) == -1) { + (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno)); + } + else if ((retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_MALLOC(statbuf.st_size + 1))) == nullptr) { + (void)snprintf(errbuf, errbufsiz, "cannot allocate memory: %s", otc_strerror(errno)); + } + else { + char *buf = retptr; + off_t size = statbuf.st_size; + + while (size > 0) { + ssize_t n; + + if ((n = read(fd, buf, size)) > 0) { + size -= n; + buf += n; + } + else if (n == -1) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + break; + } + else if (errno != EINTR) + { + (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno)); + OT_FREE_CLEAR(retptr); + + break; + } + } + else { + break; + } + } + + if (comment != nullptr) { + off_t i = 0, c = -1, n = statbuf.st_size; + + for (i = 0; i < n; i++) + if (c < 0) { + /* Remember the starting position of the comment line. */ + if ((strchr(comment, retptr[i]) != nullptr) && ((i == 0) || (retptr[i - 1] == '\n'))) + c = i; + } + else if ((retptr[i] == '\n') && ((i + 1) < n)) { + /* Delete the entire comment line. */ + (void)memmove(retptr + c, retptr + i + 1, n - i - 1); + + n -= i + 1 - c; + i = c - 1; + c = -1; + } + + /* If a comment remains in the last line, delete it. */ + if (c >= 0) { + n -= i - c; + i = c; + } + + retptr[i] = '\0'; + } + else if (size != 0) + OT_FREE_CLEAR(retptr); + } + + (void)close(fd); + + return retptr; +} + + +/*** + * NAME + * otc_statistics - + * + * ARGUMENTS + * buffer - + * bufsiz - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void otc_statistics(char *buffer, size_t bufsiz) +{ + if ((buffer == nullptr) || (bufsiz < 24)) + return; + + (void)snprintf(buffer, bufsiz, "span: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64 ", context: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64, + ot_span.key, ot_span_handle.size(), ot_span.erase_cnt, ot_span.destroy_cnt, ot_span.alloc_fail_cnt, + ot_span_context.key, ot_span_context_handle.size(), ot_span_context.erase_cnt, ot_span_context.destroy_cnt, ot_span_context.alloc_fail_cnt); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ |