summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/app_meetme.c4
-rw-r--r--channels/chan_iax2.c8
-rw-r--r--channels/chan_sip.c38
-rw-r--r--include/asterisk/stringfields.h323
-rw-r--r--main/channel.c4
-rw-r--r--main/pbx.c2
-rw-r--r--main/utils.c109
-rw-r--r--res/res_features.c4
8 files changed, 228 insertions, 264 deletions
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index bb3c1e9fb..472a33263 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -4872,7 +4872,7 @@ static void destroy_trunk(struct sla_trunk *trunk)
while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
ast_free(station_ref);
- ast_string_field_free_all(trunk);
+ ast_string_field_free_memory(trunk);
ast_free(trunk);
}
@@ -4898,7 +4898,7 @@ static void destroy_station(struct sla_station *station)
while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
ast_free(trunk_ref);
- ast_string_field_free_all(station);
+ ast_string_field_free_memory(station);
ast_free(station);
}
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index dff41ecb2..dded09177 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -2152,7 +2152,7 @@ retry:
iax2_frame_free(frame.data);
jb_destroy(pvt->jb);
/* gotta free up the stringfields */
- ast_string_field_free_pools(pvt);
+ ast_string_field_free_memory(pvt);
ast_free(pvt);
}
}
@@ -9735,7 +9735,7 @@ static void peer_destructor(void *obj)
if (peer->mwi_event_sub)
ast_event_unsubscribe(peer->mwi_event_sub);
- ast_string_field_free_pools(peer);
+ ast_string_field_free_memory(peer);
}
/*! \brief Create peer structure based on configuration */
@@ -9987,7 +9987,7 @@ static void user_destructor(void *obj)
ast_variables_destroy(user->vars);
user->vars = NULL;
}
- ast_string_field_free_pools(user);
+ ast_string_field_free_memory(user);
}
/*! \brief Create in-memory user structure from configuration */
@@ -10028,7 +10028,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
if (user) {
if (firstpass) {
- ast_string_field_free_pools(user);
+ ast_string_field_free_memory(user);
memset(user, 0, sizeof(struct iax2_user));
if (ast_string_field_init(user, 32)) {
user = user_unref(user);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index d895a3689..1b1369343 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -3602,7 +3602,7 @@ static void sip_registry_destroy(struct sip_registry *reg)
ast_sched_del(sched, reg->expire);
if (reg->timeout > -1)
ast_sched_del(sched, reg->timeout);
- ast_string_field_free_pools(reg);
+ ast_string_field_free_memory(reg);
regobjs--;
ast_free(reg);
@@ -3709,7 +3709,7 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
}
ast_mutex_destroy(&p->pvt_lock);
- ast_string_field_free_pools(p);
+ ast_string_field_free_memory(p);
ast_free(p);
}
@@ -6455,7 +6455,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
if (!ast_strlen_zero(p->url)) {
add_header(resp, "Access-URL", p->url);
- ast_string_field_free(p, url);
+ ast_string_field_set(p, url, NULL);
}
return 0;
@@ -6565,7 +6565,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
if (!ast_strlen_zero(p->url)) {
add_header(req, "Access-URL", p->url);
- ast_string_field_free(p, url);
+ ast_string_field_set(p, url, NULL);
}
return 0;
@@ -6607,7 +6607,7 @@ static void temp_pvt_cleanup(void *data)
{
struct sip_pvt *p = data;
- ast_string_field_free_pools(p);
+ ast_string_field_free_memory(p);
ast_free(data);
}
@@ -6657,7 +6657,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr
__transmit_response(p, msg, req, XMIT_UNRELIABLE);
/* Free the string fields, but not the pool space */
- ast_string_field_free_all(p);
+ ast_string_field_init(p, 0);
return 0;
}
@@ -8178,7 +8178,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
} else {
p = r->call;
make_our_tag(p->tag, sizeof(p->tag)); /* create a new local tag for every register attempt */
- ast_string_field_free(p, theirtag); /* forget their old tag, so we don't match tags when getting response */
+ ast_string_field_set(p, theirtag, NULL); /* forget their old tag, so we don't match tags when getting response */
}
} else {
/* Build callid for registration if we haven't registered before */
@@ -10238,8 +10238,8 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
p->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
/* Pretend there is no required authentication */
- ast_string_field_free(p, peersecret);
- ast_string_field_free(p, peermd5secret);
+ ast_string_field_set(p, peersecret, NULL);
+ ast_string_field_set(p, peermd5secret, NULL);
}
if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, req->ignore))) {
ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
@@ -12633,13 +12633,13 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
/* table of recognised keywords, and places where they should be copied */
const struct x {
const char *key;
- int field_index;
+ const ast_string_field *field;
} *i, keys[] = {
- { "realm=", ast_string_field_index(p, realm) },
- { "nonce=", ast_string_field_index(p, nonce) },
- { "opaque=", ast_string_field_index(p, opaque) },
- { "qop=", ast_string_field_index(p, qop) },
- { "domain=", ast_string_field_index(p, domain) },
+ { "realm=", &p->realm },
+ { "nonce=", &p->nonce },
+ { "opaque=", &p->opaque },
+ { "qop=", &p->qop },
+ { "domain=", &p->domain },
{ NULL, 0 },
};
@@ -12667,7 +12667,7 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
separator = ",";
}
strsep(&c, separator); /* clear separator and move ptr */
- ast_string_field_index_set(p, i->field_index, src);
+ ast_string_field_ptr_set(p, i->field, src);
break;
}
if (i->key == NULL) /* not found, try ',' */
@@ -13285,7 +13285,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
p->options->auth_type = resp;
/* Then we AUTH */
- ast_string_field_free(p, theirtag); /* forget their old tag, so we don't match tags when getting response */
+ ast_string_field_set(p, theirtag, NULL); /* forget their old tag, so we don't match tags when getting response */
if (!req->ignore) {
if (p->authtries < MAX_AUTHTRIES)
p->invitestate = INV_CALLING;
@@ -14853,7 +14853,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
}
p->invitestate = INV_COMPLETED;
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- ast_string_field_free(p, theirtag);
+ ast_string_field_set(p, theirtag, NULL);
return 0;
}
@@ -16974,7 +16974,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
SIP/peername will still use the full contact */
if (ext) {
ast_string_field_set(p, username, ext);
- ast_string_field_free(p, fullcontact);
+ ast_string_field_set(p, fullcontact, NULL);
}
#if 0
printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h
index defa18af9..efa290593 100644
--- a/include/asterisk/stringfields.h
+++ b/include/asterisk/stringfields.h
@@ -23,60 +23,80 @@
fields in structures without requiring them to be allocated
as fixed-size buffers or requiring individual allocations for
for each field.
-
- Using this functionality is quite simple... an example structure
+
+ Using this functionality is quite simple. An example structure
with three fields is defined like this:
\code
struct sample_fields {
int x1;
AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name);
- AST_STRING_FIELD(address);
- AST_STRING_FIELD(password);
+ AST_STRING_FIELD(foo);
+ AST_STRING_FIELD(bar);
+ AST_STRING_FIELD(blah);
);
long x2;
};
\endcode
- When an instance of this structure is allocated, the fields
- (and the pool of storage for them) must be initialized:
+ When an instance of this structure is allocated (either statically or
+ dynamically), the fields and the pool of storage for them must be
+ initialized:
\code
- struct sample_fields *sample;
+ struct sample_fields *x;
- sample = calloc(1, sizeof(*sample));
- if (sample) {
- if (ast_string_field_init(sample, 256)) {
- free(sample);
- sample = NULL;
- }
- }
-
- if (!sample) {
- ...
+ x = ast_calloc(1, sizeof(*x));
+ if (x == NULL || ast_string_field_init(x, 252)) {
+ if (x)
+ ast_free(x);
+ x = NULL;
+ ... handle error
}
\endcode
+
+ Fields will default to pointing to an empty string, and will revert to
+ that when ast_string_field_set() is called with a NULL argument.
+ A string field will \b never contain NULL (this feature is not used
+ in this code, but comes from external requirements).
+
+ ast_string_field_init(x, 0) will reset fields to the
+ initial value while keeping the pool allocated.
- Fields will default to pointing to an empty string, and will
- revert to that when ast_string_field_free() is called. This means
- that a string field will \b never contain NULL.
-
- Using the fields is much like using regular 'char *' fields
- in the structure, except that writing into them must be done
- using wrapper macros defined in this file.
-
- Storing simple values into fields can be done using ast_string_field_set();
- more complex values (using printf-style format strings) can be stored
- using ast_string_field_build().
-
+ Reading the fields is much like using 'const char * const' fields in the
+ structure: you cannot write to the field or to the memory it points to
+ (XXX perhaps the latter is too much of a restriction since values
+ are not shared).
+
+ Writing to the fields must be done using the wrapper macros listed below;
+ and assignments are always by value (i.e. strings are copied):
+ * ast_string_field_set() stores a simple value;
+ * ast_string_field_build() builds the string using a printf-style;
+ * ast_string_field_build_va() is the varargs version of the above (for
+ portability reasons it uses two vararg);
+ * variants of these function allow passing a pointer to the field
+ as an argument.
+ \code
+ ast_string_field_set(x, foo, "infinite loop");
+ ast_string_field_set(x, foo, NULL); // set to an empty string
+ ast_string_field_ptr_set(x, &x->bar, "right way");
+
+ ast_string_field_build(x, blah, "%d %s", zipcode, city);
+ ast_string_field_ptr_build(x, &x->blah, "%d %s", zipcode, city);
+
+ ast_string_field_build_va(x, bar, fmt, args1, args2)
+ ast_string_field_ptr_build_va(x, &x->bar, fmt, args1, args2)
+ \endcode
+
When the structure instance is no longer needed, the fields
and their storage pool must be freed:
\code
- ast_string_field_free_all(sample);
- free(sample);
+ ast_string_field_free_memory(x);
+ ast_free(x);
\endcode
+
+ This completes the API description.
*/
#ifndef _ASTERISK_STRINGFIELDS_H
@@ -116,72 +136,57 @@ struct ast_string_field_pool {
/*!
\internal
- \brief Structure used to manage the storage for a set of string fields
+ \brief Structure used to manage the storage for a set of string fields.
+ Because of the way pools are managed, we can only allocate from the topmost
+ pool, so the numbers here reflect just that.
*/
struct ast_string_field_mgr {
- struct ast_string_field_pool *pool; /*!< the address of the pool's structure */
- size_t size; /*!< the total size of the current pool */
- size_t space; /*!< the space available in the current pool */
- size_t used; /*!< the space used in the current pool */
+ size_t size; /*!< the total size of the current pool */
+ size_t used; /*!< the space used in the current pool */
};
/*!
\internal
- \brief Initialize a field pool manager and fields
- \param mgr Pointer to the pool manager structure
- \param size Amount of storage to allocate
- \param fields Pointer to the first entry of the field array
- \param num_fields Number of fields in the array
- \return 0 on success, non-zero on failure
-*/
-int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
- ast_string_field *fields, int num_fields);
-
-/*!
- \internal
\brief Allocate space for a field
\param mgr Pointer to the pool manager structure
\param needed Amount of space needed for this field
\param fields Pointer to the first entry of the field array
- \param num_fields Number of fields in the array
\return NULL on failure, an address for the field on success.
This function will allocate the requested amount of space from
the field pool. If the requested amount of space is not available,
an additional pool will be allocated.
*/
-ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
- ast_string_field *fields, int num_fields);
+ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, size_t needed);
/*!
\internal
\brief Set a field to a complex (built) value
\param mgr Pointer to the pool manager structure
\param fields Pointer to the first entry of the field array
- \param num_fields Number of fields in the array
- \param index Index position of the field within the structure
+ \param ptr Pointer to a field within the structure
\param format printf-style format string
\return nothing
*/
-void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
- ast_string_field *fields, int num_fields,
- int index, const char *format, ...);
+void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, ...);
/*!
\internal
\brief Set a field to a complex (built) value
\param mgr Pointer to the pool manager structure
\param fields Pointer to the first entry of the field array
- \param num_fields Number of fields in the array
- \param index Index position of the field within the structure
+ \param ptr Pointer to a field within the structure
\param format printf-style format string
\param args va_list of the args for the format_string
\param args_again a copy of the first va_list for the sake of bsd not having a copy routine
\return nothing
*/
-void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
- ast_string_field *fields, int num_fields,
- int index, const char *format, va_list a1, va_list a2);
+void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, va_list a1, va_list a2);
/*!
\brief Declare a string field
@@ -191,79 +196,61 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
/*!
\brief Declare the fields needed in a structure
- \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one
+ \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one.
+ Internally, string fields are stored as a pointer to the head of the pool,
+ followed by individual string fields, and then a struct ast_string_field_mgr
+ which describes the space allocated.
+ We split the two variables so they can be used as markers around the
+ field_list, and this allows us to determine how many entries are in
+ the field, and play with them.
+ In particular, for writing to the fields, we rely on __field_mgr_pool to be
+ a non-const pointer, so we know it has the same size as ast_string_field,
+ and we can use it to locate the fields.
*/
#define AST_DECLARE_STRING_FIELDS(field_list) \
- ast_string_field __begin_field[0]; \
- field_list \
- ast_string_field __end_field[0]; \
+ struct ast_string_field_pool *__field_mgr_pool; \
+ field_list \
struct ast_string_field_mgr __field_mgr
/*!
- \brief Get the number of string fields in a structure
- \param x Pointer to a structure containing fields
- \return the number of fields in the structure's definition
-*/
-#define ast_string_field_count(x) \
- (offsetof(typeof(*(x)), __end_field) - offsetof(typeof(*(x)), __begin_field)) / sizeof(ast_string_field)
-
-/*!
- \brief Get the index of a field in a structure
- \param x Pointer to a structure containing fields
- \param field Name of the field to locate
- \return the position (index) of the field within the structure's
- array of fields
-*/
-#define ast_string_field_index(x, field) \
- (offsetof(typeof(*x), field) - offsetof(typeof(*x), __begin_field)) / sizeof(ast_string_field)
-
-/*!
\brief Initialize a field pool and fields
\param x Pointer to a structure containing fields
- \param size Amount of storage to allocate
+ \param size Amount of storage to allocate.
+ Use 0 to reset fields to the default value,
+ and release all but the most recent pool.
+ size<0 (used internally) means free all pools.
\return 0 on success, non-zero on failure
*/
#define ast_string_field_init(x, size) \
- __ast_string_field_init(&(x)->__field_mgr, size, &(x)->__begin_field[0], ast_string_field_count(x))
+ __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size)
+
+/*! \brief free all memory - to be called before destroying the object */
+#define ast_string_field_free_memory(x) \
+ __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, -1)
+
+/*! \internal \brief internal version of ast_string_field_init */
+int __ast_string_field_init(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, size_t needed);
/*!
\brief Set a field to a simple string value
\param x Pointer to a structure containing fields
- \param index Index position of the field within the structure
+ \param ptr Pointer to a field within the structure
\param data String value to be copied into the field
\return nothing
*/
-#define ast_string_field_index_set(x, index, data) do { \
- char *__zz__ = (char*)(x)->__begin_field[index]; \
- size_t __dlen__ = strlen(data); \
- if( __dlen__ == 0 ) { (x)->__begin_field[index] = __ast_string_field_empty; \
- } else { \
- if( __zz__[0] != 0 && __dlen__ <= strlen(__zz__) ) { \
- strcpy(__zz__, data); \
- } else { \
- if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__ + 1, &(x)->__begin_field[0], ast_string_field_count(x)))) \
- strcpy((char*)(x)->__begin_field[index], data); \
- } \
- } \
- } while (0)
-
-#ifdef FOR_TEST
-#define ast_string_field_index_logset(x, index, data, logstr) do { \
- char *__zz__ = (char*)(x)->__begin_field[index]; \
- size_t __dlen__ = strlen(data); \
- if( __dlen__ == 0 ) { (x)->__begin_field[index] = __ast_string_field_empty; \
- } else { \
- if( __zz__[0] != 0 && __dlen__ <= strlen(__zz__) ) { \
- ast_verbose("%s: ======replacing '%s' with '%s'\n", logstr, __zz__, data); \
- strcpy(__zz__, data); \
- } else { \
- ast_verbose("%s: ++++++allocating room for '%s' to replace '%s'\n", logstr, data, __zz__); \
- if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__ + 1, &(x)->__begin_field[0], ast_string_field_count(x)))) \
- strcpy((char*)(x)->__begin_field[index], data); \
- } \
- } \
- } while (0)
-#endif
+
+#define ast_string_field_ptr_set(x, ptr, data) do { \
+ const char *__d__ = (data); \
+ size_t __dlen__ = (__d__) ? strlen(__d__) : 0; \
+ const char **__p__ = (const char **)(ptr); \
+ if (__dlen__ == 0) \
+ *__p__ = __ast_string_field_empty; \
+ else if (__dlen__ <= strlen(*__p__)) \
+ strcpy((char *)*__p__, __d__); \
+ else if ( (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__ + 1) ) ) \
+ strcpy((char *)*__p__, __d__); \
+ } while (0)
/*!
\brief Set a field to a simple string value
@@ -272,47 +259,44 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
\param data String value to be copied into the field
\return nothing
*/
-#define ast_string_field_set(x, field, data) \
- ast_string_field_index_set(x, ast_string_field_index(x, field), data)
+#define ast_string_field_set(x, field, data) do { \
+ ast_string_field_ptr_set(x, &(x)->field, data); \
+ } while (0)
-#ifdef FOR_TEST
-#define ast_string_field_logset(x, field, data, logstr) \
- ast_string_field_index_logset(x, ast_string_field_index(x, field), data, logstr)
-#endif
/*!
\brief Set a field to a complex (built) value
\param x Pointer to a structure containing fields
- \param index Index position of the field within the structure
+ \param ptr Pointer to a field within the structure
\param fmt printf-style format string
\param args Arguments for format string
\return nothing
*/
-#define ast_string_field_index_build(x, index, fmt, args...) \
- __ast_string_field_index_build(&(x)->__field_mgr, &(x)->__begin_field[0], ast_string_field_count(x), index, fmt, args)
+#define ast_string_field_ptr_build(x, ptr, fmt, args...) \
+ __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args)
/*!
- \brief Set a field to a complex (built) value with prebuilt va_lists.
+ \brief Set a field to a complex (built) value
\param x Pointer to a structure containing fields
- \param index Index position of the field within the structure
+ \param field Name of the field to set
\param fmt printf-style format string
- \param args1 Arguments for format string in va_list format
- \param args2 a second copy of the va_list for the sake of bsd, with no va_list copy operation
+ \param args Arguments for format string
\return nothing
*/
-#define ast_string_field_index_build_va(x, index, fmt, args1, args2) \
- __ast_string_field_index_build_va(&(x)->__field_mgr, &(x)->__begin_field[0], ast_string_field_count(x), index, fmt, args1, args2)
+#define ast_string_field_build(x, field, fmt, args...) \
+ __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args)
/*!
- \brief Set a field to a complex (built) value
+ \brief Set a field to a complex (built) value with prebuilt va_lists.
\param x Pointer to a structure containing fields
- \param field Name of the field to set
+ \param ptr Pointer to a field within the structure
\param fmt printf-style format string
- \param args Arguments for format string
+ \param args1 Arguments for format string in va_list format
+ \param args2 a second copy of the va_list for the sake of bsd, with no va_list copy operation
\return nothing
*/
-#define ast_string_field_build(x, field, fmt, args...) \
- ast_string_field_index_build(x, ast_string_field_index(x, field), fmt, args)
+#define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \
+ __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args1, args2)
/*!
\brief Set a field to a complex (built) value
@@ -324,67 +308,6 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
\return nothing
*/
#define ast_string_field_build_va(x, field, fmt, args1, args2) \
- ast_string_field_index_build_va(x, ast_string_field_index(x, field), fmt, args1, args2)
-
-/*!
- \brief Free a field's value.
- \param x Pointer to a structure containing fields
- \param index Index position of the field within the structure
- \return nothing
-
- \note Because of the storage pool used, the memory
- occupied by the field's value is \b not recovered; the field
- pointer is just changed to point to an empty string.
-*/
-#define ast_string_field_index_free(x, index) do { \
- (x)->__begin_field[index] = __ast_string_field_empty; \
- } while(0)
-
-/*!
- \brief Free a field's value.
- \param x Pointer to a structure containing fields
- \param field Name of the field to free
- \return nothing
-
- \note Because of the storage pool used, the memory
- occupied by the field's value is \b not recovered; the field
- pointer is just changed to point to an empty string.
-*/
-#define ast_string_field_free(x, field) \
- ast_string_field_index_free(x, ast_string_field_index(x, field))
-
-/*!
- \brief Free the stringfield storage pools attached to a structure
- \param x Pointer to a structure containing fields
- \return nothing.
-
- After calling this macro, fields can no longer be accessed in
- structure; it should only be called immediately before freeing
- the structure itself.
-*/
-#define ast_string_field_free_pools(x) do { \
- struct ast_string_field_pool *this, *prev; \
- for (this = (x)->__field_mgr.pool; this; this = prev) { \
- prev = this->prev; \
- free(this); \
- } \
- } while(0)
-
-/*!
- \brief Free the stringfields in a structure
- \param x Pointer to a structure containing fields
- \return nothing.
-
- After calling this macro, the most recently allocated pool
- attached to the structure will be available for use by
- stringfields again.
-*/
-#define ast_string_field_free_all(x) do { \
- int index; \
- for (index = 0; index < ast_string_field_count(x); index++) \
- ast_string_field_index_free(x, index); \
- (x)->__field_mgr.used = 0; \
- (x)->__field_mgr.space = (x)->__field_mgr.size; \
- } while(0)
+ __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args1, args2)
#endif /* _ASTERISK_STRINGFIELDS_H */
diff --git a/main/channel.c b/main/channel.c
index 843c1dd27..84d5cd66a 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -678,7 +678,7 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
if (needqueue) {
if (pipe(tmp->alertpipe)) {
ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
- ast_string_field_free_pools(tmp);
+ ast_string_field_free_memory(tmp);
ast_free(tmp);
return NULL;
} else {
@@ -1171,7 +1171,7 @@ void ast_channel_free(struct ast_channel *chan)
/* Destroy the jitterbuffer */
ast_jb_destroy(chan);
- ast_string_field_free_pools(chan);
+ ast_string_field_free_memory(chan);
ast_free(chan);
AST_RWLIST_UNLOCK(&channels);
diff --git a/main/pbx.c b/main/pbx.c
index 54e464cbe..71190ae9a 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1289,7 +1289,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
static void exception_store_free(void *data)
{
struct pbx_exception *exception = data;
- ast_string_field_free_pools(exception);
+ ast_string_field_free_memory(exception);
ast_free(exception);
}
diff --git a/main/utils.c b/main/utils.c
index 5e9544bf3..79bfd5306 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1207,100 +1207,141 @@ void ast_join(char *s, size_t len, char * const w[])
s[ofs] = '\0';
}
-const char __ast_string_field_empty[] = "";
+/*
+ * stringfields support routines.
+ */
-static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
+const char __ast_string_field_empty[] = ""; /*!< the empty string */
+
+/*! \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)
{
struct ast_string_field_pool *pool;
if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
return -1;
- pool->prev = mgr->pool;
- mgr->pool = pool;
+ pool->prev = *pool_head;
+ *pool_head = pool;
mgr->size = size;
- mgr->space = size;
mgr->used = 0;
return 0;
}
-int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
- ast_string_field *fields, int num_fields)
+/*
+ * 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.
+ * 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, size_t size)
{
- int index;
-
- if (add_string_pool(mgr, size))
- return -1;
-
- for (index = 0; index < num_fields; index++)
- fields[index] = __ast_string_field_empty;
-
+ const char **p = (const char **)pool_head + 1;
+ struct ast_string_field_pool *cur = *pool_head;
+
+ /* clear fields - this is always necessary */
+ while ((struct ast_string_field_mgr *)p != mgr)
+ *p++ = __ast_string_field_empty;
+ if (size > 0) { /* allocate the initial pool */
+ *pool_head = NULL;
+ return add_string_pool(mgr, pool_head, size);
+ }
+ if (size < 0) { /* reset all pools */
+ *pool_head = NULL;
+ } else { /* preserve the first pool */
+ if (cur == NULL) {
+ ast_log(LOG_WARNING, "trying to reset empty pool\n");
+ return -1;
+ }
+ cur = cur->prev;
+ (*pool_head)->prev = NULL;
+ mgr->used = 0;
+ }
+ while (cur) {
+ struct ast_string_field_pool *prev = cur->prev;
+ ast_free(cur);
+ cur = prev;
+ }
return 0;
}
-ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
- ast_string_field *fields, int num_fields)
+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 = mgr->size - mgr->used;
- if (__builtin_expect(needed > mgr->space, 0)) {
+ if (__builtin_expect(needed > space, 0)) {
size_t new_size = mgr->size * 2;
while (new_size < needed)
new_size *= 2;
- if (add_string_pool(mgr, new_size))
+ if (add_string_pool(mgr, pool_head, new_size))
return NULL;
}
- result = mgr->pool->base + mgr->used;
+ result = (*pool_head)->base + mgr->used;
mgr->used += needed;
- mgr->space -= needed;
return result;
}
-void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
- ast_string_field *fields, int num_fields,
- int index, const char *format, va_list ap1, va_list ap2)
+void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
{
size_t needed;
+ char *dst = (*pool_head)->base + mgr->used;
+ const char **p = (const char **)ptr;
+ size_t space = mgr->size - mgr->used;
- needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
+ /* try to write using available space */
+ needed = vsnprintf(dst, space, format, ap1) + 1;
va_end(ap1);
- if (needed > mgr->space) {
+ if (needed > space) { /* if it fails, reallocate */
size_t new_size = mgr->size * 2;
while (new_size < needed)
new_size *= 2;
- if (add_string_pool(mgr, new_size))
+ if (add_string_pool(mgr, pool_head, new_size))
return;
- vsprintf(mgr->pool->base + mgr->used, format, ap2);
+ dst = (*pool_head)->base + mgr->used;
+ vsprintf(dst, format, ap2);
}
- fields[index] = mgr->pool->base + mgr->used;
+ *p = dst;
mgr->used += needed;
- mgr->space -= needed;
}
-void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
- ast_string_field *fields, int num_fields,
- int index, const char *format, ...)
+void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, ...)
{
va_list ap1, ap2;
va_start(ap1, format);
va_start(ap2, format); /* va_copy does not exist on FreeBSD */
- __ast_string_field_index_build_va(mgr, fields, num_fields, index, format, ap1, ap2);
+ __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
va_end(ap1);
va_end(ap2);
}
+/* end of stringfields support */
AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
diff --git a/res/res_features.c b/res/res_features.c
index e32a23c69..3e47f2e57 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -1272,11 +1272,11 @@ static void ast_unregister_groups(void)
AST_RWLIST_WRLOCK(&feature_groups);
while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
- ast_string_field_free_all(fge);
+ ast_string_field_free_memory(fge);
ast_free(fge);
}
- ast_string_field_free_all(fg);
+ ast_string_field_free_memory(fg);
ast_free(fg);
}
AST_RWLIST_UNLOCK(&feature_groups);