Wed Apr 6 11:29:54 2011

Asterisk developer's documentation


ccss.c File Reference

Call Completion Supplementary Services implementation. More...

#include "asterisk.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/ccss.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/event.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/causes.h"

Go to the source code of this file.

Data Structures

struct  ast_cc_config_params
struct  ast_cc_monitor_failure_data
struct  cc_agent_backend
struct  cc_agent_backends
struct  cc_callback_helper
struct  cc_control_payload
 The payload for an AST_CONTROL_CC frame. More...
struct  cc_core_instance
struct  cc_generic_agent_pvt
struct  cc_monitor_backend
struct  cc_monitor_backends
struct  cc_monitor_tree
 The "tree" of interfaces that is dialed. More...
struct  cc_recall_ds_data
struct  cc_state_change_args
struct  cc_status_response_args
struct  count_agents_cb_data
struct  count_monitors_cb_data
struct  dialed_cc_interfaces
struct  extension_child_dialstring
 Data regarding an extension monitor's child's dialstrings. More...
struct  extension_monitor_pvt
 Private data for an extension monitor. More...
struct  generic_monitor_instance
struct  generic_monitor_instance_list
struct  generic_monitor_pvt
 private data for generic device monitor More...
struct  generic_tp_cb_data

Defines

#define CC_MAX_AGENTS_DEFAULT   5
#define CC_MAX_MONITORS_DEFAULT   5
#define CC_OFFER_TIMER_DEFAULT   20
#define CC_RECALL_TIMER_DEFAULT   20
#define CCBS_AVAILABLE_TIMER_DEFAULT   4800
#define CCNR_AVAILABLE_TIMER_DEFAULT   7200
#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

Enumerations

enum  cc_state {
  CC_AVAILABLE, CC_CALLER_OFFERED, CC_CALLER_REQUESTED, CC_ACTIVE,
  CC_CALLEE_READY, CC_CALLER_BUSY, CC_RECALLING, CC_COMPLETE,
  CC_FAILED
}
 The states used in the CCSS core state machine. More...
enum  match_flags { MATCH_NO_REQUEST = (1 << 0), MATCH_REQUEST = (1 << 1) }

Functions

ast_cc_config_params__ast_cc_config_params_init (const char *file, int line, const char *function)
 Allocate and initialize an ast_cc_config_params structure.
static void agent_destroy (void *data)
static const char * agent_policy_to_str (enum ast_cc_agent_policies policy)
int ast_cc_agent_accept_request (int core_id, const char *const debug,...)
 Accept inbound CC request.
ast_cc_agentast_cc_agent_callback (int flags, ao2_callback_fn *function, void *args, const char *const type)
 Call a callback on all agents of a specific type.
int ast_cc_agent_caller_available (int core_id, const char *const debug,...)
 Indicate that a previously unavailable caller has become available.
int ast_cc_agent_caller_busy (int core_id, const char *debug,...)
 Indicate that the caller is busy.
int ast_cc_agent_recalling (int core_id, const char *const debug,...)
 Tell the CC core that a caller is currently recalling.
int ast_cc_agent_register (const struct ast_cc_agent_callbacks *callbacks)
 Register a set of agent callbacks with the core.
int ast_cc_agent_set_interfaces_chanvar (struct ast_channel *chan)
 Set the first level CC_INTERFACES channel variable for a channel.
int ast_cc_agent_status_response (int core_id, enum ast_device_state devstate)
 Response with a caller's current status.
void ast_cc_agent_unregister (const struct ast_cc_agent_callbacks *callbacks)
 Unregister a set of agent callbacks with the core.
int ast_cc_available_timer_expire (const void *data)
 Scheduler callback for available timer expiration.
int ast_cc_build_frame (struct ast_channel *chan, struct ast_cc_config_params *cc_params, const char *monitor_type, const char *const device_name, const char *const dialstring, enum ast_cc_service_type service, void *private_data, struct ast_frame *frame)
 Create a CC Control frame.
void ast_cc_busy_interface (struct ast_channel *inbound, struct ast_cc_config_params *cc_params, const char *monitor_type, const char *const device_name, const char *const dialstring, void *private_data)
 Callback made from ast_cc_callback for certain channel types.
void ast_cc_call_failed (struct ast_channel *incoming, struct ast_channel *outgoing, const char *const dialstring)
 Make CCBS available in the case that ast_call fails.
int ast_cc_call_init (struct ast_channel *chan, int *ignore_cc)
 Start the CC process on a call.
int ast_cc_callback (struct ast_channel *inbound, const char *const tech, const char *const dest, ast_cc_callback_fn callback)
 Run a callback for potential matching destinations.
int ast_cc_completed (struct ast_channel *chan, const char *const debug,...)
 Indicate recall has been acknowledged.
void ast_cc_config_params_destroy (struct ast_cc_config_params *params)
 Free memory from CCSS configuration params.
void ast_cc_copy_config_params (struct ast_cc_config_params *dest, const struct ast_cc_config_params *src)
 copy CCSS configuration parameters from one structure to another
void ast_cc_default_config_params (struct ast_cc_config_params *params)
 Set the specified CC config params to default values.
void ast_cc_extension_monitor_add_dialstring (struct ast_channel *incoming, const char *const dialstring, const char *const device_name)
 Add a child dialstring to an extension monitor.
int ast_cc_failed (int core_id, const char *const debug,...)
 Indicate failure has occurred.
int ast_cc_get_current_core_id (struct ast_channel *chan)
 Get the core id for the current call.
ast_cc_monitorast_cc_get_monitor_by_recall_core_id (const int core_id, const char *const device_name)
 Get the associated monitor given the device name and core_id.
int ast_cc_get_param (struct ast_cc_config_params *params, const char *const name, char *buf, size_t buf_len)
 get a CCSS configuration parameter, given its name
int ast_cc_init (void)
 Initialize CCSS.
int ast_cc_is_config_param (const char *const name)
 Is this a CCSS configuration parameter?
int ast_cc_is_recall (struct ast_channel *chan, int *core_id, const char *const monitor_type)
 Decide if a call to a particular channel is a CC recall.
int ast_cc_monitor_callee_available (const int core_id, const char *const debug,...)
 Alert the core that a device being monitored has become available.
int ast_cc_monitor_count (const char *const name, const char *const type)
 Return the number of outstanding CC requests to a specific device.
int ast_cc_monitor_failed (int core_id, const char *const monitor_name, const char *const debug,...)
 Indicate that a failure has occurred on a specific monitor.
int ast_cc_monitor_party_b_free (int core_id)
 Alert a caller that though the callee has become free, the caller himself is not and may not call back.
int ast_cc_monitor_register (const struct ast_cc_monitor_callbacks *callbacks)
 Register a set of monitor callbacks with the core.
int ast_cc_monitor_request_acked (int core_id, const char *const debug,...)
 Indicate that an outbound entity has accepted our CC request.
int ast_cc_monitor_status_request (int core_id)
 Request the status of a caller or callers.
int ast_cc_monitor_stop_ringing (int core_id)
 Alert a caller to stop ringing.
void ast_cc_monitor_unregister (const struct ast_cc_monitor_callbacks *callbacks)
 Unregister a set of monitor callbacks with the core.
int ast_cc_offer (struct ast_channel *caller_chan)
 Offer CC to a caller.
int ast_cc_request_is_within_limits (void)
 Check if the incoming CC request is within the bounds set by the cc_max_requests configuration option.
int ast_cc_set_param (struct ast_cc_config_params *params, const char *const name, const char *const value)
 set a CCSS configuration parameter, given its name
const char * ast_get_cc_agent_dialstring (struct ast_cc_config_params *config)
 Get the cc_agent_dialstring.
enum ast_cc_agent_policies ast_get_cc_agent_policy (struct ast_cc_config_params *config)
 Get the cc_agent_policy.
const char * ast_get_cc_callback_macro (struct ast_cc_config_params *config)
 Get the name of the callback_macro.
unsigned int ast_get_cc_max_agents (struct ast_cc_config_params *config)
 Get the cc_max_agents.
unsigned int ast_get_cc_max_monitors (struct ast_cc_config_params *config)
 Get the cc_max_monitors.
enum ast_cc_monitor_policies ast_get_cc_monitor_policy (struct ast_cc_config_params *config)
 Get the cc_monitor_policy.
unsigned int ast_get_cc_offer_timer (struct ast_cc_config_params *config)
 Get the cc_offer_timer.
unsigned int ast_get_cc_recall_timer (struct ast_cc_config_params *config)
 Get the cc_recall_timer.
unsigned int ast_get_ccbs_available_timer (struct ast_cc_config_params *config)
 Get the ccbs_available_timer.
unsigned int ast_get_ccnr_available_timer (struct ast_cc_config_params *config)
 Get the ccnr_available_timer.
void ast_handle_cc_control_frame (struct ast_channel *inbound, struct ast_channel *outbound, void *frame_data)
 Properly react to a CC control frame.
void ast_ignore_cc (struct ast_channel *chan)
 Mark the channel to ignore further CC activity.
int ast_queue_cc_frame (struct ast_channel *chan, const char *monitor_type, const char *const dialstring, enum ast_cc_service_type service, void *private_data)
 Queue an AST_CONTROL_CC frame.
void ast_set_cc_agent_dialstring (struct ast_cc_config_params *config, const char *const value)
 Set the cc_agent_dialstring.
int ast_set_cc_agent_policy (struct ast_cc_config_params *config, enum ast_cc_agent_policies value)
 Set the cc_agent_policy.
void ast_set_cc_callback_macro (struct ast_cc_config_params *config, const char *const value)
 Set the callback_macro name.
int ast_set_cc_interfaces_chanvar (struct ast_channel *chan, const char *const extension)
 Set the CC_INTERFACES channel variable for a channel using an extension as a starting point.
void ast_set_cc_max_agents (struct ast_cc_config_params *config, unsigned int value)
 Set the cc_max_agents.
void ast_set_cc_max_monitors (struct ast_cc_config_params *config, unsigned int value)
 Set the cc_max_monitors.
int ast_set_cc_monitor_policy (struct ast_cc_config_params *config, enum ast_cc_monitor_policies value)
 Set the cc_monitor_policy.
void ast_set_cc_offer_timer (struct ast_cc_config_params *config, unsigned int value)
 Set the cc_offer_timer.
void ast_set_cc_recall_timer (struct ast_cc_config_params *config, unsigned int value)
 Set the cc_recall_timer.
void ast_set_ccbs_available_timer (struct ast_cc_config_params *config, unsigned int value)
 Set the ccbs_available_timer.
void ast_set_ccnr_available_timer (struct ast_cc_config_params *config, unsigned int value)
 Set the ccnr_available_timer.
int ast_setup_cc_recall_datastore (struct ast_channel *chan, const int core_id)
 Set up a CC recall datastore on a channel.
