[asterisk-commits] kmoore: trunk r370316 - in /trunk: ./ channels/ funcs/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jul 20 10:49:00 CDT 2012


Author: kmoore
Date: Fri Jul 20 10:48:55 2012
New Revision: 370316

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=370316
Log:
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/

Added:
    trunk/funcs/func_hangupcause.c   (with props)
Modified:
    trunk/UPGRADE.txt
    trunk/channels/chan_dahdi.c
    trunk/channels/chan_iax2.c
    trunk/channels/chan_sip.c
    trunk/channels/sig_analog.c
    trunk/channels/sig_pri.c
    trunk/channels/sig_ss7.c
    trunk/include/asterisk/channel.h
    trunk/include/asterisk/frame.h
    trunk/main/channel.c
    trunk/main/channel_internal_api.c
    trunk/main/rtp_engine.c

Modified: trunk/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/trunk/UPGRADE.txt?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/UPGRADE.txt (original)
+++ trunk/UPGRADE.txt Fri Jul 20 10:48:55 2012
@@ -46,6 +46,10 @@
    CONNECTED_LINE_SEND_SUB, CONNECTED_LINE_SEND_SUB_ARGS.
  - The REDIRECTING function now supports the redirecting original party id
    and reason.
+ - The HANGUPCAUSE and HANGUPCAUSE_KEYS functions have been introduced to
+   provide a replacement for the SIP_CAUSE hash. The HangupCauseClear
+   application has also been introduced to remove this data from the channel
+   when necessary.
 
 
 func_enum:
@@ -105,10 +109,10 @@
    a call is terminated due to RTP stream inactivity or SIP session timer
    expiration.
  - SIP_CAUSE is now deprecated.  It has been modified to use the same
-   mechanism as HANGUPCAUSE.  Behavior should not change, but performance
-   should be vastly improved.  The HANGUPCAUSE hash should now be used instead
-   of SIP_CAUSE. Because of this, the storesipcause option in sip.conf is also
-   deprecated.
+   mechanism as the HANGUPCAUSE function.  Behavior should not change, but
+   performance should be vastly improved.  The HANGUPCAUSE function should now
+   be used instead of SIP_CAUSE. Because of this, the storesipcause option in
+   sip.conf is also deprecated.
  - The sip paramater for Originating Line Information (oli, isup-oli, and
    ss7-oli) is now parsed out of the From header and copied into the channel's
    ANI2 information field.  This is readable from the CALLERID(ani2) dialplan

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Fri Jul 20 10:48:55 2012
@@ -4182,6 +4182,7 @@
 	snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
 	datalen += strlen(cause_str);
 	cause_code = alloca(datalen);
