Restore usefulness of the CEL Peer field

This change makes the CEL peer field useful again for BRIDGE_ENTER and
BRIDGE_EXIT events and fills the field with a comma-separated list of
all channels in the bridge other than the channel that is entering or
exiting the bridge.

Review: https://reviewboard.asterisk.org/r/2840/
(closes issue ASTERISK-22393)
........

Merged revisions 399912 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@399913 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kinsey Moore
2013-09-27 14:08:23 +00:00
parent 103ebcf807
commit b22612110c
3 changed files with 256 additions and 58 deletions

View File

@@ -273,6 +273,7 @@ struct ast_channel_snapshot;
* \param userdefevname Custom name for the call event. (optional) * \param userdefevname Custom name for the call event. (optional)
* \param extra An event-specific opaque JSON blob to be rendered and placed * \param extra An event-specific opaque JSON blob to be rendered and placed
* in the "CEL_EXTRA" information element of the call event. (optional) * in the "CEL_EXTRA" information element of the call event. (optional)
* \param peer_str A list of comma-separated peer channel names. (optional)
* *
* \since 12 * \since 12
* *
@@ -281,7 +282,7 @@ struct ast_channel_snapshot;
*/ */
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot, struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname, enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra); struct ast_json *extra, const char *peer_str);
/*! /*!
* \brief CEL backend callback * \brief CEL backend callback

View File

@@ -585,7 +585,7 @@ static int cel_track_app(const char *const_app)
static int cel_linkedid_ref(const char *linkedid); static int cel_linkedid_ref(const char *linkedid);
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot, struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname, enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra) struct ast_json *extra, const char *peer)
{ {
struct timeval eventtime = ast_tvnow(); struct timeval eventtime = ast_tvnow();
RAII_VAR(char *, extra_txt, NULL, ast_json_free); RAII_VAR(char *, extra_txt, NULL, ast_json_free);
@@ -614,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_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield, 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_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, "", AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer, ""),
AST_EVENT_IE_END); AST_EVENT_IE_END);
} }
@@ -628,7 +628,7 @@ static int cel_backend_send_cb(void *obj, void *arg, int flags)
static int cel_report_event(struct ast_channel_snapshot *snapshot, static int cel_report_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname, enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra) struct ast_json *extra, const char *peer_str)
{ {
struct ast_event *ev; struct ast_event *ev;
char *linkedid = ast_strdupa(snapshot->linkedid); char *linkedid = ast_strdupa(snapshot->linkedid);
@@ -659,7 +659,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
return 0; return 0;
} }
ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra); ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra, peer_str);
if (!ev) { if (!ev) {
return -1; return -1;
} }
@@ -692,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. */ * before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
if (ao2_ref(lid, -1) == 3) { if (ao2_ref(lid, -1) == 3) {
ast_str_container_remove(linkedids, lid); ast_str_container_remove(linkedids, lid);
cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL); cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
} }
ao2_ref(lid, -1); ao2_ref(lid, -1);
} }
@@ -928,13 +928,13 @@ static void cel_channel_state_change(
int is_hungup, was_hungup; int is_hungup, was_hungup;
if (!new_snapshot) { if (!new_snapshot) {
cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL); cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
check_retire_linkedid(old_snapshot); check_retire_linkedid(old_snapshot);
return; return;
} }
if (!old_snapshot) { if (!old_snapshot) {
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL); cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
return; return;
} }
@@ -952,12 +952,12 @@ static void cel_channel_state_change(
"hangupcause", new_snapshot->hangupcause, "hangupcause", new_snapshot->hangupcause,
"hangupsource", new_snapshot->hangupsource, "hangupsource", new_snapshot->hangupsource,
"dialstatus", dialstatus); "dialstatus", dialstatus);
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra); cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
return; return;
} }
if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) { if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL); cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
return; return;
} }
} }
@@ -990,12 +990,12 @@ static void cel_channel_app_change(
/* old snapshot has an application, end it */ /* old snapshot has an application, end it */
if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) { if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL); cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
} }
/* new snapshot has an application, start it */ /* new snapshot has an application, start it */
if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) { if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL); cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
} }
} }
@@ -1041,6 +1041,45 @@ static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
} }
} }
static struct ast_str *cel_generate_peer_str(
struct ast_bridge_snapshot *bridge,
struct ast_channel_snapshot *chan)
{
struct ast_str *peer_str = ast_str_create(32);
struct ao2_iterator i;
char *current_chan = NULL;
if (!peer_str) {
return NULL;
}
for (i = ao2_iterator_init(bridge->channels, 0);
(current_chan = ao2_iterator_next(&i));
ao2_cleanup(current_chan)) {
RAII_VAR(struct ast_channel_snapshot *, current_snapshot,
NULL,
ao2_cleanup);
/* Don't add the channel for which this message is being generated */
if (!strcmp(current_chan, chan->uniqueid)) {
continue;
}
current_snapshot = ast_channel_snapshot_get_latest(current_chan);
if (!current_snapshot) {
continue;
}
ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
}
ao2_iterator_destroy(&i);
/* Rip off the trailing comma */
ast_str_truncate(peer_str, -1);
return peer_str;
}
static void cel_bridge_enter_cb( static void cel_bridge_enter_cb(
void *data, struct stasis_subscription *sub, void *data, struct stasis_subscription *sub,
struct stasis_topic *topic, struct stasis_topic *topic,
@@ -1050,6 +1089,7 @@ static void cel_bridge_enter_cb(
struct ast_bridge_snapshot *snapshot = blob->bridge; struct ast_bridge_snapshot *snapshot = blob->bridge;
struct ast_channel_snapshot *chan_snapshot = blob->channel; struct ast_channel_snapshot *chan_snapshot = blob->channel;
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
if (cel_filter_channel_snapshot(chan_snapshot)) { if (cel_filter_channel_snapshot(chan_snapshot)) {
return; return;
@@ -1060,7 +1100,12 @@ static void cel_bridge_enter_cb(
return; return;
} }
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, NULL, extra); peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
if (!peer_str) {
return;
}
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, NULL, extra, ast_str_buffer(peer_str));
} }
static void cel_bridge_leave_cb( static void cel_bridge_leave_cb(
@@ -1072,6 +1117,7 @@ static void cel_bridge_leave_cb(
struct ast_bridge_snapshot *snapshot = blob->bridge; struct ast_bridge_snapshot *snapshot = blob->bridge;
struct ast_channel_snapshot *chan_snapshot = blob->channel; struct ast_channel_snapshot *chan_snapshot = blob->channel;
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
if (cel_filter_channel_snapshot(chan_snapshot)) { if (cel_filter_channel_snapshot(chan_snapshot)) {
return; return;
@@ -1082,7 +1128,12 @@ static void cel_bridge_leave_cb(
return; return;
} }
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, NULL, extra); peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
if (!peer_str) {
return;
}
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str));
} }
static void cel_parking_cb( static void cel_parking_cb(
@@ -1100,7 +1151,7 @@ static void cel_parking_cb(
"parker_dial_string", parked_payload->parker_dial_string, "parker_dial_string", parked_payload->parker_dial_string,
"parking_lot", parked_payload->parkinglot); "parking_lot", parked_payload->parkinglot);
if (extra) { if (extra) {
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra); cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
} }
return; return;
case PARKED_CALL_TIMEOUT: case PARKED_CALL_TIMEOUT:
@@ -1122,7 +1173,7 @@ static void cel_parking_cb(
extra = ast_json_pack("{s: s}", "reason", reason); extra = ast_json_pack("{s: s}", "reason", reason);
if (extra) { if (extra) {
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra); cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
} }
} }
@@ -1154,7 +1205,7 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward")); extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
if (extra) { if (extra) {
cel_report_event(caller, AST_CEL_FORWARD, NULL, extra); cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL);
} }
} }
@@ -1179,7 +1230,7 @@ static void cel_generic_cb(
{ {
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event")); 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"); struct ast_json *extra = ast_json_object_get(event_details, "extra");
cel_report_event(obj->snapshot, event_type, event, extra); cel_report_event(obj->snapshot, event_type, event, extra, NULL);
break; break;
} }
default: default:
@@ -1232,7 +1283,7 @@ static void cel_blind_transfer_cb(
"bridge_id", bridge_snapshot->uniqueid); "bridge_id", bridge_snapshot->uniqueid);
if (extra) { if (extra) {
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra); cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
} }
} }
@@ -1286,7 +1337,7 @@ static void cel_attended_transfer_cb(
} }
break; break;
} }
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra); cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
} }
static void cel_pickup_cb( static void cel_pickup_cb(
@@ -1308,7 +1359,7 @@ static void cel_pickup_cb(
return; return;
} }
cel_report_event(target, AST_CEL_PICKUP, NULL, extra); cel_report_event(target, AST_CEL_PICKUP, NULL, extra, NULL);
} }
static void cel_local_cb( static void cel_local_cb(
@@ -1330,7 +1381,7 @@ static void cel_local_cb(
return; return;
} }
cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, extra); cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
} }
static void ast_cel_engine_term(void) static void ast_cel_engine_term(void)

