diff options
author | Kinsey Moore <kmoore@digium.com> | 2012-07-20 15:48:55 +0000 |
---|---|---|
committer | Kinsey Moore <kmoore@digium.com> | 2012-07-20 15:48:55 +0000 |
commit | cb9756daa2042d6e5b91290def004b0f0c9eb168 (patch) | |
tree | 9ea585c25213ade435c83c95a055082f1e291f2a /main | |
parent | 499a445af213b1cbce99db9219f041ef053fbc18 (diff) |
Add hangupcause translation support
The HANGUPCAUSE hash (trunk only) meant to replace SIP_CAUSE has now
been replaced with the HANGUPCAUSE and HANGUPCAUSE_KEYS dialplan
functions to better facilitate access to the AST_CAUSE translations
for technology-specific cause codes. The HangupCauseClear application
has also been added to remove this data from the channel.
(closes issue SWP-4738)
Review: https://reviewboard.asterisk.org/r/2025/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370316 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r-- | main/channel.c | 12 | ||||
-rw-r--r-- | main/channel_internal_api.c | 77 | ||||
-rw-r--r-- | main/rtp_engine.c | 4 |
3 files changed, 86 insertions, 7 deletions
diff --git a/main/channel.c b/main/channel.c index 6b4f8b721..f2660e1fd 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4298,12 +4298,14 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con return 0; } -void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code) +void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen) { char causevar[256]; - snprintf(causevar, sizeof(causevar), "HASH(HANGUPCAUSE,%s)", cause_code->chan_name); - ast_func_write(chan, causevar, cause_code->code); + if (ast_channel_dialed_causes_add(chan, cause_code, datalen)) { + ast_log(LOG_WARNING, "Unable to store hangup cause for %s on %s\n", cause_code->chan_name, ast_channel_name(chan)); + } + if (cause_code->emulate_sip_cause) { snprintf(causevar, sizeof(causevar), "HASH(SIP_CAUSE,%s)", cause_code->chan_name); ast_func_write(chan, causevar, cause_code->code); @@ -4455,7 +4457,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ts = ast_get_indication_tone(ast_channel_zone(chan), "congestion"); break; case AST_CONTROL_PVT_CAUSE_CODE: - ast_channel_hangupcause_hash_set(chan, data); + ast_channel_hangupcause_hash_set(chan, data, datalen); res = 0; break; case AST_CONTROL_PROGRESS: @@ -5602,7 +5604,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c break; case AST_CONTROL_PVT_CAUSE_CODE: - ast_channel_hangupcause_hash_set(chan, f->data.ptr); + ast_channel_hangupcause_hash_set(chan, f->data.ptr, f->datalen); break; /* Ignore these */ diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index a9dea31cc..b659fb9b6 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -88,6 +88,7 @@ struct ast_channel { #ifdef HAVE_EPOLL struct ast_epoll_data *epfd_data[AST_MAX_FDS]; #endif + struct ao2_container *dialed_causes; /*!< Contains tech-specific and Asterisk cause data from dialed channels */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(name); /*!< ASCII unique channel name */ @@ -1197,6 +1198,72 @@ struct ast_flags *ast_channel_flags(struct ast_channel *chan) return &chan->flags; } +static int collect_names_cb(void *obj, void *arg, int flags) { + struct ast_control_pvt_cause_code *cause_code = obj; + struct ast_str **str = arg; + + ast_str_append(str, 0, "%s%s", (ast_str_strlen(*str) ? "," : ""), cause_code->chan_name); + + return 0; +} + +struct ast_str *ast_channel_dialed_causes_channels(const struct ast_channel *chan) +{ + struct ast_str *chanlist = ast_str_create(128); + + if (!chanlist) { + return NULL; + } + + ao2_callback(chan->dialed_causes, 0, collect_names_cb, &chanlist); + + return chanlist; +} + +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); +} + +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); + + 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; + } +} + +void ast_channel_dialed_causes_clear(const struct ast_channel *chan) +{ + ao2_callback(chan->dialed_causes, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); +} + +/* \brief Hash function for pvt cause code frames */ +static int pvt_cause_hash_fn(const void *vpc, const int flags) +{ + const struct ast_control_pvt_cause_code *pc = vpc; + return ast_str_hash(ast_tech_to_upper(ast_strdupa(pc->chan_name))); +} + +/* \brief Comparison function for pvt cause code frames */ +static int pvt_cause_cmp_fn(void *obj, void *vstr, int flags) +{ + struct ast_control_pvt_cause_code *pc = obj; + char *str = ast_tech_to_upper(ast_strdupa(vstr)); + char *pc_str = ast_tech_to_upper(ast_strdupa(pc->chan_name)); + return !strcmp(pc_str, str) ? CMP_MATCH | CMP_STOP : 0; +} + +#define DIALED_CAUSES_BUCKETS 37 + struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *file, int line, const char *function) { struct ast_channel *tmp; @@ -1214,11 +1281,21 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), return ast_channel_unref(tmp); } + if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) { + return ast_channel_unref(tmp); + } + return tmp; } void ast_channel_internal_cleanup(struct ast_channel *chan) { + if (chan->dialed_causes) { + ao2_t_ref(chan->dialed_causes, -1, + "done with dialed causes since the channel is going away"); + chan->dialed_causes = NULL; + } + ast_string_field_free_memory(chan); } diff --git a/main/rtp_engine.c b/main/rtp_engine.c index a8851e887..68cdfd306 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -933,7 +933,7 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { - ast_channel_hangupcause_hash_set(other, fr->data.ptr); + ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen); ast_frfree(fr); } else { *fo = fr; @@ -1227,7 +1227,7 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { - ast_channel_hangupcause_hash_set(other, fr->data.ptr); + ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen); ast_frfree(fr); } else { *fo = fr; |