+	cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
 	ast_copy_string(cause_code->chan_name, ast_channel_name(p->owner), AST_CHANNEL_NAME);
 	ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
 	ast_queue_control_data(p->owner, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
@@ -7640,7 +7641,7 @@
 		switch (f ? f->frametype : AST_FRAME_CONTROL) {
 		case AST_FRAME_CONTROL:
 			if (f && f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
-				ast_channel_hangupcause_hash_set((who == c0) ? c1 : c0, f->data.ptr);
+				ast_channel_hangupcause_hash_set((who == c0) ? c1 : c0, f->data.ptr, f->datalen);
 				break;
 			}
 			*fo = f;

Modified: trunk/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Fri Jul 20 10:48:55 2012
@@ -5653,7 +5653,7 @@
 		other = (who == c0) ? c1 : c0;  /* the 'other' channel */
 		if ((f->frametype == AST_FRAME_CONTROL)) {
 			if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
-				ast_channel_hangupcause_hash_set(other, f->data.ptr);
+				ast_channel_hangupcause_hash_set(other, f->data.ptr, f->datalen);
 			} else if (!(flags & AST_BRIDGE_IGNORE_SIGS)
 				&& (f->subclass.integer != AST_CONTROL_SRCUPDATE)) {
 				*fo = f;
@@ -10239,6 +10239,7 @@
 		cause_code = alloca(data_size);
 		ast_copy_string(cause_code->chan_name, ast_channel_name(iaxs[fr->callno]->owner), AST_CHANNEL_NAME);
 
+		cause_code->ast_cause = ies.causecode;
 		snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "IAX2 %s(%d)", subclass, ies.causecode);
 
 		iax2_queue_control_data(fr->callno, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Fri Jul 20 10:48:55 2012
@@ -27004,6 +27004,7 @@
 
 				snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %s", REQ_OFFSET_TO_STR(req, rlPart2));
 
+				cause_code->ast_cause = hangup_sip2cause(respid);
 				if (global_store_sip_cause) {
 					cause_code->emulate_sip_cause = 1;
 				}

Modified: trunk/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_analog.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/sig_analog.c (original)
+++ trunk/channels/sig_analog.c Fri Jul 20 10:48:55 2012
@@ -2735,6 +2735,7 @@
 		subclass = analog_event2str(res);
 		data_size += strlen(subclass);
 		cause_code = alloca(data_size);
+		cause_code->ast_cause = AST_CAUSE_NORMAL_CLEARING;
 		ast_copy_string(cause_code->chan_name, ast_channel_name(ast), AST_CHANNEL_NAME);
 		snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "ANALOG %s", subclass);
 		break;
@@ -2826,6 +2827,7 @@
 	case ANALOG_EVENT_ALARM:
 		analog_set_alarm(p, 1);
 		analog_get_and_handle_alarms(p);
+		cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
 	case ANALOG_EVENT_ONHOOK:
 		ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
 		switch (p->sig) {

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Fri Jul 20 10:48:55 2012
@@ -1277,7 +1277,7 @@
  *
  * \return Nothing
  */
-static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause)
+static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause, int ast_cause)
 {
 	struct ast_channel *chan;
 	struct ast_control_pvt_cause_code *cause_code;
@@ -1287,6 +1287,7 @@
 	if (chan) {
 		int datalen = sizeof(*cause_code) + strlen(cause);
 		cause_code = alloca(datalen);
+		cause_code->ast_cause = ast_cause;
 		ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
 		ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
 		ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
@@ -6638,7 +6639,7 @@
 				if (e->proceeding.cause > -1) {
 					if (pri->pvts[chanpos]->owner) {
 						snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_PROGRESS (%d)", e->proceeding.cause);
-						pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+						pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->proceeding.cause);
 					}
 
 					ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
@@ -6944,7 +6945,7 @@
 						int do_hangup = 0;
 
 						snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
-						pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+						pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
 
 						/* Queue a BUSY instead of a hangup if our cause is appropriate */
 						ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
@@ -7099,7 +7100,7 @@
 					int do_hangup = 0;
 
 					snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
-					pri_queue_pvt_cause_data(pri, chanpos, cause_str);
+					pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
 
 					ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
 					switch (ast_channel_state(pri->pvts[chanpos]->owner)) {

Modified: trunk/channels/sig_ss7.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_ss7.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/channels/sig_ss7.c (original)
+++ trunk/channels/sig_ss7.c Fri Jul 20 10:48:55 2012
@@ -384,12 +384,13 @@
  *
  * \return Nothing
  */
-static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *cause)
+static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *cause, int ast_cause)
 {
 	struct ast_control_pvt_cause_code *cause_code;
 	int datalen = sizeof(*cause_code) + strlen(cause);
 
 	cause_code = alloca(datalen);
+	cause_code->ast_cause = ast_cause;
 	ast_copy_string(cause_code->chan_name, ast_channel_name(owner), AST_CHANNEL_NAME);
 	ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
 	ast_queue_control_data(owner, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
@@ -915,7 +916,7 @@
 				sig_ss7_lock_owner(linkset, chanpos);
 				p->ss7call = NULL;
 				if (p->owner) {
-					ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_RSC");
+					ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_RSC", AST_CAUSE_INTERWORKING);
 					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
 					ast_channel_unlock(p->owner);
 				}
@@ -973,7 +974,7 @@
 					}
 					p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
 					if (p->owner) {
-						ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_IAM (glare)");
+						ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_IAM (glare)", AST_CAUSE_NORMAL_CLEARING);
 						ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
 						ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
 						ast_channel_unlock(p->owner);
@@ -1119,7 +1120,7 @@
 				sig_ss7_lock_owner(linkset, chanpos);
 				if (p->owner) {
 					snprintf(cause_str, sizeof(cause_str), "SS7 ISUP_EVENT_REL (%d)", e->rel.cause);
-					ss7_queue_pvt_cause_data(p->owner, cause_str);
+					ss7_queue_pvt_cause_data(p->owner, cause_str, e->rel.cause);
 
 					ast_channel_hangupcause_set(p->owner, e->rel.cause);
 					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);

Added: trunk/funcs/func_hangupcause.c
URL: http://svnview.digium.com/svn/asterisk/trunk/funcs/func_hangupcause.c?view=auto&rev=370316
==============================================================================
--- trunk/funcs/func_hangupcause.c (added)
+++ trunk/funcs/func_hangupcause.c Fri Jul 20 10:48:55 2012
@@ -1,0 +1,258 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999-2012, Digium, Inc.
+ *
+ * Kinsey Moore <kmoore at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Functions related to retreiving per-channel hangupcause information
+ *
+ * \author Kinsey Moore <kmoore at digium.com>
+ * \ingroup functions
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+
+/*** DOCUMENTATION
+	<function name="HANGUPCAUSE" language="en_US">
+		<synopsis>
+			Gets per-channel hangupcause information from the channel.
+		</synopsis>
+		<syntax>
+			<parameter name="channel" required="true">
+				<para>The name of the channel for which to retreive cause information.</para>
+			</parameter>
+			<parameter name="type" required="true">
+				<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="ast"><para>Translated Asterisk cause code</para></enum>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Gets technology-specific or translated Asterisk cause code information
+			from the channel for the specified channel that resulted from a dial.</para>
+		</description>
+		<see-also>
+			<ref type="function">HANGUPCAUSE_KEYS</ref>
+			<ref type="application">HangupCauseClear</ref>
+		</see-also>
+	</function>
+	<function name="HANGUPCAUSE_KEYS" language="en_US">
+		<synopsis>
+			Gets the list of channels for which hangup causes are available.
+		</synopsis>
+		<description>
+			<para>Returns a comma-separated list of channel names to be used with the HANGUPCAUSE function.</para>
+		</description>
+		<see-also>
+			<ref type="function">HANGUPCAUSE</ref>
+			<ref type="application">HangupCauseClear</ref>
+		</see-also>
+	</function>
+	<application name="HangupCauseClear" language="en_US">
+		<synopsis>
+			Clears hangup cause information from the channel that is available through HANGUPCAUSE.
+		</synopsis>
+		<description>
+			<para>Clears all channel-specific hangup cause information from the channel.
+			This is never done automatically (i.e. for new Dial()s).</para>
+		</description>
+		<see-also>
+			<ref type="function">HANGUPCAUSE</ref>
+			<ref type="function">HANGUPCAUSE_KEYS</ref>
+		</see-also>
+	</application>
+ ***/
+
+/*!
+ * \internal
+ * \brief Read values from the hangupcause ao2 container.
+ *
+ * \param chan Asterisk channel to read
+ * \param cmd Not used
+ * \param data HANGUPCAUSE function argument string
+ * \param buf Buffer to fill with read value.
+ * \param len Length of the buffer
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int hangupcause_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	char *parms;
+	struct ast_control_pvt_cause_code *cause_code;
+	int res = 0;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(channel);	/*!< Channel name */
+		AST_APP_ARG(type);	/*!< Type of information requested (ast or tech) */
+		);
+
+	/* Ensure that the buffer is empty */
+	*buf = 0;
+
+	if (!chan) {
+		return -1;
+	}
+
+	parms = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parms);
+	if (args.argc != 2) {
+		/* Must have two arguments. */
+		ast_log(LOG_WARNING, "The HANGUPCAUSE function must have 2 parameters, not %d\n", args.argc);
+		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);
+		return -1;
+	}
+
+	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 {
+		ast_log(LOG_WARNING, "Information type not recognized (%s)\n", args.type);
+		res = -1;
+	}
+
+	ao2_ref(cause_code, -1);
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Read keys from the hangupcause ao2 container.
+ *
+ * \param chan Asterisk channel to read
+ * \param cmd Not used
+ * \param data HANGUPCAUSE_KEYS function argument string
+ * \param buf Buffer to fill with read value.
+ * \param len Length of the buffer
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int hangupcause_keys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	struct ast_str *chanlist;
+
+	/* Ensure that the buffer is empty */
+	*buf = 0;
+
+	if (!chan) {
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	chanlist = ast_channel_dialed_causes_channels(chan);
+	ast_channel_unlock(chan);
+
+	if (chanlist && ast_str_strlen(chanlist)) {
+		ast_copy_string(buf, ast_str_buffer(chanlist), len);
+	}
+
+	ast_free(chanlist);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Remove all keys from the hangupcause ao2 container.
+ *
+ * \param chan Asterisk channel to read
+ * \param data Not used
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int hangupcause_clear_exec(struct ast_channel *chan, const char *data) {
+	ast_channel_lock(chan);
+	ast_channel_dialed_causes_clear(chan);
+	ast_channel_unlock(chan);
+	return 0;
+}
+
+static struct ast_custom_function hangupcause_function = {
+	.name = "HANGUPCAUSE",
+	.read = hangupcause_read,
+};
+
+static struct ast_custom_function hangupcause_keys_function = {
+	.name = "HANGUPCAUSE_KEYS",
+	.read = hangupcause_keys_read,
+};
+
+static const char app[] = "HangupcauseClear";
+
+/*!
+ * \internal
+ * \brief Unload the function module
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int unload_module(void)
+{
+	int res;
+
+	res = ast_custom_function_unregister(&hangupcause_function);
+	res |= ast_custom_function_unregister(&hangupcause_keys_function);
+	res |= ast_unregister_application(app);
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Load and initialize the function module.
+ *
+ * \retval AST_MODULE_LOAD_SUCCESS on success.
+ * \retval AST_MODULE_LOAD_DECLINE on error.
+ */
+static int load_module(void)
+{
+	int res;
+
+	res = ast_custom_function_register(&hangupcause_function);
+	res |= ast_custom_function_register(&hangupcause_keys_function);
+	res |= ast_register_application_xml(app, hangupcause_clear_exec);
+	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
+}
+
+/* Do not wrap the following line. */
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "HANGUPCAUSE related functions and applications");

Propchange: trunk/funcs/func_hangupcause.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/funcs/func_hangupcause.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: trunk/funcs/func_hangupcause.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Fri Jul 20 10:48:55 2012
@@ -3592,8 +3592,9 @@
  *
  * \param chan channel on which to set the cause information
  * \param cause_code ast_control_pvt_cause_code structure containing cause information
- */
-void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code);
+ * \param datalen total length of the structure since it may vary
+ */
+void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen);
 
 /* ACCESSOR FUNTIONS */
 /*! \brief Set the channel name */