View File

@@ -91,13 +91,19 @@ static void do_sleep(void)
} }
#define APPEND_EVENT(chan, ev_type, userevent, extra) do { \ #define APPEND_EVENT(chan, ev_type, userevent, extra) do { \
if (append_expected_event(chan, ev_type, userevent, extra)) { \ if (append_expected_event(chan, ev_type, userevent, extra, NULL)) { \
return AST_TEST_FAIL; \ return AST_TEST_FAIL; \
} \ } \
} while (0) } while (0)
#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra) do { \ #define APPEND_EVENT_PEER(chan, ev_type, userevent, extra, peer) do { \
if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra)) { \ if (append_expected_event(chan, ev_type, userevent, extra, peer)) { \
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)) { \
return AST_TEST_FAIL; \ return AST_TEST_FAIL; \
} \ } \
} while (0) } while (0)
@@ -115,17 +121,31 @@ static void do_sleep(void)
} while (0) } while (0)
#define BRIDGE_EXIT_EVENT(channel, bridge) do { \ #define BRIDGE_EXIT_EVENT(channel, bridge) do { \
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
stasis_topic_wait(ast_channel_topic_all()); \
stasis_topic_wait(ast_bridge_topic_all()); \
peer_str = test_cel_generate_peer_str(channel, bridge); \
ast_test_validate(test, peer_str != NULL); \
BRIDGE_EXIT_EVENT_PEER(channel, bridge, ast_str_buffer(peer_str)); \
} while (0)
#define BRIDGE_EXIT_EVENT_PEER(channel, bridge, peer) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \ RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \ extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \ ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra); \ APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, peer); \
} while (0) } while (0)
#define BRIDGE_EXIT_SNAPSHOT(channel, bridge) do { \ #define BRIDGE_EXIT_SNAPSHOT(channel, bridge) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \ RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
stasis_topic_wait(ast_channel_topic_all()); \
stasis_topic_wait(ast_bridge_topic_all()); \
peer_str = test_cel_generate_peer_str_snapshot(channel, bridge); \
ast_test_validate(test, peer_str != NULL); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \ extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \ ast_test_validate(test, extra != NULL); \
APPEND_EVENT_SNAPSHOT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra); \ APPEND_EVENT_SNAPSHOT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str)); \
} while (0) } while (0)
#define BRIDGE_ENTER(channel, bridge) do { \ #define BRIDGE_ENTER(channel, bridge) do { \
@@ -136,10 +156,19 @@ static void do_sleep(void)
} while (0) } while (0)
#define BRIDGE_ENTER_EVENT(channel, bridge) do { \ #define BRIDGE_ENTER_EVENT(channel, bridge) do { \
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
stasis_topic_wait(ast_channel_topic_all()); \
stasis_topic_wait(ast_bridge_topic_all()); \
peer_str = test_cel_generate_peer_str(channel, bridge); \
ast_test_validate(test, peer_str != NULL); \
BRIDGE_ENTER_EVENT_PEER(channel, bridge, ast_str_buffer(peer_str)); \
} while (0)
#define BRIDGE_ENTER_EVENT_PEER(channel, bridge, peer) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \ RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \ extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
ast_test_validate(test, extra != NULL); \ ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_BRIDGE_ENTER, NULL, extra); \ APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_ENTER, NULL, extra, peer); \
} while (0) } while (0)
#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \ #define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
@@ -248,16 +277,81 @@ static int append_expected_event(
struct ast_channel *chan, struct ast_channel *chan,
enum ast_cel_event_type type, enum ast_cel_event_type type,
const char *userdefevname, const char *userdefevname,
struct ast_json *extra); struct ast_json *extra,
const char *peer);
static int append_expected_event_snapshot( static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type type, enum ast_cel_event_type type,
const char *userdefevname, const char *userdefevname,
struct ast_json *extra); struct ast_json *extra,
const char *peer);
static int append_dummy_event(void); static int append_dummy_event(void);
static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot *chan, struct ast_bridge_snapshot *bridge)
{
struct ast_str *peer_str = ast_str_create(32);
struct ao2_iterator i;
char *current_chan = NULL;
if (!peer_str) {
return NULL;
}
for (i = ao2_iterator_init(bridge->channels, 0);
(current_chan = ao2_iterator_next(&i));
ao2_cleanup(current_chan)) {
RAII_VAR(struct ast_channel_snapshot *, current_snapshot,
NULL,
ao2_cleanup);
/* Don't add the channel for which this message is being generated */
if (!strcmp(current_chan, chan->uniqueid)) {
continue;
}
current_snapshot = ast_channel_snapshot_get_latest(current_chan);
if (!current_snapshot) {
continue;
}
ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
}
ao2_iterator_destroy(&i);
/* Rip off the trailing comma */
ast_str_truncate(peer_str, -1);
return peer_str;
}
static struct ast_str *test_cel_generate_peer_str_snapshot(struct ast_channel_snapshot *chan, struct ast_bridge *bridge)
{
RAII_VAR(struct ast_bridge_snapshot *, snapshot,
ast_bridge_snapshot_get_latest(bridge->uniqueid),
ao2_cleanup);
if (!snapshot) {
return NULL;
}
return __test_cel_generate_peer_str(chan, snapshot);
}
static struct ast_str *test_cel_generate_peer_str(struct ast_channel *chan, struct ast_bridge *bridge)
{
RAII_VAR(struct ast_channel_snapshot *, snapshot,
ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
ao2_cleanup);
if (!snapshot) {
return NULL;
}
return test_cel_generate_peer_str_snapshot(snapshot, bridge);
}
static void safe_channel_release(struct ast_channel *chan) static void safe_channel_release(struct ast_channel *chan)
{ {
if (!chan) { if (!chan) {
@@ -620,7 +714,7 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
#define EMULATE_DIAL(channel, dialstring) do { \ #define EMULATE_DIAL(channel, dialstring) do { \
EMULATE_APP_DATA(channel, 1, "Dial", dialstring); \ EMULATE_APP_DATA(channel, 1, "Dial", dialstring); \
if (append_expected_event(channel, AST_CEL_APP_START, NULL, NULL)) { \ if (append_expected_event(channel, AST_CEL_APP_START, NULL, NULL, NULL)) { \
return AST_TEST_FAIL; \ return AST_TEST_FAIL; \
} \ } \
} while (0) } while (0)
@@ -630,7 +724,7 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
#define START_DIALED_FULL(caller, callee, number, name) do { \ #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); \ 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)) { \ if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL, NULL)) { \
return AST_TEST_FAIL; \ return AST_TEST_FAIL; \
} \ } \
ast_set_flag(ast_channel_flags(callee), AST_FLAG_OUTGOING); \ ast_set_flag(ast_channel_flags(callee), AST_FLAG_OUTGOING); \
@@ -1182,7 +1276,7 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
/* Perform attended transfer */ /* Perform attended transfer */
ast_bridge_transfer_attended(chan_alice, chan_david); ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep(); do_sleep();
BRIDGE_ENTER_EVENT(chan_bob, bridge2); BRIDGE_ENTER_EVENT_PEER(chan_bob, bridge2, "CELTestChannel/David,CELTestChannel/Charlie");
BRIDGE_EXIT_EVENT(chan_david, bridge2); BRIDGE_EXIT_EVENT(chan_david, bridge2);
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2); ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2);
@@ -1260,8 +1354,8 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
/* Perform attended transfer */ /* Perform attended transfer */
ast_bridge_transfer_attended(chan_alice, chan_david); ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep(); do_sleep();
BRIDGE_EXIT_EVENT(chan_charlie, bridge2); BRIDGE_EXIT_EVENT_PEER(chan_charlie, bridge2, "CELTestChannel/David");
BRIDGE_ENTER_EVENT(chan_charlie, bridge1); BRIDGE_ENTER_EVENT_PEER(chan_charlie, bridge1, "CELTestChannel/Bob,CELTestChannel/Alice");
BRIDGE_EXIT_EVENT(chan_david, bridge2); BRIDGE_EXIT_EVENT(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1); BRIDGE_EXIT_EVENT(chan_alice, bridge1);
@@ -1485,7 +1579,7 @@ AST_TEST_DEFINE(test_cel_local_optimize)
extra = ast_json_pack("{s: s}", "local_two", bob_snapshot->name); extra = ast_json_pack("{s: s}", "local_two", bob_snapshot->name);
ast_test_validate(test, extra != NULL); ast_test_validate(test, extra != NULL);
APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra); APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, ""); HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, ""); HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
@@ -1568,10 +1662,11 @@ static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type type, enum ast_cel_event_type type,
const char *userdefevname, const char *userdefevname,
struct ast_json *extra) struct ast_json *extra,
const char *peer)
{ {
RAII_VAR(struct ast_event *, ev, NULL, ast_free); RAII_VAR(struct ast_event *, ev, NULL, ast_free);
ev = ast_cel_create_event(snapshot, type, userdefevname, extra); ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
if (!ev) { if (!ev) {
return -1; return -1;
} }
@@ -1583,7 +1678,8 @@ static int append_expected_event(
struct ast_channel *chan, struct ast_channel *chan,
enum ast_cel_event_type type, enum ast_cel_event_type type,
const char *userdefevname, const char *userdefevname,
struct ast_json *extra) struct ast_json *extra,
const char *peer)
{ {
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
snapshot = ast_channel_snapshot_create(chan); snapshot = ast_channel_snapshot_create(chan);
@@ -1591,7 +1687,7 @@ static int append_expected_event(
return -1; return -1;
} }
return append_expected_event_snapshot(snapshot, type, userdefevname, extra); return append_expected_event_snapshot(snapshot, type, userdefevname, extra, peer);
} }
static void test_sub(struct ast_event *event) static void test_sub(struct ast_event *event)
@@ -1647,7 +1743,48 @@ static int test_cel_init_cb(struct ast_test_info *info, struct ast_test *test)
return 0; return 0;
} }
/*! \brief Check an IE value from two events, */ /*!
* \brief Check two peer strings for equality
*
* \retval zero if the peer strings do not match
* \retval non-zero if the peer strings match
*/
static int test_cel_peer_strings_match(const char *str1, const char *str2)
{
struct ao2_container *intersection = ast_str_container_alloc(11);
RAII_VAR(char *, str1_dup, ast_strdup(str1), ast_free);
RAII_VAR(char *, str2_dup, ast_strdup(str2), ast_free);
char *chan;
while ((chan = strsep(&str1_dup, ","))) {
ast_str_container_add(intersection, chan);
}
while ((chan = strsep(&str2_dup, ","))) {
RAII_VAR(char *, ao2_chan, ao2_find(intersection, chan, OBJ_SEARCH_KEY), ao2_cleanup);
/* item in str2 not in str1 */
if (!ao2_chan) {
return 0;
}
ast_str_container_remove(intersection, chan);
}
/* item in str1 not in str2 */
if (ao2_container_count(intersection)) {
return 0;
}
return 1;
}
/*!
* \brief Check an IE value from two events
*
* \retval zero if the IEs in the events of the specified type do not match
* \retval non-zero if the IEs in the events of the specified type match
*/
static int match_ie_val( static int match_ie_val(
const struct ast_event *event1, const struct ast_event *event1,
const struct ast_event *event2, const struct ast_event *event2,
@@ -1655,6 +1792,15 @@ static int match_ie_val(
{ {
enum ast_event_ie_pltype pltype = ast_event_get_ie_pltype(type); enum ast_event_ie_pltype pltype = ast_event_get_ie_pltype(type);
/* XXX ignore sec/usec for now */
if (type == AST_EVENT_IE_CEL_EVENT_TIME_USEC) {
return 1;
}
if (type == AST_EVENT_IE_CEL_EVENT_TIME) {
return 1;
}
switch (pltype) { switch (pltype) {
case AST_EVENT_IE_PLTYPE_UINT: case AST_EVENT_IE_PLTYPE_UINT:
{ {
@@ -1664,20 +1810,23 @@ static int match_ie_val(
} }
case AST_EVENT_IE_PLTYPE_STR: case AST_EVENT_IE_PLTYPE_STR:
{ {
const char *str; const char *str1 = ast_event_get_ie_str(event1, type);
const char *str2 = ast_event_get_ie_str(event2, type);
str = ast_event_get_ie_str(event2, type); if (!str1 && !str2) {
if (str) {
const char *e1str, *e2str;
e1str = ast_event_get_ie_str(event1, type);
e2str = str;
if (!strcmp(e1str, e2str)) {
return 1; return 1;
} } else if (!str1) {
return 0;
} else if (!str2) {
return 0;
} }
return 0; /* use special matching for CEL PEER field */
if (type == AST_EVENT_IE_CEL_PEER) {
return test_cel_peer_strings_match(str1, str2);
}
return !strcmp(str1, str2);
} }
default: default:
break; break;
@@ -1696,11 +1845,8 @@ static int events_are_equal(struct ast_test *test, struct ast_event *received, s
} }
for (res = ast_event_iterator_init(&iterator, received); !res; res = ast_event_iterator_next(&iterator)) { for (res = ast_event_iterator_init(&iterator, received); !res; res = ast_event_iterator_next(&iterator)) {
/* XXX ignore sec/usec for now */
int ie_type = ast_event_iterator_get_ie_type(&iterator); int ie_type = ast_event_iterator_get_ie_type(&iterator);
if (ie_type != AST_EVENT_IE_CEL_EVENT_TIME_USEC if (!match_ie_val(received, expected, ie_type)) {
&& ie_type != AST_EVENT_IE_CEL_EVENT_TIME
&& !match_ie_val(received, expected, ie_type)) {
ast_test_status_update(test, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type)); ast_test_status_update(test, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type));
return 0; return 0;
} }