* 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
------------------
------------------
* 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
------------------
# 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)
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,$@)),)
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;
}
/* 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;
--- /dev/null
+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)
+])
--- /dev/null
+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"
+])
-/\/\*\*\* MODULEINFO/ {printit=1; next}
+/\/\*\*\* +MODULEINFO/ {printit=1; next}
/<support_level>/ {if (gotsupportlevel) { next }; gotsupportlevel=1}
/\*\*\*\// {printit=0}
/.*/ {if (printit) print}
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 */
usegmtime = 0;
loguniqueid = 0;
loguserfield = 0;
+ newcdrcolumns = 0;
if (!(v = ast_variable_browse(cfg, "csv"))) {
ast_config_destroy(cfg);
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;
/* 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 */
#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) */
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")) {
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;
}
} 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;
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")) {
#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"
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;
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;
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);
}
} 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")) {
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;
} 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")) {
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;
}
* \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;
}
/* ------------------------------------------------------------------- */
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);
/* ------------------------------------------------------------------- */
*/
//#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. */
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",
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");
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",
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)) {
#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. */
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;
-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
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
;
;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
; 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=========================
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
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
+
+ { $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
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 :
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
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,
down_revision = '23530d604b96'
from alembic import op
+from sqlalchemy.dialects.postgresql import ENUM
import sqlalchemy as sa
OLD_ENUM = ['rfc4733', 'inband', 'info']
#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 */
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
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
/* 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
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
*
* \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
*/
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);
*
* \li language
* \li accountcode
- * \li peeracccount
+ * \li peeraccount
* \li linkedid
*/
DECLARE_STRINGFIELD_SETTERS_FOR(name);
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()
* \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
* \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
*/
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)
/*!
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)
* \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
/*! \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.
* \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
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);
{ \
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, \
/* 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
{ \
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) \
* \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.
#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,
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;
};
/*!
/*!
* \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.
* 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
*/
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
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
extern "C" {
#endif
-#include "asterisk/optional_api.h"
#include "asterisk/config.h"
#define AST_SIP_API_VERSION 1
/*!
* \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
* \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);
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
#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 */
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
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;
}
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)
{
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");
}
}
+ 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) */
*/
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;
}
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);
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.
*/
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);
}
/*!
*/
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);
}
}
*/
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);
+ }
}
/*!
*/
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);
+ }
}
/*!
/*!
* \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);
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);
}
/*!
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,
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;
}
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;
}
}
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);
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;
}
}
}
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
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);
}
}
}
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))) {
}
}
}
- return list->stimulus;
+ stimulus = list->stimulus;
+ ast_free(list);
+ return stimulus;
}
/*!
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);
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) ||
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;
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 */
#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"
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");
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;
}
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);
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;
}
.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;
*/
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"));
#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"
#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
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);
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;
}
} 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") ) {
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);
}
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);
}
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);
}
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);
}
#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 :
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);
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
*/
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;
}
/* 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");
}
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");
static void destroy_hint(void *obj)
{
struct ast_hint *hint = obj;
+ int i;
if (hint->callbacks) {
struct ast_state_cb *state_cb;
}
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);
}
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);
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;
}
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);
#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;
}
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);
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);
} 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);
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) {
}
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);
{
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.
ast_channel_unlock(forwarded);
}
ast_channel_unlock(peer);
+ remove_dial_masquerade_caller(caller);
ast_channel_unlock(caller);
}
}
return;
}
ast_free(doomed->dialstring);
+ ast_channel_cleanup(doomed->peer);
ast_free(doomed);
}
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)
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)
.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.
*/
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;
}
/*!
{
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;
}
return -1;
}
}
- target->peer = peer;
+ target->peer = ast_channel_ref(peer);
/* Put peer target into datastore */
ao2_lock(masq_data);
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);
+}
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;
}
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, ...)
{
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;
}
{
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;
}
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);
}
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);
}
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)
{
return -1;
}
+ AST_TEST_REGISTER(test_registrations);
+
/* Register cli commands */
ast_cli_register_multiple(test_cli, ARRAY_LEN(test_cli));
#endif
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@
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) {
*/
/*** MODULEINFO
+ <depend type="module">res_stasis_recording</depend>
+ <depend type="module">res_stasis_playback</depend>
<support_level>core</support_level>
***/
*/
/*** MODULEINFO
- <depend type="module">res_stasis_device_states</depend>
+ <depend type="module">res_stasis_device_state</depend>
<support_level>core</support_level>
***/
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;
}
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);
}
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;
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;
}
* \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);
"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) {
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])) {
res = CLI_SHOWUSAGE;
}
- ast_module_unref(ast_module_info->self);
-
return res;
}
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;
if (fs_in)
ast_closestream(fs_in);
- ast_module_unref(ast_module_info->self);
-
return ret;
}
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--;
}
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) {
char *tracefile = "/tmp/odbc.trace";
#endif
SQLHDBC con;
+ long int negative_cache_expiration;
if (obj->up) {
odbc_obj_disconnect(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)) {
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();
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();
* \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
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)) {
}
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();
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;
* at the top of the source tree.
*/
-/*** MODULEINFO
+/*** MODULEINFO
<depend>pjproject</depend>
<depend>res_pjsip</depend>
<depend>res_pjsip_session</depend>
#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
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(®ister_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)
{
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;
}
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 {
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(®ister_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;
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;
}
}
/* 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;
}
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(®exbuf);
return -1;
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");
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");
--- /dev/null
+/*
+ * 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");
$(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 "$<" "$@"
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 *),
}
-void ast_cli_register_multiple(void)
+void __ast_cli_register_multiple(void)
{
if(!no_comp)
printf("Executed ast_cli_register_multiple();\n");
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;
}
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)
{
}