Merge "cdr/cdr_csv.c: Refactor, function to write content of csv file."
authorMatt Jordan <mjordan@digium.com>
Thu, 7 May 2015 12:05:35 +0000 (07:05 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Thu, 7 May 2015 12:05:35 +0000 (07:05 -0500)
92 files changed:
CHANGES
Makefile.moddir_rules
Makefile.rules
apps/app_queue.c
autoconf/ast_check_raii.m4 [new file with mode: 0644]
autoconf/ast_check_strsep_array_bounds.m4 [new file with mode: 0644]
build_tools/get_moduleinfo
cdr/cdr_csv.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_unistim.c
channels/dahdi/bridge_native_dahdi.c
channels/dahdi/bridge_native_dahdi.h
channels/sig_pri.c
channels/sig_pri.h
channels/sip/dialplan_functions.c
codecs/lpc10/lpcini.c
configs/samples/cdr.conf.sample
configs/samples/chan_dahdi.conf.sample
configs/samples/pjsip.conf.sample
configure
configure.ac
contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
include/asterisk.h
include/asterisk/app.h
include/asterisk/autoconfig.h.in
include/asterisk/bridge_technology.h
include/asterisk/bucket.h
include/asterisk/channel.h
include/asterisk/cli.h
include/asterisk/codec.h
include/asterisk/data.h
include/asterisk/format.h
include/asterisk/manager.h
include/asterisk/mod_format.h
include/asterisk/module.h
include/asterisk/monitor.h
include/asterisk/parking.h
include/asterisk/pbx.h
include/asterisk/rtp_engine.h
include/asterisk/sip_api.h
include/asterisk/sorcery.h
include/asterisk/timing.h
include/asterisk/translate.h
include/asterisk/vector.h
main/Makefile
main/acl.c
main/asterisk.c
main/astobj2.c
main/bridge_basic.c
main/channel.c
main/cli.c
main/features.c
main/format.c
main/format_cap.c
main/manager.c
main/parking.c
main/pbx.c
main/presencestate.c
main/rtp_engine.c
main/stasis_channels.c
main/term.c
main/test.c
makeopts.in
pbx/pbx_config.c
res/ari/resource_bridges.c
res/ari/resource_device_states.c
res/parking/parking_applications.c
res/parking/parking_bridge_features.c
res/parking/parking_manager.c
res/parking/res_parking.h
res/res_clioriginate.c
res/res_convert.c
res/res_odbc.c
res/res_parking.c
res/res_pjsip.c
res/res_pjsip/include/res_pjsip_private.h
res/res_pjsip/pjsip_configuration.c
res/res_pjsip/pjsip_options.c
res/res_pjsip_acl.c
res/res_pjsip_dlg_options.c
res/res_pjsip_outbound_registration.c
res/res_stasis_snoop.c
tests/test_message.c
tests/test_vector.c [new file with mode: 0644]
utils/Makefile
utils/ael_main.c
utils/clicompat.c
utils/conf2ael.c

diff --git a/CHANGES b/CHANGES
index fcb4877..1753be6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -40,6 +40,12 @@ cdr_odbc
  * Added a new configuration option, "newcdrcolumns", which enables use of the
    post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'.
 
+------------------
+cdr_csv
+------------------
+ * Added a new configuration option, "newcdrcolumns", which enables use of the
+   post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'.
+
 
 Channel Drivers
 ------------------
@@ -48,6 +54,9 @@ chan_dahdi
 ------------------
  * The CALLERID(ani2) value for incoming calls is now populated in featdmf
    signaling mode.  The information was previously discarded.
+ * Added the force_restart_unavailable_chans compatibility option.  When
+   enabled it causes Asterisk to restart the ISDN B channel if an outgoing
+   call receives cause 44 (Requested channel not available).
 
 chan_iax2
 ------------------
index 3d3e6ad..e702282 100644 (file)
@@ -60,13 +60,19 @@ endif
 # is used to collect the required flags for a module... which can
 # then be used any place they are required.
 
-MOD_ASTCFLAGS=-DAST_MODULE=\"$(1)\" $(MENUSELECT_OPTS_$(1):%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_$(1)),$(value $(dep)_INCLUDE))
+MOD_ASTCFLAGS=\
+       -DAST_MODULE=\"$(1)\" \
+       -DAST_MODULE_SELF_SYM=__internal_$(1)_self \
+       $(MENUSELECT_OPTS_$(1):%=-D%) \
+       $(foreach dep,$(MENUSELECT_DEPENDS_$(1)),$(value $(dep)_INCLUDE))
 
 define MOD_ADD_SOURCE
 $$(if $$(filter $(1),$$(EMBEDDED_MODS)),modules.link,$(1).so): $$(subst $(3),$(5),$(2))
 $$(subst $(3),$(5),$(2)): _ASTCFLAGS+=$$(call MOD_ASTCFLAGS,$(1))
 .$(1).moduleinfo: MODULEINFO_EXTRA_OUTPUT=" $$(addprefix $$(SUBDIR)/,$$(subst $(3),$(5),$(2)) $$(subst $(3),$(4),$(2)))"
-.$(1).moduleinfo: $(2)
+# The use of wildcard ensures that 'make menuselect' will not fail for modules that
+# require additional source downloads.
+.$(1).moduleinfo: $(wildcard $(2))
 
 clean:: clean-$(1)$(3)
 
index a24cc72..a274c95 100644 (file)
@@ -65,6 +65,11 @@ endif
 CC_CFLAGS=$(PTHREAD_CFLAGS) $(_ASTCFLAGS) $(ASTCFLAGS)
 CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(_ASTCFLAGS) $(ASTCFLAGS))
 
+# Clang -Werror warning suppressions
+ifeq ($(C_COMPILER_FAMILY),clang)
+       CC_CFLAGS+=-Wno-unused-value -Wno-parentheses-equality
+endif
+
 ifeq ($(GNU_LD),1)
 SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(subst .so,.exports,$@),--warn-common
 ifneq ($(wildcard $(subst .so,.dynamics,$@)),)
index d2c6406..069ef37 100644 (file)
@@ -7835,7 +7835,8 @@ check_turns:
                        record_abandoned(&qe);
                        reason = QUEUE_TIMEOUT;
                        res = 0;
-                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+                               "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
                        break;
                }
 
@@ -7864,7 +7865,8 @@ check_turns:
                /* exit after 'timeout' cycle if 'n' option enabled */
                if (noption && tries >= ao2_container_count(qe.parent->members)) {
                        ast_verb(3, "Exiting on time-out cycle\n");
-                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+                               "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
                        record_abandoned(&qe);
                        reason = QUEUE_TIMEOUT;
                        res = 0;
diff --git a/autoconf/ast_check_raii.m4 b/autoconf/ast_check_raii.m4
new file mode 100644 (file)
index 0000000..e39a43d
--- /dev/null
@@ -0,0 +1,56 @@
+dnl check RAII requirements
+dnl
+dnl gcc / llvm-gcc: -fnested-functions
+dnl clang : -fblocks / -fblocks and -lBlocksRuntime"
+AC_DEFUN([AST_CHECK_RAII], [
+       AC_MSG_CHECKING([for RAII support])
+       AST_C_COMPILER_FAMILY=""
+       AC_LINK_IFELSE(
+               [AC_LANG_PROGRAM([], [
+                       int main() {
+                               #if defined(__clang__)
+                               choke
+                               #endif
+                               return 0;
+                       }
+                       ])
+               ],[
+                       dnl Nested functions required for RAII implementation
+                       AC_MSG_CHECKING(for gcc -fnested-functions)
+                       AC_COMPILE_IFELSE(
+                               dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
+                               [
+                                       AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])
+                               ],[
+                                       AST_NESTED_FUNCTIONS=""
+                                       AC_MSG_RESULT(no)
+                               ],[
+                                       AST_NESTED_FUNCTIONS="-fnested-functions"
+                                       AC_MSG_RESULT(yes)
+                               ]
+                       )
+                       AC_SUBST(AST_NESTED_FUNCTIONS)
+                       AST_C_COMPILER_FAMILY="gcc"
+               ],[
+                       AC_MSG_CHECKING(for clang -fblocks)
+                       if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS=""
+                               AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+                               AC_MSG_RESULT(yes)
+                       elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+                               AST_CLANG_BLOCKS="-fblocks"
+                               AC_MSG_RESULT(yes)
+                       else
+                               AC_MSG_ERROR([BlocksRuntime is required for clang, please install libblocksruntime])
+                       fi
+                       AC_SUBST(AST_CLANG_BLOCKS_LIBS)
+                       AC_SUBST(AST_CLANG_BLOCKS)
+                       AST_C_COMPILER_FAMILY="clang"
+               ]
+       )
+       if test -z "${AST_C_COMPILER_FAMILY}"; then
+               AC_MSG_ERROR([Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev])
+       fi
+       AC_SUBST(AST_C_COMPILER_FAMILY)
+])
diff --git a/autoconf/ast_check_strsep_array_bounds.m4 b/autoconf/ast_check_strsep_array_bounds.m4
new file mode 100644 (file)
index 0000000..47a41e5
--- /dev/null
@@ -0,0 +1,81 @@
+dnl macro AST_CHECK_STRSEP_ARRAY_BOUNDS0
+dnl
+dnl The optimized strcmp and strsep macro's in
+dnl /usr/include/xxx-linux-gnu/bits/string2.h produce a warning (-Warray-bounds)
+dnl when compiled with clang (+ -O1), when the delimiter parameter is
+dnl passed in as a char *, instead of the expected char[]
+dnl
+dnl Instead of replacing all occurrences of strsep and strcmp, looking like:
+dnl xxx_name = strsep(&rest, ",");
+dnl
+dnl with:
+dnl char delimiters[] = ",";
+dnl xxx_name = strsep(&rest, delimiters);
+dnl
+dnl to get around this warning, without having to suppress the warning completely.
+dnl This macro detects the warning and force these 'optimizations' to be
+dnl switched off (Clang already has a set of builtin optimizers which should result
+dnl in good performance for these type of functions).
+dnl
+dnl When the issue is detected it will add a define to autoconfig.h which will prevent
+dnl bits/string2.h from replacing the standard implementation of strsep/strcmp with it's
+dnl macro optimized version. bits/string.h checks these defines before inserting it's
+dnl replacements.
+dnl
+dnl When bits/string2.h get's fixed in the future, this macro should be able to
+dnl detect the new behaviour, and when no warning is generated, it will use the optimize
+dnl version from bits/string2.h
+dnl
+dnl
+dnl See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h'
+dnl
+dnl llvm-comment: Normally, this array-bounds warning are suppressed for macros, so that
+dnl unused paths like the one that accesses __s1[3] are not warned about.  But if you
+dnl preprocess manually, and feed the result to another instance of clang, it will warn
+dnl about all the possible forks of this particular if statement.
+dnl
+dnl Instead of switching of this optimization, another solution would be to run the pre-
+dnl processing step with -frewrite-includes, which should preserve enough information
+dnl so that clang should still be able to suppress the diagnostic at the compile step
+dnl later on.
+dnl
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=11536"
+dnl
+AC_DEFUN([AST_CHECK_STRSEP_ARRAY_BOUNDS], [
+       AC_MSG_CHECKING([for clang strsep/strcmp optimization])
+       save_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+       AC_COMPILE_IFELSE(
+               [
+                       AC_LANG_SOURCE([
+                               #include <stdio.h>
+                               #include <string.h>
+
+                               /* fails with clang and -O1 */
+                               void test_strsep_strcmp (void) {
+                                       char *haystackstr = "test1,test2";
+                                       char *outstr;
+                                       if (!strcmp(haystackstr, ",")) {
+                                               printf("fail\n");
+                                       }
+                                       if ((outstr = strsep(&haystackstr, ","))) {
+                                               printf("fail:%s\n", outstr);
+                                       }
+                               }
+                               int main(int argc, char *argv[]) {
+                                       test_strsep_strcmp();
+                                       return 0;
+                               }
+                       ])
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       dnl setting this define in autoconfig.h will prevent bits/string2.h from replacing the standard implementation of strsep/strcmp
+                       AC_DEFINE([_HAVE_STRING_ARCH_strcmp], 1, [Prevent clang array-bounds warning by not using strcmp from bits/string2.h])
+                       AC_DEFINE([_HAVE_STRING_ARCH_strsep], 1, [Prevent clang array-bounds warning by not using strsep from bits/string2.h])
+                       AC_MSG_RESULT([prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h])
+               ]
+       )
+       CFLAGS="$save_CFLAGS"
+])
index 4dbb294..e4e72bb 100644 (file)
@@ -1,4 +1,4 @@
-/\/\*\*\* MODULEINFO/ {printit=1; next}
+/\/\*\*\* +MODULEINFO/ {printit=1; next}
 /<support_level>/ {if (gotsupportlevel) { next }; gotsupportlevel=1}
 /\*\*\*\// {printit=0}
 /.*/ {if (printit) print}
index 0fc39ad..6fb2b71 100644 (file)
@@ -58,6 +58,7 @@ static int accountlogs = 1;
 static int loguniqueid = 0;
 static int loguserfield = 0;
 static int loaded = 0;
+static int newcdrcolumns = 0;
 static const char config[] = "cdr.conf";
 
 /* #define CSV_LOGUNIQUEID 1 */
@@ -112,6 +113,7 @@ static int load_config(int reload)
        usegmtime = 0;
        loguniqueid = 0;
        loguserfield = 0;
+       newcdrcolumns = 0;
 
        if (!(v = ast_variable_browse(cfg, "csv"))) {
                ast_config_destroy(cfg);
@@ -128,7 +130,10 @@ static int load_config(int reload)
                        loguniqueid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "loguserfield")) {
                        loguserfield = ast_true(v->value);
+               } else if (!strcasecmp(v->name, "newcdrcolumns")) {
+                       newcdrcolumns = ast_true(v->value);
                }
+
        }
        ast_config_destroy(cfg);
        return 1;
@@ -240,6 +245,11 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
        /* append the user field */
        if(loguserfield)
                append_string(buf, cdr->userfield, bufsize);
+       if (newcdrcolumns) {
+               append_string(buf, cdr->peeraccount, bufsize);
+               append_string(buf, cdr->linkedid, bufsize);
+               append_int(buf, cdr->sequence, bufsize);
+       }
        /* If we hit the end of our buffer, log an error */
        if (strlen(buf) < bufsize - 5) {
                /* Trim off trailing comma */
index b7df2b8..0b187dc 100644 (file)
@@ -12346,6 +12346,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #if defined(HAVE_PRI_MCID)
                                                pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
 #endif /* defined(HAVE_PRI_MCID) */
+                                               pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
 #if defined(HAVE_PRI_DATETIME_SEND)
                                                pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
@@ -18258,6 +18259,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                                else
                                        ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
                                                v->value, v->lineno);
