diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/Makefile | 20 | ||||
-rw-r--r-- | main/config.c | 33 | ||||
-rw-r--r-- | main/core_unreal.c | 2 | ||||
-rw-r--r-- | main/rtp_engine.c | 29 | ||||
-rw-r--r-- | main/sdp_srtp.c | 2 | ||||
-rw-r--r-- | main/stringfields.c | 508 | ||||
-rw-r--r-- | main/utils.c | 373 |
7 files changed, 567 insertions, 400 deletions
diff --git a/main/Makefile b/main/Makefile index 50fdc5739..d52c3f0a7 100644 --- a/main/Makefile +++ b/main/Makefile @@ -225,11 +225,11 @@ endif $(ASTSSL_LIB): $(ASTSSL_LIB).$(ASTSSL_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" -ifneq ($(LDCONFIG),) - $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null -else - $(CMD_PREFIX) $(LN) -sf $< $@ -endif + $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ + $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ + else \ + $(LN) -sf $< $@ ;\ + fi else # Darwin ASTSSL_LIB:=libasteriskssl.dylib @@ -305,11 +305,11 @@ $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): libasteriskpj.o libasteriskpj.exports $(ASTPJ_LIB): $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" -ifneq ($(LDCONFIG),) - $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null -else - $(CMD_PREFIX) $(LN) -sf $< $@ -endif + $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ + $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ + else \ + $(LN) -sf $< $@ ;\ + fi else # Darwin ASTPJ_LIB:=libasteriskpj.dylib diff --git a/main/config.c b/main/config.c index a9ea01a8b..dad3b668b 100644 --- a/main/config.c +++ b/main/config.c @@ -72,7 +72,8 @@ static char *extconfig_conf = "extconfig.conf"; static struct ao2_container *cfg_hooks; static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg); static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2); -static int does_category_match(struct ast_category *cat, const char *category_name, const char *match); +static int does_category_match(struct ast_category *cat, const char *category_name, + const char *match, char sep); /*! \brief Structure to keep comments for rewriting configuration files */ struct ast_comment { @@ -864,7 +865,8 @@ static void move_variables(struct ast_category *old, struct ast_category *new) /*! \brief Returns true if ALL of the regex expressions and category name match. * Both can be NULL (I.E. no predicate) which results in a true return; */ -static int does_category_match(struct ast_category *cat, const char *category_name, const char *match) +static int does_category_match(struct ast_category *cat, const char *category_name, + const char *match, char sep) { char *dupmatch; char *nvp = NULL; @@ -883,7 +885,7 @@ static int does_category_match(struct ast_category *cat, const char *category_na dupmatch = ast_strdupa(match); - while ((nvp = ast_strsep(&dupmatch, ',', AST_STRSEP_STRIP))) { + while ((nvp = ast_strsep(&dupmatch, sep, AST_STRSEP_STRIP))) { struct ast_variable *v; char *match_name; char *match_value = NULL; @@ -982,19 +984,19 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_ return new_category(name, in_file, lineno, 1); } -struct ast_category *ast_category_get(const struct ast_config *config, - const char *category_name, const char *filter) +static struct ast_category *category_get_sep(const struct ast_config *config, + const char *category_name, const char *filter, char sep) { struct ast_category *cat; for (cat = config->root; cat; cat = cat->next) { - if (cat->name == category_name && does_category_match(cat, category_name, filter)) { + if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) { return cat; } } for (cat = config->root; cat; cat = cat->next) { - if (does_category_match(cat, category_name, filter)) { + if (does_category_match(cat, category_name, filter, sep)) { return cat; } } @@ -1002,6 +1004,12 @@ struct ast_category *ast_category_get(const struct ast_config *config, return NULL; } +struct ast_category *ast_category_get(const struct ast_config *config, + const char *category_name, const char *filter) +{ + return category_get_sep(config, category_name, filter, ','); +} + const char *ast_category_get_name(const struct ast_category *category) { return category->name; @@ -1125,7 +1133,7 @@ static void ast_includes_destroy(struct ast_config_include *incls) static struct ast_category *next_available_category(struct ast_category *cat, const char *name, const char *filter) { - for (; cat && !does_category_match(cat, name, filter); cat = cat->next); + for (; cat && !does_category_match(cat, name, filter, ','); cat = cat->next); return cat; } @@ -1777,8 +1785,13 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat, while ((cur = strsep(&c, ","))) { if (!strcasecmp(cur, "!")) { (*cat)->ignored = 1; - } else if (!strcasecmp(cur, "+")) { - *cat = ast_category_get(cfg, catname, NULL); + } else if (cur[0] == '+') { + char *filter = NULL; + + if (cur[1] != ',') { + filter = &cur[1]; + } + *cat = category_get_sep(cfg, catname, filter, '&'); if (!(*cat)) { if (newcat) { ast_category_destroy(newcat); diff --git a/main/core_unreal.c b/main/core_unreal.c index da0bb43bb..1f5c202ba 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -805,9 +805,11 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge return -1; } + /* The bridge thread now controls the chan ref from the ast_unreal_pvt */ ao2_lock(p); ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); + ast_channel_unref(chan); return 0; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index fd472ba72..11e94c699 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -188,6 +188,8 @@ struct ast_rtp_instance { struct ast_rtp_glue *glue; /*! SRTP info associated with the instance */ struct ast_srtp *srtp; + /*! SRTP info dedicated for RTCP associated with the instance */ + struct ast_srtp *rtcp_srtp; /*! Channel unique ID */ char channel_uniqueid[AST_MAX_UNIQUEID]; /*! Time of last packet sent */ @@ -364,6 +366,10 @@ static void instance_destructor(void *obj) res_srtp->destroy(instance->srtp); } + if (instance->rtcp_srtp) { + res_srtp->destroy(instance->rtcp_srtp); + } + ast_rtp_codecs_payloads_destroy(&instance->codecs); /* Drop our engine reference */ @@ -2052,29 +2058,38 @@ int ast_rtp_engine_srtp_is_registered(void) return res_srtp && res_srtp_policy; } -int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy) +int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy, int rtcp) { int res = 0; + struct ast_srtp **srtp; if (!res_srtp) { return -1; } - if (!instance->srtp) { - res = res_srtp->create(&instance->srtp, instance, remote_policy); + + srtp = rtcp ? &instance->rtcp_srtp : &instance->srtp; + + if (!*srtp) { + res = res_srtp->create(srtp, instance, remote_policy); } else { - res = res_srtp->replace(&instance->srtp, instance, remote_policy); + res = res_srtp->replace(srtp, instance, remote_policy); } if (!res) { - res = res_srtp->add_stream(instance->srtp, local_policy); + res = res_srtp->add_stream(*srtp, local_policy); } return res; } -struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance) +struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, int rtcp) { - return instance->srtp; + if (rtcp && instance->rtcp_srtp) { + return instance->rtcp_srtp; + } + else { + return instance->srtp; + } } int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level) diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index e576258c3..c92387bc2 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -183,7 +183,7 @@ static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned cha } /* Add the SRTP policies */ - if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy)) { + if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy, 0)) { ast_log(LOG_WARNING, "Could not set SRTP policies\n"); goto err; } diff --git a/main/stringfields.c b/main/stringfields.c new file mode 100644 index 000000000..67dd06c9b --- /dev/null +++ b/main/stringfields.c @@ -0,0 +1,508 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Kevin P. Fleming <kpfleming@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief String fields + * + * \author Kevin P. Fleming <kpfleming@digium.com> + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/stringfields.h" +#include "asterisk/utils.h" + +/* this is a little complex... string fields are stored with their + allocated size in the bytes preceding the string; even the + constant 'empty' string has to be this way, so the code that + checks to see if there is enough room for a new string doesn't + have to have any special case checks +*/ + +static const struct { + ast_string_field_allocation allocation; + char string[1]; +} __ast_string_field_empty_buffer; + +ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string; + +#define ALLOCATOR_OVERHEAD 48 + +static size_t optimal_alloc_size(size_t size) +{ + unsigned int count; + + size += ALLOCATOR_OVERHEAD; + + for (count = 1; size; size >>= 1, count++); + + return (1 << count) - ALLOCATOR_OVERHEAD; +} + +static void *calloc_wrapper(unsigned int num_structs, size_t struct_size, + const char *file, int lineno, const char *func) +{ +#if defined(__AST_DEBUG_MALLOC) + return __ast_calloc(num_structs, struct_size, file, lineno, func); +#else + return ast_calloc(num_structs, struct_size); +#endif +} + +/*! \brief add a new block to the pool. + * We can only allocate from the topmost pool, so the + * fields in *mgr reflect the size of that only. + */ +static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, + size_t size, const char *file, int lineno, const char *func) +{ + struct ast_string_field_pool *pool; + size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size); + + if (!(pool = calloc_wrapper(1, alloc_size, file, lineno, func))) { + return -1; + } + + pool->prev = *pool_head; + pool->size = alloc_size - sizeof(*pool); + *pool_head = pool; + mgr->last_alloc = NULL; + + return 0; +} + +static void reset_field(const char **p) +{ + *p = __ast_string_field_empty; +} + +/*! + * \brief Internal cleanup function + * \internal + * \param mgr + * \param pool_head + * \param cleanup_type + * 0: Reset all string fields and free all pools except the last or embedded pool. + * Keep the internal management structures so the structure can be reused. + * -1: Reset all string fields and free all pools except the embedded pool. + * Free the internal management structures. + * \param file + * \param lineno + * \param func + * + * \retval 0 Success + * \retval -1 Failure + */ +int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type, + const char *file, int lineno, const char *func) +{ + struct ast_string_field_pool *cur = NULL; + struct ast_string_field_pool *preserve = NULL; + + if (!mgr->header) { + return -1; + } + + /* reset all the fields regardless of cleanup type */ + AST_VECTOR_CALLBACK_VOID(&mgr->header->string_fields, reset_field); + + switch (cleanup_type) { + case AST_STRINGFIELD_DESTROY: + AST_VECTOR_FREE(&mgr->header->string_fields); + + if (mgr->header->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */ + preserve = mgr->header->embedded_pool; + preserve->used = preserve->active = 0; + } + + ast_free(mgr->header); + mgr->header = NULL; + break; + case AST_STRINGFIELD_RESET: + /* Preserve the embedded pool if there is one, otherwise the last pool */ + if (mgr->header->embedded_pool) { + preserve = mgr->header->embedded_pool; + } else { + if (*pool_head == NULL) { + ast_log(LOG_WARNING, "trying to reset empty pool\n"); + return -1; + } + preserve = *pool_head; + } + preserve->used = preserve->active = 0; + break; + default: + return -1; + } + + cur = *pool_head; + while (cur) { + struct ast_string_field_pool *prev = cur->prev; + + if (cur != preserve) { + ast_free(cur); + } + cur = prev; + } + + *pool_head = preserve; + if (preserve) { + preserve->prev = NULL; + } + + return 0; +} + +/*! + * \brief Internal initialization function + * \internal + * \param mgr + * \param pool_head + * \param needed + * \param file + * \param lineno + * \param func + * + * \retval 0 Success + * \retval -1 Failure + */ +int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, + int needed, const char *file, int lineno, const char *func) +{ + const char **p = (const char **) pool_head + 1; + size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p); + + if (needed <= 0) { + return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func); + } + + mgr->last_alloc = NULL; +#if defined(__AST_DEBUG_MALLOC) + mgr->owner_file = file; + mgr->owner_func = func; + mgr->owner_line = lineno; +#endif + + if (!(mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func))) { + return -1; + } + + if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { + ast_free(mgr->header); + mgr->header = NULL; + return -1; + } + + while ((struct ast_string_field_mgr *) p != mgr) { + AST_VECTOR_APPEND(&mgr->header->string_fields, p); + *p++ = __ast_string_field_empty; + } + + *pool_head = NULL; + mgr->header->embedded_pool = NULL; + if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) { + AST_VECTOR_FREE(&mgr->header->string_fields); + ast_free(mgr->header); + mgr->header = NULL; + return -1; + } + + return 0; +} + +ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, size_t needed) +{ + char *result = NULL; + size_t space = (*pool_head)->size - (*pool_head)->used; + size_t to_alloc; + + /* Make room for ast_string_field_allocation and make it a multiple of that. */ + to_alloc = ast_make_room_for(needed, ast_string_field_allocation); + ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0); + + if (__builtin_expect(to_alloc > space, 0)) { + size_t new_size = (*pool_head)->size; + + while (new_size < to_alloc) { + new_size *= 2; + } + +#if defined(__AST_DEBUG_MALLOC) + if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) + return NULL; +#else + if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) + return NULL; +#endif + } + + /* pool->base is always aligned (gcc aligned attribute). We ensure that + * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation) + * causing result to always be aligned as well; which in turn fixes that + * AST_STRING_FIELD_ALLOCATION(result) is aligned. */ + result = (*pool_head)->base + (*pool_head)->used; + (*pool_head)->used += to_alloc; + (*pool_head)->active += needed; + result += ast_alignof(ast_string_field_allocation); + AST_STRING_FIELD_ALLOCATION(result) = needed; + mgr->last_alloc = result; + + return result; +} + +int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr) +{ + ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr); + size_t space = (*pool_head)->size - (*pool_head)->used; + + if (*ptr != mgr->last_alloc) { + return 1; + } + + if (space < grow) { + return 1; + } + + (*pool_head)->used += grow; + (*pool_head)->active += grow; + AST_STRING_FIELD_ALLOCATION(*ptr) += grow; + + return 0; +} + +void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, + const ast_string_field ptr) +{ + struct ast_string_field_pool *pool, *prev; + + if (ptr == __ast_string_field_empty) { + return; + } + + for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) { + if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) { + pool->active -= AST_STRING_FIELD_ALLOCATION(ptr); + if (pool->active == 0) { + if (prev) { + prev->prev = pool->prev; + ast_free(pool); + } else { + pool->used = 0; + } + } + break; + } + } +} + +void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, ast_string_field *ptr, + const char *format, va_list ap) +{ + size_t needed; + size_t available; + size_t space = (*pool_head)->size - (*pool_head)->used; + int res; + ssize_t grow; + char *target; + va_list ap2; + + /* if the field already has space allocated, try to reuse it; + otherwise, try to use the empty space at the end of the current + pool + */ + if (*ptr != __ast_string_field_empty) { + target = (char *) *ptr; + available = AST_STRING_FIELD_ALLOCATION(*ptr); + if (*ptr == mgr->last_alloc) { + available += space; + } + } else { + /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation) + * so we don't need to re-align anything here. + */ + target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation); + if (space > ast_alignof(ast_string_field_allocation)) { + available = space - ast_alignof(ast_string_field_allocation); + } else { + available = 0; + } + } + + va_copy(ap2, ap); + res = vsnprintf(target, available, format, ap2); + va_end(ap2); + + if (res < 0) { + /* Are we out of memory? */ + return; + } + if (res == 0) { + __ast_string_field_release_active(*pool_head, *ptr); + *ptr = __ast_string_field_empty; + return; + } + needed = (size_t)res + 1; /* NUL byte */ + + if (needed > available) { + /* the allocation could not be satisfied using the field's current allocation + (if it has one), or the space available in the pool (if it does not). allocate + space for it, adding a new string pool if necessary. + */ + if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) { + return; + } + vsprintf(target, format, ap); + va_end(ap); /* XXX va_end without va_start? */ + __ast_string_field_release_active(*pool_head, *ptr); + *ptr = target; + } else if (*ptr != target) { + /* the allocation was satisfied using available space in the pool, but not + using the space already allocated to the field + */ + __ast_string_field_release_active(*pool_head, *ptr); + mgr->last_alloc = *ptr = target; + ast_assert(needed < (ast_string_field_allocation)-1); + AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed; + (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation); + (*pool_head)->active += needed; + } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { + /* the allocation was satisfied by using available space in the pool *and* + the field was the last allocated field from the pool, so it grew + */ + AST_STRING_FIELD_ALLOCATION(*ptr) += grow; + (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation); + (*pool_head)->active += grow; + } +} + +void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap); + va_end(ap); +} + +void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, + size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file, + int lineno, const char *func) +{ + struct ast_string_field_mgr *mgr; + struct ast_string_field_pool *pool; + struct ast_string_field_pool **pool_head; + size_t pool_size_needed = sizeof(*pool) + pool_size; + size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed); + void *allocation; + const char **p; + size_t initial_vector_size; + + ast_assert(num_structs == 1); + + if (!(allocation = calloc_wrapper(num_structs, size_to_alloc, file, lineno, func))) { + return NULL; + } + + mgr = allocation + field_mgr_offset; + + /* + * The header is calloced in __ast_string_field_init so it also gets calloced here + * so __ast_string_fields_free_memory can always just free mgr->header. + */ + mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func); + if (!mgr->header) { + ast_free(allocation); + return NULL; + } + + pool = allocation + struct_size; + pool_head = allocation + field_mgr_pool_offset; + p = (const char **) pool_head + 1; + initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p); + + if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { + ast_free(mgr->header); + ast_free(allocation); + return NULL; + } + + while ((struct ast_string_field_mgr *) p != mgr) { + AST_VECTOR_APPEND(&mgr->header->string_fields, p); + *p++ = __ast_string_field_empty; + } + + mgr->header->embedded_pool = pool; + *pool_head = pool; + pool->size = size_to_alloc - struct_size - sizeof(*pool); +#if defined(__AST_DEBUG_MALLOC) + mgr->owner_file = file; + mgr->owner_func = func; + mgr->owner_line = lineno; +#endif + + return allocation; +} + +int __ast_string_fields_cmp(struct ast_string_field_vector *left, + struct ast_string_field_vector *right) +{ + int i; + int res = 0; + + ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right)); + + for (i = 0; i < AST_VECTOR_SIZE(left); i++) { + if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) { + return res; + } + } + + return res; +} + +int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, + struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr) +{ + int i; + struct ast_string_field_vector *dest = &(copy_mgr->header->string_fields); + struct ast_string_field_vector *src = &(orig_mgr->header->string_fields); + + ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src)); + + for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { + __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i)); + *AST_VECTOR_GET(dest, i) = __ast_string_field_empty; + } + + for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { + if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i), + *AST_VECTOR_GET(src, i))) { + return -1; + } + } + + return 0; +} diff --git a/main/utils.c b/main/utils.c index 6a778b90c..09839752b 100644 --- a/main/utils.c +++ b/main/utils.c @@ -61,9 +61,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/time.h" #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ -#include "asterisk/stringfields.h" - -#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ #include "asterisk/utils.h" #define AST_API_MODULE @@ -1153,7 +1150,7 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_ "Usage: core show locks\n" " This command is for lock debugging. It prints out which locks\n" "are owned by each active thread.\n"; - ast_cli_allow_on_shutdown(e); + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: @@ -2023,374 +2020,6 @@ char *ast_to_camel_case_delim(const char *s, const char *delim) return res; } -/* - * stringfields support routines. - */ - -/* this is a little complex... string fields are stored with their - allocated size in the bytes preceding the string; even the - constant 'empty' string has to be this way, so the code that - checks to see if there is enough room for a new string doesn't - have to have any special case checks -*/ - -static const struct { - ast_string_field_allocation allocation; - char string[1]; -} __ast_string_field_empty_buffer; - -ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string; - -#define ALLOCATOR_OVERHEAD 48 - -static size_t optimal_alloc_size(size_t size) -{ - unsigned int count; - - size += ALLOCATOR_OVERHEAD; - - for (count = 1; size; size >>= 1, count++); - - return (1 << count) - ALLOCATOR_OVERHEAD; -} - -/*! \brief add a new block to the pool. - * We can only allocate from the topmost pool, so the - * fields in *mgr reflect the size of that only. - */ -static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - size_t size, const char *file, int lineno, const char *func) -{ - struct ast_string_field_pool *pool; - size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size); - -#if defined(__AST_DEBUG_MALLOC) - if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) { - return -1; - } -#else - if (!(pool = ast_calloc(1, alloc_size))) { - return -1; - } -#endif - - pool->prev = *pool_head; - pool->size = alloc_size - sizeof(*pool); - *pool_head = pool; - mgr->last_alloc = NULL; - - return 0; -} - -/* - * This is an internal API, code should not use it directly. - * It initializes all fields as empty, then uses 'size' for 3 functions: - * size > 0 means initialize the pool list with a pool of given size. - * This must be called right after allocating the object. - * size = 0 means release all pools except the most recent one. - * If the first pool was allocated via embedding in another - * object, that pool will be preserved instead. - * This is useful to e.g. reset an object to the initial value. - * size < 0 means release all pools. - * This must be done before destroying the object. - */ -int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - int needed, const char *file, int lineno, const char *func) -{ - const char **p = (const char **) pool_head + 1; - struct ast_string_field_pool *cur = NULL; - struct ast_string_field_pool *preserve = NULL; - - /* clear fields - this is always necessary */ - while ((struct ast_string_field_mgr *) p != mgr) { - *p++ = __ast_string_field_empty; - } - - mgr->last_alloc = NULL; -#if defined(__AST_DEBUG_MALLOC) - mgr->owner_file = file; - mgr->owner_func = func; - mgr->owner_line = lineno; -#endif - if (needed > 0) { /* allocate the initial pool */ - *pool_head = NULL; - mgr->embedded_pool = NULL; - return add_string_pool(mgr, pool_head, needed, file, lineno, func); - } - - /* if there is an embedded pool, we can't actually release *all* - * pools, we must keep the embedded one. if the caller is about - * to free the structure that contains the stringfield manager - * and embedded pool anyway, it will be freed as part of that - * operation. - */ - if ((needed < 0) && mgr->embedded_pool) { - needed = 0; - } - - if (needed < 0) { /* reset all pools */ - cur = *pool_head; - } else if (mgr->embedded_pool) { /* preserve the embedded pool */ - preserve = mgr->embedded_pool; - cur = *pool_head; - } else { /* preserve the last pool */ - if (*pool_head == NULL) { - ast_log(LOG_WARNING, "trying to reset empty pool\n"); - return -1; - } - preserve = *pool_head; - cur = preserve->prev; - } - - if (preserve) { - preserve->prev = NULL; - preserve->used = preserve->active = 0; - } - - while (cur) { - struct ast_string_field_pool *prev = cur->prev; - - if (cur != preserve) { - ast_free(cur); - } - cur = prev; - } - - *pool_head = preserve; - - return 0; -} - -ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, size_t needed) -{ - char *result = NULL; - size_t space = (*pool_head)->size - (*pool_head)->used; - size_t to_alloc; - - /* Make room for ast_string_field_allocation and make it a multiple of that. */ - to_alloc = ast_make_room_for(needed, ast_string_field_allocation); - ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0); - - if (__builtin_expect(to_alloc > space, 0)) { - size_t new_size = (*pool_head)->size; - - while (new_size < to_alloc) { - new_size *= 2; - } - -#if defined(__AST_DEBUG_MALLOC) - if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) - return NULL; -#else - if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) - return NULL; -#endif - } - - /* pool->base is always aligned (gcc aligned attribute). We ensure that - * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation) - * causing result to always be aligned as well; which in turn fixes that - * AST_STRING_FIELD_ALLOCATION(result) is aligned. */ - result = (*pool_head)->base + (*pool_head)->used; - (*pool_head)->used += to_alloc; - (*pool_head)->active += needed; - result += ast_alignof(ast_string_field_allocation); - AST_STRING_FIELD_ALLOCATION(result) = needed; - mgr->last_alloc = result; - - return result; -} - -int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, size_t needed, - const ast_string_field *ptr) -{ - ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr); - size_t space = (*pool_head)->size - (*pool_head)->used; - - if (*ptr != mgr->last_alloc) { - return 1; - } - - if (space < grow) { - return 1; - } - - (*pool_head)->used += grow; - (*pool_head)->active += grow; - AST_STRING_FIELD_ALLOCATION(*ptr) += grow; - - return 0; -} - -void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, - const ast_string_field ptr) -{ - struct ast_string_field_pool *pool, *prev; - - if (ptr == __ast_string_field_empty) { - return; - } - - for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) { - if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) { - pool->active -= AST_STRING_FIELD_ALLOCATION(ptr); - if (pool->active == 0) { - if (prev) { - prev->prev = pool->prev; - ast_free(pool); - } else { - pool->used = 0; - } - } - break; - } - } -} - -void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, - ast_string_field *ptr, const char *format, va_list ap) -{ - size_t needed; - size_t available; - size_t space = (*pool_head)->size - (*pool_head)->used; - int res; - ssize_t grow; - char *target; - va_list ap2; - - /* if the field already has space allocated, try to reuse it; - otherwise, try to use the empty space at the end of the current - pool - */ - if (*ptr != __ast_string_field_empty) { - target = (char *) *ptr; - available = AST_STRING_FIELD_ALLOCATION(*ptr); - if (*ptr == mgr->last_alloc) { - available += space; - } - } else { - /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation) - * so we don't need to re-align anything here. - */ - target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation); - if (space > ast_alignof(ast_string_field_allocation)) { - available = space - ast_alignof(ast_string_field_allocation); - } else { - available = 0; - } - } - - va_copy(ap2, ap); - res = vsnprintf(target, available, format, ap2); - va_end(ap2); - - if (res < 0) { - /* Are we out of memory? */ - return; - } - if (res == 0) { - __ast_string_field_release_active(*pool_head, *ptr); - *ptr = __ast_string_field_empty; - return; - } - needed = (size_t)res + 1; /* NUL byte */ - - if (needed > available) { - /* the allocation could not be satisfied using the field's current allocation - (if it has one), or the space available in the pool (if it does not). allocate - space for it, adding a new string pool if necessary. - */ - if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) { - return; - } - vsprintf(target, format, ap); - va_end(ap); /* XXX va_end without va_start? */ - __ast_string_field_release_active(*pool_head, *ptr); - *ptr = target; - } else if (*ptr != target) { - /* the allocation was satisfied using available space in the pool, but not - using the space already allocated to the field - */ - __ast_string_field_release_active(*pool_head, *ptr); - mgr->last_alloc = *ptr = target; - ast_assert(needed < (ast_string_field_allocation)-1); - AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed; - (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation); - (*pool_head)->active += needed; - } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { - /* the allocation was satisfied by using available space in the pool *and* - the field was the last allocated field from the pool, so it grew - */ - AST_STRING_FIELD_ALLOCATION(*ptr) += grow; - (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation); - (*pool_head)->active += grow; - } -} - -void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, - ast_string_field *ptr, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap); - va_end(ap); -} - -void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset, - size_t field_mgr_pool_offset, size_t pool_size, const char *file, - int lineno, const char *func) -{ - struct ast_string_field_mgr *mgr; - struct ast_string_field_pool *pool; - struct ast_string_field_pool **pool_head; - size_t pool_size_needed = sizeof(*pool) + pool_size; - size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed); - void *allocation; - unsigned int x; - -#if defined(__AST_DEBUG_MALLOC) - if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) { - return NULL; - } -#else - if (!(allocation = ast_calloc(num_structs, size_to_alloc))) { - return NULL; - } -#endif - - for (x = 0; x < num_structs; x++) { - void *base = allocation + (size_to_alloc * x); - const char **p; - - mgr = base + field_mgr_offset; - pool_head = base + field_mgr_pool_offset; - pool = base + struct_size; - - p = (const char **) pool_head + 1; - while ((struct ast_string_field_mgr *) p != mgr) { - *p++ = __ast_string_field_empty; - } - - mgr->embedded_pool = pool; - *pool_head = pool; - pool->size = size_to_alloc - struct_size - sizeof(*pool); -#if defined(__AST_DEBUG_MALLOC) - mgr->owner_file = file; - mgr->owner_func = func; - mgr->owner_line = lineno; -#endif - } - - return allocation; -} - -/* end of stringfields support */ - AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */ int ast_atomic_fetchadd_int_slow(volatile int *p, int v) |