mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-01 19:43:03 +00:00
Simplify the implementation and the API for stringfields;
details and examples are in include/asterisk/stringfields.h. Not applicable to older branches except for 1.4 which will receive a fix for the routines that free memory pools. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88454 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,36 +259,21 @@ 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)
|
||||
|
||||
/*!
|
||||
\brief Set a field to a complex (built) value with prebuilt va_lists.
|
||||
\param x Pointer to a structure containing fields
|
||||
\param index Index position of the field within the structure
|
||||
\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
|
||||
\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_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
|
||||
@@ -312,7 +284,19 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
|
||||
\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)
|
||||
__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 with prebuilt va_lists.
|
||||
\param x Pointer to a structure containing fields
|
||||
\param ptr Pointer to a field within the structure
|
||||
\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
|
||||
\return nothing
|
||||
*/
|
||||
#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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
107
main/utils.c
107
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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user