Skip to content
Snippets Groups Projects
extconf.c 171 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*  
     * Asterisk -- An open source telephony toolkit.
     *
     * Copyright (C) 2006, Digium, Inc.
     *
     * Steve Murphy <murf@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.
     */
    
    
    
    Andrew Latham's avatar
    Andrew Latham committed
    /*!
     * \file extconf
    
     * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
     * for operations outside of asterisk. A huge, awful hack.
     *
     */
    
    Andrew Latham's avatar
    Andrew Latham committed
    /*!
     * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
     * \addtogroup configuration_file Configuration Files
     */
    
    /*!
     * \page extconfig.conf extconfig.conf
     * \verbinclude extconfig.conf.sample
     */
    
    /*!
     * \page extensions.conf extensions.conf
     * \verbinclude extensions.conf.sample
     */
    
    
    /*** MODULEINFO
    	<support_level>extended</support_level>
     ***/
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    #undef DEBUG_THREADS
    
    #include "asterisk/compat.h"
    
    #include "asterisk/paths.h"	/* we use AST_CONFIG_DIR */
    
    
    #include <errno.h>
    #include <time.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/wait.h>
    #include <stdarg.h>
    #include <string.h>
    #include <locale.h>
    #include <ctype.h>
    #if !defined(SOLARIS) && !defined(__CYGWIN__)
    #include <err.h>
    #endif
    #include <regex.h>
    #include <limits.h>
    #include <pthread.h>
    #include <netdb.h>
    #include <sys/param.h>
    
    #include <signal.h>
    
    static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
    void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
    
    
    #define ASINCLUDE_GLOB 1
    #ifdef AST_INCLUDE_GLOB
    
    # include <glob.h>
    #endif
    
    #define AST_API_MODULE  1 /* gimme the inline defs! */
    struct ast_channel 
    {
    	char x; /* basically empty! */
    };
    
    
    
    #include "asterisk/inline_api.h"
    #include "asterisk/endian.h"
    #include "asterisk/ast_expr.h"
    
    #include "asterisk/extconf.h"
    
    Steve Murphy's avatar
    Steve Murphy committed
    
    
    #define EVENTLOG "event_log"
    #define	QUEUELOG	"queue_log"
    
    #define DEBUG_M(a) { \
    	a; \
    }
    
    #define VERBOSE_PREFIX_1 " "
    #define VERBOSE_PREFIX_2 "  == "
    #define VERBOSE_PREFIX_3 "    -- "
    #define VERBOSE_PREFIX_4 "       > "
    
    
    
    void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
    
    	__attribute__((format(printf, 5, 6)));
    
    
    /* IN CONFLICT: void ast_verbose(const char *fmt, ...)
    
       __attribute__((format(printf, 1, 2))); */
    
    
    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);
    
    #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
    
    #ifdef LOG_DEBUG
    #undef LOG_DEBUG
    #endif
    #define __LOG_DEBUG    0
    #define LOG_DEBUG      __LOG_DEBUG, _A_
    
    #ifdef LOG_EVENT
    #undef LOG_EVENT
    #endif
    #define __LOG_EVENT    1
    #define LOG_EVENT      __LOG_EVENT, _A_
    
    #ifdef LOG_NOTICE
    #undef LOG_NOTICE
    #endif
    #define __LOG_NOTICE   2
    #define LOG_NOTICE     __LOG_NOTICE, _A_
    
    #ifdef LOG_WARNING
    #undef LOG_WARNING
    #endif
    #define __LOG_WARNING  3
    #define LOG_WARNING    __LOG_WARNING, _A_
    
    #ifdef LOG_ERROR
    #undef LOG_ERROR
    #endif
    #define __LOG_ERROR    4
    #define LOG_ERROR      __LOG_ERROR, _A_
    
    #ifdef LOG_VERBOSE
    #undef LOG_VERBOSE
    #endif
    #define __LOG_VERBOSE  5
    #define LOG_VERBOSE    __LOG_VERBOSE, _A_
    
    #ifdef LOG_DTMF
    #undef LOG_DTMF
    #endif
    #define __LOG_DTMF  6
    #define LOG_DTMF    __LOG_DTMF, _A_
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* lock.h */
    
    #define _ASTERISK_LOCK_H /* A small indication that this is horribly wrong. */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef	HAVE_MTX_PROFILE
    #define	__MTX_PROF(a)	return pthread_mutex_lock((a))
    #else
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define	__MTX_PROF(a)	do {			\
    	int i;					\
    	/* profile only non-blocking events */	\
    	ast_mark(mtx_prof, 1);			\
    	i = pthread_mutex_trylock((a));		\
    	ast_mark(mtx_prof, 0);			\
    	if (!i)					\
    		return i;			\
    	else					\
    		return pthread_mutex_lock((a)); \
    	} while (0)
    #endif	/* HAVE_MTX_PROFILE */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_PTHREADT_NULL (pthread_t) -1
    #define AST_PTHREADT_STOP (pthread_t) -2
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(SOLARIS) || defined(BSD)
    #define AST_MUTEX_INIT_W_CONSTRUCTORS
    #endif /* SOLARIS || BSD */
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* Asterisk REQUIRES recursive (not error checking) mutexes
       and will not run without them. */
    #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
    #define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
    #define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE_NP
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_MUTEX_INITIALIZER
    #define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE
    #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef DEBUG_THREADS
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef THREAD_CRASH
    #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
    #else
    #define DO_THREAD_CRASH do { } while (0)
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MAX_REENTRANCY 10
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_mutex_info {
    	pthread_mutex_t mutex;
    	/*! Track which thread holds this lock */
    	unsigned int track:1;
    	const char *file[AST_MAX_REENTRANCY];
    	int lineno[AST_MAX_REENTRANCY];
    	int reentrancy;
    	const char *func[AST_MAX_REENTRANCY];
    	pthread_t thread[AST_MAX_REENTRANCY];
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef struct ast_mutex_info ast_mutex_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_cond_t ast_cond_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static pthread_mutex_t empty_mutex;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void __attribute__((constructor)) init_empty_mutex(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	memset(&empty_mutex, 0, sizeof(empty_mutex));
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
    						const char *mutex_name, ast_mutex_t *t,
    						pthread_mutexattr_t *attr) 
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		if ((t->mutex) != (empty_mutex)) {
    			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
    					   filename, lineno, func, mutex_name);
    			__ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
    					   t->file[0], t->lineno[0], t->func[0], mutex_name);
    			DO_THREAD_CRASH;
    			return 0;
    		}
    
    Steve Murphy's avatar
    Steve Murphy committed
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	t->file[0] = filename;
    	t->lineno[0] = lineno;
    	t->func[0] = func;
    	t->thread[0]  = 0;
    	t->reentrancy = 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_mutex_init(&t->mutex, attr);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
    					   const char *mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	static pthread_mutexattr_t  attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_init(&attr);
    	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
    						const char *mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    				   filename, lineno, func, mutex_name);
    	}
    #endif
    
    	res = pthread_mutex_trylock(&t->mutex);
    	switch (res) {
    	case 0:
    		pthread_mutex_unlock(&t->mutex);
    		break;
    	case EINVAL:
    		__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
    				  filename, lineno, func, mutex_name);
    		break;
    	case EBUSY:
    		__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
    				   filename, lineno, func, mutex_name);
    		__ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
    				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
    		break;
    	}
    
    	if ((res = pthread_mutex_destroy(&t->mutex)))
    		__ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
    				   filename, lineno, func, strerror(res));
    #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
    	else
    		t->mutex = PTHREAD_MUTEX_INIT_VALUE;
    #endif
    	t->file[0] = filename;
    	t->lineno[0] = lineno;
    	t->func[0] = func;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
                                               const char* mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    				 filename, lineno, func, mutex_name);
    		ast_mutex_init(t);
    	}
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef DETECT_DEADLOCKS
    	{
    		time_t seconds = time(NULL);
    		time_t current;
    		do {
    #ifdef	HAVE_MTX_PROFILE
    			ast_mark(mtx_prof, 1);
    #endif
    			res = pthread_mutex_trylock(&t->mutex);
    #ifdef	HAVE_MTX_PROFILE
    			ast_mark(mtx_prof, 0);
    #endif
    			if (res == EBUSY) {
    				current = time(NULL);
    				if ((current - seconds) && (!((current - seconds) % 5))) {
    					__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
    							   filename, lineno, func, (int)(current - seconds), mutex_name);
    					__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
    							   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
    							   t->func[t->reentrancy-1], mutex_name);
    				}
    				usleep(200);
    			}
    		} while (res == EBUSY);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef	HAVE_MTX_PROFILE
    	ast_mark(mtx_prof, 1);
    	res = pthread_mutex_trylock(&t->mutex);
    	ast_mark(mtx_prof, 0);
    	if (res)
    #endif
    	res = pthread_mutex_lock(&t->mutex);
    #endif /* DETECT_DEADLOCKS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!res) {
    		if (t->reentrancy < AST_MAX_REENTRANCY) {
    			t->file[t->reentrancy] = filename;
    			t->lineno[t->reentrancy] = lineno;
    			t->func[t->reentrancy] = func;
    			t->thread[t->reentrancy] = pthread_self();
    			t->reentrancy++;
    		} else {
    			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
    							   filename, lineno, func, mutex_name);
    		}
    	} else {
    		__ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
    				   filename, lineno, func, strerror(errno));
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
                                                  const char* mutex_name, ast_mutex_t *t)
    {
    	int res;
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    				   filename, lineno, func, mutex_name);
    		ast_mutex_init(t);
    	}
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!(res = pthread_mutex_trylock(&t->mutex))) {
    		if (t->reentrancy < AST_MAX_REENTRANCY) {
    			t->file[t->reentrancy] = filename;
    			t->lineno[t->reentrancy] = lineno;
    			t->func[t->reentrancy] = func;
    			t->thread[t->reentrancy] = pthread_self();
    			t->reentrancy++;
    		} else {
    			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
    					   filename, lineno, func, mutex_name);
    		}
    	} else {
    		__ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
                                       t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
    					     const char *mutex_name, ast_mutex_t *t)
    {
    	int res;
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    				   filename, lineno, func, mutex_name);
    	}
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
    		__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
    				   filename, lineno, func, mutex_name);
    		__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
    				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (--t->reentrancy < 0) {
    		__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
    				   filename, lineno, func, mutex_name);
    		t->reentrancy = 0;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (t->reentrancy < AST_MAX_REENTRANCY) {
    		t->file[t->reentrancy] = NULL;
    		t->lineno[t->reentrancy] = 0;
    		t->func[t->reentrancy] = NULL;
    		t->thread[t->reentrancy] = 0;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((res = pthread_mutex_unlock(&t->mutex))) {
    		__ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
    				   filename, lineno, func, strerror(res));
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else /* !DEBUG_THREADS */
    
    
    typedef pthread_mutex_t ast_mutex_t;
    
    #define AST_MUTEX_INIT_VALUE	((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
    
    static inline int ast_mutex_init(ast_mutex_t *pmutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_t attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_init(&attr);
    	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_mutex_init(pmutex, &attr);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_cond_t ast_cond_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #endif /* !DEBUG_THREADS */
    
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
     constructors/destructors to create/destroy mutexes.  */
    #define __AST_MUTEX_DEFINE(scope, mutex) \
    	scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
    
    static void  __attribute__((constructor)) init_##mutex(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
    	ast_mutex_init(&mutex); \
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
    /* By default, use static initialization of mutexes. */ 
    #define __AST_MUTEX_DEFINE(scope, mutex) \
    	scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
    #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
    #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef __linux__
    #define pthread_create __use_ast_pthread_create_instead__
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_rwlock_t ast_rwlock_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
    {
    	pthread_rwlockattr_t attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_rwlockattr_init(&attr);
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
    	pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
    #endif
    
    	return pthread_rwlock_init(prwlock, &attr);
    }
    
    static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_rwlock_destroy(prwlock);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
    {
    	return pthread_rwlock_unlock(prwlock);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
    {
    	return pthread_rwlock_rdlock(prwlock);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_rwlock_wrlock(prwlock);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* Statically declared read/write locks */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
    #define __AST_RWLOCK_DEFINE(scope, rwlock) \
            scope ast_rwlock_t rwlock; \
    
    static void  __attribute__((constructor)) init_##rwlock(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
            ast_rwlock_init(&rwlock); \
    } \
    
    static void  __attribute__((destructor)) fini_##rwlock(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
            ast_rwlock_destroy(&rwlock); \
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else
    #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
    #define __AST_RWLOCK_DEFINE(scope, rwlock) \
            scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*
     * Initial support for atomic instructions.
     * For platforms that have it, use the native cpu instruction to
     * implement them. For other platforms, resort to a 'slow' version
     * (defined in utils.c) that protects the atomic instruction with
     * a single lock.
     * The slow versions is always available, for testing purposes,
     * as ast_atomic_fetchadd_int_slow()
     */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_OSX_ATOMICS)
    #include "libkern/OSAtomic.h"
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Atomically add v to *p and return * the previous value of *p.
     * This can be used to handle reference counts, and the return value
     * can be used to generate unique identifiers.
     */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_GCC_ATOMICS)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __sync_fetch_and_add(p, v);
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return OSAtomicAdd32(v, (int32_t *) p);
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return OSAtomicAdd64(v, (int64_t *) p);
    #elif defined (__i386__) || defined(__x86_64__)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	__asm __volatile (
    	"       lock   xaddl   %0, %1 ;        "
    	: "+r" (v),                     /* 0 (result) */   
    	  "=m" (*p)                     /* 1 */
    	: "m" (*p));                    /* 2 */
    	return (v);
    })
    #else
    static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
    {
    	int ret;
    	ret = *p;
    	*p += v;
    	return ret;
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return ast_atomic_fetchadd_int_slow(p, v);
    })
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief decrement *p by 1 and return true if the variable has reached 0.
     * Useful e.g. to check if a refcount has reached 0.
     */
    #if defined(HAVE_GCC_ATOMICS)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __sync_sub_and_fetch(p, 1) == 0;
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	return OSAtomicAdd32( -1, (int32_t *) p) == 0;
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	return OSAtomicAdd64( -1, (int64_t *) p) == 0;
    #else
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	int a = ast_atomic_fetchadd_int(p, -1);
    	return a == 1; /* true if the value is 0 now (so it was 1 previously) */
    })
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Lock AST channel (and print debugging output)
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
    int ast_channel_lock(struct ast_channel *chan);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Unlock AST channel (and print debugging output)
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function
    */
    int ast_channel_unlock(struct ast_channel *chan);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Lock AST channel (and print debugging output)
    \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
    int ast_channel_trylock(struct ast_channel *chan);
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #include "asterisk/hashtab.h"
    #include "asterisk/ael_structs.h"
    #include "asterisk/pval.h"
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from utils.h */
    
    #define ast_free free
    
    #define ast_free_ptr free
    
    
    #define MALLOC_FAILURE_MSG \
    	ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
    
    /*!
     * \brief A wrapper for malloc()
     *
     * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The argument and return value are the same as malloc()
     */
    #define ast_malloc(len) \
    	_ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_calloc(num, len) \
    	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_calloc_cache(num, len) \
    	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_realloc(p, len) \
    	_ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_strdup(str) \
    	_ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_strndup(str, len) \
    	_ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    #define ast_asprintf(ret, fmt, ...) \
    	_ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
    
    #define ast_vasprintf(ret, fmt, ap) \
    	_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_flags {  /* stolen from utils.h */
    	unsigned int flags;
    };
    #define ast_test_flag(p,flag) 		({ \
    					typeof ((p)->flags) __p = (p)->flags; \
    
    Steve Murphy's avatar
    Steve Murphy committed
    					(void) (&__p == &__x); \
    					((p)->flags & (flag)); \
    					})
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_set2_flag(p,value,flag)	do { \
    					typeof ((p)->flags) __p = (p)->flags; \
    
    Steve Murphy's avatar
    Steve Murphy committed
    					(void) (&__p == &__x); \
    					if (value) \
    						(p)->flags |= (flag); \
    					else \
    						(p)->flags &= ~(flag); \
    					} while (0)
    
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MALLOC_FAILURE_MSG \
    	ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
    /*!
     * \brief A wrapper for malloc()
     *
     * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The argument and return value are the same as malloc()
     */
    #define ast_malloc(len) \
    	_ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    AST_INLINE_API(
    void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	void *p;
    
    	if (!(p = malloc(len)))
    		MALLOC_FAILURE_MSG;
    
    	return p;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for calloc()
     *
     * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as calloc()
     */
    #define ast_calloc(num, len) \
    	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    AST_INLINE_API(
    void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	void *p;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!(p = calloc(num, len)))
    		MALLOC_FAILURE_MSG;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return p;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for calloc() for use in cache pools
     *
     * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
     * message in the case that the allocation fails. When memory debugging is in use,
     * the memory allocated by this function will be marked as 'cache' so it can be
     * distinguished from normal memory allocations.
     *
     * The arguments and return value are the same as calloc()
     */
    #define ast_calloc_cache(num, len) \
    	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for realloc()
     *
     * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as realloc()
     */
    #define ast_realloc(p, len) \
    	_ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
    {
    	void *newp;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!(newp = realloc(p, len)))
    		MALLOC_FAILURE_MSG;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newp;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for strdup()
     *
     * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
     * argument is provided, ast_strdup will return NULL without generating any
     * kind of error log message.
     *
     * The argument and return value are the same as strdup()
     */
    #define ast_strdup(str) \
    	_ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
    {
    	char *newstr = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (str) {
    		if (!(newstr = strdup(str)))
    			MALLOC_FAILURE_MSG;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newstr;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for strndup()
     *
     * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
     * string to duplicate. If a NULL argument is provided, ast_strdup will return  
     * NULL without generating any kind of error log message.
     *
     * The arguments and return value are the same as strndup()
     */
    #define ast_strndup(str, len) \
    	_ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
    {
    	char *newstr = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (str) {
    		if (!(newstr = strndup(str, len)))
    			MALLOC_FAILURE_MSG;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newstr;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for asprintf()
     *
     * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as asprintf()
     */
    #define ast_asprintf(ret, fmt, ...) \
    	_ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    
    __attribute__((format(printf, 5, 6)))
    
    Steve Murphy's avatar
    Steve Murphy committed
    int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
    {
    	int res;
    	va_list ap;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	va_start(ap, fmt);
    	if ((res = vasprintf(ret, fmt, ap)) == -1)
    		MALLOC_FAILURE_MSG;
    	va_end(ap);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for vasprintf()
     *
     * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as vasprintf()
     */
    #define ast_vasprintf(ret, fmt, ap) \
    	_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    
    __attribute__((format(printf, 5, 0)))
    
    Steve Murphy's avatar
    Steve Murphy committed
    int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
    {
    	int res;
    
    	if ((res = vasprintf(ret, fmt, ap)) == -1)
    		MALLOC_FAILURE_MSG;
    
    	return res;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if !defined(ast_strdupa) && defined(__GNUC__)
    /*!
      \brief duplicate a string in memory from the stack
      \param s The string to duplicate
    
      This macro will duplicate the given string.  It returns a pointer to the stack
      allocatted memory for the new string.
    */
    #define ast_strdupa(s)                                                    \
    	(__extension__                                                    \
    	({                                                                \
    		const char *__old = (s);                                  \
    		size_t __len = strlen(__old) + 1;                         \
    		char *__new = __builtin_alloca(__len);                    \
    		memcpy (__new, __old, __len);                             \
    		__new;                                                    \
    	}))
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from config.c */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MAX_NESTED_COMMENTS 128
    #define COMMENT_START ";--"
    #define COMMENT_END "--;"
    #define COMMENT_META ';'
    #define COMMENT_TAG '-'
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *extconfig_conf = "extconfig.conf";
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! Growable string buffer */
    static char *comment_buffer;   /*!< this will be a comment collector.*/
    static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
    static int  lline_buffer_size;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define CB_INCR 250
    
    struct ast_comment {
    	struct ast_comment *next;
    	char cmt[0];
    };
    
    static void CB_INIT(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!comment_buffer) {
    		comment_buffer = ast_malloc(CB_INCR);
    		if (!comment_buffer)
    			return;
    		comment_buffer[0] = 0;
    		comment_buffer_size = CB_INCR;
    		lline_buffer = ast_malloc(CB_INCR);
    		if (!lline_buffer)
    			return;
    		lline_buffer[0] = 0;
    		lline_buffer_size = CB_INCR;
    	} else {
    		comment_buffer[0] = 0;
    		lline_buffer[0] = 0;
    	}