mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 19:28:53 +00:00
Merge "cel: Ensure only one dial status per channel exists."
This commit is contained in:
112
main/cel.c
112
main/cel.c
@@ -171,6 +171,13 @@ struct cel_linkedid {
|
|||||||
/*! Container of channel references to a linkedid for CEL purposes. */
|
/*! Container of channel references to a linkedid for CEL purposes. */
|
||||||
static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
|
static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
|
||||||
|
|
||||||
|
struct cel_dialstatus {
|
||||||
|
/*! Uniqueid of the channel */
|
||||||
|
char uniqueid[AST_MAX_UNIQUEID];
|
||||||
|
/*! The dial status */
|
||||||
|
char dialstatus[0];
|
||||||
|
};
|
||||||
|
|
||||||
/*! \brief Destructor for cel_config */
|
/*! \brief Destructor for cel_config */
|
||||||
static void cel_general_config_dtor(void *obj)
|
static void cel_general_config_dtor(void *obj)
|
||||||
{
|
{
|
||||||
@@ -373,20 +380,10 @@ static int cel_backend_cmp(void *obj, void *arg, int flags)
|
|||||||
return CMP_MATCH;
|
return CMP_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
|
||||||
if (!caller) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return caller->uniqueid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Hashing function for dialstatus container */
|
/*! \brief Hashing function for dialstatus container */
|
||||||
static int dialstatus_hash(const void *obj, int flags)
|
static int dialstatus_hash(const void *obj, int flags)
|
||||||
{
|
{
|
||||||
struct ast_multi_channel_blob *blob;
|
const struct cel_dialstatus *dialstatus;
|
||||||
const char *key;
|
const char *key;
|
||||||
|
|
||||||
switch (flags & OBJ_SEARCH_MASK) {
|
switch (flags & OBJ_SEARCH_MASK) {
|
||||||
@@ -394,8 +391,8 @@ static int dialstatus_hash(const void *obj, int flags)
|
|||||||
key = obj;
|
key = obj;
|
||||||
break;
|
break;
|
||||||
case OBJ_SEARCH_OBJECT:
|
case OBJ_SEARCH_OBJECT:
|
||||||
blob = (void *) obj;
|
dialstatus = obj;
|
||||||
key = get_caller_uniqueid(blob);
|
key = dialstatus->uniqueid;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Hash can only work on something with a full key. */
|
/* Hash can only work on something with a full key. */
|
||||||
@@ -408,24 +405,24 @@ static int dialstatus_hash(const void *obj, int flags)
|
|||||||
/*! \brief Comparator function for dialstatus container */
|
/*! \brief Comparator function for dialstatus container */
|
||||||
static int dialstatus_cmp(void *obj, void *arg, int flags)
|
static int dialstatus_cmp(void *obj, void *arg, int flags)
|
||||||
{
|
{
|
||||||
struct ast_multi_channel_blob *object_left = obj;
|
struct cel_dialstatus *object_left = obj;
|
||||||
struct ast_multi_channel_blob *object_right = arg;
|
struct cel_dialstatus *object_right = arg;
|
||||||
const char *right_key = arg;
|
const char *right_key = arg;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
switch (flags & OBJ_SEARCH_MASK) {
|
switch (flags & OBJ_SEARCH_MASK) {
|
||||||
case OBJ_SEARCH_OBJECT:
|
case OBJ_SEARCH_OBJECT:
|
||||||
right_key = get_caller_uniqueid(object_right);
|
right_key = object_right->uniqueid;
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case OBJ_SEARCH_KEY:
|
case OBJ_SEARCH_KEY:
|
||||||
cmp = strcmp(get_caller_uniqueid(object_left), right_key);
|
cmp = strcmp(object_left->uniqueid, right_key);
|
||||||
break;
|
break;
|
||||||
case OBJ_SEARCH_PARTIAL_KEY:
|
case OBJ_SEARCH_PARTIAL_KEY:
|
||||||
/*
|
/*
|
||||||
* We could also use a partial key struct containing a length
|
* We could also use a partial key struct containing a length
|
||||||
* so strlen() does not get called for every comparison instead.
|
* so strlen() does not get called for every comparison instead.
|
||||||
*/
|
*/
|
||||||
cmp = strncmp(get_caller_uniqueid(object_left), right_key, strlen(right_key));
|
cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
@@ -959,16 +956,16 @@ typedef void (*cel_channel_snapshot_monitor)(
|
|||||||
struct ast_channel_snapshot *old_snapshot,
|
struct ast_channel_snapshot *old_snapshot,
|
||||||
struct ast_channel_snapshot *new_snapshot);
|
struct ast_channel_snapshot *new_snapshot);
|
||||||
|
|
||||||
static struct ast_multi_channel_blob *get_dialstatus_blob(const char *uniqueid)
|
static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
|
||||||
{
|
{
|
||||||
struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
|
struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
|
||||||
struct ast_multi_channel_blob *blob = NULL;
|
struct cel_dialstatus *dialstatus = NULL;
|
||||||
|
|
||||||
if (dial_statuses) {
|
if (dial_statuses) {
|
||||||
blob = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
|
dialstatus = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
|
||||||
ao2_ref(dial_statuses, -1);
|
ao2_ref(dial_statuses, -1);
|
||||||
}
|
}
|
||||||
return blob;
|
return dialstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
|
static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
|
||||||
@@ -1011,19 +1008,15 @@ static void cel_channel_state_change(
|
|||||||
|
|
||||||
if (!was_hungup && is_hungup) {
|
if (!was_hungup && is_hungup) {
|
||||||
struct ast_json *extra;
|
struct ast_json *extra;
|
||||||
struct ast_multi_channel_blob *blob = get_dialstatus_blob(new_snapshot->uniqueid);
|
struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->uniqueid);
|
||||||
const char *dialstatus = "";
|
|
||||||
|
|
||||||
if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
|
|
||||||
dialstatus = get_blob_variable(blob, "dialstatus");
|
|
||||||
}
|
|
||||||
extra = ast_json_pack("{s: i, s: s, s: s}",
|
extra = ast_json_pack("{s: i, s: s, s: s}",
|
||||||
"hangupcause", new_snapshot->hangupcause,
|
"hangupcause", new_snapshot->hangupcause,
|
||||||
"hangupsource", new_snapshot->hangupsource,
|
"hangupsource", new_snapshot->hangupsource,
|
||||||
"dialstatus", dialstatus);
|
"dialstatus", dialstatus ? dialstatus->dialstatus : "");
|
||||||
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
|
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
|
||||||
ast_json_unref(extra);
|
ast_json_unref(extra);
|
||||||
ao2_cleanup(blob);
|
ao2_cleanup(dialstatus);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,16 +1248,48 @@ static void cel_parking_cb(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_dialstatus(struct ast_multi_channel_blob *blob)
|
static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot)
|
||||||
{
|
{
|
||||||
struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
|
struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
|
||||||
|
const char *dialstatus_string = get_blob_variable(blob, "dialstatus");
|
||||||
|
struct cel_dialstatus *dialstatus;
|
||||||
|
size_t dialstatus_string_len;
|
||||||
|
|
||||||
ast_assert(blob != NULL);
|
if (!dial_statuses || ast_strlen_zero(dialstatus_string)) {
|
||||||
|
ao2_cleanup(dial_statuses);
|
||||||
if (dial_statuses) {
|
return;
|
||||||
ao2_link(dial_statuses, blob);
|
|
||||||
ao2_ref(dial_statuses, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialstatus = ao2_find(dial_statuses, snapshot->uniqueid, OBJ_SEARCH_KEY);
|
||||||
|
if (dialstatus) {
|
||||||
|
if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
|
||||||
|
/* In the case of an answer after we already have a dial status we give
|
||||||
|
* priority to the answer since the call was, well, answered. In the case of
|
||||||
|
* failure dial status results we simply let the first failure be the status.
|
||||||
|
*/
|
||||||
|
ao2_unlink(dial_statuses, dialstatus);
|
||||||
|
ao2_ref(dialstatus, -1);
|
||||||
|
} else {
|
||||||
|
ao2_ref(dialstatus, -1);
|
||||||
|
ao2_ref(dial_statuses, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialstatus_string_len = strlen(dialstatus_string) + 1;
|
||||||
|
dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL,
|
||||||
|
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||||
|
if (!dialstatus) {
|
||||||
|
ao2_ref(dial_statuses, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_copy_string(dialstatus->uniqueid, snapshot->uniqueid, sizeof(dialstatus->uniqueid));
|
||||||
|
ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
|
||||||
|
|
||||||
|
ao2_link(dial_statuses, dialstatus);
|
||||||
|
ao2_ref(dialstatus, -1);
|
||||||
|
ao2_ref(dial_statuses, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
|
static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
|
||||||
@@ -1300,32 +1325,25 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
|
|||||||
struct stasis_message *message)
|
struct stasis_message *message)
|
||||||
{
|
{
|
||||||
struct ast_multi_channel_blob *blob = stasis_message_data(message);
|
struct ast_multi_channel_blob *blob = stasis_message_data(message);
|
||||||
|
struct ast_channel_snapshot *snapshot;
|
||||||
|
|
||||||
if (cel_filter_channel_snapshot(ast_multi_channel_blob_get_channel(blob, "caller"))) {
|
snapshot = ast_multi_channel_blob_get_channel(blob, "caller");
|
||||||
return;
|
if (!snapshot || cel_filter_channel_snapshot(snapshot)) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_caller_uniqueid(blob)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
|
if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
|
||||||
struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
|
|
||||||
struct ast_json *extra;
|
struct ast_json *extra;
|
||||||
|
|
||||||
if (!caller) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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, NULL);
|
cel_report_event(snapshot, AST_CEL_FORWARD, NULL, extra, NULL);
|
||||||
ast_json_unref(extra);
|
ast_json_unref(extra);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_valid_dialstatus(blob)) {
|
if (is_valid_dialstatus(blob)) {
|
||||||
save_dialstatus(blob);
|
save_dialstatus(blob, snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1610,7 +1610,7 @@ AST_TEST_DEFINE(test_cel_dial_pickup)
|
|||||||
|
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
|
Reference in New Issue
Block a user