func_hangupcause.c: Add access to Reason headers via HANGUPCAUSE()

As soon as SIP call may end with several Reason headers, we
want to make all of them available through the HAGUPCAUSE() function.
This implementation uses the same ao2 hash for cause codes storage
and adds a flag to make difference between last processed sip
message and content of reason headers.

UserNote: Added a new option to HANGUPCAUSE to access additional
information about hangup reason. Reason headers from pjsip
could be read using 'tech_extended' cause type.
This commit is contained in:
Igor Goncharovsky
2025-09-04 10:54:27 +06:00
parent 129f90e3db
commit 4f45f21b71
5 changed files with 125 additions and 15 deletions

View File

@@ -1145,23 +1145,68 @@ struct ast_str *ast_channel_dialed_causes_channels(const struct ast_channel *cha
struct ast_control_pvt_cause_code *ast_channel_dialed_causes_find(const struct ast_channel *chan, const char *chan_name)
{
return ao2_find(chan->dialed_causes, chan_name, OBJ_KEY);
struct ao2_iterator causes;
struct ast_control_pvt_cause_code *cause_code;
causes = ao2_iterator_init(chan->dialed_causes, 0);
while ((cause_code = ao2_iterator_next(&causes))) {
if (strcmp(cause_code->chan_name, chan_name)) {
ao2_ref(cause_code, -1);
continue;
}
if (!cause_code->cause_extended) {
ao2_iterator_destroy(&causes);
return cause_code;
}
ao2_ref(cause_code, -1);
}
ao2_iterator_destroy(&causes);
return NULL;
}
struct ao2_iterator *ast_channel_dialed_causes_find_multiple(const struct ast_channel *chan, const char *chan_name)
{
struct ao2_iterator *causes;
struct ast_control_pvt_cause_code *cause_code;
causes = ao2_find(chan->dialed_causes, chan_name, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
while ((cause_code = ao2_iterator_next(causes))) {
ao2_ref(cause_code, -1);
}
ao2_iterator_destroy(causes);
return ao2_find(chan->dialed_causes, chan_name, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
}
static int remove_dialstatus_cb(void *obj, void *arg, int flags)
{
struct ast_control_pvt_cause_code *cause_code = obj;
char *str = ast_tech_to_upper(ast_strdupa(arg));
char *pc_str = ast_tech_to_upper(ast_strdupa(cause_code->chan_name));
if (cause_code->cause_extended) {
return 0;
}
return !strcmp(pc_str, str) ? CMP_MATCH | CMP_STOP : 0;
}
int ast_channel_dialed_causes_add(const struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen)
{
struct ast_control_pvt_cause_code *ao2_cause_code;
ao2_find(chan->dialed_causes, cause_code->chan_name, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA);
ao2_cause_code = ao2_alloc(datalen, NULL);
char *arg = ast_strdupa(cause_code->chan_name);
ao2_callback(chan->dialed_causes, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, remove_dialstatus_cb, arg);
ao2_cause_code = ao2_alloc(datalen, NULL);
if (ao2_cause_code) {
memcpy(ao2_cause_code, cause_code, datalen);
ao2_link(chan->dialed_causes, ao2_cause_code);
ao2_ref(ao2_cause_code, -1);
return 0;
} else {
return -1;
}
return -1;
}
void ast_channel_dialed_causes_clear(const struct ast_channel *chan)