@@ -3825,5 +3826,66 @@
 struct ast_channel *ast_channel_internal_bridged_channel(const struct ast_channel *chan);
 void ast_channel_internal_bridged_channel_set(struct ast_channel *chan, struct ast_channel *value);
 
+/*!
+ * \since 11
+ * \brief Retreive a comma-separated list of channels for which dialed cause information is available
+ *
+ * \details
+ * This function makes use of datastore operations on the channel, so
+ * it is important to lock the channel before calling this function.
+ *
+ * \param chan The channel from which to retreive information
+ * \retval NULL on allocation failure
+ * \retval Pointer to an ast_str object containing the desired information which must be freed
+ */
+struct ast_str *ast_channel_dialed_causes_channels(const struct ast_channel *chan);
+
+/*!
+ * \since 11
+ * \brief Retreive a ref-counted cause code information structure
+ *
+ * \details
+ * This function makes use of datastore operations on the channel, so
+ * it is important to lock the channel before calling this function.
+ * This function increases the ref count of the returned object, so the
+ * calling function must decrease the reference count when it is finished
+ * with the object.
+ *
+ * \param chan The channel from which to retreive information
+ * \param chan_name The name of the channel about which to retreive information
+ * \retval NULL on search failure
+ * \retval Pointer to a ref-counted ast_control_pvt_cause_code object containing the desired information
+ */
+struct ast_control_pvt_cause_code *ast_channel_dialed_causes_find(const struct ast_channel *chan, const char *chan_name);
+
+/*!
+ * \since 11
+ * \brief Add cause code information to the channel
+ *
+ * \details
+ * This function makes use of datastore operations on the channel, so
+ * it is important to lock the channel before calling this function.
+ * The passed in data is copied and so is still owned by the caller.
+ *
+ * \param chan The channel on which to add information
+ * \param cause_code The cause information to be added to the channel
+ * \param datalen The total length of the structure since its length is variable
+ * \retval 0 on success
+ * \retval -1 on error
+ */
+int ast_channel_dialed_causes_add(const struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen);
+
+/*!
+ * \since 11
+ * \brief Clear all cause information from the channel
+ *
+ * \details
+ * This function makes use of datastore operations on the channel, so
+ * it is important to lock the channel before calling this function.
+ *
+ * \param chan The channel from which to clear information
+ */
+void ast_channel_dialed_causes_clear(const struct ast_channel *chan);
+
 struct ast_flags *ast_channel_flags(struct ast_channel *chan);
 #endif /* _ASTERISK_CHANNEL_H */

