[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386874 - in /team/mjordan/cdrs-of-doom:...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 29 18:12:52 CDT 2013


Author: mjordan
Date: Mon Apr 29 18:12:48 2013
New Revision: 386874

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386874
Log:
A whole lot of doxygen

Modified:
    team/mjordan/cdrs-of-doom/apps/app_dial.c
    team/mjordan/cdrs-of-doom/apps/app_queue.c
    team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c
    team/mjordan/cdrs-of-doom/channels/chan_dahdi.c
    team/mjordan/cdrs-of-doom/channels/chan_iax2.c
    team/mjordan/cdrs-of-doom/channels/chan_mgcp.c
    team/mjordan/cdrs-of-doom/channels/chan_skinny.c
    team/mjordan/cdrs-of-doom/funcs/func_cdr.c
    team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
    team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h
    team/mjordan/cdrs-of-doom/main/asterisk.c
    team/mjordan/cdrs-of-doom/main/bridging.c
    team/mjordan/cdrs-of-doom/main/cdr.c
    team/mjordan/cdrs-of-doom/main/manager.c
    team/mjordan/cdrs-of-doom/main/stasis_channels.c
    team/mjordan/cdrs-of-doom/tests/test_cdr.c

Modified: team/mjordan/cdrs-of-doom/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_dial.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_dial.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_dial.c Mon Apr 29 18:12:48 2013
@@ -56,7 +56,6 @@
 #include "asterisk/app.h"
 #include "asterisk/causes.h"
 #include "asterisk/rtp_engine.h"
-#include "asterisk/cdr.h"
 #include "asterisk/manager.h"
 #include "asterisk/privacy.h"
 #include "asterisk/stringfields.h"

Modified: team/mjordan/cdrs-of-doom/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_queue.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_queue.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_queue.c Mon Apr 29 18:12:48 2013
@@ -5436,21 +5436,6 @@
 		if (res == -1) {
 			ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
 		}
-		if (ast_cdr_isset_unanswered()) {
-			/* channel contains the name of one of the outgoing channels
-			   in its CDR; zero out this CDR to avoid a dual-posting */
-			struct callattempt *o;
-			for (o = outgoing; o; o = o->q_next) {
-				if (!o->chan) {
-					continue;
-				}
-				/* BUGBUG: this is terrible */
-				/*if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
-					ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_DISABLE);
-					break;
-				}*/
-			}
-		}
 	} else { /* peer is valid */
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the

Modified: team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c (original)
+++ team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c Mon Apr 29 18:12:48 2013
@@ -873,6 +873,10 @@
 		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
 			struct softmix_channel *sc = bridge_channel->tech_pvt;
 
+			if (!sc) {
+				continue;
+			}
+
 			/* Update the sample rate to match the bridge's native sample rate if necessary. */
 			if (update_all_rates) {
 				set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1);

Modified: team/mjordan/cdrs-of-doom/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_dahdi.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_dahdi.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_dahdi.c Mon Apr 29 18:12:48 2013
@@ -107,7 +107,6 @@
 #include "asterisk/callerid.h"
 #include "asterisk/adsi.h"
 #include "asterisk/cli.h"
-#include "asterisk/cdr.h"
 #include "asterisk/cel.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"

Modified: team/mjordan/cdrs-of-doom/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_iax2.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_iax2.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_iax2.c Mon Apr 29 18:12:48 2013
@@ -77,7 +77,6 @@
 #include "asterisk/cli.h"
 #include "asterisk/translate.h"
 #include "asterisk/md5.h"
-#include "asterisk/cdr.h"
 #include "asterisk/crypto.h"
 #include "asterisk/acl.h"
 #include "asterisk/manager.h"

Modified: team/mjordan/cdrs-of-doom/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_mgcp.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_mgcp.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_mgcp.c Mon Apr 29 18:12:48 2013
@@ -67,7 +67,6 @@
 #include "asterisk/callerid.h"
 #include "asterisk/cli.h"
 #include "asterisk/say.h"
-#include "asterisk/cdr.h"
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
 #include "asterisk/app.h"

Modified: team/mjordan/cdrs-of-doom/channels/chan_skinny.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_skinny.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_skinny.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_skinny.c Mon Apr 29 18:12:48 2013
@@ -67,7 +67,6 @@
 #include "asterisk/cli.h"
 #include "asterisk/manager.h"
 #include "asterisk/say.h"
-#include "asterisk/cdr.h"
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
 #include "asterisk/app.h"

Modified: team/mjordan/cdrs-of-doom/funcs/func_cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/funcs/func_cdr.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/funcs/func_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/funcs/func_cdr.c Mon Apr 29 18:12:48 2013
@@ -142,11 +142,6 @@
 				<optionlist>
 					<option name="f">
 						<para>Returns billsec or duration fields as floating point values.</para>
-					</option>
-					<option name="r">
-						<para>Searches the entire stack of CDRs on the channel.
-						If this option is not specified, only the most recent CDR
-						is affected by the operation.</para>
 					</option>
 					<option name="u">
 						<para>Retrieves the raw, unprocessed value.</para>
@@ -163,10 +158,6 @@
 			<literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
 			a name not on the above list, and create your own variable, whose value can be changed
 			with this function, and this variable will be stored on the CDR.</para>
-			<note><para>For setting CDR values, the <literal>r</literal> flag does not apply to
-			setting the <literal>accountcode</literal>, <literal>userfield</literal>, or
-			<literal>amaflags</literal>. These values will always be set on all CDRs that
-			have not yet been finalized.</para>
 			<para>CDRs can only be modified before the bridge between two channels is
 			torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
 			application has returned.</para></note>
@@ -189,41 +180,54 @@
 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
 		    char *buf, size_t len)
 {
+	char format_buf[128];
 	char *ret = NULL;
 	struct ast_flags flags = { 0 };
-	char temp_buf[128];
+	RAII_VAR(char *, tempbuf, ast_malloc(128), ast_free);
+	char *info;
 	AST_DECLARE_APP_ARGS(args,
 			     AST_APP_ARG(variable);
 			     AST_APP_ARG(options);
 	);
 
-	if (ast_strlen_zero(parse) || !chan)
+	if (!chan || !tempbuf) {
 		return -1;
-
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (!ast_strlen_zero(args.options))
+	}
+
+	if (ast_strlen_zero(parse)) {
+		ast_log(AST_LOG_WARNING, "FUNC_CDR requires a variable (FUNC_CDR(variable[,option]))\n)");
+		return -1;
+	}
+	info = ast_strdupa(parse);
+	AST_STANDARD_APP_ARGS(args, info);
+
+	if (!ast_strlen_zero(args.options)) {
 		ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
-
-	/*ast_cdr_getvar(cdr, args.variable, tempbuf, sizeof(temp_buf),
-		       ast_test_flag(&flags, OPT_RECURSIVE));
-
-	if (ast_test_flag(&flags, OPT_FLOAT) && (!strcasecmp("billsec", args.variable)
-			|| !strcasecmp("duration", args.variable))) {
-		char format_buf[128];
+	}
+
+	if (ast_cdr_getvar(ast_channel_name(chan), args.variable, &tempbuf, sizeof(*tempbuf))) {
+		return 0;
+	}
+
+	if (ast_test_flag(&flags, OPT_FLOAT) && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
 		sprintf(format_buf, "%lf", temp_buf);
 		strcpy(temp_buf, format_buf);
 	} else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
-		if (!strcasecmp("start") || !strcasecmp("end")
-				|| (!strcasecmp("answer"))) {
+		if (!strcasecmp("start") || !strcasecmp("end") || (!strcasecmp("answer"))) {
 
 		} else if (!strcasecmp("disposition")) {
-
+			int disposition;
+			sscanf(tempbuf, "%8d", &disposition);
+			snprintf(format_buf, sizeof(format_buf), "%s", ast_cdr_disp2str(disposition));
+			strcpy(tempbuf, format_buf);
 		} else if (!strcasecmp("amaflags")) {
-
+			int amaflags;
+			sscanf(tempbuf, "%8d", &amaflags);
+			snprintf(format_buf, sizeof(format_buf), "%s", ast_channel_amaflags2string(amaflags));
+			strcpy(tempbuf, format_buf);
 		}
 	}
-*/
+
 	ast_copy_string(buf, temp_buf, len);
 	return ret ? 0 : -1;
 }

Modified: team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/cdr.h?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/cdr.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/cdr.h Mon Apr 29 18:12:48 2013
@@ -164,24 +164,6 @@
 void ast_cdr_set_config(struct ast_cdr_config *config);
 
 /*!
- * \brief Return whether or not the CDR engine accepts unanswered CDRs
- *
- * TODO: this should probably get removed
- *
- * \retval 0 the engine will not dispatch unanswered records
- * \retval 1 the engine will dispatch unanswered records
- */
-int ast_cdr_isset_unanswered(void);
-
-/*!
- * \brief Return whether or not a channel has a CDR where it is the Party A
- *
- * \retval 0 if the channel does not have a CDR
- * \retval 1 if the channel does have a CDR
- */
-int ast_cdr_exists(const char *channel_name);
-
-/*!
  * \since 12
  * \brief Format a CDR variable from an already posted CDR
  *
@@ -277,9 +259,15 @@
  */
 int ast_cdr_reset(const char *channel_name, struct ast_flags *options);
 
+/*!
+ * \brief Serializes all the data and variables for a current CDR record
+ * \param channel_name The channel to get the CDR for
+ * \param buf A buffer to use for formatting the data
+ * \param delim A delimeter to use to separate variable keys/values
+ * \param sep A separator to use between nestings
+ * \retval the total number of serialized variables
+ */
 int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep);
