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 83b9f2055d
commit cd41d461bd
5 changed files with 125 additions and 15 deletions

View File

@@ -55,6 +55,7 @@
<para>Parameter describing which type of information is requested. Types are:</para>
<enumlist>
<enum name="tech"><para>Technology-specific cause information</para></enum>
<enum name="tech_extended"><para>Technology-specific extended list of cause information</para></enum>
<enum name="ast"><para>Translated Asterisk cause code</para></enum>
</enumlist>
</parameter>
@@ -119,9 +120,10 @@ static int hangupcause_read(struct ast_channel *chan, const char *cmd, char *dat
char *parms;
struct ast_control_pvt_cause_code *cause_code;
int res = 0;
struct ast_str *causelist;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(channel); /*!< Channel name */
AST_APP_ARG(type); /*!< Type of information requested (ast or tech) */
AST_APP_ARG(type); /*!< Type of information requested (ast, tech or tech_extended) */
);
/* Ensure that the buffer is empty */
@@ -139,25 +141,49 @@ static int hangupcause_read(struct ast_channel *chan, const char *cmd, char *dat
return -1;
}
ast_channel_lock(chan);
cause_code = ast_channel_dialed_causes_find(chan, args.channel);
ast_channel_unlock(chan);
if (!cause_code) {
ast_log(LOG_WARNING, "Unable to find information for channel %s\n", args.channel);
causelist = ast_str_create(128);
if (!causelist) {
ast_log(LOG_ERROR, "Unable to allocate buffer, cause information will be unavailable!\n");
return -1;
}
ast_channel_lock(chan);
if (!strcmp(args.type, "tech_extended")) {
struct ao2_iterator *cause_codes;
cause_codes = ast_channel_dialed_causes_find_multiple(chan, args.channel);
while ((cause_code = ao2_iterator_next(cause_codes))) {
if (!cause_code->cause_extended) {
ao2_ref(cause_code, -1);
continue;
}
ast_str_append(&causelist, 0, "%s%s", (ast_str_strlen(causelist) ? "," : ""), cause_code->code);
ao2_ref(cause_code, -1);
}
ao2_iterator_destroy(cause_codes);
} else {
cause_code = ast_channel_dialed_causes_find(chan, args.channel);
if (!cause_code) {
ast_log(LOG_WARNING, "Unable to find information for channel '%s'\n", args.channel);
ast_channel_unlock(chan);
return -1;
}
}
ast_channel_unlock(chan);
if (!strcmp(args.type, "ast")) {
ast_copy_string(buf, ast_cause2str(cause_code->ast_cause), len);
} else if (!strcmp(args.type, "tech")) {
ast_copy_string(buf, cause_code->code, len);
} else if (!strcmp(args.type, "tech_extended")) {
ast_copy_string(buf, ast_str_buffer(causelist), len);
} else {
ast_log(LOG_WARNING, "Information type not recognized (%s)\n", args.type);
res = -1;
}
ao2_ref(cause_code, -1);
if (cause_code) {
ao2_cleanup(cause_code);
}
return res;
}