+                       } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
+                               confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "minunused")) {
                                confp->pri.pri.minunused = atoi(v->value);
                        } else if (!strcasecmp(v->name, "minidle")) {
@@ -19516,7 +19519,7 @@ static int load_module(void)
        ast_format_cap_append(dahdi_tech.capabilities, ast_format_ulaw, 0);
        ast_format_cap_append(dahdi_tech.capabilities, ast_format_alaw, 0);
 
-       if (dahdi_native_load(ast_module_info->self, &dahdi_tech)) {
+       if (dahdi_native_load(&dahdi_tech)) {
                ao2_ref(dahdi_tech.capabilities, -1);
                return AST_MODULE_LOAD_FAILURE;
        }
index 253160a..bb9c52b 100644 (file)
@@ -13746,6 +13746,7 @@ static int set_config(const char *config_file, int reload, int forced)
                } else if (!strcasecmp(v->name, "calltokenoptional")) {
                        if (add_calltoken_ignore(v->value)) {
                                ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
+                               return -1;
                        }
                } else if (!strcasecmp(v->name, "calltokenexpiration")) {
                        int temp = -1;
index 602d38d..37935be 100644 (file)
@@ -4104,7 +4104,19 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                        ast_sockaddr_to_sin(&tmp, &gw->defaddr);
                } else if (!strcasecmp(v->name, "permit") ||
                        !strcasecmp(v->name, "deny")) {
-                       gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
+                       int acl_error = 0;
+                       gw->ha = ast_append_ha(v->name, v->value, gw->ha, &acl_error);
+                       if (acl_error) {
+                               ast_log(LOG_ERROR, "Invalid ACL '%s' specified for MGCP gateway '%s' on line %d. Not creating.\n",
+                                               v->value, cat, v->lineno);
+                               if (!gw_reload) {
+                                       ast_mutex_destroy(&gw->msgs_lock);
+                                       ast_free(gw);
+                               } else {
+                                       gw->delme = 1;
+                               }
+                               return NULL;
+                       }
                } else if (!strcasecmp(v->name, "port")) {
                        gw->addr.sin_port = htons(atoi(v->value));
                } else if (!strcasecmp(v->name, "context")) {
index aa616cd..528e208 100644 (file)
@@ -254,7 +254,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/astobj2.h"
 #include "asterisk/dnsmgr.h"
 #include "asterisk/devicestate.h"
-#include "asterisk/monitor.h"
 #include "asterisk/netsock2.h"
 #include "asterisk/localtime.h"
 #include "asterisk/abstract_jb.h"
@@ -30609,7 +30608,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_append_acl(v->name, v->value, &peer->acl, &ha_error, &acl_change_subscription_needed);
                                }
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny") || !strcasecmp(v->name, "contactacl")) {
                                int ha_error = 0;
@@ -30617,13 +30618,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_append_acl(v->name + 7, v->value, &peer->contactacl, &ha_error, &acl_change_subscription_needed);
                                }
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad contact ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "directmediapermit") || !strcasecmp(v->name, "directmediadeny") || !strcasecmp(v->name, "directmediaacl")) {
                                int ha_error = 0;
                                ast_append_acl(v->name + 11, v->value, &peer->directmediaacl, &ha_error, &acl_change_subscription_needed);
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad direct media ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "port")) {
                                peer->portinuri = 1;
@@ -31567,7 +31572,8 @@ static int reload_config(enum channelreloadreason reason)
                        int ha_error = 0;
                        ast_append_acl(v->name + 7, v->value, &sip_cfg.contact_acl, &ha_error, &acl_change_subscription_needed);
                        if (ha_error) {
-                               ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                               ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Failing to load chan_sip.so\n", v->lineno, v->value);
+                               return -1;
                        }
                } else if (!strcasecmp(v->name, "rtautoclear")) {
                        int i = atoi(v->value);
index 5f30a13..1d7d65a 100644 (file)
@@ -8044,7 +8044,14 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
                        }
                } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
                        if (type & (TYPE_DEVICE)) {
-                               CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
+                               int acl_error = 0;
+
+                               CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, &acl_error);
+                               if (acl_error) {
+                                       ast_log(LOG_ERROR, "Invalid ACL '%s' on line '%d'. Deleting device\n",
+                                                       v->value, v->lineno);
+                                       CDEV->prune = 1;
+                               }
                                continue;
                        }
                } else if (!strcasecmp(v->name, "allow")) {
index 4379aa5..82b3fce 100644 (file)
@@ -6395,6 +6395,85 @@ static struct unistim_line *find_line_by_number(struct unistim_device *d, const
        return ret;
 }
 
+static void delete_device(struct unistim_device *d)
+{
+       struct unistim_line *l;
+       struct unistim_subchannel *sub;
+       struct unistimsession *s;
+
+       if (unistimdebug) {
+               ast_verb(0, "Removing device '%s'\n", d->name);
+       }
+       AST_LIST_LOCK(&d->subs);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
+               if (sub->subtype == SUB_REAL) {
+                       if (sub->owner) {
+                               ast_log(LOG_WARNING,
+                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
+                                               d->name);
+                               AST_LIST_UNLOCK(&d->subs);
+                               return;
+                       }
+               }
+               if (sub->subtype == SUB_THREEWAY) {
+                       ast_log(LOG_WARNING,
+                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
+                                       d->name);
+                       AST_LIST_UNLOCK(&d->subs);
+                       return;
+               }
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&sub->lock);
+               ast_free(sub);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->subs);
+
+
+       AST_LIST_LOCK(&d->lines);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&l->lock);
+               unistim_line_destroy(l);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->lines);
+
+       if (d->session) {
+               if (sessions == d->session) {
+                       sessions = d->session->next;
+               } else {
+                       s = sessions;
+                       while (s) {
+                               if (s->next == d->session) {
+                                       s->next = d->session->next;
+                                       break;
+                               }
+                               s = s->next;
+                       }
+               }
+               ast_mutex_destroy(&d->session->lock);
+               ast_free(d->session);
+       }
+       if (devices == d) {
+               devices = d->next;
+       } else {
+               struct unistim_device *d2 = devices;
+               while (d2) {
+                       if (d2->next == d) {
+                               d2->next = d->next;
+                               break;
+                       }
+                       d2 = d2->next;
+               }
+       }
+       if (d->tz) {
+               d->tz = ast_tone_zone_unref(d->tz);
+       }
+       ast_mutex_destroy(&d->lock);
+       ast_free(d);
+}
+
 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
 {
        struct unistim_device *d;
@@ -6486,7 +6565,14 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
                } else if (!strcasecmp(v->name, "tn")) {
                        ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
                } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
-                       d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
+                       int acl_error = 0;
+                       d->ha = ast_append_ha(v->name, v->value, d->ha, &acl_error);
+                       if (acl_error) {
+                               ast_log(LOG_ERROR, "Invalid ACL '%s' specified for device '%s' on line %d. Deleting device\n",
+                                               v->value, cat, v->lineno);
+                               delete_device(d);
+                               return NULL;
+                       }
                } else if (!strcasecmp(v->name, "context")) {
                        ast_copy_string(d->context, v->value, sizeof(d->context));
                } else if (!strcasecmp(v->name, "maintext0")) {
@@ -6853,85 +6939,7 @@ static int reload_config(void)
        d = devices;
        while (d) {
                if (d->to_delete) {
-                       struct unistim_line *l;
-                       struct unistim_subchannel *sub;
-
-                       if (unistimdebug) {
-                               ast_verb(0, "Removing device '%s'\n", d->name);
-                       }
-                       AST_LIST_LOCK(&d->subs);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
-                               if (sub->subtype == SUB_REAL) {
-                                       if (!sub) {
-                                               ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
-                                                               d->name);
-                                               ast_config_destroy(cfg);
-                                               return 0;
-                                       }
-                                       if (sub->owner) {
-                                               ast_log(LOG_WARNING,
-                                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
-                                                               d->name);
-                                               d = d->next;
-                                               continue;
-                                       }
-                               }
-                               if (sub->subtype == SUB_THREEWAY) {
-                                       ast_log(LOG_WARNING,
-                                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
-                                                       d->name);
-                                       break;
-                               }
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&sub->lock);
-                               ast_free(sub);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->subs);
-
-
-                       AST_LIST_LOCK(&d->lines);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&l->lock);
-                               unistim_line_destroy(l);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->lines);
-
-                       if (d->session) {
-                               if (sessions == d->session) {
-                                       sessions = d->session->next;
-                               } else {
-                                       s = sessions;
-                                       while (s) {
-                                               if (s->next == d->session) {
-                                                       s->next = d->session->next;
-                                                       break;
-                                               }
-                                               s = s->next;
-                                       }
-                               }
-                               ast_mutex_destroy(&d->session->lock);
-                               ast_free(d->session);
-                       }
-                       if (devices == d) {
-                               devices = d->next;
-                       } else {
-                               struct unistim_device *d2 = devices;
-                               while (d2) {
-                                       if (d2->next == d) {
-                                               d2->next = d->next;
-                                               break;
-                                       }
-                                       d2 = d2->next;
-                               }
-                       }
-                       if (d->tz) {
-                               d->tz = ast_tone_zone_unref(d->tz);
-                       }
-                       ast_mutex_destroy(&d->lock);
-                       ast_free(d);
+                       delete_device(d);
                        d = devices;
                        continue;
                }
index d67cb5c..234228b 100644 (file)
@@ -903,11 +903,11 @@ void dahdi_native_unload(void)
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech)
+int dahdi_native_load(const struct ast_channel_tech *tech)
 {
        dahdi_tech = tech;
 
-       if (__ast_bridge_technology_register(&native_bridge, mod)) {
+       if (ast_bridge_technology_register(&native_bridge)) {
                dahdi_native_unload();
                return -1;
        }
index 91e8d16..6362a6f 100644 (file)
@@ -36,7 +36,7 @@ extern "C" {
 /* ------------------------------------------------------------------- */
 
 void dahdi_native_unload(void);
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech);
+int dahdi_native_load(const struct ast_channel_tech *tech);
 
 /* ------------------------------------------------------------------- */
 
index e4ad589..c58a3f3 100644 (file)
  */
 //#define ALWAYS_PICK_CHANNEL  1
 
-/*!
- * Define to force a RESTART on a channel that returns a cause
- * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
- * is because of a stuck channel on the peer and the channel is
- * always the next channel we pick for an outgoing call then
- * this can help.
- */
-#define FORCE_RESTART_UNAVAIL_CHANS            1
-
 #if defined(HAVE_PRI_CCSS)
 struct sig_pri_cc_agent_prv {
        /*! Asterisk span D channel control structure. */
@@ -7158,9 +7149,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7169,7 +7160,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
                                if (e->hangup.aoc_units > -1)
                                        ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
                                                pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
@@ -7307,9 +7297,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7318,7 +7308,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 
 #ifdef SUPPORT_USERUSER
                                if (!ast_strlen_zero(e->hangup.useruserinfo)) {
index 12f3dca..52e6c72 100644 (file)
@@ -496,6 +496,8 @@ struct sig_pri_span {
 #if defined(HAVE_PRI_MCID)
        /*! \brief TRUE if allow sending MCID request on this span. */
        unsigned int mcid_send:1;
+       /*! \brief TRUE if forcing RESTART when receive cause 44 on this span. */
+       unsigned int force_restart_unavailable_chans:1;
 #endif /* defined(HAVE_PRI_MCID) */
 #if defined(HAVE_PRI_DATETIME_SEND)
        /*! \brief Configured date/time ie send policy option. */
index 91a4678..33ba71c 100644 (file)
@@ -338,7 +338,7 @@ AST_TEST_DEFINE(test_sip_rtpqos_1)
                break;
        }
 
-       ast_rtp_engine_register2(&test_engine, NULL);
+       ast_rtp_engine_register(&test_engine);
        /* Have to associate this with a SIP pvt and an ast_channel */
        if (!(p = sip_alloc(0, NULL, 0, SIP_NOTIFY, NULL, 0))) {
                res = AST_TEST_NOT_RUN;
index 42c2331..ebe229a 100644 (file)
@@ -34,7 +34,7 @@ Some OSS fixes and a few lpc changes to make it actually work
        -lf2c -lm   (in that order)
 */
 
-#include "asterisk.h"
+#include <stdlib.h>
 #include "f2c.h"
 
 #ifdef P_R_O_T_O_T_Y_P_E_S
index 2c7cdf6..e175a2a 100644 (file)
@@ -154,6 +154,8 @@ usegmtime=yes    ; log date/time in GMT.  Default is "no"
 loguniqueid=yes  ; log uniqueid.  Default is "no"
 loguserfield=yes ; log user field.  Default is "no"
 accountlogs=yes  ; create separate log file for each account code. Default is "yes"
+;newcdrcolumns=yes ; Enable logging of post-1.8 CDR columns (peeraccount, linkedid, sequence).
+                   ; Default is "no".
 
 ;[radius]
 ;usegmtime=yes    ; log date/time in GMT
index 13691fc..e0c69eb 100644 (file)
@@ -196,6 +196,22 @@ context=public
 ;
 ;resetinterval = 3600
 ;
+; Enable per ISDN span to force a RESTART on a channel that returns a cause
+; code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If this option is enabled
+; and the reason the peer rejected the call with cause 44 was that the
+; channel is stuck in an unavailable state on the peer, then this might
+; help release the channel.  It is worth noting that the next outgoing call
+; Asterisk makes will likely try the same channel again.
+;
+; NOTE: Sending a RESTART in response to a cause 44 is not required
+; (nor prohibited) by the standards and is likely a primitive chan_dahdi
+; response to call collisions (glare) and buggy peers.  However, there
+; are telco switches out there that ignore the RESTART and continue to
+; send calls to the channel in the restarting state.
+; Default no.
+;
+;force_restart_unavailable_chans=yes
+;
 ; Assume inband audio may be present when a SETUP ACK message is received.
 ; Q.931 Section 5.1.3 says that in scenarios with overlap dialing, when a
 ; dialtone is sent from the network side, progress indicator 8 "Inband info
index 0f95d19..5e37571 100644 (file)
             ; Identifier names are derived from res_pjsip_endpoint_identifier_*
             ; modules. (default: ip,username,anonymous)
 ;max_initial_qualify_time=4 ; The maximum amount of time (in seconds) from
-                              startup that qualifies should be attempted on all
-                              contacts.  If greater than the qualify_frequency
-                              for an aor, qualify_frequency will be used instead.
+                            ; startup that qualifies should be attempted on all
+                            ; contacts.  If greater than the qualify_frequency
+                            ; for an aor, qualify_frequency will be used instead.
 
 ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl
 ;==========================ACL SECTION OPTIONS=========================
index c539ee9..9f7a862 100755 (executable)
--- a/configure
+++ b/configure
@@ -687,9 +687,6 @@ PBX_RTLD_NOLOAD
 PBX_GLOB_BRACE
 PBX_GLOB_NOMAGIC
 AST_RPATH
-AST_CLANG_BLOCKS
-AST_CLANG_BLOCKS_LIBS
-AST_NESTED_FUNCTIONS
 AST_NATIVE_ARCH
 AST_SHADOW_WARNINGS
 AST_NO_STRICT_OVERFLOW
@@ -1148,6 +1145,10 @@ PBX_ALSA
 ALSA_DIR
 ALSA_INCLUDE
 ALSA_LIB
+AST_C_COMPILER_FAMILY
+AST_CLANG_BLOCKS
+AST_CLANG_BLOCKS_LIBS
+AST_NESTED_FUNCTIONS
 AST_CODE_COVERAGE
 AST_DEVMODE_STRICT
 AST_DEVMODE
@@ -8227,6 +8228,146 @@ fi
 
 
 
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RAII support" >&5
+$as_echo_n "checking for RAII support... " >&6; }
+       AST_C_COMPILER_FAMILY=""
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+                       int main() {
+                               #if defined(__clang__)
+                               choke
+                               #endif
+                               return 0;
+                       }
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -fnested-functions" >&5
+$as_echo_n "checking for gcc -fnested-functions... " >&6; }
+                       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+auto void foo(void); void foo(void) {}
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                                       AST_NESTED_FUNCTIONS=""
+                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+                                       AST_NESTED_FUNCTIONS="-fnested-functions"
+                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+                       AST_C_COMPILER_FAMILY="gcc"
+
+else
+
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang -fblocks" >&5
+$as_echo_n "checking for clang -fblocks... " >&6; }
+                       if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS=""
+                               AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                       elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+                               AST_CLANG_BLOCKS="-fblocks"
+                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                       else
+                               as_fn_error $? "BlocksRuntime is required for clang, please install libblocksruntime" "$LINENO" 5
+                       fi
+
+
+                       AST_C_COMPILER_FAMILY="clang"
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+       if test -z "${AST_C_COMPILER_FAMILY}"; then
+               as_fn_error $? "Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev" "$LINENO" 5
+       fi
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang strsep/strcmp optimization" >&5
+$as_echo_n "checking for clang strsep/strcmp optimization... " >&6; }
+       save_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+                               #include <stdio.h>
+                               #include <string.h>
+
+                               /* fails with clang and -O1 */
+                               void test_strsep_strcmp (void) {
+                                       char *haystackstr = "test1,test2";
+                                       char *outstr;
+                                       if (!strcmp(haystackstr, ",")) {
+                                               printf("fail\n");
+                                       }
+                                       if ((outstr = strsep(&haystackstr, ","))) {
+                                               printf("fail:%s\n", outstr);
+                                       }
+                               }
+                               int main(int argc, char *argv) {
+                                       test_strsep_strcmp();
+                                       return 0;
+                               }
+
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strcmp 1" >>confdefs.h
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strsep 1" >>confdefs.h
+
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&5
+$as_echo "prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       CFLAGS="$save_CFLAGS"
+
+
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
 # various packages.
 # $1 is the prefix for the variables in makeopts and autoconfig.h
@@ -17430,74 +17571,6 @@ $as_echo "no" >&6; }
 fi
 
 
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-               #if defined(__clang__)
-               choke
-               #endif
-
-  ;
-  return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -fnested-functions" >&5
-$as_echo_n "checking for gcc -fnested-functions... " >&6; }
-               cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-auto void foo(void); void foo(void) {}
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       AST_NESTED_FUNCTIONS=
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-                       AST_NESTED_FUNCTIONS=-fnested-functions
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
-else
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang -fblocks" >&5
-$as_echo_n "checking for clang -fblocks... " >&6; }
-               if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
-                       AST_CLANG_BLOCKS_LIBS=""
-                       AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-               elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
-                       AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
-                       AST_CLANG_BLOCKS="-fblocks"
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-               else
-                       as_fn_error $? "\"BlocksRuntime is required for clang\"" "$LINENO" 5
-               fi
-
-
-
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
 
 # Check whether --enable-rpath was given.
 if test "${enable_rpath+set}" = set; then :