Modified: trunk/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/frame.h?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/include/asterisk/frame.h (original)
+++ trunk/include/asterisk/frame.h Fri Jul 20 10:48:55 2012
@@ -327,7 +327,8 @@
 
 struct ast_control_pvt_cause_code {
 	char chan_name[AST_CHANNEL_NAME];	/*!< Name of the channel that originated the cause information */
-	unsigned int emulate_sip_cause:1;		/*!< Indicates whether this should be used to emulate SIP_CAUSE support */
+	unsigned int emulate_sip_cause:1;	/*!< Indicates whether this should be used to emulate SIP_CAUSE support */
+	int ast_cause;				/*!< Asterisk cause code associated with this message */
 	char code[1];				/*!< Tech-specific cause code information, beginning with the name of the tech */
 };
 

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Fri Jul 20 10:48:55 2012
@@ -4298,12 +4298,14 @@
 	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 @@
 		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 @@
 					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 */

Modified: trunk/main/channel_internal_api.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel_internal_api.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/main/channel_internal_api.c (original)
+++ trunk/main/channel_internal_api.c Fri Jul 20 10:48:55 2012
@@ -88,6 +88,7 @@
 #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 @@
 	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 @@
 		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);
 }
 

Modified: trunk/main/rtp_engine.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/rtp_engine.c?view=diff&rev=370316&r1=370315&r2=370316
==============================================================================
--- trunk/main/rtp_engine.c (original)
+++ trunk/main/rtp_engine.c Fri Jul 20 10:48:55 2012
@@ -933,7 +933,7 @@
 				}
 				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 @@
 				}
 				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;




More information about the asterisk-commits mailing list