static void build_cc_interfaces_chanvar (struct ast_cc_monitor *starting_point, struct ast_str *str)
static void call_destructor_with_no_monitor (const char *const monitor_type, void *private_data)
static void cancel_available_timer (struct cc_core_instance *core_instance)
static int cc_active (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_agent_callback_helper (void *obj, void *args, int flags)
static struct ast_cc_agentcc_agent_init (struct ast_channel *caller_chan, const char *const caller_name, const int core_id, struct cc_monitor_tree *interface_tree)
static int cc_available (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_build_payload (struct ast_channel *chan, struct ast_cc_config_params *cc_params, const char *monitor_type, const char *const device_name, const char *dialstring, enum ast_cc_service_type service, void *private_data, struct cc_control_payload *payload)
static int cc_callee_ready (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_caller_busy (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_caller_offered (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_caller_requested (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static int cc_cli_output_status (void *data)
static void cc_cli_print_monitor_stats (struct ast_cc_monitor *monitor, int fd, int parent_id)
static int cc_complete (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static struct cc_core_instancecc_core_init_instance (struct ast_channel *caller_chan, struct cc_monitor_tree *called_tree, const int core_id, struct cc_control_payload *cc_data)
static int cc_core_instance_cmp_fn (void *obj, void *arg, int flags)
static void cc_core_instance_destructor (void *data)
static int cc_core_instance_hash_fn (const void *obj, const int flags)
static struct ast_cc_monitorcc_device_monitor_init (const char *const device_name, const char *const dialstring, const struct cc_control_payload *cc_data, int core_id)
static int cc_do_state_change (void *datap)
static void cc_extension_monitor_change_is_valid (struct cc_core_instance *core_instance, unsigned int parent_id, const char *const device_name, int is_valid)
static void cc_extension_monitor_destructor (void *private_data)
static struct ast_cc_monitorcc_extension_monitor_init (const char *const exten, const char *const context, const unsigned int parent_id)
static int cc_failed (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static void cc_generic_agent_ack (struct ast_cc_agent *agent)
static void cc_generic_agent_destructor (struct ast_cc_agent *agent)
static int cc_generic_agent_init (struct ast_cc_agent *agent, struct ast_channel *chan)
static int cc_generic_agent_recall (struct ast_cc_agent *agent)
static int cc_generic_agent_start_monitoring (struct ast_cc_agent *agent)
static int cc_generic_agent_start_offer_timer (struct ast_cc_agent *agent)
static int cc_generic_agent_status_request (struct ast_cc_agent *agent)
static int cc_generic_agent_stop_offer_timer (struct ast_cc_agent *agent)
static int cc_generic_agent_stop_ringing (struct ast_cc_agent *agent)
static int cc_generic_monitor_cancel_available_timer (struct ast_cc_monitor *monitor, int *sched_id)
static void cc_generic_monitor_destructor (void *private_data)
static int cc_generic_monitor_request_cc (struct ast_cc_monitor *monitor, int *available_timer_id)
static int cc_generic_monitor_suspend (struct ast_cc_monitor *monitor)
static int cc_generic_monitor_unsuspend (struct ast_cc_monitor *monitor)
static void cc_interface_destroy (void *data)
static void cc_interface_tree_destroy (void *data)
static int cc_interfaces_datastore_init (struct ast_channel *chan)
static void cc_monitor_destroy (void *data)
static int cc_monitor_failed (void *data)
static int cc_offer (const int core_id, const char *const debug,...)
static int cc_party_b_free (void *data)
static void cc_recall_ds_destroy (void *data)
static void * cc_recall_ds_duplicate (void *data)
static int cc_recalling (struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
static void * cc_ref (void *obj, const char *debug)
static int cc_request_state_change (enum cc_state state, const int core_id, const char *debug, va_list ap)
static const char * cc_service_to_string (enum ast_cc_service_type service)
static const char * cc_state_to_string (enum cc_state state)
static int cc_status_request (void *data)
static int cc_status_response (void *data)
static int cc_stop_ringing (void *data)
static void cc_unique_append (struct ast_str *str, const char *const dialstring)
static void * cc_unref (void *obj, const char *debug)
static int cccancel_exec (struct ast_channel *chan, const char *data)
static int ccreq_exec (struct ast_channel *chan, const char *data)
static void check_callback_sanity (const struct ast_cc_agent_callbacks *callbacks)
static char * complete_core_id (const char *line, const char *word, int pos, int state)
static long count_agents (const char *const caller, const int core_id_exception)
static int count_agents_cb (void *obj, void *arg, void *data, int flags)
static int count_monitors_cb (void *obj, void *arg, int flags)
static struct generic_monitor_instance_listcreate_new_generic_list (struct ast_cc_monitor *monitor)
static void dialed_cc_interfaces_destroy (void *data)
static void * dialed_cc_interfaces_duplicate (void *data)
static struct extension_monitor_pvtextension_monitor_pvt_init (void)
static struct ast_cc_agent_callbacksfind_agent_callbacks (struct ast_channel *chan)
static struct cc_core_instancefind_cc_core_instance (const int core_id)
static struct generic_monitor_instance_listfind_generic_monitor_instance_list (const char *const device_name)
static struct ast_cc_monitor_callbacksfind_monitor_callbacks (const char *const type)
static void generic_agent_devstate_cb (const struct ast_event *event, void *userdata)
static int generic_agent_devstate_unsubscribe (void *data)
static int generic_monitor_cmp_fn (void *obj, void *arg, int flags)
static void generic_monitor_devstate_cb (const struct ast_event *event, void *userdata)
static int generic_monitor_devstate_tp_cb (void *data)
static int generic_monitor_hash_fn (const void *obj, const int flags)
static void generic_monitor_instance_list_destructor (void *obj)
static void * generic_recall (void *data)
static char * handle_cc_kill (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cc_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int has_device_monitors (struct cc_core_instance *core_instance)
 check if the core instance has any device monitors
static void initialize_cc_max_requests (void)
static int is_state_change_valid (enum cc_state current_state, const enum cc_state new_state, struct ast_cc_agent *agent)
static int kill_cores (void *obj, void *arg, int flags)
static void kill_duplicate_offers (char *caller)
static int match_agent (void *obj, void *arg, void *data, int flags)
static const char * monitor_policy_to_str (enum ast_cc_monitor_policies policy)
static int offer_timer_expire (const void *data)
static int print_stats_cb (void *obj, void *arg, int flags)
static void request_cc (struct cc_core_instance *core_instance)
static enum ast_cc_agent_policies str_to_agent_policy (const char *const value)
static enum ast_cc_monitor_policies str_to_monitor_policy (const char *const value)
static void suspend (struct cc_core_instance *core_instance)
static void unsuspend (struct cc_core_instance *core_instance)

Variables

static struct ast_cli_entry cc_cli []
static struct ao2_containercc_core_instances
static const int CC_CORE_INSTANCES_BUCKETS = 17
static struct ast_taskprocessorcc_core_taskprocessor
static struct ast_cc_config_params cc_default_params
static int cc_logger_level
static const char * CC_LOGGER_LEVEL_NAME = "CC"
static int cc_request_count
static struct ast_sched_threadcc_sched_thread
struct {
   enum ast_cc_service_type   service
   const char *   service_string
cc_service_to_string_map []
struct {
   enum cc_state   state
   const char *   state_string
cc_state_to_string_map []
static const char * cccancel_app = "CallCompletionCancel"
static const char * ccreq_app = "CallCompletionRequest"
static int core_id_counter
static int dialed_cc_interface_counter
static struct ast_datastore_info dialed_cc_interfaces_info
static struct ast_cc_agent_callbacks generic_agent_callbacks
static struct ast_cc_monitor_callbacks generic_monitor_cbs
ao2_containergeneric_monitors
static unsigned int global_cc_max_requests
static struct ast_datastore_info recall_ds_info
static int(*const []) state_change_funcs (struct cc_core_instance *, struct cc_state_change_args *, enum cc_state previous_state)


Detailed Description

Call Completion Supplementary Services implementation.

Author:
Mark Michelson <mmichelson@digium.com>

Definition in file ccss.c.


Define Documentation

#define CC_MAX_AGENTS_DEFAULT   5

Definition at line 508 of file ccss.c.

#define CC_MAX_MONITORS_DEFAULT   5

Definition at line 509 of file ccss.c.

#define CC_OFFER_TIMER_DEFAULT   20

Definition at line 504 of file ccss.c.

#define CC_RECALL_TIMER_DEFAULT   20

Definition at line 507 of file ccss.c.

#define CCBS_AVAILABLE_TIMER_DEFAULT   4800

Definition at line 506 of file ccss.c.

#define CCNR_AVAILABLE_TIMER_DEFAULT   7200

Definition at line 505 of file ccss.c.

#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

Definition at line 510 of file ccss.c.

Referenced by initialize_cc_max_requests().


Enumeration Type Documentation

enum cc_state

The states used in the CCSS core state machine.

Since:
1.8
For more information, see doc/CCSS_architecture.pdf
Enumerator:
CC_AVAILABLE  Entered when it is determined that CCSS may be used for the call
CC_CALLER_OFFERED  Entered when a CCSS agent has offered CCSS to a caller
CC_CALLER_REQUESTED  Entered when a CCSS agent confirms that a caller has requested CCSS
CC_ACTIVE  Entered when a CCSS monitor confirms acknowledgment of an outbound CCSS request
CC_CALLEE_READY  Entered when a CCSS monitor alerts the core that the called party has become available
CC_CALLER_BUSY  Entered when a CCSS agent alerts the core that the calling party may not be recalled because he is unavailable
CC_RECALLING  Entered when a CCSS agent alerts the core that the calling party is attempting to recall the called party
CC_COMPLETE  Entered when an application alerts the core that the calling party's recall attempt has had a call progress response indicated
CC_FAILED  Entered any time that something goes wrong during the process, thus resulting in the failure of the attempted CCSS transaction. Note also that cancellations of CC are treated as failures.

Definition at line 138 of file ccss.c.

00138               {
00139    /*! Entered when it is determined that CCSS may be used for the call */
00140    CC_AVAILABLE,
00141    /*! Entered when a CCSS agent has offered CCSS to a caller */
00142    CC_CALLER_OFFERED,
00143    /*! Entered when a CCSS agent confirms that a caller has
00144     * requested CCSS */
00145    CC_CALLER_REQUESTED,
00146    /*! Entered when a CCSS monitor confirms acknowledgment of an
00147     * outbound CCSS request */
00148    CC_ACTIVE,
00149    /*! Entered when a CCSS monitor alerts the core that the called party
00150     * has become available */
00151    CC_CALLEE_READY,
00152    /*! Entered when a CCSS agent alerts the core that the calling party
00153     * may not be recalled because he is unavailable
00154     */
00155    CC_CALLER_BUSY,
00156    /*! Entered when a CCSS agent alerts the core that the calling party
00157     * is attempting to recall the called party
00158     */
00159    CC_RECALLING,
00160    /*! Entered when an application alerts the core that the calling party's
00161     * recall attempt has had a call progress response indicated
00162     */
00163    CC_COMPLETE,
00164    /*! Entered any time that something goes wrong during the process, thus
00165     * resulting in the failure of the attempted CCSS transaction. Note also
00166     * that cancellations of CC are treated as failures.
00167     */
00168    CC_FAILED,
00169 };

enum match_flags

Enumerator:
MATCH_NO_REQUEST 
MATCH_REQUEST 

Definition at line 426 of file ccss.c.

00426                  {
00427    /* Only match agents that have not yet
00428     * made a CC request
00429     */
00430    MATCH_NO_REQUEST = (1 << 0),
00431    /* Only match agents that have made
00432     * a CC request
00433     */
00434    MATCH_REQUEST = (1 << 1),
00435 };


Function Documentation

struct ast_cc_config_params* __ast_cc_config_params_init ( const char *  file,
int  line,
const char *  function 
)

Allocate and initialize an ast_cc_config_params structure.

Note:
Reasonable default values are chosen for the parameters upon allocation.
Return values:
NULL Unable to allocate the structure
non-NULL A pointer to the newly allocated and initialized structure

Definition at line 530 of file ccss.c.

References __ast_malloc(), ast_cc_default_config_params(), and ast_malloc.

00531 {
00532 #if defined(__AST_DEBUG_MALLOC)
00533    struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
00534 #else
00535    struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
00536 #endif
00537 
00538    if (!params) {
00539       return NULL;
00540    }
00541 
00542    ast_cc_default_config_params(params);
00543    return params;
00544 }

static void agent_destroy ( void *  data  )  [static]

Definition at line 2215 of file ccss.c.

References ast_cc_config_params_destroy(), ast_cc_agent::callbacks, ast_cc_agent::cc_params, and ast_cc_agent_callbacks::destructor.

Referenced by cc_agent_init().

02216 {
02217    struct ast_cc_agent *agent = data;
02218 
02219    if (agent->callbacks) {
02220       agent->callbacks->destructor(agent);
02221    }
02222    ast_cc_config_params_destroy(agent->cc_params);
02223 }

static const char* agent_policy_to_str ( enum ast_cc_agent_policies  policy  )  [static]

Definition at line 581 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, and AST_CC_AGENT_NEVER.

Referenced by ast_cc_get_param().

00582 {
00583    switch (policy) {
00584    case AST_CC_AGENT_NEVER:
00585       return "never";
00586    case AST_CC_AGENT_NATIVE:
00587       return "native";
00588    case AST_CC_AGENT_GENERIC:
00589       return "generic";
00590    default:
00591       /* This should never happen... */
00592       return "";
00593    }
00594 }

int ast_cc_agent_accept_request ( int  core_id,
const char *const   debug,
  ... 
)

Accept inbound CC request.

Since:
1.8
When a caller requests CC, this function should be called to let the core know that the request has been accepted.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3391 of file ccss.c.

References CC_CALLER_REQUESTED, and cc_request_state_change().

Referenced by ccreq_exec(), handle_cc_subscribe(), and sig_pri_handle_cis_subcmds().

03392 {
03393    va_list ap;
03394    int res;
03395 
03396    va_start(ap, debug);
03397    res = cc_request_state_change(CC_CALLER_REQUESTED, core_id, debug, ap);
03398    va_end(ap);
03399    return res;
03400 }

struct ast_cc_agent* ast_cc_agent_callback ( int  flags,
ao2_callback_fn function,
void *  arg,
const char *const   type 
)

Call a callback on all agents of a specific type.

Since the container of CC core instances is private, and so are the items which the container contains, we have to provide an ao2_callback-like method so that a specific agent may be found or so that an operation can be made on all agents of a particular type. The first three arguments should be familiar to anyone who has used ao2_callback. The final argument is the type of agent you wish to have the callback called on.

Note:
Since agents are refcounted, and this function returns a reference to the agent, it is imperative that you decrement the refcount of the agent once you have finished using it.
Parameters:
flags astobj2 search flags
function an ao2 callback function to call
arg the argument to the callback function
type The type of agents to call the callback on

Definition at line 413 of file ccss.c.

References cc_core_instance::agent, ao2_t_callback, cc_agent_callback_helper(), cc_core_instances, cc_ref(), cc_unref(), and cc_callback_helper::function.

Referenced by find_sip_cc_agent_by_notify_uri(), find_sip_cc_agent_by_original_callid(), and find_sip_cc_agent_by_subscribe_uri().

00414 {
00415    struct cc_callback_helper helper = {.function = function, .args = args, .type = type};
00416    struct cc_core_instance *core_instance;
00417    if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
00418                "Calling provided agent callback function"))) {
00419       struct ast_cc_agent *agent = cc_ref(core_instance->agent, "An outside entity needs the agent");
00420       cc_unref(core_instance, "agent callback done with the core_instance");
00421       return agent;
00422    }
00423    return NULL;
00424 }

int ast_cc_agent_caller_available ( int  core_id,
const char *const   debug,
  ... 
)

Indicate that a previously unavailable caller has become available.

Since:
1.8
If a monitor is suspended due to a caller becoming unavailable, then this function should be called to indicate that the caller has become available.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3435 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

Referenced by cc_esc_publish_handler(), generic_agent_devstate_cb(), and sig_pri_handle_cis_subcmds().

03436 {
03437    va_list ap;
03438    int res;
03439 
03440    va_start(ap, debug);
03441    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03442    va_end(ap);
03443    return res;
03444 }

int ast_cc_agent_caller_busy ( int  core_id,
const char *const   debug,
  ... 
)

Indicate that the caller is busy.

Since:
1.8
When the callee makes it known that he is available, the core will let the caller's channel driver know that it may attempt to let the caller know to attempt a recall. If the channel driver can detect, though, that the caller is busy, then the channel driver should call this function to let the CC core know.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3424 of file ccss.c.

References CC_CALLER_BUSY, and cc_request_state_change().

Referenced by cc_esc_publish_handler(), cc_generic_agent_recall(), sig_pri_handle_cis_subcmds(), and sip_cc_agent_recall().

03425 {
03426    va_list ap;
03427    int res;
03428 
03429    va_start(ap, debug);
03430    res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
03431    va_end(ap);
03432    return res;
03433 }

int ast_cc_agent_recalling ( int  core_id,
const char *const   debug,
  ... 
)

Tell the CC core that a caller is currently recalling.

Since:
1.8
The main purpose of this is so that the core can alert the monitor to stop its available timer since the caller has begun its recall phase.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3446 of file ccss.c.

References CC_RECALLING, and cc_request_state_change().

Referenced by generic_recall(), get_destination(), and sig_pri_handle_subcmds().

03447 {
03448    va_list ap;
03449    int res;
03450 
03451    va_start(ap, debug);
03452    res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
03453    va_end(ap);
03454    return res;
03455 }

int ast_cc_agent_register ( const struct ast_cc_agent_callbacks callbacks  ) 

Register a set of agent callbacks with the core.

Since:
1.8
This is made so that at agent creation time, the proper callbacks may be installed and the proper .init callback may be called for the monitor to establish private data.

Parameters:
callbacks The callbacks used by the agent implementation
Return values:
0 Successfully registered
-1 Failure to register

Definition at line 917 of file ccss.c.

References ast_calloc, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and cc_monitor_backend::next.

Referenced by ast_cc_init(), and load_module().

00918 {
00919    struct cc_agent_backend *backend = ast_calloc(1, sizeof(*backend));
00920 
00921    if (!backend) {
00922       return -1;
00923    }
00924 
00925    backend->callbacks = callbacks;
00926    AST_RWLIST_WRLOCK(&cc_agent_backends);
00927    AST_RWLIST_INSERT_TAIL(&cc_agent_backends, backend, next);
00928    AST_RWLIST_UNLOCK(&cc_agent_backends);
00929    return 0;
00930 }

int ast_cc_agent_set_interfaces_chanvar ( struct ast_channel chan  ) 

Set the first level CC_INTERFACES channel variable for a channel.

Since:
1.8
Note:
Implementers of protocol-specific CC agents should call this function after calling ast_setup_cc_recall_datastore.

This function will lock the channel as well as the list of monitors stored on the channel's CC recall datastore, though neither are held at the same time. Callers of this function should be aware of potential lock ordering problems that may arise.

The CC_INTERFACES channel variable will have the interfaces that should be called back for a specific PBX instance.

Parameters:
chan The channel to set the CC_INTERFACES variable on

Definition at line 3246 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_free, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log_dynamic_level, ast_str_buffer(), ast_str_create(), build_cc_interfaces_chanvar(), cc_recall_ds_data::core_id, ast_datastore::data, cc_recall_ds_data::interface_tree, monitor, pbx_builtin_setvar_helper(), recall_ds_info, and str.

Referenced by generic_recall(), handle_request_invite(), and sig_pri_handle_subcmds().

03247 {
03248    struct ast_datastore *recall_datastore;
03249    struct cc_monitor_tree *interface_tree;
03250    struct ast_cc_monitor *monitor;
03251    struct cc_recall_ds_data *recall_data;
03252    struct ast_str *str = ast_str_create(64);
03253    int core_id;
03254 
03255    if (!str) {
03256       return -1;
03257    }
03258 
03259    ast_channel_lock(chan);
03260    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03261       ast_channel_unlock(chan);
03262       ast_free(str);
03263       return -1;
03264    }
03265    recall_data = recall_datastore->data;
03266    interface_tree = recall_data->interface_tree;
03267    core_id = recall_data->core_id;
03268    ast_channel_unlock(chan);
03269 
03270    AST_LIST_LOCK(interface_tree);
03271    monitor = AST_LIST_FIRST(interface_tree);
03272    build_cc_interfaces_chanvar(monitor, str);
03273    AST_LIST_UNLOCK(interface_tree);
03274 
03275    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03276    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03277          core_id, ast_str_buffer(str));
03278 
03279    ast_free(str);
03280    return 0;
03281 }

int ast_cc_agent_status_response ( int  core_id,
enum ast_device_state  devstate 
)

Response with a caller's current status.

When an ISDN PTMP monitor requests the caller's status, the agent must respond to the request using this function. For simplicity it is recommended that the devstate parameter be one of AST_DEVICE_INUSE or AST_DEVICE_NOT_INUSE.

Parameters:
core_id The core ID of the CC transaction
devstate The current state of the caller to which the agent pertains
Return values:
0 Successfully responded with our status
-1 Failed to respond with our status

Definition at line 3711 of file ccss.c.

References args, ast_calloc, ast_free, ast_taskprocessor_push(), cc_core_taskprocessor, cc_status_response(), cc_unref(), and find_cc_core_instance().

Referenced by cc_generic_agent_status_request(), sig_pri_handle_cis_subcmds(), and sip_cc_agent_status_request().

03712 {
03713    struct cc_status_response_args *args;
03714    struct cc_core_instance *core_instance;
03715    int res;
03716 
03717    args = ast_calloc(1, sizeof(*args));
03718    if (!args) {
03719       return -1;
03720    }
03721 
03722    core_instance = find_cc_core_instance(core_id);
03723    if (!core_instance) {
03724       ast_free(args);
03725       return -1;
03726    }
03727 
03728    args->core_instance = core_instance;
03729    args->devstate = devstate;
03730 
03731    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
03732    if (res) {
03733       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03734       ast_free(args);
03735    }
03736    return res;
03737 }

void ast_cc_agent_unregister ( const struct ast_cc_agent_callbacks callbacks  ) 

Unregister a set of agent callbacks with the core.

Since:
1.8
If a module which makes use of a CC agent is unloaded, then it may unregister its agent callbacks with the core.

Parameters:
callbacks The callbacks used by the agent implementation
Return values:
0 Successfully unregistered
-1 Failure to unregister

Definition at line 932 of file ccss.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cc_monitor_backend::callbacks, cc_agent_backend::callbacks, and cc_monitor_backend::next.

Referenced by __unload_module(), and unload_module().

00933 {
00934    struct cc_agent_backend *backend;
00935    AST_RWLIST_WRLOCK(&cc_agent_backends);
00936    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_agent_backends, backend, next) {
00937       if (backend->callbacks == callbacks) {
00938          AST_RWLIST_REMOVE_CURRENT(next);
00939          ast_free(backend);
00940          break;
00941       }
00942    }
00943    AST_RWLIST_TRAVERSE_SAFE_END;
00944    AST_RWLIST_UNLOCK(&cc_agent_backends);
00945 }

int ast_cc_available_timer_expire ( const void *  data  ) 

Scheduler callback for available timer expiration.

Since:
1.8
Note:
When arming the available timer from within a device monitor, you MUST use this function as the callback for the scheduler.
Parameters:
data A reference to the CC monitor on which the timer was running.

Definition at line 1184 of file ccss.c.

References ast_cc_monitor_failed(), cc_unref(), and monitor.

Referenced by cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

01185 {
01186    struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
01187    int res;
01188    monitor->available_timer_id = -1;
01189    res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
01190    cc_unref(monitor, "Unref reference from scheduler\n");
01191    return res;
01192 }

int ast_cc_build_frame ( struct ast_channel chan,
struct ast_cc_config_params cc_params,
const char *  monitor_type,
const char *const   device_name,
const char *const   dialstring,
enum ast_cc_service_type  service,
void *  private_data,
struct ast_frame frame 
)

Create a CC Control frame.

Since:
1.8
chan_dahdi is weird. It doesn't seem to actually queue frames when it needs to tell an application something. Instead it wakes up, tells the application that it has data ready, and then based on set flags, creates the proper frame type. For chan_dahdi, we provide this function. It provides us the data we need, and we'll make its frame for it.

Parameters:
chan A channel involved in the call. What we want is on a datastore on both incoming and outgoing so either may be provided
cc_params The CC configuration parameters for the outbound target
monitor_type The type of monitor to use when CC is requested
device_name The name of the outbound target device.
dialstring The dial string used when calling this specific interface
service What kind of CC service is being offered. (CCBS/CCNR/etc...)
private_data If a native monitor is being used, and some channel-driver-specific private data has been allocated, then this parameter should contain a pointer to that data. If using a generic monitor, this parameter should remain NULL. Note that if this function should fail at some point, it is the responsibility of the caller to free the private data upon return.
[out] frame The frame we will be returning to the caller. It is vital that ast_frame_free be called on this frame since the payload will be allocated on the heap.
Return values:
-1 Failure. At some point there was a failure. Do not attempt to use the frame in this case.
0 Success

Definition at line 3794 of file ccss.c.

References ast_calloc, AST_CONTROL_CC, AST_FRAME_CONTROL, ast_free, AST_MALLOCD_DATA, cc_build_payload(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame_subclass::integer, ast_frame::mallocd, ast_frame::ptr, and ast_frame::subclass.

Referenced by ast_queue_cc_frame().

03798 {
03799    struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));
03800 
03801    if (!payload) {
03802       return -1;
03803    }
03804    if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
03805       /* Something screwed up, we can't make a frame with this */
03806       ast_free(payload);
03807       return -1;
03808    }
03809    frame->frametype = AST_FRAME_CONTROL;
03810    frame->subclass.integer = AST_CONTROL_CC;
03811    frame->data.ptr = payload;
03812    frame->datalen = sizeof(*payload);
03813    frame->mallocd = AST_MALLOCD_DATA;
03814    return 0;
03815 }

void ast_cc_busy_interface ( struct ast_channel inbound,
struct ast_cc_config_params cc_params,
const char *  monitor_type,
const char *const   device_name,
const char *const   dialstring,
void *  private_data 
)

Callback made from ast_cc_callback for certain channel types.

Since:
1.8
Parameters:
inbound Incoming asterisk channel.
cc_params The CC configuration parameters for the outbound target
monitor_type The type of monitor to use when CC is requested
device_name The name of the outbound target device.
dialstring The dial string used when calling this specific interface
private_data If a native monitor is being used, and some channel-driver-specific private data has been allocated, then this parameter should contain a pointer to that data. If using a generic monitor, this parameter should remain NULL. Note that if this function should fail at some point, it is the responsibility of the caller to free the private data upon return.
For channel types that fail ast_request when the device is busy, we call into the channel driver with ast_cc_callback. This is the callback that is called in that case for each device found which could have been returned by ast_request.

This function creates a CC control frame payload, simulating the act of reading it from the nonexistent outgoing channel's frame queue. We then handle this simulated frame just as we would a normal CC frame which had actually been queued by the channel driver.

Definition at line 3850 of file ccss.c.

References AST_CC_CCBS, ast_handle_cc_control_frame(), call_destructor_with_no_monitor(), and cc_build_payload().

Referenced by dial_exec_full().

03852 {
03853    struct cc_control_payload payload;
03854    if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
03855       /* Something screwed up. Don't try to handle this payload */
03856       call_destructor_with_no_monitor(monitor_type, private_data);
03857       return;
03858    }
03859    ast_handle_cc_control_frame(inbound, NULL, &payload);
03860 }

void ast_cc_call_failed ( struct ast_channel incoming,
struct ast_channel outgoing,
const char *const   dialstring 
)

Make CCBS available in the case that ast_call fails.

Since:
1.8
In some situations, notably if a call-limit is reached in SIP, ast_call will fail due to Asterisk's knowing that the desired device is currently busy. In such a situation, CCBS should be made available to the caller.

One caveat is that this may only be used if generic monitoring is being used. The reason is that since Asterisk determined that the device was busy without actually placing a call to it, the far end will have no idea what call we are requesting call completion for if we were to send a call completion request.

Definition at line 3817 of file ccss.c.

References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CC_CCBS, AST_CC_GENERIC_MONITOR_TYPE, AST_CC_MONITOR_GENERIC, ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_get_cc_monitor_policy(), ast_handle_cc_control_frame(), cc_build_payload(), and ast_channel::hangupcause.

Referenced by dial_exec_full().

03818 {
03819    char device_name[AST_CHANNEL_NAME];
03820    struct cc_control_payload payload;
03821    struct ast_cc_config_params *cc_params;
03822 
03823    if (outgoing->hangupcause != AST_CAUSE_BUSY && outgoing->hangupcause != AST_CAUSE_CONGESTION) {
03824       /* It doesn't make sense to try to offer CCBS to the caller if the reason for ast_call
03825        * failing is something other than busy or congestion
03826        */
03827       return;
03828    }
03829 
03830    cc_params = ast_channel_get_cc_config_params(outgoing);
03831    if (!cc_params) {
03832       return;
03833    }
03834    if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
03835       /* This sort of CCBS only works if using generic CC. For native, we would end up sending
03836        * a CC request for a non-existent call. The far end will reject this every time
03837        */
03838       return;
03839    }
03840 
03841    ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
03842    if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
03843       dialstring, AST_CC_CCBS, NULL, &payload)) {
03844       /* Something screwed up, we can't make a frame with this */
03845       return;
03846    }
03847    ast_handle_cc_control_frame(incoming, outgoing, &payload);
03848 }

int ast_cc_call_init ( struct ast_channel chan,
int *  ignore_cc 
)

Start the CC process on a call.

Since:
1.8
Whenever a CC-capable application, such as Dial, wishes to engage in CC activity, it initiates the process by calling this function. If the CC core should discover that a previous application has called ast_ignore_cc on this channel or a "parent" channel, then the value of the ignore_cc integer passed in will be set nonzero.

The ignore_cc parameter is a convenience parameter. It can save an application the trouble of trying to call CC APIs when it knows that it should just ignore further attempts at CC actions.

Parameters:
chan The inbound channel calling the CC-capable application.
[out] ignore_cc Will be set non-zero if no further CC actions need to be taken
Return values:
0 Success
-1 Failure

Definition at line 2091 of file ccss.c.

References AST_CC_AGENT_NEVER, ast_channel_datastore_find(), ast_channel_get_cc_config_params(), ast_channel_lock, ast_channel_unlock, ast_get_cc_agent_policy(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log_dynamic_level, cc_extension_monitor_init(), cc_interfaces_datastore_init(), cc_ref(), cc_unref(), ast_channel::context, dialed_cc_interfaces::core_id, ast_datastore::data, dialed_cc_interfaces::dial_parent_id, dialed_cc_interfaces_info, ast_channel::exten, dialed_cc_interfaces::ignore, dialed_cc_interfaces::interface_tree, ast_channel::macrocontext, ast_channel::macroexten, monitor, ast_channel::name, cc_monitor_backend::next, and S_OR.

Referenced by dial_exec_full().

02092 {
02093    /* There are three situations to deal with here:
02094     *
02095     * 1. The channel does not have a dialed_cc_interfaces datastore on
02096     * it. This means that this is the first time that Dial has
02097     * been called. We need to create/initialize the datastore.
02098     *
02099     * 2. The channel does have a cc_interface datastore on it and
02100     * the "ignore" indicator is 0. This means that a Local channel
02101     * was called by a "parent" dial. We can check the datastore's
02102     * parent field to see who the root of this particular dial tree
02103     * is.
02104     *
02105     * 3. The channel does have a cc_interface datastore on it and
02106     * the "ignore" indicator is 1. This means that a second Dial call
02107     * is being made from an extension. In this case, we do not
02108     * want to make any additions/modifications to the datastore. We
02109     * will instead set a flag to indicate that CCSS is completely
02110     * disabled for this Dial attempt.
02111     */
02112 
02113    struct ast_datastore *cc_interfaces_datastore;
02114    struct dialed_cc_interfaces *interfaces;
02115    struct ast_cc_monitor *monitor;
02116    struct ast_cc_config_params *cc_params;
02117 
02118    ast_channel_lock(chan);
02119 
02120    cc_params = ast_channel_get_cc_config_params(chan);
02121    if (!cc_params) {
02122       ast_channel_unlock(chan);
02123       return -1;
02124    }
02125    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
02126       /* We can't offer CC to this caller anyway, so don't bother with CC on this call
02127        */
02128       *ignore_cc = 1;
02129       ast_channel_unlock(chan);
02130       ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", chan->name);
02131       return 0;
02132    }
02133 
02134    if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02135       /* Situation 1 has occurred */
02136       ast_channel_unlock(chan);
02137       return cc_interfaces_datastore_init(chan);
02138    }
02139    interfaces = cc_interfaces_datastore->data;
02140    ast_channel_unlock(chan);
02141 
02142    if (interfaces->ignore) {
02143       /* Situation 3 has occurred */
02144       *ignore_cc = 1;
02145       ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
02146       return 0;
02147    }
02148 
02149    /* Situation 2 has occurred */
02150    if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten),
02151          S_OR(chan->macrocontext, chan->context), interfaces->dial_parent_id))) {
02152       return -1;
02153    }
02154    monitor->core_id = interfaces->core_id;
02155    AST_LIST_LOCK(interfaces->interface_tree);
02156    cc_ref(monitor, "monitor tree's reference to the monitor");
02157    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
02158    AST_LIST_UNLOCK(interfaces->interface_tree);
02159    interfaces->dial_parent_id = monitor->id;
02160    cc_unref(monitor, "Unref monitor's allocation reference");
02161    return 0;
02162 }

int ast_cc_callback ( struct ast_channel inbound,
const char *const   tech,
const char *const   dest,
ast_cc_callback_fn  callback 
)

Run a callback for potential matching destinations.

Since:
1.8
Note:
See the explanation in ast_channel_tech::cc_callback for more details.
Parameters:
inbound 
tech Channel technology to use
dest Channel/group/peer or whatever the specific technology uses
callback Function to call when a target is reached
Return values:
Always 0, I guess.

Definition at line 3862 of file ccss.c.

References ast_get_channel_tech(), and ast_channel_tech::cc_callback.

Referenced by dial_exec_full().

03863 {
03864    const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);
03865 
03866    if (chantech && chantech->cc_callback) {
03867       chantech->cc_callback(inbound, dest, callback);
03868    }
03869 
03870    return 0;
03871 }

int ast_cc_completed ( struct ast_channel chan,
const char *const   debug,
  ... 
)

Indicate recall has been acknowledged.

Since:
1.8
When we receive confirmation that an endpoint has responded to our CC recall, we call this function.

Parameters:
chan The inbound channel making the CC recall
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3457 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, CC_COMPLETE, cc_request_state_change(), cc_recall_ds_data::core_id, ast_datastore::data, cc_recall_ds_data::ignore, cc_recall_ds_data::nested, and recall_ds_info.

03458 {
03459    struct ast_datastore *recall_datastore;
03460    struct cc_recall_ds_data *recall_data;
03461    int core_id;
03462    va_list ap;
03463    int res;
03464 
03465    ast_channel_lock(chan);
03466    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03467       /* Silly! Why did you call this function if there's no recall DS? */
03468       ast_channel_unlock(chan);
03469       return -1;
03470    }
03471    recall_data = recall_datastore->data;
03472    if (recall_data->nested || recall_data->ignore) {
03473       /* If this is being called from a nested Dial, it is too
03474        * early to determine if the recall has actually completed.
03475        * The outermost dial is the only one with the authority to
03476        * declare the recall to be complete.
03477        *
03478        * Similarly, if this function has been called when the
03479        * recall has progressed beyond the first dial, this is not
03480        * a legitimate time to declare the recall to be done. In fact,
03481        * that should have been done already.
03482        */
03483       ast_channel_unlock(chan);
03484       return -1;
03485    }
03486    core_id = recall_data->core_id;
03487    ast_channel_unlock(chan);
03488    va_start(ap, debug);
03489    res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
03490    va_end(ap);
03491    return res;
03492 }

void ast_cc_config_params_destroy ( struct ast_cc_config_params params  ) 

Free memory from CCSS configuration params.

Note:
Just a call to ast_free for now...
Parameters:
params Pointer to structure whose memory we need to free
Return values:
void 

Definition at line 546 of file ccss.c.

References ast_free.

Referenced by __sip_destroy(), agent_destroy(), ast_channel_cc_params_init(), cc_interface_destroy(), channel_cc_params_destroy(), destroy_dahdi_pvt(), setup_dahdi(), and sip_destroy_peer().

00547 {
00548    ast_free(params);
00549 }

void ast_cc_copy_config_params ( struct ast_cc_config_params dest,
const struct ast_cc_config_params src 
)

copy CCSS configuration parameters from one structure to another

Since:
1.8
For now, this is a simple memcpy, but this function is necessary since the size of an ast_cc_config_params structure is unknown outside of main/ccss.c. Also, this allows for easier expansion of the function in case it becomes more complex than just a memcpy.

Parameters:
src The structure from which data is copied
dest The structure to which data is copied
Returns:
Nothing

Definition at line 708 of file ccss.c.

Referenced by ast_channel_cc_params_init(), cc_agent_init(), cc_build_payload(), cc_device_monitor_init(), channel_cc_params_copy(), check_peer_ok(), create_addr_from_peer(), dahdi_new(), deep_copy_dahdi_chan_conf(), and duplicate_pseudo().

00709 {
00710    *dest = *src;
00711 }

void ast_cc_default_config_params ( struct ast_cc_config_params params  ) 

Set the specified CC config params to default values.

Since:
1.8
This is just like ast_cc_copy_config_params() and could be used in place of it if you need to set the config params to defaults instead. You are simply "copying" defaults into the destination.

Parameters:
params CC config params to set to default values.
Returns:
Nothing

Definition at line 525 of file ccss.c.

References cc_default_params.

Referenced by __ast_cc_config_params_init().

00526 {
00527    *params = cc_default_params;
00528 }

void ast_cc_extension_monitor_add_dialstring ( struct ast_channel incoming,
const char *const   dialstring,
const char *const   device_name 
)

Add a child dialstring to an extension monitor.

Since:
1.8
Whenever we request a channel, the parent extension monitor needs to store the dialstring of the device requested. The reason is so that we can call the device back during the recall even if we are not monitoring the device.

Parameters:
incoming The caller's channel
dialstring The dialstring used when requesting the outbound channel
device_name The device name associated with the requested outbound channel
Return values:
void 

Definition at line 1680 of file ccss.c.

References ast_calloc, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, extension_monitor_pvt::child_dialstrings, ast_datastore::data, dialed_cc_interfaces::dial_parent_id, dialed_cc_interfaces_info, id, dialed_cc_interfaces::interface_tree, monitor, and cc_monitor_backend::next.

Referenced by dial_exec_full().