index 8a37075..c09d30a 100644 (file)
@@ -386,6 +386,9 @@ AC_ARG_ENABLE([coverage],
        esac])
 AC_SUBST(AST_CODE_COVERAGE)
 
+AST_CHECK_RAII()
+AST_CHECK_STRSEP_ARRAY_BOUNDS()
+
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
 # various packages.
 # $1 is the prefix for the variables in makeopts and autoconfig.h
@@ -1134,42 +1137,6 @@ else
 fi
 AC_SUBST(AST_NATIVE_ARCH)
 
-dnl Nested functions required for RAII implementation
-AC_LINK_IFELSE(
-       [AC_LANG_PROGRAM([], [
-               #if defined(__clang__)
-               choke
-               #endif
-               ])
-       ],[
-               dnl Nested functions required for RAII implementation
-               AC_MSG_CHECKING(for gcc -fnested-functions)
-               AC_COMPILE_IFELSE(
-                       dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
-                       [AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])],
-                       AC_MSG_RESULT(no)
-                       [AST_NESTED_FUNCTIONS=],
-                       AC_MSG_RESULT(yes)
-                       [AST_NESTED_FUNCTIONS=-fnested-functions]
-               )
-               AC_SUBST(AST_NESTED_FUNCTIONS)
-       ],[
-               AC_MSG_CHECKING(for clang -fblocks)
-               if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
-                       [AST_CLANG_BLOCKS_LIBS=""]
-                       [AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"]
-                       AC_MSG_RESULT(yes)
-               elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
-                       [AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"]
-                       [AST_CLANG_BLOCKS="-fblocks"]
-                       AC_MSG_RESULT(yes)
-               else
-                       AC_MSG_ERROR("BlocksRuntime is required for clang")
-               fi
-               AC_SUBST(AST_CLANG_BLOCKS_LIBS)
-               AC_SUBST(AST_CLANG_BLOCKS)
-       ]
-)
 
 dnl Check to see if rpath should be set in LDFLAGS
 AC_ARG_ENABLE(rpath,
index fd1b6c7..0d84390 100644 (file)
@@ -11,6 +11,7 @@ revision = '31cd4f4891ec'
 down_revision = '23530d604b96'
 
 from alembic import op
+from sqlalchemy.dialects.postgresql import ENUM
 import sqlalchemy as sa
 
 OLD_ENUM = ['rfc4733', 'inband', 'info']
index 14e88e6..ab2a3dd 100644 (file)
@@ -271,4 +271,21 @@ struct ast_sched_context;
 #define __stringify_1(x)       #x
 #define __stringify(x)         __stringify_1(x)
 
+#if defined(AST_IN_CORE) \
+       || (!defined(AST_MODULE_SELF_SYM) \
+               && (defined(STANDALONE) || defined(STANDALONE2) || defined(AST_NOT_MODULE)))
+
+#define AST_MODULE_SELF NULL
+
+#elif defined(AST_MODULE_SELF_SYM)
+
+/*! Retreive the 'struct ast_module *' for the current module. */
+#define AST_MODULE_SELF AST_MODULE_SELF_SYM()
+
+struct ast_module;
+/* Internal/forward declaration, AST_MODULE_SELF should be used instead. */
+struct ast_module *AST_MODULE_SELF_SYM(void);
+
+#endif
+
 #endif /* _ASTERISK_H */
index 6171dd4..3975fda 100644 (file)
@@ -584,7 +584,7 @@ int ast_vm_is_registered(void);
 int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module *module);
 
 /*! \brief See \ref __ast_vm_register() */
-#define ast_vm_register(vm_table) __ast_vm_register(vm_table, ast_module_info ? ast_module_info->self : NULL)
+#define ast_vm_register(vm_table) __ast_vm_register(vm_table, AST_MODULE_SELF)
 
 /*!
  * \brief Unregister the specified voicemail provider
@@ -652,7 +652,7 @@ int ast_vm_greeter_is_registered(void);
 int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module);
 
 /*! \brief See \ref __ast_vm_greeter_register() */
-#define ast_vm_greeter_register(vm_table) __ast_vm_greeter_register(vm_table, ast_module_info ? ast_module_info->self : NULL)
+#define ast_vm_greeter_register(vm_table) __ast_vm_greeter_register(vm_table, AST_MODULE_SELF)
 
 /*!
  * \brief Unregister the specified voicemail greeter provider
index 474fb8c..6b41a8c 100644 (file)
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
+/* Prevent clang array-bounds warning by not using strcmp from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strcmp
+
+/* Prevent clang array-bounds warning by not using strsep from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strsep
+
 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 #undef _LARGEFILE_SOURCE
 
index 01031e3..b83a51b 100644 (file)
@@ -182,7 +182,7 @@ struct ast_bridge_technology {
 int __ast_bridge_technology_register(struct ast_bridge_technology *technology, struct ast_module *mod);
 
 /*! \brief See \ref __ast_bridge_technology_register() */
-#define ast_bridge_technology_register(technology) __ast_bridge_technology_register(technology, ast_module_info->self)
+#define ast_bridge_technology_register(technology) __ast_bridge_technology_register(technology, AST_MODULE_SELF)
 
 /*!
  * \brief Unregister a bridge technology from use
index c07fb0c..da83759 100644 (file)
@@ -134,7 +134,7 @@ int ast_bucket_init(void);
  *
  * \note Once a scheme has been registered it can not be unregistered
  */
-#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb) __ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb, ast_module_info ? ast_module_info->self : NULL)
+#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb) __ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb, AST_MODULE_SELF)
 
 /*!
  * \brief Register support for a specific scheme
index aec7f75..fffbe5c 100644 (file)
@@ -3885,6 +3885,26 @@ enum ama_flags ast_channel_string2amaflag(const char *flag);
  */
 const char *ast_channel_amaflags2string(enum ama_flags flags);
 
+enum AST_MONITORING_STATE {
+       AST_MONITOR_RUNNING,
+       AST_MONITOR_PAUSED
+};
+
+/*! Responsible for channel monitoring data */
+struct ast_channel_monitor {
+       struct ast_filestream *read_stream;
+       struct ast_filestream *write_stream;
+       char read_filename[FILENAME_MAX];
+       char write_filename[FILENAME_MAX];
+       char filename_base[FILENAME_MAX];
+       char beep_id[64];
+       int filename_changed;
+       char *format;
+       int joinfiles;
+       enum AST_MONITORING_STATE state;
+       int (*stop)(struct ast_channel *chan, int need_lock);
+};
+
 /* ACCESSOR FUNTIONS */
 /*! \brief Set the channel name */
 void ast_channel_name_set(struct ast_channel *chan, const char *name);
@@ -3900,7 +3920,7 @@ void ast_channel_name_set(struct ast_channel *chan, const char *name);
  *
  * \li language
  * \li accountcode
- * \li peeracccount
+ * \li peeraccount
  * \li linkedid
  */
 DECLARE_STRINGFIELD_SETTERS_FOR(name);
index 458ebc8..82363c1 100644 (file)
@@ -177,7 +177,7 @@ struct ast_cli_entry {
        const char * usage;                             /*!< Detailed usage information */
 
        int inuse;                              /*!< For keeping track of usage */
-       struct module *module;                  /*!< module this belongs to */
+       struct ast_module *module;                      /*!< module this belongs to */
        char *_full_cmd;                        /*!< built at load time from cmda[] */
        int cmdlen;                             /*!< len up to the first invalid char [<{% */
        /*! \brief This gets set in ast_cli_register()
@@ -253,14 +253,19 @@ int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const c
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_cli_register(struct ast_cli_entry *e);
+#define ast_cli_register(e) __ast_cli_register(e, AST_MODULE_SELF)
+
+int __ast_cli_register(struct ast_cli_entry *e, struct ast_module *mod);
 
 /*!
  * \brief Register multiple commands
  * \param e pointer to first cli entry to register
  * \param len number of entries to register
  */
-int ast_cli_register_multiple(struct ast_cli_entry *e, int len);
+#define ast_cli_register_multiple(e, len) \
+       __ast_cli_register_multiple(e, len, AST_MODULE_SELF)
+
+int __ast_cli_register_multiple(struct ast_cli_entry *e, int len, struct ast_module *mod);
 
 /*! 
  * \brief Unregisters a command or an array of commands
index 28befec..3873324 100644 (file)
@@ -116,7 +116,7 @@ int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod);
  * \retval 0 success
  * \retval -1 failure
  */
-#define ast_codec_register(codec) __ast_codec_register(codec, ast_module_info->self)
+#define ast_codec_register(codec) __ast_codec_register(codec, AST_MODULE_SELF)
 
 /*!
  * \brief Retrieve a codec given a name, type, and sample rate
index 3676b8d..d6da1f7 100644 (file)
@@ -360,7 +360,7 @@ struct ast_data_mapping_structure {
  */
 int __ast_data_register(const char *path, const struct ast_data_handler *handler,
        const char *registrar, struct ast_module *mod);
-#define ast_data_register(path, handler) __ast_data_register(path, handler, __FILE__, ast_module_info->self)
+#define ast_data_register(path, handler) __ast_data_register(path, handler, __FILE__, AST_MODULE_SELF)
 #define ast_data_register_core(path, handler) __ast_data_register(path, handler, __FILE__, NULL)
 
 /*!
@@ -376,7 +376,7 @@ int __ast_data_register(const char *path, const struct ast_data_handler *handler
 int __ast_data_register_multiple(const struct ast_data_entry *data_entries,
        size_t entries, const char *registrar, struct ast_module *mod);
 #define ast_data_register_multiple(data_entries, entries) \
-       __ast_data_register_multiple(data_entries, entries, __FILE__, ast_module_info->self)
+       __ast_data_register_multiple(data_entries, entries, __FILE__, AST_MODULE_SELF)
 #define ast_data_register_multiple_core(data_entries, entries) \
        __ast_data_register_multiple(data_entries, entries, __FILE__, NULL)
 
index 3da2d82..c99c8f3 100644 (file)
@@ -247,7 +247,7 @@ int __ast_format_interface_register(const char *codec, const struct ast_format_i
  * \retval 0 success
  * \retval -1 failure
  */
-#define ast_format_interface_register(codec, interface) __ast_format_interface_register(codec, interface, ast_module_info->self)
+#define ast_format_interface_register(codec, interface) __ast_format_interface_register(codec, interface, AST_MODULE_SELF)
 
 /*!
  * \brief Get the attribute data on a format
index b5ede54..1ec1cba 100644 (file)
@@ -180,10 +180,10 @@ struct manager_action {
 
 /*! \brief External routines may register/unregister manager callbacks this way 
  * \note  Use ast_manager_register2() to register with help text for new manager commands */
-#define ast_manager_register(action, authority, func, synopsis) ast_manager_register2(action, authority, func, ast_module_info->self, synopsis, NULL)
+#define ast_manager_register(action, authority, func, synopsis) ast_manager_register2(action, authority, func, AST_MODULE_SELF, synopsis, NULL)
 
 /*! \brief Register a manager callback using XML documentation to describe the manager. */
-#define ast_manager_register_xml(action, authority, func) ast_manager_register2(action, authority, func, ast_module_info->self, NULL, NULL)
+#define ast_manager_register_xml(action, authority, func) ast_manager_register2(action, authority, func, AST_MODULE_SELF, NULL, NULL)
 
 /*!
  * \brief Register a manager callback using XML documentation to describe the manager.
index 7f17741..bcd31de 100644 (file)
@@ -128,7 +128,7 @@ struct ast_filestream {
  * \retval -1 on failure
  */
 int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod);
-#define ast_format_def_register(f) __ast_format_def_register(f, ast_module_info->self)
+#define ast_format_def_register(f) __ast_format_def_register(f, AST_MODULE_SELF)
 
 /*! 
  * \brief Unregisters a file format 
index 6d5e04d..f427491 100644 (file)
@@ -312,9 +312,9 @@ struct ast_module_user *__ast_module_user_add(struct ast_module *, struct ast_ch
 void __ast_module_user_remove(struct ast_module *, struct ast_module_user *);
 void __ast_module_user_hangup_all(struct ast_module *);
 
-#define ast_module_user_add(chan) __ast_module_user_add(ast_module_info->self, chan)
-#define ast_module_user_remove(user) __ast_module_user_remove(ast_module_info->self, user)
-#define ast_module_user_hangup_all() __ast_module_user_hangup_all(ast_module_info->self)
+#define ast_module_user_add(chan) __ast_module_user_add(AST_MODULE_SELF, chan)
+#define ast_module_user_remove(user) __ast_module_user_remove(AST_MODULE_SELF, user)
+#define ast_module_user_hangup_all() __ast_module_user_hangup_all(AST_MODULE_SELF)
 
 struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func);
 void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func);
@@ -368,8 +368,13 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons
        {                                                                  \
                ast_module_unregister(&__mod_info);                            \
        }                                                                  \
+       struct ast_module *AST_MODULE_SELF_SYM(void)                       \
+       {                                                                  \
+               return __mod_info.self;                                        \
+       }                                                                  \
        static const __attribute__((unused)) struct ast_module_info *ast_module_info = &__mod_info
 
+
 #define AST_MODULE_INFO_STANDARD(keystr, desc)              \
        AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
                        load_module,                                    \
@@ -401,7 +406,9 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons
 /* forward declare this pointer in modules, so that macro/function
    calls that need it can get it, since it will actually be declared
    and populated at the end of the module's source file... */
+#if !defined(AST_IN_CORE)
 static const __attribute__((unused)) struct ast_module_info *ast_module_info;
+#endif
 
 #if !defined(EMBEDDED_MODULE)
 #define __MODULE_INFO_SECTION
@@ -482,6 +489,10 @@ static void __restore_globals(void)
        { \
                ast_module_unregister(&__mod_info); \
        } \
+       struct ast_module *AST_MODULE_SELF_SYM(void)                       \
+       {                                                                  \
+               return __mod_info.self;                                        \
+       }                                                                  \
        static const struct ast_module_info *ast_module_info = &__mod_info
 
 #define AST_MODULE_INFO_STANDARD(keystr, desc)              \
@@ -527,7 +538,7 @@ static void __restore_globals(void)
  * \retval 0 success 
  * \retval -1 failure.
  */
-#define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, ast_module_info->self)
+#define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, AST_MODULE_SELF)
 
 /*! 
  * \brief Register an application using XML documentation.
index 6030221..377cb62 100644 (file)
 #include "asterisk/channel.h"
 #include "asterisk/optional_api.h"
 
-enum AST_MONITORING_STATE {
-       AST_MONITOR_RUNNING,
-       AST_MONITOR_PAUSED
-};
-
 /* Streams recording control */
 #define X_REC_IN       1
 #define X_REC_OUT      2
 #define X_JOIN         4
 
-/*! Responsible for channel monitoring data */
-struct ast_channel_monitor {
-       struct ast_filestream *read_stream;
-       struct ast_filestream *write_stream;
-       char read_filename[FILENAME_MAX];
-       char write_filename[FILENAME_MAX];
-       char filename_base[FILENAME_MAX];
-       char beep_id[64];
-       int filename_changed;
-       char *format;
-       int joinfiles;
-       enum AST_MONITORING_STATE state;
-       int (*stop)(struct ast_channel *chan, int need_lock);
-};
-
 /* Start monitoring a channel */
 AST_OPTIONAL_API(int, ast_monitor_start,
                 (struct ast_channel *chan, const char *format_spec,
index a8832cd..4c93c3b 100644 (file)
@@ -196,7 +196,7 @@ struct ast_parking_bridge_feature_fn_table {
        int (* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);
 
        /*! \brief The module info for the module registering this parking provider */
-       const struct ast_module_info *module_info;
+       struct ast_module *module;
 };
 
 /*!
index 795af05..c09de98 100644 (file)
@@ -1406,7 +1406,7 @@ enum ast_custom_function_escalation {
 /*!
  * \brief Register a custom function
  */
-#define ast_custom_function_register(acf) __ast_custom_function_register(acf, ast_module_info->self)
+#define ast_custom_function_register(acf) __ast_custom_function_register(acf, AST_MODULE_SELF)
 
 /*!
  * \brief Register a custom function which requires escalated privileges.
@@ -1415,7 +1415,7 @@ enum ast_custom_function_escalation {
  * arbitrary code) or FILE() (for which write needs permission to change files
  * on the filesystem).
  */
-#define ast_custom_function_register_escalating(acf, escalation) __ast_custom_function_register_escalating(acf, escalation, ast_module_info->self)
+#define ast_custom_function_register_escalating(acf, escalation) __ast_custom_function_register_escalating(acf, escalation, AST_MODULE_SELF)
 
 /*!
  * \brief Register a custom function
index a1a17da..a94cb42 100644 (file)
@@ -643,7 +643,7 @@ struct ast_rtp_glue {
  */
 struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void);
 
-#define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, ast_module_info->self)
+#define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, AST_MODULE_SELF)
 
 /*!
  * \brief Register an RTP engine
@@ -696,7 +696,7 @@ int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_
 void ast_rtp_engine_unregister_srtp(void);
 int ast_rtp_engine_srtp_is_registered(void);
 
-#define ast_rtp_glue_register(glue) ast_rtp_glue_register2(glue, ast_module_info->self)
+#define ast_rtp_glue_register(glue) ast_rtp_glue_register2(glue, AST_MODULE_SELF)
 
 /*!
  * \brief Register RTP glue
index 2b8a3f2..fddac16 100644 (file)
@@ -23,7 +23,6 @@
 extern "C" {
 #endif
 
-#include "asterisk/optional_api.h"
 #include "asterisk/config.h"
 
 #define AST_SIP_API_VERSION 1
index 874dac2..a5061c6 100644 (file)
@@ -366,7 +366,7 @@ int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, st
 /*!
  * \brief See \ref __ast_sorcery_wizard_register()
  */
-#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, ast_module_info ? ast_module_info->self : NULL)
+#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, AST_MODULE_SELF)
 
 /*!
  * \brief Unregister a sorcery wizard
index ff4947a..2682003 100644 (file)
@@ -92,7 +92,7 @@ struct ast_timing_interface {
  * \retval non-Null handle to be passed to ast_unregister_timing_interface() on success
  * \since 1.6.1
  */
-#define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
+#define ast_register_timing_interface(i) _ast_register_timing_interface(i, AST_MODULE_SELF)
 void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
                                                 struct ast_module *mod);
 
index e8e4c02..87e9a2c 100644 (file)
@@ -241,7 +241,7 @@ struct ast_trans_pvt;
 int __ast_register_translator(struct ast_translator *t, struct ast_module *module);
 
 /*! \brief See \ref __ast_register_translator() */
-#define ast_register_translator(t) __ast_register_translator(t, ast_module_info->self)
+#define ast_register_translator(t) __ast_register_translator(t, AST_MODULE_SELF)
 
 /*!
  * \brief Unregister a translator
index 0053d8a..23db8a5 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef _ASTERISK_VECTOR_H
 #define _ASTERISK_VECTOR_H
 
+#include "asterisk/lock.h"
+
 /*! \file
  *
  * \brief Vector container support.
        }
 
 /*!
+ * \brief Define a vector structure with a read/write lock
+ *
+ * \param name Optional vector struct name.
+ * \param type Vector element type.
+ */
+#define AST_VECTOR_RW(name, type) \
+       struct name {            \
+               type *elems;         \
+               size_t max;          \
+               size_t current;      \
+               ast_rwlock_t lock;   \
+       }
+
+/*!
  * \brief Initialize a vector
  *
  * If \a size is 0, then no space will be allocated until the vector is
 })
 
 /*!
+ * \brief Initialize a vector with a read/write lock
+ *
+ * If \a size is 0, then no space will be allocated until the vector is
+ * appended to.
+ *
+ * \param vec Vector to initialize.
+ * \param size Initial size of the vector.
+ *
+ * \return 0 on success.
+ * \return Non-zero on failure.
+ */
+#define AST_VECTOR_RW_INIT(vec, size) ({ \
+       int res = -1; \
+       if (AST_VECTOR_INIT(vec, size) == 0) { \
+               res = ast_rwlock_init(&(vec)->lock); \
+       } \
+       res; \
+})
+
+/*!
  * \brief Deallocates this vector.
  *
  * If any code to free the elements of this vector need to be run, that should
 } while (0)
 
 /*!
+ * \brief Deallocates this locked vector
+ *
+ * If any code to free the elements of this vector need to be run, that should
+ * be done prior to this call.
+ *
+ * \param vec Vector to deallocate.
+ */
+#define AST_VECTOR_RW_FREE(vec) do { \
+       AST_VECTOR_FREE(vec); \
+       ast_rwlock_destroy(&(vec)->lock); \
+} while(0)
+
+/*!
  * \brief Append an element to a vector, growing the vector if needed.
  *
  * \param vec Vector to append to.
 })
 
 /*!
- * \brief Insert an element at a specific position in a vector, growing the vector if needed.
+ * \brief Replace an element at a specific position in a vector, growing the vector if needed.
  *
- * \param vec Vector to insert into.
- * \param idx Position to insert at.
- * \param elem Element to insert.
+ * \param vec Vector to replace into.
+ * \param idx Position to replace.
+ * \param elem Element to replace.
  *
  * \return 0 on success.
  * \return Non-zero on failure.
  * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering
  * of the vector itself.
  */
