#include "asterisk.h"
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "asterisk/network.h"
#include "asterisk/lock.h"
#include "asterisk/io.h"
#include "asterisk/md5.h"
#include "asterisk/sha1.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.h"
#include "asterisk/strings.h"
#include "asterisk/time.h"
#include "asterisk/stringfields.h"
#include "asterisk/utils.h"
#include "asterisk/threadstorage.h"
#include "asterisk/config.h"
Go to the source code of this file.
Data Structures | |
struct | lock_infos |
A list of each thread's lock info. More... | |
struct | thr_arg |
struct | thr_lock_info |
Keep track of which locks a thread holds. More... | |
Defines | |
#define | ALLOCATOR_OVERHEAD 48 |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_API_MODULE |
#define | AST_MAX_LOCKS 64 |
A reasonable maximum number of locks a thread would be holding ... | |
#define | ONE_MILLION 1000000 |
Functions | |
void * | __ast_calloc_with_stringfields (unsigned int num_structs, size_t struct_size, size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file, int lineno, const char *func) |
ast_string_field | __ast_string_field_alloc_space (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t needed) |
int | __ast_string_field_init (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, int needed, const char *file, int lineno, const char *func) |
void | __ast_string_field_ptr_build (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format,...) |
void | __ast_string_field_ptr_build_va (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, va_list ap1, va_list ap2) |
int | __ast_string_field_ptr_grow (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr) |
void | __ast_string_field_release_active (struct ast_string_field_pool *pool_head, const ast_string_field ptr) |
static void | __init_inet_ntoa_buf (void) |
static void | __init_thread_lock_info (void) |
The thread storage key for per-thread lock info. | |
int | _ast_asprintf (char **ret, const char *file, int lineno, const char *func, const char *fmt,...) |
static int | add_string_pool (struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t size, const char *file, int lineno, const char *func) |
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 void | append_backtrace_information (struct ast_str **str, struct ast_bt *bt) |
static void | append_lock_information (struct ast_str **str, struct thr_lock_info *lock_info, int i) |
int | ast_atomic_fetchadd_int_slow (volatile int *p, int v) |
int | ast_base64decode (unsigned char *dst, const char *src, int max) |
Decode data from base64. | |
int | ast_base64encode (char *dst, const unsigned char *src, int srclen, int max) |
Encode data in base64. | |
int | ast_base64encode_full (char *dst, const unsigned char *src, int srclen, int max, int linebreaks) |
encode text to BASE64 coding | |
int | ast_build_string (char **buffer, size_t *space, const char *fmt,...) |
Build a string in a buffer, designed to be called repeatedly. | |
int | ast_build_string_va (char **buffer, size_t *space, const char *fmt, va_list ap) |
Build a string in a buffer, designed to be called repeatedly. | |
int | ast_careful_fwrite (FILE *f, int fd, const char *src, size_t len, int timeoutms) |
Write data to a file stream with a timeout. | |
int | ast_carefulwrite (int fd, char *s, int len, int timeoutms) |
Try to write string, but wait no more than ms milliseconds before timing out. | |
void | ast_enable_packet_fragmentation (int sock) |
Disable PMTU discovery on a socket. | |
int | ast_false (const char *s) |
Make sure something is false. Determine if a string containing a boolean value is "false". This function checks to see whether a string passed to it is an indication of an "false" value. It checks to see if the string is "no", "false", "n", "f", "off" or "0". | |
int | ast_find_lock_info (void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size) |
retrieve lock info for the specified mutex | |
int | ast_get_time_t (const char *src, time_t *dst, time_t _default, int *consumed) |
get values from config variables. | |
int | ast_get_timeval (const char *src, struct timeval *dst, struct timeval _default, int *consumed) |
get values from config variables. | |
hostent * | ast_gethostbyname (const char *host, struct ast_hostent *hp) |
Thread-safe gethostbyname function to use in Asterisk. | |
const char * | ast_inet_ntoa (struct in_addr ia) |
thread-safe replacement for inet_ntoa(). | |
void | ast_join (char *s, size_t len, const char *const w[]) |
void | ast_mark_lock_acquired (void *lock_addr) |
Mark the last lock as acquired. | |
void | ast_mark_lock_failed (void *lock_addr) |
Mark the last lock as failed (trylock). | |
void | ast_md5_hash (char *output, const char *input) |
Produces MD5 hash based on input string. | |
int | ast_mkdir (const char *path, int mode) |
Recursively create directory path. | |
int | ast_parse_digest (const char *digest, struct ast_http_digest *d, int request, int pedantic) |
Parse digest authorization header. | |
char * | ast_process_quotes_and_slashes (char *start, char find, char replace_with) |
Process a string to find and replace characters. | |
int | ast_pthread_create_detached_stack (pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, const char *file, const char *caller, int line, const char *start_fn) |
int | ast_pthread_create_stack (pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, const char *file, const char *caller, int line, const char *start_fn) |
long int | ast_random (void) |
void | ast_remove_lock_info (void *lock_addr, struct ast_bt *bt) |
remove lock info for the current thread | |
void | ast_sha1_hash (char *output, const char *input) |
Produces SHA1 hash based on input string. | |
void | ast_store_lock_info (enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) |
Store lock info for the current thread. | |
char * | ast_strip_quoted (char *s, const char *beg_quotes, const char *end_quotes) |
Strip leading/trailing whitespace and quotes from a string. | |
int | ast_true (const char *s) |
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1". | |
timeval | ast_tvadd (struct timeval a, struct timeval b) |
Returns the sum of two timevals a + b. | |
timeval | ast_tvsub (struct timeval a, struct timeval b) |
Returns the difference of two timevals a - b. | |
char * | ast_unescape_c (char *src) |
Convert some C escape sequences. | |
char * | ast_unescape_semicolon (char *s) |
Strip backslash for "escaped" semicolons, the string to be stripped (will be modified). | |
void | ast_uri_decode (char *s) |
Decode URI, URN, URL (overwrite string). | |
char * | ast_uri_encode (const char *string, char *outbuf, int buflen, int do_special_char) |
Turn text string to URI-encoded XX version. | |
int | ast_utils_init (void) |
char * | ast_utils_which (const char *binary, char *fullpath, size_t fullpath_size) |
Resolve a binary to a full pathname. | |
int | ast_wait_for_input (int fd, int ms) |
static int | ast_wait_for_output (int fd, int timeoutms) |
static void | base64_init (void) |
static void * | dummy_start (void *data) |
static char * | handle_show_locks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static void | lock_info_destroy (void *data) |
Destroy a thread's lock info. | |
static const char * | locktype2str (enum ast_lock_type type) |
void | log_show_lock (void *this_lock_addr) |
log info for the current lock with ast_log(). | |
static size_t | optimal_alloc_size (size_t size) |
static struct timeval | tvfix (struct timeval a) |
Variables | |
ast_string_field | __ast_string_field_empty = __ast_string_field_empty_buffer.string |
struct { | |
ast_string_field_allocation allocation | |
char string [1] | |
} | __ast_string_field_empty_buffer |
static char | b2a [256] |
static char | base64 [64] |
static int | dev_urandom_fd |
static ast_mutex_t | fetchadd_m = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
static struct ast_threadstorage | inet_ntoa_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_inet_ntoa_buf , .custom_init = NULL , } |
static ast_mutex_t | lock_infos_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
Locked when accessing the lock_infos list. | |
static ast_mutex_t | randomlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
glibc puts a lock inside random(3), so that the results are thread-safe. BSD libc (and others) do not. | |
static struct ast_threadstorage | thread_lock_info = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_lock_info , .custom_init = NULL , } |
static struct ast_cli_entry | utils_cli [] |
Definition in file utils.c.
#define ALLOCATOR_OVERHEAD 48 |
#define AST_MAX_LOCKS 64 |
#define ONE_MILLION 1000000 |
void* __ast_calloc_with_stringfields | ( | unsigned int | num_structs, | |
size_t | struct_size, | |||
size_t | field_mgr_offset, | |||
size_t | field_mgr_pool_offset, | |||
size_t | pool_size, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 1777 of file utils.c.
References __ast_calloc(), __ast_string_field_empty, allocation, ast_calloc, ast_string_field_pool::base, ast_string_field_mgr::embedded_pool, optimal_alloc_size(), and ast_string_field_pool::size.
01780 { 01781 struct ast_string_field_mgr *mgr; 01782 struct ast_string_field_pool *pool; 01783 struct ast_string_field_pool **pool_head; 01784 size_t pool_size_needed = sizeof(*pool) + pool_size; 01785 size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed); 01786 void *allocation; 01787 unsigned int x; 01788 01789 #if defined(__AST_DEBUG_MALLOC) 01790 if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) { 01791 return NULL; 01792 } 01793 #else 01794 if (!(allocation = ast_calloc(num_structs, size_to_alloc))) { 01795 return NULL; 01796 } 01797 #endif 01798 01799 for (x = 0; x < num_structs; x++) { 01800 void *base = allocation + (size_to_alloc * x); 01801 const char **p; 01802 01803 mgr = base + field_mgr_offset; 01804 pool_head = base + field_mgr_pool_offset; 01805 pool = base + struct_size; 01806 01807 p = (const char **) pool_head + 1; 01808 while ((struct ast_string_field_mgr *) p != mgr) { 01809 *p++ = __ast_string_field_empty; 01810 } 01811 01812 mgr->embedded_pool = pool; 01813 *pool_head = pool; 01814 pool->size = size_to_alloc - struct_size - sizeof(*pool); 01815 #if defined(__AST_DEBUG_MALLOC) 01816 mgr->owner_file = file; 01817 mgr->owner_func = func; 01818 mgr->owner_line = lineno; 01819 #endif 01820 } 01821 01822 return allocation; 01823 }
ast_string_field __ast_string_field_alloc_space | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
size_t | needed | |||
) |
Definition at line 1613 of file utils.c.
References add_string_pool(), AST_STRING_FIELD_ALLOCATION, and ast_string_field_mgr::last_alloc.
Referenced by __ast_string_field_ptr_build_va().
01615 { 01616 char *result = NULL; 01617 size_t space = (*pool_head)->size - (*pool_head)->used; 01618 size_t to_alloc = needed + sizeof(ast_string_field_allocation); 01619 01620 /* This +1 accounts for alignment on SPARC */ 01621 if (__builtin_expect(to_alloc + 1 > space, 0)) { 01622 size_t new_size = (*pool_head)->size; 01623 01624 while (new_size < to_alloc) { 01625 new_size *= 2; 01626 } 01627 01628 #if defined(__AST_DEBUG_MALLOC) 01629 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) 01630 return NULL; 01631 #else 01632 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) 01633 return NULL; 01634 #endif 01635 } 01636 01637 result = (*pool_head)->base + (*pool_head)->used; 01638 #ifdef __sparc__ 01639 /* SPARC requires that the allocation field be aligned. */ 01640 if ((long) result % sizeof(ast_string_field_allocation)) { 01641 result++; 01642 (*pool_head)->used++; 01643 } 01644 #endif 01645 (*pool_head)->used += to_alloc; 01646 (*pool_head)->active += needed; 01647 result += sizeof(ast_string_field_allocation); 01648 AST_STRING_FIELD_ALLOCATION(result) = needed; 01649 mgr->last_alloc = result; 01650 01651 return result; 01652 }
int __ast_string_field_init | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
int | needed, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) |
Definition at line 1546 of file utils.c.
References ast_string_field_pool::active, add_string_pool(), ast_free, ast_log(), ast_string_field_mgr::embedded_pool, ast_string_field_mgr::last_alloc, LOG_WARNING, ast_string_field_pool::prev, and ast_string_field_pool::used.
01548 { 01549 const char **p = (const char **) pool_head + 1; 01550 struct ast_string_field_pool *cur = NULL; 01551 struct ast_string_field_pool *preserve = NULL; 01552 01553 /* clear fields - this is always necessary */ 01554 while ((struct ast_string_field_mgr *) p != mgr) { 01555 *p++ = __ast_string_field_empty; 01556 } 01557 01558 mgr->last_alloc = NULL; 01559 #if defined(__AST_DEBUG_MALLOC) 01560 mgr->owner_file = file; 01561 mgr->owner_func = func; 01562 mgr->owner_line = lineno; 01563 #endif 01564 if (needed > 0) { /* allocate the initial pool */ 01565 *pool_head = NULL; 01566 mgr->embedded_pool = NULL; 01567 return add_string_pool(mgr, pool_head, needed, file, lineno, func); 01568 } 01569 01570 /* if there is an embedded pool, we can't actually release *all* 01571 * pools, we must keep the embedded one. if the caller is about 01572 * to free the structure that contains the stringfield manager 01573 * and embedded pool anyway, it will be freed as part of that 01574 * operation. 01575 */ 01576 if ((needed < 0) && mgr->embedded_pool) { 01577 needed = 0; 01578 } 01579 01580 if (needed < 0) { /* reset all pools */ 01581 cur = *pool_head; 01582 } else if (mgr->embedded_pool) { /* preserve the embedded pool */ 01583 preserve = mgr->embedded_pool; 01584 cur = *pool_head; 01585 } else { /* preserve the last pool */ 01586 if (*pool_head == NULL) { 01587 ast_log(LOG_WARNING, "trying to reset empty pool\n"); 01588 return -1; 01589 } 01590 preserve = *pool_head; 01591 cur = preserve->prev; 01592 } 01593 01594 if (preserve) { 01595 preserve->prev = NULL; 01596 preserve->used = preserve->active = 0; 01597 } 01598 01599 while (cur) { 01600 struct ast_string_field_pool *prev = cur->prev; 01601 01602 if (cur != preserve) { 01603 ast_free(cur); 01604 } 01605 cur = prev; 01606 } 01607 01608 *pool_head = preserve; 01609 01610 return 0; 01611 }
void __ast_string_field_ptr_build | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
ast_string_field * | ptr, | |||
const char * | format, | |||
... | ||||
) |
Definition at line 1762 of file utils.c.
References __ast_string_field_ptr_build_va().
01765 { 01766 va_list ap1, ap2; 01767 01768 va_start(ap1, format); 01769 va_start(ap2, format); /* va_copy does not exist on FreeBSD */ 01770 01771 __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2); 01772 01773 va_end(ap1); 01774 va_end(ap2); 01775 }
void __ast_string_field_ptr_build_va | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
ast_string_field * | ptr, | |||
const char * | format, | |||
va_list | ap1, | |||
va_list | ap2 | |||
) |
Definition at line 1697 of file utils.c.
References __ast_string_field_alloc_space(), __ast_string_field_empty, __ast_string_field_release_active(), AST_STRING_FIELD_ALLOCATION, available(), and ast_string_field_mgr::last_alloc.
Referenced by __ast_string_field_ptr_build().
01700 { 01701 size_t needed; 01702 size_t available; 01703 size_t space = (*pool_head)->size - (*pool_head)->used; 01704 ssize_t grow; 01705 char *target; 01706 01707 /* if the field already has space allocated, try to reuse it; 01708 otherwise, try to use the empty space at the end of the current 01709 pool 01710 */ 01711 if (*ptr != __ast_string_field_empty) { 01712 target = (char *) *ptr; 01713 available = AST_STRING_FIELD_ALLOCATION(*ptr); 01714 if (*ptr == mgr->last_alloc) { 01715 available += space; 01716 } 01717 } else { 01718 target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation); 01719 #ifdef __sparc__ 01720 if ((long) target % sizeof(ast_string_field_allocation)) { 01721 target++; 01722 space--; 01723 } 01724 #endif 01725 available = space - sizeof(ast_string_field_allocation); 01726 } 01727 01728 needed = vsnprintf(target, available, format, ap1) + 1; 01729 01730 va_end(ap1); 01731 01732 if (needed > available) { 01733 /* the allocation could not be satisfied using the field's current allocation 01734 (if it has one), or the space available in the pool (if it does not). allocate 01735 space for it, adding a new string pool if necessary. 01736 */ 01737 if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) { 01738 return; 01739 } 01740 vsprintf(target, format, ap2); 01741 __ast_string_field_release_active(*pool_head, *ptr); 01742 *ptr = target; 01743 } else if (*ptr != target) { 01744 /* the allocation was satisfied using available space in the pool, but not 01745 using the space already allocated to the field 01746 */ 01747 __ast_string_field_release_active(*pool_head, *ptr); 01748 mgr->last_alloc = *ptr = target; 01749 AST_STRING_FIELD_ALLOCATION(target) = needed; 01750 (*pool_head)->used += needed + sizeof(ast_string_field_allocation); 01751 (*pool_head)->active += needed; 01752 } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { 01753 /* the allocation was satisfied by using available space in the pool *and* 01754 the field was the last allocated field from the pool, so it grew 01755 */ 01756 (*pool_head)->used += grow; 01757 (*pool_head)->active += grow; 01758 AST_STRING_FIELD_ALLOCATION(*ptr) += grow; 01759 } 01760 }
int __ast_string_field_ptr_grow | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
size_t | needed, | |||
const ast_string_field * | ptr | |||
) |
Definition at line 1654 of file utils.c.
References AST_STRING_FIELD_ALLOCATION, and ast_string_field_mgr::last_alloc.
01657 { 01658 ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr); 01659 size_t space = (*pool_head)->size - (*pool_head)->used; 01660 01661 if (*ptr != mgr->last_alloc) { 01662 return 1; 01663 } 01664 01665 if (space < grow) { 01666 return 1; 01667 } 01668 01669 (*pool_head)->used += grow; 01670 (*pool_head)->active += grow; 01671 AST_STRING_FIELD_ALLOCATION(*ptr) += grow; 01672 01673 return 0; 01674 }
void __ast_string_field_release_active | ( | struct ast_string_field_pool * | pool_head, | |
const ast_string_field | ptr | |||
) |
Definition at line 1676 of file utils.c.
References ast_string_field_pool::active, ast_free, AST_STRING_FIELD_ALLOCATION, and ast_string_field_pool::prev.
Referenced by __ast_string_field_ptr_build_va().
01678 { 01679 struct ast_string_field_pool *pool, *prev; 01680 01681 if (ptr == __ast_string_field_empty) { 01682 return; 01683 } 01684 01685 for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) { 01686 if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) { 01687 pool->active -= AST_STRING_FIELD_ALLOCATION(ptr); 01688 if ((pool->active == 0) && prev) { 01689 prev->prev = pool->prev; 01690 ast_free(pool); 01691 } 01692 break; 01693 } 01694 } 01695 }
static void __init_thread_lock_info | ( | void | ) | [static] |
int _ast_asprintf | ( | char ** | ret, | |
const char * | file, | |||
int | lineno, | |||
const char * | func, | |||
const char * | fmt, | |||
... | ||||
) |
Definition at line 2072 of file utils.c.
References MALLOC_FAILURE_MSG, and vasprintf.
02073 { 02074 int res; 02075 va_list ap; 02076 02077 va_start(ap, fmt); 02078 if ((res = vasprintf(ret, fmt, ap)) == -1) { 02079 MALLOC_FAILURE_MSG; 02080 } 02081 va_end(ap); 02082 02083 return res; 02084 }
static int add_string_pool | ( | struct ast_string_field_mgr * | mgr, | |
struct ast_string_field_pool ** | pool_head, | |||
size_t | size, | |||
const char * | file, | |||
int | lineno, | |||
const char * | func | |||
) | [static] |
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.
Definition at line 1510 of file utils.c.
References __ast_calloc(), ast_calloc, ast_string_field_mgr::last_alloc, optimal_alloc_size(), and ast_string_field_pool::size.
Referenced by __ast_string_field_alloc_space(), and __ast_string_field_init().
01512 { 01513 struct ast_string_field_pool *pool; 01514 size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size); 01515 01516 #if defined(__AST_DEBUG_MALLOC) 01517 if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) { 01518 return -1; 01519 } 01520 #else 01521 if (!(pool = ast_calloc(1, alloc_size))) { 01522 return -1; 01523 } 01524 #endif 01525 01526 pool->prev = *pool_head; 01527 pool->size = alloc_size - sizeof(*pool); 01528 *pool_head = pool; 01529 mgr->last_alloc = NULL; 01530 01531 return 0; 01532 }
Definition at line 735 of file utils.c.
References ast_bt::addresses, ast_bt_get_symbols(), ast_str_append(), free, ast_bt::num_frames, and str.
Referenced by append_lock_information().
00736 { 00737 char **symbols; 00738 00739 if (!bt) { 00740 ast_str_append(str, 0, "\tNo backtrace to print\n"); 00741 return; 00742 } 00743 00744 if ((symbols = ast_bt_get_symbols(bt->addresses, bt->num_frames))) { 00745 int frame_iterator; 00746 00747 for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) { 00748 ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]); 00749 } 00750 00751 free(symbols); 00752 } else { 00753 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n"); 00754 } 00755 }
static void append_lock_information | ( | struct ast_str ** | str, | |
struct thr_lock_info * | lock_info, | |||
int | i | |||
) | [static] |
Definition at line 758 of file utils.c.
References append_backtrace_information(), AST_MUTEX, ast_reentrancy_lock(), ast_reentrancy_unlock(), ast_str_append(), ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, lock, lock_info, locktype2str(), ast_lock_track::reentrancy, str, ast_mutex_info::track, and ast_datastore_info::type.
Referenced by handle_show_locks(), and log_show_lock().
00759 { 00760 int j; 00761 ast_mutex_t *lock; 00762 struct ast_lock_track *lt; 00763 00764 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n", 00765 lock_info->locks[i].pending > 0 ? "Waiting for " : 00766 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i, 00767 lock_info->locks[i].file, 00768 locktype2str(lock_info->locks[i].type), 00769 lock_info->locks[i].line_num, 00770 lock_info->locks[i].func, lock_info->locks[i].lock_name, 00771 lock_info->locks[i].lock_addr, 00772 lock_info->locks[i].times_locked); 00773 #ifdef HAVE_BKTR 00774 append_backtrace_information(str, lock_info->locks[i].backtrace); 00775 #endif 00776 00777 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1) 00778 return; 00779 00780 /* We only have further details for mutexes right now */ 00781 if (lock_info->locks[i].type != AST_MUTEX) 00782 return; 00783 00784 lock = lock_info->locks[i].lock_addr; 00785 lt = lock->track; 00786 ast_reentrancy_lock(lt); 00787 for (j = 0; *str && j < lt->reentrancy; j++) { 00788 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n", 00789 lt->file[j], lt->lineno[j], lt->func[j]); 00790 } 00791 ast_reentrancy_unlock(lt); 00792 }
int ast_atomic_fetchadd_int_slow | ( | volatile int * | p, | |
int | v | |||
) |
Definition at line 1829 of file utils.c.
References ast_mutex_lock, ast_mutex_unlock, and fetchadd_m.
01830 { 01831 int ret; 01832 ast_mutex_lock(&fetchadd_m); 01833 ret = *p; 01834 *p += v; 01835 ast_mutex_unlock(&fetchadd_m); 01836 return ret; 01837 }
int ast_base64decode | ( | unsigned char * | dst, | |
const char * | src, | |||
int | max | |||
) |
Decode data from base64.
dst | the destination buffer | |
src | the source buffer | |
max | The maximum number of bytes to write into the destination buffer. Note that this function will not ensure that the destination buffer is NULL terminated. So, in general, this parameter should be sizeof(dst) - 1. |
Definition at line 267 of file utils.c.
Referenced by aes_helper(), ast_check_signature(), base64_helper(), and osp_validate_token().
00268 { 00269 int cnt = 0; 00270 unsigned int byte = 0; 00271 unsigned int bits = 0; 00272 int incnt = 0; 00273 while(*src && *src != '=' && (cnt < max)) { 00274 /* Shift in 6 bits of input */ 00275 byte <<= 6; 00276 byte |= (b2a[(int)(*src)]) & 0x3f; 00277 bits += 6; 00278 src++; 00279 incnt++; 00280 /* If we have at least 8 bits left over, take that character 00281 off the top */ 00282 if (bits >= 8) { 00283 bits -= 8; 00284 *dst = (byte >> bits) & 0xff; 00285 dst++; 00286 cnt++; 00287 } 00288 } 00289 /* Don't worry about left over bits, they're extra anyway */ 00290 return cnt; 00291 }
int ast_base64encode | ( | char * | dst, | |
const unsigned char * | src, | |||
int | srclen, | |||
int | max | |||
) |
Encode data in base64.
dst | the destination buffer | |
src | the source data to be encoded | |
srclen | the number of bytes present in the source buffer | |
max | the maximum number of bytes to write into the destination buffer, *including* the terminating NULL character. |
Definition at line 345 of file utils.c.
References ast_base64encode_full().
Referenced by aes_helper(), aji_start_sasl(), ast_sign(), base64_helper(), build_secret(), and osp_check_destination().
00346 { 00347 return ast_base64encode_full(dst, src, srclen, max, 0); 00348 }
int ast_base64encode_full | ( | char * | dst, | |
const unsigned char * | src, | |||
int | srclen, | |||
int | max, | |||
int | linebreaks | |||
) |
encode text to BASE64 coding
Definition at line 294 of file utils.c.
Referenced by ast_base64encode().
00295 { 00296 int cnt = 0; 00297 int col = 0; 00298 unsigned int byte = 0; 00299 int bits = 0; 00300 int cntin = 0; 00301 /* Reserve space for null byte at end of string */ 00302 max--; 00303 while ((cntin < srclen) && (cnt < max)) { 00304 byte <<= 8; 00305 byte |= *(src++); 00306 bits += 8; 00307 cntin++; 00308 if ((bits == 24) && (cnt + 4 <= max)) { 00309 *dst++ = base64[(byte >> 18) & 0x3f]; 00310 *dst++ = base64[(byte >> 12) & 0x3f]; 00311 *dst++ = base64[(byte >> 6) & 0x3f]; 00312 *dst++ = base64[byte & 0x3f]; 00313 cnt += 4; 00314 col += 4; 00315 bits = 0; 00316 byte = 0; 00317 } 00318 if (linebreaks && (cnt < max) && (col == 64)) { 00319 *dst++ = '\n'; 00320 cnt++; 00321 col = 0; 00322 } 00323 } 00324 if (bits && (cnt + 4 <= max)) { 00325 /* Add one last character for the remaining bits, 00326 padding the rest with 0 */ 00327 byte <<= 24 - bits; 00328 *dst++ = base64[(byte >> 18) & 0x3f]; 00329 *dst++ = base64[(byte >> 12) & 0x3f]; 00330 if (bits == 16) 00331 *dst++ = base64[(byte >> 6) & 0x3f]; 00332 else 00333 *dst++ = '='; 00334 *dst++ = '='; 00335 cnt += 4; 00336 } 00337 if (linebreaks && (cnt < max)) { 00338 *dst++ = '\n'; 00339 cnt++; 00340 } 00341 *dst = '\0'; 00342 return cnt; 00343 }
int ast_build_string | ( | char ** | buffer, | |
size_t * | space, | |||
const char * | fmt, | |||
... | ||||
) |
Build a string in a buffer, designed to be called repeatedly.
buffer | current position in buffer to place string into (will be updated on return) | |
space | remaining space in buffer (will be updated on return) | |
fmt | printf-style format string |
0 | on success | |
non-zero | on failure. |
Definition at line 1304 of file utils.c.
References ast_build_string_va().
Referenced by ast_fax_caps_to_str(), config_odbc(), generate_filenames_string(), handle_speechrecognize(), lua_func_read(), lua_pbx_exec(), pp_each_extension_helper(), and pp_each_user_helper().
01305 { 01306 va_list ap; 01307 int result; 01308 01309 va_start(ap, fmt); 01310 result = ast_build_string_va(buffer, space, fmt, ap); 01311 va_end(ap); 01312 01313 return result; 01314 }
int ast_build_string_va | ( | char ** | buffer, | |
size_t * | space, | |||
const char * | fmt, | |||
va_list | ap | |||
) |
Build a string in a buffer, designed to be called repeatedly.
This is a wrapper for snprintf, that properly handles the buffer pointer and buffer space available.
buffer | current position in buffer to place string into (will be updated on return) | |
space | remaining space in buffer (will be updated on return) | |
fmt | printf-style format string | |
ap | varargs list of arguments for format |
Definition at line 1285 of file utils.c.
Referenced by ast_build_string().
01286 { 01287 int result; 01288 01289 if (!buffer || !*buffer || !space || !*space) 01290 return -1; 01291 01292 result = vsnprintf(*buffer, *space, fmt, ap); 01293 01294 if (result < 0) 01295 return -1; 01296 else if (result > *space) 01297 result = *space; 01298 01299 *buffer += result; 01300 *space -= result; 01301 return 0; 01302 }
int ast_careful_fwrite | ( | FILE * | f, | |
int | fd, | |||
const char * | s, | |||
size_t | len, | |||
int | timeoutms | |||
) |
Write data to a file stream with a timeout.
f | the file stream to write to | |
fd | the file description to poll on to know when the file stream can be written to without blocking. | |
s | the buffer to write from | |
len | the number of bytes to write | |
timeoutms | The maximum amount of time to block in this function trying to write, specified in milliseconds. |
0 | success | |
-1 | error |
Definition at line 1159 of file utils.c.
References ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_wait_for_output(), errno, fwrite, and LOG_ERROR.
Referenced by send_string().
01160 { 01161 struct timeval start = ast_tvnow(); 01162 int n = 0; 01163 int elapsed = 0; 01164 01165 while (len) { 01166 if (ast_wait_for_output(fd, timeoutms - elapsed)) { 01167 /* poll returned a fatal error, so bail out immediately. */ 01168 return -1; 01169 } 01170 01171 /* Clear any errors from a previous write */ 01172 clearerr(f); 01173 01174 n = fwrite(src, 1, len, f); 01175 01176 if (ferror(f) && errno != EINTR && errno != EAGAIN) { 01177 /* fatal error from fwrite() */ 01178 if (!feof(f)) { 01179 /* Don't spam the logs if it was just that the connection is closed. */ 01180 ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno)); 01181 } 01182 n = -1; 01183 break; 01184 } 01185 01186 /* Update for data already written to the socket */ 01187 len -= n; 01188 src += n; 01189 01190 elapsed = ast_tvdiff_ms(ast_tvnow(), start); 01191 if (elapsed >= timeoutms) { 01192 /* We've taken too long to write 01193 * This is only an error condition if we haven't finished writing. */ 01194 n = len ? -1 : 0; 01195 break; 01196 } 01197 } 01198 01199 while (fflush(f)) { 01200 if (errno == EAGAIN || errno == EINTR) { 01201 continue; 01202 } 01203 if (!feof(f)) { 01204 /* Don't spam the logs if it was just that the connection is closed. */ 01205 ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno)); 01206 } 01207 n = -1; 01208 break; 01209 } 01210 01211 return n < 0 ? -1 : 0; 01212 }
int ast_carefulwrite | ( | int | fd, | |
char * | s, | |||
int | len, | |||
int | timeoutms | |||
) |
Try to write string, but wait no more than ms milliseconds before timing out.
Try to write string, but wait no more than ms milliseconds before timing out.
Definition at line 1118 of file utils.c.
References ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_wait_for_output(), errno, and LOG_ERROR.
Referenced by ast_agi_send(), and ast_cli().
01119 { 01120 struct timeval start = ast_tvnow(); 01121 int res = 0; 01122 int elapsed = 0; 01123 01124 while (len) { 01125 if (ast_wait_for_output(fd, timeoutms - elapsed)) { 01126 return -1; 01127 } 01128 01129 res = write(fd, s, len); 01130 01131 if (res < 0 && errno != EAGAIN && errno != EINTR) { 01132 /* fatal error from write() */ 01133 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno)); 01134 return -1; 01135 } 01136 01137 if (res < 0) { 01138 /* It was an acceptable error */ 01139 res = 0; 01140 } 01141 01142 /* Update how much data we have left to write */ 01143 len -= res; 01144 s += res; 01145 res = 0; 01146 01147 elapsed = ast_tvdiff_ms(ast_tvnow(), start); 01148 if (elapsed >= timeoutms) { 01149 /* We've taken too long to write 01150 * This is only an error condition if we haven't finished writing. */ 01151 res = len ? -1 : 0; 01152 break; 01153 } 01154 } 01155 01156 return res; 01157 }
void ast_enable_packet_fragmentation | ( | int | sock | ) |
Disable PMTU discovery on a socket.
sock | The socket to manipulate |
Because of this, UDP packets sent by Asterisk that are larger than the MTU of any hop in the path will be lost. This function can be called on a socket to ensure that the DF bit will not be set.
Definition at line 1892 of file utils.c.
References ast_log(), and LOG_WARNING.
Referenced by ast_netsock_bindaddr().
01893 { 01894 #if defined(HAVE_IP_MTU_DISCOVER) 01895 int val = IP_PMTUDISC_DONT; 01896 01897 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))) 01898 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n"); 01899 #endif /* HAVE_IP_MTU_DISCOVER */ 01900 }
int ast_false | ( | const char * | val | ) |
Make sure something is false. Determine if a string containing a boolean value is "false". This function checks to see whether a string passed to it is an indication of an "false" value. It checks to see if the string is "no", "false", "n", "f", "off" or "0".
0 | if val is a NULL pointer. | |
-1 | if "true". | |
0 | otherwise. |
Definition at line 1333 of file utils.c.
References ast_strlen_zero().
Referenced by __ast_udptl_reload(), acf_faxopt_write(), acf_transaction_write(), aji_create_client(), aji_load_config(), aoc_cli_debug_enable(), build_peer(), build_user(), dahdi_set_dnd(), find_realtime(), func_channel_write_real(), handle_common_options(), init_acf_query(), load_config(), load_odbc_config(), manager_mute_mixmonitor(), parse_empty_options(), rtp_reload(), run_agi(), set_config(), set_insecure_flags(), and strings_to_mask().
01334 { 01335 if (ast_strlen_zero(s)) 01336 return 0; 01337 01338 /* Determine if this is a false value */ 01339 if (!strcasecmp(s, "no") || 01340 !strcasecmp(s, "false") || 01341 !strcasecmp(s, "n") || 01342 !strcasecmp(s, "f") || 01343 !strcasecmp(s, "0") || 01344 !strcasecmp(s, "off")) 01345 return -1; 01346 01347 return 0; 01348 }
int ast_find_lock_info | ( | void * | lock_addr, | |
char * | filename, | |||
size_t | filename_size, | |||
int * | lineno, | |||
char * | func, | |||
size_t | func_size, | |||
char * | mutex_name, | |||
size_t | mutex_name_size | |||
) |
retrieve lock info for the specified mutex
this gets called during deadlock avoidance, so that the information may be preserved as to what location originally acquired the lock.
Definition at line 644 of file utils.c.
References ast_copy_string(), ast_threadstorage_get(), lock_info, pthread_mutex_lock, pthread_mutex_unlock, and thread_lock_info.
00645 { 00646 struct thr_lock_info *lock_info; 00647 int i = 0; 00648 00649 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00650 return -1; 00651 00652 pthread_mutex_lock(&lock_info->lock); 00653 00654 for (i = lock_info->num_locks - 1; i >= 0; i--) { 00655 if (lock_info->locks[i].lock_addr == lock_addr) 00656 break; 00657 } 00658 00659 if (i == -1) { 00660 /* Lock not found :( */ 00661 pthread_mutex_unlock(&lock_info->lock); 00662 return -1; 00663 } 00664 00665 ast_copy_string(filename, lock_info->locks[i].file, filename_size); 00666 *lineno = lock_info->locks[i].line_num; 00667 ast_copy_string(func, lock_info->locks[i].func, func_size); 00668 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size); 00669 00670 pthread_mutex_unlock(&lock_info->lock); 00671 00672 return 0; 00673 }
int ast_get_time_t | ( | const char * | src, | |
time_t * | dst, | |||
time_t | _default, | |||
int * | consumed | |||
) |
get values from config variables.
Definition at line 1869 of file utils.c.
References ast_strlen_zero().
Referenced by build_peer(), cache_lookup_internal(), handle_saydatetime(), load_password(), play_message_datetime(), process_clearcache(), and sayunixtime_exec().
01870 { 01871 long t; 01872 int scanned; 01873 01874 if (dst == NULL) 01875 return -1; 01876 01877 *dst = _default; 01878 01879 if (ast_strlen_zero(src)) 01880 return -1; 01881 01882 /* only integer at the moment, but one day we could accept more formats */ 01883 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) { 01884 *dst = t; 01885 if (consumed) 01886 *consumed = scanned; 01887 return 0; 01888 } else 01889 return -1; 01890 }
int ast_get_timeval | ( | const char * | src, | |
struct timeval * | dst, | |||
struct timeval | _default, | |||
int * | consumed | |||
) |
get values from config variables.
Definition at line 1842 of file utils.c.
References ast_strlen_zero().
Referenced by acf_strftime().
01843 { 01844 long double dtv = 0.0; 01845 int scanned; 01846 01847 if (dst == NULL) 01848 return -1; 01849 01850 *dst = _default; 01851 01852 if (ast_strlen_zero(src)) 01853 return -1; 01854 01855 /* only integer at the moment, but one day we could accept more formats */ 01856 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) { 01857 dst->tv_sec = dtv; 01858 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0; 01859 if (consumed) 01860 *consumed = scanned; 01861 return 0; 01862 } else 01863 return -1; 01864 }
struct hostent* ast_gethostbyname | ( | const char * | host, | |
struct ast_hostent * | hp | |||
) |
Thread-safe gethostbyname function to use in Asterisk.
Definition at line 183 of file utils.c.
References hp.
Referenced by ast_parse_arg(), config_load(), config_parse_variables(), create_addr(), festival_exec(), gtalk_update_stun(), iax_template_parse(), jingle_load_config(), jingle_update_stun(), launch_netscript(), process_sdp(), realtime_peer(), realtime_user(), reload_config(), rpt_exec(), and set_config().
00184 { 00185 int res; 00186 int herrno; 00187 int dots = 0; 00188 const char *s; 00189 struct hostent *result = NULL; 00190 /* Although it is perfectly legitimate to lookup a pure integer, for 00191 the sake of the sanity of people who like to name their peers as 00192 integers, we break with tradition and refuse to look up a 00193 pure integer */ 00194 s = host; 00195 res = 0; 00196 while (s && *s) { 00197 if (*s == '.') 00198 dots++; 00199 else if (!isdigit(*s)) 00200 break; 00201 s++; 00202 } 00203 if (!s || !*s) { 00204 /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */ 00205 if (dots != 3) 00206 return NULL; 00207 memset(hp, 0, sizeof(struct ast_hostent)); 00208 hp->hp.h_addrtype = AF_INET; 00209 hp->hp.h_addr_list = (void *) hp->buf; 00210 hp->hp.h_addr = hp->buf + sizeof(void *); 00211 /* For AF_INET, this will always be 4 */ 00212 hp->hp.h_length = 4; 00213 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0) 00214 return &hp->hp; 00215 return NULL; 00216 00217 } 00218 #ifdef HAVE_GETHOSTBYNAME_R_5 00219 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno); 00220 00221 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0]) 00222 return NULL; 00223 #else 00224 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno); 00225 00226 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0]) 00227 return NULL; 00228 #endif 00229 return &hp->hp; 00230 }
const char* ast_inet_ntoa | ( | struct in_addr | ia | ) |
thread-safe replacement for inet_ntoa().
Definition at line 436 of file utils.c.
References ast_threadstorage_get(), and inet_ntoa_buf.
Referenced by __attempt_transmit(), __find_callno(), __iax2_show_peers(), _skinny_show_device(), _skinny_show_devices(), acf_channel_read(), action_login(), add_ipv4_ie(), add_sdp(), ast_apply_ha(), ast_netsock_bindaddr(), ast_parse_arg(), authenticate(), calltoken_required(), check_access(), config_load(), create_client(), data_get_xml_add_child(), data_result_manager_output(), data_result_print_cli_node(), do_message(), dump_addr(), dump_ipaddr(), dundi_rexmit(), dundi_show_peer(), dundi_show_peers(), dundi_show_trans(), dundi_showframe(), dundi_xmit(), external_rtp_create(), find_command(), find_peer(), find_subchannel_and_lock(), find_tpeer(), function_iaxpeer(), gtalk_update_externip(), gtalk_update_stun(), handle_call_token(), handle_cli_iax2_set_debug(), handle_cli_iax2_show_callno_limits(), handle_cli_iax2_show_channels(), handle_cli_iax2_show_peer(), handle_cli_iax2_show_registry(), handle_command_response(), handle_error(), handle_mgcp_show_endpoints(), handle_open_receive_channel_ack_message(), handle_request(), handle_show_http(), handle_showmanconn(), handle_skinny_show_settings(), iax2_ack_registry(), iax2_prov_app(), iax2_trunk_queue(), iax_server(), iax_showframe(), jingle_create_candidates(), load_module(), manager_iax2_show_peer_list(), manager_iax2_show_registry(), mgcpsock_read(), oh323_addrcmp_str(), oh323_call(), oh323_set_rtp_peer(), parsing(), peercnt_add(), peercnt_modify(), peercnt_remove(), peers_data_provider_get(), phoneprov_callback(), process_request(), process_sdp(), purge_sessions(), raw_hangup(), realtime_peer(), realtime_user(), register_verify(), registry_rerequest(), resend_response(), rpt_exec(), sched_delay_remove(), score_address(), send_packet(), send_raw_client(), send_request(), send_response(), send_trunk(), session_do(), set_config(), set_peercnt_limit(), setup_incoming_call(), show_main_page(), skinny_session(), skinny_set_rtp_peer(), socket_process(), socket_process_meta(), start_rtp(), stun_monitor_request(), timing_read(), unistim_info(), unistimsock_read(), and update_registry().
00437 { 00438 char *buf; 00439 00440 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN))) 00441 return ""; 00442 00443 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN); 00444 }
void ast_join | ( | char * | s, | |
size_t | len, | |||
const char *const | w[] | |||
) |
Definition at line 1456 of file utils.c.
Referenced by __ast_cli_generator(), ast_agi_register(), ast_agi_unregister(), ast_cli_command_full(), cli_console_sendtext(), console_sendtext(), find_best(), handle_cli_agi_show(), handle_cli_check_permissions(), handle_help(), help1(), help_workhorse(), set_full_cmd(), and write_htmldump().
01457 { 01458 int x, ofs = 0; 01459 const char *src; 01460 01461 /* Join words into a string */ 01462 if (!s) 01463 return; 01464 for (x = 0; ofs < len && w[x]; x++) { 01465 if (x > 0) 01466 s[ofs++] = ' '; 01467 for (src = w[x]; *src && ofs < len; src++) 01468 s[ofs++] = *src; 01469 } 01470 if (ofs == len) 01471 ofs--; 01472 s[ofs] = '\0'; 01473 }
void ast_mark_lock_acquired | ( | void * | lock_addr | ) |
Mark the last lock as acquired.
Definition at line 615 of file utils.c.
References ast_threadstorage_get(), lock_info, pthread_mutex_lock, pthread_mutex_unlock, and thread_lock_info.
Referenced by __ast_pthread_mutex_lock(), __ast_pthread_mutex_trylock(), __ast_rwlock_rdlock(), __ast_rwlock_tryrdlock(), __ast_rwlock_trywrlock(), and __ast_rwlock_wrlock().
00616 { 00617 struct thr_lock_info *lock_info; 00618 00619 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00620 return; 00621 00622 pthread_mutex_lock(&lock_info->lock); 00623 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) { 00624 lock_info->locks[lock_info->num_locks - 1].pending = 0; 00625 } 00626 pthread_mutex_unlock(&lock_info->lock); 00627 }
void ast_mark_lock_failed | ( | void * | lock_addr | ) |
Mark the last lock as failed (trylock).
Definition at line 629 of file utils.c.
References ast_threadstorage_get(), lock_info, pthread_mutex_lock, pthread_mutex_unlock, and thread_lock_info.
Referenced by __ast_pthread_mutex_trylock(), __ast_rwlock_tryrdlock(), and __ast_rwlock_trywrlock().
00630 { 00631 struct thr_lock_info *lock_info; 00632 00633 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00634 return; 00635 00636 pthread_mutex_lock(&lock_info->lock); 00637 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) { 00638 lock_info->locks[lock_info->num_locks - 1].pending = -1; 00639 lock_info->locks[lock_info->num_locks - 1].times_locked--; 00640 } 00641 pthread_mutex_unlock(&lock_info->lock); 00642 }
void ast_md5_hash | ( | char * | output, | |
const char * | input | |||
) |
Produces MD5 hash based on input string.
Definition at line 233 of file utils.c.
References md5(), MD5Final(), MD5Init(), and MD5Update().
Referenced by build_reply_digest(), and md5().
00234 { 00235 struct MD5Context md5; 00236 unsigned char digest[16]; 00237 char *ptr; 00238 int x; 00239 00240 MD5Init(&md5); 00241 MD5Update(&md5, (const unsigned char *) input, strlen(input)); 00242 MD5Final(digest, &md5); 00243 ptr = output; 00244 for (x = 0; x < 16; x++) 00245 ptr += sprintf(ptr, "%2.2x", digest[x]); 00246 }
int ast_mkdir | ( | const char * | path, | |
int | mode | |||
) |
Recursively create directory path.
path | The directory path to create | |
mode | The permissions with which to try to create the directory |
Definition at line 1902 of file utils.c.
References ast_strdupa, errno, and len().
Referenced by ast_monitor_change_fname(), ast_monitor_start(), conf_run(), create_dirpath(), dictate_exec(), init_logger(), load_module(), mixmonitor_exec(), reload_logger(), remove_from_queue(), setup_privacy_args(), sms_nextoutgoing(), sms_writefile(), testclient_exec(), testserver_exec(), and write_history().
01903 { 01904 char *ptr; 01905 int len = strlen(path), count = 0, x, piececount = 0; 01906 char *tmp = ast_strdupa(path); 01907 char **pieces; 01908 char *fullpath = alloca(len + 1); 01909 int res = 0; 01910 01911 for (ptr = tmp; *ptr; ptr++) { 01912 if (*ptr == '/') 01913 count++; 01914 } 01915 01916 /* Count the components to the directory path */ 01917 pieces = alloca(count * sizeof(*pieces)); 01918 for (ptr = tmp; *ptr; ptr++) { 01919 if (*ptr == '/') { 01920 *ptr = '\0'; 01921 pieces[piececount++] = ptr + 1; 01922 } 01923 } 01924 01925 *fullpath = '\0'; 01926 for (x = 0; x < piececount; x++) { 01927 /* This looks funky, but the buffer is always ideally-sized, so it's fine. */ 01928 strcat(fullpath, "/"); 01929 strcat(fullpath, pieces[x]); 01930 res = mkdir(fullpath, mode); 01931 if (res && errno != EEXIST) 01932 return errno; 01933 } 01934 return 0; 01935 }
int ast_parse_digest | ( | const char * | digest, | |
struct ast_http_digest * | d, | |||
int | request, | |||
int | pedantic | |||
) |
Parse digest authorization header.
Definition at line 1959 of file utils.c.
References ast_free, ast_log(), ast_skip_blanks(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_string_field_set, ast_strlen_zero(), ast_http_digest::cnonce, LOG_WARNING, ast_http_digest::nc, ast_http_digest::nonce, ast_http_digest::qop, ast_http_digest::realm, ast_http_digest::response, str, ast_http_digest::uri, and ast_http_digest::username.
01959 { 01960 int i; 01961 char *c, key[512], val[512], tmp[512]; 01962 struct ast_str *str = ast_str_create(16); 01963 01964 if (ast_strlen_zero(digest) || !d || !str) { 01965 ast_free(str); 01966 return -1; 01967 } 01968 01969 ast_str_set(&str, 0, "%s", digest); 01970 01971 c = ast_skip_blanks(ast_str_buffer(str)); 01972 01973 if (strncasecmp(tmp, "Digest ", strlen("Digest "))) { 01974 ast_log(LOG_WARNING, "Missing Digest.\n"); 01975 ast_free(str); 01976 return -1; 01977 } 01978 c += strlen("Digest "); 01979 01980 /* lookup for keys/value pair */ 01981 while (*c && *(c = ast_skip_blanks(c))) { 01982 /* find key */ 01983 i = 0; 01984 while (*c && *c != '=' && *c != ',' && !isspace(*c)) { 01985 key[i++] = *c++; 01986 } 01987 key[i] = '\0'; 01988 c = ast_skip_blanks(c); 01989 if (*c == '=') { 01990 c = ast_skip_blanks(++c); 01991 i = 0; 01992 if (*c == '\"') { 01993 /* in quotes. Skip first and look for last */ 01994 c++; 01995 while (*c && *c != '\"') { 01996 if (*c == '\\' && c[1] != '\0') { /* unescape chars */ 01997 c++; 01998 } 01999 val[i++] = *c++; 02000 } 02001 } else { 02002 /* token */ 02003 while (*c && *c != ',' && !isspace(*c)) { 02004 val[i++] = *c++; 02005 } 02006 } 02007 val[i] = '\0'; 02008 } 02009 02010 while (*c && *c != ',') { 02011 c++; 02012 } 02013 if (*c) { 02014 c++; 02015 } 02016 02017 if (!strcasecmp(key, "username")) { 02018 ast_string_field_set(d, username, val); 02019 } else if (!strcasecmp(key, "realm")) { 02020 ast_string_field_set(d, realm, val); 02021 } else if (!strcasecmp(key, "nonce")) { 02022 ast_string_field_set(d, nonce, val); 02023 } else if (!strcasecmp(key, "uri")) { 02024 ast_string_field_set(d, uri, val); 02025 } else if (!strcasecmp(key, "domain")) { 02026 ast_string_field_set(d, domain, val); 02027 } else if (!strcasecmp(key, "response")) { 02028 ast_string_field_set(d, response, val); 02029 } else if (!strcasecmp(key, "algorithm")) { 02030 if (strcasecmp(val, "MD5")) { 02031 ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", val); 02032 return -1; 02033 } 02034 } else if (!strcasecmp(key, "cnonce")) { 02035 ast_string_field_set(d, cnonce, val); 02036 } else if (!strcasecmp(key, "opaque")) { 02037 ast_string_field_set(d, opaque, val); 02038 } else if (!strcasecmp(key, "qop") && !strcasecmp(val, "auth")) { 02039 d->qop = 1; 02040 } else if (!strcasecmp(key, "nc")) { 02041 unsigned long u; 02042 if (sscanf(val, "%30lx", &u) != 1) { 02043 ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", val); 02044 return -1; 02045 } 02046 ast_string_field_set(d, nc, val); 02047 } 02048 } 02049 ast_free(str); 02050 02051 /* Digest checkout */ 02052 if (ast_strlen_zero(d->realm) || ast_strlen_zero(d->nonce)) { 02053 /* "realm" and "nonce" MUST be always exist */ 02054 return -1; 02055 } 02056 02057 if (!request) { 02058 /* Additional check for Digest response */ 02059 if (ast_strlen_zero(d->username) || ast_strlen_zero(d->uri) || ast_strlen_zero(d->response)) { 02060 return -1; 02061 } 02062 02063 if (pedantic && d->qop && (ast_strlen_zero(d->cnonce) || ast_strlen_zero(d->nc))) { 02064 return -1; 02065 } 02066 } 02067 02068 return 0; 02069 }
char* ast_process_quotes_and_slashes | ( | char * | start, | |
char | find, | |||
char | replace_with | |||
) |
Process a string to find and replace characters.
start | The string to analyze | |
find | The character to find | |
replace_with | The character that will replace the one we are looking for |
Definition at line 1430 of file utils.c.
01431 { 01432 char *dataPut = start; 01433 int inEscape = 0; 01434 int inQuotes = 0; 01435 01436 for (; *start; start++) { 01437 if (inEscape) { 01438 *dataPut++ = *start; /* Always goes verbatim */ 01439 inEscape = 0; 01440 } else { 01441 if (*start == '\\') { 01442 inEscape = 1; /* Do not copy \ into the data */ 01443 } else if (*start == '\'') { 01444 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */ 01445 } else { 01446 /* Replace , with |, unless in quotes */ 01447 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start); 01448 } 01449 } 01450 } 01451 if (start != dataPut) 01452 *dataPut = 0; 01453 return dataPut; 01454 }
int ast_pthread_create_detached_stack | ( | pthread_t * | thread, | |
pthread_attr_t * | attr, | |||
void *(*)(void *) | start_routine, | |||
void * | data, | |||
size_t | stacksize, | |||
const char * | file, | |||
const char * | caller, | |||
int | line, | |||
const char * | start_fn | |||
) |
Definition at line 1031 of file utils.c.
References ast_log(), ast_pthread_create_stack(), errno, and LOG_WARNING.
01034 { 01035 unsigned char attr_destroy = 0; 01036 int res; 01037 01038 if (!attr) { 01039 attr = alloca(sizeof(*attr)); 01040 pthread_attr_init(attr); 01041 attr_destroy = 1; 01042 } 01043 01044 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED))) 01045 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno)); 01046 01047 res = ast_pthread_create_stack(thread, attr, start_routine, data, 01048 stacksize, file, caller, line, start_fn); 01049 01050 if (attr_destroy) 01051 pthread_attr_destroy(attr); 01052 01053 return res; 01054 }
int ast_pthread_create_stack | ( | pthread_t * | thread, | |
pthread_attr_t * | attr, | |||
void *(*)(void *) | start_routine, | |||
void * | data, | |||
size_t | stacksize, | |||
const char * | file, | |||
const char * | caller, | |||
int | line, | |||
const char * | start_fn | |||
) |
Definition at line 982 of file utils.c.
References asprintf, ast_log(), ast_malloc, AST_STACKSIZE, dummy_start(), errno, LOG_WARNING, and pthread_create.
Referenced by ast_pthread_create_detached_stack().
00985 { 00986 #if !defined(LOW_MEMORY) 00987 struct thr_arg *a; 00988 #endif 00989 00990 if (!attr) { 00991 attr = alloca(sizeof(*attr)); 00992 pthread_attr_init(attr); 00993 } 00994 00995 #ifdef __linux__ 00996 /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED, 00997 which is kind of useless. Change this here to 00998 PTHREAD_INHERIT_SCHED; that way the -p option to set realtime 00999 priority will propagate down to new threads by default. 01000 This does mean that callers cannot set a different priority using 01001 PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set 01002 the priority afterwards with pthread_setschedparam(). */ 01003 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED))) 01004 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno)); 01005 #endif 01006 01007 if (!stacksize) 01008 stacksize = AST_STACKSIZE; 01009 01010 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE))) 01011 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno)); 01012 01013 #if !defined(LOW_MEMORY) 01014 if ((a = ast_malloc(sizeof(*a)))) { 01015 a->start_routine = start_routine; 01016 a->data = data; 01017 start_routine = dummy_start; 01018 if (asprintf(&a->name, "%-20s started at [%5d] %s %s()", 01019 start_fn, line, file, caller) < 0) { 01020 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 01021 a->name = NULL; 01022 } 01023 data = a; 01024 } 01025 #endif /* !LOW_MEMORY */ 01026 01027 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */ 01028 }
long int ast_random | ( | void | ) |
Definition at line 1406 of file utils.c.
References ast_mutex_lock, ast_mutex_unlock, and randomlock.
Referenced by acf_rand_exec(), action_challenge(), add_sdp(), agent_new(), agi_handle_command(), ast_lock_path_lockfile(), ast_moh_files_next(), ast_rtp_change_source(), ast_rtp_new(), ast_udptl_new_with_bindaddr(), authenticate_request(), build_iv(), build_rand_pad(), build_reply_digest(), calc_metric(), calc_rxstamp(), caldav_write_event(), callno_hash(), create_channel_name(), generate_exchange_uuid(), generate_random_string(), get_trans_id(), gtalk_alloc(), gtalk_create_candidates(), gtalk_new(), handle_incoming(), handle_response_invite(), iax2_key_rotate(), iax2_start_transfer(), jingle_alloc(), jingle_create_candidates(), jingle_new(), load_module(), local_new(), make_email_file(), make_our_tag(), moh_files_alloc(), multicast_rtp_new(), ogg_vorbis_rewrite(), osp_create_uuid(), page_exec(), park_space_reserve(), process_weights(), reg_source_db(), registry_authrequest(), reqprep(), say_periodic_announcement(), sendmail(), set_nonce_randdata(), sip_alloc(), socket_read(), start_rtp(), stun_req_id(), transmit_invite(), transmit_register(), transmit_response_using_temp(), and try_firmware().
01407 { 01408 long int res; 01409 #ifdef HAVE_DEV_URANDOM 01410 if (dev_urandom_fd >= 0) { 01411 int read_res = read(dev_urandom_fd, &res, sizeof(res)); 01412 if (read_res > 0) { 01413 long int rm = RAND_MAX; 01414 res = res < 0 ? ~res : res; 01415 rm++; 01416 return res % rm; 01417 } 01418 } 01419 #endif 01420 #ifdef linux 01421 res = random(); 01422 #else 01423 ast_mutex_lock(&randomlock); 01424 res = random(); 01425 ast_mutex_unlock(&randomlock); 01426 #endif 01427 return res; 01428 }
void ast_remove_lock_info | ( | void * | lock_addr, | |
struct ast_bt * | bt | |||
) |
remove lock info for the current thread
this gets called by ast_mutex_unlock so that information on the lock can be removed from the current thread's lock info struct.
Definition at line 676 of file utils.c.
References ast_threadstorage_get(), lock_info, thr_lock_info::num_locks, pthread_mutex_lock, pthread_mutex_unlock, and thread_lock_info.
Referenced by __ast_cond_timedwait(), __ast_cond_wait(), __ast_pthread_mutex_lock(), __ast_pthread_mutex_unlock(), __ast_rwlock_rdlock(), __ast_rwlock_unlock(), and __ast_rwlock_wrlock().
00680 { 00681 struct thr_lock_info *lock_info; 00682 int i = 0; 00683 00684 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00685 return; 00686 00687 pthread_mutex_lock(&lock_info->lock); 00688 00689 for (i = lock_info->num_locks - 1; i >= 0; i--) { 00690 if (lock_info->locks[i].lock_addr == lock_addr) 00691 break; 00692 } 00693 00694 if (i == -1) { 00695 /* Lock not found :( */ 00696 pthread_mutex_unlock(&lock_info->lock); 00697 return; 00698 } 00699 00700 if (lock_info->locks[i].times_locked > 1) { 00701 lock_info->locks[i].times_locked--; 00702 #ifdef HAVE_BKTR 00703 lock_info->locks[i].backtrace = bt; 00704 #endif 00705 pthread_mutex_unlock(&lock_info->lock); 00706 return; 00707 } 00708 00709 if (i < lock_info->num_locks - 1) { 00710 /* Not the last one ... *should* be rare! */ 00711 memmove(&lock_info->locks[i], &lock_info->locks[i + 1], 00712 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0])); 00713 } 00714 00715 lock_info->num_locks--; 00716 00717 pthread_mutex_unlock(&lock_info->lock); 00718 }
void ast_sha1_hash | ( | char * | output, | |
const char * | input | |||
) |
Produces SHA1 hash based on input string.
Definition at line 249 of file utils.c.
References SHA1Input(), SHA1Reset(), and SHA1Result().
Referenced by aji_act_hook(), handle_call_token(), jabber_make_auth(), and sha1().
00250 { 00251 struct SHA1Context sha; 00252 char *ptr; 00253 int x; 00254 uint8_t Message_Digest[20]; 00255 00256 SHA1Reset(&sha); 00257 00258 SHA1Input(&sha, (const unsigned char *) input, strlen(input)); 00259 00260 SHA1Result(&sha, Message_Digest); 00261 ptr = output; 00262 for (x = 0; x < 20; x++) 00263 ptr += sprintf(ptr, "%2.2x", Message_Digest[x]); 00264 }
void ast_store_lock_info | ( | enum ast_lock_type | type, | |
const char * | filename, | |||
int | line_num, | |||
const char * | func, | |||
const char * | lock_name, | |||
void * | lock_addr, | |||
struct ast_bt * | bt | |||
) |
Store lock info for the current thread.
This function gets called in ast_mutex_lock() and ast_mutex_trylock() so that information about this lock can be stored in this thread's lock info struct. The lock is marked as pending as the thread is waiting on the lock. ast_mark_lock_acquired() will mark it as held by this thread.
Definition at line 556 of file utils.c.
References ast_threadstorage_get(), HAVE_BKTR, lock_info, pthread_mutex_lock, pthread_mutex_unlock, and thread_lock_info.
Referenced by __ast_cond_timedwait(), __ast_cond_wait(), __ast_pthread_mutex_lock(), __ast_pthread_mutex_trylock(), __ast_rwlock_rdlock(), __ast_rwlock_timedrdlock(), __ast_rwlock_timedwrlock(), __ast_rwlock_tryrdlock(), __ast_rwlock_trywrlock(), and __ast_rwlock_wrlock().
00562 { 00563 struct thr_lock_info *lock_info; 00564 int i; 00565 00566 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00567 return; 00568 00569 pthread_mutex_lock(&lock_info->lock); 00570 00571 for (i = 0; i < lock_info->num_locks; i++) { 00572 if (lock_info->locks[i].lock_addr == lock_addr) { 00573 lock_info->locks[i].times_locked++; 00574 #ifdef HAVE_BKTR 00575 lock_info->locks[i].backtrace = bt; 00576 #endif 00577 pthread_mutex_unlock(&lock_info->lock); 00578 return; 00579 } 00580 } 00581 00582 if (lock_info->num_locks == AST_MAX_LOCKS) { 00583 /* Can't use ast_log here, because it will cause infinite recursion */ 00584 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'." 00585 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS); 00586 pthread_mutex_unlock(&lock_info->lock); 00587 return; 00588 } 00589 00590 if (i && lock_info->locks[i - 1].pending == -1) { 00591 /* The last lock on the list was one that this thread tried to lock but 00592 * failed at doing so. It has now moved on to something else, so remove 00593 * the old lock from the list. */ 00594 i--; 00595 lock_info->num_locks--; 00596 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0])); 00597 } 00598 00599 lock_info->locks[i].file = filename; 00600 lock_info->locks[i].line_num = line_num; 00601 lock_info->locks[i].func = func; 00602 lock_info->locks[i].lock_name = lock_name; 00603 lock_info->locks[i].lock_addr = lock_addr; 00604 lock_info->locks[i].times_locked = 1; 00605 lock_info->locks[i].type = type; 00606 lock_info->locks[i].pending = 1; 00607 #ifdef HAVE_BKTR 00608 lock_info->locks[i].backtrace = bt; 00609 #endif 00610 lock_info->num_locks++; 00611 00612 pthread_mutex_unlock(&lock_info->lock); 00613 }
char* ast_strip_quoted | ( | char * | s, | |
const char * | beg_quotes, | |||
const char * | end_quotes | |||
) |
Strip leading/trailing whitespace and quotes from a string.
s | The string to be stripped (will be modified). | |
beg_quotes | The list of possible beginning quote characters. | |
end_quotes | The list of matching ending quote characters. |
It can also remove beginning and ending quote (or quote-like) characters, in matching pairs. If the first character of the string matches any character in beg_quotes, and the last character of the string is the matching character in end_quotes, then they are removed from the string.
Examples:
ast_strip_quoted(buf, "\"", "\""); ast_strip_quoted(buf, "'", "'"); ast_strip_quoted(buf, "[{(", "]})");
Definition at line 1214 of file utils.c.
References ast_strip().
Referenced by ast_register_file_version(), get_rdnis(), iftime(), load_values_config(), parse_allowed_methods(), parse_cookies(), and parse_dial_string().
01215 { 01216 char *e; 01217 char *q; 01218 01219 s = ast_strip(s); 01220 if ((q = strchr(beg_quotes, *s)) && *q != '\0') { 01221 e = s + strlen(s) - 1; 01222 if (*e == *(end_quotes + (q - beg_quotes))) { 01223 s++; 01224 *e = '\0'; 01225 } 01226 } 01227 01228 return s; 01229 }
int ast_true | ( | const char * | val | ) |
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
0 | if val is a NULL pointer. | |
-1 | if "true". | |
0 | otherwise. |
Definition at line 1316 of file utils.c.
References ast_strlen_zero().
Referenced by __ast_http_load(), __ast_udptl_reload(), __init_manager(), _parse(), acf_curlopt_write(), acf_faxopt_write(), acf_transaction_write(), action_agent_logoff(), action_bridge(), action_originate(), action_updateconfig(), aji_create_client(), aji_load_config(), aoc_cli_debug_enable(), apply_general_options(), apply_option(), apply_outgoing(), ast_bridge_timelimit(), ast_jb_read_conf(), ast_plc_reload(), ast_tls_read_conf(), autopause2int(), build_device(), build_peer(), build_user(), config_parse_variables(), connect_link(), dahdi_r2_answer(), dahdi_set_dnd(), data_search_cmp_bool(), do_reload(), festival_exec(), func_channel_write_real(), func_inheritance_write(), func_mute_write(), get_encrypt_methods(), gtalk_load_config(), handle_common_options(), handle_logger_set_level(), handle_t38_options(), init_logger_chain(), jingle_load_config(), load_config(), load_config_meetme(), load_module(), load_moh_classes(), load_odbc_config(), load_rpt_vars(), local_ast_moh_start(), login_exec(), manager_add_queue_member(), manager_mutestream(), manager_pause_queue_member(), message_template_build(), misdn_answer(), odbc_load_module(), osp_load(), osplookup_exec(), parse_config(), parse_empty_options(), pbx_load_config(), pbx_load_users(), process_echocancel(), queue_set_global_params(), queue_set_param(), read_agent_config(), realtime_directory(), reload_config(), rtp_reload(), run_startup_commands(), search_directory(), search_directory_sub(), set_active(), set_config(), sla_load_config(), speex_write(), start_monitor_action(), strings_to_mask(), tds_load_module(), update_common_options(), xmldoc_get_syntax_cmd(), xmldoc_get_syntax_fun(), and xmldoc_get_syntax_manager().
01317 { 01318 if (ast_strlen_zero(s)) 01319 return 0; 01320 01321 /* Determine if this is a true value */ 01322 if (!strcasecmp(s, "yes") || 01323 !strcasecmp(s, "true") || 01324 !strcasecmp(s, "y") || 01325 !strcasecmp(s, "t") || 01326 !strcasecmp(s, "1") || 01327 !strcasecmp(s, "on")) 01328 return -1; 01329 01330 return 0; 01331 }
struct timeval ast_tvadd | ( | struct timeval | a, | |
struct timeval | b | |||
) |
Returns the sum of two timevals a + b.
Definition at line 1370 of file utils.c.
References ONE_MILLION, and tvfix().
Referenced by __get_from_jb(), acf_jabberreceive_read(), agent_hangup(), ast_audiohook_trigger_wait(), ast_channel_bridge(), ast_channel_cmpwhentohangup_tv(), ast_channel_setwhentohangup_tv(), ast_generic_bridge(), ast_poll2(), ast_rtp_dtmf_begin(), ast_rtp_dtmf_end_with_duration(), ast_sched_runq(), ast_smoother_read(), ast_translate(), calc_rxstamp(), calc_timestamp(), cli_tps_ping(), conf_run(), dial_exec_full(), do_cdr(), do_timing(), iax2_process_thread(), jb_get_and_deliver(), mb_poll_thread(), monmp3thread(), mp3_exec(), mwi_monitor_handler(), NBScat_exec(), sched_run(), sched_settime(), schedule_delivery(), sla_process_timers(), smdi_message_wait(), and timeout_write().
01371 { 01372 /* consistency checks to guarantee usec in 0..999999 */ 01373 a = tvfix(a); 01374 b = tvfix(b); 01375 a.tv_sec += b.tv_sec; 01376 a.tv_usec += b.tv_usec; 01377 if (a.tv_usec >= ONE_MILLION) { 01378 a.tv_sec++; 01379 a.tv_usec -= ONE_MILLION; 01380 } 01381 return a; 01382 }
struct timeval ast_tvsub | ( | struct timeval | a, | |
struct timeval | b | |||
) |
Returns the difference of two timevals a - b.
Definition at line 1384 of file utils.c.
References ONE_MILLION, and tvfix().
Referenced by __ast_rwlock_timedrdlock(), __ast_rwlock_timedwrlock(), ast_channel_bridge(), ast_poll2(), ast_sched_dump(), ast_translate(), ast_waitfor_nandfds(), calc_rxstamp(), calc_timestamp(), cli_tps_ping(), conf_run(), debug_check_frame_for_silence(), handle_showcalls(), handle_showuptime(), and pri_dchannel().
01385 { 01386 /* consistency checks to guarantee usec in 0..999999 */ 01387 a = tvfix(a); 01388 b = tvfix(b); 01389 a.tv_sec -= b.tv_sec; 01390 a.tv_usec -= b.tv_usec; 01391 if (a.tv_usec < 0) { 01392 a.tv_sec-- ; 01393 a.tv_usec += ONE_MILLION; 01394 } 01395 return a; 01396 }
char* ast_unescape_c | ( | char * | s | ) |
Convert some C escape sequences.
(\b\f\n\r\t)
Definition at line 1250 of file utils.c.
01251 { 01252 char c, *ret, *dst; 01253 01254 if (src == NULL) 01255 return NULL; 01256 for (ret = dst = src; (c = *src++); *dst++ = c ) { 01257 if (c != '\\') 01258 continue; /* copy char at the end of the loop */ 01259 switch ((c = *src++)) { 01260 case '\0': /* special, trailing '\' */ 01261 c = '\\'; 01262 break; 01263 case 'b': /* backspace */ 01264 c = '\b'; 01265 break; 01266 case 'f': /* form feed */ 01267 c = '\f'; 01268 break; 01269 case 'n': 01270 c = '\n'; 01271 break; 01272 case 'r': 01273 c = '\r'; 01274 break; 01275 case 't': 01276 c = '\t'; 01277 break; 01278 } 01279 /* default, use the char literally */ 01280 } 01281 *dst = '\0'; 01282 return ret; 01283 }
char* ast_unescape_semicolon | ( | char * | s | ) |
Strip backslash for "escaped" semicolons, the string to be stripped (will be modified).
Definition at line 1231 of file utils.c.
Referenced by sip_cli_notify().
01232 { 01233 char *e; 01234 char *work = s; 01235 01236 while ((e = strchr(work, ';'))) { 01237 if ((e > work) && (*(e-1) == '\\')) { 01238 memmove(e - 1, e, strlen(e) + 1); 01239 work = e; 01240 } else { 01241 work = e + 1; 01242 } 01243 } 01244 01245 return s; 01246 }
void ast_uri_decode | ( | char * | s | ) |
Decode URI, URN, URL (overwrite string).
s | String to be decoded |
Definition at line 419 of file utils.c.
Referenced by acf_curl_helper(), config_curl(), get_destination(), get_refer_info(), handle_request_invite(), http_decode(), parse_moved_contact(), realtime_curl(), realtime_multi_curl(), sip_new(), and uridecode().
00420 { 00421 char *o; 00422 unsigned int tmp; 00423 00424 for (o = s; *s; s++, o++) { 00425 if (*s == '%' && s[1] != '\0' && s[2] != '\0' && sscanf(s + 1, "%2x", &tmp) == 1) { 00426 /* have '%', two chars and correct parsing */ 00427 *o = tmp; 00428 s += 2; /* Will be incremented once more when we break out */ 00429 } else /* all other cases, just copy */ 00430 *o = *s; 00431 } 00432 *o = '\0'; 00433 }
char* ast_uri_encode | ( | const char * | string, | |
char * | outbuf, | |||
int | buflen, | |||
int | do_special_char | |||
) |
Turn text string to URI-encoded XX version.
Definition at line 386 of file utils.c.
Referenced by add_rpid(), build_contact(), config_curl(), destroy_curl(), initreqprep(), launch_asyncagi(), realtime_curl(), realtime_multi_curl(), require_curl(), store_curl(), update2_curl(), update_curl(), and uriencode().
00387 { 00388 const char *ptr = string; /* Start with the string */ 00389 char *out = outbuf; 00390 const char *mark = "-_.!~*'()"; /* no encode set, RFC 2396 section 2.3, RFC 3261 sec 25 */ 00391 00392 while (*ptr && out - outbuf < buflen - 1) { 00393 if ((const signed char) *ptr < 32 || *ptr == 0x7f || *ptr == '%' || 00394 (do_special_char && 00395 !(*ptr >= '0' && *ptr <= '9') && /* num */ 00396 !(*ptr >= 'A' && *ptr <= 'Z') && /* ALPHA */ 00397 !(*ptr >= 'a' && *ptr <= 'z') && /* alpha */ 00398 !strchr(mark, *ptr))) { /* mark set */ 00399 if (out - outbuf >= buflen - 3) { 00400 break; 00401 } 00402 00403 out += sprintf(out, "%%%02X", (unsigned char) *ptr); 00404 } else { 00405 *out = *ptr; /* Continue copying the string */ 00406 out++; 00407 } 00408 ptr++; 00409 } 00410 00411 if (buflen) { 00412 *out = '\0'; 00413 } 00414 00415 return outbuf; 00416 }
int ast_utils_init | ( | void | ) |
Definition at line 1937 of file utils.c.
References ARRAY_LEN, ast_cli_register_multiple(), base64_init(), and utils_cli.
Referenced by main().
01938 { 01939 #ifdef HAVE_DEV_URANDOM 01940 dev_urandom_fd = open("/dev/urandom", O_RDONLY); 01941 #endif 01942 base64_init(); 01943 #ifdef DEBUG_THREADS 01944 #if !defined(LOW_MEMORY) 01945 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli)); 01946 #endif 01947 #endif 01948 return 0; 01949 }
char* ast_utils_which | ( | const char * | binary, | |
char * | fullpath, | |||
size_t | fullpath_size | |||
) |
Resolve a binary to a full pathname.
binary | Name of the executable to resolve | |
fullpath | Buffer to hold the complete pathname | |
fullpath_size | Size of fullpath |
NULL | binary was not found or the environment variable PATH is not set |
Definition at line 2087 of file utils.c.
References ast_strdupa, and strsep().
Referenced by ast_bt_get_symbols().
02088 { 02089 const char *envPATH = getenv("PATH"); 02090 char *tpath, *path; 02091 struct stat unused; 02092 if (!envPATH) { 02093 return NULL; 02094 } 02095 tpath = ast_strdupa(envPATH); 02096 while ((path = strsep(&tpath, ":"))) { 02097 snprintf(fullpath, fullpath_size, "%s/%s", path, binary); 02098 if (!stat(fullpath, &unused)) { 02099 return fullpath; 02100 } 02101 } 02102 return NULL; 02103 }
int ast_wait_for_input | ( | int | fd, | |
int | ms | |||
) |
Definition at line 1056 of file utils.c.
References ast_poll.
Referenced by ast_tcptls_server_root(), dahdi_test_timer(), and moh_class_destructor().
01057 { 01058 struct pollfd pfd[1]; 01059 memset(pfd, 0, sizeof(pfd)); 01060 pfd[0].fd = fd; 01061 pfd[0].events = POLLIN|POLLPRI; 01062 return ast_poll(pfd, 1, ms); 01063 }
static int ast_wait_for_output | ( | int | fd, | |
int | timeoutms | |||
) | [static] |
Definition at line 1065 of file utils.c.
References ast_debug, ast_log(), ast_poll, ast_tvdiff_ms(), ast_tvnow(), errno, and LOG_ERROR.
Referenced by ast_careful_fwrite(), and ast_carefulwrite().
01066 { 01067 struct pollfd pfd = { 01068 .fd = fd, 01069 .events = POLLOUT, 01070 }; 01071 int res; 01072 struct timeval start = ast_tvnow(); 01073 int elapsed = 0; 01074 01075 /* poll() until the fd is writable without blocking */ 01076 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) { 01077 if (res == 0) { 01078 /* timed out. */ 01079 #ifndef STANDALONE 01080 ast_debug(1, "Timed out trying to write\n"); 01081 #endif 01082 return -1; 01083 } else if (res == -1) { 01084 /* poll() returned an error, check to see if it was fatal */ 01085 01086 if (errno == EINTR || errno == EAGAIN) { 01087 elapsed = ast_tvdiff_ms(ast_tvnow(), start); 01088 if (elapsed >= timeoutms) { 01089 return -1; 01090 } 01091 /* This was an acceptable error, go back into poll() */ 01092 continue; 01093 } 01094 01095 /* Fatal error, bail. */ 01096 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno)); 01097 01098 return -1; 01099 } 01100 elapsed = ast_tvdiff_ms(ast_tvnow(), start); 01101 if (elapsed >= timeoutms) { 01102 return -1; 01103 } 01104 } 01105 01106 return 0; 01107 }
static void base64_init | ( | void | ) | [static] |
Definition at line 350 of file utils.c.
Referenced by ast_utils_init().
00351 { 00352 int x; 00353 memset(b2a, -1, sizeof(b2a)); 00354 /* Initialize base-64 Conversion table */ 00355 for (x = 0; x < 26; x++) { 00356 /* A-Z */ 00357 base64[x] = 'A' + x; 00358 b2a['A' + x] = x; 00359 /* a-z */ 00360 base64[x + 26] = 'a' + x; 00361 b2a['a' + x] = x + 26; 00362 /* 0-9 */ 00363 if (x < 10) { 00364 base64[x + 52] = '0' + x; 00365 b2a['0' + x] = x + 52; 00366 } 00367 } 00368 base64[62] = '+'; 00369 base64[63] = '/'; 00370 b2a[(int)'+'] = 62; 00371 b2a[(int)'/'] = 63; 00372 }
static void* dummy_start | ( | void * | data | ) | [static] |
Definition at line 938 of file utils.c.
References ast_free, AST_LIST_INSERT_TAIL, AST_MUTEX_KIND, ast_register_thread(), ast_threadstorage_get(), ast_unregister_thread(), thr_arg::data, thr_lock_info::entry, lock_info, lock_infos_lock, ast_mutex_info::mutex, thr_arg::name, pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock, thr_arg::start_routine, strdup, and thread_lock_info.
Referenced by ast_pthread_create_stack().
00939 { 00940 void *ret; 00941 struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */ 00942 #ifdef DEBUG_THREADS 00943 struct thr_lock_info *lock_info; 00944 pthread_mutexattr_t mutex_attr; 00945 #endif 00946 00947 /* note that even though data->name is a pointer to allocated memory, 00948 we are not freeing it here because ast_register_thread is going to 00949 keep a copy of the pointer and then ast_unregister_thread will 00950 free the memory 00951 */ 00952 ast_free(data); 00953 ast_register_thread(a.name); 00954 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self()); 00955 00956 #ifdef DEBUG_THREADS 00957 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) 00958 return NULL; 00959 00960 lock_info->thread_id = pthread_self(); 00961 lock_info->thread_name = strdup(a.name); 00962 00963 pthread_mutexattr_init(&mutex_attr); 00964 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND); 00965 pthread_mutex_init(&lock_info->lock, &mutex_attr); 00966 pthread_mutexattr_destroy(&mutex_attr); 00967 00968 pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */ 00969 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry); 00970 pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */ 00971 #endif /* DEBUG_THREADS */ 00972 00973 ret = a.start_routine(a.data); 00974 00975 pthread_cleanup_pop(1); 00976 00977 return ret; 00978 }
static char* handle_show_locks | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 845 of file utils.c.
References append_lock_information(), ast_cli(), ast_free, AST_LIST_TRAVERSE, ast_str_append(), ast_str_buffer(), ast_str_create(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, lock_info, lock_infos_lock, ast_mutex_info::mutex, pthread_mutex_lock, pthread_mutex_unlock, str, and ast_cli_entry::usage.
00846 { 00847 struct thr_lock_info *lock_info; 00848 struct ast_str *str; 00849 00850 if (!(str = ast_str_create(4096))) 00851 return CLI_FAILURE; 00852 00853 switch (cmd) { 00854 case CLI_INIT: 00855 e->command = "core show locks"; 00856 e->usage = 00857 "Usage: core show locks\n" 00858 " This command is for lock debugging. It prints out which locks\n" 00859 "are owned by each active thread.\n"; 00860 return NULL; 00861 00862 case CLI_GENERATE: 00863 return NULL; 00864 } 00865 00866 ast_str_append(&str, 0, "\n" 00867 "=======================================================================\n" 00868 "=== Currently Held Locks ==============================================\n" 00869 "=======================================================================\n" 00870 "===\n" 00871 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n" 00872 "===\n"); 00873 00874 if (!str) 00875 return CLI_FAILURE; 00876 00877 pthread_mutex_lock(&lock_infos_lock.mutex); 00878 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) { 00879 int i; 00880 if (lock_info->num_locks) { 00881 ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id, 00882 lock_info->thread_name); 00883 pthread_mutex_lock(&lock_info->lock); 00884 for (i = 0; str && i < lock_info->num_locks; i++) { 00885 append_lock_information(&str, lock_info, i); 00886 } 00887 pthread_mutex_unlock(&lock_info->lock); 00888 if (!str) 00889 break; 00890 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n" 00891 "===\n"); 00892 if (!str) 00893 break; 00894 } 00895 } 00896 pthread_mutex_unlock(&lock_infos_lock.mutex); 00897 00898 if (!str) 00899 return CLI_FAILURE; 00900 00901 ast_str_append(&str, 0, "=======================================================================\n" 00902 "\n"); 00903 00904 if (!str) 00905 return CLI_FAILURE; 00906 00907 ast_cli(a->fd, "%s", ast_str_buffer(str)); 00908 00909 ast_free(str); 00910 00911 return CLI_SUCCESS; 00912 }
static void lock_info_destroy | ( | void * | data | ) | [static] |
Destroy a thread's lock info.
This gets called automatically when the thread stops
Definition at line 517 of file utils.c.
References AST_LIST_REMOVE, ast_log(), thr_lock_info::entry, lock_info, LOG_ERROR, pthread_mutex_lock, and pthread_mutex_unlock.
00518 { 00519 struct thr_lock_info *lock_info = data; 00520 int i; 00521 00522 pthread_mutex_lock(&lock_infos_lock.mutex); 00523 AST_LIST_REMOVE(&lock_infos, lock_info, entry); 00524 pthread_mutex_unlock(&lock_infos_lock.mutex); 00525 00526 00527 for (i = 0; i < lock_info->num_locks; i++) { 00528 if (lock_info->locks[i].pending == -1) { 00529 /* This just means that the last lock this thread went for was by 00530 * using trylock, and it failed. This is fine. */ 00531 break; 00532 } 00533 00534 ast_log(LOG_ERROR, 00535 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n", 00536 lock_info->thread_name, 00537 lock_info->locks[i].lock_name, 00538 lock_info->locks[i].lock_addr, 00539 lock_info->locks[i].func, 00540 lock_info->locks[i].file, 00541 lock_info->locks[i].line_num 00542 ); 00543 } 00544 00545 pthread_mutex_destroy(&lock_info->lock); 00546 if (lock_info->thread_name) 00547 free((void *) lock_info->thread_name); 00548 free(lock_info); 00549 }
static const char* locktype2str | ( | enum ast_lock_type | type | ) | [static] |
Definition at line 720 of file utils.c.
References AST_MUTEX, AST_RDLOCK, and AST_WRLOCK.
Referenced by append_lock_information().
00721 { 00722 switch (type) { 00723 case AST_MUTEX: 00724 return "MUTEX"; 00725 case AST_RDLOCK: 00726 return "RDLOCK"; 00727 case AST_WRLOCK: 00728 return "WRLOCK"; 00729 } 00730 00731 return "UNKNOWN"; 00732 }
void log_show_lock | ( | void * | this_lock_addr | ) |
log info for the current lock with ast_log().
This function can help you find highly temporal locks; locks that happen for a short time, but at unexpected times, usually at times that create a deadlock, Why is this thing locked right then? Who is locking it? Who am I fighting with for this lock?
To answer such questions, just call this routine before you would normally try to aquire a lock. It doesn't do anything if the lock is not acquired. If the lock is taken, it will publish a line or two to the console via ast_log().
Sometimes, the lock message is pretty uninformative. For instance, you might find that the lock is being aquired deep within the astobj2 code; this tells you little about higher level routines that call the astobj2 routines. But, using gdb, you can set a break at the ast_log below, and for that breakpoint, you can set the commands: where cont which will give a stack trace and continue. -- that aught to do the job!
Definition at line 814 of file utils.c.
References append_lock_information(), AST_LIST_TRAVERSE, ast_log(), ast_str_buffer(), ast_str_create(), lock_info, lock_infos_lock, LOG_NOTICE, ast_mutex_info::mutex, pthread_mutex_lock, pthread_mutex_unlock, and str.
00815 { 00816 struct thr_lock_info *lock_info; 00817 struct ast_str *str; 00818 00819 if (!(str = ast_str_create(4096))) { 00820 ast_log(LOG_NOTICE,"Could not create str\n"); 00821 return; 00822 } 00823 00824 00825 pthread_mutex_lock(&lock_infos_lock.mutex); 00826 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) { 00827 int i; 00828 pthread_mutex_lock(&lock_info->lock); 00829 for (i = 0; str && i < lock_info->num_locks; i++) { 00830 /* ONLY show info about this particular lock, if 00831 it's acquired... */ 00832 if (lock_info->locks[i].lock_addr == this_lock_addr) { 00833 append_lock_information(&str, lock_info, i); 00834 ast_log(LOG_NOTICE, "%s", ast_str_buffer(str)); 00835 break; 00836 } 00837 } 00838 pthread_mutex_unlock(&lock_info->lock); 00839 } 00840 pthread_mutex_unlock(&lock_infos_lock.mutex); 00841 ast_free(str); 00842 }
static size_t optimal_alloc_size | ( | size_t | size | ) | [static] |
Definition at line 1495 of file utils.c.
References ALLOCATOR_OVERHEAD.
Referenced by __ast_calloc_with_stringfields(), and add_string_pool().
01496 { 01497 unsigned int count; 01498 01499 size += ALLOCATOR_OVERHEAD; 01500 01501 for (count = 1; size; size >>= 1, count++); 01502 01503 return (1 << count) - ALLOCATOR_OVERHEAD; 01504 }
static struct timeval tvfix | ( | struct timeval | a | ) | [static] |
Definition at line 1355 of file utils.c.
References ast_log(), LOG_WARNING, and ONE_MILLION.
Referenced by ast_tvadd(), and ast_tvsub().
01356 { 01357 if (a.tv_usec >= ONE_MILLION) { 01358 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n", 01359 (long)a.tv_sec, (long int) a.tv_usec); 01360 a.tv_sec += a.tv_usec / ONE_MILLION; 01361 a.tv_usec %= ONE_MILLION; 01362 } else if (a.tv_usec < 0) { 01363 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n", 01364 (long)a.tv_sec, (long int) a.tv_usec); 01365 a.tv_usec = 0; 01366 } 01367 return a; 01368 }
Definition at line 1491 of file utils.c.
Referenced by __ast_calloc_with_stringfields(), and __ast_string_field_ptr_build_va().
struct { ... } __ast_string_field_empty_buffer [static] |
char base64[64] [static] |
int dev_urandom_fd [static] |
ast_mutex_t fetchadd_m = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
struct ast_threadstorage inet_ntoa_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_inet_ntoa_buf , .custom_init = NULL , } [static] |
ast_mutex_t lock_infos_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Locked when accessing the lock_infos list.
Definition at line 506 of file utils.c.
Referenced by dummy_start(), handle_show_locks(), and log_show_lock().
ast_mutex_t randomlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
glibc puts a lock inside random(3), so that the results are thread-safe. BSD libc (and others) do not.
Definition at line 1403 of file utils.c.
Referenced by ast_random().
char string[1] |
Definition at line 1488 of file utils.c.
Referenced by channel_steer(), filter(), function_cop(), pp_each_user_helper(), and private_enum_init().
struct ast_threadstorage thread_lock_info = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_lock_info , .custom_init = NULL , } [static] |
Definition at line 554 of file utils.c.
Referenced by ast_find_lock_info(), ast_mark_lock_acquired(), ast_mark_lock_failed(), ast_remove_lock_info(), ast_store_lock_info(), and dummy_start().
struct ast_cli_entry utils_cli[] [static] |
Initial value:
{ { .handler = handle_show_locks , .summary = "Show which locks are held by which thread" ,__VA_ARGS__ }, }
Definition at line 914 of file utils.c.
Referenced by ast_utils_init().