01681 {
01682    struct ast_datastore *cc_datastore;
01683    struct dialed_cc_interfaces *cc_interfaces;
01684    struct ast_cc_monitor *monitor;
01685    struct extension_monitor_pvt *extension_pvt;
01686    struct extension_child_dialstring *child_dialstring;
01687    struct cc_monitor_tree *interface_tree;
01688    int id;
01689 
01690    ast_channel_lock(incoming);
01691    if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
01692       ast_channel_unlock(incoming);
01693       return;
01694    }
01695 
01696    cc_interfaces = cc_datastore->data;
01697    interface_tree = cc_interfaces->interface_tree;
01698    id = cc_interfaces->dial_parent_id;
01699    ast_channel_unlock(incoming);
01700 
01701    AST_LIST_LOCK(interface_tree);
01702    AST_LIST_TRAVERSE(interface_tree, monitor, next) {
01703       if (monitor->id == id) {
01704          break;
01705       }
01706    }
01707 
01708    if (!monitor) {
01709       AST_LIST_UNLOCK(interface_tree);
01710       return;
01711    }
01712 
01713    extension_pvt = monitor->private_data;
01714    if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
01715       AST_LIST_UNLOCK(interface_tree);
01716       return;
01717    }
01718    ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
01719    ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
01720    child_dialstring->is_valid = 1;
01721    AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
01722    AST_LIST_UNLOCK(interface_tree);
01723 }

int ast_cc_failed ( int  core_id,
const char *const   debug,
  ... 
)

Indicate failure has occurred.

Since:
1.8
If at any point a failure occurs, this is the function to call so that the core can initiate cleanup procedures.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3494 of file ccss.c.

References CC_FAILED, and cc_request_state_change().

Referenced by cancel_available_timer(), cc_caller_offered(), cc_caller_requested(), cc_monitor_failed(), cccancel_exec(), ccreq_exec(), generic_recall(), handle_cc_subscribe(), kill_cores(), offer_timer_expire(), request_cc(), sig_pri_handle_cis_subcmds(), sip_offer_timer_expire(), suspend(), unsuspend(), and wait_for_answer().

03495 {
03496    va_list ap;
03497    int res;
03498 
03499    va_start(ap, debug);
03500    res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
03501    va_end(ap);
03502    return res;
03503 }

int ast_cc_get_current_core_id ( struct ast_channel chan  ) 

Get the core id for the current call.

Since:
1.8
The main use of this function is for channel drivers who queue an AST_CONTROL_CC frame. A channel driver may call this function in order to get the core_id for what may become a CC request. This way, when monitor functions are called which use a core_id as a means of identification, the channel driver will have saved this information.

The channel given to this function may be an inbound or outbound channel. Both will have the necessary info on it.

Parameters:
chan The channel from which to get the core_id.
Return values:
core_id on success
-1 Failure

Definition at line 2169 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, dialed_cc_interfaces::core_id, ast_datastore::data, dialed_cc_interfaces_info, and dialed_cc_interfaces::ignore.

Referenced by sig_pri_cc_generic_check(), and sip_handle_cc().

02170 {
02171    struct ast_datastore *datastore;
02172    struct dialed_cc_interfaces *cc_interfaces;
02173    int core_id_return;
02174 
02175    ast_channel_lock(chan);
02176    if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02177       ast_channel_unlock(chan);
02178       return -1;
02179    }
02180 
02181    cc_interfaces = datastore->data;
02182    core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
02183    ast_channel_unlock(chan);
02184    return core_id_return;
02185 
02186 }

struct ast_cc_monitor* ast_cc_get_monitor_by_recall_core_id ( const int  core_id,
const char *const   device_name 
)

Get the associated monitor given the device name and core_id.

Since:
1.8
The function ast_cc_is_recall is helpful for determining if a call to a specific channel is a recall. However, once you have determined that this is a recall, you will most likely need access to the private data within the associated monitor. This function is what one uses to get that monitor.

Note:
This function locks the list of monitors that correspond to the core_id passed in. Be sure that you have no potential lock order issues when calling this function.
Parameters:
core_id The core ID to which this recall corresponds. This likely will have been obtained using the ast_cc_is_recall function
device_name Which device to find the monitor for.
Return values:
NULL Appropriate monitor does not exist
non-NULL The monitor to use for this recall

Definition at line 3150 of file ccss.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, cc_ref(), cc_unref(), ast_cc_interface::device_name, find_cc_core_instance(), ast_cc_monitor::interface, cc_core_instance::monitors, and cc_monitor_backend::next.

Referenced by sig_pri_call(), sig_pri_cc_generic_check(), and sip_call().

03151 {
03152    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03153    struct ast_cc_monitor *monitor_iter;
03154 
03155    if (!core_instance) {
03156       return NULL;
03157    }
03158 
03159    AST_LIST_LOCK(core_instance->monitors);
03160    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03161       if (!strcmp(monitor_iter->interface->device_name, device_name)) {
03162          /* Found a monitor. */
03163          cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
03164          break;
03165       }
03166    }
03167    AST_LIST_UNLOCK(core_instance->monitors);
03168    cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
03169    return monitor_iter;
03170 }

int ast_cc_get_param ( struct ast_cc_config_params params,
const char *const   name,
char *  buf,
size_t  buf_len 
)

get a CCSS configuration parameter, given its name

Note:
Useful when reading input as a string, like from dialplan or manager.
Parameters:
params The CCSS configuration from which to get the value
name The name of the CCSS parameter we want
buf A preallocated buffer to hold the value
buf_len The size of buf
Return values:
0 Success
-1 Failure

Definition at line 612 of file ccss.c.

References agent_policy_to_str(), ast_copy_string(), ast_get_cc_agent_dialstring(), ast_get_cc_agent_policy(), ast_get_cc_callback_macro(), ast_get_cc_max_agents(), ast_get_cc_max_monitors(), ast_get_cc_monitor_policy(), ast_get_cc_offer_timer(), ast_get_cc_recall_timer(), ast_get_ccbs_available_timer(), ast_get_ccnr_available_timer(), ast_log(), ast_strlen_zero(), LOG_WARNING, monitor_policy_to_str(), and value.

Referenced by acf_cc_read().

00614 {
00615    const char *value = NULL;
00616    if (!strcasecmp(name, "cc_callback_macro")) {
00617       value = ast_get_cc_callback_macro(params);
00618    } else if (!strcasecmp(name, "cc_agent_policy")) {
00619       value = agent_policy_to_str(ast_get_cc_agent_policy(params));
00620    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00621       value = monitor_policy_to_str(ast_get_cc_monitor_policy(params));
00622    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00623       value = ast_get_cc_agent_dialstring(params);
00624    }
00625 
00626    if (!ast_strlen_zero(value)) {
00627       ast_copy_string(buf, value, buf_len);
00628       return 0;
00629    }
00630 
00631    /* The rest of these are all ints of some sort and require some
00632     * snprintf-itude
00633     */
00634 
00635    if (!strcasecmp(name, "cc_offer_timer")) {
00636       snprintf(buf, buf_len, "%u", ast_get_cc_offer_timer(params));
00637    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00638       snprintf(buf, buf_len, "%u", ast_get_ccnr_available_timer(params));
00639    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00640       snprintf(buf, buf_len, "%u", ast_get_ccbs_available_timer(params));
00641    } else if (!strcasecmp(name, "cc_max_agents")) {
00642       snprintf(buf, buf_len, "%u", ast_get_cc_max_agents(params));
00643    } else if (!strcasecmp(name, "cc_max_monitors")) {
00644       snprintf(buf, buf_len, "%u", ast_get_cc_max_monitors(params));
00645    } else if (!strcasecmp(name, "cc_recall_timer")) {
00646       snprintf(buf, buf_len, "%u", ast_get_cc_recall_timer(params));
00647    } else {
00648       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00649       return -1;
00650    }
00651 
00652    return 0;
00653 }

int ast_cc_init ( void   ) 

Initialize CCSS.

Since:
1.8
Performs startup routines necessary for CC operation.

Return values:
0 Success
nonzero Failure

Definition at line 4178 of file ccss.c.

References ao2_t_container_alloc, ARRAY_LEN, ast_cc_agent_register(), ast_cc_monitor_register(), ast_cli_register_multiple(), ast_logger_register_level(), ast_register_application2(), ast_sched_thread_create(), ast_taskprocessor_get(), cc_cli, cc_core_instance_cmp_fn(), cc_core_instance_hash_fn(), cc_core_instances, cc_core_taskprocessor, cc_sched_thread, cccancel_exec(), ccreq_exec(), generic_agent_callbacks, generic_monitor_cbs, generic_monitor_cmp_fn(), generic_monitor_hash_fn(), generic_monitors, initialize_cc_max_requests(), and TPS_REF_DEFAULT.

Referenced by main().

04179 {
04180    int res;
04181 
04182    if (!(cc_core_instances = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04183                cc_core_instance_hash_fn, cc_core_instance_cmp_fn,
04184                "Create core instance container"))) {
04185       return -1;
04186    }
04187    if (!(generic_monitors = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04188                generic_monitor_hash_fn, generic_monitor_cmp_fn,
04189                "Create generic monitor container"))) {
04190       return -1;
04191    }
04192    if (!(cc_core_taskprocessor = ast_taskprocessor_get("CCSS core", TPS_REF_DEFAULT))) {
04193       return -1;
04194    }
04195    if (!(cc_sched_thread = ast_sched_thread_create())) {
04196       return -1;
04197    }
04198    res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL);
04199    res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL);
04200    res |= ast_cc_monitor_register(&generic_monitor_cbs);
04201    res |= ast_cc_agent_register(&generic_agent_callbacks);
04202    ast_cli_register_multiple(cc_cli, ARRAY_LEN(cc_cli));
04203    cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME);
04204    dialed_cc_interface_counter = 1;
04205    initialize_cc_max_requests();
04206    return res;
04207 }

int ast_cc_is_config_param ( const char *const   name  ) 

Is this a CCSS configuration parameter?

Since:
1.8
Parameters:
name Name of configuration option being parsed.
Return values:
1 Yes, this is a CCSS configuration parameter.
0 No, this is not a CCSS configuration parameter.

Definition at line 694 of file ccss.c.

Referenced by build_peer().

00695 {
00696    return (!strcasecmp(name, "cc_agent_policy") ||
00697             !strcasecmp(name, "cc_monitor_policy") ||
00698             !strcasecmp(name, "cc_offer_timer") ||
00699             !strcasecmp(name, "ccnr_available_timer") ||
00700             !strcasecmp(name, "ccbs_available_timer") ||
00701             !strcasecmp(name, "cc_max_agents") ||
00702             !strcasecmp(name, "cc_max_monitors") ||
00703             !strcasecmp(name, "cc_callback_macro") ||
00704             !strcasecmp(name, "cc_agent_dialstring") ||
00705             !strcasecmp(name, "cc_recall_timer"));
00706 }

int ast_cc_is_recall ( struct ast_channel chan,
int *  core_id,
const char *const   monitor_type 
)

Decide if a call to a particular channel is a CC recall.

Since:
1.8
When a CC recall happens, it is important on the called side to know that the call is a CC recall and not a normal call. This function will determine first if the call in question is a CC recall. Then it will determine based on the chan parameter if the channel is being called is being recalled.

As a quick example, let's say a call is placed to SIP/1000 and SIP/1000 is currently on the phone. The caller requests CCBS. SIP/1000 finishes his call, and so the caller attempts to recall. Now, the dialplan administrator has set up this second call so that not only is SIP/1000 called, but also SIP/2000 is called. If SIP/1000's channel were passed to this function, the return value would be non-zero, but if SIP/2000's channel were passed into this function, then the return would be 0 since SIP/2000 was not one of the original devices dialed.

Note:
This function may be called on a calling channel as well to determine if it is part of a CC recall.

This function will lock the channel as well as the list of monitors on the channel datastore, though the locks are not held at the same time. Be sure that you have no potential lock order issues here.

Parameters:
chan The channel to check
[out] core_id If this is a valid CC recall, the core_id of the failed call will be placed in this output parameter
monitor_type Clarify which type of monitor type we are looking for if this is happening on a called channel. For incoming channels, this parameter is not used.
Return values:
0 Either this is not a recall or it is but this channel is not part of the recall
non-zero This is a recall and the channel in question is directly involved.

Definition at line 3069 of file ccss.c.

References ast_assert, ast_channel_datastore_find(), ast_channel_get_device_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), cc_recall_ds_data::core_id, ast_datastore::data, ast_cc_interface::device_name, cc_recall_ds_data::ignore, ast_cc_monitor::interface, cc_recall_ds_data::interface_tree, ast_cc_interface::monitor_type, cc_recall_ds_data::nested, cc_monitor_backend::next, and recall_ds_info.

Referenced by cc_core_init_instance(), sig_pri_call(), sip_call(), and wait_for_answer().

03070 {
03071    struct ast_datastore *recall_datastore;
03072    struct cc_recall_ds_data *recall_data;
03073    struct cc_monitor_tree *interface_tree;
03074    char device_name[AST_CHANNEL_NAME];
03075    struct ast_cc_monitor *device_monitor;
03076    int core_id_candidate;
03077 
03078    ast_assert(core_id != NULL);
03079 
03080    *core_id = -1;
03081 
03082    ast_channel_lock(chan);
03083    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03084       /* Obviously not a recall if the datastore isn't present */
03085       ast_channel_unlock(chan);
03086       return 0;
03087    }
03088 
03089    recall_data = recall_datastore->data;
03090 
03091    if (recall_data->ignore) {
03092       /* Though this is a recall, the call to this particular interface is not part of the
03093        * recall either because this is a call forward or because this is not the first
03094        * invocation of Dial during this call
03095        */
03096       ast_channel_unlock(chan);
03097       return 0;
03098    }
03099 
03100    if (!recall_data->nested) {
03101       /* If the nested flag is not set, then this means that
03102        * the channel passed to this function is the caller making
03103        * the recall. This means that we shouldn't look through
03104        * the monitor tree for the channel because it shouldn't be
03105        * there. However, this is a recall though, so return true.
03106        */
03107       *core_id = recall_data->core_id;
03108       ast_channel_unlock(chan);
03109       return 1;
03110    }
03111 
03112    if (ast_strlen_zero(monitor_type)) {
03113       /* If someone passed a NULL or empty monitor type, then it is clear
03114        * the channel they passed in was an incoming channel, and so searching
03115        * the list of dialed interfaces is not going to be helpful. Just return
03116        * false immediately.
03117        */
03118       ast_channel_unlock(chan);
03119       return 0;
03120    }
03121 
03122    interface_tree = recall_data->interface_tree;
03123    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03124    /* We grab the value of the recall_data->core_id so that we
03125     * can unlock the channel before we start looking through the
03126     * interface list. That way we don't have to worry about a possible
03127     * clash between the channel lock and the monitor tree lock.
03128     */
03129    core_id_candidate = recall_data->core_id;
03130    ast_channel_unlock(chan);
03131 
03132    /*
03133     * Now we need to find out if the channel device name
03134     * is in the list of interfaces in the called tree.
03135     */
03136    AST_LIST_LOCK(interface_tree);
03137    AST_LIST_TRAVERSE(interface_tree, device_monitor, next) {
03138       if (!strcmp(device_monitor->interface->device_name, device_name) &&
03139             !strcmp(device_monitor->interface->monitor_type, monitor_type)) {
03140          /* BOOM! Device is in the tree! We have a winner! */
03141          *core_id = core_id_candidate;
03142          AST_LIST_UNLOCK(interface_tree);
03143          return 1;
03144       }
03145    }
03146    AST_LIST_UNLOCK(interface_tree);
03147    return 0;
03148 }

int ast_cc_monitor_callee_available ( const int  core_id,
const char *const   debug,
  ... 
)

Alert the core that a device being monitored has become available.

Since:
1.8
Note:
The code in the core will take care of making sure that the information gets passed up the ladder correctly.
Parameters:
core_id The core ID of the corresponding CC transaction
debug 
Return values:
0 Request successfully queued
-1 Request could not be queued

Definition at line 3413 of file ccss.c.

References CC_CALLEE_READY, and cc_request_state_change().

Referenced by cc_generic_monitor_destructor(), cc_generic_monitor_suspend(), cc_generic_monitor_unsuspend(), generic_monitor_devstate_tp_cb(), handle_cc_notify(), and sig_pri_handle_cis_subcmds().

03414 {
03415    va_list ap;
03416    int res;
03417 
03418    va_start(ap, debug);
03419    res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
03420    va_end(ap);
03421    return res;
03422 }

int ast_cc_monitor_count ( const char *const   name,
const char *const   type 
)

Return the number of outstanding CC requests to a specific device.

Since:
1.8
Note:
This function will lock the list of monitors stored on every instance of the CC core. Callers of this function should be aware of this and avoid any potential lock ordering problems.
Parameters:
name The name of the monitored device
type The type of the monitored device (e.g. "generic")
Returns:
The number of CC requests for the monitor

Definition at line 3970 of file ccss.c.

References ao2_t_callback, ast_log_dynamic_level, cc_core_instances, count_monitors_cb_data::count, count_monitors_cb(), count_monitors_cb_data::device_name, and OBJ_NODATA.

Referenced by ast_queue_cc_frame().

03971 {
03972    struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};
03973 
03974    ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
03975    ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
03976    return data.count;
03977 }

int ast_cc_monitor_failed ( int  core_id,
const char *const   monitor_name,
const char *const   debug,
  ... 
)

Indicate that a failure has occurred on a specific monitor.

Since:
1.8
If a monitor should detect that a failure has occurred when communicating with its endpoint, then ast_cc_monitor_failed should be called. The big difference between ast_cc_monitor_failed and ast_cc_failed is that ast_cc_failed indicates a global failure for a CC transaction, where as ast_cc_monitor_failed is localized to a particular monitor. When ast_cc_failed is called, the entire CC transaction is torn down. When ast_cc_monitor_failed is called, only the monitor on which the failure occurred is pruned from the tree of monitors.

If there are no more devices left to monitor when this function is called, then the core will fail the CC transaction globally.

Parameters:
core_id The core ID for the CC transaction
monitor_name The name of the monitor on which the failure occurred
debug A debug message to print to the CC log
Returns:
void

Definition at line 3559 of file ccss.c.

References ast_calloc, ast_free, ast_strdup, ast_taskprocessor_push(), ast_vasprintf, cc_core_taskprocessor, and cc_monitor_failed().

Referenced by ast_cc_available_timer_expire(), cc_handle_publish_error(), handle_response(), and sig_pri_handle_cis_subcmds().

03560 {
03561    struct ast_cc_monitor_failure_data *failure_data;
03562    int res;
03563    va_list ap;
03564 
03565    if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
03566       return -1;
03567    }
03568 
03569    if (!(failure_data->device_name = ast_strdup(monitor_name))) {
03570       ast_free(failure_data);
03571       return -1;
03572    }
03573 
03574    va_start(ap, debug);
03575    if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
03576       va_end(ap);
03577       ast_free((char *)failure_data->device_name);
03578       ast_free(failure_data);
03579       return -1;
03580    }
03581    va_end(ap);
03582 
03583    failure_data->core_id = core_id;
03584 
03585    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
03586    if (res) {
03587       ast_free((char *)failure_data->device_name);
03588       ast_free((char *)failure_data->debug);
03589       ast_free(failure_data);
03590    }
03591    return res;
03592 }

int ast_cc_monitor_party_b_free ( int  core_id  ) 

Alert a caller that though the callee has become free, the caller himself is not and may not call back.

When an ISDN PTMP monitor senses that his monitored party has become available, he will request the status of the called party. If he determines that the caller is currently not available, then he will call this function so that an appropriate message is sent to the caller.

Yes, you just read that correctly. The callee asks the caller what his current status is, and if the caller is currently unavailable, the monitor must send him a message anyway. WTF?

This function results in the agent's party_b_free callback being called. It is most likely that you will not need to actually implement the party_b_free callback in an agent because it is not likely that you will need to or even want to send a caller a message indicating the callee's status if the caller himself is not also free.

Parameters:
core_id The core ID of the CC transaction
Return values:
0 Successfully alerted the core that party B is free
-1 Could not alert the core that party B is free

Definition at line 3669 of file ccss.c.

References ast_taskprocessor_push(), cc_core_taskprocessor, cc_party_b_free(), cc_unref(), and find_cc_core_instance().

Referenced by sig_pri_handle_cis_subcmds().

03670 {
03671    int res;
03672    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03673 
03674    if (!core_instance) {
03675       return -1;
03676    }
03677 
03678    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
03679    if (res) {
03680       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03681    }
03682    return res;
03683 }

int ast_cc_monitor_register ( const struct ast_cc_monitor_callbacks callbacks  ) 

Register a set of monitor callbacks with the core.

Since:
1.8
This is made so that at monitor creation time, the proper callbacks may be installed and the proper .init callback may be called for the monitor to establish private data.

Parameters:
callbacks The callbacks used by the monitor implementation
Return values:
0 Successfully registered
-1 Failure to register

Definition at line 862 of file ccss.c.

References ast_calloc, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and cc_monitor_backend::next.

Referenced by ast_cc_init(), and load_module().

00863 {
00864    struct cc_monitor_backend *backend = ast_calloc(1, sizeof(*backend));
00865 
00866    if (!backend) {
00867       return -1;
00868    }
00869 
00870    backend->callbacks = callbacks;
00871 
00872    AST_RWLIST_WRLOCK(&cc_monitor_backends);
00873    AST_RWLIST_INSERT_TAIL(&cc_monitor_backends, backend, next);
00874    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00875    return 0;
00876 }

int ast_cc_monitor_request_acked ( int  core_id,
const char *const   debug,
  ... 
)

Indicate that an outbound entity has accepted our CC request.

Since:
1.8
When we receive confirmation that an outbound device has accepted the CC request we sent it, this function must be called.

Parameters:
core_id core_id of the CC transaction
debug optional string to print for debugging purposes
Return values:
0 Success
-1 Failure

Definition at line 3402 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

Referenced by cc_generic_monitor_request_cc(), cc_stop_ringing(), handle_cc_notify(), and sig_pri_handle_cis_subcmds().

03403 {
03404    va_list ap;
03405    int res;
03406 
03407    va_start(ap, debug);
03408    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03409    va_end(ap);
03410    return res;
03411 }

int ast_cc_monitor_status_request ( int  core_id  ) 

Request the status of a caller or callers.

When an ISDN PTMP monitor senses that the callee has become available, it needs to know the current status of the caller in order to determine the appropriate response to send to the caller. In order to do this, the monitor calls this function. Responses will arrive asynchronously.

Note:
Zero or more responses may come as a result.
Parameters:
core_id The core ID of the CC transaction
Return values:
0 Successfully requested status
-1 Failed to request status

Definition at line 3604 of file ccss.c.

References ast_taskprocessor_push(), cc_core_taskprocessor, cc_status_request(), cc_unref(), and find_cc_core_instance().

Referenced by sig_pri_handle_cis_subcmds().

03605 {
03606    int res;
03607    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03608 
03609    if (!core_instance) {
03610       return -1;
03611    }
03612 
03613    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
03614    if (res) {
03615       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03616    }
03617    return res;
03618 }

int ast_cc_monitor_stop_ringing ( int  core_id  ) 

Alert a caller to stop ringing.

When an ISDN PTMP monitor becomes available, it is assumed that the agent will then cause the caller's phone to ring. In some cases, this is literally what happens. In other cases, it may be that the caller gets a visible indication on his phone that he may attempt to recall the callee. If multiple callers are recalled (since it may be possible to have a group of callers configured as a single party A), and one of those callers picks up his phone, then the ISDN PTMP monitor will alert the other callers to stop ringing. The agent's stop_ringing callback will be called, and it is up to the agent's driver to send an appropriate message to make his caller stop ringing.

Parameters:
core_id The core ID of the CC transaction
Return values:
0 Successfully requested for the phone to stop ringing
-1 Could not request for the phone to stop ringing

Definition at line 3641 of file ccss.c.

References ast_taskprocessor_push(), cc_core_taskprocessor, cc_stop_ringing(), cc_unref(), and find_cc_core_instance().

Referenced by sig_pri_handle_cis_subcmds().

03642 {
03643    int res;
03644    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03645 
03646    if (!core_instance) {
03647       return -1;
03648    }
03649 
03650    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
03651    if (res) {
03652       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03653    }
03654    return res;
03655 }

void ast_cc_monitor_unregister ( const struct ast_cc_monitor_callbacks callbacks  ) 

Unregister a set of monitor callbacks with the core.

Since:
1.8
If a module which makes use of a CC monitor is unloaded, then it may unregister its monitor callbacks with the core.

Parameters:
callbacks The callbacks used by the monitor implementation
Return values:
0 Successfully unregistered
-1 Failure to unregister

Definition at line 895 of file ccss.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cc_monitor_backend::callbacks, and cc_monitor_backend::next.

Referenced by __unload_module(), and unload_module().

00896 {
00897    struct cc_monitor_backend *backend;
00898    AST_RWLIST_WRLOCK(&cc_monitor_backends);
00899    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_monitor_backends, backend, next) {
00900       if (backend->callbacks == callbacks) {
00901          AST_RWLIST_REMOVE_CURRENT(next);
00902          ast_free(backend);
00903          break;
00904       }
00905    }
00906    AST_RWLIST_TRAVERSE_SAFE_END;
00907    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00908 }

int ast_cc_offer ( struct ast_channel caller_chan  ) 

Offer CC to a caller.

Since:
1.8
This function is called from ast_hangup if the caller is eligible to be offered call completion service.

