diff --git a/asterisk.c b/asterisk.c index d9d962797eddead67a1a6186276c1d8f733848ff..b523bfb0d6b523c2aa923dc4555349a6a64c0b8c 100644 --- a/asterisk.c +++ b/asterisk.c @@ -746,23 +746,9 @@ void ast_console_puts(const char *string) ast_network_puts(string); } -static void network_verboser(const char *s, int pos, int replace, int complete) - /* ARGUSED */ -{ - if (replace) { - char *t; - if ((t = alloca(strlen(s) + 2))) { - sprintf(t, "\r%s", s); - if (complete) - ast_network_puts_mutable(t); - } else { - ast_log(LOG_ERROR, "Out of memory\n"); - ast_network_puts_mutable(s); - } - } else { - if (complete) - ast_network_puts_mutable(s); - } +static void network_verboser(const char *s) +{ + ast_network_puts_mutable(s); } static pthread_t lthread; @@ -1203,29 +1189,25 @@ static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp return NULL; } -static void console_verboser(const char *s, int pos, int replace, int complete) +static void console_verboser(const char *s) { char tmp[80]; const char *c = NULL; - /* Return to the beginning of the line */ - if (!pos) { - fprintf(stdout, "\r"); - if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) - fputs(tmp, stdout); - } - if (c) - fputs(c + pos,stdout); - else - fputs(s + pos,stdout); + + if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) || + (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) || + (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) || + (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) { + fputs(tmp, stdout); + fputs(c, stdout); + } else + fputs(s, stdout); + fflush(stdout); - if (complete) { - /* Wake up a poll()ing console */ - if (ast_opt_console && consolethread != AST_PTHREADT_NULL) - pthread_kill(consolethread, SIGURG); - } + + /* Wake up a poll()ing console */ + if (ast_opt_console && consolethread != AST_PTHREADT_NULL) + pthread_kill(consolethread, SIGURG); } static int ast_all_zeros(char *s) @@ -2427,6 +2409,14 @@ int main(int argc, char *argv[]) } } + if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) { + ast_register_verbose(console_verboser); + WELCOME_MESSAGE; + } + + if (ast_opt_console && !option_verbose) + ast_verbose("[ Booting...\n"); + if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) { ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n"); ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK); @@ -2443,7 +2433,7 @@ int main(int argc, char *argv[]) } if (ast_opt_console && !option_verbose) - ast_verbose("[ Reading Master Configuration ]"); + ast_verbose("[ Reading Master Configuration ]\n"); ast_readconfig(); if (ast_opt_dump_core) { @@ -2526,7 +2516,7 @@ int main(int argc, char *argv[]) fflush(stdout); if (ast_opt_console && !option_verbose) - ast_verbose("[ Initializing Custom Configuration Options ]"); + ast_verbose("[ Initializing Custom Configuration Options ]\n"); /* custom config setup */ register_config_cli(); read_config_maps(); @@ -2548,8 +2538,6 @@ int main(int argc, char *argv[]) exit(0); } printf(term_quit()); - ast_register_verbose(console_verboser); - WELCOME_MESSAGE; ast_remotecontrol(NULL); quit_handler(0, 0, 0, 0); exit(0); @@ -2597,15 +2585,6 @@ int main(int argc, char *argv[]) sigaddset(&sigs, SIGPIPE); sigaddset(&sigs, SIGWINCH); pthread_sigmask(SIG_BLOCK, &sigs, NULL); - if (ast_opt_console || option_verbose || ast_opt_remote) - ast_register_verbose(console_verboser); - /* Print a welcome message if desired */ - if (option_verbose || ast_opt_console) { - WELCOME_MESSAGE; - } - if (ast_opt_console && !option_verbose) - ast_verbose("[ Booting..."); - signal(SIGURG, urg_handler); signal(SIGINT, __quit_handler); signal(SIGTERM, __quit_handler); diff --git a/channel.c b/channel.c index f2700b29ec6d7beeb145b54cbc8f66ec35b8cba3..e978f4888120368095f0c3ee42f13818646683d9 100644 --- a/channel.c +++ b/channel.c @@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/transcap.h" #include "asterisk/devicestate.h" #include "asterisk/sha1.h" +#include "asterisk/threadstorage.h" #include "asterisk/slinfactory.h" struct channel_spy_trans { @@ -99,8 +100,7 @@ static int uniqueint = 0; unsigned long global_fin = 0, global_fout = 0; -static pthread_key_t state2str_buf_key; -static pthread_once_t state2str_buf_once = PTHREAD_ONCE_INIT; +AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init); #define STATE2STR_BUFSIZE 32 struct chanlist { @@ -167,15 +167,6 @@ const struct ast_cause { { AST_CAUSE_INTERWORKING, "INTERWORKING", "Interworking, unspecified" }, }; -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - struct ast_variable *ast_channeltype_list(void) { struct chanlist *cl; @@ -500,11 +491,6 @@ int ast_str2cause(const char *name) return -1; } -static void state2str_buf_key_create(void) -{ - pthread_key_create(&state2str_buf_key, FREE); -} - /*! \brief Gives the string form of a given channel state */ char *ast_state2str(int state) { @@ -532,12 +518,8 @@ char *ast_state2str(int state) case AST_STATE_PRERING: return "Pre-ring"; default: - pthread_once(&state2str_buf_once, state2str_buf_key_create); - if (!(buf = pthread_getspecific(state2str_buf_key))) { - if (!(buf = ast_malloc(STATE2STR_BUFSIZE))) - return NULL; - pthread_setspecific(state2str_buf_key, buf); - } + if (!(buf = ast_threadstorage_get(&state2str_threadbuf, STATE2STR_BUFSIZE))) + return "Unknown"; snprintf(buf, STATE2STR_BUFSIZE, "Unknown (%d)", state); return buf; } diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index d78b3f2006762bd6512558ab1bf0ad9361a640a3..2809003e670b2394c2550e5b147864219025d726 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -712,15 +712,6 @@ static AST_LIST_HEAD_STATIC(dynamic_list, iax2_thread); static void *iax2_process_thread(void *data); -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond) { ast_mutex_lock(lock); @@ -5472,7 +5463,7 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff) if (onoff) { if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL)) ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, - "Noop", ast_strdup(peer->name), FREE, "IAX2"); + "Noop", ast_strdup(peer->name), ast_free, "IAX2"); } else ast_context_remove_extension(regcontext, ext, 1, NULL); } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cbe8cbb8c1165dcc0600a0be125a9d05c8178512..0aeb0f5c322c234efbf732f8beae029af6364d2a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1538,15 +1538,6 @@ static struct ast_udptl_protocol sip_udptl = { set_udptl_peer: sip_set_udptl_peer, }; -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - /*! \brief Convert transfer status to string */ static char *referstatus2str(enum referstatus rstatus) { @@ -2253,7 +2244,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff) } if (onoff) ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop", - ast_strdup(peer->name), FREE, "SIP"); + ast_strdup(peer->name), ast_free, "SIP"); else ast_context_remove_extension(context, ext, 1, NULL); } diff --git a/cli.c b/cli.c index 6afd56d5e703b66b57b13288abebb16118973608..6e1d950392e6f564568f34c3f5be0dff568c0a41 100644 --- a/cli.c +++ b/cli.c @@ -48,62 +48,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/lock.h" #include "editline/readline/readline.h" +#include "asterisk/threadstorage.h" extern unsigned long global_fin, global_fout; -static pthread_key_t ast_cli_buf_key; -static pthread_once_t ast_cli_buf_once = PTHREAD_ONCE_INIT; +AST_THREADSTORAGE(ast_cli_buf, ast_cli_buf_init); /*! \brief Initial buffer size for resulting strings in ast_cli() */ #define AST_CLI_MAXSTRLEN 256 -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - -static void ast_cli_buf_key_create(void) -{ - pthread_key_create(&ast_cli_buf_key, FREE); -} - void ast_cli(int fd, char *fmt, ...) { - struct { - size_t len; - char str[0]; - } *buf; int res; + struct ast_dynamic_str *buf; va_list ap; - pthread_once(&ast_cli_buf_once, ast_cli_buf_key_create); - if (!(buf = pthread_getspecific(ast_cli_buf_key))) { - if (!(buf = ast_malloc(AST_CLI_MAXSTRLEN + sizeof(*buf)))) - return; - buf->len = AST_CLI_MAXSTRLEN; - pthread_setspecific(ast_cli_buf_key, buf); - } + if (!(buf = ast_dynamic_str_thread_get(&ast_cli_buf, AST_CLI_MAXSTRLEN))) + return; va_start(ap, fmt); - res = vsnprintf(buf->str, buf->len, fmt, ap); - while (res >= buf->len) { - if (!(buf = ast_realloc(buf, (buf->len * 2) + sizeof(*buf)))) { - va_end(ap); - return; - } - buf->len *= 2; - pthread_setspecific(ast_cli_buf_key, buf); - va_end(ap); - va_start(ap, fmt); - res = vsnprintf(buf->str, buf->len, fmt, ap); - } + res = ast_dynamic_str_thread_set_va(&buf, 0, &ast_cli_buf, fmt, ap); va_end(ap); - if (res > 0) + if (res != AST_DYNSTR_BUILD_FAILED) ast_carefulwrite(fd, buf->str, strlen(buf->str), 100); } diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h index a36138d8ac7bd0882a09388eeef0b804e394829c..575a1b2d3a5582b58136cdf472252ed306589a53 100644 --- a/include/asterisk/compiler.h +++ b/include/asterisk/compiler.h @@ -33,5 +33,6 @@ #endif #define attribute_const __attribute__((const)) +#define attribute_unused __attribute__((unused)) #endif /* _ASTERISK_COMPILER_H */ diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 247ac83260b4eccf15e6c0e69964ce65ae6b946b..6e486620df8a5c3ffad0d6bc427b80558d0db92c 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -77,9 +77,9 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent, void ast_verbose(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -int ast_register_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete)); -int ast_unregister_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete)); -int ast_verbose_dmesg(void (*verboser)(const char *string, int opos, int replacelast, int complete)); +int ast_register_verbose(void (*verboser)(const char *string)); +int ast_unregister_verbose(void (*verboser)(const char *string)); + void ast_console_puts(const char *string); void ast_console_puts_mutable(const char *string); diff --git a/include/asterisk/threadstorage.h b/include/asterisk/threadstorage.h new file mode 100644 index 0000000000000000000000000000000000000000..6e141a5d2d19bad1937a78db940175e067e7519a --- /dev/null +++ b/include/asterisk/threadstorage.h @@ -0,0 +1,427 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Russell Bryant <russell@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 threadstorage.h + * \author Russell Bryant <russell@digium.com> + * + * \brief Definitions to aid in the use of thread local storage +*/ + +#ifndef ASTERISK_THREADSTORAGE_H +#define ASTERISK_THREADSTORAGE_H + +#include <pthread.h> + +#include "asterisk/utils.h" +#include "asterisk/inline_api.h" + +/*! + * \brief data for a thread locally stored variable + */ +struct ast_threadstorage { + /*! Ensure that the key is only initialized by one thread */ + pthread_once_t once; + /*! The key used to retrieve this thread's data */ + pthread_key_t key; + /*! The function that initializes the key */ + void (*key_init)(void); +}; + +/*! + * \brief Define a thread storage variable + * + * \arg name The name of the thread storage + * \arg name_init This is a name used to create the function that gets called + * to initialize this thread storage. It can be anything since it will not + * be referred to anywhere else + * + * This macro would be used to declare an instance of thread storage in a file. + * + * Example usage: + * \code + * AST_THREADSTORAGE(my_buf, my_buf_init); + * \endcode + */ +#define AST_THREADSTORAGE(name, name_init) \ + AST_THREADSTORAGE_CUSTOM(name, name_init, ast_free) + +#define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup) \ +static void name_init(void); \ +static struct ast_threadstorage name = { \ + .once = PTHREAD_ONCE_INIT, \ + .key_init = name_init, \ +}; \ +static void name_init(void) \ +{ \ + pthread_key_create(&(name).key, cleanup); \ +} + +/*! + * \brief Retrieve thread storage + * + * \arg ts This is a pointer to the thread storage structure declared by using + * the AST_THREADSTORAGE macro. If declared with + * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be + * (&my_buf). + * \arg init_size This is the amount of space to be allocated the first time + * this thread requests its data. Thus, this should be the size that the + * code accessing this thread storage is assuming the size to be. + * + * \return This function will return the thread local storage associated with + * the thread storage management variable passed as the first argument. + * The result will be NULL in the case of a memory allocation error. + * + * Example usage: + * \code + * AST_THREADSTORAGE(my_buf, my_buf_init); + * #define MY_BUF_SIZE 128 + * ... + * void my_func(const char *fmt, ...) + * { + * void *buf; + * + * if (!(buf = ast_threadstorage_get(&my_buf, MY_BUF_SIZE))) + * return; + * ... + * } + * \endcode + */ +AST_INLINE_API( +void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size), +{ + void *buf; + + pthread_once(&ts->once, ts->key_init); + if (!(buf = pthread_getspecific(ts->key))) { + if (!(buf = ast_calloc(1, init_size))) + return NULL; + pthread_setspecific(ts->key, buf); + } + + return buf; +} +) + +/*! + * \brief A dynamic length string + */ +struct ast_dynamic_str { + /* The current maximum length of the string */ + size_t len; + /* The string buffer */ + char str[0]; +}; + +/*! + * \brief Create a dynamic length string + * + * \arg init_len This is the initial length of the string buffer + * + * \return This function returns a pointer to the dynamic string length. The + * result will be NULL in the case of a memory allocation error. + * + * /note The result of this function is dynamically allocated memory, and must + * be free()'d after it is no longer needed. + */ +AST_INLINE_API( +struct ast_dynamic_str *__attribute__ ((malloc)) ast_dynamic_str_create(size_t init_len), +{ + struct ast_dynamic_str *buf; + + if (!(buf = ast_calloc(1, sizeof(*buf) + init_len))) + return NULL; + + buf->len = init_len; + + return buf; +} +) + +/*! + * \brief Retrieve a thread locally stored dynamic string + * + * \arg ts This is a pointer to the thread storage structure declared by using + * the AST_THREADSTORAGE macro. If declared with + * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be + * (&my_buf). + * \arg init_len This is the initial length of the thread's dynamic string. The + * current length may be bigger if previous operations in this thread have + * caused it to increase. + * + * \return This function will return the thread locally storaged dynamic string + * associated with the thread storage management variable passed as the + * first argument. + * The result will be NULL in the case of a memory allocation error. + * + * Example usage: + * \code + * AST_THREADSTORAGE(my_str, my_str_init); + * #define MY_STR_INIT_SIZE 128 + * ... + * void my_func(const char *fmt, ...) + * { + * struct ast_dynamic_str *buf; + * + * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE))) + * return; + * ... + * } + * \endcode + */ +AST_INLINE_API( +struct ast_dynamic_str *ast_dynamic_str_thread_get(struct ast_threadstorage *ts, + size_t init_len), +{ + struct ast_dynamic_str *buf; + + if (!(buf = ast_threadstorage_get(ts, sizeof(*buf) + init_len))) + return NULL; + + if (!buf->len) + buf->len = init_len; + + return buf; +} +) + +/*! + * \brief Error codes from ast_dynamic_str_thread_build_va() + */ +enum { + /*! An error has occured and the contents of the dynamic string + * are undefined */ + AST_DYNSTR_BUILD_FAILED = -1, + /*! The buffer size for the dynamic string had to be increased, and + * ast_dynamic_str_thread_build_va() needs to be called again after + * a va_end() and va_start(). + */ + AST_DYNSTR_BUILD_RETRY = -2 +}; + +/*! + * \brief Set a thread locally stored dynamic string from a va_list + * + * \arg buf This is the address of a pointer to an ast_dynamic_str which should + * have been retrieved using ast_dynamic_str_thread_get. It will need to + * be updated in the case that the buffer has to be reallocated to + * accomodate a longer string than what it currently has space for. + * \arg max_len This is the maximum length to allow the string buffer to grow + * to. If this is set to 0, then there is no maximum length. + * \arg ts This is a pointer to the thread storage structure declared by using + * the AST_THREADSTORAGE macro. If declared with + * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be + * (&my_buf). + * \arg fmt This is the format string (printf style) + * \arg ap This is the va_list + * + * \return The return value of this function is the same as that of the printf + * family of functions. + * + * Example usage: + * \code + * AST_THREADSTORAGE(my_str, my_str_init); + * #define MY_STR_INIT_SIZE 128 + * ... + * void my_func(const char *fmt, ...) + * { + * struct ast_dynamic_str *buf; + * va_list ap; + * + * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE))) + * return; + * ... + * va_start(fmt, ap); + * ast_dynamic_str_thread_set_va(&buf, 0, &my_str, fmt, ap); + * va_end(ap); + * + * printf("This is the string we just built: %s\n", buf->str); + * ... + * } + * \endcode + */ +#define ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap) \ + ({ \ + int __res; \ + while ((__res = ast_dynamic_str_thread_build_va(buf, max_len, \ + ts, 0, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) { \ + va_end(ap); \ + va_start(ap, fmt); \ + } \ + (__res); \ + }) + +/*! + * \brief Append to a thread local dynamic string using a va_list + * + * The arguments, return values, and usage of this are the same as those for + * ast_dynamic_str_thread_set_va(). However, instead of setting a new value + * for the string, this will append to the current value. + */ +#define ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap) \ + ({ \ + int __res; \ + while ((__res = ast_dynamic_str_thread_build_va(buf, max_len, \ + ts, 1, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) { \ + va_end(ap); \ + va_start(ap, fmt); \ + } \ + (__res); \ + }) + +/*! + * \brief Core functionality of ast_dynamic_str_thread_(set|append)_va + * + * The arguments to this function are the same as those described for + * ast_dynamic_str_thread_set_va except for an addition argument, append. + * If append is non-zero, this will append to the current string instead of + * writing over it. + */ +int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len, + struct ast_threadstorage *ts, int append, const char *fmt, va_list ap); + +/*! + * \brief Set a thread locally stored dynamic string using variable arguments + * + * \arg buf This is the address of a pointer to an ast_dynamic_str which should + * have been retrieved using ast_dynamic_str_thread_get. It will need to + * be updated in the case that the buffer has to be reallocated to + * accomodate a longer string than what it currently has space for. + * \arg max_len This is the maximum length to allow the string buffer to grow + * to. If this is set to 0, then there is no maximum length. + * \arg ts This is a pointer to the thread storage structure declared by using + * the AST_THREADSTORAGE macro. If declared with + * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be + * (&my_buf). + * \arg fmt This is the format string (printf style) + * + * \return The return value of this function is the same as that of the printf + * family of functions. + * + * Example usage: + * \code + * AST_THREADSTORAGE(my_str, my_str_init); + * #define MY_STR_INIT_SIZE 128 + * ... + * void my_func(int arg1, int arg2) + * { + * struct ast_dynamic_str *buf; + * va_list ap; + * + * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE))) + * return; + * ... + * ast_dynamic_str_thread_set(&buf, 0, &my_str, "arg1: %d arg2: %d\n", + * arg1, arg2); + * + * printf("This is the string we just built: %s\n", buf->str); + * ... + * } + * \endcode + */ +AST_INLINE_API( +int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_set( + struct ast_dynamic_str **buf, size_t max_len, + struct ast_threadstorage *ts, const char *fmt, ...), +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap); + va_end(ap); + + return res; +} +) + +/*! + * \brief Append to a thread local dynamic string + * + * The arguments, return values, and usage of this function are the same as + * ast_dynamic_str_thread_set(). However, instead of setting a new value for + * the string, this function appends to the current value. + */ +AST_INLINE_API( +int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_append( + struct ast_dynamic_str **buf, size_t max_len, + struct ast_threadstorage *ts, const char *fmt, ...), +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap); + va_end(ap); + + return res; +} +) + +/*! + * \brief Set a dynamic string + * + * \arg buf This is the address of a pointer to an ast_dynamic_str. It will + * need to be updated in the case that the buffer has to be reallocated to + * accomodate a longer string than what it currently has space for. + * \arg max_len This is the maximum length to allow the string buffer to grow + * to. If this is set to 0, then there is no maximum length. + * + * \return The return value of this function is the same as that of the printf + * family of functions. + */ +AST_INLINE_API( +int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_set( + struct ast_dynamic_str **buf, size_t max_len, + const char *fmt, ...), +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = ast_dynamic_str_thread_set_va(buf, max_len, NULL, fmt, ap); + va_end(ap); + + return res; +} +) + +/*! + * \brief Append to a dynatic string + * + * The arguments, return values, and usage of this function are the same as + * ast_dynamic_str_set(). However, this function appends to the string instead + * of setting a new value. + */ +AST_INLINE_API( +int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_append( + struct ast_dynamic_str **buf, size_t max_len, + const char *fmt, ...), +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = ast_dynamic_str_thread_append_va(buf, max_len, NULL, fmt, ap); + va_end(ap); + + return res; +} +) + +#endif /* ASTERISK_THREADSTORAGE_H */ diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index ba1cd5948313f5eb860c7ab7787012b893b07e18..ea8b352fbff1692aaebb60b68ccc969b7c6f833d 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -35,6 +35,7 @@ #include "asterisk/time.h" #include "asterisk/strings.h" #include "asterisk/logger.h" +#include "asterisk/compiler.h" /*! \note \verbatim @@ -272,6 +273,22 @@ int getloadavg(double *list, int nelem); long int ast_random(void); #endif +/*! + * \brief free() wrapper + * + * ast_free should be used when a function pointer for free() needs to be passed + * as the argument to a function. Otherwise, astmm will cause seg faults. + */ +#ifdef __AST_DEBUG_MALLOC +static void ast_free(void *ptr) attribute_unused; +static void ast_free(void *ptr) +{ + free(ptr); +} +#else +#define ast_free free +#endif + #ifndef __AST_DEBUG_MALLOC /*! diff --git a/logger.c b/logger.c index a4f7c8c1d7dea348b40f0b9be39dde310c8a1a9d..532023b216708a0852596a34dc4a0a863e35517f 100644 --- a/logger.c +++ b/logger.c @@ -68,8 +68,7 @@ static int syslog_level_map[] = { #include "asterisk/cli.h" #include "asterisk/utils.h" #include "asterisk/manager.h" - -#define MAX_MSG_QUEUE 200 +#include "asterisk/threadstorage.h" #if defined(__linux__) && !defined(__NR_gettid) #include <asm/unistd.h> @@ -84,8 +83,6 @@ static int syslog_level_map[] = { static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */ -AST_MUTEX_DEFINE_STATIC(msglist_lock); -AST_MUTEX_DEFINE_STATIC(loglock); static int filesize_reload_needed = 0; static int global_logmask = -1; @@ -94,11 +91,6 @@ static struct { unsigned int event_log:1; } logfiles = { 1, 1 }; -static struct msglist { - char *msg; - struct msglist *next; -} *list = NULL, *last = NULL; - static char hostname[MAXHOSTNAMELEN]; enum logtypes { @@ -114,12 +106,10 @@ struct logchannel { enum logtypes type; /* Type of log channel */ FILE *fileptr; /* logfile logging file pointer */ char filename[256]; /* Filename */ - struct logchannel *next; /* Next channel in chain */ + AST_LIST_ENTRY(logchannel) list; }; -static struct logchannel *logchannels = NULL; - -static int msgcnt = 0; +static AST_LIST_HEAD_STATIC(logchannels, logchannel); static FILE *eventlog = NULL; static FILE *qlog = NULL; @@ -144,6 +134,12 @@ static int colors[] = { COLOR_BRGREEN }; +AST_THREADSTORAGE(verbose_buf, verbose_buf_init); +#define VERBOSE_BUF_INIT_SIZE 128 + +AST_THREADSTORAGE(log_buf, log_buf_init); +#define LOG_BUF_INIT_SIZE 128 + static int make_components(char *s, int lineno) { char *w; @@ -287,21 +283,16 @@ static struct logchannel *make_logchannel(char *channel, char *components, int l static void init_logger_chain(void) { - struct logchannel *chan, *cur; + struct logchannel *chan; struct ast_config *cfg; struct ast_variable *var; char *s; /* delete our list of log channels */ - ast_mutex_lock(&loglock); - chan = logchannels; - while (chan) { - cur = chan->next; + AST_LIST_LOCK(&logchannels); + while ((chan = AST_LIST_REMOVE_HEAD(&logchannels, list))) free(chan); - chan = cur; - } - logchannels = NULL; - ast_mutex_unlock(&loglock); + AST_LIST_UNLOCK(&logchannels); global_logmask = 0; /* close syslog */ @@ -316,16 +307,16 @@ static void init_logger_chain(void) return; chan->type = LOGTYPE_CONSOLE; chan->logmask = 28; /*warning,notice,error */ - chan->next = logchannels; - logchannels = chan; + AST_LIST_LOCK(&logchannels); + AST_LIST_INSERT_HEAD(&logchannels, chan, list); + AST_LIST_UNLOCK(&logchannels); global_logmask |= chan->logmask; return; } - ast_mutex_lock(&loglock); if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) { - if(ast_true(s)) { - if(gethostname(hostname, sizeof(hostname)-1)) { + if (ast_true(s)) { + if (gethostname(hostname, sizeof(hostname) - 1)) { ast_copy_string(hostname, "unknown", sizeof(hostname)); ast_log(LOG_WARNING, "What box has no hostname???\n"); } @@ -333,36 +324,32 @@ static void init_logger_chain(void) hostname[0] = '\0'; } else hostname[0] = '\0'; - if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) { + if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) ast_copy_string(dateformat, s, sizeof(dateformat)); - } else + else ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat)); - if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) { + if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) logfiles.queue_log = ast_true(s); - } - if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) { + if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) logfiles.event_log = ast_true(s); - } + AST_LIST_LOCK(&logchannels); var = ast_variable_browse(cfg, "logfiles"); - while(var) { - chan = make_logchannel(var->name, var->value, var->lineno); - if (chan) { - chan->next = logchannels; - logchannels = chan; - global_logmask |= chan->logmask; - } - var = var->next; + for (; var; var = var->next) { + if (!(chan = make_logchannel(var->name, var->value, var->lineno))) + continue; + AST_LIST_INSERT_HEAD(&logchannels, chan, list); + global_logmask |= chan->logmask; } + AST_LIST_UNLOCK(&logchannels); ast_config_destroy(cfg); - ast_mutex_unlock(&loglock); } void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...) { va_list ap; - ast_mutex_lock(&loglock); + AST_LIST_LOCK(&logchannels); if (qlog) { va_start(ap, fmt); fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event); @@ -371,7 +358,7 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent, va_end(ap); fflush(qlog); } - ast_mutex_unlock(&loglock); + AST_LIST_UNLOCK(&logchannels); } int reload_logger(int rotate) @@ -383,8 +370,8 @@ int reload_logger(int rotate) FILE *myf; int x, res = 0; - ast_mutex_lock(&msglist_lock); /* to avoid deadlock */ - ast_mutex_lock(&loglock); + AST_LIST_LOCK(&logchannels); + if (eventlog) fclose(eventlog); else @@ -399,8 +386,7 @@ int reload_logger(int rotate) mkdir((char *)ast_config_AST_LOG_DIR, 0755); - f = logchannels; - while(f) { + AST_LIST_TRAVERSE(&logchannels, f, list) { if (f->disabled) { f->disabled = 0; /* Re-enable logging at reload */ manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename); @@ -408,17 +394,16 @@ int reload_logger(int rotate) if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) { fclose(f->fileptr); /* Close file */ f->fileptr = NULL; - if(rotate) { + if (rotate) { ast_copy_string(old, f->filename, sizeof(old)); - for(x=0;;x++) { + for (x = 0; ; x++) { snprintf(new, sizeof(new), "%s.%d", f->filename, x); myf = fopen((char *)new, "r"); - if (myf) { + if (myf) fclose(myf); - } else { + else break; - } } /* do it */ @@ -426,7 +411,6 @@ int reload_logger(int rotate) fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new); } } - f = f->next; } filesize_reload_needed = 0; @@ -489,8 +473,8 @@ int reload_logger(int rotate) res = -1; } } - ast_mutex_unlock(&loglock); - ast_mutex_unlock(&msglist_lock); + + AST_LIST_UNLOCK(&logchannels); return res; } @@ -519,14 +503,12 @@ static int handle_logger_show_channels(int fd, int argc, char *argv[]) #define FORMATL "%-35.35s %-8.8s %-9.9s " struct logchannel *chan; - ast_mutex_lock(&loglock); - - chan = logchannels; ast_cli(fd,FORMATL, "Channel", "Type", "Status"); ast_cli(fd, "Configuration\n"); ast_cli(fd,FORMATL, "-------", "----", "------"); ast_cli(fd, "-------------\n"); - while (chan) { + AST_LIST_LOCK(&logchannels); + AST_LIST_TRAVERSE(&logchannels, chan, list) { ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"), chan->disabled ? "Disabled" : "Enabled"); ast_cli(fd, " - "); @@ -545,20 +527,19 @@ static int handle_logger_show_channels(int fd, int argc, char *argv[]) if (chan->logmask & (1 << __LOG_EVENT)) ast_cli(fd, "Event "); ast_cli(fd, "\n"); - chan = chan->next; } + AST_LIST_UNLOCK(&logchannels); ast_cli(fd, "\n"); - - ast_mutex_unlock(&loglock); return RESULT_SUCCESS; } -static struct verb { - void (*verboser)(const char *string, int opos, int replacelast, int complete); - struct verb *next; -} *verboser = NULL; +struct verb { + void (*verboser)(const char *string); + AST_LIST_ENTRY(verb) list; +}; +static AST_LIST_HEAD_STATIC(verbosers, verb); static char logger_reload_help[] = "Usage: logger reload\n" @@ -637,21 +618,31 @@ int init_logger(void) void close_logger(void) { - struct msglist *m, *tmp; + struct logchannel *f; - ast_mutex_lock(&msglist_lock); - m = list; - while(m) { - if (m->msg) { - free(m->msg); + AST_LIST_LOCK(&logchannels); + + if (eventlog) { + fclose(eventlog); + eventlog = NULL; + } + + if (qlog) { + fclose(qlog); + qlog = NULL; + } + + AST_LIST_TRAVERSE(&logchannels, f, list) { + if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) { + fclose(f->fileptr); + f->fileptr = NULL; } - tmp = m->next; - free(m); - m = tmp; } - list = last = NULL; - msgcnt = 0; - ast_mutex_unlock(&msglist_lock); + + closelog(); /* syslog */ + + AST_LIST_UNLOCK(&logchannels); + return; } @@ -681,28 +672,30 @@ static void ast_log_vsyslog(int level, const char *file, int line, const char *f syslog(syslog_level_map[level], "%s", buf); } -/* - * send log messages to syslog and/or the console +/*! + * \brief send log messages to syslog and/or the console */ void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) { struct logchannel *chan; - char buf[BUFSIZ]; + struct ast_dynamic_str *buf; time_t t; struct tm tm; char date[256]; va_list ap; - + + if (!(buf = ast_dynamic_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) + return; + /* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug are non-zero; LOG_DEBUG messages can still be displayed if option_debug is zero, if option_verbose is non-zero (this allows for 'level zero' LOG_DEBUG messages to be displayed, if the logmask on any channel allows it) */ - if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) { + if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) return; - } /* Ignore anything that never gets logged anywhere */ if (!(global_logmask & (1 << level))) @@ -712,13 +705,12 @@ void ast_log(int level, const char *file, int line, const char *function, const if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file)) return; - /* begin critical section */ - ast_mutex_lock(&loglock); - time(&t); localtime_r(&t, &tm); strftime(date, sizeof(date), dateformat, &tm); + AST_LIST_LOCK(&logchannels); + if (logfiles.event_log && level == __LOG_EVENT) { va_start(ap, fmt); @@ -727,13 +719,14 @@ void ast_log(int level, const char *file, int line, const char *function, const fflush(eventlog); va_end(ap); - ast_mutex_unlock(&loglock); + AST_LIST_UNLOCK(&logchannels); return; } - if (logchannels) { - chan = logchannels; - while(chan && !chan->disabled) { + if (!AST_LIST_EMPTY(&logchannels)) { + AST_LIST_TRAVERSE(&logchannels, chan, list) { + if (chan->disabled) + break; /* Check syslog channels */ if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) { va_start(ap, fmt); @@ -745,28 +738,33 @@ void ast_log(int level, const char *file, int line, const char *function, const char tmp1[80], tmp2[80], tmp3[80], tmp4[80]; if (level != __LOG_VERBOSE) { + int res; sprintf(linestr, "%d", line); - snprintf(buf, sizeof(buf), "[%s] %s[%ld]: %s:%s %s: ", + ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf, + "[%s] %s[%ld]: %s:%s %s: ", date, term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)), (long)GETTID(), term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)), term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)), term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4))); + + ast_console_puts_mutable(buf->str); - ast_console_puts_mutable(buf); va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap); va_end(ap); - ast_console_puts_mutable(buf); + if (res != AST_DYNSTR_BUILD_FAILED) + ast_console_puts_mutable(buf->str); } /* File channels */ } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) { int res; - snprintf(buf, sizeof(buf), "[%s] %s[%ld] %s: ", date, - levels[level], (long)GETTID(), file); - res = fprintf(chan->fileptr, buf); - if (res <= 0 && buf[0] != '\0') { /* Error, no characters printed */ + ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf, + "[%s] %s[%ld] %s: ", + date, levels[level], (long)GETTID(), file); + res = fprintf(chan->fileptr, "%s", buf->str); + if (res <= 0 && !ast_strlen_zero(buf->str)) { /* Error, no characters printed */ fprintf(stderr,"**** Asterisk Logging Error: ***********\n"); if (errno == ENOMEM || errno == ENOSPC) { fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename); @@ -775,16 +773,18 @@ void ast_log(int level, const char *file, int line, const char *function, const manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno)); chan->disabled = 1; } else { + int res; /* No error message, continue printing */ va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap); va_end(ap); - term_strip(buf, buf, sizeof(buf)); - fputs(buf, chan->fileptr); - fflush(chan->fileptr); + if (res != AST_DYNSTR_BUILD_FAILED) { + term_strip(buf->str, buf->str, buf->len); + fputs(buf->str, chan->fileptr); + fflush(chan->fileptr); + } } } - chan = chan->next; } } else { /* @@ -792,15 +792,17 @@ void ast_log(int level, const char *file, int line, const char *function, const * so just log to stdout */ if (level != __LOG_VERBOSE) { + int res; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap); va_end(ap); - fputs(buf, stdout); + if (res != AST_DYNSTR_BUILD_FAILED) + fputs(buf->str, stdout); } } - ast_mutex_unlock(&loglock); - /* end critical section */ + AST_LIST_UNLOCK(&logchannels); + if (filesize_reload_needed) { reload_logger(1); ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n"); @@ -840,17 +842,10 @@ void ast_backtrace(void) void ast_verbose(const char *fmt, ...) { - static char stuff[4096]; - static int len = 0; - static int replacelast = 0; - - int complete; - int olen; - struct msglist *m; struct verb *v; - + struct ast_dynamic_str *buf; + int res; va_list ap; - va_start(ap, fmt); if (ast_opt_timestamp) { time_t t; @@ -866,128 +861,54 @@ void ast_verbose(const char *fmt, ...) fmt = datefmt; } - /* this lock is also protecting against multiple threads - being in this function at the same time, so it must be - held before any of the static variables are accessed - */ - ast_mutex_lock(&msglist_lock); + if (!(buf = ast_dynamic_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE))) + return; - /* there is a potential security problem here: if formatting - the current date using 'dateformat' results in a string - containing '%', then the vsnprintf() call below will - probably try to access random memory - */ - vsnprintf(stuff + len, sizeof(stuff) - len, fmt, ap); + va_start(ap, fmt); + res = ast_dynamic_str_thread_set_va(&buf, 0, &verbose_buf, fmt, ap); va_end(ap); - olen = len; - len = strlen(stuff); - - complete = (stuff[len - 1] == '\n') ? 1 : 0; - - /* If we filled up the stuff completely, then log it even without the '\n' */ - if (len >= sizeof(stuff) - 1) { - complete = 1; - len = 0; - } + if (res == AST_DYNSTR_BUILD_FAILED) + return; - if (complete) { - if (msgcnt < MAX_MSG_QUEUE) { - /* Allocate new structure */ - if ((m = ast_malloc(sizeof(*m)))) - msgcnt++; - } else { - /* Recycle the oldest entry */ - m = list; - list = list->next; - free(m->msg); - } - if (m) { - if ((m->msg = ast_strdup(stuff))) { - if (last) - last->next = m; - else - list = m; - m->next = NULL; - last = m; - } else { - msgcnt--; - free(m); - } - } - } + AST_LIST_LOCK(&verbosers); + AST_LIST_TRAVERSE(&verbosers, v, list) + v->verboser(buf->str); + AST_LIST_UNLOCK(&verbosers); - for (v = verboser; v; v = v->next) - v->verboser(stuff, olen, replacelast, complete); + ast_log(LOG_VERBOSE, "%s", buf->str); +} - ast_log(LOG_VERBOSE, "%s", stuff); +int ast_register_verbose(void (*v)(const char *string)) +{ + struct verb *verb; - if (len) { - if (!complete) - replacelast = 1; - else - replacelast = len = 0; - } + if (!(verb = ast_malloc(sizeof(*verb)))) + return -1; - ast_mutex_unlock(&msglist_lock); -} + verb->verboser = v; -int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete)) -{ - struct msglist *m; - ast_mutex_lock(&msglist_lock); - m = list; - while(m) { - /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */ - v(m->msg, 0, 0, 1); - m = m->next; - } - ast_mutex_unlock(&msglist_lock); + AST_LIST_LOCK(&verbosers); + AST_LIST_INSERT_HEAD(&verbosers, verb, list); + AST_LIST_UNLOCK(&verbosers); + return 0; } -int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete)) +int ast_unregister_verbose(void (*v)(const char *string)) { - struct msglist *m; - struct verb *tmp; - /* XXX Should be more flexible here, taking > 1 verboser XXX */ - if ((tmp = ast_malloc(sizeof(*tmp)))) { - tmp->verboser = v; - ast_mutex_lock(&msglist_lock); - tmp->next = verboser; - verboser = tmp; - m = list; - while(m) { - /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */ - v(m->msg, 0, 0, 1); - m = m->next; - } - ast_mutex_unlock(&msglist_lock); - return 0; - } - return -1; -} + struct verb *cur; -int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete)) -{ - int res = -1; - struct verb *tmp, *tmpl=NULL; - ast_mutex_lock(&msglist_lock); - tmp = verboser; - while(tmp) { - if (tmp->verboser == v) { - if (tmpl) - tmpl->next = tmp->next; - else - verboser = tmp->next; - free(tmp); + AST_LIST_LOCK(&verbosers); + AST_LIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) { + if (cur->verboser == v) { + AST_LIST_REMOVE_CURRENT(&verbosers, list); + free(cur); break; } - tmpl = tmp; - tmp = tmp->next; } - if (tmp) - res = 0; - ast_mutex_unlock(&msglist_lock); - return res; + AST_LIST_TRAVERSE_SAFE_END + AST_LIST_UNLOCK(&verbosers); + + return cur ? 0 : -1; } diff --git a/manager.c b/manager.c index 99f726fdf12adcb4e4e4ef43d75bb221d90e2746..03bfdbd2701fae6595dddd6d9160230e801aafeb 100644 --- a/manager.c +++ b/manager.c @@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/acl.h" #include "asterisk/utils.h" #include "asterisk/http.h" +#include "asterisk/threadstorage.h" struct fast_originate_helper { char tech[AST_MAX_MANHEADER_LEN]; @@ -104,6 +105,9 @@ static int block_sockets = 0; static int num_sessions = 0; struct eventqent *master_eventq = NULL; +AST_THREADSTORAGE(manager_event_buf, manager_event_buf_init); +#define MANAGER_EVENT_BUF_INITSIZE 256 + static struct permalias { int num; char *label; @@ -2113,33 +2117,37 @@ int manager_event(int category, const char *event, const char *fmt, ...) { struct mansession *s; char auth[80]; - char tmp[4096] = ""; - char *tmp_next = tmp; - size_t tmp_left = sizeof(tmp) - 2; va_list ap; struct timeval now; + struct ast_dynamic_str *buf; /* Abort if there aren't any manager sessions */ if (!num_sessions) return 0; - ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n", + if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) + return -1; + + ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf, + "Event: %s\r\nPrivilege: %s\r\n", event, authority_to_str(category, auth, sizeof(auth))); + if (timestampevents) { now = ast_tvnow(); - ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n", + ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, + "Timestamp: %ld.%06lu\r\n", now.tv_sec, (unsigned long) now.tv_usec); } + va_start(ap, fmt); - ast_build_string_va(&tmp_next, &tmp_left, fmt, ap); + ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap); va_end(ap); - *tmp_next++ = '\r'; - *tmp_next++ = '\n'; - *tmp_next = '\0'; + + ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n"); ast_mutex_lock(&sessionlock); /* Append even to master list and wake up any sleeping sessions */ - append_event(tmp, category); + append_event(buf->str, category); for (s = sessions; s; s = s->next) { ast_mutex_lock(&s->__lock); if (s->waiting_thread != AST_PTHREADT_NULL) diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c index 17bcada960ab94294401981e06f5fa7650b5af4f..f7a5f6c543fa38358ebdeb3277e1cb90fa6ea6be 100644 --- a/pbx/pbx_ael.c +++ b/pbx/pbx_ael.c @@ -51,16 +51,6 @@ static char expr_output[2096]; /* these functions are in ../ast_expr2.fl */ - -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - #define DEBUG_READ (1 << 0) #define DEBUG_TOKENS (1 << 1) #define DEBUG_MACROS (1 << 2) @@ -3403,7 +3393,7 @@ void add_extensions(struct ael_extension *exten) if (exten->hints) { if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, PRIORITY_HINT, NULL, exten->cidmatch, - exten->hints, NULL, FREE, registrar)) { + exten->hints, NULL, ast_free, registrar)) { ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", exten->name); } @@ -3483,7 +3473,7 @@ void add_extensions(struct ael_extension *exten) label = 0; if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, pr->priority_num, (label?label:NULL), exten->cidmatch, - app, strdup(appargs), FREE, registrar)) { + app, strdup(appargs), ast_free, registrar)) { ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, exten->name); } diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 6b6edbc4865a2cbf4c6b15c6beaeea2c264440ae..c74c4c105982698a16ef043ca0b7dea92a126479 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -42,15 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/cli.h" #include "asterisk/callerid.h" -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - static char *config = "extensions.conf"; static char *registrar = "pbx_config"; @@ -1458,7 +1449,7 @@ static void pbx_load_config(const char *config_file) lastpri = ipri; if (!ast_opt_dont_warn && !strcmp(realext, "_.")) ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno); - if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) { + if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, registrar)) { ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); } } diff --git a/res/res_agi.c b/res/res_agi.c index 64c0390ebbea9404a90ee70ee209e84d56bc7363..d12de6e2dcee874093c1d71a2a9f0b55e2546e7f 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -130,7 +130,7 @@ static void agi_debug_cli(int fd, char *fmt, ...) ast_log(LOG_ERROR, "Out of memory\n"); } else { if (agidebug) - ast_verbose("AGI Tx >> %s", stuff); + ast_verbose("AGI Tx >> %s\n", stuff); ast_carefulwrite(fd, stuff, strlen(stuff), 100); free(stuff); } diff --git a/res/res_features.c b/res/res_features.c index 1b7212c25ab1606f2c1c9872c5515fbd943dbc4c..d584ee814c0239401d52f0b8416cbe1cce325dc6 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -59,15 +59,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/devicestate.h" #include "asterisk/monitor.h" -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - #define DEFAULT_PARK_TIME 45000 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 @@ -427,7 +418,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou if (!con) /* Still no context? Bad */ ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); else { /* Add extension to context */ - if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), FREE, registrar)) + if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) notify_metermaids(pu->parkingexten, parking_con); } /* Tell the peer channel the number of the parking space */ @@ -1555,7 +1546,7 @@ static void *do_parking_thread(void *ignore) if (con) { char returnexten[AST_MAX_EXTENSION]; snprintf(returnexten, sizeof(returnexten), "%s||t", peername); - ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar); + ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); } set_c_e_p(chan, parking_con_dial, peername, 1); } else { @@ -2250,7 +2241,7 @@ static int load_config(void) ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); return -1; } - res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar); + res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free, registrar); if (parkaddhints) park_add_hints(parking_con, parking_start, parking_stop); if (!res) diff --git a/utils.c b/utils.c index ef251bfa96ddb668b2b15b1b129f2a1ab27dd203..0aaa791a509e034da9df8d36b4d281d14415094b 100644 --- a/utils.c +++ b/utils.c @@ -59,20 +59,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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 +#include "asterisk/threadstorage.h" + static char base64[64]; static char b2a[256]; -static pthread_key_t inet_ntoa_buf_key; -static pthread_once_t inet_ntoa_buf_once = PTHREAD_ONCE_INIT; - -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif +AST_THREADSTORAGE(inet_ntoa_buf, inet_ntoa_buf_init); #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__) @@ -495,22 +488,13 @@ void ast_uri_decode(char *s) *o = '\0'; } -static void inet_ntoa_buf_key_create(void) -{ - pthread_key_create(&inet_ntoa_buf_key, FREE); -} - /*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */ const char *ast_inet_ntoa(struct in_addr ia) { char *buf; - pthread_once(&inet_ntoa_buf_once, inet_ntoa_buf_key_create); - if (!(buf = pthread_getspecific(inet_ntoa_buf_key))) { - if (!(buf = ast_calloc(1, INET_ADDRSTRLEN))) - return NULL; - pthread_setspecific(inet_ntoa_buf_key, buf); - } + if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN))) + return ""; return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN); } @@ -1211,3 +1195,37 @@ int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed) return -1; } +int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len, + struct ast_threadstorage *ts, int append, const char *fmt, va_list ap) +{ + int res; + int offset = append ? strlen((*buf)->str) : 0; + + res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap); + + /* Check to see if there was not enough space in the string buffer to prepare + * the string. Also, if a maximum length is present, make sure the current + * length is less than the maximum before increasing the size. */ + if ((res + offset + 1) > (*buf)->len && (max_len ? ((*buf)->len < max_len) : 1)) { + /* Set the new size of the string buffer to be the size needed + * to hold the resulting string (res) plus one byte for the + * terminating '\0'. If this size is greater than the max, set + * the new length to be the maximum allowed. */ + if (max_len) + (*buf)->len = ((res + offset + 1) < max_len) ? (res + offset + 1) : max_len; + else + (*buf)->len = res + offset + 1; + + if (!(*buf = ast_realloc(*buf, (*buf)->len + sizeof(*(*buf))))) + return AST_DYNSTR_BUILD_FAILED; + + if (ts) + pthread_setspecific(ts->key, *buf); + + /* va_end() and va_start() must be done before calling + * vsnprintf() again. */ + return AST_DYNSTR_BUILD_RETRY; + } + + return res; +}