-#define AST_VECTOR_INSERT(vec, idx, elem) ({                                   \
+#define AST_VECTOR_REPLACE(vec, idx, elem) ({                                  \
        int res = 0;                                                                                            \
        do {                                                                                                            \
                if (((idx) + 1) > (vec)->max) {                                                 \
 })
 
 /*!
+ * \brief Insert an element at a specific position in a vector, growing the vector if needed.
+ *
+ * \param vec Vector to insert into.
+ * \param idx Position to insert at.
+ * \param elem Element to insert.
+ *
+ * \return 0 on success.
+ * \return Non-zero on failure.
+ *
+ * \warning This macro will shift existing elements right to make room for the new element.
+ *
+ * \warning Use of this macro with the expectation that the element will remain at the provided
+ * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering
+ * of the vector itself.
+ */
+#define AST_VECTOR_INSERT_AT(vec, idx, elem) ({ \
+       int res = 0; \
+       size_t __move; \
+       do { \
+               if ((vec)->current + 1 > (vec)->max) { \
+                       size_t new_max = (vec)->max ? 2 * (vec)->max : 1; \
+                       typeof((vec)->elems) new_elems = ast_realloc( \
+                               (vec)->elems, new_max * sizeof(*new_elems)); \
+                       if (new_elems) { \
+                               (vec)->elems = new_elems; \
+                               (vec)->max = new_max; \
+                       } else { \
+                               res = -1; \
+                               break; \
+                       } \
+               } \
+               __move = ((vec)->current - 1) * sizeof(typeof((vec)->elems[0])); \
+               memmove(&(vec)->elems[(idx) + 1], &(vec)->elems[(idx)], __move); \
+               (vec)->elems[(idx)] = (elem); \
+               (vec)->current++; \
+       } while (0); \
+       res; \
+})
+
+/*!
  * \brief Remove an element from a vector by index.
  *
  * Note that elements in the vector may be reordered, so that the remove can
        res;                                                            \
 })
 
-
 /*!
  * \brief Remove an element from a vector that matches the given comparison
  *
        (vec)->elems[__idx];                    \
 })
 
+/*!
+ * \brief Get an element from a vector that matches the given comparison
+ *
+ * \param vec Vector to get from.
+ * \param value Value to pass into comparator.
+ * \param cmp Comparator function/macros (called as \c cmp(elem, value))
+ *
+ * \return a pointer to the element that was found or NULL
+ */
+#define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \
+       void *res = NULL; \
+       size_t idx; \
+       typeof(value) __value = (value); \
+       for (idx = 0; idx < (vec)->current; ++idx) { \
+               if (cmp((vec)->elems[idx], __value)) { \
+                       res = &(vec)->elems[idx]; \
+                       break; \
+               } \
+       } \
+       res; \
+})
+
+/*!
+ * \brief Execute a callback on every element in a vector
+ *
+ * \param vec Vector to operate on.
+ * \param callback A callback that takes at least 1 argument (the element)
+ * plus number of optional arguments
+ *
+ * \return the number of elements visited before the end of the vector
+ * was reached or CMP_STOP was returned.
+ */
+#define AST_VECTOR_CALLBACK(vec, callback, ...) ({ \
+       size_t idx; \
+       for (idx = 0; idx < (vec)->current; idx++) { \
+               int rc = callback((vec)->elems[idx], ##__VA_ARGS__);    \
+               if (rc == CMP_STOP) { \
+                       idx++; \
+                       break; \
+               }\
+       } \
+       idx; \
+})
+
+/*!
+ * \brief Obtain read lock on vector
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock)
+
+/*!
+ * \brief Obtain write lock on vector
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock)
+
+/*!
+ * \brief Unlock vector
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock)
+
+/*!
+ * \brief Try to obtain read lock on vector failing immediately if unable
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock)
+
+/*!
+ * \brief Try to obtain write lock on vector failing immediately if unable
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock)
+
+/*!
+ * \brief Try to obtain read lock on vector failing after timeout if unable
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec)
+
+/*!
+ * \brief Try to obtain write lock on vector failing after timeout if unable
+ *
+ * \param vec Vector to operate on.
+ *
+ * \return 0 if success
+ * \return Non-zero if error
+ */
+#define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec)
+
 #endif /* _ASTERISK_VECTOR_H */
index c0c0aff..08496e6 100644 (file)
@@ -201,7 +201,7 @@ ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin
 ASTSSL_LIB:=libasteriskssl.so
 
 $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)
-$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\"
+$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\" -DAST_NOT_MODULE
 $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): LIBS+=$(ASTSSL_LIBS)
 ifeq ($(GNU_LD),1)
     $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskssl.exports,--warn-common
index 92b6754..d133b2a 100644 (file)
@@ -479,7 +479,7 @@ void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **
                AST_LIST_TRAVERSE(working_list, current, list) {
                        if (!strcasecmp(current->name, tmp)) { /* ACL= */
                                /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */
-                               ast_log(LOG_ERROR, "Named ACL '%s' is already included in the ast_acl container.", tmp);
+                               ast_log(LOG_ERROR, "Named ACL '%s' occurs multiple times in ACL definition. Please update your ACL configuration.", tmp);
                                if (error) {
                                        *error = 1;
                                }
index 86a190b..277604b 100644 (file)
@@ -4260,7 +4260,10 @@ int main(int argc, char *argv[])
        register_config_cli();
        read_config_maps();
 
-       astobj2_init();
+       if (astobj2_init()) {
+               printf("Failed: astobj2_init\n%s", term_quit());
+               exit(1);
+       }
 
        if (ast_opt_console) {
                if (el_hist == NULL || el == NULL)
index f9dd8d4..1db2dd4 100644 (file)
@@ -1143,10 +1143,6 @@ int astobj2_init(void)
 {
        char ref_filename[1024];
 
-       if (container_init() != 0) {
-               return -1;
-       }
-
        if (ast_opt_ref_debug) {
                snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
                ref_log = fopen(ref_filename, "w");
@@ -1155,6 +1151,11 @@ int astobj2_init(void)
                }
        }
 
+       if (container_init() != 0) {
+               fclose(ref_log);
+               return -1;
+       }
+
 #if defined(AO2_DEBUG)
        ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
 #endif /* defined(AO2_DEBUG) */
index c48db5c..5e20f30 100644 (file)
@@ -606,18 +606,17 @@ static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags)
  */
 static int setup_bridge_features_dynamic(struct ast_bridge_features *features, struct ast_channel *chan)
 {
-       RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
+       struct ao2_container *applicationmap;
        int res = 0;
 
        ast_channel_lock(chan);
        applicationmap = ast_get_chan_applicationmap(chan);
        ast_channel_unlock(chan);
-       if (!applicationmap) {
-               return 0;
+       if (applicationmap) {
+               ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res);
+               ao2_ref(applicationmap, -1);
        }
 
-       ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res);
-
        return res;
 }
 
@@ -1418,7 +1417,7 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
        char *tech;
        char *addr;
        char *serial;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        struct ast_flags *transferer_features;
 
        props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor);