-
-int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr);
 
 /*!
  * \brief CDR backend callback
@@ -290,7 +278,7 @@
 typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
 
 /*! \brief Return TRUE if CDR subsystem is enabled */
-int check_cdr_enabled(void);
+int ast_cdr_is_enabled(void);
 
 /*!
  * \brief Allocate a CDR record
@@ -334,25 +322,6 @@
  */
 void ast_cdr_unregister(const char *name);
 
-
-
-/*!
- * \brief Detaches the detail record for posting (and freeing) either now or at a
- * later time in bulk with other records during batch mode operation.
- * \param cdr Which CDR to detach from the channel thread
- * Prevents the channel thread from blocking on the CDR handling
- * Returns nothing
- */
-void ast_cdr_detach(struct ast_cdr *cdr);
-
-/*!
- * \brief Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines
- * \param shutdown Whether or not we are shutting down
- * Blocks the asterisk shutdown procedures until the CDR data is submitted.
- * Returns nothing
- */
-void ast_cdr_submit_batch(int shutdown);
-
 /*!
  * \brief Disposition to a string
  * \param disposition input binary form
@@ -361,8 +330,6 @@
  */
 const char *ast_cdr_disp2str(int disposition);
 
-
-
 /*!
  * \brief Set CDR user field for channel (stored in CDR)
  *

Modified: team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h Mon Apr 29 18:12:48 2013
@@ -52,6 +52,9 @@
 		AST_STRING_FIELD(exten);		/*!< Dialplan: Current extension number */
 		AST_STRING_FIELD(caller_name);		/*!< Caller ID Name */
 		AST_STRING_FIELD(caller_number);	/*!< Caller ID Number */
