diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asterisk/bridging.h | 31 | ||||
-rw-r--r-- | include/asterisk/cdr.h | 649 | ||||
-rw-r--r-- | include/asterisk/cel.h | 25 | ||||
-rw-r--r-- | include/asterisk/channel.h | 111 | ||||
-rw-r--r-- | include/asterisk/channel_internal.h | 4 | ||||
-rw-r--r-- | include/asterisk/stasis_channels.h | 60 | ||||
-rw-r--r-- | include/asterisk/stasis_internal.h | 69 | ||||
-rw-r--r-- | include/asterisk/test.h | 73 | ||||
-rw-r--r-- | include/asterisk/time.h | 11 |
9 files changed, 653 insertions, 380 deletions
diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index 9d3f5b3cf..0bfcc3254 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -1032,6 +1032,37 @@ void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action); /*! + * \brief Update the linkedid for all channels in a bridge + * \since 12.0.0 + * + * \param bridge The bridge to update the linkedids on + * \param bridge_channel The channel joining the bridge + * \param swap The channel being swapped out of the bridge. May be NULL. + * + * \note The bridge must be locked prior to calling this function. + * \note This API call is meant for internal bridging operations. + */ +void ast_bridge_update_linkedids(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); + +/*! + * \brief Update the accountcodes for a channel entering a bridge + * \since 12.0.0 + * + * This function updates the accountcode and peeraccount on channels in two-party + * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense - + * however accountcode propagation will still occur if the channel joining has an + * accountcode. + * + * \param bridge The bridge to update the accountcodes in + * \param bridge_channel The channel joining the bridge + * \param swap The channel being swapped out of the bridge. May be NULL. + * + * \note The bridge must be locked prior to calling this function. + * \note This API call is meant for internal bridging operations. + */ +void ast_bridge_update_accountcodes(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); + +/*! * \brief Write a frame to the specified bridge_channel. * \since 12.0.0 * diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h index c2268e312..548ca994d 100644 --- a/include/asterisk/cdr.h +++ b/include/asterisk/cdr.h @@ -26,33 +26,216 @@ #ifndef _ASTERISK_CDR_H #define _ASTERISK_CDR_H -#include <sys/time.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 + * + * \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) + * + * \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 Pending state + * + * \par Pending + * + * After a channel leaves a bridge, we often don't know what's going to happen + * to it. It can enter another bridge; it can be hung up; it can continue on + * in the dialplan. It can even enter into limbo! Pending holds the state of the + * CDR until we get a subsequent Stasis message telling us what should happen. + * + * The following transitions can occur while in the Pending state: + * \li If a \ref ast_bridge_blob_type message is received, a new CDR is created + * and it is transitioned to the Bridge state + * \li If a \ref ast_channel_dial_type indicating a Dial Begin is received, a + * new CDR is created and it is transitioned to the Dial state + * \li If a \ref ast_channel_cache_update is received indicating a change in + * Context/Extension/Priority, a new CDR is created and transitioned to the + * Single state. If the update indicates that the party has been hung up, the + * CDR is transitioned 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 */ +}; -#include "asterisk/data.h" +/*! \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 Flags + * \brief CDR manipulation options. Certain function calls will manipulate the + * state of a CDR object based on these flags. */ -enum { - AST_CDR_FLAG_KEEP_VARS = (1 << 0), - AST_CDR_FLAG_POSTED = (1 << 1), - AST_CDR_FLAG_LOCKED = (1 << 2), - AST_CDR_FLAG_CHILD = (1 << 3), - AST_CDR_FLAG_POST_DISABLED = (1 << 4), - AST_CDR_FLAG_BRIDGED = (1 << 5), - AST_CDR_FLAG_MAIN = (1 << 6), - AST_CDR_FLAG_ENABLE = (1 << 7), - AST_CDR_FLAG_ANSLOCKED = (1 << 8), - AST_CDR_FLAG_DONT_TOUCH = (1 << 9), - AST_CDR_FLAG_POST_ENABLE = (1 << 10), - AST_CDR_FLAG_DIALED = (1 << 11), - AST_CDR_FLAG_ORIGINATED = (1 << 12), +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 */ }; /*! * \brief CDR Flags - Disposition */ -enum { +enum ast_cdr_disposition { AST_CDR_NOANSWER = 0, AST_CDR_NULL = (1 << 0), AST_CDR_FAILED = (1 << 1), @@ -61,21 +244,16 @@ enum { AST_CDR_CONGESTION = (1 << 4), }; -/*! - * \brief CDR AMA Flags - */ -enum { - AST_CDR_OMIT = 1, - AST_CDR_BILLING = 2, - AST_CDR_DOCUMENTATION = 3, -}; - -#define AST_MAX_USER_FIELD 256 -#define AST_MAX_ACCOUNT_CODE 20 -/* Include channel.h after relevant declarations it will need */ -#include "asterisk/channel.h" -#include "asterisk/utils.h" +/*! \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 @@ -133,249 +311,186 @@ struct ast_cdr { struct ast_cdr *next; }; -int ast_cdr_isset_unanswered(void); -int ast_cdr_isset_congestion(void); -void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw); -int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur); -int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur); -void ast_cdr_free_vars(struct ast_cdr *cdr, int recur); -int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr); - -/*! - * \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 check_cdr_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 record and increment the sequence number. - * \param cdr the record to duplicate - * \retval a malloc'd ast_cdr structure, - * \retval NULL on error (malloc failure) - * \see ast_cdr_dup() - * \see ast_cdr_dup_unique_swap() - */ -struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr); - -/*! - * \brief Duplicate a record and increment the sequence number of the old - * record. - * \param cdr the record to duplicate - * \retval a malloc'd ast_cdr structure, - * \retval NULL on error (malloc failure) - * \note This version increments the original CDR's sequence number rather than - * the duplicate's sequence number. The effect is as if the original CDR's - * sequence number was swapped with the duplicate's sequence number. + * \since 12 + * \brief Obtain the current CDR configuration * - * \see ast_cdr_dup() - * \see ast_cdr_dup_unique() - */ -struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr); - -/*! - * \brief Duplicate a record - * \param cdr the record to duplicate - * \retval a malloc'd ast_cdr structure, - * \retval NULL on error (malloc failure) - * \see ast_cdr_dup_unique() - * \see ast_cdr_dup_unique_swap() - */ -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 Discard and free a CDR record - * \param cdr ast_cdr structure to free - * Returns nothing -- same as free, but no checks or complaints + * 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 */ -void ast_cdr_discard(struct ast_cdr *cdr); +struct ast_cdr_config *ast_cdr_get_config(void); /*! - * \brief Initialize based on a channel - * \param cdr Call Detail Record to use for channel - * \param chan Channel to bind CDR with - * Initializes a CDR and associates it with a particular channel - * \note The channel should be locked before calling. - * \return 0 by default + * \since 12 + * \brief Set the current CDR configuration + * + * \param config The new CDR configuration */ -int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *chan); +void ast_cdr_set_config(struct ast_cdr_config *config); /*! - * \brief Initialize based on a channel - * \param cdr Call Detail Record to use for channel - * \param chan Channel to bind CDR with - * Initializes a CDR and associates it with a particular channel - * \note The channel should be locked before calling. - * \return 0 by default + * \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 */ -int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *chan); +void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw); /*! - * \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 + * \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_register(const char *name, const char *desc, ast_cdrbe be); +int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length); /*! - * \brief Unregister a CDR handling engine - * \param name name of CDR handler to unregister - * Unregisters a CDR by it's name + * \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 */ -void ast_cdr_unregister(const char *name); +int ast_cdr_setvar(const char *channel_name, const char *name, const char *value); /*! - * \brief Start a call - * \param cdr the cdr you wish to associate with the call - * Starts all CDR stuff necessary for monitoring a call - * Returns nothing - */ -void ast_cdr_start(struct ast_cdr *cdr); - -/*! \brief Answer a call - * \param cdr the cdr you wish to associate with the call - * Starts all CDR stuff necessary for doing CDR when answering a call - * \note NULL argument is just fine. + * \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 */ -void ast_cdr_answer(struct ast_cdr *cdr); +int ast_cdr_fork(const char *channel_name, struct ast_flags *options); /*! - * \brief A call wasn't answered - * \param cdr the cdr you wish to associate with the call - * Marks the channel disposition as "NO ANSWER" - * Will skip CDR's in chain with ANS_LOCK bit set. (see - * forkCDR() application. + * \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 */ -extern void ast_cdr_noanswer(struct ast_cdr *cdr); +int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option); /*! - * \brief A call was set to congestion - * \param cdr the cdr you wish to associate with the call - * Markst he channel disposition as "CONGESTION" - * Will skip CDR's in chain with ANS_LOCK bit set. (see - * forkCDR() application + * \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 */ -extern void ast_cdr_congestion(struct ast_cdr *cdr); +int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option); /*! - * \brief Busy a call - * \param cdr the cdr you wish to associate with the call - * Marks the channel disposition as "BUSY" - * Will skip CDR's in chain with ANS_LOCK bit set. (see - * forkCDR() application. - * Returns nothing + * \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 */ -void ast_cdr_busy(struct ast_cdr *cdr); +int ast_cdr_reset(const char *channel_name, struct ast_flags *options); /*! - * \brief Fail a call - * \param cdr the cdr you wish to associate with the call - * Marks the channel disposition as "FAILED" - * Will skip CDR's in chain with ANS_LOCK bit set. (see - * forkCDR() application. - * Returns nothing + * \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 */ -void ast_cdr_failed(struct ast_cdr *cdr); +int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep); /*! - * \brief Save the result of the call based on the AST_CAUSE_* - * \param cdr the cdr you wish to associate with the call - * \param cause the AST_CAUSE_* - * Returns nothing + * \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. */ -int ast_cdr_disposition(struct ast_cdr *cdr, int cause); +typedef int (*ast_cdrbe)(struct ast_cdr *cdr); -/*! - * \brief End a call - * \param cdr the cdr you have associated the call with - * Registers the end of call time in the cdr structure. - * Returns nothing - */ -void ast_cdr_end(struct ast_cdr *cdr); +/*! \brief Return TRUE if CDR subsystem is enabled */ +int ast_cdr_is_enabled(void); /*! - * \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 + * \brief Allocate a CDR record + * \retval a malloc'd ast_cdr structure + * \retval NULL on error (malloc failure) */ -void ast_cdr_detach(struct ast_cdr *cdr); +struct ast_cdr *ast_cdr_alloc(void); -/*! - * \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 Set the destination channel, if there was one - * \param cdr Which cdr it's applied to - * \param chan Channel to which dest will be - * Sets the destination channel the CDR is applied to - * Returns nothing + * \brief Duplicate a public CDR + * \param cdr the record to duplicate + * + * \retval a malloc'd ast_cdr structure, + * \retval NULL on error (malloc failure) */ -void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chan); +struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr); /*! - * \brief Set the last executed application - * \param cdr which cdr to act upon - * \param app the name of the app you wish to change it to - * \param data the data you want in the data field of app you set it to - * Changes the value of the last executed app + * \brief Free a CDR record + * \param cdr ast_cdr structure to free * Returns nothing */ -void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data); - -/*! - * \brief Set the answer time for a call - * \param cdr the cdr you wish to associate with the call - * \param t the answer time - * Starts all CDR stuff necessary for doing CDR when answering a call - * NULL argument is just fine. - */ -void ast_cdr_setanswer(struct ast_cdr *cdr, struct timeval t); +void ast_cdr_free(struct ast_cdr *cdr); /*! - * \brief Set the disposition for a call - * \param cdr the cdr you wish to associate with the call - * \param disposition the new disposition - * Set the disposition on a call. - * NULL argument is just fine. + * \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 */ -void ast_cdr_setdisposition(struct ast_cdr *cdr, long int disposition); +int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be); /*! - * \brief Convert a string to a detail record AMA flag - * \param flag string form of flag - * Converts the string form of the flag to the binary form. - * \return the binary form of the flag + * \brief Unregister a CDR handling engine + * \param name name of CDR handler to unregister + * Unregisters a CDR by it's name */ -int ast_cdr_amaflags2int(const char *flag); +void ast_cdr_unregister(const char *name); /*! * \brief Disposition to a string @@ -383,81 +498,15 @@ int ast_cdr_amaflags2int(const char *flag); * Converts the binary form of a disposition to string form. * \return a pointer to the string form */ -char *ast_cdr_disp2str(int disposition); - -/*! - * \brief Reset the detail record, optionally posting it first - * \param cdr which cdr to act upon - * \param flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it - * |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's - */ -void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *flags); - -/*! Reset the detail record times, flags */ -/*! - * \param cdr which cdr to act upon - * \param flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it - * |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's - */ -void ast_cdr_specialized_reset(struct ast_cdr *cdr, struct ast_flags *flags); - -/*! Flags to a string */ -/*! - * \param flags binary flag - * Converts binary flags to string flags - * Returns string with flag name - */ -char *ast_cdr_flags2str(int flags); - -/*! - * \brief Move the non-null data from the "from" cdr to the "to" cdr - * \param to the cdr to get the goodies - * \param from the cdr to give the goodies - */ -void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from); - -/*! - * \brief Set account code, will generate AMI event - * \note The channel should be locked before calling. - */ -int ast_cdr_setaccount(struct ast_channel *chan, const char *account); - -/*! - * \brief Set the peer account - * \note The channel should be locked before calling. - */ -int ast_cdr_setpeeraccount(struct ast_channel *chan, const char *account); - -/*! - * \brief Set AMA flags for channel - * \note The channel should be locked before calling. - */ -int ast_cdr_setamaflags(struct ast_channel *chan, const char *amaflags); +const char *ast_cdr_disp2str(int disposition); /*! * \brief Set CDR user field for channel (stored in CDR) - * \note The channel should be locked before calling. - */ -int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield); -/*! - * \brief Append to CDR user field for channel (stored in CDR) - * \note The channel should be locked before calling. - */ -int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield); - - -/*! - * \brief Update CDR on a channel - * \note The channel should be locked before calling. + * + * \param channel_name The name of the channel that owns the CDR + * \param userfield The user field to set */ -int ast_cdr_update(struct ast_channel *chan); - - -extern int ast_default_amaflags; - -extern char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]; - -struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr); +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); @@ -468,14 +517,4 @@ int ast_cdr_engine_init(void); /*! Submit any remaining CDRs and prepare for shutdown */ void ast_cdr_engine_term(void); -/*! - * \brief - * \param[in] tree Where to insert the cdr. - * \param[in] cdr The cdr structure to insert in 'tree'. - * \param[in] recur Go throw all the cdr levels. - * \retval <0 on error. - * \retval 0 on success. - */ -int ast_cdr_data_add_structure(struct ast_data *tree, struct ast_cdr *cdr, int recur); - #endif /* _ASTERISK_CDR_H */ diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h index 034a96ab9..914037d4c 100644 --- a/include/asterisk/cel.h +++ b/include/asterisk/cel.h @@ -36,20 +36,6 @@ extern "C" { #include "asterisk/event.h" /*! - * \brief AMA Flags - * - * \note This must much up with the AST_CDR_* defines for AMA flags. - */ -enum ast_cel_ama_flag { - AST_CEL_AMA_FLAG_NONE, - AST_CEL_AMA_FLAG_OMIT, - AST_CEL_AMA_FLAG_BILLING, - AST_CEL_AMA_FLAG_DOCUMENTATION, - /*! \brief Must be final entry */ - AST_CEL_AMA_FLAG_TOTAL, -}; - -/*! * \brief CEL event types */ enum ast_cel_event_type { @@ -162,17 +148,6 @@ const char *ast_cel_get_type_name(enum ast_cel_event_type type); */ enum ast_cel_event_type ast_cel_str_to_event_type(const char *name); -/*! - * \brief Convert AMA flag to printable string - * - * \param[in] flag the flag to convert to a string - * - * \since 1.8 - * - * \return the string representation of the flag - */ -const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag); - /*! * \brief Check and potentially retire a Linked ID * diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 42d50f21b..1b36c14ae 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -131,11 +131,13 @@ References: extern "C" { #endif -#define AST_MAX_EXTENSION 80 /*!< Max length of an extension */ -#define AST_MAX_CONTEXT 80 /*!< Max length of a context */ -#define AST_CHANNEL_NAME 80 /*!< Max length of an ast_channel name */ -#define MAX_LANGUAGE 40 /*!< Max length of the language setting */ -#define MAX_MUSICCLASS 80 /*!< Max length of the music class setting */ +#define AST_MAX_EXTENSION 80 /*!< Max length of an extension */ +#define AST_MAX_CONTEXT 80 /*!< Max length of a context */ +#define AST_MAX_ACCOUNT_CODE 20 /*!< Max length of an account code */ +#define AST_CHANNEL_NAME 80 /*!< Max length of an ast_channel name */ +#define MAX_LANGUAGE 40 /*!< Max length of the language setting */ +#define MAX_MUSICCLASS 80 /*!< Max length of the music class setting */ +#define AST_MAX_USER_FIELD 256 /*!< Max length of the channel user field */ #include "asterisk/frame.h" #include "asterisk/chanvars.h" @@ -915,6 +917,10 @@ enum { * to continue. */ AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT = (1 << 22), + /*! + * This flag indicates that the channel was originated. + */ + AST_FLAG_ORIGINATED = (1 << 23), }; /*! \brief ast_bridge_config flags */ @@ -1028,6 +1034,16 @@ enum channelreloadreason { }; /*! + * \brief Channel AMA Flags + */ +enum ama_flags { + AST_AMA_NONE = 0, + AST_AMA_OMIT, + AST_AMA_BILLING, + AST_AMA_DOCUMENTATION, +}; + +/*! * \note None of the datastore API calls lock the ast_channel they are using. * So, the channel should be locked before calling the functions that * take a channel argument. @@ -1100,7 +1116,7 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 13, 14))) __ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, - const char *linkedid, const int amaflag, + const char *linkedid, enum ama_flags amaflag, const char *file, int line, const char *function, const char *name_fmt, ...); @@ -1591,7 +1607,6 @@ int ast_answer(struct ast_channel *chan); * \brief Answer a channel * * \param chan channel to answer - * \param cdr_answer flag to control whether any associated CDR should be marked as 'answered' * * This function answers a channel and handles all necessary call * setup functions. @@ -1607,14 +1622,13 @@ int ast_answer(struct ast_channel *chan); * \retval 0 on success * \retval non-zero on failure */ -int ast_raw_answer(struct ast_channel *chan, int cdr_answer); +int ast_raw_answer(struct ast_channel *chan); /*! * \brief Answer a channel, with a selectable delay before returning * * \param chan channel to answer * \param delay maximum amount of time to wait for incoming media - * \param cdr_answer flag to control whether any associated CDR should be marked as 'answered' * * This function answers a channel and handles all necessary call * setup functions. @@ -1630,7 +1644,7 @@ int ast_raw_answer(struct ast_channel *chan, int cdr_answer); * \retval 0 on success * \retval non-zero on failure */ -int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer); +int __ast_answer(struct ast_channel *chan, unsigned int delay); /*! * \brief Execute a Gosub call on the channel before a call is placed. @@ -2197,6 +2211,28 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void ast_deactivate_generator(struct ast_channel *chan); /*! + * \since 12 + * \brief Obtain how long the channel since the channel was created + * + * \param chan The channel object + * + * \retval 0 if the time value cannot be computed (or you called this really fast) + * \retval The number of seconds the channel has been up + */ +int ast_channel_get_duration(struct ast_channel *chan); + +/*! + * \since 12 + * \brief Obtain how long it has been since the channel was answered + * + * \param chan The channel object + * + * \retval 0 if the channel isn't answered (or you called this really fast) + * \retval The number of seconds the channel has been up + */ +int ast_channel_get_up_time(struct ast_channel *chan); + +/*! * \brief Set caller ID number, name and ANI and generate AMI event. * * \note Use ast_channel_set_caller() and ast_channel_set_caller_event() instead. @@ -2728,12 +2764,6 @@ struct ast_channel *ast_channel_get_by_exten(const char *exten, const char *cont /*! @} End channel search functions. */ /*! - \brief propagate the linked id between chan and peer - */ -void ast_channel_set_linkgroup(struct ast_channel *chan, struct ast_channel *peer); - - -/*! * \brief Initialize the given name structure. * \since 1.8 * @@ -3806,6 +3836,26 @@ void ast_channel_unlink(struct ast_channel *chan); */ void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen); +/*! + * \since 12 + * \brief Convert a string to a detail record AMA flag + * + * \param flag string form of flag + * + * \retval the enum (integer) form of the flag + */ +enum ama_flags ast_channel_string2amaflag(const char *flag); + +/*! + * \since 12 + * \brief Convert the enum representation of an AMA flag to a string representation + * + * \param flags integer flag + * + * \retval A string representation of the flag + */ +const char *ast_channel_amaflags2string(enum ama_flags flags); + /* ACCESSOR FUNTIONS */ /*! \brief Set the channel name */ void ast_channel_name_set(struct ast_channel *chan, const char *name); @@ -3863,8 +3913,8 @@ char ast_channel_sending_dtmf_digit(const struct ast_channel *chan); void ast_channel_sending_dtmf_digit_set(struct ast_channel *chan, char value); struct timeval ast_channel_sending_dtmf_tv(const struct ast_channel *chan); void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval value); -int ast_channel_amaflags(const struct ast_channel *chan); -void ast_channel_amaflags_set(struct ast_channel *chan, int value); +enum ama_flags ast_channel_amaflags(const struct ast_channel *chan); +void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value); int ast_channel_epfd(const struct ast_channel *chan); void ast_channel_epfd_set(struct ast_channel *chan, int value); int ast_channel_fdno(const struct ast_channel *chan); @@ -3988,6 +4038,8 @@ void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *valu void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value); struct timeval ast_channel_creationtime(struct ast_channel *chan); void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value); +struct timeval ast_channel_answertime(struct ast_channel *chan); +void ast_channel_answertime_set(struct ast_channel *chan, struct timeval *value); /* List getters */ struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan); @@ -4278,4 +4330,27 @@ int ast_channel_move(struct ast_channel *dest, struct ast_channel *source); */ int ast_channel_forward_endpoint(struct ast_channel *chan, struct ast_endpoint *endpoint); +/*! + * \brief Return the oldest linkedid between two channels. + * + * A channel linkedid is derived from the channel uniqueid which is formed like this: + * [systemname-]ctime.seq + * + * The systemname, and the dash are optional, followed by the epoch time followed by an + * integer sequence. Note that this is not a decimal number, since 1.2 is less than 1.11 + * in uniqueid land. + * + * To compare two uniqueids, we parse out the integer values of the time and the sequence + * numbers and compare them, with time trumping sequence. + * + * \param a The linkedid value of the first channel to compare + * \param b The linkedid value of the second channel to compare + * + * \retval NULL on failure + * \retval The oldest linkedid value + * \since 12.0.0 +*/ +const char *ast_channel_oldest_linkedid(const char *a, const char *b); + + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 38776c1e1..a54a1b848 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -18,8 +18,8 @@ * \brief Internal channel functions for channel.c to use */ -#define ast_channel_internal_alloc(destructor) __ast_channel_internal_alloc(destructor, __FILE__, __LINE__, __PRETTY_FUNCTION__) -struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *file, int line, const char *function); +#define ast_channel_internal_alloc(destructor, linkedid) __ast_channel_internal_alloc(destructor, linkedid, __FILE__, __LINE__, __PRETTY_FUNCTION__) +struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *linkedid, const char *file, int line, const char *function); void ast_channel_internal_finalize(struct ast_channel *chan); int ast_channel_internal_is_finalized(struct ast_channel *chan); void ast_channel_internal_cleanup(struct ast_channel *chan); diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index 339c77274..ca075ae69 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -38,36 +38,38 @@ */ struct ast_channel_snapshot { AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(name); /*!< ASCII unique channel name */ - AST_STRING_FIELD(accountcode); /*!< Account code for billing */ - AST_STRING_FIELD(peeraccount); /*!< Peer account code for billing */ - AST_STRING_FIELD(userfield); /*!< Userfield for CEL billing */ - AST_STRING_FIELD(uniqueid); /*!< Unique Channel Identifier */ - AST_STRING_FIELD(linkedid); /*!< Linked Channel Identifier -- gets propagated by linkage */ - AST_STRING_FIELD(parkinglot); /*!< Default parking lot, if empty, default parking lot */ - AST_STRING_FIELD(hangupsource); /*!< Who is responsible for hanging up this channel */ - AST_STRING_FIELD(appl); /*!< Current application */ - AST_STRING_FIELD(data); /*!< Data passed to current application */ - AST_STRING_FIELD(context); /*!< Dialplan: Current extension context */ - 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(caller_ani); /*!< Caller ID ANI Number */ - AST_STRING_FIELD(caller_rdnis); /*!< Caller ID RDNIS Number */ - AST_STRING_FIELD(caller_dnid); /*!< Caller ID DNID Number */ - AST_STRING_FIELD(connected_name); /*!< Connected Line Name */ - AST_STRING_FIELD(connected_number); /*!< Connected Line Number */ - AST_STRING_FIELD(language); /*!< The default spoken language for the channel */ + AST_STRING_FIELD(name); /*!< ASCII unique channel name */ + AST_STRING_FIELD(accountcode); /*!< Account code for billing */ + AST_STRING_FIELD(peeraccount); /*!< Peer account code for billing */ + AST_STRING_FIELD(userfield); /*!< Userfield for CEL billing */ + AST_STRING_FIELD(uniqueid); /*!< Unique Channel Identifier */ + AST_STRING_FIELD(linkedid); /*!< Linked Channel Identifier -- gets propagated by linkage */ + AST_STRING_FIELD(parkinglot); /*!< Default parking lot, if empty, default parking lot */ + AST_STRING_FIELD(hangupsource); /*!< Who is responsible for hanging up this channel */ + AST_STRING_FIELD(appl); /*!< Current application */ + AST_STRING_FIELD(data); /*!< Data passed to current application */ + AST_STRING_FIELD(context); /*!< Dialplan: Current extension context */ + 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(caller_dnid); /*!< Dialed ID Number */ + AST_STRING_FIELD(caller_ani); /*< Caller ID ANI Number */ + AST_STRING_FIELD(caller_rdnis); /*!< Caller ID RDNIS 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 */ + AST_STRING_FIELD(language); /*!< The default spoken language for the channel */ ); - struct timeval creationtime; /*!< The time of channel creation */ - enum ast_channel_state state; /*!< State of line */ - int priority; /*!< Dialplan: Current extension priority */ - int amaflags; /*!< AMA flags for billing */ - int hangupcause; /*!< Why is the channel hanged up. See causes.h */ - int caller_pres; /*!< Caller ID presentation. */ - struct ast_flags flags; /*!< channel flags of AST_FLAG_ type */ - struct varshead *manager_vars; /*!< Variables to be appended to manager events */ + struct timeval creationtime; /*!< The time of channel creation */ + enum ast_channel_state state; /*!< State of line */ + int priority; /*!< Dialplan: Current extension priority */ + int amaflags; /*!< AMA flags for billing */ + int hangupcause; /*!< Why is the channel hanged up. See causes.h */ + int caller_pres; /*!< Caller ID presentation. */ + struct ast_flags flags; /*!< channel flags of AST_FLAG_ type */ + struct varshead *manager_vars; /*!< Variables to be appended to manager events */ }; /*! @@ -300,7 +302,7 @@ void ast_channel_publish_snapshot(struct ast_channel *chan); * \since 12 * \brief Publish a \ref ast_channel_varset for a channel. * - * \param chan Channel to pulish the event for, or \c NULL for 'none'. + * \param chan Channel to publish the event for, or \c NULL for 'none'. * \param variable Name of the variable being set * \param value Value. */ diff --git a/include/asterisk/stasis_internal.h b/include/asterisk/stasis_internal.h new file mode 100644 index 000000000..67ab88ff0 --- /dev/null +++ b/include/asterisk/stasis_internal.h @@ -0,0 +1,69 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * Matt Jordan <mjordan@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. + */ + +#ifndef STASIS_INTERNAL_H_ +#define STASIS_INTERNAL_H_ + +/*! \file + * + * \brief Internal Stasis APIs. + * + * This header file is used to define functions that are shared between files that make + * up \ref stasis. Functions declared here should not be used by any module outside of + * Stasis. + * + * If you find yourself needing to call one of these functions directly, something has + * probably gone horribly wrong. + * + * \author Matt Jordan <mjordan@digium.com> + */ + +struct stasis_topic; +struct stasis_subscription; +struct stasis_message; + +/*! + * \brief Create a subscription. + * + * In addition to being AO2 managed memory (requiring an ao2_cleanup() to free + * up this reference), the subscription must be explicitly unsubscribed from its + * topic using stasis_unsubscribe(). + * + * The invocations of the callback are serialized, but may not always occur on + * the same thread. The invocation order of different subscriptions is + * unspecified. + * + * Note: modules outside of Stasis should use \ref stasis_subscribe. + * + * \param topic Topic to subscribe to. + * \param callback Callback function for subscription messages. + * \param data Data to be passed to the callback, in addition to the message. + * \param needs_mailbox Determines whether or not the subscription requires a mailbox. + * Subscriptions with mailboxes will be delivered on a thread in the Stasis threadpool; + * subscriptions without mailboxes will be delivered on the publisher thread. + * \return New \ref stasis_subscription object. + * \return \c NULL on error. + * \since 12 + */ +struct stasis_subscription *internal_stasis_subscribe( + struct stasis_topic *topic, + void (*stasis_subscription_cb)(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message), + void *data, + int needs_mailbox); + +#endif /* STASIS_INTERNAL_H_ */ diff --git a/include/asterisk/test.h b/include/asterisk/test.h index d890b7a3e..d29969f8b 100644 --- a/include/asterisk/test.h +++ b/include/asterisk/test.h @@ -238,7 +238,9 @@ struct ast_test_info { /*! * \brief Generic test callback function * - * \param error buffer string for failure results + * \param info The test info object + * \param cmd What to perform in the test + * \param test The actual test object being manipulated * * \retval AST_TEST_PASS for pass * \retval AST_TEST_FAIL for failure @@ -247,6 +249,30 @@ typedef enum ast_test_result_state (ast_test_cb_t)(struct ast_test_info *info, enum ast_test_command cmd, struct ast_test *test); /*! + * \since 12 + * \brief A test initialization callback function + * + * \param info The test info object + * \param test The actual test object that will be manipulated + * + * \retval 0 success + * \retval other failure. This will fail the test. + */ +typedef int (ast_test_init_cb_t)(struct ast_test_info *info, struct ast_test *test); + +/*! + * \since 12 + * \brief A test cleanup callback function + * + * \param info The test info object + * \param test The actual test object that was executed + * + * \retval 0 success + * \retval other failure. This will fail the test. + */ +typedef int (ast_test_cleanup_cb_t)(struct ast_test_info *info, struct ast_test *test); + +/*! * \brief unregisters a test with the test framework * * \param test callback function (required) @@ -267,6 +293,40 @@ int ast_test_unregister(ast_test_cb_t *cb); int ast_test_register(ast_test_cb_t *cb); /*! + * \since 12 + * \brief Register an initialization function to be run before each test + * executes + * + * This function lets a registered test have an initialization function that + * will be run prior to test execution. Each category may have a single init + * function. + * + * If the initialization function returns a non-zero value, the test will not + * be executed and the result will be set to \ref AST_TEST_FAIL. + * + * \retval 0 success + * \retval other failure + */ +int ast_test_register_init(const char *category, ast_test_init_cb_t *cb); + +/*! + * \since 12 + * \brief Register a cleanup function to be run after each test executes + * + * This function lets a registered test have a cleanup function that will be + * run immediately after test execution. Each category may have a single + * cleanup function. + * + * If the cleanup function returns a non-zero value, the test result will be + * set to \ref AST_TEST_FAIL. + * + * \retval 0 success + * \retval other failure + */ +int ast_test_register_cleanup(const char *category, ast_test_cleanup_cb_t *cb); + + +/*! * \brief Unit test debug output. * \since 12.0.0 * @@ -278,6 +338,17 @@ int ast_test_register(ast_test_cb_t *cb); void ast_test_debug(struct ast_test *test, const char *fmt, ...) __attribute__((format(printf, 2, 3))); /*! + * \brief Set the result of a test. + * + * If the caller of this function sets the result to AST_TEST_FAIL, returning + * AST_TEST_PASS from the test will not pass the test. This lets a test writer + * end and fail a test and continue on with logic, catching multiple failure + * conditions within a single test. + */ +void ast_test_set_result(struct ast_test *test, enum ast_test_result_state state); + + +/*! * \brief update test's status during testing. * * \param test currently executing test diff --git a/include/asterisk/time.h b/include/asterisk/time.h index dd68db704..f2382df33 100644 --- a/include/asterisk/time.h +++ b/include/asterisk/time.h @@ -152,6 +152,17 @@ struct timeval ast_tvadd(struct timeval a, struct timeval b); struct timeval ast_tvsub(struct timeval a, struct timeval b); /*! + * \since 12 + * \brief Formats a duration into HH:MM:SS + * + * \param duration The time (in seconds) to format + * \param buf A buffer to hold the formatted string' + * \param length The size of the buffer + */ +void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length); + + +/*! * \brief Calculate remaining milliseconds given a starting timestamp * and upper bound * |