@@ -1450,6 +1449,7 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
        ast_string_field_set(props, context, get_transfer_context(transferer, context));
        ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
        ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
+       ao2_ref(xfer_cfg, -1);
 
        /*
         * Save the transferee's party information for any recall calls.
@@ -1695,17 +1695,16 @@ static void publish_transfer_fail(struct attended_transfer_properties *props)
  */
 static void play_sound(struct ast_channel *chan, const char *sound)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       if (!bridge_channel) {
-               return;
+       if (bridge_channel) {
+               ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
+               ao2_ref(bridge_channel, -1);
        }
-
-       ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
 }
 
 /*!
@@ -1713,16 +1712,19 @@ static void play_sound(struct ast_channel *chan, const char *sound)
  */
 static void hold(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
-       if (chan) {
-               ast_channel_lock(chan);
-               bridge_channel = ast_channel_get_bridge_channel(chan);
-               ast_channel_unlock(chan);
+       if (!chan) {
+               return;
+       }
 
-               ast_assert(bridge_channel != NULL);
+       ast_channel_lock(chan);
+       bridge_channel = ast_channel_get_bridge_channel(chan);
+       ast_channel_unlock(chan);
 
+       if (bridge_channel) {
                ast_bridge_channel_write_hold(bridge_channel, NULL);
+               ao2_ref(bridge_channel, -1);
        }
 }
 
@@ -1731,15 +1733,20 @@ static void hold(struct ast_channel *chan)
  */
 static void unhold(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
+
+       if (!chan) {
+               return;
+       }
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       ast_assert(bridge_channel != NULL);
-
-       ast_bridge_channel_write_unhold(bridge_channel);
+       if (bridge_channel) {
+               ast_bridge_channel_write_unhold(bridge_channel);
+               ao2_ref(bridge_channel, -1);
+       }
 }
 
 /*!
@@ -1747,15 +1754,16 @@ static void unhold(struct ast_channel *chan)
  */
 static void ringing(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       ast_assert(bridge_channel != NULL);
-
-       ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_RINGING, NULL, 0);
+       if (bridge_channel) {
+               ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_RINGING, NULL, 0);
+               ao2_ref(bridge_channel, -1);
+       }
 }
 
 /*!
@@ -1800,10 +1808,9 @@ static void bridge_unhold(struct ast_bridge *bridge)
 /*!
  * \brief Wrapper for \ref bridge_do_move
  */
-static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
+static void bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
 {
-       int res;
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_bridge_lock_both(src, dest);
 
@@ -1811,18 +1818,18 @@ static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct a
        bridge_channel = ast_channel_get_bridge_channel(channel);
        ast_channel_unlock(channel);
 
-       ast_assert(bridge_channel != NULL);
-
-       ao2_lock(bridge_channel);
-       bridge_channel->swap = swap;
-       ao2_unlock(bridge_channel);
+       if (bridge_channel) {
+               ao2_lock(bridge_channel);
+               bridge_channel->swap = swap;
+               ao2_unlock(bridge_channel);
 
-       res = bridge_do_move(dest, bridge_channel, 1, 0);
+               bridge_do_move(dest, bridge_channel, 1, 0);
+       }
 
        ast_bridge_unlock(dest);
        ast_bridge_unlock(src);
 
-       return res;
+       ao2_cleanup(bridge_channel);
 }
 
 /*!
@@ -2033,7 +2040,8 @@ static const struct attended_transfer_state_properties state_properties[] = {
 
 static int calling_target_enter(struct attended_transfer_properties *props)
 {
-       return bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
+       bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
+       return 0;
 }
 
 static enum attended_transfer_state calling_target_exit(struct attended_transfer_properties *props,
@@ -2072,10 +2080,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
 
 static int hesitant_enter(struct attended_transfer_properties *props)
 {
-       if (bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL)) {
-               return -1;
-       }
-
+       bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL);
        unhold(props->transferer);
        return 0;
 }
@@ -2115,11 +2120,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
 
 static int rebridge_enter(struct attended_transfer_properties *props)
 {
-       if (bridge_move(props->transferee_bridge, props->target_bridge,
-                       props->transferer, NULL)) {
-               return -1;
-       }
-
+       bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL);
        unhold(props->transferer);
        return 0;
 }
@@ -2839,7 +2840,8 @@ static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *br
        }
 
        if (self->num_channels == 1) {
-               RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
+               struct ast_bridge_channel *transferer_bridge_channel;
+               int not_transferer;
 
                ast_channel_lock(props->transferer);
                transferer_bridge_channel = ast_channel_get_bridge_channel(props->transferer);
@@ -2849,7 +2851,9 @@ static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *br
                        return;
                }
 
-               if (AST_LIST_FIRST(&self->channels) != transferer_bridge_channel) {
+               not_transferer = AST_LIST_FIRST(&self->channels) != transferer_bridge_channel;
+               ao2_ref(transferer_bridge_channel, -1);
+               if (not_transferer) {
                        return;
                }
        }
@@ -2886,7 +2890,8 @@ static void recall_pull(struct ast_bridge *self, struct ast_bridge_channel *brid
        }
 
        if (self->num_channels == 1) {
-               RAII_VAR(struct ast_bridge_channel *, target_bridge_channel, NULL, ao2_cleanup);
+               struct ast_bridge_channel *target_bridge_channel;
+
                if (!props->recall_target) {
                        /* No recall target means that the pull happened on a transferee. If there's still
                         * a channel left in the bridge, we don't need to send a stimulus
@@ -2898,12 +2903,11 @@ static void recall_pull(struct ast_bridge *self, struct ast_bridge_channel *brid
                target_bridge_channel = ast_channel_get_bridge_channel(props->recall_target);
                ast_channel_unlock(props->recall_target);
 
-               if (!target_bridge_channel) {
-                       return;
-               }
-
-               if (AST_LIST_FIRST(&self->channels) == target_bridge_channel) {
-                       stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
+               if (target_bridge_channel) {
+                       if (AST_LIST_FIRST(&self->channels) == target_bridge_channel) {
+                               stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
+                       }
+                       ao2_ref(target_bridge_channel, -1);
                }
        }
 }
@@ -2925,7 +2929,8 @@ static void bridge_personality_atxfer_pull(struct ast_bridge *self, struct ast_b
 
 static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfer_properties *props)
 {
-       RAII_VAR(struct stimulus_list *, list, NULL, ast_free_ptr);
+       enum attended_transfer_stimulus stimulus;
+       struct stimulus_list *list;
        SCOPED_MUTEX(lock, ao2_object_get_lockaddr(props));
 
        while (!(list = AST_LIST_REMOVE_HEAD(&props->stimulus_queue, next))) {
@@ -2956,7 +2961,9 @@ static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfe
                        }
                }
        }
-       return list->stimulus;
+       stimulus = list->stimulus;
+       ast_free(list);
+       return stimulus;
 }
 
 /*!
@@ -3050,7 +3057,7 @@ static int add_transferer_role(struct ast_channel *chan, struct ast_bridge_featu
        const char *atxfer_threeway;
        const char *atxfer_complete;
        const char *atxfer_swap;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        SCOPED_CHANNELLOCK(lock, chan);
 
        xfer_cfg = ast_get_chan_features_xfer_config(chan);
@@ -3068,6 +3075,7 @@ static int add_transferer_role(struct ast_channel *chan, struct ast_bridge_featu
                atxfer_complete = ast_strdupa(xfer_cfg->atxfercomplete);
                atxfer_swap = ast_strdupa(xfer_cfg->atxferswap);
        }
+       ao2_ref(xfer_cfg, -1);
 
        return ast_channel_add_bridge_role(chan, AST_TRANSFERER_ROLE_NAME) ||
                ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "abort", atxfer_abort) ||
@@ -3088,7 +3096,7 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
        int digit_timeout;
        int attempts = 0;
        int max_attempts;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        char *retry_sound;
        char *invalid_sound;
 
@@ -3103,6 +3111,7 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
        max_attempts = xfer_cfg->transferdialattempts;
        retry_sound = ast_strdupa(xfer_cfg->transferretrysound);
        invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);
+       ao2_ref(xfer_cfg, -1);
        ast_channel_unlock(chan);
 
        /* Play the simple "transfer" prompt out and wait */
index fee7763..fbdf17b 100644 (file)
@@ -53,7 +53,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/chanvars.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"
-#include "asterisk/monitor.h"
 #include "asterisk/causes.h"
 #include "asterisk/callerid.h"
 #include "asterisk/utils.h"
index a230c20..eb8800f 100644 (file)
@@ -2203,7 +2203,7 @@ static int cli_is_registered(struct ast_cli_entry *e)
        return 0;
 }
 
-static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
+int ast_cli_unregister(struct ast_cli_entry *e)
 {
        if (e->inuse) {
                ast_log(LOG_WARNING, "Can't remove command that is in use\n");
@@ -2225,7 +2225,7 @@ static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *e
        return 0;
 }
 
-static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
+int __ast_cli_register(struct ast_cli_entry *e, struct ast_module *module)
 {
        struct ast_cli_entry *cur;
        int i, lf, ret = -1;
@@ -2244,7 +2244,11 @@ static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
        }
 
        memset(&a, '\0', sizeof(a));
+
+       e->module = module;
+       /* No module reference needed here, the module called us. */
        e->handler(e, CLI_INIT, &a);
+
        /* XXX check that usage and command are filled up */
        s = ast_skip_blanks(e->command);
        s = e->command = ast_strdup(s);
@@ -2295,27 +2299,16 @@ done:
        return ret;
 }
 
-/* wrapper function, so we can unregister deprecated commands recursively */
-int ast_cli_unregister(struct ast_cli_entry *e)
-{
-       return __ast_cli_unregister(e, NULL);
-}
-
-/* wrapper function, so we can register deprecated commands recursively */
-int ast_cli_register(struct ast_cli_entry *e)
-{
-       return __ast_cli_register(e, NULL);
-}
-
 /*
  * register/unregister an array of entries.
  */
-int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
+int __ast_cli_register_multiple(struct ast_cli_entry *e, int len, struct ast_module *module)
 {
        int i, res = 0;
 
-       for (i = 0; i < len; i++)
-               res |= ast_cli_register(e + i);
+       for (i = 0; i < len; i++) {
+               res |= __ast_cli_register(e + i, module);
+       }
 
        return res;
 }
@@ -2657,7 +2650,9 @@ static char *__ast_cli_generator(const char *text, const char *word, int state,
                                        .n = state - matchnum,
                                        .argv = argv,
                                        .argc = x};
+                               ast_module_ref(e->module);
                                ret = e->handler(e, CLI_GENERATE, &a);
+                               ast_module_unref(e->module);
                        }
                        if (ret)
                                break;
@@ -2714,7 +2709,9 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
         */
        args[0] = (char *)e;
 
+       ast_module_ref(e->module);
        retval = e->handler(e, CLI_HANDLER, &a);
+       ast_module_unref(e->module);
 
        if (retval == CLI_SHOWUSAGE) {
                ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
index 4acd8aa..618f91c 100644 (file)
@@ -66,7 +66,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/utils.h"
 #include "asterisk/adsi.h"
 #include "asterisk/devicestate.h"
-#include "asterisk/monitor.h"
 #include "asterisk/audiohook.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/astobj2.h"
index 8fed71f..bbfb697 100644 (file)
@@ -36,6 +36,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/format.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/strings.h"
+#include "asterisk/module.h"
 
 /*! \brief Number of buckets to use for format interfaces (should be prime for performance reasons) */
 #define FORMAT_INTERFACE_BUCKETS 53
@@ -156,6 +157,8 @@ int __ast_format_interface_register(const char *codec, const struct ast_format_i
        format_interface->interface = interface;
        strcpy(format_interface->codec, codec); /* Safe */
 
+       /* Once registered a format interface cannot be unregistered. */
+       ast_module_shutdown_ref(mod);
        ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK);
        ao2_ref(format_interface, -1);
 
index 7456a44..5226257 100644 (file)
@@ -139,7 +139,7 @@ static inline int format_cap_framed_init(struct format_cap_framed *framed, struc
        framed->framing = framing;
 
        if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
-               if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
+               if (AST_VECTOR_REPLACE(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
                        ao2_ref(framed, -1);
                        return -1;
                }
index 2ff9df9..17a2738 100644 (file)
@@ -8977,7 +8977,14 @@ static int __init_manager(int reload, int by_external_config)
                        } else if (!strcasecmp(var->name, "deny") ||
                                       !strcasecmp(var->name, "permit") ||
                                       !strcasecmp(var->name, "acl")) {
-                               ast_append_acl(var->name, var->value, &user->acl, NULL, &acl_subscription_flag);
+                               int acl_error = 0;
+
+                               ast_append_acl(var->name, var->value, &user->acl, &acl_error, &acl_subscription_flag);
+                               if (acl_error) {
+                                       ast_log(LOG_ERROR, "Invalid ACL '%s' for manager user '%s' on line %d. Deleting user\n",
+                                               var->value, user->username, var->lineno);
+                                       user->keep = 0;
+                               }
                        }  else if (!strcasecmp(var->name, "read") ) {
                                user->readperm = get_perm(var->value);
                        }  else if (!strcasecmp(var->name, "write") ) {
index 25fdfe8..61a4896 100644 (file)
@@ -134,8 +134,8 @@ int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const cha
                return -1;
        }
 
-       if (table->module_info) {
-               SCOPED_MODULE_USE(table->module_info->self);
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
                return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
        }
 
@@ -153,8 +153,8 @@ int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
                return -1;
        }
 
-       if (table->module_info) {
-               SCOPED_MODULE_USE(table->module_info->self);
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
                return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
        }
 
@@ -170,8 +170,8 @@ int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t
                return -1;
        }
 
-       if (table->module_info) {
-               SCOPED_MODULE_USE(table->module_info->self);
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
                return table->parking_park_call(parker, exten, length);
        }
 
@@ -187,8 +187,8 @@ int ast_parking_is_exten_park(const char *context, const char *exten)
                return -1;
        }
 
-       if (table->module_info) {
-               SCOPED_MODULE_USE(table->module_info->self);
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
                return table->parking_is_exten_park(context, exten);
        }
 
index fee4191..45909f5 100644 (file)
@@ -72,6 +72,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/astobj2.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
+#include "asterisk/vector.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -1046,8 +1047,9 @@ struct ast_hint {
 
        char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
        char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
-};
 
