Files
asterisk/include/asterisk/cel.h
Terry Wilson c7f2d02ef1 Fix race condition for CEL LINKEDID_END event
This patch fixes to situations that could cause the CEL LINKEDID_END event to
be missed.

1) During a core stop gracefully, modules are unloaded when ast_active_channels
== 0. The LINKDEDID_END event fires during the channel destructor. This means
that occasionally, the cel_* module will be unloaded before the channel is
destroyed. It seemed generally useful to wait until the refcount of all
channels == 0 before unloading, so I added a channel counter and used it in the
shutdown code.

2) During a masquerade, ast_channel_change_linkedid is called. It calls
ast_cel_check_retire_linkedid which unrefs the linkedid in the linkedids
container in cel.c. It didn't ref the new linkedid. Now it does. 

Review: https://reviewboard.asterisk.org/r/1900/
........

Merged revisions 367292 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 367299 from http://svn.asterisk.org/svn/asterisk/branches/10


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@367309 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-05-22 17:29:12 +00:00

301 lines
8.1 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2008 - 2009, Digium, Inc.
*
* 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 Event Logging API
*
* \todo TODO: There some event types that have been defined here, but are not
* yet used anywhere in the code. It would be really awesome if someone
* went through and had Asterisk generate these events where it is
* appropriate to do so. The defined, but unused events are:
* CONF_ENTER, CONF_EXIT, CONF_START, CONF_END, 3WAY_START, 3WAY_END,
* TRANSFER, and HOOKFLASH.
*/
#ifndef __AST_CEL_H__
#define __AST_CEL_H__
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#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 {
/*! \brief channel birth */
AST_CEL_CHANNEL_START = 1,
/*! \brief channel end */
AST_CEL_CHANNEL_END = 2,
/*! \brief hangup terminates connection */
AST_CEL_HANGUP = 3,
/*! \brief A ringing phone is answered */
AST_CEL_ANSWER = 4,
/*! \brief an app starts */
AST_CEL_APP_START = 5,
/*! \brief an app ends */
AST_CEL_APP_END = 6,
/*! \brief a bridge is established */
AST_CEL_BRIDGE_START = 7,
/*! \brief a bridge is torn down */
AST_CEL_BRIDGE_END = 8,
/*! \brief a conference is started */
AST_CEL_CONF_START = 9,
/*! \brief a conference is ended */
AST_CEL_CONF_END = 10,
/*! \brief a channel is parked */
AST_CEL_PARK_START = 11,
/*! \brief channel out of the park */
AST_CEL_PARK_END = 12,
/*! \brief a transfer occurs */
AST_CEL_BLINDTRANSFER = 13,
/*! \brief a transfer occurs */
AST_CEL_ATTENDEDTRANSFER = 14,
/*! \brief a transfer occurs */
AST_CEL_TRANSFER = 15,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_HOOKFLASH = 16,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_3WAY_START = 17,
/*! \brief a 3-way conference, usually part of a transfer */
AST_CEL_3WAY_END = 18,
/*! \brief channel enters a conference */
AST_CEL_CONF_ENTER = 19,
/*! \brief channel exits a conference */
AST_CEL_CONF_EXIT = 20,
/*! \brief a user-defined event, the event name field should be set */
AST_CEL_USER_DEFINED = 21,
/*! \brief the last channel with the given linkedid is retired */
AST_CEL_LINKEDID_END = 22,
/*! \brief a masquerade happened to alter the participants on a bridge */
AST_CEL_BRIDGE_UPDATE = 23,
/*! \brief a directed pickup was performed on this channel */
AST_CEL_PICKUP = 24,
/*! \brief this call was forwarded somewhere else */
AST_CEL_FORWARD = 25,
};
/*!
* \brief Check to see if CEL is enabled
*
* \since 1.8
*
* \retval zero not enabled
* \retval non-zero enabled
*/
unsigned int ast_cel_check_enabled(void);
/*!
* \brief Allocate a CEL record
*
* \since 1.8
*
* \note The CEL record must be destroyed with ast_cel_destroy().
*
* \retval non-NULL an allocated ast_cel structure
* \retval NULL error
*/
struct ast_cel *ast_cel_alloc(void);
/*!
* \brief Destroy a CEL record.
*
* \param cel the record to destroy
*
* \since 1.8
*
* \return nothing.
*/
void ast_cel_destroy(struct ast_cel *cel);
/*!
* \brief Get the name of a CEL event type
*
* \param type the type to get the name of
*
* \since 1.8
*
* \return the string representation of the type
*/
const char *ast_cel_get_type_name(enum ast_cel_event_type type);
/*!
* \brief Get the event type from a string
*
* \param name the event type name as a string
*
* \since 1.8
*
* \return the ast_cel_event_type given by the string
*/
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
*
* \param chan channel that is being destroyed or its linkedid is changing
*
* \since 1.8
*
* If at least one CEL backend is looking for CEL_LINKEDID_END
* events, this function will check if the given channel is the last
* active channel with that linkedid, and if it is, emit a
* CEL_LINKEDID_END event.
*
* \return nothing
*/
void ast_cel_check_retire_linkedid(struct ast_channel *chan);
/*!
* \brief Inform CEL that a new linkedid is being used
* \since 11
*
* \retval -1 error
* \retval 0 success
*/
int ast_cel_linkedid_ref(const char *linkedid);
/*!
* \brief Create a fake channel from data in a CEL event
*
* \note
* This function creates a fake channel containing the
* serialized channel data in the given cel event. It should be
* released with ast_channel_unref() but could be released with
* ast_channel_release().
*
* \param event the CEL event
*
* \since 1.8
*
* \return a channel with the data filled in, or NULL on error
*
* \todo This function is \b very expensive, especially given that some CEL backends
* use it on \b every CEL event. This function really needs to go away at
* some point.
*/
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event);
/*!
* \brief Report a channel event
*
* \param chan This argument is required. This is the primary channel associated with
* this channel event.
* \param event_type This is the type of call event being reported.
* \param userdefevname This is an optional custom name for the call event.
* \param extra This is an optional opaque field that will go into the "CEL_EXTRA"
* information element of the call event.
* \param peer2 All CEL events contain a "peer name" information element. The first
* place the code will look to get a peer name is from the bridged channel to
* chan. If chan has no bridged channel and peer2 is specified, then the name
* of peer2 will go into the "peer name" field. If neither are available, the
* peer name field will be blank.
*
* \since 1.8
*
* \pre chan and peer2 are both unlocked
*
* \retval 0 success
* \retval non-zero failure
*/
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
const char *userdefevname, const char *extra, struct ast_channel *peer2);
/*!
* \brief Helper struct for getting the fields out of a CEL event
*/
struct ast_cel_event_record {
/*!
* \brief struct ABI version
* \note This \b must be incremented when the struct changes.
*/
#define AST_CEL_EVENT_RECORD_VERSION 2
/*!
* \brief struct ABI version
* \note This \b must stay as the first member.
*/
uint32_t version;
enum ast_cel_event_type event_type;
struct timeval event_time;
const char *event_name;
const char *user_defined_name;
const char *caller_id_name;
const char *caller_id_num;
const char *caller_id_ani;
const char *caller_id_rdnis;
const char *caller_id_dnid;
const char *extension;
const char *context;
const char *channel_name;
const char *application_name;
const char *application_data;
const char *account_code;
const char *peer_account;
const char *unique_id;
const char *linked_id;
uint amaflag;
const char *user_field;
const char *peer;
const char *extra;
};
/*!
* \brief Fill in an ast_cel_event_record from a CEL event
*
* \param[in] event the CEL event
* \param[out] r the ast_cel_event_record to fill in
*
* \since 1.8
*
* \retval 0 success
* \retval non-zero failure
*/
int ast_cel_fill_record(const struct ast_event *event, struct ast_cel_event_record *r);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* __AST_CEL_H__ */