Parameters:
caller_chan The calling channel
Return values:
-1 Error
0 Success

Definition at line 3366 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, cc_offer(), dialed_cc_interfaces::core_id, cc_recall_ds_data::core_id, ast_datastore::data, dialed_cc_interfaces_info, dialed_cc_interfaces::is_original_caller, and ast_channel::name.

Referenced by ast_hangup().

03367 {
03368    int core_id;
03369    int res = -1;
03370    struct ast_datastore *datastore;
03371    struct dialed_cc_interfaces *cc_interfaces;
03372    char cc_is_offerable;
03373 
03374    ast_channel_lock(caller_chan);
03375    if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
03376       ast_channel_unlock(caller_chan);
03377       return res;
03378    }
03379 
03380    cc_interfaces = datastore->data;
03381    cc_is_offerable = cc_interfaces->is_original_caller;
03382    core_id = cc_interfaces->core_id;
03383    ast_channel_unlock(caller_chan);
03384 
03385    if (cc_is_offerable) {
03386       res = cc_offer(core_id, "CC offered to caller %s", caller_chan->name);
03387    }
03388    return res;
03389 }

int ast_cc_request_is_within_limits ( void   ) 

Check if the incoming CC request is within the bounds set by the cc_max_requests configuration option.

Since:
1.8
It is recommended that an entity which receives an incoming CC request calls this function before calling ast_cc_agent_accept_request. This way, immediate feedback can be given to the caller about why his request was rejected.

If this is not called and a state change to CC_CALLER_REQUESTED is made, then the core will still not allow for the request to succeed. However, if done this way, it may not be obvious to the requestor why the request failed.

Return values:
0 Not within the limits. Fail.
non-zero Within the limits. Success.

Definition at line 2164 of file ccss.c.

Referenced by cc_caller_requested(), cc_interfaces_datastore_init(), ccreq_exec(), and sig_pri_handle_cis_subcmds().

02165 {
02166    return cc_request_count < global_cc_max_requests;
02167 }

int ast_cc_set_param ( struct ast_cc_config_params params,
const char *const   name,
const char *  value 
)

set a CCSS configuration parameter, given its name

Note:
Useful when parsing config files when used in conjunction with ast_ccss_is_cc_config_param.
Parameters:
params The parameter structure to set the value on
name The name of the cc parameter
value The value of the parameter
Return values:
0 Success
-1 Failure

Definition at line 655 of file ccss.c.

References ast_log(), ast_set_cc_agent_dialstring(), ast_set_cc_agent_policy(), ast_set_cc_callback_macro(), ast_set_cc_max_agents(), ast_set_cc_max_monitors(), ast_set_cc_monitor_policy(), ast_set_cc_offer_timer(), ast_set_cc_recall_timer(), ast_set_ccbs_available_timer(), ast_set_ccnr_available_timer(), LOG_WARNING, str_to_agent_policy(), and str_to_monitor_policy().

Referenced by acf_cc_write(), and build_peer().

00657 {
00658    unsigned int value_as_uint;
00659    if (!strcasecmp(name, "cc_agent_policy")) {
00660       return ast_set_cc_agent_policy(params, str_to_agent_policy(value));
00661    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00662       return ast_set_cc_monitor_policy(params, str_to_monitor_policy(value));
00663    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00664       ast_set_cc_agent_dialstring(params, value);
00665    } else if (!strcasecmp(name, "cc_callback_macro")) {
00666       ast_set_cc_callback_macro(params, value);
00667       return 0;
00668    }
00669 
00670    if (!sscanf(value, "%30u", &value_as_uint) == 1) {
00671       return -1;
00672    }
00673 
00674    if (!strcasecmp(name, "cc_offer_timer")) {
00675       ast_set_cc_offer_timer(params, value_as_uint);
00676    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00677       ast_set_ccnr_available_timer(params, value_as_uint);
00678    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00679       ast_set_ccbs_available_timer(params, value_as_uint);
00680    } else if (!strcasecmp(name, "cc_max_agents")) {
00681       ast_set_cc_max_agents(params, value_as_uint);
00682    } else if (!strcasecmp(name, "cc_max_monitors")) {
00683       ast_set_cc_max_monitors(params, value_as_uint);
00684    } else if (!strcasecmp(name, "cc_recall_timer")) {
00685       ast_set_cc_recall_timer(params, value_as_uint);
00686    } else {
00687       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00688       return -1;
00689    }
00690 
00691    return 0;
00692 }

const char* ast_get_cc_agent_dialstring ( struct ast_cc_config_params config  ) 

Get the cc_agent_dialstring.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_agent_dialstring from
Returns:
The cc_agent_dialstring from this configuration

Definition at line 807 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00808 {
00809    return config->cc_agent_dialstring;
00810 }

enum ast_cc_agent_policies ast_get_cc_agent_policy ( struct ast_cc_config_params config  ) 

Get the cc_agent_policy.

Since:
1.8
Parameters:
config The configuration to retrieve the policy from
Returns:
The current cc_agent_policy for this configuration

Definition at line 713 of file ccss.c.

References config.

Referenced by ast_cc_call_init(), ast_cc_get_param(), build_peer(), cc_core_init_instance(), and find_agent_callbacks().

00714 {
00715    return config->cc_agent_policy;
00716 }

const char* ast_get_cc_callback_macro ( struct ast_cc_config_params config  ) 

Get the name of the callback_macro.

Since:
1.8
Parameters:
config The configuration to retrieve the callback_macro from
Returns:
The callback_macro name

Definition at line 841 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00842 {
00843    return config->cc_callback_macro;
00844 }

unsigned int ast_get_cc_max_agents ( struct ast_cc_config_params config  ) 

Get the cc_max_agents.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_max_agents from
Returns:
The cc_max_agents from this configuration

Definition at line 821 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), and cc_core_init_instance().

00822 {
00823    return config->cc_max_agents;
00824 }

unsigned int ast_get_cc_max_monitors ( struct ast_cc_config_params config  ) 

Get the cc_max_monitors.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_max_monitors from
Returns:
The cc_max_monitors from this configuration

Definition at line 831 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), and ast_queue_cc_frame().

00832 {
00833    return config->cc_max_monitors;
00834 }

enum ast_cc_monitor_policies ast_get_cc_monitor_policy ( struct ast_cc_config_params config  ) 

Get the cc_monitor_policy.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_monitor_policy from
Returns:
The cc_monitor_policy retrieved from the configuration

Definition at line 730 of file ccss.c.

References config.

Referenced by analog_call(), ast_cc_call_failed(), ast_cc_get_param(), dahdi_cc_callback(), sig_pri_cc_generic_check(), and sip_handle_cc().

00731 {
00732    return config->cc_monitor_policy;
00733 }

unsigned int ast_get_cc_offer_timer ( struct ast_cc_config_params config  ) 

Get the cc_offer_timer.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_offer_timer from
Returns:
The cc_offer_timer from this configuration

Definition at line 747 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), cc_generic_agent_start_offer_timer(), and sip_cc_agent_start_offer_timer().

00748 {
00749    return config->cc_offer_timer;
00750 }

unsigned int ast_get_cc_recall_timer ( struct ast_cc_config_params config  ) 

Get the cc_recall_timer.

Since:
1.8
Parameters:
config The configuration to retrieve the cc_recall_timer from
Returns:
The cc_recall_timer from this configuration

Definition at line 777 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00778 {
00779    return config->cc_recall_timer;
00780 }

unsigned int ast_get_ccbs_available_timer ( struct ast_cc_config_params config  ) 

Get the ccbs_available_timer.

Since:
1.8
Parameters:
config The configuration to retrieve the ccbs_available_timer from
Returns:
The ccbs_available_timer from this configuration

Definition at line 792 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

00793 {
00794    return config->ccbs_available_timer;
00795 }

unsigned int ast_get_ccnr_available_timer ( struct ast_cc_config_params config  ) 

Get the ccnr_available_timer.

Since:
1.8
Parameters:
config The configuration to retrieve the ccnr_available_timer from
Returns:
The ccnr_available_timer from this configuration

Definition at line 762 of file ccss.c.

References config.

Referenced by ast_cc_get_param(), cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

00763 {
00764    return config->ccnr_available_timer;
00765 }

void ast_handle_cc_control_frame ( struct ast_channel inbound,
struct ast_channel outbound,
void *  frame_data 
)

Properly react to a CC control frame.

Unless we are ignoring CC for some reason, we will always call this function when we read an AST_CONTROL_CC frame from an outbound channel.

This function will call cc_device_monitor_init to create the new cc_monitor for the device from which we read the frame. In addition, the new device will be added to the monitor tree on the dialed_cc_interfaces datastore on the inbound channel.

If this is the first AST_CONTROL_CC frame that we have handled for this call, then we will also initialize the CC core for this call.

Definition at line 1993 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_CC, ast_indicate_data(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_log_dynamic_level, call_destructor_with_no_monitor(), cc_core_init_instance(), cc_device_monitor_init(), cc_extension_monitor_change_is_valid(), cc_ref(), cc_service_to_string(), cc_unref(), cc_core_instance::core_id, dialed_cc_interfaces::core_id, ast_datastore::data, cc_control_payload::device_name, dialed_cc_interfaces_info, cc_control_payload::dialstring, ast_cc_monitor::dialstring, EVENT_FLAG_CC, find_cc_core_instance(), dialed_cc_interfaces::ignore, dialed_cc_interfaces::interface_tree, dialed_cc_interfaces::is_original_caller, LOG_WARNING, manager_event, monitor, cc_control_payload::monitor_type, cc_monitor_backend::next, cc_control_payload::private_data, and cc_control_payload::service.

Referenced by ast_cc_busy_interface(), and ast_cc_call_failed().

01994 {
01995    char *device_name;
01996    char *dialstring;
01997    struct ast_cc_monitor *monitor;
01998    struct ast_datastore *cc_datastore;
01999    struct dialed_cc_interfaces *cc_interfaces;
02000    struct cc_control_payload *cc_data = frame_data;
02001    struct cc_core_instance *core_instance;
02002 
02003    device_name = cc_data->device_name;
02004    dialstring = cc_data->dialstring;
02005 
02006    ast_channel_lock(inbound);
02007    if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
02008       ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
02009       ast_channel_unlock(inbound);
02010       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02011       return;
02012    }
02013 
02014    cc_interfaces = cc_datastore->data;
02015 
02016    if (cc_interfaces->ignore) {
02017       ast_channel_unlock(inbound);
02018       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02019       return;
02020    }
02021 
02022    if (!cc_interfaces->is_original_caller) {
02023       /* If the is_original_caller is not set on the *inbound* channel, then
02024        * it must be a local channel. As such, we do not want to create a core instance
02025        * or an agent for the local channel. Instead, we want to pass this along to the
02026        * other side of the local channel so that the original caller can benefit.
02027        */
02028       ast_channel_unlock(inbound);
02029       ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
02030       return;
02031    }
02032 
02033    core_instance = find_cc_core_instance(cc_interfaces->core_id);
02034    if (!core_instance) {
02035       core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
02036          cc_interfaces->core_id, cc_data);
02037       if (!core_instance) {
02038          cc_interfaces->ignore = 1;
02039          ast_channel_unlock(inbound);
02040          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02041          return;
02042       }
02043    }
02044 
02045    ast_channel_unlock(inbound);
02046 
02047    /* Yeah this kind of sucks, but luckily most people
02048     * aren't dialing thousands of interfaces on every call
02049     *
02050     * This traversal helps us to not create duplicate monitors in
02051     * case a device queues multiple CC control frames.
02052     */
02053    AST_LIST_LOCK(cc_interfaces->interface_tree);
02054    AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
02055       if (!strcmp(monitor->interface->device_name, device_name)) {
02056          ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
02057                core_instance->core_id, device_name);
02058          AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02059          cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02060          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02061          return;
02062       }
02063    }
02064    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02065 
02066    if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
02067       ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
02068       cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02069       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02070       return;
02071    }
02072 
02073    AST_LIST_LOCK(cc_interfaces->interface_tree);
02074    cc_ref(monitor, "monitor tree's reference to the monitor");
02075    AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
02076    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02077 
02078    cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
02079 
02080    manager_event(EVENT_FLAG_CC, "CCAvailable",
02081       "CoreID: %d\r\n"
02082       "Callee: %s\r\n"
02083       "Service: %s\r\n",
02084       cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
02085    );
02086 
02087    cc_unref(core_instance, "Done with core_instance after handling CC control frame");
02088    cc_unref(monitor, "Unref reference from allocating monitor");
02089 }

void ast_ignore_cc ( struct ast_channel chan  ) 

Mark the channel to ignore further CC activity.

Since:
1.8
When a CC-capable application, such as Dial, has finished with all CC processing for a channel and knows that any further CC processing should be ignored, this function should be called.

Parameters:
chan The channel for which further CC processing should be ignored.
Return values:
void 

Definition at line 3335 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore::data, dialed_cc_interfaces_info, cc_recall_ds_data::ignore, dialed_cc_interfaces::ignore, and recall_ds_info.

Referenced by dial_exec_full(), and do_forward().

03336 {
03337    struct ast_datastore *cc_datastore;
03338    struct ast_datastore *cc_recall_datastore;
03339    struct dialed_cc_interfaces *cc_interfaces;
03340    struct cc_recall_ds_data *recall_cc_data;
03341 
03342    ast_channel_lock(chan);
03343    if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
03344       cc_interfaces = cc_datastore->data;
03345       cc_interfaces->ignore = 1;
03346    }
03347 
03348    if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03349       recall_cc_data = cc_recall_datastore->data;
03350       recall_cc_data->ignore = 1;
03351    }
03352    ast_channel_unlock(chan);
03353 }

int ast_queue_cc_frame ( struct ast_channel chan,
const char *const   monitor_type,
const char *const   dialstring,
enum ast_cc_service_type  service,
void *  private_data 
)

Queue an AST_CONTROL_CC frame.

Since:
1.8
Note:
Since this function calls ast_queue_frame, the channel will be locked during the course of this function.
Parameters:
chan The channel onto which to queue the frame
monitor_type The type of monitor to use when CC is requested
dialstring The dial string used to call the device
service The type of CC service the device is willing to offer
private_data If a native monitor is being used, and some channel-driver-specific private data has been allocated, then this parameter should contain a pointer to that data. If using a generic monitor, this parameter should remain NULL. Note that if this function should fail at some point, it is the responsibility of the caller to free the private data upon return.
Return values:
0 Success
-1 Error

Definition at line 3767 of file ccss.c.

References ast_cc_build_frame(), ast_cc_monitor_count(), ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_frfree, ast_get_cc_max_monitors(), ast_log(), ast_queue_frame(), and LOG_NOTICE.

Referenced by analog_call(), sig_pri_cc_generic_check(), and sip_handle_cc().

03769 {
03770    struct ast_frame frame = {0,};
03771    char device_name[AST_CHANNEL_NAME];
03772    int retval;
03773    struct ast_cc_config_params *cc_params;
03774 
03775    cc_params = ast_channel_get_cc_config_params(chan);
03776    if (!cc_params) {
03777       return -1;
03778    }
03779    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03780    if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
03781       ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
03782       return -1;
03783    }
03784 
03785    if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
03786       /* Frame building failed. We can't use this. */
03787       return -1;
03788    }
03789    retval = ast_queue_frame(chan, &frame);
03790    ast_frfree(&frame);
03791    return retval;
03792 }

void ast_set_cc_agent_dialstring ( struct ast_cc_config_params config,
const char *const   value 
)

Set the cc_agent_dialstring.

Since:
1.8
Parameters:
config The configuration to set the cc_agent_dialstring on
value The new cc_agent_dialstring we want to change to
Return values:
void 

Definition at line 812 of file ccss.c.

References ast_copy_string(), ast_strlen_zero(), and config.

Referenced by ast_cc_set_param().

00813 {
00814    if (ast_strlen_zero(value)) {
00815       config->cc_agent_dialstring[0] = '\0';
00816    } else {
00817       ast_copy_string(config->cc_agent_dialstring, value, sizeof(config->cc_agent_dialstring));
00818    }
00819 }

int ast_set_cc_agent_policy ( struct ast_cc_config_params config,
enum ast_cc_agent_policies  value 
)

Set the cc_agent_policy.

Since:
1.8
Parameters:
config The configuration to set the cc_agent_policy on
value The new cc_agent_policy we want to change to
Return values:
0 Success
-1 Failure (likely due to bad input)

Definition at line 718 of file ccss.c.

References AST_CC_AGENT_GENERIC, and config.

Referenced by ast_cc_set_param(), and build_peer().

00719 {
00720    /* Screw C and its weak type checking for making me have to do this
00721     * validation at runtime.
00722     */
00723    if (value < AST_CC_AGENT_NEVER || value > AST_CC_AGENT_GENERIC) {
00724       return -1;
00725    }
00726    config->cc_agent_policy = value;
00727    return 0;
00728 }

void ast_set_cc_callback_macro ( struct ast_cc_config_params config,
const char *const   value 
)

Set the callback_macro name.

Since:
1.8
Parameters:
config The configuration to set the callback_macro on
value The new callback macro we want to change to
Return values:
void 

Definition at line 846 of file ccss.c.

References ast_copy_string(), ast_strlen_zero(), and config.

Referenced by ast_cc_set_param().

00847 {
00848    if (ast_strlen_zero(value)) {
00849       config->cc_callback_macro[0] = '\0';
00850    } else {
00851       ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
00852    }
00853 }

int ast_set_cc_interfaces_chanvar ( struct ast_channel chan,
const char *const   extension 
)

Set the CC_INTERFACES channel variable for a channel using an extension as a starting point.

Since:
1.8
The CC_INTERFACES channel variable will have the interfaces that should be called back for a specific PBX instance. This version of the function is used mainly by chan_local, wherein we need to set CC_INTERFACES based on an extension and context that appear in the middle of the tree of dialed interfaces

Note:
This function will lock the channel as well as the list of monitors stored on the channel's CC recall datastore, though neither are held at the same time. Callers of this function should be aware of potential lock ordering problems that may arise.
Parameters:
chan The channel to set the CC_INTERFACES variable on
extension The name of the extension for which we're setting the variable. This should be in the form of "exten@context"

Definition at line 3283 of file ccss.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log_dynamic_level, ast_str_buffer(), ast_str_create(), build_cc_interfaces_chanvar(), cc_recall_ds_data::core_id, ast_datastore::data, ast_cc_interface::device_name, ast_cc_monitor::interface, cc_recall_ds_data::interface_tree, cc_monitor_backend::next, pbx_builtin_setvar_helper(), recall_ds_info, and str.

Referenced by local_call().

03284 {
03285    struct ast_datastore *recall_datastore;
03286    struct cc_monitor_tree *interface_tree;
03287    struct ast_cc_monitor *monitor_iter;
03288    struct cc_recall_ds_data *recall_data;
03289    struct ast_str *str = ast_str_create(64);
03290    int core_id;
03291 
03292    if (!str) {
03293       return -1;
03294    }
03295 
03296    ast_channel_lock(chan);
03297    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03298       ast_channel_unlock(chan);
03299       ast_free(str);
03300       return -1;
03301    }
03302    recall_data = recall_datastore->data;
03303    interface_tree = recall_data->interface_tree;
03304    core_id = recall_data->core_id;
03305    ast_channel_unlock(chan);
03306 
03307    AST_LIST_LOCK(interface_tree);
03308    AST_LIST_TRAVERSE(interface_tree, monitor_iter, next) {
03309       if (!strcmp(monitor_iter->interface->device_name, extension)) {
03310          break;
03311       }
03312    }
03313 
03314    if (!monitor_iter) {
03315       /* We couldn't find this extension. This may be because
03316        * we have been directed into an unexpected extension because
03317        * the admin has changed a CC_INTERFACES variable at some point.
03318        */
03319       AST_LIST_UNLOCK(interface_tree);
03320       ast_free(str);
03321       return -1;
03322    }
03323 
03324    build_cc_interfaces_chanvar(monitor_iter, str);
03325    AST_LIST_UNLOCK(interface_tree);
03326 
03327    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03328    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03329          core_id, ast_str_buffer(str));
03330 
03331    ast_free(str);
03332    return 0;
03333 }

void ast_set_cc_max_agents ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_agents.

Since:
1.8
Parameters:
config The configuration to set the cc_max_agents on
value The new cc_max_agents we want to change to
Return values:
void 

Definition at line 826 of file ccss.c.

References config.

Referenced by ast_cc_set_param().

00827 {
00828    config->cc_max_agents = value;
00829 }

void ast_set_cc_max_monitors ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_monitors.

Since:
1.8
Parameters:
config The configuration to set the cc_max_monitors on
value The new cc_max_monitors we want to change to
Return values:
void 

Definition at line 836 of file ccss.c.

References config.

Referenced by ast_cc_set_param().

00837 {
00838    config->cc_max_monitors = value;
00839 }

int ast_set_cc_monitor_policy ( struct ast_cc_config_params config,
enum ast_cc_monitor_policies  value 
)

Set the cc_monitor_policy.

Since:
1.8
Parameters:
config The configuration to set the cc_monitor_policy on
value The new cc_monitor_policy we want to change to
Return values:
0 Success
-1 Failure (likely due to bad input)

Definition at line 735 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, and config.

Referenced by ast_cc_set_param().

00736 {
00737    /* Screw C and its weak type checking for making me have to do this
00738     * validation at runtime.
00739     */
00740    if (value < AST_CC_MONITOR_NEVER || value > AST_CC_MONITOR_ALWAYS) {
00741       return -1;
00742    }
00743    config->cc_monitor_policy = value;
00744    return 0;
00745 }

void ast_set_cc_offer_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_offer_timer.

Since:
1.8
Parameters:
config The configuration to set the cc_offer_timer on
value The new cc_offer_timer we want to change to
Return values:
void 

Definition at line 752 of file ccss.c.

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

00753 {
00754    /* 0 is an unreasonable value for any timer. Stick with the default */
00755    if (value == 0) {
00756       ast_log(LOG_WARNING, "0 is an invalid value for cc_offer_timer. Retaining value as %u\n", config->cc_offer_timer);
00757       return;
00758    }
00759    config->cc_offer_timer = value;
00760 }

void ast_set_cc_recall_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_recall_timer.

Since:
1.8
Parameters:
config The configuration to set the cc_recall_timer on
value The new cc_recall_timer we want to change to
Return values:
void 

Definition at line 782 of file ccss.c.

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

00783 {
00784    /* 0 is an unreasonable value for any timer. Stick with the default */
00785    if (value == 0) {
00786       ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
00787       return;
00788    }
00789    config->cc_recall_timer = value;
00790 }

void ast_set_ccbs_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccbs_available_timer.

Since:
1.8
Parameters:
config The configuration to set the ccbs_available_timer on
value The new ccbs_available_timer we want to change to
Return values:
void 

Definition at line 797 of file ccss.c.

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

00798 {
00799    /* 0 is an unreasonable value for any timer. Stick with the default */
00800    if (value == 0) {
00801       ast_log(LOG_WARNING, "0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
00802       return;
00803    }
00804    config->ccbs_available_timer = value;
00805 }

void ast_set_ccnr_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccnr_available_timer.

Since:
1.8
Parameters:
config The configuration to set the ccnr_available_timer on
value The new ccnr_available_timer we want to change to
Return values:
void 

Definition at line 767 of file ccss.c.

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

00768 {
00769    /* 0 is an unreasonable value for any timer. Stick with the default */
00770    if (value == 0) {
00771       ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->ccnr_available_timer);
00772       return;
00773    }
00774    config->ccnr_available_timer = value;
00775 }

int ast_setup_cc_recall_datastore ( struct ast_channel chan,
const int  core_id 
)

Set up a CC recall datastore on a channel.

Since:
1.8
Implementers of protocol-specific CC agents will need to call this function in order for the channel to have the necessary interfaces to recall.

This function must be called by the implementer once it has been detected that an inbound call is a cc_recall. After allocating the channel, call this function, followed by ast_cc_set_cc_interfaces_chanvar. While it would be nice to be able to have the core do this automatically, it just cannot be done given the current architecture.

Definition at line 3036 of file ccss.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_free, cc_ref(), cc_unref(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, find_cc_core_instance(), ast_datastore::inheritance, cc_core_instance::monitors, and recall_ds_info.

Referenced by generic_recall(), handle_request_invite(), and sig_pri_handle_subcmds().

03037 {
03038    struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
03039    struct cc_recall_ds_data *recall_data;
03040    struct cc_core_instance *core_instance;
03041 
03042    if (!recall_datastore) {
03043       return -1;
03044    }
03045 
03046    if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
03047       ast_datastore_free(recall_datastore);
03048       return -1;
03049    }
03050 
03051    if (!(core_instance = find_cc_core_instance(core_id))) {
03052       ast_free(recall_data);
03053       ast_datastore_free(recall_datastore);
03054       return -1;
03055    }
03056 
03057    recall_data->interface_tree = cc_ref(core_instance->monitors,
03058          "Bump refcount for monitor tree for recall datastore");
03059    recall_data->core_id = core_id;
03060    recall_datastore->data = recall_data;
03061    recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
03062    ast_channel_lock(chan);
03063    ast_channel_datastore_add(chan, recall_datastore);
03064    ast_channel_unlock(chan);
03065    cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
03066    return 0;
03067 }