+       AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
+};
 
 #define HINTDEVICE_DATA_LENGTH 16
 AST_THREADSTORAGE(hintdevice_data);
@@ -1077,15 +1079,28 @@ struct ast_hintdevice {
        char hintdevice[1];
 };
 
-
 /*!
  * \note Using the device for hash
  */
 static int hintdevice_hash_cb(const void *obj, const int flags)
 {
-       const struct ast_hintdevice *ext = obj;
+       const struct ast_hintdevice *ext;
+       const char *key;
 
-       return ast_str_case_hash(ext->hintdevice);
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_KEY:
+               key = obj;
+               break;
+       case OBJ_SEARCH_OBJECT:
+               ext = obj;
+               key = ext->hintdevice;
+               break;
+       default:
+               ast_assert(0);
+               return 0;
+       }
+
+       return ast_str_case_hash(key);
 }
 /*!
  * \note Devices on hints are not unique so no CMP_STOP is returned
@@ -1094,29 +1109,58 @@ static int hintdevice_hash_cb(const void *obj, const int flags)
  */
 static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
 {
-       struct ast_hintdevice *ext = obj, *ext2 = arg;
+       struct ast_hintdevice *left = obj;
+       struct ast_hintdevice *right = arg;
+       const char *right_key = arg;
+       int cmp;
 
-       return !strcasecmp(ext->hintdevice, ext2->hintdevice) ? CMP_MATCH  : 0;
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+               right_key = right->hintdevice;
+               /* Fall through */
+       case OBJ_SEARCH_KEY:
+               cmp = strcmp(left->hintdevice, right_key);
+               break;
+       case OBJ_SEARCH_PARTIAL_KEY:
+               /*
+               * We could also use a partial key struct containing a length
+               * so strlen() does not get called for every comparison instead.
+               */
+               cmp = strncmp(left->hintdevice, right_key, strlen(right_key));
+               break;
+       default:
+               ast_assert(0);
+               cmp = 0;
+               break;
+       }
+       return cmp ? 0 : CMP_MATCH;
 }
 
-/*
- * \details This is used with ao2_callback to remove old devices
- * when they are linked to the hint
-*/
-static int hintdevice_remove_cb(void *deviceobj, void *arg, int flags)
+/*! \internal \brief \c ao2_callback function to remove hintdevices */
+static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
 {
-       struct ast_hintdevice *device = deviceobj;
-       struct ast_hint *hint = arg;
+       struct ast_hintdevice *candidate = obj;
+       char *device = arg;
+       struct ast_hint *hint = data;
 
-       return (device->hint == hint) ? CMP_MATCH : 0;
+       if (!strcmp(candidate->hintdevice, device)
+               && candidate->hint == hint) {
+               return CMP_MATCH;
+       }
+       return 0;
 }
 
 static int remove_hintdevice(struct ast_hint *hint)
 {
-       /* iterate through all devices and remove the devices which are linked to this hint */
-       ao2_t_callback(hintdevices, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
-               hintdevice_remove_cb, hint,
-               "callback to remove all devices which are linked to a hint");
+       while (AST_VECTOR_SIZE(&hint->devices) > 0) {
+               char *device = AST_VECTOR_GET(&hint->devices, 0);
+
+               ao2_t_callback_data(hintdevices, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA,
+                       hintdevice_remove_cb, device, hint, "Remove device from container");
+               AST_VECTOR_REMOVE_UNORDERED(&hint->devices, 0);
+               ast_free(device);
+       }
+
        return 0;
 }
 
@@ -1161,18 +1205,32 @@ static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
 
        /* Spit on '&' and ',' to handle presence hints as well */
        while ((cur = strsep(&parse, "&,"))) {
+               char *device_name;
+
                devicelength = strlen(cur);
                if (!devicelength) {
                        continue;
                }
+
+               device_name = ast_strdup(cur);
+               if (!device_name) {
+                       return -1;
+               }
+
                device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
                        "allocating a hintdevice structure");
                if (!device) {
+                       ast_free(device_name);
                        return -1;
                }
                strcpy(device->hintdevice, cur);
                ao2_ref(hint, +1);
                device->hint = hint;
+               if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
+                       ast_free(device_name);
+                       ao2_ref(device, -1);
+                       return -1;
+               }
                ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
                ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
        }
@@ -5385,7 +5443,7 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 
        ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
        dev_iter = ao2_t_callback(hintdevices,
-               OBJ_POINTER | OBJ_MULTIPLE,
+               OBJ_SEARCH_OBJECT | OBJ_MULTIPLE,
                hintdevice_cmp_multiple,
                cmpdevice,
                "find devices in container");
@@ -5697,6 +5755,7 @@ static int hint_id_cmp(void *obj, void *arg, int flags)
 static void destroy_hint(void *obj)
 {
        struct ast_hint *hint = obj;
+       int i;
 
        if (hint->callbacks) {
                struct ast_state_cb *state_cb;
@@ -5726,6 +5785,12 @@ static void destroy_hint(void *obj)
                }
                ao2_ref(hint->callbacks, -1);
        }
+
+       for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+               char *device = AST_VECTOR_GET(&hint->devices, i);
+               ast_free(device);
+       }
+       AST_VECTOR_FREE(&hint->devices);
        ast_free(hint->last_presence_subtype);
        ast_free(hint->last_presence_message);
 }
@@ -5787,6 +5852,7 @@ static int ast_add_hint(struct ast_exten *e)
        if (!hint_new) {
                return -1;
        }
+       AST_VECTOR_INIT(&hint_new->devices, 8);
 
        /* Initialize new hint. */
        hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
@@ -12526,14 +12592,17 @@ static int statecbs_cmp(void *obj, void *arg, int flags)
 static void pbx_shutdown(void)
 {
        if (hints) {
+               ao2_container_unregister("hints");
                ao2_ref(hints, -1);
                hints = NULL;
        }
        if (hintdevices) {
+               ao2_container_unregister("hintdevices");
                ao2_ref(hintdevices, -1);
                hintdevices = NULL;
        }
        if (statecbs) {
+               ao2_container_unregister("statecbs");
                ao2_ref(statecbs, -1);
                statecbs = NULL;
        }
@@ -12543,11 +12612,53 @@ static void pbx_shutdown(void)
        pbx_builtin_clear_globals();
 }
 
+static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_hint *hint = v_obj;
+
+       if (!hint) {
+               return;
+       }
+       prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
+               ast_get_context_name(ast_get_extension_context(hint->exten)));
+}
+
+static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_hintdevice *hintdevice = v_obj;
+
+       if (!hintdevice) {
+               return;
+       }
+       prnt(where, "%s => %s@%s", hintdevice->hintdevice,
+               ast_get_extension_name(hintdevice->hint->exten),
+               ast_get_context_name(ast_get_extension_context(hintdevice->hint->exten)));
+}
+
+static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_state_cb *state_cb = v_obj;
+
+       if (!state_cb) {
+               return;
+       }
+       prnt(where, "%d", state_cb->id);
+}
+
 int ast_pbx_init(void)
 {
        hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
+       if (hints) {
+               ao2_container_register("hints", hints, print_hints_key);
+       }
        hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
+       if (hintdevices) {
+               ao2_container_register("hintdevices", hintdevices, print_hintdevices_key);
+       }
        statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
+       if (statecbs) {
+               ao2_container_register("statecbs", statecbs, print_statecbs_key);
+       }
 
        ast_register_cleanup(pbx_shutdown);
 
index 32f19e6..399613e 100644 (file)
@@ -389,7 +389,7 @@ static const char *presence_state_get_id(struct stasis_message *msg)
 
 #if defined(TEST_FRAMEWORK)
 
-#define TEST_CATEGORY "/main/presence"
+#define TEST_CATEGORY "/main/presence/"
 
 static int presence_test_alice_state = AST_PRESENCE_UNAVAILABLE;
 static int presence_test_bob_state = AST_PRESENCE_UNAVAILABLE;
index aa91b7d..88d2db3 100644 (file)
@@ -625,7 +625,7 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
                }
                ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest);
                ao2_bump(type);
-               AST_VECTOR_INSERT(&dest->payloads, i, type);
+               AST_VECTOR_REPLACE(&dest->payloads, i, type);
 
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code);
@@ -662,7 +662,7 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as
        new_type->format = ao2_bump(static_RTP_PT[payload].format);
 
        ast_debug(1, "Setting payload %d (%p) based on m type on %p\n", payload, new_type, codecs);
-       AST_VECTOR_INSERT(&codecs->payloads, payload, new_type);
+       AST_VECTOR_REPLACE(&codecs->payloads, payload, new_type);
 
        if (instance && instance->engine && instance->engine->payload_set) {
                instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
@@ -727,7 +727,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
                } else {
                        new_type->format = ao2_bump(t->payload_type.format);
                }
-               AST_VECTOR_INSERT(&codecs->payloads, pt, new_type);
+               AST_VECTOR_REPLACE(&codecs->payloads, pt, new_type);
 
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
@@ -760,7 +760,7 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
        if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
                type = AST_VECTOR_GET(&codecs->payloads, payload);
                ao2_cleanup(type);