+		AST_STRING_FIELD(dnid);				/*!< Dialed ID Number */
+		AST_STRING_FIELD(caller_subaddr);	/*!< Caller subaddress */
+		AST_STRING_FIELD(dialed_subaddr);	/*!< Dialed subaddress */
 		AST_STRING_FIELD(connected_name);	/*!< Connected Line Name */
 		AST_STRING_FIELD(connected_number);	/*!< Connected Line Number */
 	);

Modified: team/mjordan/cdrs-of-doom/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/asterisk.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/asterisk.c (original)
+++ team/mjordan/cdrs-of-doom/main/asterisk.c Mon Apr 29 18:12:48 2013
@@ -598,7 +598,7 @@
 	ast_cli(a->fd, "  -------------\n");
 	ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
-	ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
+	ast_cli(a->fd, "  Call data records:           %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
 
 	/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */

Modified: team/mjordan/cdrs-of-doom/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/bridging.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/bridging.c (original)
+++ team/mjordan/cdrs-of-doom/main/bridging.c Mon Apr 29 18:12:48 2013
@@ -518,6 +518,10 @@
 	/* BUGBUG If this was an outbound channel and it is not hung up, clear the
 	 * outbound flag
 	 */
+	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING)
+			&& !ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
+
+	}
 
 	/* Remove channel from the bridge */
 	if (!bridge_channel->suspended) {

Modified: team/mjordan/cdrs-of-doom/main/cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/cdr.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Mon Apr 29 18:12:48 2013
@@ -198,6 +198,9 @@
 		ast_verb(1, (fmt), ##__VA_ARGS__); \
 	} } while (0)
 
