Make CEL behavior conform to the documentation

This modifies the behavior of the CEL engine to conform to documented
behavior for Asterisk 12 as defined on the wiki
https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+CEL+Specification

The primary changes deal with removal of the peer field from function
calls since it is no longer directly relevant to the bridging system
and removal of the layer of CDR-like business logic that was providing
a partial emulation of Asterisk 11 CEL functionality. With this change,
there is no longer a distinction between "bridges" and "conferences"
and all participation changes are denoted with bridge enter and bridge
exit messages.

This updates the CEL unit tests to handle these changes and simplifies
some of the macros used in the process.

This also fixes a segfault when attempting to ref a configuration that
failed to load.

Review: https://reviewboard.asterisk.org/r/2788/
(issue ASTERISK-21567)


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397431 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kinsey Moore 2013-08-22 17:13:16 +00:00
parent 641748cc1b
commit 20dcc49d2e
3 changed files with 202 additions and 504 deletions

View File

@ -51,44 +51,28 @@ enum ast_cel_event_type {
AST_CEL_APP_START = 5,
/*! \brief an app ends */
AST_CEL_APP_END = 6,
/*! \brief a bridge is established */
AST_CEL_BRIDGE_START = 7,
/*! \brief a bridge is torn down */
AST_CEL_BRIDGE_END = 8,
/*! \brief a conference is started */
AST_CEL_CONF_START = 9,
/*! \brief a conference is ended */
AST_CEL_CONF_END = 10,
/*! \brief channel enters a bridge */
AST_CEL_BRIDGE_ENTER = 7,
/*! \brief channel exits a bridge */
AST_CEL_BRIDGE_EXIT = 8,
/*! \brief a channel is parked */
AST_CEL_PARK_START = 11,
AST_CEL_PARK_START = 9,
/*! \brief channel out of the park */
AST_CEL_PARK_END = 12,
AST_CEL_PARK_END = 10,
/*! \brief a transfer occurs */
AST_CEL_BLINDTRANSFER = 13,
AST_CEL_BLINDTRANSFER = 11,
/*! \brief a transfer occurs */
AST_CEL_ATTENDEDTRANSFER = 14,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_HOOKFLASH = 16,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_3WAY_START = 17,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_3WAY_END = 18,
/*! \brief channel enters a conference */
AST_CEL_CONF_ENTER = 19,
/*! \brief channel exits a conference */
AST_CEL_CONF_EXIT = 20,
AST_CEL_ATTENDEDTRANSFER = 12,
/*! \brief a user-defined event, the event name field should be set */
AST_CEL_USER_DEFINED = 21,
AST_CEL_USER_DEFINED = 13,
/*! \brief the last channel with the given linkedid is retired */
AST_CEL_LINKEDID_END = 22,
AST_CEL_LINKEDID_END = 14,
/*! \brief a directed pickup was performed on this channel */
AST_CEL_PICKUP = 24,
AST_CEL_PICKUP = 15,
/*! \brief this call was forwarded somewhere else */
AST_CEL_FORWARD = 25,
/*! \brief a bridge turned into a conference and will be treated as such until it is torn down */
AST_CEL_BRIDGE_TO_CONF = 26,
AST_CEL_FORWARD = 16,
/*! \brief A local channel optimization occurred */
AST_CEL_LOCAL_OPTIMIZE = 27,
AST_CEL_LOCAL_OPTIMIZE = 17,
};
/*!
@ -289,7 +273,6 @@ struct ast_channel_snapshot;
* \param userdefevname Custom name for the call event. (optional)
* \param extra An event-specific opaque JSON blob to be rendered and placed
* in the "CEL_EXTRA" information element of the call event. (optional)
* \param peer_name The peer name to be placed into the event. (optional)
*
* \since 12
*
@ -298,7 +281,7 @@ struct ast_channel_snapshot;
*/
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra, const char *peer_name);
struct ast_json *extra);
/*!
* \brief CEL backend callback

View File

@ -21,10 +21,6 @@
*
* \author Steve Murphy <murf@digium.com>
* \author Russell Bryant <russell@digium.com>
*
* \todo Do thorough testing of all transfer methods to ensure that BLINDTRANSFER,
* ATTENDEDTRANSFER, BRIDGE_START, and BRIDGE_END events are all reported
* as expected.
*/
/*! \li \ref cel.c uses the configuration file \ref cel.conf
@ -96,23 +92,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="HANGUP"/>
<enum name="APP_START"/>
<enum name="APP_END"/>
<enum name="BRIDGE_START"/>
<enum name="BRIDGE_END"/>
<enum name="BRIDGE_TO_CONF"/>
<enum name="CONF_START"/>
<enum name="CONF_END"/>
<enum name="PARK_START"/>
<enum name="PARK_END"/>
<enum name="USER_DEFINED"/>
<enum name="CONF_ENTER"/>
<enum name="CONF_EXIT"/>
<enum name="BRIDGE_ENTER"/>
<enum name="BRIDGE_EXIT"/>
<enum name="BLINDTRANSFER"/>
<enum name="ATTENDEDTRANSFER"/>
<enum name="PICKUP"/>
<enum name="FORWARD"/>
<enum name="3WAY_START"/>
<enum name="3WAY_END"/>
<enum name="HOOKFLASH"/>
<enum name="LINKEDID_END"/>
<enum name="LOCAL_OPTIMIZE"/>
</enumlist>
@ -144,12 +132,6 @@ static struct stasis_subscription *cel_parking_forwarder;
/*! Subscription for forwarding the CEL-specific topic */
static struct stasis_subscription *cel_cel_forwarder;
/*! Container for primary channel/bridge ID listing for 2 party bridges */
static struct ao2_container *bridge_primaries;
/*! The number of buckets into which bridge primary structs will be hashed */
#define BRIDGE_PRIMARY_BUCKETS 251
struct stasis_message_type *cel_generic_type(void);
STASIS_MESSAGE_TYPE_DEFN(cel_generic_type);
@ -308,23 +290,15 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
[AST_CEL_HANGUP] = "HANGUP",
[AST_CEL_APP_START] = "APP_START",
[AST_CEL_APP_END] = "APP_END",
[AST_CEL_BRIDGE_START] = "BRIDGE_START",
[AST_CEL_BRIDGE_END] = "BRIDGE_END",
[AST_CEL_BRIDGE_TO_CONF] = "BRIDGE_TO_CONF",
[AST_CEL_CONF_START] = "CONF_START",
[AST_CEL_CONF_END] = "CONF_END",
[AST_CEL_PARK_START] = "PARK_START",
[AST_CEL_PARK_END] = "PARK_END",
[AST_CEL_USER_DEFINED] = "USER_DEFINED",
[AST_CEL_CONF_ENTER] = "CONF_ENTER",
[AST_CEL_CONF_EXIT] = "CONF_EXIT",
[AST_CEL_BRIDGE_ENTER] = "BRIDGE_ENTER",
[AST_CEL_BRIDGE_EXIT] = "BRIDGE_EXIT",
[AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
[AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
[AST_CEL_PICKUP] = "PICKUP",
[AST_CEL_FORWARD] = "FORWARD",
[AST_CEL_3WAY_START] = "3WAY_START",
[AST_CEL_3WAY_END] = "3WAY_END",
[AST_CEL_HOOKFLASH] = "HOOKFLASH",
[AST_CEL_LINKEDID_END] = "LINKEDID_END",
[AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
};
@ -380,80 +354,6 @@ static int cel_backend_cmp(void *obj, void *arg, int flags)
return !strcmp(backend1_id, backend2_id) ? CMP_MATCH | CMP_STOP : 0;
}
struct bridge_assoc {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(bridge_id); /*!< UniqueID of the bridge */
AST_STRING_FIELD(secondary_name); /*!< UniqueID of the secondary/dialed channel */
);
struct ast_channel_snapshot *primary_snapshot; /*!< The snapshot for the initiating channel in the bridge */
int track_as_conf; /*!< Whether this bridge will be treated like a conference in CEL terms */
};
static void bridge_assoc_dtor(void *obj)
{
struct bridge_assoc *assoc = obj;
ast_string_field_free_memory(assoc);
ao2_cleanup(assoc->primary_snapshot);
assoc->primary_snapshot = NULL;
}
static struct bridge_assoc *bridge_assoc_alloc(struct ast_channel_snapshot *primary, const char *bridge_id, const char *secondary_name)
{
RAII_VAR(struct bridge_assoc *, assoc, ao2_alloc(sizeof(*assoc), bridge_assoc_dtor), ao2_cleanup);
if (!primary || !assoc || ast_string_field_init(assoc, 64)) {
return NULL;
}
ast_string_field_set(assoc, bridge_id, bridge_id);
ast_string_field_set(assoc, secondary_name, secondary_name);
assoc->primary_snapshot = primary;
ao2_ref(primary, +1);
ao2_ref(assoc, +1);
return assoc;
}
static int add_bridge_primary(struct ast_channel_snapshot *primary, const char *bridge_id, const char *secondary_name)
{
RAII_VAR(struct bridge_assoc *, assoc, bridge_assoc_alloc(primary, bridge_id, secondary_name), ao2_cleanup);
if (!assoc) {
return -1;
}
ao2_link(bridge_primaries, assoc);
return 0;
}
static void remove_bridge_primary(const char *channel_id)
{
ao2_find(bridge_primaries, channel_id, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_KEY);
}
/*! \brief Hashing function for bridge_assoc */
static int bridge_assoc_hash(const void *obj, int flags)
{
const struct bridge_assoc *assoc = obj;
const char *uniqueid = obj;
if (!(flags & OBJ_KEY)) {
uniqueid = assoc->primary_snapshot->uniqueid;
}
return ast_str_hash(uniqueid);
}
/*! \brief Comparator function for bridge_assoc */
static int bridge_assoc_cmp(void *obj, void *arg, int flags)
{
struct bridge_assoc *assoc1 = obj, *assoc2 = arg;
const char *assoc2_id = arg, *assoc1_id = assoc1->primary_snapshot->uniqueid;
if (!(flags & OBJ_KEY)) {
assoc2_id = assoc2->primary_snapshot->uniqueid;
}
return !strcmp(assoc1_id, assoc2_id) ? CMP_MATCH | CMP_STOP : 0;
}
static const char *get_caller_uniqueid(struct ast_multi_channel_blob *blob)
{
struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
@ -685,7 +585,7 @@ static int cel_track_app(const char *const_app)
static int cel_linkedid_ref(const char *linkedid);
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra, const char *peer_name)
struct ast_json *extra)
{
struct timeval eventtime = ast_tvnow();
RAII_VAR(char *, extra_txt, NULL, ast_json_free);
@ -714,7 +614,7 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer_name, ""),
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, "",
AST_EVENT_IE_END);
}
@ -728,12 +628,10 @@ static int cel_backend_send_cb(void *obj, void *arg, int flags)
static int cel_report_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra, const char *peer2_name)
struct ast_json *extra)
{
struct ast_event *ev;
char *linkedid = ast_strdupa(snapshot->linkedid);
const char *peer_name = peer2_name;
RAII_VAR(struct bridge_assoc *, assoc, NULL, ao2_cleanup);
RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
if (!cfg || !cfg->general) {
@ -744,13 +642,6 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
return 0;
}
if (ast_strlen_zero(peer_name)) {
assoc = ao2_find(bridge_primaries, snapshot->uniqueid, OBJ_KEY);
if (assoc) {
peer_name = assoc->secondary_name;
}
}
/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
* reporting on CHANNEL_START so we can track when to send LINKEDID_END */
if (ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
@ -768,7 +659,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
return 0;
}
ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra, peer_name);
ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra);
if (!ev) {
return -1;
}
@ -801,7 +692,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
* before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
if (ao2_ref(lid, -1) == 3) {
ast_str_container_remove(linkedids, lid);
cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL);
}
ao2_ref(lid, -1);
}
@ -1037,13 +928,13 @@ static void cel_channel_state_change(
int is_hungup, was_hungup;
if (!new_snapshot) {
cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL);
check_retire_linkedid(old_snapshot);
return;
}
if (!old_snapshot) {
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL);
return;
}
@ -1061,12 +952,12 @@ static void cel_channel_state_change(
"hangupcause", new_snapshot->hangupcause,
"hangupsource", new_snapshot->hangupsource,
"dialstatus", dialstatus);
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra);
return;
}
if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL);
return;
}
}
@ -1099,12 +990,12 @@ static void cel_channel_app_change(
/* old snapshot has an application, end it */
if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL);
}
/* new snapshot has an application, start it */
if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL);
}
}
@ -1119,46 +1010,6 @@ cel_channel_snapshot_monitor cel_channel_monitors[] = {
cel_channel_linkedid_change,
};
static void update_bridge_primary(struct ast_channel_snapshot *snapshot)
{
RAII_VAR(struct bridge_assoc *, assoc, NULL, ao2_cleanup);
if (!snapshot) {
return;
}
assoc = ao2_find(bridge_primaries, snapshot->uniqueid, OBJ_KEY);
if (!assoc) {
return;
}
ao2_cleanup(assoc->primary_snapshot);
ao2_ref(snapshot, +1);
assoc->primary_snapshot = snapshot;
}
static int bridge_match_cb(void *obj, void *arg, int flags)
{
struct bridge_assoc *assoc = obj;
char *bridge_id = arg;
if (!strcmp(bridge_id, assoc->bridge_id)) {
return CMP_MATCH;
}
return 0;
}
static struct bridge_assoc *find_bridge_primary_by_bridge_id(const char *bridge_id)
{
char *dup_id = ast_strdupa(bridge_id);
return ao2_callback(bridge_primaries, 0, bridge_match_cb, dup_id);
}
static void clear_bridge_primary(const char *bridge_id)
{
char *dup_id = ast_strdupa(bridge_id);
ao2_callback(bridge_primaries, OBJ_KEY | OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, bridge_match_cb, dup_id);
}
static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
{
if (!snapshot) {
@ -1184,26 +1035,9 @@ static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
return;
}
update_bridge_primary(new_snapshot);
for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
cel_channel_monitors[i](old_snapshot, new_snapshot);
}
} else if (ast_bridge_snapshot_type() == update->type) {
struct ast_bridge_snapshot *old_snapshot;
struct ast_bridge_snapshot *new_snapshot;
old_snapshot = stasis_message_data(update->old_snapshot);
new_snapshot = stasis_message_data(update->new_snapshot);
if (!old_snapshot) {
return;
}
if (!new_snapshot) {
clear_bridge_primary(old_snapshot->uniqueid);
return;
}
}
}
@ -1215,79 +1049,18 @@ static void cel_bridge_enter_cb(
struct ast_bridge_blob *blob = stasis_message_data(message);
struct ast_bridge_snapshot *snapshot = blob->bridge;
struct ast_channel_snapshot *chan_snapshot = blob->channel;
RAII_VAR(struct bridge_assoc *, assoc, find_bridge_primary_by_bridge_id(snapshot->uniqueid), ao2_cleanup);
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
if (cel_filter_channel_snapshot(chan_snapshot)) {
return;
}
if (snapshot->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) {
if (assoc && assoc->track_as_conf) {
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (extra) {
cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
}
return;
}
if (ao2_container_count(snapshot->channels) == 2) {
struct ao2_iterator i;
RAII_VAR(char *, channel_id, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, latest_primary, NULL, ao2_cleanup);
/* get the name of the channel in the container we don't already know the name of */
i = ao2_iterator_init(snapshot->channels, 0);
while ((channel_id = ao2_iterator_next(&i))) {
if (strcmp(channel_id, chan_snapshot->uniqueid)) {
break;
}
ao2_cleanup(channel_id);
channel_id = NULL;
}
ao2_iterator_destroy(&i);
latest_primary = ast_channel_snapshot_get_latest(channel_id);
if (!latest_primary) {
return;
}
add_bridge_primary(latest_primary, snapshot->uniqueid, chan_snapshot->name);
cel_report_event(latest_primary, AST_CEL_BRIDGE_START, NULL, NULL, chan_snapshot->name);
} else if (ao2_container_count(snapshot->channels) > 2) {
if (!assoc) {
ast_log(LOG_ERROR, "No association found for bridge %s\n", snapshot->uniqueid);
return;
}
/* this bridge will no longer be treated like a bridge, so mark the bridge_assoc as such */
if (!assoc->track_as_conf) {
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
assoc->track_as_conf = 1;
extra = ast_json_pack("{s: s, s: s}",
"channel_name", chan_snapshot->name,
"bridge_id", snapshot->uniqueid);
if (extra) {
cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_TO_CONF, NULL,
extra, assoc->secondary_name);
}
ast_string_field_set(assoc, secondary_name, "");
}
}
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
if (!assoc) {
add_bridge_primary(chan_snapshot, snapshot->uniqueid, "");
return;
}
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (extra) {
cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
}
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (!extra) {
return;
}
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, NULL, extra);
}
static void cel_bridge_leave_cb(
@ -1298,41 +1071,18 @@ static void cel_bridge_leave_cb(
struct ast_bridge_blob *blob = stasis_message_data(message);
struct ast_bridge_snapshot *snapshot = blob->bridge;
struct ast_channel_snapshot *chan_snapshot = blob->channel;
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
if (cel_filter_channel_snapshot(chan_snapshot)) {
return;
}
if (snapshot->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) {
RAII_VAR(struct bridge_assoc *, assoc,
find_bridge_primary_by_bridge_id(snapshot->uniqueid),
ao2_cleanup);
if (!assoc) {
return;
}
if (assoc->track_as_conf) {
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (extra) {
cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
}
return;
}
if (ao2_container_count(snapshot->channels) == 1) {
cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_END, NULL, NULL, assoc->secondary_name);
remove_bridge_primary(assoc->primary_snapshot->uniqueid);
return;
}
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (extra) {
cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
}
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
if (!extra) {
return;
}
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, NULL, extra);
}
static void cel_parking_cb(
@ -1350,7 +1100,7 @@ static void cel_parking_cb(
"parker_dial_string", parked_payload->parker_dial_string,
"parking_lot", parked_payload->parkinglot);
if (extra) {
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra);
}
return;
case PARKED_CALL_TIMEOUT:
@ -1372,7 +1122,7 @@ static void cel_parking_cb(
extra = ast_json_pack("{s: s}", "reason", reason);
if (extra) {
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra);
}
}
@ -1404,7 +1154,7 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
if (extra) {
cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL);
cel_report_event(caller, AST_CEL_FORWARD, NULL, extra);
}
}
@ -1429,7 +1179,7 @@ static void cel_generic_cb(
{
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
struct ast_json *extra = ast_json_object_get(event_details, "extra");
cel_report_event(obj->snapshot, event_type, event, extra, NULL);
cel_report_event(obj->snapshot, event_type, event, extra);
break;
}
default:
@ -1467,7 +1217,7 @@ static void cel_blind_transfer_cb(
"bridge_id", bridge_snapshot->uniqueid);
if (extra) {
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra);
}
}
@ -1521,7 +1271,7 @@ static void cel_attended_transfer_cb(
}
break;
}
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra);
}
static void cel_pickup_cb(
@ -1532,12 +1282,18 @@ static void cel_pickup_cb(
struct ast_multi_channel_blob *obj = stasis_message_data(message);
struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
if (!channel || !target) {
return;
}
cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, channel->name);
extra = ast_json_pack("{s: s}", "pickup_channel", channel->name);
if (!extra) {
return;
}
cel_report_event(target, AST_CEL_PICKUP, NULL, extra);
}
static void cel_local_cb(
@ -1548,12 +1304,18 @@ static void cel_local_cb(
struct ast_multi_channel_blob *obj = stasis_message_data(message);
struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
if (!localone || !localtwo) {
return;
}
cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, NULL, localtwo->name);
extra = ast_json_pack("{s: s}", "local_two", localtwo->name);
if (!extra) {
return;
}
cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, extra);
}
static void ast_cel_engine_term(void)
@ -1570,8 +1332,6 @@ static void ast_cel_engine_term(void)
cel_bridge_forwarder = stasis_unsubscribe_and_join(cel_bridge_forwarder);
cel_parking_forwarder = stasis_unsubscribe_and_join(cel_parking_forwarder);
cel_cel_forwarder = stasis_unsubscribe_and_join(cel_cel_forwarder);
ao2_cleanup(bridge_primaries);
bridge_primaries = NULL;
ast_cli_unregister(&cli_status);
ao2_cleanup(cel_dialstatus_store);
cel_dialstatus_store = NULL;
@ -1599,11 +1359,6 @@ int ast_cel_engine_init(void)
return -1;
}
bridge_primaries = ao2_container_alloc(BRIDGE_PRIMARY_BUCKETS, bridge_assoc_hash, bridge_assoc_cmp);
if (!bridge_primaries) {
return -1;
}
cel_backends = ao2_container_alloc(BACKEND_BUCKETS, cel_backend_hash, cel_backend_cmp);
if (!cel_backends) {
return -1;
@ -1756,6 +1511,11 @@ struct stasis_topic *ast_cel_topic(void)
struct ast_cel_general_config *ast_cel_get_config(void)
{
RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
if (!mod_cfg->general) {
return NULL;
}
ao2_ref(mod_cfg->general, +1);
return mod_cfg->general;
}
@ -1763,9 +1523,12 @@ struct ast_cel_general_config *ast_cel_get_config(void)
void ast_cel_set_config(struct ast_cel_general_config *config)
{
RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
ao2_cleanup(mod_cfg->general);
RAII_VAR(struct ast_cel_general_config *, cleanup_config, mod_cfg->general, ao2_cleanup);
mod_cfg->general = config;
ao2_ref(mod_cfg->general, +1);
if (mod_cfg->general) {
ao2_ref(mod_cfg->general, +1);
}
}
int ast_cel_backend_unregister(const char *name)

View File

@ -90,14 +90,14 @@ static void do_sleep(void)
while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
}
#define APPEND_EVENT(chan, ev_type, userevent, extra, peer) do { \
if (append_expected_event(chan, ev_type, userevent, extra, peer)) { \
#define APPEND_EVENT(chan, ev_type, userevent, extra) do { \
if (append_expected_event(chan, ev_type, userevent, extra)) { \
return AST_TEST_FAIL; \
} \
} while (0)
#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra, peer) do { \
if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra, peer)) { \
#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra) do { \
if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra)) { \
return AST_TEST_FAIL; \
} \
} while (0)
@ -108,40 +108,38 @@ static void do_sleep(void)
} \
} while (0)
#define CONF_EXIT(channel, bridge) do { \
#define BRIDGE_EXIT(channel, bridge) do { \
ast_test_validate(test, 0 == ast_bridge_depart(channel)); \
CONF_EXIT_EVENT(channel, bridge); \
BRIDGE_EXIT_EVENT(channel, bridge); \
mid_test_sync(); \
} while (0)
#define CONF_EXIT_EVENT(channel, bridge) do { \
#define BRIDGE_EXIT_EVENT(channel, bridge) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
APPEND_EVENT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra); \
} while (0)
#define CONF_EXIT_SNAPSHOT(channel, bridge) do { \
#define BRIDGE_EXIT_SNAPSHOT(channel, bridge) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT_SNAPSHOT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
APPEND_EVENT_SNAPSHOT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra); \
} while (0)
#define CONF_ENTER_EVENT(channel, bridge) do { \
#define BRIDGE_ENTER(channel, bridge) do { \
ast_test_validate(test, 0 == ast_bridge_impart(bridge, channel, NULL, NULL, 0)); \
do_sleep(); \
BRIDGE_ENTER_EVENT(channel, bridge); \
mid_test_sync(); \
} while (0)
#define BRIDGE_ENTER_EVENT(channel, bridge) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_CONF_ENTER, NULL, extra, NULL); \
} while (0)
#define BRIDGE_TO_CONF(first, second, third, bridge) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s, s: s}", \
"channel_name", ast_channel_name(third), \
"bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(first, AST_CEL_BRIDGE_TO_CONF, NULL, extra, ast_channel_name(second)); \
APPEND_EVENT(channel, AST_CEL_BRIDGE_ENTER, NULL, extra); \
} while (0)
#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
@ -151,7 +149,7 @@ static void do_sleep(void)
"context", context, \
"bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra, NULL); \
APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra); \
} while (0)
#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2) do { \
@ -161,7 +159,7 @@ static void do_sleep(void)
"channel2_name", ast_channel_name(channel2), \
"bridge2_id", bridge2->uniqueid); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL); \
APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra); \
} while (0)
/*! \brief Alice's Caller ID */
@ -179,25 +177,25 @@ static void do_sleep(void)
/*! \brief Create a \ref test_cel_chan_tech for Alice. */
#define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for Bob. */
#define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for David. */
#define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
} while (0)
/*! \brief Emulate a channel entering into an application */
@ -217,7 +215,7 @@ static void do_sleep(void)
#define ANSWER_NO_APP(chan) do { \
ast_setstate(chan, AST_STATE_UP); \
APPEND_EVENT(chan, AST_CEL_ANSWER, NULL, NULL, NULL); \
APPEND_EVENT(chan, AST_CEL_ANSWER, NULL, NULL); \
} while (0)
/*! \brief Hang up a test channel safely */
@ -226,7 +224,7 @@ static void do_sleep(void)
ao2_ref(channel, +1); \
ast_hangup((channel)); \
HANGUP_EVENT(channel, cause, dialstatus); \
APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL, NULL); \
APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL); \
stasis_topic_wait(ast_channel_topic_all_cached()); \
ao2_cleanup(stasis_cache_get(ast_channel_cache(), \
ast_channel_snapshot_type(), ast_channel_uniqueid(channel))); \
@ -241,7 +239,7 @@ static void do_sleep(void)
"hangupsource", "", \
"dialstatus", dialstatus); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, extra, NULL); \
APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, extra); \
} while (0)
static void mid_test_sync(void);
@ -250,13 +248,13 @@ static int append_expected_event(
struct ast_channel *chan,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra, const char *peer);
struct ast_json *extra);
static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra, const char *peer);
struct ast_json *extra);
static int append_dummy_event(void);
@ -408,11 +406,11 @@ AST_TEST_DEFINE(test_cel_single_bridge)
EMULATE_APP_DATA(chan, 2, "Bridge", "");
do_sleep();
ast_bridge_impart(bridge, chan, NULL, NULL, 0);
BRIDGE_ENTER(chan, bridge);
do_sleep();
ast_bridge_depart(chan);
BRIDGE_EXIT(chan, bridge);
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
@ -446,11 +444,11 @@ AST_TEST_DEFINE(test_cel_single_bridge_continue)
EMULATE_APP_DATA(chan, 2, "Bridge", "");
do_sleep();
ast_bridge_impart(bridge, chan, NULL, NULL, 0);
BRIDGE_ENTER(chan, bridge);
do_sleep();
ast_bridge_depart(chan);
BRIDGE_EXIT(chan, bridge);
EMULATE_APP_DATA(chan, 3, "Wait", "");
@ -491,19 +489,16 @@ AST_TEST_DEFINE(test_cel_single_twoparty_bridge_a)
ANSWER_CHANNEL(chan_alice);
EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0);
BRIDGE_ENTER(chan_alice, bridge);
do_sleep();
ANSWER_CHANNEL(chan_bob);
EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0);
do_sleep();
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_bob));
BRIDGE_ENTER(chan_bob, bridge);
ast_bridge_depart(chan_alice);
ast_bridge_depart(chan_bob);
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_bob));
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@ -546,16 +541,12 @@ AST_TEST_DEFINE(test_cel_single_twoparty_bridge_b)
EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
do_sleep();
ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0);
do_sleep();
BRIDGE_ENTER(chan_bob, bridge);
ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0);
do_sleep();
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_ENTER(chan_alice, bridge);
ast_bridge_depart(chan_alice);
ast_bridge_depart(chan_bob);
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@ -566,7 +557,7 @@ AST_TEST_DEFINE(test_cel_single_twoparty_bridge_b)
/* XXX Validation needs to be reworked on a per-channel basis before
* test_cel_single_multiparty_bridge and test_cel_dial_answer_multiparty
* can operate properly. */
#if 0
#ifdef RACEY_TESTS
AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
@ -602,26 +593,22 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
do_sleep();
ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0);
BRIDGE_ENTER(chan_alice, bridge);
ANSWER_CHANNEL(chan_bob);
EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
do_sleep();
ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0);
do_sleep();
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_bob));
BRIDGE_ENTER(chan_bob, bridge);
ANSWER_CHANNEL(chan_charlie);
EMULATE_APP_DATA(chan_charlie, 2, "Bridge", "");
do_sleep();
ast_bridge_impart(bridge, chan_charlie, NULL, NULL, 0);
do_sleep();
BRIDGE_TO_CONF(chan_alice, chan_bob, chan_charlie, bridge);
BRIDGE_ENTER(chan_charlie, bridge);
CONF_EXIT(chan_alice, bridge);
CONF_EXIT(chan_bob, bridge);
CONF_EXIT(chan_charlie, bridge);
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
BRIDGE_EXIT(chan_charlie, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@ -633,7 +620,7 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
#define EMULATE_DIAL(channel, dialstring) do { \
EMULATE_APP_DATA(channel, 1, "Dial", dialstring); \
if (append_expected_event(channel, AST_CEL_APP_START, NULL, NULL, NULL)) { \
if (append_expected_event(channel, AST_CEL_APP_START, NULL, NULL)) { \
return AST_TEST_FAIL; \
} \
} while (0)
@ -643,7 +630,7 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
#define START_DIALED_FULL(caller, callee, number, name) do { \
callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, number, NULL, NULL, ast_channel_linkedid(caller), 0, CHANNEL_TECH_NAME "/" name); \
if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL, NULL)) { \
if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL)) { \
return AST_TEST_FAIL; \
} \
ast_set_flag(ast_channel_flags(callee), AST_FLAG_OUTGOING); \
@ -955,15 +942,11 @@ AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_a)
do_sleep();
ast_bridge_impart(bridge, chan_caller, NULL, NULL, 0);
do_sleep();
ast_bridge_impart(bridge, chan_callee, NULL, NULL, 0);
do_sleep();
APPEND_EVENT(chan_caller, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_callee));
BRIDGE_ENTER(chan_caller, bridge);
BRIDGE_ENTER(chan_callee, bridge);
ast_bridge_depart(chan_caller);
ast_bridge_depart(chan_callee);
APPEND_EVENT(chan_caller, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_callee));
BRIDGE_EXIT(chan_caller, bridge);
BRIDGE_EXIT(chan_callee, bridge);
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
@ -1005,15 +988,11 @@ AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_b)
ANSWER_NO_APP(chan_callee);
do_sleep();
ast_bridge_impart(bridge, chan_callee, NULL, NULL, 0);
do_sleep();
ast_bridge_impart(bridge, chan_caller, NULL, NULL, 0);
do_sleep();
APPEND_EVENT(chan_callee, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_caller));
BRIDGE_ENTER(chan_callee, bridge);
BRIDGE_ENTER(chan_caller, bridge);
ast_bridge_depart(chan_caller);
ast_bridge_depart(chan_callee);
APPEND_EVENT(chan_callee, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_caller));
BRIDGE_EXIT(chan_caller, bridge);
BRIDGE_EXIT(chan_callee, bridge);
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
@ -1021,7 +1000,7 @@ AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_b)
return AST_TEST_PASS;
}
#if 0
#ifdef RACEY_TESTS
AST_TEST_DEFINE(test_cel_dial_answer_multiparty)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
@ -1079,24 +1058,15 @@ AST_TEST_DEFINE(test_cel_dial_answer_multiparty)
do_sleep();
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_charlie, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_david, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_david));
BRIDGE_ENTER(chan_charlie, bridge);
BRIDGE_ENTER(chan_david, bridge);
BRIDGE_ENTER(chan_bob, bridge);
BRIDGE_ENTER(chan_alice, bridge);
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0));
do_sleep();
BRIDGE_TO_CONF(chan_charlie, chan_david, chan_bob, bridge);
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0));
do_sleep();
CONF_ENTER_EVENT(chan_alice, bridge);
CONF_EXIT(chan_alice, bridge);
CONF_EXIT(chan_bob, bridge);
CONF_EXIT(chan_charlie, bridge);
CONF_EXIT(chan_david, bridge);
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
BRIDGE_EXIT(chan_charlie, bridge);
BRIDGE_EXIT(chan_david, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@ -1137,12 +1107,8 @@ AST_TEST_DEFINE(test_cel_blind_transfer)
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_ENTER(chan_bob, bridge);
BRIDGE_ENTER(chan_alice, bridge);
pair.bridge = bridge;
pair.channel = chan_alice;
@ -1150,10 +1116,8 @@ AST_TEST_DEFINE(test_cel_blind_transfer)
&pair, "transfer_context", "transfer_extension");
BLINDTRANSFER_EVENT(chan_alice, bridge, "transfer_extension", "transfer_context");
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
ast_test_validate(test, 0 == ast_bridge_depart(chan_alice));
ast_test_validate(test, 0 == ast_bridge_depart(chan_bob));
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
do_sleep();
@ -1197,12 +1161,8 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_basic_new();
@ -1213,26 +1173,24 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
ANSWER_NO_APP(chan_david);
ANSWER_NO_APP(chan_charlie);
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
do_sleep();
BRIDGE_ENTER(chan_charlie, bridge2);
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_david, NULL, NULL, 0));
BRIDGE_ENTER(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_bob, bridge1);
do_sleep();
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_david));
/* Perform attended transfer */
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep();
BRIDGE_TO_CONF(chan_charlie, chan_david, chan_bob, bridge2);
CONF_EXIT_EVENT(chan_david, bridge2);
BRIDGE_ENTER_EVENT(chan_bob, bridge2);
BRIDGE_EXIT_EVENT(chan_david, bridge2);
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1);
do_sleep();
CONF_EXIT(chan_bob, bridge2);
CONF_EXIT(chan_charlie, bridge2);
BRIDGE_EXIT(chan_bob, bridge2);
BRIDGE_EXIT(chan_charlie, bridge2);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
do_sleep();
@ -1282,12 +1240,8 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
@ -1299,26 +1253,23 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
ANSWER_NO_APP(chan_david);
ANSWER_NO_APP(chan_charlie);
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
do_sleep();
BRIDGE_ENTER(chan_charlie, bridge2);
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_david, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_david));
BRIDGE_ENTER(chan_david, bridge2);
/* Perform attended transfer */
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_david));
ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep();
BRIDGE_TO_CONF(chan_bob, chan_alice, chan_charlie, bridge1);
CONF_EXIT_EVENT(chan_alice, bridge1);
BRIDGE_EXIT_EVENT(chan_charlie, bridge2);
BRIDGE_ENTER_EVENT(chan_charlie, bridge1);
BRIDGE_EXIT_EVENT(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1);
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2);
do_sleep();
CONF_EXIT(chan_bob, bridge1);
CONF_EXIT(chan_charlie, bridge1);
BRIDGE_EXIT(chan_bob, bridge1);
BRIDGE_EXIT(chan_charlie, bridge1);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
do_sleep();
@ -1370,12 +1321,8 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
@ -1389,12 +1336,8 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
ANSWER_NO_APP(chan_david);
ANSWER_NO_APP(chan_charlie);
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
do_sleep();
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_david, NULL, NULL, 0));
do_sleep();
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_david));
BRIDGE_ENTER(chan_charlie, bridge2);
BRIDGE_ENTER(chan_david, bridge2);
/* Perform attended transfer */
@ -1407,27 +1350,21 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2);
/* The two BRIDGE_TO_CONFs and CONF_EXITs are all racing to be first */
/* BRIDGE_TO_CONF with primary charlie, peer david, and trigger channel ;2 */
APPEND_DUMMY_EVENT();
ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep();
/* BRIDGE_TO_CONF with primary bob, peer alice, and trigger channel ;1 */
/* ;1 and ;2 BRIDGE_ENTER and ;1 ANSWER */
APPEND_DUMMY_EVENT();
/* CONF_EXIT alice and david */
APPEND_DUMMY_EVENT();
APPEND_DUMMY_EVENT();
/* ANSWER ;1 */
/* BRIDGE_EXIT alice and david */
APPEND_DUMMY_EVENT();
APPEND_DUMMY_EVENT();
do_sleep();
CONF_EXIT(chan_bob, bridge1);
CONF_EXIT(chan_charlie, bridge2);
BRIDGE_EXIT(chan_bob, bridge1);
BRIDGE_EXIT(chan_charlie, bridge2);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
do_sleep();
@ -1473,8 +1410,13 @@ AST_TEST_DEFINE(test_cel_dial_pickup)
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
{
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
SCOPED_CHANNELLOCK(lock, chan_callee);
APPEND_EVENT(chan_callee, AST_CEL_PICKUP, NULL, NULL, ast_channel_name(chan_charlie));
extra = ast_json_pack("{s: s}", "pickup_channel", ast_channel_name(chan_charlie));
ast_test_validate(test, extra != NULL);
APPEND_EVENT(chan_callee, AST_CEL_PICKUP, NULL, extra);
ast_test_validate(test, 0 == ast_do_pickup(chan_charlie, chan_callee));
}
@ -1500,6 +1442,7 @@ AST_TEST_DEFINE(test_cel_local_optimize)
RAII_VAR(struct ast_channel_snapshot *, bob_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, local_opt_begin, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, local_opt_end, NULL, ao2_cleanup);
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
switch (cmd) {
case TEST_INIT:
@ -1538,7 +1481,11 @@ AST_TEST_DEFINE(test_cel_local_optimize)
stasis_publish(ast_channel_topic(chan_alice), local_opt_begin);
stasis_publish(ast_channel_topic(chan_alice), local_opt_end);
APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, NULL, bob_snapshot->name);
extra = ast_json_pack("{s: s}", "local_two", bob_snapshot->name);
ast_test_validate(test, extra != NULL);
APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@ -1621,10 +1568,10 @@ static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra, const char *peer)
struct ast_json *extra)
{
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
ev = ast_cel_create_event(snapshot, type, userdefevname, extra);
if (!ev) {
return -1;
}
@ -1636,7 +1583,7 @@ static int append_expected_event(
struct ast_channel *chan,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra, const char *peer)
struct ast_json *extra)
{
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
snapshot = ast_channel_snapshot_create(chan);
@ -1644,7 +1591,7 @@ static int append_expected_event(
return -1;
}
return append_expected_event_snapshot(snapshot, type, userdefevname, extra, peer);
return append_expected_event_snapshot(snapshot, type, userdefevname, extra);
}
static void test_sub(struct ast_event *event)
@ -1904,7 +1851,9 @@ static int unload_module(void)
AST_TEST_UNREGISTER(test_cel_single_bridge_continue);
AST_TEST_UNREGISTER(test_cel_single_twoparty_bridge_a);
AST_TEST_UNREGISTER(test_cel_single_twoparty_bridge_b);
/*AST_TEST_UNREGISTER(test_cel_single_multiparty_bridge);*/
#ifdef RACEY_TESTS
AST_TEST_UNREGISTER(test_cel_single_multiparty_bridge);
#endif
AST_TEST_UNREGISTER(test_cel_dial_unanswered);
AST_TEST_UNREGISTER(test_cel_dial_congestion);
@ -1915,7 +1864,9 @@ static int unload_module(void)
AST_TEST_UNREGISTER(test_cel_dial_answer_no_bridge);
AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_a);
AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_b);
/*AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);*/
#ifdef RACEY_TESTS
AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);
#endif
AST_TEST_UNREGISTER(test_cel_blind_transfer);
AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_swap);
@ -1956,11 +1907,8 @@ static int load_module(void)
cel_test_config->events |= 1<<AST_CEL_CHANNEL_END;
cel_test_config->events |= 1<<AST_CEL_ANSWER;
cel_test_config->events |= 1<<AST_CEL_HANGUP;
cel_test_config->events |= 1<<AST_CEL_BRIDGE_START;
cel_test_config->events |= 1<<AST_CEL_BRIDGE_END;
cel_test_config->events |= 1<<AST_CEL_BRIDGE_TO_CONF;
cel_test_config->events |= 1<<AST_CEL_CONF_ENTER;
cel_test_config->events |= 1<<AST_CEL_CONF_EXIT;
cel_test_config->events |= 1<<AST_CEL_BRIDGE_ENTER;
cel_test_config->events |= 1<<AST_CEL_BRIDGE_EXIT;
cel_test_config->events |= 1<<AST_CEL_BLINDTRANSFER;
cel_test_config->events |= 1<<AST_CEL_ATTENDEDTRANSFER;
cel_test_config->events |= 1<<AST_CEL_PICKUP;
@ -1977,7 +1925,9 @@ static int load_module(void)
AST_TEST_REGISTER(test_cel_single_bridge_continue);
AST_TEST_REGISTER(test_cel_single_twoparty_bridge_a);
AST_TEST_REGISTER(test_cel_single_twoparty_bridge_b);
/*AST_TEST_REGISTER(test_cel_single_multiparty_bridge);*/
#ifdef RACEY_TESTS
AST_TEST_REGISTER(test_cel_single_multiparty_bridge);
#endif
AST_TEST_REGISTER(test_cel_dial_unanswered);
AST_TEST_REGISTER(test_cel_dial_congestion);
@ -1988,7 +1938,9 @@ static int load_module(void)
AST_TEST_REGISTER(test_cel_dial_answer_no_bridge);
AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_a);
AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_b);
/*AST_TEST_REGISTER(test_cel_dial_answer_multiparty);*/
#ifdef RACEY_TESTS
AST_TEST_REGISTER(test_cel_dial_answer_multiparty);
#endif
AST_TEST_REGISTER(test_cel_blind_transfer);
AST_TEST_REGISTER(test_cel_attended_transfer_bridges_swap);