-               AST_VECTOR_INSERT(&codecs->payloads, payload, NULL);
+               AST_VECTOR_REPLACE(&codecs->payloads, payload, NULL);
        }
 
        if (instance && instance->engine && instance->engine->payload_set) {
index 5990cdd..7dc57bf 100644 (file)
@@ -364,6 +364,7 @@ static void ast_channel_publish_dial_internal(struct ast_channel *caller,
 }
 
 static void remove_dial_masquerade(struct ast_channel *peer);
+static void remove_dial_masquerade_caller(struct ast_channel *caller);
 static int set_dial_masquerade(struct ast_channel *caller,
        struct ast_channel *peer, const char *dialstring);
 
@@ -373,6 +374,11 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
 {
        ast_assert(peer != NULL);
 
+       /* XXX With an early bridge the below dial masquerade datastore code could, theoretically,
+        * go away as the act of changing the channel during dialing would be done using the bridge
+        * API itself and not a masquerade.
+        */
+
        if (caller) {
                /*
                 * Lock two or three channels.
@@ -407,6 +413,7 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
                        ast_channel_unlock(forwarded);
                }
                ast_channel_unlock(peer);
+               remove_dial_masquerade_caller(caller);
                ast_channel_unlock(caller);
        }
 }
@@ -1326,6 +1333,7 @@ static void dial_target_free(struct dial_target *doomed)
                return;
        }
        ast_free(doomed->dialstring);
+       ast_channel_cleanup(doomed->peer);
        ast_free(doomed);
 }
 
@@ -1348,7 +1356,6 @@ static void dial_masquerade_datastore_cleanup(struct dial_masquerade_datastore *
        while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
                dial_target_free(cur);
        }
-       masq_data->caller = NULL;
 }
 
 static void dial_masquerade_datastore_remove_chan(struct dial_masquerade_datastore *masq_data, struct ast_channel *chan)
@@ -1398,6 +1405,16 @@ static void dial_masquerade_datastore_destroy(void *data)
        ao2_ref(data, -1);
 }
 
+/*!
+ * \internal
+ * \brief Datastore destructor for dial_masquerade_datastore
+ */
+static void dial_masquerade_caller_datastore_destroy(void *data)
+{
+       dial_masquerade_datastore_cleanup(data);
+       ao2_ref(data, -1);
+}
+
 static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
 
 static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
@@ -1516,6 +1533,13 @@ static const struct ast_datastore_info dial_masquerade_info = {
        .chan_breakdown = dial_masquerade_breakdown,
 };
 
+static const struct ast_datastore_info dial_masquerade_caller_info = {
+       .type = "stasis-chan-dial-masq",
+       .destroy = dial_masquerade_caller_datastore_destroy,
+       .chan_fixup = dial_masquerade_fixup,
+       .chan_breakdown = dial_masquerade_breakdown,
+};
+
 /*!
  * \internal
  * \brief Find the dial masquerade datastore on the given channel.
@@ -1526,7 +1550,14 @@ static const struct ast_datastore_info dial_masquerade_info = {
  */
 static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan)
 {
-       return ast_channel_datastore_find(chan, &dial_masquerade_info, NULL);
+       struct ast_datastore *datastore;
+
+       datastore = ast_channel_datastore_find(chan, &dial_masquerade_info, NULL);
+       if (!datastore) {
+               datastore = ast_channel_datastore_find(chan, &dial_masquerade_caller_info, NULL);
+       }
+
+       return datastore;
 }
 
 /*!
@@ -1545,7 +1576,7 @@ static struct dial_masquerade_datastore *dial_masquerade_datastore_add(
 {
        struct ast_datastore *datastore;
 
-       datastore = ast_datastore_alloc(&dial_masquerade_info, NULL);
+       datastore = ast_datastore_alloc(!masq_data ? &dial_masquerade_caller_info : &dial_masquerade_info, NULL);
        if (!datastore) {
                return NULL;
        }
@@ -1604,7 +1635,7 @@ static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *p
                        return -1;
                }
        }
-       target->peer = peer;
+       target->peer = ast_channel_ref(peer);
 
        /* Put peer target into datastore */
        ao2_lock(masq_data);
@@ -1662,3 +1693,24 @@ static void remove_dial_masquerade(struct ast_channel *peer)
        ast_channel_datastore_remove(peer, datastore);
        ast_datastore_free(datastore);
 }
+
+static void remove_dial_masquerade_caller(struct ast_channel *caller)
+{
+       struct ast_datastore *datastore;
+       struct dial_masquerade_datastore *masq_data;
+
+       datastore = dial_masquerade_datastore_find(caller);
+       if (!datastore) {
+               return;
+       }
+
+       masq_data = datastore->data;
+       if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) {
+               return;
+       }
+
+       dial_masquerade_datastore_remove_chan(masq_data, caller);
+
+       ast_channel_datastore_remove(caller, datastore);
+       ast_datastore_free(datastore);
+}
index a19c1f1..cf21719 100644 (file)
@@ -311,8 +311,7 @@ const char *ast_term_color(int fgcolor, int bgcolor)
 const char *ast_term_reset(void)
 {
        if (ast_opt_force_black_background) {
-               static const char reset[] = { ESC, '[', COLOR_BLACK + 10, 'm', 0 };
-               return reset;
+               return enddata;
        } else {
                return quitdata;
        }
index 47ae7f8..d1dce09 100644 (file)
@@ -110,6 +110,7 @@ static struct ast_test *test_free(struct ast_test *test);
 static int test_insert(struct ast_test *test);
 static struct ast_test *test_remove(ast_test_cb_t *cb);
 static int test_cat_cmp(const char *cat1, const char *cat2);
+static int registration_errors = 0;
 
 void ast_test_debug(struct ast_test *test, const char *fmt, ...)
 {
@@ -197,16 +198,19 @@ int ast_test_register(ast_test_cb_t *cb)
        struct ast_test *test;
 
        if (!cb) {
-               ast_log(LOG_WARNING, "Attempted to register test without all required information\n");
+               ast_log(LOG_ERROR, "Attempted to register test without all required information\n");
+               registration_errors++;
                return -1;
        }
 
        if (!(test = test_alloc(cb))) {
+               registration_errors++;
                return -1;
        }
 
        if (test_insert(test)) {
                test_free(test);
+               registration_errors++;
                return -1;
        }
 
@@ -619,7 +623,9 @@ static struct ast_test *test_alloc(ast_test_cb_t *cb)
 {
        struct ast_test *test;
 
-       if (!cb || !(test = ast_calloc(1, sizeof(*test)))) {
+       test = ast_calloc(1, sizeof(*test));
+       if (!test) {
+               ast_log(LOG_ERROR, "Failed to allocate test, registration failed.\n");
                return NULL;
        }
 
@@ -628,12 +634,12 @@ static struct ast_test *test_alloc(ast_test_cb_t *cb)
        test->cb(&test->info, TEST_INIT, test);
 
        if (ast_strlen_zero(test->info.name)) {
-               ast_log(LOG_WARNING, "Test has no name, test registration refused.\n");
+               ast_log(LOG_ERROR, "Test has no name, test registration refused.\n");
                return test_free(test);
        }
 
        if (ast_strlen_zero(test->info.category)) {
-               ast_log(LOG_WARNING, "Test %s has no category, test registration refused.\n",
+               ast_log(LOG_ERROR, "Test %s has no category, test registration refused.\n",
                                test->info.name);
                return test_free(test);
        }
@@ -641,21 +647,26 @@ static struct ast_test *test_alloc(ast_test_cb_t *cb)
        if (test->info.category[0] != '/' || test->info.category[strlen(test->info.category) - 1] != '/') {
                ast_log(LOG_WARNING, "Test category '%s' for test '%s' is missing a leading or trailing slash.\n",
                                test->info.category, test->info.name);
+               /* Flag an error anyways so test_registrations fails but allow the test to be
+                * registered. */
+               registration_errors++;
        }
 
        if (ast_strlen_zero(test->info.summary)) {
-               ast_log(LOG_WARNING, "Test %s%s has no summary, test registration refused.\n",
+               ast_log(LOG_ERROR, "Test %s%s has no summary, test registration refused.\n",
                                test->info.category, test->info.name);
                return test_free(test);
        }
 
        if (ast_strlen_zero(test->info.description)) {
-               ast_log(LOG_WARNING, "Test %s%s has no description, test registration refused.\n",
+               ast_log(LOG_ERROR, "Test %s%s has no description, test registration refused.\n",
                                test->info.category, test->info.name);
                return test_free(test);
        }
 
        if (!(test->status_str = ast_str_create(128))) {
+               ast_log(LOG_ERROR, "Failed to allocate status_str for %s%s, test registration failed.\n",
+                               test->info.category, test->info.name);
                return test_free(test);
        }
 
@@ -1095,19 +1106,38 @@ void __ast_test_suite_event_notify(const char *file, const char *func, int line,
        stasis_publish(ast_test_suite_topic(), msg);
 }
 
-#endif /* TEST_FRAMEWORK */
+AST_TEST_DEFINE(test_registrations)
+{
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "registrations";
+               info->category = "/main/test/";
+               info->summary = "Validate Test Registration Data.";
+               info->description = "Validate Test Registration Data.";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
 
-#ifdef TEST_FRAMEWORK
+       if (registration_errors) {
+               ast_test_status_update(test,
+                       "%d test registration error%s occurred.  See startup logs for details.\n",
+                       registration_errors, registration_errors > 1 ? "s" : "");
+               return AST_TEST_FAIL;
+       }
+
+       return AST_TEST_PASS;
+}
 
 static void test_cleanup(void)
 {
+       AST_TEST_UNREGISTER(test_registrations);
        ast_cli_unregister_multiple(test_cli, ARRAY_LEN(test_cli));
        ao2_cleanup(test_suite_topic);
        test_suite_topic = NULL;
        STASIS_MESSAGE_TYPE_CLEANUP(ast_test_suite_message_type);
 }
-
-#endif
+#endif /* TEST_FRAMEWORK */
 
 int ast_test_init(void)
 {
@@ -1124,6 +1154,8 @@ int ast_test_init(void)
                return -1;
        }
 
+       AST_TEST_REGISTER(test_registrations);
+
        /* Register cli commands */
        ast_cli_register_multiple(test_cli, ARRAY_LEN(test_cli));
 #endif
index cc23310..69636f1 100644 (file)
@@ -111,6 +111,7 @@ AST_SHADOW_WARNINGS=@AST_SHADOW_WARNINGS@
 AST_NESTED_FUNCTIONS=@AST_NESTED_FUNCTIONS@
 AST_CLANG_BLOCKS=@AST_CLANG_BLOCKS@
 AST_CLANG_BLOCKS_LIBS=@AST_CLANG_BLOCKS_LIBS@
+C_COMPILER_FAMILY=@AST_C_COMPILER_FAMILY@
 AST_RPATH=@AST_RPATH@
 AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
 AST_MARCH_NATIVE=@AST_MARCH_NATIVE@
index 92462bf..09941a6 100644 (file)
@@ -2080,9 +2080,9 @@ static int load_module(void)
                ast_cli_register(&cli_dialplan_save);
        ast_cli_register_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config));
 
-       res = ast_manager_register_xml_core(AMI_EXTENSION_ADD,
+       res = ast_manager_register_xml(AMI_EXTENSION_ADD,
                EVENT_FLAG_SYSTEM, manager_dialplan_extension_add);
-       res |= ast_manager_register_xml_core(AMI_EXTENSION_REMOVE,
+       res |= ast_manager_register_xml(AMI_EXTENSION_REMOVE,
                EVENT_FLAG_SYSTEM, manager_dialplan_extension_remove);
 
        if (res) {
index 70365ec..7b9b946 100644 (file)
@@ -24,6 +24,8 @@
  */
 
 /*** MODULEINFO
+       <depend type="module">res_stasis_recording</depend>
+       <depend type="module">res_stasis_playback</depend>
        <support_level>core</support_level>
  ***/
 
index 6f68d52..493d7a1 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*** MODULEINFO
-       <depend type="module">res_stasis_device_states</depend>
+       <depend type="module">res_stasis_device_state</depend>
        <support_level>core</support_level>
  ***/
 
index 762bf55..5077474 100644 (file)
@@ -868,8 +868,6 @@ static int park_and_announce_app_exec(struct ast_channel *chan, const char *data
 
 int load_parking_applications(void)
 {
-       const struct ast_module_info *ast_module_info = parking_get_module_info();
-
        if (ast_register_application_xml(PARK_APPLICATION, park_app_exec)) {
                return -1;
        }
index 4a01e4c..4cb87c8 100644 (file)
@@ -502,7 +502,7 @@ static int parking_park_call(struct ast_bridge_channel *parker, char *exten, siz
 
 static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-       SCOPED_MODULE_USE(parking_get_module_info()->self);
+       SCOPED_MODULE_USE(AST_MODULE_SELF);
 
        return parking_park_call(bridge_channel, NULL, 0);
 }
@@ -726,7 +726,7 @@ void unload_parking_bridge_features(void)
 
 int load_parking_bridge_features(void)
 {
-       parking_provider.module_info = parking_get_module_info();
+       parking_provider.module = AST_MODULE_SELF;
 
        if (ast_parking_register_bridge_features(&parking_provider)) {
                return -1;
index ffa4bc7..175ae5f 100644 (file)
@@ -678,11 +678,10 @@ static void parking_manager_enable_stasis(void)
 int load_parking_manager(void)
 {
        int res;
-       const struct ast_module_info *module = parking_get_module_info();
 
-       res = ast_manager_register2("Parkinglots", EVENT_FLAG_CALL, manager_parking_lot_list, module->self, NULL, NULL);
-       res |= ast_manager_register2("ParkedCalls", EVENT_FLAG_CALL, manager_parking_status, module->self, NULL, NULL);
-       res |= ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, module->self, NULL, NULL);
+       res = ast_manager_register_xml("Parkinglots", EVENT_FLAG_CALL, manager_parking_lot_list);
+       res |= ast_manager_register_xml("ParkedCalls", EVENT_FLAG_CALL, manager_parking_status);
+       res |= ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
        parking_manager_enable_stasis();
        return res ? -1 : 0;
 }
index 3d77e51..2c4a180 100644 (file)
@@ -560,12 +560,3 @@ int load_parking_tests(void);
  * \return Nothing
  */
 void unload_parking_tests(void);
-
-struct ast_module_info;
-/*!
- * \since 12.0.0
- * \brief Get res_parking's module info
- *
- * \retval res_parking's ast_module
- */
-const struct ast_module_info *parking_get_module_info(void);
index 173f9f5..451b174 100644 (file)
@@ -156,8 +156,6 @@ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
                        "used. If no extension is given, the 's' extension will be used.\n";
                return NULL;
        case CLI_GENERATE:
-               /* ugly, can be removed when CLI entries have ast_module pointers */
-               ast_module_ref(ast_module_info->self);
                if (a->pos == 3) {
                        res = ast_cli_complete(a->word, choices, a->n);
                } else if (a->pos == 4) {
@@ -165,16 +163,12 @@ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
                                res = ast_complete_applications(a->line, a->word, a->n);
                        }
                }
-               ast_module_unref(ast_module_info->self);
                return res;
        }
 
        if (ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3]))
                return CLI_SHOWUSAGE;
 
-       /* ugly, can be removed when CLI entries have ast_module pointers */
-       ast_module_ref(ast_module_info->self);
-
        if (!strcasecmp("application", a->argv[3])) {
                res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
        } else if (!strcasecmp("extension", a->argv[3])) {
@@ -183,8 +177,6 @@ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
                res = CLI_SHOWUSAGE;
        }
 
-       ast_module_unref(ast_module_info->self);
-
        return res;
 }
 
index 2a691a5..3ca5965 100644 (file)
@@ -88,9 +88,6 @@ static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct as
                return NULL;
        }
        
-       /* ugly, can be removed when CLI entries have ast_module pointers */
-       ast_module_ref(ast_module_info->self);
-
        if (a->argc != 4 || ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3])) {
                ret = CLI_SHOWUSAGE;
                goto fail_out;  
@@ -142,8 +139,6 @@ fail_out:
        if (fs_in) 
                ast_closestream(fs_in);
 
-       ast_module_unref(ast_module_info->self);
-
        return ret;
 }
 
index 5f2f2c5..2530a48 100644 (file)
@@ -1253,8 +1253,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
                if (obj) {
                        ast_assert(ao2_ref(obj, 0) > 1);
                }
-               if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
-                               (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
+               if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit)) {
                        obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
                        if (!obj) {
                                class->count--;
@@ -1412,10 +1411,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
        }
 
        if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
-               /* Check if this connection qualifies for reconnection, with negative connection cache time */
-               if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) {
-                       odbc_obj_connect(obj);
-               }
+               odbc_obj_connect(obj);
        } else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
                ast_odbc_sanity_check(obj);
        } else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
@@ -1522,6 +1518,7 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
        char *tracefile = "/tmp/odbc.trace";
 #endif
        SQLHDBC con;
+       long int negative_cache_expiration;
 
        if (obj->up) {
                odbc_obj_disconnect(obj);
@@ -1531,6 +1528,13 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
                ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
        }
 
+       /* Dont connect while server is marked as unreachable via negative_connection_cache */
+       negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
+       if (time(NULL) < negative_cache_expiration) {
+               ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
+               return ODBC_FAIL;
+       }
+
        res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
index a40990e..02740da 100644 (file)
@@ -1159,11 +1159,6 @@ static void link_configured_disable_marked_lots(void)
        disable_marked_lots();
 }
 
-const struct ast_module_info *parking_get_module_info(void)
-{
-       return ast_module_info;
-}
-
 static int unload_module(void)
 {
        unload_parking_bridge_features();
index 8be019f..a263809 100644 (file)
@@ -3650,7 +3650,7 @@ static int load_module(void)
 
        ast_sip_initialize_global_headers();
 
-       if (ast_res_pjsip_initialize_configuration(ast_module_info)) {
+       if (ast_res_pjsip_initialize_configuration()) {
                ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n");
                ast_sip_destroy_global_headers();
                stop_monitor_thread();
index 5120fc6..a53e0c4 100644 (file)
@@ -25,7 +25,7 @@ struct ast_sip_cli_context;
  * \internal
  * \brief Initialize the configuration for res_pjsip
  */
-int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info);
+int ast_res_pjsip_initialize_configuration(void);
 
 /*!
  * \internal
index 54fdb65..f147b34 100644 (file)
@@ -1742,7 +1742,7 @@ static struct ast_cli_entry cli_commands[] = {
 struct ast_sip_cli_formatter_entry *channel_formatter;
 struct ast_sip_cli_formatter_entry *endpoint_formatter;
 
-int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info)
+int ast_res_pjsip_initialize_configuration(void)
 {
        if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
            ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
index 8ffb88c..87c67fa 100644 (file)
@@ -1181,7 +1181,7 @@ int ast_res_pjsip_init_options_handling(int reload)
        }
 
        internal_sip_register_endpoint_formatter(&contact_status_formatter);
-       ast_manager_register2("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify, NULL, NULL, NULL);
+       ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify);
        ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
 
        qualify_and_schedule_all();
index a04f2b4..151ebed 100644 (file)
@@ -238,8 +238,21 @@ static int acl_handler(const struct aco_option *opt, struct ast_variable *var, v
 
        if (!strncmp(var->name, "contact_", 8)) {
                ast_append_acl(var->name + 8, var->value, &sip_acl->contact_acl, &error, &ignore);
+               if (error) {
+                       ast_log(LOG_ERROR, "Bad contact ACL '%s' at line '%d' of pjsip.conf\n",
+                                       var->value, var->lineno);
+               }
        } else {
                ast_append_acl(var->name, var->value, &sip_acl->acl, &error, &ignore);
+               if (error) {
+                       ast_log(LOG_ERROR, "Bad ACL '%s' at line '%d' of pjsip.conf\n",
+                                       var->value, var->lineno);
+               }
+       }
+
+       if (error) {
+               ast_log(LOG_ERROR, "There is an error in ACL configuration. Blocking ALL SIP traffic.\n");
+               ast_append_acl("deny", "0.0.0.0/0.0.0.0", &sip_acl->acl, NULL, &ignore);
        }
 
        return error;
index 45a1940..3415124 100644 (file)
@@ -16,7 +16,7 @@
  * at the top of the source tree.
  */
 
-/***  MODULEINFO
+/*** MODULEINFO
        <depend>pjproject</depend>
        <depend>res_pjsip</depend>
        <depend>res_pjsip_session</depend>
index c2eb62b..1dd5f58 100644 (file)
@@ -33,6 +33,7 @@
 #include "asterisk/taskprocessor.h"
 #include "asterisk/cli.h"
 #include "asterisk/stasis_system.h"
+#include "asterisk/threadstorage.h"
 #include "res_pjsip/include/res_pjsip_private.h"
 
 /*** DOCUMENTATION
        </manager>
  ***/
 
+/*! \brief Some thread local storage used to determine if the running thread invoked the callback */
+AST_THREADSTORAGE(register_callback_invoked);
+
 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
 #define REREGISTER_BUFFER_TIME 10
 
@@ -429,6 +433,33 @@ static void cancel_registration(struct sip_outbound_registration_client_state *c
 
 static pj_str_t PATH_NAME = { "path", 4 };
 
+/*! \brief Helper function which sends a message and cleans up, if needed, on failure */
+static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,
+       pjsip_tx_data *tdata)
+{
+       pj_status_t status;
+       int *callback_invoked;
+
+       callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
+       if (!callback_invoked) {
+               return PJ_ENOMEM;
+       }
+       *callback_invoked = 0;
+
+       /* Due to the message going out the callback may now be invoked, so bump the count */
+       ao2_ref(client_state, +1);
+       status = pjsip_regc_send(client_state->client, tdata);
+
+       /* If the attempt to send the message failed and the callback was not invoked we need to
+        * drop the reference we just added
+        */
+       if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
+               ao2_ref(client_state, -1);
+       }
+
+       return status;
+}
+
 /*! \brief Callback function for registering */
 static int handle_client_registration(void *data)
 {
@@ -466,11 +497,7 @@ static int handle_client_registration(void *data)
                pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
        }
 
-       /* Due to the registration the callback may now get called, so bump the ref count */
-       ao2_ref(client_state, +1);
-       if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
-               ao2_ref(client_state, -1);
-       }
+       registration_client_send(client_state, tdata);
 
        return 0;
 }