+static void cdr_detach(struct ast_cdr *cdr);
+static void cdr_submit_batch(int shutdown);
+
 /*! \brief The configuration settings for this module */
 struct module_config {
 	struct ast_cdr_config *general;		/*< CDR global settings */
@@ -293,6 +296,7 @@
 
 static struct ast_sched_context *sched;
 static int cdr_sched = -1;
+AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
 static pthread_t cdr_thread = AST_PTHREADT_NULL;
 
 AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
@@ -310,8 +314,10 @@
 /*! \brief Message router for stasis messages regarding channel state */
 static struct stasis_message_router *stasis_router;
 
+/*! \brief Our subscription for bridges */
 static struct stasis_subscription *bridge_subscription;
 
+/*! \brief Our subscription for channels */
 static struct stasis_subscription *channel_subscription;
 
 /*! \brief The parent topic for all topics we want to aggregate for CDRs */
@@ -324,57 +330,107 @@
  * implementation, it is safe to leave it NULL.
  */
 struct cdr_object_fn_table {
-	/*! Name of the subclass */
+	/*! \brief Name of the subclass */
 	const char *name;
 
-	/*! An initialization function. This will be called automatically when a
-	 * \ref cdr_object is switched to this type in
+	/*!
+	 * \brief An initialization function. This will be called automatically
+	 * when a \ref cdr_object is switched to this type in
 	 * \ref cdr_object_transition_state
 	 *
 	 * \param cdr The \ref cdr_object that was just transitioned
 	 */
 	void (* const init_function)(struct cdr_object *cdr);
 
-	/*! Process a Party A update for the \ref cdr_object
+	/*!
+	 * \brief Process a Party A update for the \ref cdr_object
 	 *
 	 * \param cdr The \ref cdr_object to process the update
 	 * \param snapshot The snapshot for the CDR's Party A
 	 * \retval 0 the CDR handled the update or ignored it
 	 * \retval 1 the CDR is finalized and a new one should be made to handle it
 	 */
-	int (* const process_party_a_update)(struct cdr_object *cdr,
+	int (* const process_party_a)(struct cdr_object *cdr,
 			struct ast_channel_snapshot *snapshot);
 
-	/*! Process a Party B update for the \ref cdr_object
+	/*!
+	 * \brief Process a Party B update for the \ref cdr_object
 	 *
 	 * \param cdr The \ref cdr_object to process the update
 	 * \param snapshot The snapshot for the CDR's Party B
 	 */
-	void (* const process_party_b_update)(struct cdr_object *cdr,
+	void (* const process_party_b)(struct cdr_object *cdr,
 			struct ast_channel_snapshot *snapshot);
 
-	/*! Process the beginning of a dial. A dial message implies one of two
+	/*!
+	 * \brief Process the beginning of a dial. A dial message implies one of two
 	 * things:
 	 * The \ref cdr_object's Party A has been originated
 	 * The \ref cdr_object's Party A is dialing its Party B
-	 * Functions should return 0 if the parties in the dial message are for this
-	 * \ref cdr_object, any other value otherwise.
+	 *
+	 * \param cdr The \ref cdr_object
+	 * \param caller The originator of the dial attempt
+	 * \param peer The destination of the dial attempt
+	 *
+	 * \retval 0 if the parties in the dial were handled by this CDR
+	 * \retval 1 if the parties could not be handled by this CDR
 	 */
 	int (* const process_dial_begin)(struct cdr_object *cdr,
 			struct ast_channel_snapshot *caller,
 			struct ast_channel_snapshot *peer);
+
+	/*!
+	 * \brief Process the end of a dial. At the end of a dial, a CDR can be
+	 * transitioned into one of two states - DialedPending
+	 * (\ref dialed_pending_state_fn_table) or Finalized
+	 * (\ref finalized_state_fn_table).
+	 *
+	 * \param cdr The \ref cdr_object
+	 * \param caller The originator of the dial attempt
+	 * \param peer the Destination of the dial attempt
+	 * \param dial_status What happened
+	 *
+	 * \retval 0 if the parties in the dial were handled by this CDR
+	 * \retval 1 if the parties could not be handled by this CDR
+	 */
 	int (* const process_dial_end)(struct cdr_object *cdr,
 			struct ast_channel_snapshot *caller,
 			struct ast_channel_snapshot *peer,
 			const char *dial_status);
+
+	/*!
+	 * \brief Process the entering of a bridge by this CDR. The purpose of this
+	 * callback is to have the CDR prepare itself for the bridge and attempt to
+	 * find a valid Party B. The act of creating new CDRs based on the entering
+	 * of this channel into the bridge is handled by the higher level message
+	 * handler.
+	 *
+	 * \param cdr The\ref cdr_object
+	 * \param bridge The bridge that the Party A just entered into
+	 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
+	 *
+	 * \retval 0 This CDR found a Party B for itself and updated it, or there
+	 * was no Party B to find (we're all alone)
+	 * \retval 1 This CDR couldn't find a Party B, and there were options
+	 */
 	int (* const process_bridge_enter)(struct cdr_object *cdr,
 			struct ast_bridge_snapshot *bridge,
 			struct ast_channel_snapshot *channel);
+
+	/*!
+	 * \brief Process the leaving of a bridge by this CDR.
+	 *
+	 * \param cdr The\ref cdr_object
+	 * \param bridge The bridge that the Party A just left
+	 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
+	 *
+	 * \retval 0 This CDR left successfully
+	 * \retval 1 Error
+	 */
 	int (* const process_bridge_leave)(struct cdr_object *cdr,
 			struct ast_bridge_snapshot *bridge,
 			struct ast_channel_snapshot *channel);
 };
-AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
 
 static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
 static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
@@ -385,11 +441,22 @@
 static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
 static int single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
 
+/*!
+ * \brief The virtual table for the Single state.
+ *
+ * A \ref cdr_object starts off in this state. This represents a channel that
+ * has no Party B information itself.
+ *
+ * A \ref cdr_object from this state can go into any of the following states:
+ * * \ref dial_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
 struct cdr_object_fn_table single_state_fn_table = {
 	.name = "Single",
 	.init_function = single_state_init_function,
-	.process_party_a_update = base_process_party_a,
-	.process_party_b_update = single_state_process_party_b,
+	.process_party_a = base_process_party_a,
+	.process_party_b = single_state_process_party_b,
 	.process_dial_begin = single_state_process_dial_begin,
 	.process_dial_end = base_process_dial_end,
 	.process_bridge_enter = single_state_process_bridge_enter,
@@ -401,23 +468,77 @@
 static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
 static int dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
 
+/*!
+ * \brief The virtual table for the Dial state.
+ *
+ * A \ref cdr_object that has begun a dial operation. This state is entered when
+ * the Party A for a CDR is determined to be dialing out to a Party B or when
+ * a CDR is for an originated channel (in which case the Party A information is
+ * the originated channel, and there is no Party B).
+ *
+ * A \ref cdr_object from this state can go in any of the following states:
+ * * \ref dialed_pending_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
 struct cdr_object_fn_table dial_state_fn_table = {
 	.name = "Dial",
-	.process_party_a_update = base_process_party_a,
-	.process_party_b_update = dial_state_process_party_b,
+	.process_party_a = base_process_party_a,
+	.process_party_b = dial_state_process_party_b,
 	.process_dial_begin = dial_state_process_dial_begin,
 	.process_dial_end = dial_state_process_dial_end,
 	.process_bridge_enter = dial_state_process_bridge_enter,
 	.process_bridge_leave = base_process_bridge_leave,
 };
 
+static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
+static int dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+
+/*!
+ * \brief The virtual table for the Dialed Pending state.
+ *
+ * A \ref cdr_object that has successfully finished a dial operation, but we
+ * don't know what they're going to do yet. It's theoretically possible to dial
+ * a party and then have that party not be bridged with the caller; likewise,
+ * an origination can complete and the channel go off and execute dialplan. The
+ * pending state acts as a bridge between either:
+ * * Entering a bridge
+ * * Getting a new CDR for new dialplan execution
+ * * Switching from being originated to executing dialplan
+ *
+ * A \ref cdr_object from this state can go in any of the following states:
+ * * \ref single_state_fn_table
+ * * \ref dialed_pending_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
+struct cdr_object_fn_table dialed_pending_state_fn_table = {
+	.name = "DialedPending",
+	.process_party_a = dialed_pending_state_process_party_a,
+	.process_dial_begin = dialed_pending_state_process_dial_begin,
+	.process_dial_end = base_process_dial_end,
+	.process_bridge_enter = dialed_pending_state_process_bridge_enter,
+	.process_bridge_leave = base_process_bridge_leave,
+};
+
 static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
 static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
 
+/*!
+ * \brief The virtual table for the Bridged state
+ *
+ * A \ref cdr_object enters this state when it receives notification that the
+ * channel has entered a bridge.
+ *
+ * A \ref cdr_object from this state can go to:
+ * * \ref finalized_state_fn_table
+ * * \ref pending_state_fn_table
+ */
 struct cdr_object_fn_table bridge_state_fn_table = {
 	.name = "Bridged",
-	.process_party_a_update = base_process_party_a,
-	.process_party_b_update = bridge_state_process_party_b,
+	.process_party_a = base_process_party_a,
+	.process_party_b = bridge_state_process_party_b,
 	.process_bridge_leave = bridge_state_process_bridge_leave,
 };
 
@@ -426,36 +547,41 @@
 static int pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
 static int pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
 
+/*!
+ * \brief The virtual table for the Pending state
+ *
+ * At certain times, we don't know where to go with the CDR. A good example is
+ * when a channel leaves a bridge - we don't know if the channel is about to
+ * be hung up; if it is about to go execute dialplan; dial someone; go into
+ * another bridge, etc. At these times, the CDR goes into pending and observes
+ * the messages that come in next to infer where the next logical place to go
+ * is.
+ *
+ * In this state, a CDR can go anywhere!
+ */
 struct cdr_object_fn_table bridged_pending_state_fn_table = {
 	.name = "Pending",
 	.init_function = pending_state_init_function,
-	.process_party_a_update = pending_state_process_party_a,
+	.process_party_a = pending_state_process_party_a,
 	.process_dial_begin = pending_state_process_dial_begin,
 	.process_dial_end = base_process_dial_end,
 	.process_bridge_enter = pending_state_process_bridge_enter,
 	.process_bridge_leave = base_process_bridge_leave,
 };
 
-static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
-static int dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
-
-struct cdr_object_fn_table dialed_pending_state_fn_table = {
-	.name = "DialedPending",
-	.process_party_a_update = dialed_pending_state_process_party_a,
-	.process_dial_begin = dialed_pending_state_process_dial_begin,
-	.process_dial_end = base_process_dial_end,
-	.process_bridge_enter = dialed_pending_state_process_bridge_enter,
-	.process_bridge_leave = base_process_bridge_leave,
-};
-
 static void finalized_state_init_function(struct cdr_object *cdr);
 static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
 
+/*!
+ * \brief The virtual table for the finalized state.
+ *
+ * Once in the finalized state, the CDR is done. No modifications can be made
+ * to the CDR.
+ */
 struct cdr_object_fn_table finalized_state_fn_table = {
 	.name = "Finalized",
 	.init_function = finalized_state_init_function,
-	.process_party_a_update = finalized_state_process_party_a,
+	.process_party_a = finalized_state_process_party_a,
 };
 
 /*! \brief A wrapper object around a snapshot.
@@ -464,22 +590,22 @@
 struct cdr_object_snapshot {
 	struct ast_channel_snapshot *snapshot;	/*!< The channel snapshot */
 	char userfield[AST_MAX_USER_FIELD];		/*!< Userfield for the channel */
-	unsigned int flags;
+	unsigned int flags;						/*!< Specific flags for this party */
 	struct varshead variables;				/*!< CDR variables for the channel */
 };
 
 /*! \brief An in-memory representation of an active CDR */
 struct cdr_object {
-	struct cdr_object_snapshot party_a;
-	struct cdr_object_snapshot party_b;
-	struct cdr_object_fn_table *fn_table;
-
-	enum ast_cdr_disposition disposition;
-	struct timeval start;
-	struct timeval answer;
-	struct timeval end;
-	unsigned int sequence;
-	struct ast_flags flags;
+	struct cdr_object_snapshot party_a;		/*!< The Party A information */
+	struct cdr_object_snapshot party_b;		/*!< The Party B information */
+	struct cdr_object_fn_table *fn_table;	/*!< The current virtual table */
+
+	enum ast_cdr_disposition disposition;	/*!< The disposition of the CDR */
+	struct timeval start;					/*!< When this CDR was created */
+	struct timeval answer;					/*!< Either when the channel was answered, or when the path between channels was established */
+	struct timeval end;						/*!< When this CDR was finalized */
+	unsigned int sequence;					/*!< A monotonically increasing number for each CDR */
+	struct ast_flags flags;					/*!< Flags on the CDR */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(linkedid);		/*< Linked ID. Cached here as it may change out from party A, which must be immutable */
 		AST_STRING_FIELD(name);			/*< Channel name of party A. Cached here as the party A address may change */
@@ -489,8 +615,13 @@
 	struct cdr_object *last;			/*< The last CDR object in the chain */
 };
 
-/*! \brief Copy variables from one list to another */
-static int copy_vars(struct varshead *to_list, struct varshead *from_list)
+/*!
+ * \brief Copy variables from one list to another
+ * \param to_list destination
+ * \param from_list source
+ * \retval The number of copied variables
+ */
+static int copy_variables(struct varshead *to_list, struct varshead *from_list)
 {
 	struct ast_var_t *variables, *newvariable = NULL;
 	const char *var, *val;
@@ -509,6 +640,24 @@
 	return x;
 }
 
+/*!
+ * \brief Delete all variables from a variable list
+ * \param headp The head pointer to the variable list to delete
+ */
+static void free_variables(struct varshead *headp)
+{
+	struct ast_var_t *vardata;
+
+	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
+		ast_var_delete(vardata);
+	}
+}
+
+/*!
+ * \brief Copy a snapshot and its details
+ * \param dst The destination
+ * \param src The source
+ */
 static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
 {
 	if (dst->snapshot) {
@@ -518,13 +667,26 @@
 	ao2_ref(dst->snapshot, +1);
 	strcpy(dst->userfield, src->userfield);
 	dst->flags = src->flags;
-	copy_vars(&dst->variables, &src->variables);
-}
-
-/* NON-VIRTUAL FUNCTIONS */
-
-static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table);
-
+	copy_variables(&dst->variables, &src->variables);
+}
+
+/*!
+ * \brief Transition a \ref cdr_object to a new state
+ * \param cdr The \ref cdr_object to transition
+ * \param fn_table The \ref cdr_object_fn_table state to go to
+ */
+static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
+{
+	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
+
+	CDR_DEBUG(mod_cfg, "%p - Transitioning CDR for %s from state %s to %s\n",
+		cdr, cdr->party_a.snapshot->name,
+		cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
+	cdr->fn_table = fn_table;
+	if (cdr->fn_table->init_function) {
+		cdr->fn_table->init_function(cdr);
+	}
+}
 /*! \internal
  * \brief Hash function for containers of CDRs indexing by Party A name */
 static int cdr_object_channel_hash_fn(const void *obj, const int flags)
@@ -574,6 +736,9 @@
 	return 0;
 }
 