static void build_cc_interfaces_chanvar ( struct ast_cc_monitor starting_point,
struct ast_str str 
) [static]

Definition at line 3215 of file ccss.c.

References AST_LIST_NEXT, AST_LIST_TRAVERSE, ast_str_strlen(), ast_str_truncate(), cc_unique_append(), extension_monitor_pvt::child_dialstrings, ast_cc_monitor::dialstring, ast_cc_monitor::id, extension_child_dialstring::is_valid, cc_monitor_backend::next, extension_child_dialstring::original_dialstring, ast_cc_monitor::parent_id, ast_cc_monitor::private_data, and str.

Referenced by ast_cc_agent_set_interfaces_chanvar(), and ast_set_cc_interfaces_chanvar().

03216 {
03217    struct extension_monitor_pvt *extension_pvt;
03218    struct extension_child_dialstring *child_dialstring;
03219    struct ast_cc_monitor *monitor_iter = starting_point;
03220    int top_level_id = starting_point->id;
03221 
03222    /* First we need to take all of the is_valid child_dialstrings from
03223     * the extension monitor we found and add them to the CC_INTERFACES
03224     * chanvar
03225     */
03226    extension_pvt = starting_point->private_data;
03227    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
03228       if (child_dialstring->is_valid) {
03229          cc_unique_append(str, child_dialstring->original_dialstring);
03230       }
03231    }
03232 
03233    /* And now we get the dialstrings from each of the device monitors */
03234    while ((monitor_iter = AST_LIST_NEXT(monitor_iter, next))) {
03235       if (monitor_iter->parent_id == top_level_id) {
03236          cc_unique_append(str, monitor_iter->dialstring);
03237       }
03238    }
03239 
03240    /* str will have an extra '&' tacked onto the end of it, so we need
03241     * to get rid of that.
03242     */
03243    ast_str_truncate(str, ast_str_strlen(str) - 1);
03244 }

static void call_destructor_with_no_monitor ( const char *const   monitor_type,
void *  private_data 
) [static]

Definition at line 1891 of file ccss.c.

References ast_cc_monitor_callbacks::destructor, and find_monitor_callbacks().

Referenced by ast_cc_busy_interface(), and ast_handle_cc_control_frame().

01892 {
01893    const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
01894 
01895    if (!monitor_callbacks) {
01896       return;
01897    }
01898 
01899    monitor_callbacks->destructor(private_data);
01900 }

static void cancel_available_timer ( struct cc_core_instance core_instance  )  [static]

Definition at line 2867 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cc_failed(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, ast_cc_monitor_callbacks::cancel_available_timer, cc_extension_monitor_change_is_valid(), cc_unref(), cc_core_instance::core_id, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, and cc_monitor_backend::next.

Referenced by cc_recalling().

02868 {
02869    struct ast_cc_monitor *monitor_iter;
02870    AST_LIST_LOCK(core_instance->monitors);
02871    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02872       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02873          if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
02874             AST_LIST_REMOVE_CURRENT(next);
02875             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02876                   monitor_iter->interface->device_name, 1);
02877             cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
02878          }
02879       }
02880    }
02881    AST_LIST_TRAVERSE_SAFE_END;
02882 
02883    if (!has_device_monitors(core_instance)) {
02884       ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
02885    }
02886    AST_LIST_UNLOCK(core_instance->monitors);
02887 }

static int cc_active ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2801 of file ccss.c.

References ast_cc_agent_callbacks::ack, cc_core_instance::agent, ast_cc_agent::callbacks, CC_CALLER_BUSY, CC_CALLER_REQUESTED, cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, manager_event, and unsuspend().

02802 {
02803    /* Either
02804     * 1. Callee accepted CC request, call agent's ack callback.
02805     * 2. Caller became available, call agent's stop_monitoring callback and
02806     *    call monitor's unsuspend callback.
02807     */
02808    if (previous_state == CC_CALLER_REQUESTED) {
02809       core_instance->agent->callbacks->ack(core_instance->agent);
02810       manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
02811          "CoreID: %d\r\n"
02812          "Caller: %s\r\n",
02813          core_instance->core_id, core_instance->agent->device_name);
02814    } else if (previous_state == CC_CALLER_BUSY) {
02815       manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
02816          "CoreID: %d\r\n"
02817          "Caller: %s\r\n",
02818          core_instance->core_id, core_instance->agent->device_name);
02819       unsuspend(core_instance);
02820    }
02821    /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
02822    return 0;
02823 }

static int cc_agent_callback_helper ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 401 of file ccss.c.

References cc_core_instance::agent, cc_callback_helper::args, ast_cc_agent::callbacks, cc_callback_helper::function, cc_callback_helper::type, and ast_cc_agent_callbacks::type.

Referenced by ast_cc_agent_callback().

00402 {
00403    struct cc_core_instance *core_instance = obj;
00404    struct cc_callback_helper *helper = args;
00405 
00406    if (strcmp(core_instance->agent->callbacks->type, helper->type)) {
00407       return 0;
00408    }
00409 
00410    return helper->function(core_instance->agent, helper->args, flags);
00411 }

static struct ast_cc_agent* cc_agent_init ( struct ast_channel caller_chan,
const char *const   caller_name,
const int  core_id,
struct cc_monitor_tree interface_tree 
) [static]

Definition at line 2225 of file ccss.c.

References agent_destroy(), ao2_t_alloc, ast_cc_config_params_init, ast_cc_copy_config_params(), ast_channel_get_cc_config_params(), ast_log_dynamic_level, cc_unref(), check_callback_sanity(), ast_cc_agent::core_id, and find_agent_callbacks().

Referenced by cc_core_init_instance().

02228 {
02229    struct ast_cc_agent *agent;
02230    struct ast_cc_config_params *cc_params;
02231 
02232    if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
02233                "Allocating new ast_cc_agent"))) {
02234       return NULL;
02235    }
02236 
02237    agent->core_id = core_id;
02238    strcpy(agent->device_name, caller_name);
02239 
02240    cc_params = ast_channel_get_cc_config_params(caller_chan);
02241    if (!cc_params) {
02242       cc_unref(agent, "Could not get channel config params.");
02243       return NULL;
02244    }
02245    if (!(agent->cc_params = ast_cc_config_params_init())) {
02246       cc_unref(agent, "Could not init agent config params.");
02247       return NULL;
02248    }
02249    ast_cc_copy_config_params(agent->cc_params, cc_params);
02250 
02251    if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
02252       cc_unref(agent, "Could not find agent callbacks.");
02253       return NULL;
02254    }
02255    check_callback_sanity(agent->callbacks);
02256 
02257    if (agent->callbacks->init(agent, caller_chan)) {
02258       cc_unref(agent, "Agent init callback failed.");
02259       return NULL;
02260    }
02261    ast_log_dynamic_level(cc_logger_level, "Core %d: Created an agent for caller %s\n",
02262          agent->core_id, agent->device_name);
02263    return agent;
02264 }

static int cc_available ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2684 of file ccss.c.

References ast_log(), and LOG_WARNING.

02685 {
02686    /* This should never happen... */
02687    ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
02688    return -1;
02689 }

static int cc_build_payload ( struct ast_channel chan,
struct ast_cc_config_params cc_params,
const char *  monitor_type,
const char *const   device_name,
const char *  dialstring,
enum ast_cc_service_type  service,
void *  private_data,
struct cc_control_payload payload 
) [static]

Definition at line 3739 of file ccss.c.

References ast_cc_copy_config_params(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), cc_control_payload::config_params, ast_datastore::data, cc_control_payload::device_name, dialed_cc_interfaces::dial_parent_id, dialed_cc_interfaces_info, cc_control_payload::dialstring, cc_control_payload::monitor_type, cc_control_payload::parent_interface_id, cc_control_payload::private_data, and cc_control_payload::service.

Referenced by ast_cc_build_frame(), ast_cc_busy_interface(), and ast_cc_call_failed().

03742 {
03743    struct ast_datastore *datastore;
03744    struct dialed_cc_interfaces *cc_interfaces;
03745    int dial_parent_id;
03746 
03747    ast_channel_lock(chan);
03748    datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL);
03749    if (!datastore) {
03750       ast_channel_unlock(chan);
03751       return -1;
03752    }
03753    cc_interfaces = datastore->data;
03754    dial_parent_id = cc_interfaces->dial_parent_id;
03755    ast_channel_unlock(chan);
03756 
03757    payload->monitor_type = monitor_type;
03758    payload->private_data = private_data;
03759    payload->service = service;
03760    ast_cc_copy_config_params(&payload->config_params, cc_params);
03761    payload->parent_interface_id = dial_parent_id;
03762    ast_copy_string(payload->device_name, device_name, sizeof(payload->device_name));
03763    ast_copy_string(payload->dialstring, dialstring, sizeof(payload->dialstring));
03764    return 0;
03765 }

static int cc_callee_ready ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2825 of file ccss.c.

References cc_core_instance::agent, ast_cc_agent::callbacks, and ast_cc_agent_callbacks::callee_available.

02826 {
02827    core_instance->agent->callbacks->callee_available(core_instance->agent);
02828    return 0;
02829 }

static int cc_caller_busy ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2853 of file ccss.c.

References cc_core_instance::agent, ast_cc_agent::callbacks, cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, manager_event, ast_cc_agent_callbacks::start_monitoring, and suspend().

02854 {
02855    /* Callee was available, but caller was busy, call agent's begin_monitoring callback
02856     * and call monitor's suspend callback.
02857     */
02858    suspend(core_instance);
02859    core_instance->agent->callbacks->start_monitoring(core_instance->agent);
02860    manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
02861       "CoreID: %d\r\n"
02862       "Caller: %s\r\n",
02863       core_instance->core_id, core_instance->agent->device_name);
02864    return 0;
02865 }

static int cc_caller_offered ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2691 of file ccss.c.

References cc_core_instance::agent, ast_cc_failed(), ast_log_dynamic_level, ast_cc_agent::callbacks, ast_cc_config_params::cc_offer_timer, ast_cc_agent::cc_params, cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, manager_event, and ast_cc_agent_callbacks::start_offer_timer.

02692 {
02693    if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
02694       ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
02695             core_instance->agent->device_name);
02696       return -1;
02697    }
02698    manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
02699       "CoreID: %d\r\n"
02700       "Caller: %s\r\n"
02701       "Expires: %u\r\n",
02702       core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
02703    ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
02704          core_instance->core_id, core_instance->agent->device_name);
02705    return 0;
02706 }

static int cc_caller_requested ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2767 of file ccss.c.

References cc_core_instance::agent, ast_cc_failed(), ast_cc_request_is_within_limits(), ast_log(), ast_cc_agent::callbacks, cc_core_instance::core_id, LOG_WARNING, request_cc(), and ast_cc_agent_callbacks::stop_offer_timer.

02768 {
02769    if (!ast_cc_request_is_within_limits()) {
02770       ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
02771       ast_cc_failed(core_instance->core_id, "Too many requests in the system");
02772       return -1;
02773    }
02774    core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
02775    request_cc(core_instance);
02776    return 0;
02777 }

static int cc_cli_output_status ( void *  data  )  [static]

Definition at line 4043 of file ccss.c.

References ao2_container_count(), ao2_t_callback, ast_cli(), ast_free, cc_core_instances, OBJ_NODATA, and print_stats_cb().

Referenced by handle_cc_status().

04044 {
04045    int *cli_fd = data;
04046    int count = ao2_container_count(cc_core_instances);
04047 
04048    if (!count) {
04049       ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
04050    } else {
04051       ast_cli(*cli_fd, "%d Call completion transactions\n", count);
04052       ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
04053       ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
04054       ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
04055    }
04056    ast_free(cli_fd);
04057    return 0;
04058 }

static void cc_cli_print_monitor_stats ( struct ast_cc_monitor monitor,
int  fd,
int  parent_id 
) [static]

Definition at line 4010 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cli(), AST_LIST_NEXT, cc_service_to_string(), ast_cc_monitor::id, monitor, cc_monitor_backend::next, and ast_cc_monitor::parent_id.

Referenced by print_stats_cb().

04011 {
04012    struct ast_cc_monitor *child_monitor_iter = monitor;
04013    if (!monitor) {
04014       return;
04015    }
04016 
04017    ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
04018    if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
04019       ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
04020    }
04021    ast_cli(fd, "\n");
04022 
04023    while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
04024       if (child_monitor_iter->parent_id == monitor->id) {
04025          cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
04026       }
04027    }
04028 }

static int cc_complete ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2901 of file ccss.c.

References cc_core_instance::agent, ao2_t_unlink, cc_core_instances, cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, and manager_event.

02902 {
02903    /* Recall has made progress, call agent and monitor destructor functions
02904     */
02905    manager_event(EVENT_FLAG_CC, "CCRecallComplete",
02906       "CoreID: %d\r\n"
02907       "Caller: %s\r\n",
02908       core_instance->core_id, core_instance->agent->device_name);
02909    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
02910    return 0;
02911 }

static struct cc_core_instance * cc_core_init_instance ( struct ast_channel caller_chan,
struct cc_monitor_tree called_tree,
const int  core_id,
struct cc_control_payload cc_data 
) [static]

Definition at line 2568 of file ccss.c.

References ao2_t_alloc, ao2_t_link, AST_CC_AGENT_GENERIC, ast_cc_is_recall(), ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_get_cc_agent_policy(), ast_get_cc_max_agents(), ast_log_dynamic_level, cc_agent_init(), cc_core_instance_destructor(), cc_core_instances, cc_ref(), cc_unref(), count_agents(), and kill_duplicate_offers().

Referenced by ast_handle_cc_control_frame().

02570 {
02571    char caller[AST_CHANNEL_NAME];
02572    struct cc_core_instance *core_instance;
02573    struct ast_cc_config_params *cc_params;
02574    long agent_count;
02575    int recall_core_id;
02576 
02577    ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
02578    cc_params = ast_channel_get_cc_config_params(caller_chan);
02579    if (!cc_params) {
02580       ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
02581          caller);
02582       return NULL;
02583    }
02584    /* First, we need to kill off other pending CC offers from caller. If the caller is going
02585     * to request a CC service, it may only be for the latest call he made.
02586     */
02587    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02588       kill_duplicate_offers(caller);
02589    }
02590 
02591    ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
02592    agent_count = count_agents(caller, recall_core_id);
02593    if (agent_count >= ast_get_cc_max_agents(cc_params)) {
02594       ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
02595       return NULL;
02596    }
02597 
02598    /* Generic agents can only have a single outstanding CC request per caller. */
02599    if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02600       ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
02601       return NULL;
02602    }
02603 
02604    /* Next, we need to create the core instance for this call */
02605    if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
02606       return NULL;
02607    }
02608 
02609    core_instance->core_id = core_id;
02610    if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
02611       cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
02612       return NULL;
02613    }
02614 
02615    core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");
02616 
02617    ao2_t_link(cc_core_instances, core_instance, "Link core instance into container");
02618 
02619    return core_instance;
02620 }

static int cc_core_instance_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 380 of file ccss.c.

References CMP_MATCH, CMP_STOP, and cc_core_instance::core_id.

Referenced by ast_cc_init().

00381 {
00382    struct cc_core_instance *core_instance1 = obj;
00383    struct cc_core_instance *core_instance2 = arg;
00384 
00385    return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
00386 }

static void cc_core_instance_destructor ( void *  data  )  [static]

Definition at line 2556 of file ccss.c.

References cc_core_instance::agent, ast_log_dynamic_level, cc_unref(), cc_core_instance::core_id, and cc_core_instance::monitors.

Referenced by cc_core_init_instance().

02557 {
02558    struct cc_core_instance *core_instance = data;
02559    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
02560    if (core_instance->agent) {
02561       cc_unref(core_instance->agent, "Core instance is done with the agent now");
02562    }
02563    if (core_instance->monitors) {
02564       core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
02565    }
02566 }

static int cc_core_instance_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 374 of file ccss.c.

References cc_core_instance::core_id.

Referenced by ast_cc_init().

00375 {
00376    const struct cc_core_instance *core_instance = obj;
00377    return core_instance->core_id;
00378 }

static struct ast_cc_monitor* cc_device_monitor_init ( const char *const   device_name,
const char *const   dialstring,
const struct cc_control_payload cc_data,
int  core_id 
) [static]

Definition at line 1927 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), ast_cc_config_params_init, ast_cc_copy_config_params(), AST_CC_DEVICE_MONITOR, ast_log_dynamic_level, ast_strdup, cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), cc_control_payload::config_params, find_monitor_callbacks(), monitor, cc_control_payload::monitor_type, ast_cc_monitor::parent_id, cc_control_payload::parent_interface_id, cc_control_payload::private_data, and cc_control_payload::service.

Referenced by ast_handle_cc_control_frame().

01928 {
01929    struct ast_cc_interface *cc_interface;
01930    struct ast_cc_monitor *monitor;
01931    size_t device_name_len = strlen(device_name);
01932    int parent_id = cc_data->parent_interface_id;
01933 
01934    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
01935                "Allocating new ast_cc_interface"))) {
01936       return NULL;
01937    }
01938 
01939    if (!(cc_interface->config_params = ast_cc_config_params_init())) {
01940       cc_unref(cc_interface, "Failed to allocate config params, unref interface");
01941       return NULL;
01942    }
01943 
01944    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
01945       cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
01946       return NULL;
01947    }
01948 
01949    if (!(monitor->dialstring = ast_strdup(dialstring))) {
01950       cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
01951       cc_unref(cc_interface, "Failed to copy dialable name");
01952       return NULL;
01953    }
01954 
01955    if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
01956       cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
01957       cc_unref(cc_interface, "Failed to find monitor callbacks");
01958       return NULL;
01959    }
01960 
01961    strcpy(cc_interface->device_name, device_name);
01962    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
01963    monitor->parent_id = parent_id;
01964    monitor->core_id = core_id;
01965    monitor->service_offered = cc_data->service;
01966    monitor->private_data = cc_data->private_data;
01967    cc_interface->monitor_type = cc_data->monitor_type;
01968    cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
01969    monitor->interface = cc_interface;
01970    monitor->available_timer_id = -1;
01971    ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
01972    ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %d and parent %d\n",
01973          monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
01974    return monitor;
01975 }

static int cc_do_state_change ( void *  datap  )  [static]

Definition at line 2936 of file ccss.c.

References cc_core_instance::agent, args, ast_free, ast_log_dynamic_level, cc_state_to_string(), cc_unref(), cc_core_instance::current_state, find_cc_core_instance(), is_state_change_valid(), and state_change_funcs.

Referenced by cc_request_state_change().

02937 {
02938    struct cc_state_change_args *args = datap;
02939    struct cc_core_instance *core_instance;
02940    enum cc_state previous_state;
02941    int res;
02942 
02943    ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
02944          args->core_id, args->state, args->debug);
02945 
02946    if (!(core_instance = find_cc_core_instance(args->core_id))) {
02947       ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n", args->core_id);
02948       ast_free(args);
02949       return -1;
02950    }
02951 
02952    if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
02953       ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
02954             args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
02955       ast_free(args);
02956       cc_unref(core_instance, "Unref core instance from when it was found earlier");
02957       return -1;
02958    }
02959 
02960    /* We can change to the new state now. */
02961    previous_state = core_instance->current_state;
02962    core_instance->current_state = args->state;
02963    res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);
02964 
02965    ast_free(args);
02966    cc_unref(core_instance, "Unref since state change has completed"); /* From ao2_find */
02967    return res;
02968 }

static void cc_extension_monitor_change_is_valid ( struct cc_core_instance core_instance,
unsigned int  parent_id,
const char *const   device_name,
int  is_valid 
) [static]

Definition at line 1725 of file ccss.c.

References AST_LIST_TRAVERSE, extension_monitor_pvt::child_dialstrings, extension_child_dialstring::device_name, ast_cc_monitor::id, extension_child_dialstring::is_valid, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor::private_data.

Referenced by ast_handle_cc_control_frame(), cancel_available_timer(), cc_monitor_failed(), request_cc(), suspend(), and unsuspend().

01726 {
01727    struct ast_cc_monitor *monitor_iter;
01728    struct extension_monitor_pvt *extension_pvt;
01729    struct extension_child_dialstring *child_dialstring;
01730 
01731    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
01732       if (monitor_iter->id == parent_id) {
01733          break;
01734       }
01735    }
01736 
01737    if (!monitor_iter) {
01738       return;
01739    }
01740    extension_pvt = monitor_iter->private_data;
01741 
01742    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
01743       if (!strcmp(child_dialstring->device_name, device_name)) {
01744          child_dialstring->is_valid = is_valid;
01745          break;
01746       }
01747    }
01748 }

static void cc_extension_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1496 of file ccss.c.

References ast_free, AST_LIST_REMOVE_HEAD, extension_monitor_pvt::child_dialstrings, and cc_monitor_backend::next.

Referenced by cc_monitor_destroy().

01497 {
01498    struct extension_monitor_pvt *extension_pvt = private_data;
01499    struct extension_child_dialstring *child_dialstring;
01500 
01501    /* This shouldn't be possible, but I'm paranoid */
01502    if (!extension_pvt) {
01503       return;
01504    }
01505 
01506    while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
01507       ast_free(child_dialstring);
01508    }
01509    ast_free(extension_pvt);
01510 }

static struct ast_cc_monitor* cc_extension_monitor_init ( const char *const   exten,
const char *const   context,
const unsigned int  parent_id 
) [static]

Definition at line 1764 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), AST_CC_EXTENSION_MONITOR, ast_log_dynamic_level, AST_MAX_EXTENSION, ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_str_strlen(), cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), extension_monitor_pvt_init(), monitor, and str.

Referenced by ast_cc_call_init(), and cc_interfaces_datastore_init().

01765 {
01766    struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
01767    struct ast_cc_interface *cc_interface;
01768    struct ast_cc_monitor *monitor;
01769 
01770    ast_str_set(&str, 0, "%s@%s", exten, context);
01771 
01772    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
01773                "Allocating new ast_cc_interface"))) {
01774       return NULL;
01775    }
01776 
01777    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
01778       cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
01779       return NULL;
01780    }
01781 
01782    if (!(monitor->private_data = extension_monitor_pvt_init())) {
01783       cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
01784       cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
01785    }
01786 
01787    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
01788    monitor->parent_id = parent_id;
01789    cc_interface->monitor_type = "extension";
01790    cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
01791    strcpy(cc_interface->device_name, ast_str_buffer(str));
01792    monitor->interface = cc_interface;
01793    ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %d and parent %d\n", cc_interface->device_name, monitor->id, monitor->parent_id);
01794    return monitor;
01795 }

static int cc_failed ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2913 of file ccss.c.

References cc_core_instance::agent, ao2_t_unlink, args, cc_core_instances, cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, and manager_event.

02914 {
02915    manager_event(EVENT_FLAG_CC, "CCFailure",
02916       "CoreID: %d\r\n"
02917       "Caller: %s\r\n"
02918       "Reason: %s\r\n",
02919       core_instance->core_id, core_instance->agent->device_name, args->debug);
02920    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
02921    return 0;
02922 }

static void cc_generic_agent_ack ( struct ast_cc_agent agent  )  [static]

Definition at line 2406 of file ccss.c.

02407 {
02408    /* The generic agent doesn't have to do anything special to
02409     * acknowledge a CC request. Just return.
02410     */
02411    return;
02412 }

static void cc_generic_agent_destructor ( struct ast_cc_agent agent  )  [static]

Definition at line 2539 of file ccss.c.

References ast_event_unsubscribe(), ast_free, cc_generic_agent_stop_offer_timer(), ast_cc_agent::private_data, and cc_generic_agent_pvt::sub.

02540 {
02541    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02542 
02543    if (!agent_pvt) {
02544       /* The agent constructor probably failed. */
02545       return;
02546    }
02547 
02548    cc_generic_agent_stop_offer_timer(agent);
02549    if (agent_pvt->sub) {
02550       agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
02551    }
02552 
02553    ast_free(agent_pvt);
02554 }

static int cc_generic_agent_init ( struct ast_cc_agent agent,
struct ast_channel chan 
) [static]

Definition at line 2340 of file ccss.c.

References ast_calloc, AST_CC_AGENT_SKIP_OFFER, ast_copy_string(), ast_set_flag, ast_channel::caller, ast_channel::context, ast_channel::exten, ast_party_caller::id, ast_channel::macrocontext, ast_channel::macroexten, ast_party_id::name, ast_party_id::number, ast_cc_agent::private_data, S_OR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

02341 {
02342    struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
02343 
02344    if (!generic_pvt) {
02345       return -1;
02346    }
02347 
02348    generic_pvt->offer_timer_id = -1;
02349    if (chan->caller.id.number.valid && chan->caller.id.number.str) {
02350       ast_copy_string(generic_pvt->cid_num, chan->caller.id.number.str, sizeof(generic_pvt->cid_num));
02351    }
02352    if (chan->caller.id.name.valid && chan->caller.id.name.str) {
02353       ast_copy_string(generic_pvt->cid_name, chan->caller.id.name.str, sizeof(generic_pvt->cid_name));
02354    }
02355    ast_copy_string(generic_pvt->exten, S_OR(chan->macroexten, chan->exten), sizeof(generic_pvt->exten));
02356    ast_copy_string(generic_pvt->context, S_OR(chan->macrocontext, chan->context), sizeof(generic_pvt->context));
02357    agent->private_data = generic_pvt;
02358    ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
02359    return 0;
02360 }

