summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/Makefile20
-rw-r--r--main/config.c33
-rw-r--r--main/core_unreal.c2
-rw-r--r--main/rtp_engine.c29
-rw-r--r--main/sdp_srtp.c2
-rw-r--r--main/stringfields.c508
-rw-r--r--main/utils.c373
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)