+/*!
+ * \brief \ref cdr_object Destructor
+ */
 static void cdr_object_dtor(void *obj)
 {
 	struct cdr_object *cdr = obj;
@@ -598,6 +763,13 @@
 	}
 }
 
+/*!
+ * \brief \ref cdr_object constructor
+ * \param chan The \ref ast_channel_snapshot that is the CDR's Party A
+ *
+ * This implicitly sets the state of the newly created CDR to the Single state
+ * (\ref single_state_fn_table)
+ */
 static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
 {
 	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -621,13 +793,17 @@
 	cdr->party_a.snapshot = chan;
 	ao2_ref(cdr->party_a.snapshot, +1);
 
-	CDR_DEBUG(mod_cfg, "%p - created CDR for channel %s\n", cdr, chan->name);
+	CDR_DEBUG(mod_cfg, "%p - Created CDR for channel %s\n", cdr, chan->name);
 
 	cdr_object_transition_state(cdr, &single_state_fn_table);
 
 	return cdr;
 }
 
+/*!
+ * \brief Create a new \ref cdr_object and append it to an existing chain
+ * \param cdr The \ref cdr_object to append to
+ */
 static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr)
 {
 	struct cdr_object *new_cdr;
@@ -654,22 +830,61 @@
 	return new_cdr;
 }
 