static int cc_generic_agent_recall ( struct ast_cc_agent agent  )  [static]

Definition at line 2523 of file ccss.c.

References ast_cc_agent_caller_busy(), AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, ast_pthread_create_detached_background, ast_cc_agent::core_id, ast_cc_agent::device_name, and generic_recall().

02524 {
02525    pthread_t clotho;
02526    enum ast_device_state current_state = ast_device_state(agent->device_name);
02527 
02528    if (current_state != AST_DEVICE_NOT_INUSE && current_state != AST_DEVICE_UNKNOWN) {
02529       /* We can't try to contact the device right now because he's not available
02530        * Let the core know he's busy.
02531        */
02532       ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
02533       return 0;
02534    }
02535    ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
02536    return 0;
02537 }

static int cc_generic_agent_start_monitoring ( struct ast_cc_agent agent  )  [static]

Definition at line 2456 of file ccss.c.

References ast_assert, AST_DEVICE_NOT_INUSE, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_IE_STATE, ast_event_subscribe(), ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_cc_agent::device_name, generic_agent_devstate_cb(), ast_cc_agent::private_data, str, and cc_generic_agent_pvt::sub.

02457 {
02458    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02459    struct ast_str *str = ast_str_alloca(128);
02460 
02461    ast_assert(generic_pvt->sub == NULL);
02462    ast_str_set(&str, 0, "Starting to monitor %s device state since it is busy\n", agent->device_name);
02463 
02464    if (!(generic_pvt->sub = ast_event_subscribe(
02465          AST_EVENT_DEVICE_STATE, generic_agent_devstate_cb, ast_str_buffer(str), agent,
02466          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->device_name,
02467          AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, AST_DEVICE_NOT_INUSE,
02468          AST_EVENT_IE_END))) {
02469       return -1;
02470    }
02471    return 0;
02472 }

static int cc_generic_agent_start_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2374 of file ccss.c.

References ast_assert, ast_get_cc_offer_timer(), ast_log_dynamic_level, ast_sched_thread_add(), ast_cc_agent::cc_params, cc_ref(), cc_sched_thread, ast_cc_agent::core_id, offer_timer_expire(), cc_generic_agent_pvt::offer_timer_id, and ast_cc_agent::private_data.

02375 {
02376    int when;
02377    int sched_id;
02378    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02379 
02380    ast_assert(cc_sched_thread != NULL);
02381    ast_assert(agent->cc_params != NULL);
02382 
02383    when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
02384    ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
02385          agent->core_id, when);
02386    if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
02387       return -1;
02388    }
02389    generic_pvt->offer_timer_id = sched_id;
02390    return 0;
02391 }

static int cc_generic_agent_status_request ( struct ast_cc_agent agent  )  [static]

Definition at line 2414 of file ccss.c.

References ast_cc_agent_status_response(), ast_device_state(), ast_cc_agent::core_id, and ast_cc_agent::device_name.

02415 {
02416    ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
02417    return 0;
02418 }

static int cc_generic_agent_stop_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2393 of file ccss.c.

References ast_sched_thread_del, cc_sched_thread, cc_unref(), cc_generic_agent_pvt::offer_timer_id, and ast_cc_agent::private_data.

Referenced by cc_generic_agent_destructor().

02394 {
02395    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02396 
02397    if (generic_pvt->offer_timer_id != -1) {
02398       if (!ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id)) {
02399          cc_unref(agent, "Remove scheduler's reference to the agent");
02400       }
02401       generic_pvt->offer_timer_id = -1;
02402    }
02403    return 0;
02404 }

static int cc_generic_agent_stop_ringing ( struct ast_cc_agent agent  )  [static]

Definition at line 2420 of file ccss.c.

References ast_channel_get_by_name_prefix(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, and ast_cc_agent::device_name.

02421 {
02422    struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
02423 
02424    if (!recall_chan) {
02425       return 0;
02426    }
02427 
02428    ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
02429    return 0;
02430 }

static int cc_generic_monitor_cancel_available_timer ( struct ast_cc_monitor monitor,
int *  sched_id 
) [static]

Definition at line 1326 of file ccss.c.

References ast_assert, ast_log_dynamic_level, ast_sched_thread_del, cc_sched_thread, cc_unref(), and monitor.

01327 {
01328    ast_assert(sched_id != NULL);
01329 
01330    if (*sched_id == -1) {
01331       return 0;
01332    }
01333 
01334    ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
01335          monitor->core_id, monitor->interface->device_name);
01336    if (!ast_sched_thread_del(cc_sched_thread, *sched_id)) {
01337       cc_unref(monitor, "Remove scheduler's reference to the monitor");
01338    }
01339    *sched_id = -1;
01340    return 0;
01341 }

static void cc_generic_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1343 of file ccss.c.

References ao2_t_unlink, ast_cc_monitor_callee_available(), AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log_dynamic_level, cc_unref(), generic_monitor_instance::core_id, generic_monitor_pvt::core_id, generic_monitor_instance_list::current_state, generic_monitor_pvt::device_name, find_generic_monitor_instance_list(), generic_monitor_instance_list::fit_for_recall, generic_monitors, generic_monitor_instance::is_suspended, generic_monitor_instance_list::list, generic_monitor_instance::monitoring, and cc_monitor_backend::next.

01344 {
01345    struct generic_monitor_pvt *gen_mon_pvt = private_data;
01346    struct generic_monitor_instance_list *generic_list;
01347    struct generic_monitor_instance *generic_instance;
01348 
01349    if (!private_data) {
01350       /* If the private data is NULL, that means that the monitor hasn't even
01351        * been created yet, but that the destructor was called. While this sort
01352        * of behavior is useful for native monitors, with a generic one, there is
01353        * nothing in particular to do.
01354        */
01355       return;
01356    }
01357 
01358    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying generic monitor %s\n",
01359          gen_mon_pvt->core_id, gen_mon_pvt->device_name);
01360 
01361    if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->device_name))) {
01362       /* If there's no generic list, that means that the monitor is being destroyed
01363        * before we actually got to request CC. Not a biggie. Same in the situation
01364        * below if the list traversal should complete without finding an entry.
01365        */
01366       ast_free((char *)gen_mon_pvt->device_name);
01367       ast_free(gen_mon_pvt);
01368       return;
01369    }
01370 
01371    AST_LIST_TRAVERSE_SAFE_BEGIN(&generic_list->list, generic_instance, next) {
01372       if (generic_instance->core_id == gen_mon_pvt->core_id) {
01373          AST_LIST_REMOVE_CURRENT(next);
01374          ast_free(generic_instance);
01375          break;
01376       }
01377    }
01378    AST_LIST_TRAVERSE_SAFE_END;
01379 
01380    if (AST_LIST_EMPTY(&generic_list->list)) {
01381       /* No more monitors with this device name exist. Time to unlink this
01382        * list from the container
01383        */
01384       ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
01385    } else {
01386       /* There are still instances for this particular device. The situation
01387        * may be that we were attempting a CC recall and a failure occurred, perhaps
01388        * on the agent side. If a failure happens here and the device being monitored
01389        * is available, then we need to signal on the first unsuspended instance that
01390        * the device is available for recall.
01391        */
01392 
01393       /* First things first. We don't even want to consider this action if
01394        * the device in question isn't available right now.
01395        */
01396       if (generic_list->fit_for_recall && (generic_list->current_state == AST_DEVICE_NOT_INUSE ||
01397             generic_list->current_state == AST_DEVICE_UNKNOWN)) {
01398          AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01399             if (!generic_instance->is_suspended && generic_instance->monitoring) {
01400                ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
01401                      "availability due to other instance's failure.");
01402                break;
01403             }
01404          }
01405       }
01406    }
01407    cc_unref(generic_list, "Done with generic list in generic monitor destructor");
01408    ast_free((char *)gen_mon_pvt->device_name);
01409    ast_free(gen_mon_pvt);
01410 }

static int cc_generic_monitor_request_cc ( struct ast_cc_monitor monitor,
int *  available_timer_id 
) [static]

Definition at line 1194 of file ccss.c.

References ast_calloc, ast_cc_available_timer_expire(), AST_CC_CCBS, AST_CC_CCNL, AST_CC_CCNR, ast_cc_monitor_request_acked(), ast_free, ast_get_ccbs_available_timer(), ast_get_ccnr_available_timer(), AST_LIST_INSERT_TAIL, ast_sched_thread_add(), ast_strdup, cc_ref(), cc_sched_thread, cc_unref(), create_new_generic_list(), find_generic_monitor_instance_list(), generic_monitor_instance_list::fit_for_recall, generic_monitor_instance_list::list, monitor, cc_monitor_backend::next, and service.

01195 {
01196    struct generic_monitor_instance_list *generic_list;
01197    struct generic_monitor_instance *generic_instance;
01198    struct generic_monitor_pvt *gen_mon_pvt;
01199    enum ast_cc_service_type service = monitor->service_offered;
01200    int when;
01201 
01202    /* First things first. Native channel drivers will have their private data allocated
01203     * at the time that they tell the core that they can offer CC. Generic is quite a bit
01204     * different, and we wait until this point to allocate our private data.
01205     */
01206    if (!(gen_mon_pvt = ast_calloc(1, sizeof(*gen_mon_pvt)))) {
01207       return -1;
01208    }
01209 
01210    if (!(gen_mon_pvt->device_name = ast_strdup(monitor->interface->device_name))) {
01211       ast_free(gen_mon_pvt);
01212       return -1;
01213    }
01214 
01215    gen_mon_pvt->core_id = monitor->core_id;
01216 
01217    monitor->private_data = gen_mon_pvt;
01218 
01219    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01220       if (!(generic_list = create_new_generic_list(monitor))) {
01221          return -1;
01222       }
01223    }
01224 
01225    if (!(generic_instance = ast_calloc(1, sizeof(*generic_instance)))) {
01226       /* The generic monitor destructor will take care of the appropriate
01227        * deallocations
01228        */
01229       cc_unref(generic_list, "Generic monitor instance failed to allocate");
01230       return -1;
01231    }
01232    generic_instance->core_id = monitor->core_id;
01233    generic_instance->monitoring = 1;
01234    AST_LIST_INSERT_TAIL(&generic_list->list, generic_instance, next);
01235    when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
01236       ast_get_ccnr_available_timer(monitor->interface->config_params);
01237 
01238    *available_timer_id = ast_sched_thread_add(cc_sched_thread, when * 1000,
01239          ast_cc_available_timer_expire, cc_ref(monitor, "Give the scheduler a monitor reference"));
01240    if (*available_timer_id == -1) {
01241       cc_unref(monitor, "Failed to schedule available timer. (monitor)");
01242       cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
01243       return -1;
01244    }
01245    /* If the new instance was created as CCNR, then that means this device is not currently
01246     * fit for recall even if it previously was.
01247     */
01248    if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
01249       generic_list->fit_for_recall = 0;
01250    }
01251    ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
01252          monitor->interface->device_name);
01253    cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
01254    return 0;
01255 }

static int cc_generic_monitor_suspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1257 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, AST_LIST_TRAVERSE, cc_unref(), generic_monitor_instance::core_id, find_generic_monitor_instance_list(), generic_monitor_instance::is_suspended, generic_monitor_instance_list::list, monitor, and cc_monitor_backend::next.

01258 {
01259    struct generic_monitor_instance_list *generic_list;
01260    struct generic_monitor_instance *generic_instance;
01261    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01262 
01263    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01264       return -1;
01265    }
01266 
01267    /* First we need to mark this particular monitor as being suspended. */
01268    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01269       if (generic_instance->core_id == monitor->core_id) {
01270          generic_instance->is_suspended = 1;
01271          break;
01272       }
01273    }
01274 
01275    /* If the device being suspended is currently in use, then we don't need to
01276     * take any further actions
01277     */
01278    if (state != AST_DEVICE_NOT_INUSE && state != AST_DEVICE_UNKNOWN) {
01279       cc_unref(generic_list, "Device is in use. Nothing to do. Unref generic list.");
01280       return 0;
01281    }
01282 
01283    /* If the device is not in use, though, then it may be possible to report the
01284     * device's availability using a different monitor which is monitoring the
01285     * same device
01286     */
01287 
01288    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01289       if (!generic_instance->is_suspended) {
01290          ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01291          break;
01292       }
01293    }
01294    cc_unref(generic_list, "Done with generic list in suspend callback");
01295    return 0;
01296 }

static int cc_generic_monitor_unsuspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1298 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, AST_LIST_TRAVERSE, cc_unref(), generic_monitor_instance::core_id, find_generic_monitor_instance_list(), generic_monitor_instance::is_suspended, generic_monitor_instance_list::list, monitor, generic_monitor_instance::monitoring, and cc_monitor_backend::next.

01299 {
01300    struct generic_monitor_instance *generic_instance;
01301    struct generic_monitor_instance_list *generic_list = find_generic_monitor_instance_list(monitor->interface->device_name);
01302    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01303 
01304    if (!generic_list) {
01305       return -1;
01306    }
01307    /* If the device is currently available, we can immediately announce
01308     * its availability
01309     */
01310    if (state == AST_DEVICE_NOT_INUSE || state == AST_DEVICE_UNKNOWN) {
01311       ast_cc_monitor_callee_available(monitor->core_id, "Generic monitored party has become available");
01312    }
01313 
01314    /* In addition, we need to mark this generic_monitor_instance as not being suspended anymore */
01315    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01316       if (generic_instance->core_id == monitor->core_id) {
01317          generic_instance->is_suspended = 0;
01318          generic_instance->monitoring = 1;
01319          break;
01320       }
01321    }
01322    cc_unref(generic_list, "Done with generic list in cc_generic_monitor_unsuspend");
01323    return 0;
01324 }

static void cc_interface_destroy ( void *  data  )  [static]

Definition at line 1412 of file ccss.c.

References ast_cc_config_params_destroy(), ast_log_dynamic_level, ast_cc_interface::config_params, and ast_cc_interface::device_name.

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

01413 {
01414    struct ast_cc_interface *interface = data;
01415    ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
01416    ast_cc_config_params_destroy(interface->config_params);
01417 }

static void cc_interface_tree_destroy ( void *  data  )  [static]

Definition at line 1533 of file ccss.c.

References AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, cc_unref(), monitor, and cc_monitor_backend::next.

Referenced by cc_interfaces_datastore_init().

01534 {
01535    struct cc_monitor_tree *cc_interface_tree = data;
01536    struct ast_cc_monitor *monitor;
01537    while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
01538       if (monitor->callbacks) {
01539          monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
01540       }
01541       cc_unref(monitor, "Destroying all monitors");
01542    }
01543    AST_LIST_HEAD_DESTROY(cc_interface_tree);
01544 }

static int cc_interfaces_datastore_init ( struct ast_channel chan  )  [static]

Definition at line 1813 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), ast_calloc, ast_cc_request_is_within_limits(), ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, cc_extension_monitor_init(), cc_interface_tree_destroy(), cc_ref(), cc_unref(), ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dialed_cc_interfaces_info, ast_channel::exten, ast_datastore::inheritance, ast_channel::macrocontext, ast_channel::macroexten, monitor, cc_monitor_backend::next, and S_OR.

Referenced by ast_cc_call_init().

01813                                                                   {
01814    struct dialed_cc_interfaces *interfaces;
01815    struct ast_cc_monitor *monitor;
01816    struct ast_datastore *dial_cc_datastore;
01817 
01818    /*XXX This may be a bit controversial. In an attempt to not allocate
01819     * extra resources, I make sure that a future request will be within
01820     * limits. The problem here is that it is reasonable to think that
01821     * even if we're not within the limits at this point, we may be by
01822     * the time the requestor will have made his request. This may be
01823     * deleted at some point.
01824     */
01825    if (!ast_cc_request_is_within_limits()) {
01826       return 0;
01827    }
01828 
01829    if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
01830       return -1;
01831    }
01832 
01833    if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten), S_OR(chan->macrocontext, chan->context), 0))) {
01834       ast_free(interfaces);
01835       return -1;
01836    }
01837 
01838    if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
01839       cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
01840       ast_free(interfaces);
01841       return -1;
01842    }
01843 
01844    if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
01845                "Allocate monitor tree"))) {
01846       ast_datastore_free(dial_cc_datastore);
01847       cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
01848       ast_free(interfaces);
01849       return -1;
01850    }
01851 
01852    /* Finally, all that allocation is done... */
01853    AST_LIST_HEAD_INIT(interfaces->interface_tree);
01854    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
01855    cc_ref(monitor, "List's reference to extension monitor");
01856    dial_cc_datastore->data = interfaces;
01857    dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01858    interfaces->dial_parent_id = monitor->id;
01859    interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
01860    interfaces->is_original_caller = 1;
01861    ast_channel_lock(chan);
01862    ast_channel_datastore_add(chan, dial_cc_datastore);
01863    ast_channel_unlock(chan);
01864    cc_unref(monitor, "Unreffing allocation's reference");
01865    return 0;
01866 }

static void cc_monitor_destroy ( void *  data  )  [static]

Definition at line 1512 of file ccss.c.

References AST_CC_EXTENSION_MONITOR, ast_free, ast_log_dynamic_level, cc_extension_monitor_destructor(), cc_unref(), and monitor.

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

01513 {
01514    struct ast_cc_monitor *monitor = data;
01515    /* During the monitor creation process, it is possible for this
01516     * function to be called prior to when callbacks are assigned
01517     * to the monitor. Also, extension monitors do not have callbacks
01518     * assigned to them, so we wouldn't want to segfault when we try
01519     * to destroy one of them.
01520     */
01521    ast_log_dynamic_level(cc_logger_level, "Core %d: Calling destructor for monitor %s\n",
01522          monitor->core_id, monitor->interface->device_name);
01523    if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
01524       cc_extension_monitor_destructor(monitor->private_data);
01525    }
01526    if (monitor->callbacks) {
01527       monitor->callbacks->destructor(monitor->private_data);
01528    }
01529    cc_unref(monitor->interface, "Unreffing tree's reference to interface");
01530    ast_free(monitor->dialstring);
01531 }

static int cc_monitor_failed ( void *  data  )  [static]

Definition at line 3511 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cc_failed(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log_dynamic_level, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, ast_cc_monitor_callbacks::cancel_available_timer, cc_extension_monitor_change_is_valid(), cc_unref(), cc_core_instance::core_id, ast_cc_monitor::core_id, ast_cc_monitor_failure_data::core_id, ast_cc_monitor_failure_data::debug, ast_cc_interface::device_name, ast_cc_monitor_failure_data::device_name, EVENT_FLAG_CC, find_cc_core_instance(), has_device_monitors(), ast_cc_monitor::interface, manager_event, ast_cc_interface::monitor_class, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor::parent_id.

Referenced by ast_cc_monitor_failed().

03512 {
03513    struct ast_cc_monitor_failure_data *failure_data = data;
03514    struct cc_core_instance *core_instance;
03515    struct ast_cc_monitor *monitor_iter;
03516 
03517    core_instance = find_cc_core_instance(failure_data->core_id);
03518    if (!core_instance) {
03519       /* Core instance no longer exists or invalid core_id. */
03520       ast_log_dynamic_level(cc_logger_level,
03521          "Core %d: Could not find core instance for device %s '%s'\n",
03522          failure_data->core_id, failure_data->device_name, failure_data->debug);
03523       ast_free((char *) failure_data->device_name);
03524       ast_free((char *) failure_data->debug);
03525       ast_free(failure_data);
03526       return -1;
03527    }
03528 
03529    AST_LIST_LOCK(core_instance->monitors);
03530    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
03531       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
03532          if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
03533             AST_LIST_REMOVE_CURRENT(next);
03534             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
03535                   monitor_iter->interface->device_name, 1);
03536             monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
03537             manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
03538                "CoreID: %d\r\n"
03539                "Callee: %s\r\n",
03540                monitor_iter->core_id, monitor_iter->interface->device_name);
03541             cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
03542          }
03543       }
03544    }
03545    AST_LIST_TRAVERSE_SAFE_END;
03546 
03547    if (!has_device_monitors(core_instance)) {
03548       ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
03549    }
03550    AST_LIST_UNLOCK(core_instance->monitors);
03551    cc_unref(core_instance, "Finished with core_instance in cc_monitor_failed\n");
03552 
03553    ast_free((char *) failure_data->device_name);
03554    ast_free((char *) failure_data->debug);
03555    ast_free(failure_data);
03556    return 0;
03557 }

static int cc_offer ( const int  core_id,
const char *const   debug,
  ... 
) [static]

Definition at line 3355 of file ccss.c.

References CC_CALLER_OFFERED, and cc_request_state_change().

Referenced by ast_cc_offer().

03356 {
03357    va_list ap;
03358    int res;
03359 
03360    va_start(ap, debug);
03361    res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
03362    va_end(ap);
03363    return res;
03364 }

static int cc_party_b_free ( void *  data  )  [static]

Definition at line 3657 of file ccss.c.

References cc_core_instance::agent, ast_cc_agent::callbacks, cc_unref(), and ast_cc_agent_callbacks::party_b_free.

Referenced by ast_cc_monitor_party_b_free().

03658 {
03659    struct cc_core_instance *core_instance = data;
03660    int res = 0;
03661 
03662    if (core_instance->agent->callbacks->party_b_free) {
03663       res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
03664    }
03665    cc_unref(core_instance, "Party B free finished. Unref core_instance");
03666    return res;
03667 }

static void cc_recall_ds_destroy ( void *  data  )  [static]

Definition at line 3023 of file ccss.c.

References ast_free, cc_unref(), and cc_recall_ds_data::interface_tree.

03024 {
03025    struct cc_recall_ds_data *recall_data = data;
03026    recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
03027    ast_free(recall_data);
03028 }

static void* cc_recall_ds_duplicate ( void *  data  )  [static]

Definition at line 3009 of file ccss.c.

References ast_calloc, cc_ref(), cc_recall_ds_data::core_id, and cc_recall_ds_data::interface_tree.

03010 {
03011    struct cc_recall_ds_data *old_data = data;
03012    struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));
03013 
03014    if (!new_data) {
03015       return NULL;
03016    }
03017    new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
03018    new_data->core_id = old_data->core_id;
03019    new_data->nested = 1;
03020    return new_data;
03021 }

static int cc_recalling ( struct cc_core_instance core_instance,
struct cc_state_change_args args,
enum cc_state  previous_state 
) [static]

Definition at line 2889 of file ccss.c.

References cc_core_instance::agent, cancel_available_timer(), cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, and manager_event.

02890 {
02891    /* Both caller and callee are available, call agent's recall callback
02892     */
02893    cancel_available_timer(core_instance);
02894    manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
02895       "CoreID: %d\r\n"
02896       "Caller: %s\r\n",
02897       core_instance->core_id, core_instance->agent->device_name);
02898    return 0;
02899 }

static void* cc_ref ( void *  obj,
const char *  debug 
) [inline, static]

Definition at line 101 of file ccss.c.

References ao2_t_ref.

Referenced by ast_cc_agent_callback(), ast_cc_call_init(), ast_cc_get_monitor_by_recall_core_id(), ast_handle_cc_control_frame(), ast_setup_cc_recall_datastore(), cc_core_init_instance(), cc_generic_agent_start_offer_timer(), cc_generic_monitor_request_cc(), cc_interfaces_datastore_init(), cc_recall_ds_duplicate(), dialed_cc_interfaces_duplicate(), and generic_agent_devstate_cb().

00102 {
00103    ao2_t_ref(obj, +1, debug);
00104    return obj;
00105 }

static int cc_request_state_change ( enum cc_state  state,
const int  core_id,
const char *  debug,
va_list  ap 
) [static]

Definition at line 2970 of file ccss.c.

References args, ast_calloc, ast_free, ast_taskprocessor_push(), cc_core_taskprocessor, cc_do_state_change(), and dummy().

Referenced by ast_cc_agent_accept_request(), ast_cc_agent_caller_available(), ast_cc_agent_caller_busy(), ast_cc_agent_recalling(), ast_cc_completed(), ast_cc_failed(), ast_cc_monitor_callee_available(), ast_cc_monitor_request_acked(), and cc_offer().

02971 {
02972    int res;
02973    int debuglen;
02974    char dummy[1];
02975    va_list aq;
02976    struct cc_state_change_args *args;
02977    /* This initial call to vsnprintf is simply to find what the
02978     * size of the string needs to be
02979     */
02980    va_copy(aq, ap);
02981    /* We add 1 to the result since vsnprintf's return does not
02982     * include the terminating null byte
02983     */
02984    debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
02985    va_end(aq);
02986 
02987    if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
02988       return -1;
02989    }
02990 
02991    args->state = state;
02992    args->core_id = core_id;
02993    vsnprintf(args->debug, debuglen, debug, ap);
02994 
02995    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
02996    if (res) {
02997       ast_free(args);
02998    }
02999    return res;
03000 }