@@ -650,13 +677,11 @@ static int handle_registration_response(void *data)
                pjsip_tx_data *tdata;
                if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
                                response->rdata, response->old_request, &tdata)) {
-                       ao2_ref(response->client_state, +1);
                        response->client_state->auth_attempted = 1;
                        ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
                                        server_uri, client_uri);
-                       if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
+                       if (registration_client_send(response->client_state, tdata) != PJ_SUCCESS) {
                                response->client_state->auth_attempted = 0;
-                               ao2_cleanup(response->client_state);
                        }
                        return 0;
                } else {
@@ -732,9 +757,15 @@ static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *par
        RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
        struct registration_response *response;
        pjsip_regc_info info;
+       int *callback_invoked;
+
+       callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
 
+       ast_assert(callback_invoked != NULL);
        ast_assert(client_state != NULL);
 
+       *callback_invoked = 1;
+
        response = ao2_alloc(sizeof(*response), registration_response_destroy);
        if (!response) {
                return;
@@ -1202,10 +1233,7 @@ static int unregister_task(void *obj)
                return 0;
        }
 
-       ao2_ref(state->client_state, +1);
-       if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
-               ao2_cleanup(state->client_state);
-       }
+       registration_client_send(state->client_state, tdata);
 
        return 0;
 }
index 5311aed..68d76a4 100644 (file)
@@ -177,12 +177,28 @@ static struct ast_frame *snoop_read(struct ast_channel *chan)
        }
 
        /* Only get audio from the spy audiohook if it is active */
-       if (snoop->spy_active) {
-               ast_audiohook_lock(&snoop->spy);
-               frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format);
-               ast_audiohook_unlock(&snoop->spy);
+       if (!snoop->spy_active) {
+               return &ast_null_frame;
        }
 
+       ast_audiohook_lock(&snoop->spy);
+       if (snoop->spy_direction != AST_AUDIOHOOK_DIRECTION_BOTH) {
+               /*
+                * When a singular direction is chosen frames are still written to the
+                * opposing direction's queue. Those frames must be read so the queue
+                * does not continue to grow, however since they are not needed for the
+                * selected direction they can be dropped.
+                */
+               enum ast_audiohook_direction opposing_direction =
+                       snoop->spy_direction == AST_AUDIOHOOK_DIRECTION_READ ?
+                       AST_AUDIOHOOK_DIRECTION_WRITE : AST_AUDIOHOOK_DIRECTION_READ;
+               ast_frame_dtor(ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples,
+                                                       opposing_direction, snoop->spy_format));
+       }
+
+       frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format);
+       ast_audiohook_unlock(&snoop->spy);
+
        return frame ? frame : &ast_null_frame;
 }
 
index 7140b5f..26cd90a 100644 (file)
@@ -160,7 +160,7 @@ static int verify_user_event_fields(int user_event, const char *header, const ch
                                bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event);
                        }
                        ast_variable_list_append(&bad_headers_head, bad_header);
-                       AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head);
+                       AST_VECTOR_REPLACE(&bad_headers, user_event, bad_headers_head);
                }
                regfree(&regexbuf);
                return -1;
@@ -492,28 +492,28 @@ AST_TEST_DEFINE(test_message_queue_dialplan_nominal)
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value","^foo$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response);
 
        expected_response = NULL;
        expected = ast_variable_new("Verify", "^From$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value","^bar$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response);
 
        expected_response = NULL;
        expected = ast_variable_new("Verify", "^Body$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value", "^a body$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response);
 
        expected_response = NULL;
        expected = ast_variable_new("Verify", "^Custom$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value", "^field$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 3, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 3, expected_response);
 
        ast_msg_set_to(msg, "foo");
        ast_msg_set_from(msg, "bar");
@@ -609,21 +609,21 @@ AST_TEST_DEFINE(test_message_queue_both_nominal)
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value","^foo$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response);
 
        expected_response = NULL;
        expected = ast_variable_new("Verify", "^From$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value","^bar$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response);
 
        expected_response = NULL;
        expected = ast_variable_new("Verify", "^Body$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
        expected = ast_variable_new("Value", "^a body$", __FILE__);
        ast_variable_list_append(&expected_response, expected);
-       AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response);
+       AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response);
 
        ast_msg_set_to(msg, "foo");
        ast_msg_set_from(msg, "bar");
diff --git a/tests/test_vector.c b/tests/test_vector.c
new file mode 100644 (file)
index 0000000..eae1881
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015, Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Vector tests
+ *
+ * \author George Joseph <george.joseph@fairview5.com>
+ *
+ * This module will run some vector tests.
+ *
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+       <depend>TEST_FRAMEWORK</depend>
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include "asterisk/test.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/module.h"
+#include "asterisk/vector.h"
+
+#define test_validate_cleanup(condition) ({ \
+       if (!(condition)) {     \
+               ast_test_status_update((test), "%s: %s\n", "Condition failed", #condition); \
+               rc = AST_TEST_FAIL; \
+               goto cleanup; \
+       } \
+})
+
+static int cleanup_count;
+
+static void cleanup(char *element)
+{
+       cleanup_count++;
+}
+
+AST_TEST_DEFINE(basic_ops)
+{
+       AST_VECTOR(test_struct, char *) sv1;
+       int rc = AST_TEST_PASS;
+
+       char *AAA = "AAA";
+       char *BBB = "BBB";
+       char *CCC = "CCC";
+       char *ZZZ = "ZZZ";
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "basic";
+               info->category = "/main/vector/";
+               info->summary = "Test vector basic ops";
+               info->description = "Test vector basic ops";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0);
+       test_validate_cleanup(sv1.max == 3);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0);
+
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(sv1.max == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0);
+       test_validate_cleanup(sv1.max >= 4);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC);
+
+       test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == AAA);
+       test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "ZZZ", 0 == strcmp) == ZZZ);
+
+       AST_VECTOR_FREE(&sv1);
+       ast_test_validate(test, sv1.elems == NULL);
+       ast_test_validate(test, sv1.current == 0);
+       ast_test_validate(test, sv1.max == 0);
+
+       ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0);
+       test_validate_cleanup(sv1.max == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0);
+
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0);
+       test_validate_cleanup(sv1.max >= 3);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Overwrite index 1 */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Remove index 0 and bring the last entry into it's empty slot */
+       test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+
+       /* Replace 0 and 2 leaving 1 alone */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Remove 1 and compact preserving order */
+       test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC);
+
+       /* Equivalent of APPEND */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+
+       /* This should fail because comparison is by pointer */
+       test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, "ZZZ", cleanup) != 0);
+
+       /* This should work because we passing in the specific object to be removed */
+       cleanup_count = 0;
+       test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC);
+       test_validate_cleanup(cleanup_count == 1);
+
+       /* If we want a comparison by value, we need to pass in a comparison
+        * function.  The comparison looks weird but that's what it takes.
+        */
+       cleanup_count = 0;
+       test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC);
+       test_validate_cleanup(cleanup_count == 1);
+
+       /* This element is gone so we shouldn't be able to find it or delete it again. */
+       test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == NULL);
+       test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) != 0);
+
+       /* CCC should still be there though */
+       test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "CCC", 0 == strcmp) == CCC);
+
+cleanup:
+       AST_VECTOR_FREE(&sv1);
+       return rc;
+}
+
+static void cleanup_int(int element)
+{
+       cleanup_count++;
+}
+
+AST_TEST_DEFINE(basic_ops_integer)
+{
+       AST_VECTOR(test_struct, int) sv1;
+       int rc = AST_TEST_PASS;
+
+       int AAA = 1;
+       int BBB = 2;
+       int CCC = 3;
+       int ZZZ = 26;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "basic integer";
+               info->category = "/main/vector/";
+               info->summary = "Test integer vector basic ops";
+               info->description = "Test integer vector basic ops";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0);
+       test_validate_cleanup(sv1.max == 3);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0);
+
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(sv1.max == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0);
+       test_validate_cleanup(sv1.max >= 4);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC);
+
+       test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, AAA,  AST_VECTOR_ELEM_DEFAULT_CMP) == AAA);
+       test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, ZZZ, AST_VECTOR_ELEM_DEFAULT_CMP) == ZZZ);
+
+       AST_VECTOR_FREE(&sv1);
+       ast_test_validate(test, sv1.elems == NULL);
+       ast_test_validate(test, sv1.current == 0);
+       ast_test_validate(test, sv1.max == 0);
+
+       ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0);
+       test_validate_cleanup(sv1.max == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0);
+
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0);
+       test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0);
+       test_validate_cleanup(sv1.max >= 3);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Overwrite index 1 */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Remove index 0 and bring the last entry into it's empty slot */
+       test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == 1);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+
+       /* Replace 0 and 2 leaving 1 alone */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0);
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC);
+
+       /* Remove 1 and compact preserving order */
+       test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC);
+
+       /* Equivalent of APPEND */
+       test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3);
+
+       /* This should work because we passing in the specific object to be removed */
+       cleanup_count = 0;
+       test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup_int) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC);
+       test_validate_cleanup(cleanup_count == 1);
+
+       /* If we want a comparison by value, we need to pass in a comparison
+        * function.
+        */
+       cleanup_count = 0;
+       test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) == 0);
+       test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1);
+       test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC);
+       test_validate_cleanup(cleanup_count == 1);
+
+       /* This element is gone so we shouldn't be able to find it or delete it again. */
+       test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == NULL);
+       test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) != 0);
+
+       /* CCC should still be there though */
+       test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, CCC, AST_VECTOR_ELEM_DEFAULT_CMP) == CCC);
+
+cleanup:
+       AST_VECTOR_FREE(&sv1);
+       return rc;
+}
+
+
+static int cb(void *obj, void *arg, void *data)
+{
+       return strcmp(arg, "ARG") == 0 ? 0 : CMP_STOP;
+}
+
+static int cb_first(void *obj, void *arg, void *data)
+{
+       return data == arg ? CMP_STOP : 0;
+}
+
+AST_TEST_DEFINE(callbacks)
+{
+       AST_VECTOR(, char *) sv1;
+       int rc = AST_TEST_PASS;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "callbacks";
+               info->category = "/main/vector/";
+               info->summary = "Test vector callback ops";
+               info->description = "Test vector callback ops";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       AST_VECTOR_INIT(&sv1, 32);
+
+       AST_VECTOR_APPEND(&sv1, "AAA");
+       AST_VECTOR_APPEND(&sv1, "BBB");
+       AST_VECTOR_APPEND(&sv1, "CCC");
+
+       test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb, "ARG", test) == 3);
+
+       test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb_first, test, test) == 1);
+
+cleanup:
+       AST_VECTOR_FREE(&sv1);
+
+       return rc;
+}
+
+AST_TEST_DEFINE(locks)
+{
+       AST_VECTOR_RW(, char *) sv1;
+       int rc = AST_TEST_PASS;
+       struct timespec ts;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "locks";
+               info->category = "/main/vector/";
+               info->summary = "Test vector locking ops";
+               info->description = "Test vector locking ops";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       /* We're not actually checking that locking works,
+        * just that the macro expansions work
+        */
+
+       AST_VECTOR_RW_INIT(&sv1, 0);
+
+       test_validate_cleanup(AST_VECTOR_RW_RDLOCK(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_WRLOCK(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+
+       test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TRY(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) != 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+
+       ts.tv_nsec = 0;
+       ts.tv_sec = 2;
+
+       test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TIMED(&sv1, &ts) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) != 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) == 0);
+       test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0);
+
+cleanup:
+       AST_VECTOR_RW_FREE(&sv1);
+
+       return rc;
+}
+
+static int unload_module(void)
+{
+       AST_TEST_UNREGISTER(locks);
+       AST_TEST_UNREGISTER(callbacks);
+       AST_TEST_UNREGISTER(basic_ops_integer);
+       AST_TEST_UNREGISTER(basic_ops);
+
+       return 0;
+}
+
+static int load_module(void)
+{
+       AST_TEST_REGISTER(locks);
+       AST_TEST_REGISTER(callbacks);
+       AST_TEST_REGISTER(basic_ops_integer);
+       AST_TEST_REGISTER(basic_ops);
+
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Vector test module");
index af21673..97b0e2f 100644 (file)
@@ -150,6 +150,8 @@ pbx_ael.c: $(ASTTOPDIR)/pbx/pbx_ael.c
        $(CMD_PREFIX) sed 's/ast_debug([[:digit:]][[:digit:]]*/ast_log(LOG_DEBUG/' "$@" > "$@.new"
        $(CMD_PREFIX) mv "$@.new" "$@"
 
+pbx_ael.o: _ASTCFLAGS+=-DAST_MODULE_SELF_SYM=__internal_pbx_ael_self
+
 aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c
        $(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
        $(CMD_PREFIX) cp "$<" "$@"
index 2237625..06ba8e6 100644 (file)
@@ -103,7 +103,7 @@ static char var_dir[PATH_MAX];
 const char *ast_config_AST_CONFIG_DIR = config_dir;
 const char *ast_config_AST_VAR_DIR = var_dir;
 
-void ast_cli_register_multiple(void);
+void __ast_cli_register_multiple(void);
 int ast_add_extension2(struct ast_context *con,
                                           int replace, const char *extension, int priority, const char *label, const char *callerid,
                                                const char *application, void *data, void (*datad)(void *),
@@ -208,7 +208,7 @@ void ast_module_unregister(const struct ast_module_info *x)
 }
 
 
-void ast_cli_register_multiple(void)
+void __ast_cli_register_multiple(void)
 {
        if(!no_comp)
                printf("Executed ast_cli_register_multiple();\n");
index d25a710..426dd5c 100644 (file)
@@ -21,8 +21,8 @@ int ast_register_cleanup(void (*func)(void))
        return 0;
 }
 
-int ast_cli_register_multiple(struct ast_cli_entry *e, int len);
-int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
+int __ast_cli_register_multiple(struct ast_cli_entry *e, int len);
+int __ast_cli_register_multiple(struct ast_cli_entry *e, int len)
 {
        return 0;
 }
index 99304b2..76a3ad3 100644 (file)
@@ -605,9 +605,9 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
        return localized_context_find_or_create(extcontexts, exttable, name, registrar);
 }
 
-void ast_cli_register_multiple(void);
+void __ast_cli_register_multiple(void);
 
-void ast_cli_register_multiple(void)
+void __ast_cli_register_multiple(void)
 {
 }