-static struct ast_channel_snapshot *cdr_object_determine_party_a(struct ast_channel_snapshot *left, struct ast_channel_snapshot *right)
-{
-	/* TODO: check party a flag */
-
-	if (left->creationtime.tv_sec < right->creationtime.tv_sec) {
+/*!
+ * \brief Return whether or not a \ref ast_channel_snapshot is for a channel
+ * that was created as the result of a dial operation
+ *
+ * \retval 0 the channel was not created as the result of a dial
+ * \retval 1 the channel was created as the result of a dial
+ */
+static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
+{
+	return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
+			&& !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
+}
+
+/*!
+ * \brief Given two CDR snapshots, figure out who should be Party A for the
+ * resulting CDR
+ * \param left One of the snapshots
+ * \param right The other snapshot
+ * \retval The snapshot that won
+ */
+static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
+{
+	/* Check whether or not the party is dialed. A dialed party is never the
+	 * Party A with a party that was not dialed.
+	 */
+	if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
 		return left;
-	} else if (left->creationtime.tv_sec > right->creationtime.tv_sec) {
+	} else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
 		return right;
+	}
+
+	/* Try the Party A flag */
+	if (ast_test_flag(left, AST_CDR_FLAG_PARTY_A) && !ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
+		return left;
+	} else if (!ast_test_flag(right, AST_CDR_FLAG_PARTY_A) && ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
+		return right;
+	}
+
+	/* Neither party is dialed and neither has the Party A flag - defer to
+	 * creation time */
+	if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
+		return left;
+	} else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
+		return right;
+	} else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
+			return right;
 	} else {
-		if (left->creationtime.tv_usec > right->creationtime.tv_usec) {
-			return right;
-		}
+		/* Okay, fine, take the left one */
 		return left;
 	}
 }
 