static const char* cc_service_to_string ( enum ast_cc_service_type  service  )  [static]

Definition at line 369 of file ccss.c.

References cc_service_to_string_map.

Referenced by ast_handle_cc_control_frame(), and cc_cli_print_monitor_stats().

00370 {
00371    return cc_service_to_string_map[service].service_string;
00372 }

static const char* cc_state_to_string ( enum cc_state  state  )  [static]

Definition at line 364 of file ccss.c.

References cc_state_to_string_map.

Referenced by cc_do_state_change(), and print_stats_cb().

00365 {
00366    return cc_state_to_string_map[state].state_string;
00367 }

static int cc_status_request ( void *  data  )  [static]

Definition at line 3594 of file ccss.c.

References cc_core_instance::agent, ast_cc_agent::callbacks, cc_unref(), and ast_cc_agent_callbacks::status_request.

Referenced by ast_cc_monitor_status_request().

03595 {
03596    struct cc_core_instance *core_instance= data;
03597    int res;
03598 
03599    res = core_instance->agent->callbacks->status_request(core_instance->agent);
03600    cc_unref(core_instance, "Status request finished. Unref core instance");
03601    return res;
03602 }

static int cc_status_response ( void *  data  )  [static]

Definition at line 3690 of file ccss.c.

References args, AST_CC_DEVICE_MONITOR, ast_device_state(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_cc_monitor::callbacks, cc_unref(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor_callbacks::status_response.

Referenced by ast_cc_agent_status_response().

03691 {
03692    struct cc_status_response_args *args = data;
03693    struct cc_core_instance *core_instance = args->core_instance;
03694    struct ast_cc_monitor *monitor_iter;
03695    enum ast_device_state devstate = args->devstate;
03696 
03697    ast_free(args);
03698 
03699    AST_LIST_LOCK(core_instance->monitors);
03700    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03701       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
03702             monitor_iter->callbacks->status_response) {
03703          monitor_iter->callbacks->status_response(monitor_iter, devstate);
03704       }
03705    }
03706    AST_LIST_UNLOCK(core_instance->monitors);
03707    cc_unref(core_instance, "Status response finished. Unref core instance");
03708    return 0;
03709 }

static int cc_stop_ringing ( void *  data  )  [static]

Definition at line 3620 of file ccss.c.

References cc_core_instance::agent, ast_cc_monitor_request_acked(), ast_cc_agent::callbacks, cc_unref(), cc_core_instance::core_id, ast_cc_agent::device_name, and ast_cc_agent_callbacks::stop_ringing.

Referenced by ast_cc_monitor_stop_ringing().

03621 {
03622    struct cc_core_instance *core_instance = data;
03623    int res = 0;
03624 
03625    if (core_instance->agent->callbacks->stop_ringing) {
03626       res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
03627    }
03628    /* If an agent is being asked to stop ringing, then he needs to be prepared if for
03629     * whatever reason he needs to be called back again. The proper state to be in to
03630     * detect such a circumstance is the CC_ACTIVE state.
03631     *
03632     * We get to this state using the slightly unintuitive method of calling
03633     * ast_cc_monitor_request_acked because it gets us to the proper state.
03634     */
03635    ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
03636          core_instance->agent->device_name);
03637    cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
03638    return res;
03639 }

static void cc_unique_append ( struct ast_str str,
const char *const   dialstring 
) [static]

Definition at line 3189 of file ccss.c.

References AST_CHANNEL_NAME, ast_str_append(), ast_str_buffer(), and str.

Referenced by build_cc_interfaces_chanvar().

03190 {
03191    char dialstring_search[AST_CHANNEL_NAME];
03192 
03193    snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
03194    if (strstr(ast_str_buffer(str), dialstring_search)) {
03195       return;
03196    }
03197    ast_str_append(&str, 0, "%s", dialstring_search);
03198 }

static void* cc_unref ( void *  obj,
const char *  debug 
) [inline, static]

Definition at line 107 of file ccss.c.

References ao2_t_ref.

Referenced by ast_cc_agent_callback(), ast_cc_agent_status_response(), ast_cc_available_timer_expire(), ast_cc_call_init(), ast_cc_get_monitor_by_recall_core_id(), ast_cc_monitor_party_b_free(), ast_cc_monitor_status_request(), ast_cc_monitor_stop_ringing(), ast_handle_cc_control_frame(), ast_setup_cc_recall_datastore(), cancel_available_timer(), cc_agent_init(), cc_core_init_instance(), cc_core_instance_destructor(), cc_device_monitor_init(), cc_do_state_change(), cc_extension_monitor_init(), cc_generic_agent_stop_offer_timer(), cc_generic_monitor_cancel_available_timer(), cc_generic_monitor_destructor(), cc_generic_monitor_request_cc(), cc_generic_monitor_suspend(), cc_generic_monitor_unsuspend(), cc_interface_tree_destroy(), cc_interfaces_datastore_init(), cc_monitor_destroy(), cc_monitor_failed(), cc_party_b_free(), cc_recall_ds_destroy(), cc_status_request(), cc_status_response(), cc_stop_ringing(), cccancel_exec(), ccreq_exec(), complete_core_id(), create_new_generic_list(), dialed_cc_interfaces_destroy(), generic_agent_devstate_cb(), generic_agent_devstate_unsubscribe(), generic_monitor_devstate_tp_cb(), offer_timer_expire(), request_cc(), suspend(), and unsuspend().

00108 {
00109    ao2_t_ref(obj, -1, debug);
00110    return NULL;
00111 }

static int cccancel_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 3918 of file ccss.c.

References cc_core_instance::agent, ao2_t_callback_data, ast_cc_failed(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_log(), ast_cc_agent::callbacks, cc_core_instances, cc_unref(), cc_core_instance::core_id, LOG_WARNING, match_agent(), MATCH_REQUEST, and ast_cc_agent_callbacks::type.

Referenced by ast_cc_init().

03919 {
03920    struct cc_core_instance *core_instance;
03921    char device_name[AST_CHANNEL_NAME];
03922    unsigned long match_flags;
03923    int res;
03924 
03925    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03926 
03927    match_flags = MATCH_REQUEST;
03928    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
03929       ast_log(LOG_WARNING, "Cannot find CC transaction to cancel for caller %s\n", device_name);
03930       return -1;
03931    }
03932 
03933    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
03934       ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
03935       cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
03936       return -1;
03937    }
03938    res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
03939          core_instance->core_id, device_name);
03940    cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
03941    return res;
03942 }

static int ccreq_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 3875 of file ccss.c.

References cc_core_instance::agent, ao2_t_callback_data, ast_cc_agent_accept_request(), ast_cc_failed(), ast_cc_request_is_within_limits(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_log_dynamic_level, ast_cc_agent::callbacks, cc_core_instances, cc_unref(), cc_core_instance::core_id, match_agent(), MATCH_NO_REQUEST, pbx_builtin_setvar_helper(), and ast_cc_agent_callbacks::type.

Referenced by ast_cc_init().

03876 {
03877    struct cc_core_instance *core_instance;
03878    char device_name[AST_CHANNEL_NAME];
03879    unsigned long match_flags;
03880    int res;
03881 
03882    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03883 
03884    match_flags = MATCH_NO_REQUEST;
03885    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionRequest"))) {
03886       ast_log_dynamic_level(cc_logger_level, "Couldn't find a core instance for caller %s\n", device_name);
03887       return -1;
03888    }
03889 
03890    ast_log_dynamic_level(cc_logger_level, "Core %d: Found core_instance for caller %s\n",
03891          core_instance->core_id, device_name);
03892 
03893    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
03894       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest is only for generic agent types.\n",
03895             core_instance->core_id);
03896       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
03897       cc_unref(core_instance, "Unref core_instance since CallCompletionRequest was called with native agent");
03898       return 0;
03899    }
03900 
03901    if (!ast_cc_request_is_within_limits()) {
03902       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest failed. Too many requests in the system\n",
03903             core_instance->core_id);
03904       ast_cc_failed(core_instance->core_id, "Too many CC requests\n");
03905       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
03906       cc_unref(core_instance, "Unref core_instance since too many CC requests");
03907       return 0;
03908    }
03909 
03910    res = ast_cc_agent_accept_request(core_instance->core_id, "CallCompletionRequest called by caller %s for core_id %d", device_name, core_instance->core_id);
03911    pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", res ? "FAIL" : "SUCCESS");
03912    cc_unref(core_instance, "Done with CallCompletionRequest");
03913    return res;
03914 }

static void check_callback_sanity ( const struct ast_cc_agent_callbacks callbacks  )  [static]

Definition at line 2203 of file ccss.c.

References ast_assert, cc_monitor_backend::callbacks, and ast_cc_monitor_callbacks::destructor.

Referenced by cc_agent_init().

02204 {
02205    ast_assert(callbacks->init != NULL);
02206    ast_assert(callbacks->start_offer_timer != NULL);
02207    ast_assert(callbacks->stop_offer_timer != NULL);
02208    ast_assert(callbacks->ack != NULL);
02209    ast_assert(callbacks->status_request != NULL);
02210    ast_assert(callbacks->start_monitoring != NULL);
02211    ast_assert(callbacks->callee_available != NULL);
02212    ast_assert(callbacks->destructor != NULL);
02213 }

static char* complete_core_id ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 4104 of file ccss.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, cc_core_instances, cc_unref(), and cc_core_instance::core_id.

Referenced by handle_cc_kill().

04105 {
04106    int which = 0;
04107    int wordlen = strlen(word);
04108    char *ret = NULL;
04109    struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
04110    struct cc_core_instance *core_instance;
04111 
04112    for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
04113          cc_unref(core_instance, "CLI tab completion iteration")) {
04114       char core_id_str[20];
04115       snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
04116       if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
04117          ret = ast_strdup(core_id_str);
04118          cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
04119          break;
04120       }
04121    }
04122    ao2_iterator_destroy(&core_iter);
04123 
04124    return ret;
04125 }

static long count_agents ( const char *const   caller,
const int  core_id_exception 
) [static]

Definition at line 2188 of file ccss.c.

References ao2_t_callback_data, ast_log_dynamic_level, cc_core_instances, count_agents_cb_data::core_id_exception, count_agents_cb_data::count, count_agents_cb(), and OBJ_NODATA.

Referenced by agents_show(), agents_show_online(), and cc_core_init_instance().

02189 {
02190    struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
02191 
02192    ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
02193    ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
02194    return data.count;
02195 }

static int count_agents_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

Definition at line 487 of file ccss.c.

References cc_core_instance::agent, ast_log_dynamic_level, CC_CALLER_REQUESTED, cc_core_instance::core_id, count_agents_cb_data::core_id_exception, count_agents_cb_data::count, cc_core_instance::current_state, ast_cc_agent::device_name, and name.

Referenced by count_agents().

00488 {
00489    struct cc_core_instance *core_instance = obj;
00490    const char *name = arg;
00491    struct count_agents_cb_data *cb_data = data;
00492 
00493    if (cb_data->core_id_exception == core_instance->core_id) {
00494       ast_log_dynamic_level(cc_logger_level, "Found agent with core_id %d but not counting it toward total\n", core_instance->core_id);
00495       return 0;
00496    }
00497 
00498    if (core_instance->current_state >= CC_CALLER_REQUESTED && !strcmp(core_instance->agent->device_name, name)) {
00499       cb_data->count++;
00500    }
00501    return 0;
00502 }

static int count_monitors_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 3950 of file ccss.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, count_monitors_cb_data::count, ast_cc_interface::device_name, count_monitors_cb_data::device_name, ast_cc_monitor::interface, ast_cc_interface::monitor_type, count_monitors_cb_data::monitor_type, cc_core_instance::monitors, and cc_monitor_backend::next.

Referenced by ast_cc_monitor_count().

03951 {
03952    struct cc_core_instance *core_instance = obj;
03953    struct count_monitors_cb_data *cb_data = arg;
03954    const char *device_name = cb_data->device_name;
03955    const char *monitor_type = cb_data->monitor_type;
03956    struct ast_cc_monitor *monitor_iter;
03957 
03958    AST_LIST_LOCK(core_instance->monitors);
03959    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03960       if (!strcmp(monitor_iter->interface->device_name, device_name) &&
03961             !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
03962          cb_data->count++;
03963          break;
03964       }
03965    }
03966    AST_LIST_UNLOCK(core_instance->monitors);
03967    return 0;
03968 }

static struct generic_monitor_instance_list* create_new_generic_list ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1081 of file ccss.c.

References ao2_t_alloc, ao2_t_link, ast_device_state(), AST_EVENT_DEVICE_STATE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, ast_event_subscribe(), ast_strdup, cc_unref(), generic_monitor_devstate_cb(), generic_monitor_instance_list_destructor(), generic_monitors, and monitor.

Referenced by cc_generic_monitor_request_cc().

01082 {
01083    struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
01084          generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
01085 
01086    if (!generic_list) {
01087       return NULL;
01088    }
01089 
01090    if (!(generic_list->device_name = ast_strdup(monitor->interface->device_name))) {
01091       cc_unref(generic_list, "Failed to strdup the monitor's device name");
01092       return NULL;
01093    }
01094 
01095    if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, generic_monitor_devstate_cb,
01096             "Requesting CC", NULL, AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
01097             monitor->interface->device_name, AST_EVENT_IE_END))) {
01098       cc_unref(generic_list, "Failed to subscribe to device state");
01099       return NULL;
01100    }
01101    generic_list->current_state = ast_device_state(monitor->interface->device_name);
01102    ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
01103    return generic_list;
01104 }

static void dialed_cc_interfaces_destroy ( void *  data  )  [static]

Definition at line 1619 of file ccss.c.

References ast_free, cc_unref(), and dialed_cc_interfaces::interface_tree.

01620 {
01621    struct dialed_cc_interfaces *cc_interfaces = data;
01622    cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
01623    ast_free(cc_interfaces);
01624 }

static void* dialed_cc_interfaces_duplicate ( void *  data  )  [static]

Definition at line 1639 of file ccss.c.

References ast_calloc, cc_ref(), dialed_cc_interfaces::core_id, dialed_cc_interfaces::dial_parent_id, dialed_cc_interfaces::ignore, and dialed_cc_interfaces::interface_tree.

01640 {
01641    struct dialed_cc_interfaces *old_cc_interfaces = data;
01642    struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
01643    if (!new_cc_interfaces) {
01644       return NULL;
01645    }
01646    new_cc_interfaces->ignore = old_cc_interfaces->ignore;
01647    new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
01648    new_cc_interfaces->is_original_caller = 0;
01649    cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
01650    new_cc_interfaces->core_id = old_cc_interfaces->core_id;
01651    new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
01652    return new_cc_interfaces;
01653 }

static struct extension_monitor_pvt* extension_monitor_pvt_init ( void   )  [static]

Definition at line 1670 of file ccss.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by cc_extension_monitor_init().

01671 {
01672    struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
01673    if (!ext_pvt) {
01674       return NULL;
01675    }
01676    AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
01677    return ext_pvt;
01678 }

static struct ast_cc_agent_callbacks* find_agent_callbacks ( struct ast_channel chan  )  [static]

Definition at line 947 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, ast_channel_get_cc_agent_type(), ast_channel_get_cc_config_params(), ast_copy_string(), ast_get_cc_agent_policy(), ast_log_dynamic_level, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, cc_agent_backend::callbacks, cc_monitor_backend::callbacks, cc_monitor_backend::next, ast_cc_agent_callbacks::type, and type.

Referenced by cc_agent_init().

00948 {
00949    struct cc_agent_backend *backend;
00950    const struct ast_cc_agent_callbacks *callbacks = NULL;
00951    struct ast_cc_config_params *cc_params;
00952    char type[32];
00953 
00954    cc_params = ast_channel_get_cc_config_params(chan);
00955    if (!cc_params) {
00956       return NULL;
00957    }
00958    switch (ast_get_cc_agent_policy(cc_params)) {
00959    case AST_CC_AGENT_GENERIC:
00960       ast_copy_string(type, "generic", sizeof(type));
00961       break;
00962    case AST_CC_AGENT_NATIVE:
00963       ast_channel_get_cc_agent_type(chan, type, sizeof(type));
00964       break;
00965    default:
00966       ast_log_dynamic_level(cc_logger_level, "Not returning agent callbacks since this channel is configured not to have a CC agent\n");
00967       return NULL;
00968    }
00969 
00970    AST_RWLIST_RDLOCK(&cc_agent_backends);
00971    AST_RWLIST_TRAVERSE(&cc_agent_backends, backend, next) {
00972       if (!strcmp(backend->callbacks->type, type)) {
00973          ast_log_dynamic_level(cc_logger_level, "Returning agent backend %s\n", backend->callbacks->type);
00974          callbacks = backend->callbacks;
00975          break;
00976       }
00977    }
00978    AST_RWLIST_UNLOCK(&cc_agent_backends);
00979    return callbacks;
00980 }

static struct cc_core_instance* find_cc_core_instance ( const int  core_id  )  [static]

Definition at line 388 of file ccss.c.

References ao2_t_find, cc_core_instances, cc_core_instance::core_id, and OBJ_POINTER.

Referenced by ast_cc_agent_status_response(), ast_cc_get_monitor_by_recall_core_id(), ast_cc_monitor_party_b_free(), ast_cc_monitor_status_request(), ast_cc_monitor_stop_ringing(), ast_handle_cc_control_frame(), ast_setup_cc_recall_datastore(), cc_do_state_change(), and cc_monitor_failed().

00389 {
00390    struct cc_core_instance finder = {.core_id = core_id,};
00391 
00392    return ao2_t_find(cc_core_instances, &finder, OBJ_POINTER, "Finding a core_instance");
00393 }

static struct generic_monitor_instance_list* find_generic_monitor_instance_list ( const char *const   device_name  )  [static]

Definition at line 1061 of file ccss.c.

References ao2_t_find, generic_monitor_instance_list::device_name, generic_monitors, and OBJ_POINTER.

Referenced by cc_generic_monitor_destructor(), cc_generic_monitor_request_cc(), cc_generic_monitor_suspend(), cc_generic_monitor_unsuspend(), and generic_monitor_devstate_tp_cb().

01062 {
01063    struct generic_monitor_instance_list finder = {.device_name = device_name};
01064 
01065    return ao2_t_find(generic_monitors, &finder, OBJ_POINTER, "Finding generic monitor instance list");
01066 }

static struct ast_cc_monitor_callbacks* find_monitor_callbacks ( const char *const   type  )  [static]

Definition at line 878 of file ccss.c.

References ast_log_dynamic_level, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, cc_monitor_backend::callbacks, cc_monitor_backend::next, and ast_cc_monitor_callbacks::type.

Referenced by call_destructor_with_no_monitor(), and cc_device_monitor_init().

00879 {
00880    struct cc_monitor_backend *backend;
00881    const struct ast_cc_monitor_callbacks *callbacks = NULL;
00882 
00883    AST_RWLIST_RDLOCK(&cc_monitor_backends);
00884    AST_RWLIST_TRAVERSE(&cc_monitor_backends, backend, next) {
00885       if (!strcmp(backend->callbacks->type, type)) {
00886          ast_log_dynamic_level(cc_logger_level, "Returning monitor backend %s\n", backend->callbacks->type);
00887          callbacks = backend->callbacks;
00888          break;
00889       }
00890    }
00891    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00892    return callbacks;
00893 }

static void generic_agent_devstate_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 2444 of file ccss.c.

References ast_cc_agent_caller_available(), ast_taskprocessor_push(), cc_core_taskprocessor, cc_ref(), cc_unref(), ast_cc_agent::core_id, ast_cc_agent::device_name, and generic_agent_devstate_unsubscribe().

Referenced by cc_generic_agent_start_monitoring().

02445 {
02446    struct ast_cc_agent *agent = userdata;
02447 
02448    /* We can't unsubscribe from device state events here because it causes a deadlock */
02449    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
02450          cc_ref(agent, "ref agent for device state unsubscription"))) {
02451       cc_unref(agent, "Unref agent unsubscribing from devstate failed");
02452    }
02453    ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
02454 }

static int generic_agent_devstate_unsubscribe ( void *  data  )  [static]

Definition at line 2432 of file ccss.c.

References ast_event_unsubscribe(), cc_unref(), ast_cc_agent::private_data, and cc_generic_agent_pvt::sub.

Referenced by generic_agent_devstate_cb().

02433 {
02434    struct ast_cc_agent *agent = data;
02435    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02436 
02437    if (generic_pvt->sub != NULL) {
02438       generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
02439    }
02440    cc_unref(agent, "Done unsubscribing from devstate");
02441    return 0;
02442 }

static int generic_monitor_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1053 of file ccss.c.

References CMP_MATCH, CMP_STOP, and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01054 {
01055    const struct generic_monitor_instance_list *generic_list1 = obj;
01056    const struct generic_monitor_instance_list *generic_list2 = arg;
01057 
01058    return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
01059 }

static void generic_monitor_devstate_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 1159 of file ccss.c.

References ast_calloc, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_strdup, ast_taskprocessor_push(), cc_core_taskprocessor, and generic_monitor_devstate_tp_cb().

Referenced by create_new_generic_list().

01160 {
01161    /* Wow, it's cool that we've picked up on a state change, but we really want
01162     * the actual work to be done in the core's taskprocessor execution thread
01163     * so that all monitor operations can be serialized. Locks?! We don't need
01164     * no steenkin' locks!
01165     */
01166    struct generic_tp_cb_data *gtcd = ast_calloc(1, sizeof(*gtcd));
01167 
01168    if (!gtcd) {
01169       return;
01170    }
01171 
01172    if (!(gtcd->device_name = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE)))) {
01173       ast_free(gtcd);
01174       return;
01175    }
01176    gtcd->new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01177 
01178    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, gtcd)) {
01179       ast_free((char *)gtcd->device_name);
01180       ast_free(gtcd);
01181    }
01182 }

static int generic_monitor_devstate_tp_cb ( void *  data  )  [static]

Definition at line 1111 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_free, AST_LIST_TRAVERSE, cc_unref(), generic_monitor_instance::core_id, generic_monitor_instance_list::current_state, generic_tp_cb_data::device_name, find_generic_monitor_instance_list(), generic_monitor_instance_list::fit_for_recall, generic_monitor_instance::is_suspended, generic_monitor_instance_list::list, generic_monitor_instance::monitoring, generic_tp_cb_data::new_state, and cc_monitor_backend::next.

Referenced by generic_monitor_devstate_cb().

01112 {
01113    struct generic_tp_cb_data *gtcd = data;
01114    enum ast_device_state new_state = gtcd->new_state;
01115    enum ast_device_state previous_state = gtcd->new_state;
01116    const char *monitor_name = gtcd->device_name;
01117    struct generic_monitor_instance_list *generic_list;
01118    struct generic_monitor_instance *generic_instance;
01119 
01120    if (!(generic_list = find_generic_monitor_instance_list(monitor_name))) {
01121       /* The most likely cause for this is that we destroyed the monitor in the
01122        * time between subscribing to its device state and the time this executes.
01123        * Not really a big deal.
01124        */
01125       ast_free((char *) gtcd->device_name);
01126       ast_free(gtcd);
01127       return 0;
01128    }
01129 
01130    if (generic_list->current_state == new_state) {
01131       /* The device state hasn't actually changed, so we don't really care */
01132       cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01133       ast_free((char *) gtcd->device_name);
01134       ast_free(gtcd);
01135       return 0;
01136    }
01137 
01138    previous_state = generic_list->current_state;
01139    generic_list->current_state = new_state;
01140 
01141    if ((new_state == AST_DEVICE_NOT_INUSE || new_state == AST_DEVICE_UNKNOWN) &&
01142          (previous_state == AST_DEVICE_INUSE || previous_state == AST_DEVICE_UNAVAILABLE ||
01143           previous_state == AST_DEVICE_BUSY)) {
01144       AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01145          if (!generic_instance->is_suspended && generic_instance->monitoring) {
01146             generic_instance->monitoring = 0;
01147             generic_list->fit_for_recall = 1;
01148             ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01149             break;
01150          }
01151       }
01152    }
01153    cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01154    ast_free((char *) gtcd->device_name);
01155    ast_free(gtcd);
01156    return 0;
01157 }

static int generic_monitor_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 1047 of file ccss.c.

References ast_str_hash(), and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01048 {
01049    const struct generic_monitor_instance_list *generic_list = obj;
01050    return ast_str_hash(generic_list->device_name);
01051 }

static void generic_monitor_instance_list_destructor ( void *  obj  )  [static]

Definition at line 1068 of file ccss.c.

References ast_event_unsubscribe(), ast_free, AST_LIST_REMOVE_HEAD, generic_monitor_instance_list::device_name, generic_monitor_instance_list::list, cc_monitor_backend::next, and generic_monitor_instance_list::sub.

Referenced by create_new_generic_list().

