mirror of https://github.com/asterisk/asterisk
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
535 lines
20 KiB
535 lines
20 KiB
/*
|
|
* Asterisk -- An open source telephony toolkit.
|
|
*
|
|
* Copyright (C) 1999 - 2005, Digium, Inc.
|
|
*
|
|
* Mark Spencer <markster@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 Call Detail Record API
|
|
*
|
|
* \author Mark Spencer <markster@digium.com>
|
|
*/
|
|
|
|
#ifndef _ASTERISK_CDR_H
|
|
#define _ASTERISK_CDR_H
|
|
|
|
#include "asterisk/channel.h"
|
|
|
|
/*! \file
|
|
*
|
|
* \since 12
|
|
*
|
|
* \brief Call Detail Record Engine.
|
|
*
|
|
* \page CDR Call Detail Record Engine
|
|
*
|
|
* \par Intro
|
|
*
|
|
* The Call Detail Record (CDR) engine uses the \ref stasis Stasis Message Bus
|
|
* to build records for the channels in Asterisk. As the state of a channel and
|
|
* the bridges it participates in changes, notifications are sent over the
|
|
* Stasis Message Bus. The CDR engine consumes these notifications and builds
|
|
* records that reflect that state. Over the lifetime of a channel, many CDRs
|
|
* may be generated for that channel or that involve that channel.
|
|
*
|
|
* CDRs have a lifecycle that is a subset of the channel that they reflect. A
|
|
* single CDR for a channel represents a path of communication between the
|
|
* endpoint behind a channel and Asterisk, or between two endpoints. When a
|
|
* channel establishes a new path of communication, a new CDR is created for the
|
|
* channel. Likewise, when a path of communication is terminated, a CDR is
|
|
* finalized. Finally, when a channel is no longer present in Asterisk, all CDRs
|
|
* for that channel are dispatched for recording.
|
|
*
|
|
* Dispatching of CDRs occurs to registered CDR backends. CDR backends register
|
|
* through \ref ast_cdr_register and are responsible for taking the produced
|
|
* CDRs and storing them in permanent storage.
|
|
*
|
|
* \par CDR attributes
|
|
*
|
|
* While a CDR can have many attributes, all CDRs have two parties: a Party A
|
|
* and a Party B. The Party A is \em always the channel that owns the CDR. A CDR
|
|
* may or may not have a Party B, depending on its state.
|
|
*
|
|
* For the most part, attributes on a CDR are reflective of those same
|
|
* attributes on the channel at the time when the CDR was finalized. Specific
|
|
* CDR attributes include:
|
|
* \li \c start The time when the CDR was created
|
|
* \li \c answer The time when the Party A was answered, or when the path of
|
|
* communication between Party A and Party B was established
|
|
* \li \c end The time when the CDR was finalized
|
|
* \li \c duration \c end - \c start. If \c end is not known, the current time
|
|
* is used
|
|
* \li \c billsec \c end - \c answer. If \c end is not known, the current time
|
|
* is used
|
|
* \li \c userfield User set data on some party in the CDR
|
|
*
|
|
* Note that \c accountcode and \c amaflags are actually properties of a
|
|
* channel, not the CDR.
|
|
*
|
|
* \par CDR States
|
|
*
|
|
* CDRs go through various states during their lifetime. State transitions occur
|
|
* due to messages received over the \ref stasis Stasis Message Bus. The
|
|
* following describes the possible states a CDR can be in, and how it
|
|
* transitions through the states.
|
|
*
|
|
* \par Single
|
|
*
|
|
* When a CDR is created, it is put into the Single state. The Single state
|
|
* represents a CDR for a channel that has no Party B. CDRs can be unanswered
|
|
* or answered while in the Single state.
|
|
*
|
|
* The following transitions can occur while in the Single state:
|
|
* \li If a \ref ast_channel_dial_type indicating a Dial Begin is received, the
|
|
* state transitions to Dial
|
|
* \li If a \ref ast_channel_snapshot is received indicating that the channel
|
|
* has hung up, the state transitions to Finalized
|
|
* \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
|
|
* state transitions to Bridge
|
|
* \li If a \ref ast_bridge_blob_type message indicating an entrance to a
|
|
* holding bridge with a subclass type of "parking" is received, the CDR is
|
|
* transitioned to the Parked state.
|
|
*
|
|
* \par Dial
|
|
*
|
|
* This state represents a dial that is occurring within Asterisk. The Party A
|
|
* can either be the caller for a two party dial, or it can be the dialed party
|
|
* if the calling party is Asterisk (that is, an Originated channel). In the
|
|
* first case, the Party B is \em always the dialed channel; in the second case,
|
|
* the channel is not considered to be a "dialed" channel as it is alone in the
|
|
* dialed operation.
|
|
*
|
|
* While in the Dial state, multiple CDRs can be created for the Party A if a
|
|
* parallel dial occurs. Each dialed party receives its own CDR with Party A.
|
|
*
|
|
* The following transitions can occur while in the Dial state:
|
|
* \li If a \ref ast_channel_dial_type indicating a Dial End is received where
|
|
* the \ref dial_status is not ANSWER, the state transitions to Finalized
|
|
* \li If a \ref ast_channel_snapshot is received indicating that the channel
|
|
* has hung up, the state transitions to Finalized
|
|
* \li If a \ref ast_channel_dial_type indicating a Dial End is received where
|
|
* the \ref dial_status is ANSWER, the state transitions to DialedPending
|
|
* \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
|
|
* state transitions to Bridge
|
|
*
|
|
* \par DialedPending
|
|
*
|
|
* Technically, after being dialed, a CDR does not have to transition to the
|
|
* Bridge state. If the channel being dialed was originated, the channel may
|
|
* being executing dialplan. Strangely enough, it is also valid to have both
|
|
* Party A and Party B - after a dial - to not be bridged and instead execute
|
|
* dialplan. DialedPending handles the state where we figure out if the CDR
|
|
* showing the dial needs to move to the Bridge state; if the CDR should show
|
|
* that we started executing dialplan; of if we need a new CDR.
|
|
*
|
|
* The following transition can occur while in the DialedPending state:
|
|
* \li If a \ref ast_channel_snapshot is received that indicates that the
|
|
* channel has begun executing dialplan, we transition to the Finalized state
|
|
* if we have a Party B. Otherwise, we transition to the Single state.
|
|
* \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
|
|
* state transitions to Bridge (through the Dial state)
|
|
* \li If a \ref ast_bridge_blob_type message indicating an entrance to a
|
|
* holding bridge with a subclass type of "parking" is received, the CDR is
|
|
* transitioned to the Parked state.
|
|
*
|
|
* \par Bridge
|
|
*
|
|
* The Bridge state represents a path of communication between Party A and one
|
|
* or more other parties. When a CDR enters into the Bridge state, the following
|
|
* occurs:
|
|
* \li The CDR attempts to find a Party B. If the CDR has a Party B, it looks
|
|
* for that channel in the bridge and updates itself accordingly. If the CDR
|
|
* does not yet have a Party B, it attempts to find a channel that can be its
|
|
* Party B. If it finds one, it updates itself; otherwise, the CDR is
|
|
* temporarily finalized.
|
|
* \li Once the CDR has a Party B or it is determined that it cannot have a
|
|
* Party B, new CDRs are created for each pairing of channels with the CDR's
|
|
* Party A.
|
|
*
|
|
* As an example, consider the following:
|
|
* \li A Dials B - both answer
|
|
* \li B joins a bridge. Since no one is in the bridge and it was a dialed
|
|
* channel, it cannot have a Party B.
|
|
* \li A joins the bridge. Since A's Party B is B, A updates itself with B.
|
|
* \li Now say an Originated channel, C, joins the bridge. The bridge becomes
|
|
* a multi-party bridge.
|
|
* \li C attempts to get a Party B. A cannot be C's Party B, as it was created
|
|
* before it. B is a dialed channel and can thus be C's Party B, so C's CDR
|
|
* updates its Party B to B.
|
|
* \li New CDRs are now generated. A gets a new CDR for A -> C. B is dialed, and
|
|
* hence cannot get any CDR.
|
|
* \li Now say another Originated channel, D, joins the bridge. Say D has the
|
|
* \ref party_a flag set on it, such that it is always the preferred Party A.
|
|
* As such, it takes A as its Party B.
|
|
* \li New CDRs are generated. D gets new CDRs for D -> B and D -> C.
|
|
*
|
|
* The following transitions can occur while in the Bridge state:
|
|
* \li If a \ref ast_bridge_blob_type message indicating a leave is received,
|
|
* the state transitions to the Finalized state.
|
|
*
|
|
* \par Parked
|
|
*
|
|
* Parking is technically just another bridge in the Asterisk bridging
|
|
* framework. Unlike other bridges, however there are several key distinctions:
|
|
* \li With normal bridges, you want to show paths of communication between
|
|
* the participants. In parking, however, each participant is independent.
|
|
* From the perspective of a CDR, a call in parking should look like a dialplan
|
|
* application just executed.
|
|
* \li Holding bridges are typically items using in more complex applications,
|
|
* and so we usually don't want to show them. However, with Park, there is no
|
|
* application execution - often, a channel will be put directly into the
|
|
* holding bridge, bypassing the dialplan. This occurs when a call is blind
|
|
* transferred to a parking extension.
|
|
*
|
|
* As such, if a channel enters a bridge and that happens to be a holding bridge
|
|
* with a subclass type of "parking", we transition the CDR into the Parked
|
|
* state. The parking Stasis message updates the application name and data to
|
|
* reflect that the channel is in parking. When this occurs, a special flag is
|
|
* set on the CDR that prevents the application name from being updates by
|
|
* subsequent channel snapshot updates.
|
|
*
|
|
* The following transitions can occur while in the Parked state:
|
|
* \li If a \ref ast_bridge_blob_type message indicating a leave is received,
|
|
* the state transitions to the Finalized state
|
|
*
|
|
* \par Finalized
|
|
*
|
|
* Once a CDR enters the finalized state, it is finished. No further updates
|
|
* can be made to the party information, and the CDR cannot be changed.
|
|
*
|
|
* One exception to this occurs during linkedid propagation, in which the CDRs
|
|
* linkedids are updated based on who the channel is bridged with. In general,
|
|
* however, a finalized CDR is waiting for dispatch to the CDR backends.
|
|
*/
|
|
|
|
/*! \brief CDR engine settings */
|
|
enum ast_cdr_settings {
|
|
CDR_ENABLED = 1 << 0, /*< Enable CDRs */
|
|
CDR_BATCHMODE = 1 << 1, /*< Whether or not we should dispatch CDRs in batches */
|
|
CDR_UNANSWERED = 1 << 2, /*< Log unanswered CDRs */
|
|
CDR_CONGESTION = 1 << 3, /*< Treat congestion as if it were a failed call */
|
|
CDR_END_BEFORE_H_EXTEN = 1 << 4, /*< End the CDR before the 'h' extension runs */
|
|
CDR_INITIATED_SECONDS = 1 << 5, /*< Include microseconds into the billing time */
|
|
CDR_DEBUG = 1 << 6, /*< Enables extra debug statements */
|
|
};
|
|
|
|
/*! \brief CDR Batch Mode settings */
|
|
enum ast_cdr_batch_mode_settings {
|
|
BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*< Don't spawn a thread to handle the batches - do it on the scheduler */
|
|
BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*< During safe shutdown, submit the batched CDRs */
|
|
};
|
|
|
|
/*!
|
|
* \brief CDR manipulation options. Certain function calls will manipulate the
|
|
* state of a CDR object based on these flags.
|
|
*/
|
|
enum ast_cdr_options {
|
|
AST_CDR_FLAG_KEEP_VARS = (1 << 0), /*< Copy variables during the operation */
|
|
AST_CDR_FLAG_DISABLE = (1 << 1), /*< Disable the current CDR */
|
|
AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*< Disable the CDR and all future CDRs */
|
|
AST_CDR_FLAG_PARTY_A = (1 << 3), /*< Set the channel as party A */
|
|
AST_CDR_FLAG_FINALIZE = (1 << 4), /*< Finalize the current CDRs */
|
|
AST_CDR_FLAG_SET_ANSWER = (1 << 5), /*< If the channel is answered, set the answer time to now */
|
|
AST_CDR_FLAG_RESET = (1 << 6), /*< If set, set the start and answer time to now */
|
|
AST_CDR_LOCK_APP = (1 << 7), /*< Prevent any further changes to the application field/data field for this CDR */
|
|
};
|
|
|
|
/*!
|
|
* \brief CDR Flags - Disposition
|
|
*/
|
|
enum ast_cdr_disposition {
|
|
AST_CDR_NOANSWER = 0,
|
|
AST_CDR_NULL = (1 << 0),
|
|
AST_CDR_FAILED = (1 << 1),
|
|
AST_CDR_BUSY = (1 << 2),
|
|
AST_CDR_ANSWERED = (1 << 3),
|
|
AST_CDR_CONGESTION = (1 << 4),
|
|
};
|
|
|
|
|
|
/*! \brief The global options available for CDRs */
|
|
struct ast_cdr_config {
|
|
struct ast_flags settings; /*< CDR settings */
|
|
struct batch_settings {
|
|
unsigned int time; /*< Time between batches */
|
|
unsigned int size; /*< Size to trigger a batch */
|
|
struct ast_flags settings; /*< Settings for batches */
|
|
} batch_settings;
|
|
};
|
|
|
|
/*!
|
|
* \brief Responsible for call detail data
|
|
*/
|
|
struct ast_cdr {
|
|
/*! Caller*ID with text */
|
|
char clid[AST_MAX_EXTENSION];
|
|
/*! Caller*ID number */
|
|
char src[AST_MAX_EXTENSION];
|
|
/*! Destination extension */
|
|
char dst[AST_MAX_EXTENSION];
|
|
/*! Destination context */
|
|
char dcontext[AST_MAX_EXTENSION];
|
|
|
|
char channel[AST_MAX_EXTENSION];
|
|
/*! Destination channel if appropriate */
|
|
char dstchannel[AST_MAX_EXTENSION];
|
|
/*! Last application if appropriate */
|
|
char lastapp[AST_MAX_EXTENSION];
|
|
/*! Last application data */
|
|
char lastdata[AST_MAX_EXTENSION];
|
|
|
|
struct timeval start;
|
|
|
|
struct timeval answer;
|
|
|
|
struct timeval end;
|
|
/*! Total time in system, in seconds */
|
|
long int duration;
|
|
/*! Total time call is up, in seconds */
|
|
long int billsec;
|
|
/*! What happened to the call */
|
|
long int disposition;
|
|
/*! What flags to use */
|
|
long int amaflags;
|
|
/*! What account number to use */
|
|
char accountcode[AST_MAX_ACCOUNT_CODE];
|
|
/*! Account number of the last person we talked to */
|
|
char peeraccount[AST_MAX_ACCOUNT_CODE];
|
|
/*! flags */
|
|
unsigned int flags;
|
|
/*! Unique Channel Identifier */
|
|
char uniqueid[AST_MAX_UNIQUEID];
|
|
/* Linked group Identifier */
|
|
char linkedid[AST_MAX_UNIQUEID];
|
|
/*! User field */
|
|
char userfield[AST_MAX_USER_FIELD];
|
|
/*! Sequence field */
|
|
int sequence;
|
|
|
|
/*! A linked list for variables */
|
|
struct varshead varshead;
|
|
|
|
struct ast_cdr *next;
|
|
};
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Obtain the current CDR configuration
|
|
*
|
|
* The configuration is a ref counted object. The caller of this function must
|
|
* decrement the ref count when finished with the configuration.
|
|
*
|
|
* \retval NULL on error
|
|
* \retval The current CDR configuration
|
|
*/
|
|
struct ast_cdr_config *ast_cdr_get_config(void);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Set the current CDR configuration
|
|
*
|
|
* \param config The new CDR configuration
|
|
*/
|
|
void ast_cdr_set_config(struct ast_cdr_config *config);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Format a CDR variable from an already posted CDR
|
|
*
|
|
* \param cdr The dispatched CDR to process
|
|
* \param name The name of the variable
|
|
* \param ret Pointer to the formatted buffer
|
|
* \param workspace A pointer to the buffer to use to format the variable
|
|
* \param workspacelen The size of \ref workspace
|
|
* \param raw If non-zero and a date/time is extraced, provide epoch seconds. Otherwise format as a date/time stamp
|
|
*/
|
|
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Retrieve a CDR variable from a channel's current CDR
|
|
*
|
|
* \param channel_name The name of the party A channel that the CDR is associated with
|
|
* \param name The name of the variable to retrieve
|
|
* \param value Buffer to hold the value
|
|
* \param length The size of the buffer
|
|
*
|
|
* \retval 0 on success
|
|
* \retval non-zero on failure
|
|
*/
|
|
int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Set a variable on a CDR
|
|
*
|
|
* \param channel_name The channel to set the variable on
|
|
* \param name The name of the variable to set
|
|
* \param value The value of the variable to set
|
|
*
|
|
* \retval 0 on success
|
|
* \retval non-zero on failure
|
|
*/
|
|
int ast_cdr_setvar(const char *channel_name, const char *name, const char *value);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Fork a CDR
|
|
*
|
|
* \param channel_name The name of the channel whose CDR should be forked
|
|
* \param options Options to control how the fork occurs.
|
|
*
|
|
* \retval 0 on success
|
|
* \retval -1 on failure
|
|
*/
|
|
int ast_cdr_fork(const char *channel_name, struct ast_flags *options);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Set a property on a CDR for a channel
|
|
*
|
|
* This function sets specific administrative properties on a CDR for a channel.
|
|
* This includes properties like preventing a CDR from being dispatched, to
|
|
* setting the channel as the preferred Party A in future CDRs. See
|
|
* \ref enum ast_cdr_options for more information.
|
|
*
|
|
* \param channel_name The CDR's channel
|
|
* \param option Option to apply to the CDR
|
|
*
|
|
* \retval 0 on success
|
|
* \retval 1 on error
|
|
*/
|
|
int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Clear a property on a CDR for a channel
|
|
*
|
|
* Clears a flag previously set by \ref ast_cdr_set_property
|
|
*
|
|
* \param channel_name The CDR's channel
|
|
* \param option Option to clear from the CDR
|
|
*
|
|
* \retval 0 on success
|
|
* \retval 1 on error
|
|
*/
|
|
int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option);
|
|
|
|
/*!
|
|
* \brief Reset the detail record
|
|
* \param channel_name The channel that the CDR is associated with
|
|
* \param options Options that control what the reset operation does.
|
|
*
|
|
* Valid options are:
|
|
* \ref AST_CDR_FLAG_KEEP_VARS - keep the variables during the reset
|
|
* \ref AST_CDR_FLAG_DISABLE_ALL - when used with \ref ast_cdr_reset, re-enables
|
|
* the CDR
|
|
*
|
|
* \retval 0 on success
|
|
* \retval -1 on failure
|
|
*/
|
|
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);
|
|
|
|
/*!
|
|
* \brief CDR backend callback
|
|
* \warning CDR backends should NOT attempt to access the channel associated
|
|
* with a CDR record. This channel is not guaranteed to exist when the CDR
|
|
* backend is invoked.
|
|
*/
|
|
typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
|
|
|
|
/*! \brief Return TRUE if CDR subsystem is enabled */
|
|
int ast_cdr_is_enabled(void);
|
|
|
|
/*!
|
|
* \brief Allocate a CDR record
|
|
* \retval a malloc'd ast_cdr structure
|
|
* \retval NULL on error (malloc failure)
|
|
*/
|
|
struct ast_cdr *ast_cdr_alloc(void);
|
|
|
|
|
|
/*!
|
|
* \brief Duplicate a public CDR
|
|
* \param cdr the record to duplicate
|
|
*
|
|
* \retval a malloc'd ast_cdr structure,
|
|
* \retval NULL on error (malloc failure)
|
|
*/
|
|
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
|
|
|
|
/*!
|
|
* \brief Free a CDR record
|
|
* \param cdr ast_cdr structure to free
|
|
* Returns nothing
|
|
*/
|
|
void ast_cdr_free(struct ast_cdr *cdr);
|
|
|
|
/*!
|
|
* \brief Register a CDR handling engine
|
|
* \param name name associated with the particular CDR handler
|
|
* \param desc description of the CDR handler
|
|
* \param be function pointer to a CDR handler
|
|
* Used to register a Call Detail Record handler.
|
|
* \retval 0 on success.
|
|
* \retval -1 on error
|
|
*/
|
|
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
|
|
|
|
/*!
|
|
* \brief Unregister a CDR handling engine
|
|
* \param name name of CDR handler to unregister
|
|
* Unregisters a CDR by it's name
|
|
*/
|
|
void ast_cdr_unregister(const char *name);
|
|
|
|
/*!
|
|
* \brief Disposition to a string
|
|
* \param disposition input binary form
|
|
* Converts the binary form of a disposition to string form.
|
|
* \return a pointer to the string form
|
|
*/
|
|
const char *ast_cdr_disp2str(int disposition);
|
|
|
|
/*!
|
|
* \brief Set CDR user field for channel (stored in CDR)
|
|
*
|
|
* \param channel_name The name of the channel that owns the CDR
|
|
* \param userfield The user field to set
|
|
*/
|
|
void ast_cdr_setuserfield(const char *channel_name, const char *userfield);
|
|
|
|
/*! \brief Reload the configuration file cdr.conf and start/stop CDR scheduling thread */
|
|
int ast_cdr_engine_reload(void);
|
|
|
|
/*! \brief Load the configuration file cdr.conf and possibly start the CDR scheduling thread */
|
|
int ast_cdr_engine_init(void);
|
|
|
|
/*! Submit any remaining CDRs and prepare for shutdown */
|
|
void ast_cdr_engine_term(void);
|
|
|
|
#endif /* _ASTERISK_CDR_H */
|