+/*!
+ * Compute the duration for a \ref cdr_object
+ */
 static long cdr_object_get_duration(struct cdr_object *cdr)
 {
 	if (ast_tvzero(cdr->end)) {
@@ -679,6 +894,9 @@
 	}
 }
 
+/*!
+ * \brief Compute the billsec for a \ref cdr_object
+ */
 static long cdr_object_get_billsec(struct cdr_object *cdr)
 {
 	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -698,6 +916,13 @@
 	return ms;
 }
 
+/*!
+ * \brief Create a chain of \ref ast_cdr objects from a chain of \ref cdr_object
+ * suitable for consumption by the registered CDR backends
+ * \param cdr The \ref cdr_object to convert to a public record
+ * \retval A chain of \ref ast_cdr objects on success
+ * \retval NULL on failure
+ */
 static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 {
 	struct ast_cdr *pub_cdr = NULL, *cdr_prev;
@@ -708,11 +933,8 @@
 	while (cdr) {
 		struct ast_cdr *cdr_copy;
 
-		/* Don't create records for CDRs where the party A is an outgoing,
-		 * non-originated channel.
-		 */
-		if (ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_OUTGOING)
-			&& !ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_ORIGINATED)) {
+		/* Don't create records for CDRs where the party A was a dialed channel */
+		if (snapshot_is_dialed(cdr->party_a.snapshot)) {
 			cdr = cdr->next;
 			continue;
 		}
@@ -731,7 +953,6 @@
 		ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
 		cdr_copy->amaflags = party_a->amaflags;
 		ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
-		/* XXX TODO: we need to get the full caller ID somehow */
 		ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
 		ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
 		ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
@@ -739,30 +960,34 @@
 		ast_copy_string(cdr_copy->lastdata, party_a->data, sizeof(cdr_copy->lastdata));
 		ast_copy_string(cdr_copy->dst, party_a->exten, sizeof(cdr_copy->dst));
 		ast_copy_string(cdr_copy->dcontext, party_a->context, sizeof(cdr_copy->dcontext));
-		ast_copy_string(cdr_copy->userfield, cdr->party_a.userfield, sizeof(cdr_copy->userfield));
-		/* XXX TODO: this should just happen automatically */
-		ast_copy_flags(cdr_copy, &cdr->flags, AST_FLAGS_ALL);
 
 		/* Party B */
 		if (party_b) {
 			ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
 			ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
-		}
-
-		/* Timestamps */
+			if (!ast_strlen_zero(cdr->party_b.userfield)) {

[... 1657 lines stripped ...]



More information about the asterisk-commits mailing list