01069 {
01070    struct generic_monitor_instance_list *generic_list = obj;
01071    struct generic_monitor_instance *generic_instance;
01072 
01073    generic_list->sub = ast_event_unsubscribe(generic_list->sub);
01074    while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
01075       ast_free(generic_instance);
01076    }
01077    ast_free((char *)generic_list->device_name);
01078 }

static void* generic_recall ( void *  data  )  [static]

Definition at line 2474 of file ccss.c.

References ast_app_run_macro(), ast_cc_agent_recalling(), ast_cc_agent_set_interfaces_chanvar(), ast_cc_failed(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_get_cc_agent_dialstring(), ast_get_cc_callback_macro(), ast_get_cc_recall_timer(), ast_hangup(), ast_log_dynamic_level, ast_pbx_start(), ast_request_and_dial(), ast_setup_cc_recall_datastore(), ast_strdupa, ast_strlen_zero(), ast_cc_agent::cc_params, cc_generic_agent_pvt::cid_name, cc_generic_agent_pvt::cid_num, cc_generic_agent_pvt::context, ast_channel::context, ast_cc_agent::core_id, ast_cc_agent::device_name, cc_generic_agent_pvt::exten, ast_channel::exten, ast_channel::priority, ast_cc_agent::private_data, and S_OR.

Referenced by cc_generic_agent_recall().

02475 {
02476    struct ast_cc_agent *agent = data;
02477    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02478    const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
02479    const char *tech;
02480    char *target;
02481    int reason;
02482    struct ast_channel *chan;
02483    const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
02484    unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
02485 
02486    tech = interface;
02487    if ((target = strchr(interface, '/'))) {
02488       *target++ = '\0';
02489    }
02490    if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
02491       /* Hmm, no channel. Sucks for you, bud.
02492        */
02493       ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
02494             agent->core_id, agent->device_name, reason);
02495       ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
02496       return NULL;
02497    }
02498    if (!ast_strlen_zero(callback_macro)) {
02499       ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
02500             agent->core_id, agent->device_name);
02501       if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
02502          ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
02503          ast_hangup(chan);
02504          return NULL;
02505       }
02506    }
02507    /* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
02508     * This will be a common task for all recall functions. If it were possible, I'd have
02509     * the core do it automatically, but alas I cannot. Instead, I will provide a public
02510     * function to do so.
02511     */
02512    ast_setup_cc_recall_datastore(chan, agent->core_id);
02513    ast_cc_agent_set_interfaces_chanvar(chan);
02514 
02515    ast_copy_string(chan->exten, generic_pvt->exten, sizeof(chan->exten));
02516    ast_copy_string(chan->context, generic_pvt->context, sizeof(chan->context));
02517    chan->priority = 1;
02518    ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling", agent->device_name);
02519    ast_pbx_start(chan);
02520    return NULL;
02521 }

static char* handle_cc_kill ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4127 of file ccss.c.

References ao2_t_callback, ast_cli_args::argc, ast_cli_args::argv, ast_cli_complete(), cc_core_instances, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_core_id(), cc_core_instance::core_id, errno, kill_cores(), ast_cli_args::line, ast_cli_args::n, OBJ_NODATA, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

04128 {
04129    static const char * const option[] = { "core", "all", NULL };
04130 
04131    switch (cmd) {
04132    case CLI_INIT:
04133       e->command = "cc cancel";
04134       e->usage =
04135          "Usage: cc cancel can be used in two ways.\n"
04136          "       1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
04137          "          core ID equal to the specified core ID.\n"
04138          "       2. 'cc cancel all' will cancel all active CC transactions.\n";
04139       return NULL;
04140    case CLI_GENERATE:
04141       if (a->pos == 2) {
04142          return ast_cli_complete(a->word, option, a->n);
04143       }
04144       if (a->pos == 3) {
04145          return complete_core_id(a->line, a->word, a->pos, a->n);
04146       }
04147       return NULL;
04148    }
04149 
04150    if (a->argc == 4) {
04151       int core_id;
04152       char *endptr;
04153       if (strcasecmp(a->argv[2], "core")) {
04154          return CLI_SHOWUSAGE;
04155       }
04156       core_id = strtol(a->argv[3], &endptr, 10);
04157       if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
04158          return CLI_SHOWUSAGE;
04159       }
04160       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, &core_id, "CLI Killing Core Id");
04161    } else if (a->argc == 3) {
04162       if (strcasecmp(a->argv[2], "all")) {
04163          return CLI_SHOWUSAGE;
04164       }
04165       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, NULL, "CLI Killing all CC cores");
04166    } else {
04167       return CLI_SHOWUSAGE;
04168    }
04169 
04170    return CLI_SUCCESS;
04171 }

static char* handle_cc_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4060 of file ccss.c.

References ast_cli_args::argc, ast_free, ast_malloc, ast_taskprocessor_push(), cc_cli_output_status(), cc_core_taskprocessor, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

04061 {
04062    int *cli_fd;
04063 
04064    switch (cmd) {
04065    case CLI_INIT:
04066       e->command = "cc report status";
04067       e->usage =
04068          "Usage: cc report status\n"
04069          "       Report the current status of any ongoing CC transactions\n";
04070       return NULL;
04071    case CLI_GENERATE:
04072       return NULL;
04073    }
04074 
04075    if (a->argc != 3) {
04076       return CLI_SHOWUSAGE;
04077    }
04078 
04079    cli_fd = ast_malloc(sizeof(*cli_fd));
04080    if (!cli_fd) {
04081       return CLI_FAILURE;
04082    }
04083 
04084    *cli_fd = a->fd;
04085 
04086    if (ast_taskprocessor_push(cc_core_taskprocessor, cc_cli_output_status, cli_fd)) {
04087       ast_free(cli_fd);
04088       return CLI_FAILURE;
04089    }
04090    return CLI_SUCCESS;
04091 }

static int has_device_monitors ( struct cc_core_instance core_instance  )  [static]

check if the core instance has any device monitors

In any case where we end up removing a device monitor from the list of device monitors, it is important to see what the state of the list is afterwards. If we find that we only have extension monitors left, then no devices are actually being monitored. In such a case, we need to declare that CC has failed for this call. This function helps those cases to determine if they should declare failure.

Parameters:
core_instance The core instance we are checking for the existence of device monitors
Return values:
0 No device monitors exist on this core_instance
1 There is still at least 1 device monitor remaining

Definition at line 2724 of file ccss.c.

References AST_CC_DEVICE_MONITOR, AST_LIST_TRAVERSE, ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, and cc_monitor_backend::next.

Referenced by cancel_available_timer(), cc_monitor_failed(), request_cc(), suspend(), and unsuspend().

02725 {
02726    struct ast_cc_monitor *iter;
02727    int res = 0;
02728 
02729    AST_LIST_TRAVERSE(core_instance->monitors, iter, next) {
02730       if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02731          res = 1;
02732          break;
02733       }
02734    }
02735 
02736    return res;
02737 }

static void initialize_cc_max_requests ( void   )  [static]

Definition at line 3979 of file ccss.c.

References ast_config_destroy(), ast_config_load2(), ast_log(), ast_strlen_zero(), ast_variable_retrieve(), config_flags, CONFIG_STATUS_FILEINVALID, GLOBAL_CC_MAX_REQUESTS_DEFAULT, and LOG_WARNING.

Referenced by ast_cc_init().

03980 {
03981    struct ast_config *cc_config;
03982    const char *cc_max_requests_str;
03983    struct ast_flags config_flags = {0,};
03984    char *endptr;
03985 
03986    cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
03987    if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
03988       ast_log(LOG_WARNING, "Could not find valid ccss.conf file. Using cc_max_requests default\n");
03989       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
03990       return;
03991    }
03992 
03993    if (!(cc_max_requests_str = ast_variable_retrieve(cc_config, "general", "cc_max_requests"))) {
03994       ast_config_destroy(cc_config);
03995       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
03996       return;
03997    }
03998 
03999    global_cc_max_requests = strtol(cc_max_requests_str, &endptr, 10);
04000 
04001    if (!ast_strlen_zero(endptr)) {
04002       ast_log(LOG_WARNING, "Invalid input given for cc_max_requests. Using default\n");
04003       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04004    }
04005 
04006    ast_config_destroy(cc_config);
04007    return;
04008 }

static int is_state_change_valid ( enum cc_state  current_state,
const enum cc_state  new_state,
struct ast_cc_agent agent 
) [static]

Definition at line 2628 of file ccss.c.

References AST_CC_AGENT_SKIP_OFFER, ast_log_dynamic_level, ast_test_flag, CC_ACTIVE, CC_AVAILABLE, CC_CALLEE_READY, CC_CALLER_BUSY, CC_CALLER_OFFERED, CC_CALLER_REQUESTED, CC_COMPLETE, CC_FAILED, CC_RECALLING, and ast_cc_agent::core_id.

Referenced by cc_do_state_change().

02629 {
02630    int is_valid = 0;
02631    switch (new_state) {
02632    case CC_AVAILABLE:
02633       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
02634             agent->core_id, new_state);
02635       break;
02636    case CC_CALLER_OFFERED:
02637       if (current_state == CC_AVAILABLE) {
02638          is_valid = 1;
02639       }
02640       break;
02641    case CC_CALLER_REQUESTED:
02642       if (current_state == CC_CALLER_OFFERED ||
02643             (current_state == CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
02644          is_valid = 1;
02645       }
02646       break;
02647    case CC_ACTIVE:
02648       if (current_state == CC_CALLER_REQUESTED || current_state == CC_CALLER_BUSY) {
02649          is_valid = 1;
02650       }
02651       break;
02652    case CC_CALLEE_READY:
02653       if (current_state == CC_ACTIVE) {
02654          is_valid = 1;
02655       }
02656       break;
02657    case CC_CALLER_BUSY:
02658       if (current_state == CC_CALLEE_READY) {
02659          is_valid = 1;
02660       }
02661       break;
02662    case CC_RECALLING:
02663       if (current_state == CC_CALLEE_READY) {
02664          is_valid = 1;
02665       }
02666       break;
02667    case CC_COMPLETE:
02668       if (current_state == CC_RECALLING) {
02669          is_valid = 1;
02670       }
02671       break;
02672    case CC_FAILED:
02673       is_valid = 1;
02674       break;
02675    default:
02676       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
02677             agent->core_id, new_state);
02678       break;
02679    }
02680 
02681    return is_valid;
02682 }

static int kill_cores ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 4093 of file ccss.c.

References ast_cc_failed(), and cc_core_instance::core_id.

Referenced by handle_cc_kill().

04094 {
04095    int *core_id = arg;
04096    struct cc_core_instance *core_instance = obj;
04097 
04098    if (!core_id || (core_instance->core_id == *core_id)) {
04099       ast_cc_failed(core_instance->core_id, "CC transaction canceled administratively\n");
04100    }
04101    return 0;
04102 }

static void kill_duplicate_offers ( char *  caller  )  [static]

Definition at line 2197 of file ccss.c.

References ao2_t_callback_data, cc_core_instances, match_agent(), MATCH_NO_REQUEST, OBJ_NODATA, and OBJ_UNLINK.

Referenced by cc_core_init_instance().

02198 {
02199    unsigned long match_flags = MATCH_NO_REQUEST;
02200    ao2_t_callback_data(cc_core_instances, OBJ_UNLINK | OBJ_NODATA, match_agent, caller, &match_flags, "Killing duplicate offers");
02201 }

static int match_agent ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

Definition at line 449 of file ccss.c.

References cc_core_instance::agent, CC_CALLER_REQUESTED, CMP_MATCH, CMP_STOP, cc_core_instance::current_state, ast_cc_agent::device_name, MATCH_NO_REQUEST, MATCH_REQUEST, and name.

Referenced by cccancel_exec(), ccreq_exec(), and kill_duplicate_offers().

00450 {
00451    struct cc_core_instance *core_instance = obj;
00452    const char *name = arg;
00453    unsigned long match_flags = *(unsigned long *)data;
00454    int possible_match = 0;
00455 
00456    if ((match_flags & MATCH_NO_REQUEST) && core_instance->current_state < CC_CALLER_REQUESTED) {
00457       possible_match = 1;
00458    }
00459 
00460    if ((match_flags & MATCH_REQUEST) && core_instance->current_state >= CC_CALLER_REQUESTED) {
00461       possible_match = 1;
00462    }
00463 
00464    if (!possible_match) {
00465       return 0;
00466    }
00467 
00468    if (!strcmp(core_instance->agent->device_name, name)) {
00469       return CMP_MATCH | CMP_STOP;
00470    }
00471    return 0;
00472 }

static const char* monitor_policy_to_str ( enum ast_cc_monitor_policies  policy  )  [static]

Definition at line 596 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, AST_CC_MONITOR_GENERIC, AST_CC_MONITOR_NATIVE, and AST_CC_MONITOR_NEVER.

Referenced by ast_cc_get_param().

00597 {
00598    switch (policy) {
00599    case AST_CC_MONITOR_NEVER:
00600       return "never";
00601    case AST_CC_MONITOR_NATIVE:
00602       return "native";
00603    case AST_CC_MONITOR_GENERIC:
00604       return "generic";
00605    case AST_CC_MONITOR_ALWAYS:
00606       return "always";
00607    default:
00608       /* This should never happen... */
00609       return "";
00610    }
00611 }

static int offer_timer_expire ( const void *  data  )  [static]

Definition at line 2362 of file ccss.c.

References ast_cc_failed(), ast_log_dynamic_level, cc_unref(), ast_cc_agent::core_id, ast_cc_agent::device_name, cc_generic_agent_pvt::offer_timer_id, and ast_cc_agent::private_data.

Referenced by cc_generic_agent_start_offer_timer().

02363 {
02364    struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
02365    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02366    ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
02367          agent->core_id);
02368    agent_pvt->offer_timer_id = -1;
02369    ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
02370    cc_unref(agent, "Remove scheduler's reference to the agent");
02371    return 0;
02372 }

static int print_stats_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 4030 of file ccss.c.

References cc_core_instance::agent, ast_cli(), AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, cc_cli_print_monitor_stats(), cc_state_to_string(), cc_core_instance::core_id, cc_core_instance::current_state, ast_cc_agent::device_name, and cc_core_instance::monitors.

Referenced by cc_cli_output_status().

04031 {
04032    int *cli_fd = arg;
04033    struct cc_core_instance *core_instance = obj;
04034 
04035    ast_cli(*cli_fd, "%d\t\t%s\t\t%s\n", core_instance->core_id, core_instance->agent->device_name,
04036          cc_state_to_string(core_instance->current_state));
04037    AST_LIST_LOCK(core_instance->monitors);
04038    cc_cli_print_monitor_stats(AST_LIST_FIRST(core_instance->monitors), *cli_fd, 0);
04039    AST_LIST_UNLOCK(core_instance->monitors);
04040    return 0;
04041 }

static void request_cc ( struct cc_core_instance core_instance  )  [static]

Definition at line 2739 of file ccss.c.

References cc_core_instance::agent, AST_CC_DEVICE_MONITOR, ast_cc_failed(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, cc_extension_monitor_change_is_valid(), cc_unref(), cc_core_instance::core_id, ast_cc_agent::device_name, EVENT_FLAG_CC, has_device_monitors(), ast_cc_monitor::interface, manager_event, ast_cc_interface::monitor_class, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor_callbacks::request_cc.

Referenced by cc_caller_requested().

02740 {
02741    struct ast_cc_monitor *monitor_iter;
02742    AST_LIST_LOCK(core_instance->monitors);
02743    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02744       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02745          if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
02746             AST_LIST_REMOVE_CURRENT(next);
02747             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02748                   monitor_iter->interface->device_name, 1);
02749             cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
02750          } else {
02751             manager_event(EVENT_FLAG_CC, "CCRequested",
02752                "CoreID: %d\r\n"
02753                "Caller: %s\r\n"
02754                "Callee: %s\r\n",
02755                core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
02756          }
02757       }
02758    }
02759    AST_LIST_TRAVERSE_SAFE_END;
02760 
02761    if (!has_device_monitors(core_instance)) {
02762       ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
02763    }
02764    AST_LIST_UNLOCK(core_instance->monitors);
02765 }

static enum ast_cc_agent_policies str_to_agent_policy ( const char *const   value  )  [static]

Definition at line 551 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, AST_CC_AGENT_NEVER, ast_log(), and LOG_WARNING.

Referenced by ast_cc_set_param().

00552 {
00553    if (!strcasecmp(value, "never")) {
00554       return AST_CC_AGENT_NEVER;
00555    } else if (!strcasecmp(value, "native")) {
00556       return AST_CC_AGENT_NATIVE;
00557    } else if (!strcasecmp(value, "generic")) {
00558       return AST_CC_AGENT_GENERIC;
00559    } else {
00560       ast_log(LOG_WARNING, "%s is an invalid value for cc_agent_policy. Switching to 'never'\n", value);
00561       return AST_CC_AGENT_NEVER;
00562    }
00563 }

static enum ast_cc_monitor_policies str_to_monitor_policy ( const char *const   value  )  [static]

Definition at line 565 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, AST_CC_MONITOR_GENERIC, AST_CC_MONITOR_NATIVE, AST_CC_MONITOR_NEVER, ast_log(), and LOG_WARNING.

Referenced by ast_cc_set_param().

00566 {
00567    if (!strcasecmp(value, "never")) {
00568       return AST_CC_MONITOR_NEVER;
00569    } else if (!strcasecmp(value, "native")) {
00570       return AST_CC_MONITOR_NATIVE;
00571    } else if (!strcasecmp(value, "generic")) {
00572       return AST_CC_MONITOR_GENERIC;
00573    } else if (!strcasecmp(value, "always")) {
00574       return AST_CC_MONITOR_ALWAYS;
00575    } else {
00576       ast_log(LOG_WARNING, "%s is an invalid value for cc_monitor_policy. Switching to 'never'\n", value);
00577       return AST_CC_MONITOR_NEVER;
00578    }
00579 }

static void suspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2831 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cc_failed(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_cc_monitor::callbacks, cc_extension_monitor_change_is_valid(), cc_unref(), cc_core_instance::core_id, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor_callbacks::suspend.

Referenced by build_suspend(), cc_caller_busy(), and handle_controlstreamfile().

02832 {
02833    struct ast_cc_monitor *monitor_iter;
02834    AST_LIST_LOCK(core_instance->monitors);
02835    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02836       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02837          if (monitor_iter->callbacks->suspend(monitor_iter)) {
02838             AST_LIST_REMOVE_CURRENT(next);
02839             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02840                   monitor_iter->interface->device_name, 1);
02841             cc_unref(monitor_iter, "suspend failed. Unref list's reference to monitor");
02842          }
02843       }
02844    }
02845    AST_LIST_TRAVERSE_SAFE_END;
02846 
02847    if (!has_device_monitors(core_instance)) {
02848       ast_cc_failed(core_instance->core_id, "All device monitors failed to suspend CC");
02849    }
02850    AST_LIST_UNLOCK(core_instance->monitors);
02851 }

static void unsuspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2779 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cc_failed(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_cc_monitor::callbacks, cc_extension_monitor_change_is_valid(), cc_unref(), cc_core_instance::core_id, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, cc_monitor_backend::next, and ast_cc_monitor_callbacks::unsuspend.

Referenced by cc_active().

02780 {
02781    struct ast_cc_monitor *monitor_iter;
02782    AST_LIST_LOCK(core_instance->monitors);
02783    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02784       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02785          if (monitor_iter->callbacks->unsuspend(monitor_iter)) {
02786             AST_LIST_REMOVE_CURRENT(next);
02787             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02788                   monitor_iter->interface->device_name, 1);
02789             cc_unref(monitor_iter, "unsuspend failed. Unref list's reference to monitor");
02790          }
02791       }
02792    }
02793    AST_LIST_TRAVERSE_SAFE_END;
02794 
02795    if (!has_device_monitors(core_instance)) {
02796       ast_cc_failed(core_instance->core_id, "All device monitors failed to unsuspend CC");
02797    }
02798    AST_LIST_UNLOCK(core_instance->monitors);
02799 }


Variable Documentation

struct ast_cli_entry cc_cli[] [static]

Initial value:

 {
   { .handler =  handle_cc_status , .summary =  "Reports CC stats" ,__VA_ARGS__ },
   { .handler =  handle_cc_kill , .summary =  "Kill a CC transaction" ,__VA_ARGS__ },
}

Definition at line 4173 of file ccss.c.

Referenced by ast_cc_init().

struct ao2_container* cc_core_instances [static]

Definition at line 284 of file ccss.c.

Referenced by ast_cc_agent_callback(), ast_cc_init(), ast_cc_monitor_count(), cc_cli_output_status(), cc_complete(), cc_core_init_instance(), cc_failed(), cccancel_exec(), ccreq_exec(), complete_core_id(), count_agents(), find_cc_core_instance(), handle_cc_kill(), and kill_duplicate_offers().

const int CC_CORE_INSTANCES_BUCKETS = 17 [static]

Definition at line 283 of file ccss.c.

struct ast_taskprocessor* cc_core_taskprocessor [static]

Taskprocessor from which all CC agent and monitor callbacks are called.

Definition at line 83 of file ccss.c.

Referenced by ast_cc_agent_status_response(), ast_cc_init(), ast_cc_monitor_failed(), ast_cc_monitor_party_b_free(), ast_cc_monitor_status_request(), ast_cc_monitor_stop_ringing(), cc_request_state_change(), generic_agent_devstate_cb(), generic_monitor_devstate_cb(), and handle_cc_status().

struct ast_cc_config_params cc_default_params [static]

Definition at line 512 of file ccss.c.

Referenced by ast_cc_default_config_params().

int cc_logger_level [static]

Logger level registered by the CC core.

Definition at line 91 of file ccss.c.

const char* CC_LOGGER_LEVEL_NAME = "CC" [static]

Name printed on all CC log messages.

Definition at line 87 of file ccss.c.

int cc_request_count [static]

The current number of CC requests in the system

Definition at line 99 of file ccss.c.

struct ast_sched_thread* cc_sched_thread [static]

The sched_thread ID used for all generic CC timeouts

Definition at line 73 of file ccss.c.

Referenced by ast_cc_init(), cc_generic_agent_start_offer_timer(), cc_generic_agent_stop_offer_timer(), cc_generic_monitor_cancel_available_timer(), and cc_generic_monitor_request_cc().

struct { ... } cc_service_to_string_map[] [static]

Referenced by cc_service_to_string().

struct { ... } cc_state_to_string_map[] [static]

Referenced by cc_state_to_string().

const char* cccancel_app = "CallCompletionCancel" [static]

Definition at line 3916 of file ccss.c.

const char* ccreq_app = "CallCompletionRequest" [static]

Definition at line 3873 of file ccss.c.

int core_id_counter [static]

Counter used to create core IDs for CC calls. Each new core ID is created by atomically adding 1 to the core_id_counter

Definition at line 78 of file ccss.c.

int dialed_cc_interface_counter [static]

This counter is used for assigning unique ids to CC-enabled dialed interfaces.

Definition at line 1550 of file ccss.c.

struct ast_datastore_info dialed_cc_interfaces_info [static]

Initial value:

 {
   .type = "Dial CC Interfaces",
   .duplicate = dialed_cc_interfaces_duplicate,
   .destroy = dialed_cc_interfaces_destroy,
}

Definition at line 1664 of file ccss.c.

Referenced by ast_cc_call_init(), ast_cc_extension_monitor_add_dialstring(), ast_cc_get_current_core_id(), ast_cc_offer(), ast_handle_cc_control_frame(), ast_ignore_cc(), cc_build_payload(), and cc_interfaces_datastore_init().

struct ast_cc_agent_callbacks generic_agent_callbacks [static]

Definition at line 2277 of file ccss.c.

Referenced by ast_cc_init().

struct ast_cc_monitor_callbacks generic_monitor_cbs [static]

Definition at line 988 of file ccss.c.

Referenced by ast_cc_init().

struct ao2_container* generic_monitors

Definition at line 997 of file ccss.c.

Referenced by ast_cc_init(), cc_generic_monitor_destructor(), create_new_generic_list(), and find_generic_monitor_instance_list().

unsigned int global_cc_max_requests [static]

Parsed configuration value for cc_max_requests

Definition at line 95 of file ccss.c.

struct ast_datastore_info recall_ds_info [static]

Initial value:

 {
   .type = "cc_recall",
   .duplicate = cc_recall_ds_duplicate,
   .destroy = cc_recall_ds_destroy,
}

Definition at line 3030 of file ccss.c.

Referenced by ast_cc_agent_set_interfaces_chanvar(), ast_cc_completed(), ast_cc_is_recall(), ast_ignore_cc(), ast_set_cc_interfaces_chanvar(), and ast_setup_cc_recall_datastore().

enum ast_cc_service_type service

Definition at line 340 of file ccss.c.

const char* service_string

Definition at line 341 of file ccss.c.

enum cc_state state

Definition at line 350 of file ccss.c.

int(* const[]) state_change_funcs(struct cc_core_instance *, struct cc_state_change_args *, enum cc_state previous_state) [static]

Definition at line 2924 of file ccss.c.

Referenced by cc_do_state_change().

const char* state_string

Definition at line 351 of file ccss.c.


Generated on Wed Apr 6 11:29:54 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7