Tue Aug 20 16:34:48 2013

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

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.
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.
struct 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.
struct 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_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 void cc_generic_agent_respond (struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
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_is_device_available (enum ast_device_state state)
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 void cc_shutdown (void)
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 *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_list
create_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_pvt
extension_monitor_pvt_init (void)
static struct
ast_cc_agent_callbacks
find_agent_callbacks (struct ast_channel *chan)
static struct cc_core_instancefind_cc_core_instance (const int core_id)
static struct
generic_monitor_instance_list
find_generic_monitor_instance_list (const char *const device_name)
static struct
ast_cc_monitor_callbacks
find_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
struct 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 541 of file ccss.c.

#define CC_MAX_MONITORS_DEFAULT   5

Definition at line 542 of file ccss.c.

#define CC_OFFER_TIMER_DEFAULT   20

Definition at line 537 of file ccss.c.

#define CC_RECALL_TIMER_DEFAULT   20

Definition at line 540 of file ccss.c.

#define CCBS_AVAILABLE_TIMER_DEFAULT   4800

Definition at line 539 of file ccss.c.

#define CCNR_AVAILABLE_TIMER_DEFAULT   7200

Definition at line 538 of file ccss.c.

#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

Definition at line 543 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 171 of file ccss.c.

00171               {
00172    /*! Entered when it is determined that CCSS may be used for the call */
00173    CC_AVAILABLE,
00174    /*! Entered when a CCSS agent has offered CCSS to a caller */
00175    CC_CALLER_OFFERED,
00176    /*! Entered when a CCSS agent confirms that a caller has
00177     * requested CCSS */
00178    CC_CALLER_REQUESTED,
00179    /*! Entered when a CCSS monitor confirms acknowledgment of an
00180     * outbound CCSS request */
00181    CC_ACTIVE,
00182    /*! Entered when a CCSS monitor alerts the core that the called party
00183     * has become available */
00184    CC_CALLEE_READY,
00185    /*! Entered when a CCSS agent alerts the core that the calling party
00186     * may not be recalled because he is unavailable
00187     */
00188    CC_CALLER_BUSY,
00189    /*! Entered when a CCSS agent alerts the core that the calling party
00190     * is attempting to recall the called party
00191     */
00192    CC_RECALLING,
00193    /*! Entered when an application alerts the core that the calling party's
00194     * recall attempt has had a call progress response indicated
00195     */
00196    CC_COMPLETE,
00197    /*! Entered any time that something goes wrong during the process, thus
00198     * resulting in the failure of the attempted CCSS transaction. Note also
00199     * that cancellations of CC are treated as failures.
00200     */
00201    CC_FAILED,
00202 };

Enumerator:
MATCH_NO_REQUEST 
MATCH_REQUEST 

Definition at line 459 of file ccss.c.

00459                  {
00460    /* Only match agents that have not yet
00461     * made a CC request
00462     */
00463    MATCH_NO_REQUEST = (1 << 0),
00464    /* Only match agents that have made
00465     * a CC request
00466     */
00467    MATCH_REQUEST = (1 << 1),
00468 };


Function Documentation

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

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 563 of file ccss.c.

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

00564 {
00565 #if defined(__AST_DEBUG_MALLOC)
00566    struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
00567 #else
00568    struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
00569 #endif
00570 
00571    if (!params) {
00572       return NULL;
00573    }
00574 
00575    ast_cc_default_config_params(params);
00576    return params;
00577 }

static void agent_destroy ( void *  data  )  [static]

Definition at line 2281 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().

02282 {
02283    struct ast_cc_agent *agent = data;
02284 
02285    if (agent->callbacks) {
02286       agent->callbacks->destructor(agent);
02287    }
02288    ast_cc_config_params_destroy(agent->cc_params);
02289 }

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

Definition at line 614 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, and AST_CC_AGENT_NEVER.

Referenced by ast_cc_get_param().

00615 {
00616    switch (policy) {
00617    case AST_CC_AGENT_NEVER:
00618       return "never";
00619    case AST_CC_AGENT_NATIVE:
00620       return "native";
00621    case AST_CC_AGENT_GENERIC:
00622       return "generic";
00623    default:
00624       /* This should never happen... */
00625       return "";
00626    }
00627 }

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 3510 of file ccss.c.

References CC_CALLER_REQUESTED, and cc_request_state_change().

Referenced by ccreq_exec(), and handle_cc_subscribe().

03511 {
03512    va_list ap;
03513    int res;
03514 
03515    va_start(ap, debug);
03516    res = cc_request_state_change(CC_CALLER_REQUESTED, core_id, debug, ap);
03517    va_end(ap);
03518    return res;
03519 }

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

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 446 of file ccss.c.

References cc_core_instance::agent, ao2_t_callback, cc_agent_callback_helper(), 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().

00447 {
00448    struct cc_callback_helper helper = {.function = function, .args = args, .type = type};
00449    struct cc_core_instance *core_instance;
00450    if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
00451                "Calling provided agent callback function"))) {
00452       struct ast_cc_agent *agent = cc_ref(core_instance->agent, "An outside entity needs the agent");
00453       cc_unref(core_instance, "agent callback done with the core_instance");
00454       return agent;
00455    }
00456    return NULL;
00457 }

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 3554 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

Referenced by generic_agent_devstate_cb().

03555 {
03556    va_list ap;
03557    int res;
03558 
03559    va_start(ap, debug);
03560    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03561    va_end(ap);
03562    return res;
03563 }

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 3543 of file ccss.c.

References CC_CALLER_BUSY, and cc_request_state_change().

Referenced by cc_generic_agent_recall(), and sip_cc_agent_recall().

03544 {
03545    va_list ap;
03546    int res;
03547 
03548    va_start(ap, debug);
03549    res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
03550    va_end(ap);
03551    return res;
03552 }

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 3565 of file ccss.c.

References CC_RECALLING, and cc_request_state_change().

Referenced by generic_recall(), and get_destination().

03566 {
03567    va_list ap;
03568    int res;
03569 
03570    va_start(ap, debug);
03571    res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
03572    va_end(ap);
03573    return res;
03574 }

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 950 of file ccss.c.

References ast_calloc, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and cc_agent_backend::callbacks.

Referenced by ast_cc_init(), and load_module().

00951 {
00952    struct cc_agent_backend *backend = ast_calloc(1, sizeof(*backend));
00953 
00954    if (!backend) {
00955       return -1;
00956    }
00957 
00958    backend->callbacks = callbacks;
00959    AST_RWLIST_WRLOCK(&cc_agent_backends);
00960    AST_RWLIST_INSERT_TAIL(&cc_agent_backends, backend, next);
00961    AST_RWLIST_UNLOCK(&cc_agent_backends);
00962    return 0;
00963 }

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 3365 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(), and str.

Referenced by generic_recall(), and handle_request_invite().

03366 {
03367    struct ast_datastore *recall_datastore;
03368    struct cc_monitor_tree *interface_tree;
03369    struct ast_cc_monitor *monitor;
03370    struct cc_recall_ds_data *recall_data;
03371    struct ast_str *str = ast_str_create(64);
03372    int core_id;
03373 
03374    if (!str) {
03375       return -1;
03376    }
03377 
03378    ast_channel_lock(chan);
03379    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03380       ast_channel_unlock(chan);
03381       ast_free(str);
03382       return -1;
03383    }
03384    recall_data = recall_datastore->data;
03385    interface_tree = recall_data->interface_tree;
03386    core_id = recall_data->core_id;
03387    ast_channel_unlock(chan);
03388 
03389    AST_LIST_LOCK(interface_tree);
03390    monitor = AST_LIST_FIRST(interface_tree);
03391    build_cc_interfaces_chanvar(monitor, &str);
03392    AST_LIST_UNLOCK(interface_tree);
03393 
03394    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03395    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03396          core_id, ast_str_buffer(str));
03397 
03398    ast_free(str);
03399    return 0;
03400 }

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 3830 of file ccss.c.

References args, ast_calloc, ast_free, ast_taskprocessor_push(), cc_status_response(), cc_unref(), cc_status_response_args::core_instance, cc_status_response_args::devstate, and find_cc_core_instance().

Referenced by cc_generic_agent_status_request(), and sip_cc_agent_status_request().

03831 {
03832    struct cc_status_response_args *args;
03833    struct cc_core_instance *core_instance;
03834    int res;
03835 
03836    args = ast_calloc(1, sizeof(*args));
03837    if (!args) {
03838       return -1;
03839    }
03840 
03841    core_instance = find_cc_core_instance(core_id);
03842    if (!core_instance) {
03843       ast_free(args);
03844       return -1;
03845    }
03846 
03847    args->core_instance = core_instance;
03848    args->devstate = devstate;
03849 
03850    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
03851    if (res) {
03852       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03853       ast_free(args);
03854    }
03855    return res;
03856 }

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 965 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_agent_backend::callbacks, and cc_monitor_backend::next.

Referenced by __unload_module(), cc_shutdown(), and unload_module().

00966 {
00967    struct cc_agent_backend *backend;
00968    AST_RWLIST_WRLOCK(&cc_agent_backends);
00969    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_agent_backends, backend, next) {
00970       if (backend->callbacks == callbacks) {
00971          AST_RWLIST_REMOVE_CURRENT(next);
00972          ast_free(backend);
00973          break;
00974       }
00975    }
00976    AST_RWLIST_TRAVERSE_SAFE_END;
00977    AST_RWLIST_UNLOCK(&cc_agent_backends);
00978 }

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 1239 of file ccss.c.

References ast_cc_monitor_failed(), ast_cc_monitor::available_timer_id, cc_unref(), ast_cc_monitor::core_id, ast_cc_interface::device_name, ast_cc_monitor::interface, and monitor.

Referenced by cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

01240 {
01241    struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
01242    int res;
01243    monitor->available_timer_id = -1;
01244    res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
01245    cc_unref(monitor, "Unref reference from scheduler\n");
01246    return res;
01247 }

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 3913 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().

03917 {
03918    struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));
03919 
03920    if (!payload) {
03921       return -1;
03922    }
03923    if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
03924       /* Something screwed up, we can't make a frame with this */
03925       ast_free(payload);
03926       return -1;
03927    }
03928    frame->frametype = AST_FRAME_CONTROL;
03929    frame->subclass.integer = AST_CONTROL_CC;
03930    frame->data.ptr = payload;
03931    frame->datalen = sizeof(*payload);
03932    frame->mallocd = AST_MALLOCD_DATA;
03933    return 0;
03934 }

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 3969 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().

03971 {
03972    struct cc_control_payload payload;
03973    if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
03974       /* Something screwed up. Don't try to handle this payload */
03975       call_destructor_with_no_monitor(monitor_type, private_data);
03976       return;
03977    }
03978    ast_handle_cc_control_frame(inbound, NULL, &payload);
03979 }

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 3936 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().

03937 {
03938    char device_name[AST_CHANNEL_NAME];
03939    struct cc_control_payload payload;
03940    struct ast_cc_config_params *cc_params;
03941 
03942    if (outgoing->hangupcause != AST_CAUSE_BUSY && outgoing->hangupcause != AST_CAUSE_CONGESTION) {
03943       /* It doesn't make sense to try to offer CCBS to the caller if the reason for ast_call
03944        * failing is something other than busy or congestion
03945        */
03946       return;
03947    }
03948 
03949    cc_params = ast_channel_get_cc_config_params(outgoing);
03950    if (!cc_params) {
03951       return;
03952    }
03953    if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
03954       /* This sort of CCBS only works if using generic CC. For native, we would end up sending
03955        * a CC request for a non-existent call. The far end will reject this every time
03956        */
03957       return;
03958    }
03959 
03960    ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
03961    if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
03962       dialstring, AST_CC_CCBS, NULL, &payload)) {
03963       /* Something screwed up, we can't make a frame with this */
03964       return;
03965    }
03966    ast_handle_cc_control_frame(incoming, outgoing, &payload);
03967 }

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 2146 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_cc_monitor::core_id, ast_datastore::data, dialed_cc_interfaces::dial_parent_id, ast_channel::exten, ast_cc_monitor::id, dialed_cc_interfaces::ignore, dialed_cc_interfaces::interface_tree, ast_channel::macrocontext, ast_channel::macroexten, monitor, and S_OR.

Referenced by dial_exec_full().

02147 {
02148    /* There are three situations to deal with here:
02149     *
02150     * 1. The channel does not have a dialed_cc_interfaces datastore on
02151     * it. This means that this is the first time that Dial has
02152     * been called. We need to create/initialize the datastore.
02153     *
02154     * 2. The channel does have a cc_interface datastore on it and
02155     * the "ignore" indicator is 0. This means that a Local channel
02156     * was called by a "parent" dial. We can check the datastore's
02157     * parent field to see who the root of this particular dial tree
02158     * is.
02159     *
02160     * 3. The channel does have a cc_interface datastore on it and
02161     * the "ignore" indicator is 1. This means that a second Dial call
02162     * is being made from an extension. In this case, we do not
02163     * want to make any additions/modifications to the datastore. We
02164     * will instead set a flag to indicate that CCSS is completely
02165     * disabled for this Dial attempt.
02166     */
02167 
02168    struct ast_datastore *cc_interfaces_datastore;
02169    struct dialed_cc_interfaces *interfaces;
02170    struct ast_cc_monitor *monitor;
02171    struct ast_cc_config_params *cc_params;
02172 
02173    ast_channel_lock(chan);
02174 
02175    cc_params = ast_channel_get_cc_config_params(chan);
02176    if (!cc_params) {
02177       ast_channel_unlock(chan);
02178       return -1;
02179    }
02180    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
02181       /* We can't offer CC to this caller anyway, so don't bother with CC on this call
02182        */
02183       *ignore_cc = 1;
02184       ast_channel_unlock(chan);
02185       ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", chan->name);
02186       return 0;
02187    }
02188 
02189    if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02190       /* Situation 1 has occurred */
02191       ast_channel_unlock(chan);
02192       return cc_interfaces_datastore_init(chan);
02193    }
02194    interfaces = cc_interfaces_datastore->data;
02195    ast_channel_unlock(chan);
02196 
02197    if (interfaces->ignore) {
02198       /* Situation 3 has occurred */
02199       *ignore_cc = 1;
02200       ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
02201       return 0;
02202    }
02203 
02204    /* Situation 2 has occurred */
02205    if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten),
02206          S_OR(chan->macrocontext, chan->context), interfaces->dial_parent_id))) {
02207       return -1;
02208    }
02209    monitor->core_id = interfaces->core_id;
02210    AST_LIST_LOCK(interfaces->interface_tree);
02211    cc_ref(monitor, "monitor tree's reference to the monitor");
02212    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
02213    AST_LIST_UNLOCK(interfaces->interface_tree);
02214    interfaces->dial_parent_id = monitor->id;
02215    cc_unref(monitor, "Unref monitor's allocation reference");
02216    return 0;
02217 }

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 3981 of file ccss.c.

References ast_get_channel_tech(), and ast_channel_tech::cc_callback.

Referenced by dial_exec_full().

03982 {
03983    const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);
03984 
03985    if (chantech && chantech->cc_callback) {
03986       chantech->cc_callback(inbound, dest, callback);
03987    }
03988 
03989    return 0;
03990 }

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 3576 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, and cc_recall_ds_data::nested.

Referenced by wait_for_answer().

03577 {
03578    struct ast_datastore *recall_datastore;
03579    struct cc_recall_ds_data *recall_data;
03580    int core_id;
03581    va_list ap;
03582    int res;
03583 
03584    ast_channel_lock(chan);
03585    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03586       /* Silly! Why did you call this function if there's no recall DS? */
03587       ast_channel_unlock(chan);
03588       return -1;
03589    }
03590    recall_data = recall_datastore->data;
03591    if (recall_data->nested || recall_data->ignore) {
03592       /* If this is being called from a nested Dial, it is too
03593        * early to determine if the recall has actually completed.
03594        * The outermost dial is the only one with the authority to
03595        * declare the recall to be complete.
03596        *
03597        * Similarly, if this function has been called when the
03598        * recall has progressed beyond the first dial, this is not
03599        * a legitimate time to declare the recall to be done. In fact,
03600        * that should have been done already.
03601        */
03602       ast_channel_unlock(chan);
03603       return -1;
03604    }
03605    core_id = recall_data->core_id;
03606    ast_channel_unlock(chan);
03607    va_start(ap, debug);
03608    res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
03609    va_end(ap);
03610    return res;
03611 }

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 579 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(), process_dahdi(), setup_dahdi(), and sip_destroy_peer().

00580 {
00581    ast_free(params);
00582 }

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 741 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(), duplicate_pseudo(), and mkintf().

00742 {
00743    *dest = *src;
00744 }

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 558 of file ccss.c.

Referenced by __ast_cc_config_params_init().

00559 {
00560    *params = cc_default_params;
00561 }

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 1735 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, extension_child_dialstring::device_name, dialed_cc_interfaces::dial_parent_id, ast_cc_monitor::id, id, dialed_cc_interfaces::interface_tree, extension_child_dialstring::is_valid, monitor, extension_child_dialstring::original_dialstring, and ast_cc_monitor::private_data.

Referenced by dial_exec_full().

01736 {
01737    struct ast_datastore *cc_datastore;
01738    struct dialed_cc_interfaces *cc_interfaces;
01739    struct ast_cc_monitor *monitor;
01740    struct extension_monitor_pvt *extension_pvt;
01741    struct extension_child_dialstring *child_dialstring;
01742    struct cc_monitor_tree *interface_tree;
01743    int id;
01744 
01745    ast_channel_lock(incoming);
01746    if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
01747       ast_channel_unlock(incoming);
01748       return;
01749    }
01750 
01751    cc_interfaces = cc_datastore->data;
01752    interface_tree = cc_interfaces->interface_tree;
01753    id = cc_interfaces->dial_parent_id;
01754    ast_channel_unlock(incoming);
01755 
01756    AST_LIST_LOCK(interface_tree);
01757    AST_LIST_TRAVERSE(interface_tree, monitor, next) {
01758       if (monitor->id == id) {
01759          break;
01760       }
01761    }
01762 
01763    if (!monitor) {
01764       AST_LIST_UNLOCK(interface_tree);
01765       return;
01766    }
01767 
01768    extension_pvt = monitor->private_data;
01769    if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
01770       AST_LIST_UNLOCK(interface_tree);
01771       return;
01772    }
01773    ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
01774    ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
01775    child_dialstring->is_valid = 1;
01776    AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
01777    AST_LIST_UNLOCK(interface_tree);
01778 }

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 3613 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(), sip_offer_timer_expire(), suspend(), unsuspend(), and wait_for_answer().

03614 {
03615    va_list ap;
03616    int res;
03617 
03618    va_start(ap, debug);
03619    res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
03620    va_end(ap);
03621    return res;
03622 }

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 2224 of file ccss.c.

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

Referenced by sip_handle_cc().

02225 {
02226    struct ast_datastore *datastore;
02227    struct dialed_cc_interfaces *cc_interfaces;
02228    int core_id_return;
02229 
02230    ast_channel_lock(chan);
02231    if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02232       ast_channel_unlock(chan);
02233       return -1;
02234    }
02235 
02236    cc_interfaces = datastore->data;
02237    core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
02238    ast_channel_unlock(chan);
02239    return core_id_return;
02240 
02241 }

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

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 3253 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, and cc_core_instance::monitors.

Referenced by sip_call().

03254 {
03255    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03256    struct ast_cc_monitor *monitor_iter;
03257 
03258    if (!core_instance) {
03259       return NULL;
03260    }
03261 
03262    AST_LIST_LOCK(core_instance->monitors);
03263    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03264       if (!strcmp(monitor_iter->interface->device_name, device_name)) {
03265          /* Found a monitor. */
03266          cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
03267          break;
03268       }
03269    }
03270    AST_LIST_UNLOCK(core_instance->monitors);
03271    cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
03272    return monitor_iter;
03273 }

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 645 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(), LOG_WARNING, monitor_policy_to_str(), and value.

Referenced by acf_cc_read().

00647 {
00648    const char *value = NULL;
00649 
00650    if (!strcasecmp(name, "cc_callback_macro")) {
00651       value = ast_get_cc_callback_macro(params);
00652    } else if (!strcasecmp(name, "cc_agent_policy")) {
00653       value = agent_policy_to_str(ast_get_cc_agent_policy(params));
00654    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00655       value = monitor_policy_to_str(ast_get_cc_monitor_policy(params));
00656    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00657       value = ast_get_cc_agent_dialstring(params);
00658    }
00659    if (value) {
00660       ast_copy_string(buf, value, buf_len);
00661       return 0;
00662    }
00663 
00664    /* The rest of these are all ints of some sort and require some
00665     * snprintf-itude
00666     */
00667 
00668    if (!strcasecmp(name, "cc_offer_timer")) {
00669       snprintf(buf, buf_len, "%u", ast_get_cc_offer_timer(params));
00670    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00671       snprintf(buf, buf_len, "%u", ast_get_ccnr_available_timer(params));
00672    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00673       snprintf(buf, buf_len, "%u", ast_get_ccbs_available_timer(params));
00674    } else if (!strcasecmp(name, "cc_max_agents")) {
00675       snprintf(buf, buf_len, "%u", ast_get_cc_max_agents(params));
00676    } else if (!strcasecmp(name, "cc_max_monitors")) {
00677       snprintf(buf, buf_len, "%u", ast_get_cc_max_monitors(params));
00678    } else if (!strcasecmp(name, "cc_recall_timer")) {
00679       snprintf(buf, buf_len, "%u", ast_get_cc_recall_timer(params));
00680    } else {
00681       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00682       return -1;
00683    }
00684 
00685    return 0;
00686 }

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 4340 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_register_atexit(), ast_sched_thread_create(), ast_taskprocessor_get(), cc_core_instance_cmp_fn(), cc_core_instance_hash_fn(), cc_shutdown(), cccancel_exec(), ccreq_exec(), generic_monitor_cbs, generic_monitor_cmp_fn(), generic_monitor_hash_fn(), generic_monitors, initialize_cc_max_requests(), and TPS_REF_DEFAULT.

Referenced by main().

04341 {
04342    int res;
04343 
04344    if (!(cc_core_instances = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04345                cc_core_instance_hash_fn, cc_core_instance_cmp_fn,
04346                "Create core instance container"))) {
04347       return -1;
04348    }
04349    if (!(generic_monitors = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04350                generic_monitor_hash_fn, generic_monitor_cmp_fn,
04351                "Create generic monitor container"))) {
04352       return -1;
04353    }
04354    if (!(cc_core_taskprocessor = ast_taskprocessor_get("CCSS core", TPS_REF_DEFAULT))) {
04355       return -1;
04356    }
04357    if (!(cc_sched_thread = ast_sched_thread_create())) {
04358       return -1;
04359    }
04360    res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL);
04361    res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL);
04362    res |= ast_cc_monitor_register(&generic_monitor_cbs);
04363    res |= ast_cc_agent_register(&generic_agent_callbacks);
04364    ast_cli_register_multiple(cc_cli, ARRAY_LEN(cc_cli));
04365    cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME);
04366    dialed_cc_interface_counter = 1;
04367    initialize_cc_max_requests();
04368    ast_register_atexit(cc_shutdown);
04369    return res;
04370 }

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 727 of file ccss.c.

Referenced by build_peer(), and process_dahdi().

00728 {
00729    return (!strcasecmp(name, "cc_agent_policy") ||
00730             !strcasecmp(name, "cc_monitor_policy") ||
00731             !strcasecmp(name, "cc_offer_timer") ||
00732             !strcasecmp(name, "ccnr_available_timer") ||
00733             !strcasecmp(name, "ccbs_available_timer") ||
00734             !strcasecmp(name, "cc_max_agents") ||
00735             !strcasecmp(name, "cc_max_monitors") ||
00736             !strcasecmp(name, "cc_callback_macro") ||
00737             !strcasecmp(name, "cc_agent_dialstring") ||
00738             !strcasecmp(name, "cc_recall_timer"));
00739 }

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 3172 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, and cc_recall_ds_data::nested.

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

03173 {
03174    struct ast_datastore *recall_datastore;
03175    struct cc_recall_ds_data *recall_data;
03176    struct cc_monitor_tree *interface_tree;
03177    char device_name[AST_CHANNEL_NAME];
03178    struct ast_cc_monitor *device_monitor;
03179    int core_id_candidate;
03180 
03181    ast_assert(core_id != NULL);
03182 
03183    *core_id = -1;
03184 
03185    ast_channel_lock(chan);
03186    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03187       /* Obviously not a recall if the datastore isn't present */
03188       ast_channel_unlock(chan);
03189       return 0;
03190    }
03191 
03192    recall_data = recall_datastore->data;
03193 
03194    if (recall_data->ignore) {
03195       /* Though this is a recall, the call to this particular interface is not part of the
03196        * recall either because this is a call forward or because this is not the first
03197        * invocation of Dial during this call
03198        */
03199       ast_channel_unlock(chan);
03200       return 0;
03201    }
03202 
03203    if (!recall_data->nested) {
03204       /* If the nested flag is not set, then this means that
03205        * the channel passed to this function is the caller making
03206        * the recall. This means that we shouldn't look through
03207        * the monitor tree for the channel because it shouldn't be
03208        * there. However, this is a recall though, so return true.
03209        */
03210       *core_id = recall_data->core_id;
03211       ast_channel_unlock(chan);
03212       return 1;
03213    }
03214 
03215    if (ast_strlen_zero(monitor_type)) {
03216       /* If someone passed a NULL or empty monitor type, then it is clear
03217        * the channel they passed in was an incoming channel, and so searching
03218        * the list of dialed interfaces is not going to be helpful. Just return
03219        * false immediately.
03220        */
03221       ast_channel_unlock(chan);
03222       return 0;
03223    }
03224 
03225    interface_tree = recall_data->interface_tree;
03226    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03227    /* We grab the value of the recall_data->core_id so that we
03228     * can unlock the channel before we start looking through the
03229     * interface list. That way we don't have to worry about a possible
03230     * clash between the channel lock and the monitor tree lock.
03231     */
03232    core_id_candidate = recall_data->core_id;
03233    ast_channel_unlock(chan);
03234 
03235    /*
03236     * Now we need to find out if the channel device name
03237     * is in the list of interfaces in the called tree.
03238     */
03239    AST_LIST_LOCK(interface_tree);
03240    AST_LIST_TRAVERSE(interface_tree, device_monitor, next) {
03241       if (!strcmp(device_monitor->interface->device_name, device_name) &&
03242             !strcmp(device_monitor->interface->monitor_type, monitor_type)) {
03243          /* BOOM! Device is in the tree! We have a winner! */
03244          *core_id = core_id_candidate;
03245          AST_LIST_UNLOCK(interface_tree);
03246          return 1;
03247       }
03248    }
03249    AST_LIST_UNLOCK(interface_tree);
03250    return 0;
03251 }

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 3532 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(), and handle_cc_notify().

03533 {
03534    va_list ap;
03535    int res;
03536 
03537    va_start(ap, debug);
03538    res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
03539    va_end(ap);
03540    return res;
03541 }

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 4105 of file ccss.c.

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

Referenced by ast_queue_cc_frame().

04106 {
04107    struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};
04108 
04109    ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
04110    ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
04111    return data.count;
04112 }

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 3678 of file ccss.c.

References ast_calloc, ast_free, ast_strdup, ast_taskprocessor_push(), ast_vasprintf, cc_monitor_failed(), ast_cc_monitor_failure_data::core_id, ast_cc_monitor_failure_data::debug, and ast_cc_monitor_failure_data::device_name.

Referenced by ast_cc_available_timer_expire(), cc_handle_publish_error(), and handle_response_subscribe().

03679 {
03680    struct ast_cc_monitor_failure_data *failure_data;
03681    int res;
03682    va_list ap;
03683 
03684    if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
03685       return -1;
03686    }
03687 
03688    if (!(failure_data->device_name = ast_strdup(monitor_name))) {
03689       ast_free(failure_data);
03690       return -1;
03691    }
03692 
03693    va_start(ap, debug);
03694    if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
03695       va_end(ap);
03696       ast_free((char *)failure_data->device_name);
03697       ast_free(failure_data);
03698       return -1;
03699    }
03700    va_end(ap);
03701 
03702    failure_data->core_id = core_id;
03703 
03704    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
03705    if (res) {
03706       ast_free((char *)failure_data->device_name);
03707       ast_free((char *)failure_data->debug);
03708       ast_free(failure_data);
03709    }
03710    return res;
03711 }

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 3788 of file ccss.c.

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

03789 {
03790    int res;
03791    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03792 
03793    if (!core_instance) {
03794       return -1;
03795    }
03796 
03797    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
03798    if (res) {
03799       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03800    }
03801    return res;
03802 }

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 895 of file ccss.c.

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

Referenced by ast_cc_init(), and load_module().

00896 {
00897    struct cc_monitor_backend *backend = ast_calloc(1, sizeof(*backend));
00898 
00899    if (!backend) {
00900       return -1;
00901    }
00902 
00903    backend->callbacks = callbacks;
00904 
00905    AST_RWLIST_WRLOCK(&cc_monitor_backends);
00906    AST_RWLIST_INSERT_TAIL(&cc_monitor_backends, backend, next);
00907    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00908    return 0;
00909 }

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 3521 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

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

03522 {
03523    va_list ap;
03524    int res;
03525 
03526    va_start(ap, debug);
03527    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03528    va_end(ap);
03529    return res;
03530 }

int ast_cc_monitor_status_request ( int  core_id  ) 

Request the status of a caller or callers.

The following are all functions which are required due to the unique case where Asterisk is acting as the NT side of an ISDN PTMP connection to the caller and as the TE side of an ISDN PTMP connection to the callee. In such a case, there are several times where the PTMP monitor needs information from the agent in order to formulate the appropriate messages to send.

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 3723 of file ccss.c.

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

03724 {
03725    int res;
03726    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03727 
03728    if (!core_instance) {
03729       return -1;
03730    }
03731 
03732    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
03733    if (res) {
03734       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03735    }
03736    return res;
03737 }

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 3760 of file ccss.c.

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

03761 {
03762    int res;
03763    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03764 
03765    if (!core_instance) {
03766       return -1;
03767    }
03768 
03769    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
03770    if (res) {
03771       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03772    }
03773    return res;
03774 }

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 928 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(), cc_shutdown(), and unload_module().

00929 {
00930    struct cc_monitor_backend *backend;
00931    AST_RWLIST_WRLOCK(&cc_monitor_backends);
00932    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_monitor_backends, backend, next) {
00933       if (backend->callbacks == callbacks) {
00934          AST_RWLIST_REMOVE_CURRENT(next);
00935          ast_free(backend);
00936          break;
00937       }
00938    }
00939    AST_RWLIST_TRAVERSE_SAFE_END;
00940    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00941 }

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 3485 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, and dialed_cc_interfaces::is_original_caller.

Referenced by ast_hangup().

03486 {
03487    int core_id;
03488    int res = -1;
03489    struct ast_datastore *datastore;
03490    struct dialed_cc_interfaces *cc_interfaces;
03491    char cc_is_offerable;
03492 
03493    ast_channel_lock(caller_chan);
03494    if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
03495       ast_channel_unlock(caller_chan);
03496       return res;
03497    }
03498 
03499    cc_interfaces = datastore->data;
03500    cc_is_offerable = cc_interfaces->is_original_caller;
03501    core_id = cc_interfaces->core_id;
03502    ast_channel_unlock(caller_chan);
03503 
03504    if (cc_is_offerable) {
03505       res = cc_offer(core_id, "CC offered to caller %s", caller_chan->name);
03506    }
03507    return res;
03508 }

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 2219 of file ccss.c.

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

02220 {
02221    return cc_request_count < global_cc_max_requests;
02222 }

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 688 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(), build_peer(), and process_dahdi().

00690 {
00691    unsigned int value_as_uint;
00692    if (!strcasecmp(name, "cc_agent_policy")) {
00693       return ast_set_cc_agent_policy(params, str_to_agent_policy(value));
00694    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00695       return ast_set_cc_monitor_policy(params, str_to_monitor_policy(value));
00696    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00697       ast_set_cc_agent_dialstring(params, value);
00698    } else if (!strcasecmp(name, "cc_callback_macro")) {
00699       ast_set_cc_callback_macro(params, value);
00700       return 0;
00701    }
00702 
00703    if (!sscanf(value, "%30u", &value_as_uint) == 1) {
00704       return -1;
00705    }
00706 
00707    if (!strcasecmp(name, "cc_offer_timer")) {
00708       ast_set_cc_offer_timer(params, value_as_uint);
00709    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00710       ast_set_ccnr_available_timer(params, value_as_uint);
00711    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00712       ast_set_ccbs_available_timer(params, value_as_uint);
00713    } else if (!strcasecmp(name, "cc_max_agents")) {
00714       ast_set_cc_max_agents(params, value_as_uint);
00715    } else if (!strcasecmp(name, "cc_max_monitors")) {
00716       ast_set_cc_max_monitors(params, value_as_uint);
00717    } else if (!strcasecmp(name, "cc_recall_timer")) {
00718       ast_set_cc_recall_timer(params, value_as_uint);
00719    } else {
00720       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00721       return -1;
00722    }
00723 
00724    return 0;
00725 }

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 840 of file ccss.c.

References ast_cc_config_params::cc_agent_dialstring.

Referenced by ast_cc_get_param(), and generic_recall().

00841 {
00842    return config->cc_agent_dialstring;
00843 }

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 746 of file ccss.c.

References ast_cc_config_params::cc_agent_policy.

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

00747 {
00748    return config->cc_agent_policy;
00749 }

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 874 of file ccss.c.

References ast_cc_config_params::cc_callback_macro.

Referenced by ast_cc_get_param(), and generic_recall().

00875 {
00876    return config->cc_callback_macro;
00877 }

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 854 of file ccss.c.

References ast_cc_config_params::cc_max_agents.

Referenced by ast_cc_get_param(), and cc_core_init_instance().

00855 {
00856    return config->cc_max_agents;
00857 }

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 864 of file ccss.c.

References ast_cc_config_params::cc_max_monitors.

Referenced by ast_cc_get_param(), and ast_queue_cc_frame().

00865 {
00866    return config->cc_max_monitors;
00867 }

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 763 of file ccss.c.

References ast_cc_config_params::cc_monitor_policy.

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

00764 {
00765    return config->cc_monitor_policy;
00766 }

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 780 of file ccss.c.

References ast_cc_config_params::cc_offer_timer.

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

00781 {
00782    return config->cc_offer_timer;
00783 }

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 810 of file ccss.c.

References ast_cc_config_params::cc_recall_timer.

Referenced by ast_cc_get_param(), and generic_recall().

00811 {
00812    return config->cc_recall_timer;
00813 }

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 825 of file ccss.c.

References ast_cc_config_params::ccbs_available_timer.

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

00826 {
00827    return config->ccbs_available_timer;
00828 }

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 795 of file ccss.c.

References ast_cc_config_params::ccnr_available_timer.

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

00796 {
00797    return config->ccnr_available_timer;
00798 }

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 2048 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, ast_cc_interface::device_name, cc_control_payload::device_name, cc_control_payload::dialstring, ast_cc_monitor::dialstring, EVENT_FLAG_CC, find_cc_core_instance(), dialed_cc_interfaces::ignore, ast_cc_monitor::interface, dialed_cc_interfaces::interface_tree, dialed_cc_interfaces::is_original_caller, LOG_WARNING, manager_event, monitor, cc_control_payload::monitor_type, ast_cc_monitor::parent_id, cc_control_payload::private_data, and cc_control_payload::service.

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

02049 {
02050    char *device_name;
02051    char *dialstring;
02052    struct ast_cc_monitor *monitor;
02053    struct ast_datastore *cc_datastore;
02054    struct dialed_cc_interfaces *cc_interfaces;
02055    struct cc_control_payload *cc_data = frame_data;
02056    struct cc_core_instance *core_instance;
02057 
02058    device_name = cc_data->device_name;
02059    dialstring = cc_data->dialstring;
02060 
02061    ast_channel_lock(inbound);
02062    if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
02063       ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
02064       ast_channel_unlock(inbound);
02065       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02066       return;
02067    }
02068 
02069    cc_interfaces = cc_datastore->data;
02070 
02071    if (cc_interfaces->ignore) {
02072       ast_channel_unlock(inbound);
02073       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02074       return;
02075    }
02076 
02077    if (!cc_interfaces->is_original_caller) {
02078       /* If the is_original_caller is not set on the *inbound* channel, then
02079        * it must be a local channel. As such, we do not want to create a core instance
02080        * or an agent for the local channel. Instead, we want to pass this along to the
02081        * other side of the local channel so that the original caller can benefit.
02082        */
02083       ast_channel_unlock(inbound);
02084       ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
02085       return;
02086    }
02087 
02088    core_instance = find_cc_core_instance(cc_interfaces->core_id);
02089    if (!core_instance) {
02090       core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
02091          cc_interfaces->core_id, cc_data);
02092       if (!core_instance) {
02093          cc_interfaces->ignore = 1;
02094          ast_channel_unlock(inbound);
02095          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02096          return;
02097       }
02098    }
02099 
02100    ast_channel_unlock(inbound);
02101 
02102    /* Yeah this kind of sucks, but luckily most people
02103     * aren't dialing thousands of interfaces on every call
02104     *
02105     * This traversal helps us to not create duplicate monitors in
02106     * case a device queues multiple CC control frames.
02107     */
02108    AST_LIST_LOCK(cc_interfaces->interface_tree);
02109    AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
02110       if (!strcmp(monitor->interface->device_name, device_name)) {
02111          ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
02112                core_instance->core_id, device_name);
02113          AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02114          cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02115          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02116          return;
02117       }
02118    }
02119    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02120 
02121    if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
02122       ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
02123       cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02124       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02125       return;
02126    }
02127 
02128    AST_LIST_LOCK(cc_interfaces->interface_tree);
02129    cc_ref(monitor, "monitor tree's reference to the monitor");
02130    AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
02131    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02132 
02133    cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
02134 
02135    manager_event(EVENT_FLAG_CC, "CCAvailable",
02136       "CoreID: %d\r\n"
02137       "Callee: %s\r\n"
02138       "Service: %s\r\n",
02139       cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
02140    );
02141 
02142    cc_unref(core_instance, "Done with core_instance after handling CC control frame");
02143    cc_unref(monitor, "Unref reference from allocating monitor");
02144 }

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 3454 of file ccss.c.

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

Referenced by dial_exec_full(), and do_forward().

03455 {
03456    struct ast_datastore *cc_datastore;
03457    struct ast_datastore *cc_recall_datastore;
03458    struct dialed_cc_interfaces *cc_interfaces;
03459    struct cc_recall_ds_data *recall_cc_data;
03460 
03461    ast_channel_lock(chan);
03462    if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
03463       cc_interfaces = cc_datastore->data;
03464       cc_interfaces->ignore = 1;
03465    }
03466 
03467    if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03468       recall_cc_data = cc_recall_datastore->data;
03469       recall_cc_data->ignore = 1;
03470    }
03471    ast_channel_unlock(chan);
03472 }

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 3886 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(), and sip_handle_cc().

03888 {
03889    struct ast_frame frame = {0,};
03890    char device_name[AST_CHANNEL_NAME];
03891    int retval;
03892    struct ast_cc_config_params *cc_params;
03893 
03894    cc_params = ast_channel_get_cc_config_params(chan);
03895    if (!cc_params) {
03896       return -1;
03897    }
03898    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03899    if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
03900       ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
03901       return -1;
03902    }
03903 
03904    if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
03905       /* Frame building failed. We can't use this. */
03906       return -1;
03907    }
03908    retval = ast_queue_frame(chan, &frame);
03909    ast_frfree(&frame);
03910    return retval;
03911 }

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 845 of file ccss.c.

References ast_copy_string(), ast_strlen_zero(), and ast_cc_config_params::cc_agent_dialstring.

Referenced by ast_cc_set_param().

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

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 751 of file ccss.c.

References AST_CC_AGENT_GENERIC, and ast_cc_config_params::cc_agent_policy.

Referenced by ast_cc_set_param(), and build_peer().

00752 {
00753    /* Screw C and its weak type checking for making me have to do this
00754     * validation at runtime.
00755     */
00756    if (value < AST_CC_AGENT_NEVER || value > AST_CC_AGENT_GENERIC) {
00757       return -1;
00758    }
00759    config->cc_agent_policy = value;
00760    return 0;
00761 }

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 879 of file ccss.c.

References ast_copy_string(), ast_strlen_zero(), and ast_cc_config_params::cc_callback_macro.

Referenced by ast_cc_set_param().

00880 {
00881    if (ast_strlen_zero(value)) {
00882       config->cc_callback_macro[0] = '\0';
00883    } else {
00884       ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
00885    }
00886 }

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 3402 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, pbx_builtin_setvar_helper(), and str.

Referenced by local_call().

03403 {
03404    struct ast_datastore *recall_datastore;
03405    struct cc_monitor_tree *interface_tree;
03406    struct ast_cc_monitor *monitor_iter;
03407    struct cc_recall_ds_data *recall_data;
03408    struct ast_str *str = ast_str_create(64);
03409    int core_id;
03410 
03411    if (!str) {
03412       return -1;
03413    }
03414 
03415    ast_channel_lock(chan);
03416    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03417       ast_channel_unlock(chan);
03418       ast_free(str);
03419       return -1;
03420    }
03421    recall_data = recall_datastore->data;
03422    interface_tree = recall_data->interface_tree;
03423    core_id = recall_data->core_id;
03424    ast_channel_unlock(chan);
03425 
03426    AST_LIST_LOCK(interface_tree);
03427    AST_LIST_TRAVERSE(interface_tree, monitor_iter, next) {
03428       if (!strcmp(monitor_iter->interface->device_name, extension)) {
03429          break;
03430       }
03431    }
03432 
03433    if (!monitor_iter) {
03434       /* We couldn't find this extension. This may be because
03435        * we have been directed into an unexpected extension because
03436        * the admin has changed a CC_INTERFACES variable at some point.
03437        */
03438       AST_LIST_UNLOCK(interface_tree);
03439       ast_free(str);
03440       return -1;
03441    }
03442 
03443    build_cc_interfaces_chanvar(monitor_iter, &str);
03444    AST_LIST_UNLOCK(interface_tree);
03445 
03446    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03447    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03448          core_id, ast_str_buffer(str));
03449 
03450    ast_free(str);
03451    return 0;
03452 }

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 859 of file ccss.c.

References ast_cc_config_params::cc_max_agents.

Referenced by ast_cc_set_param().

00860 {
00861    config->cc_max_agents = value;
00862 }

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 869 of file ccss.c.

References ast_cc_config_params::cc_max_monitors.

Referenced by ast_cc_set_param().

00870 {
00871    config->cc_max_monitors = value;
00872 }

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 768 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, and ast_cc_config_params::cc_monitor_policy.

Referenced by ast_cc_set_param().

00769 {
00770    /* Screw C and its weak type checking for making me have to do this
00771     * validation at runtime.
00772     */
00773    if (value < AST_CC_MONITOR_NEVER || value > AST_CC_MONITOR_ALWAYS) {
00774       return -1;
00775    }
00776    config->cc_monitor_policy = value;
00777    return 0;
00778 }

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 785 of file ccss.c.

References ast_log(), ast_cc_config_params::cc_offer_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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 815 of file ccss.c.

References ast_log(), ast_cc_config_params::cc_recall_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00816 {
00817    /* 0 is an unreasonable value for any timer. Stick with the default */
00818    if (value == 0) {
00819       ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
00820       return;
00821    }
00822    config->cc_recall_timer = value;
00823 }

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 830 of file ccss.c.

References ast_log(), ast_cc_config_params::ccbs_available_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00831 {
00832    /* 0 is an unreasonable value for any timer. Stick with the default */
00833    if (value == 0) {
00834       ast_log(LOG_WARNING, "0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
00835       return;
00836    }
00837    config->ccbs_available_timer = value;
00838 }

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 800 of file ccss.c.

References ast_log(), ast_cc_config_params::ccnr_available_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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 3139 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(), cc_recall_ds_data::core_id, ast_datastore::data, DATASTORE_INHERIT_FOREVER, find_cc_core_instance(), ast_datastore::inheritance, cc_recall_ds_data::interface_tree, and cc_core_instance::monitors.

Referenced by generic_recall(), and handle_request_invite().

03140 {
03141    struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
03142    struct cc_recall_ds_data *recall_data;
03143    struct cc_core_instance *core_instance;
03144 
03145    if (!recall_datastore) {
03146       return -1;
03147    }
03148 
03149    if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
03150       ast_datastore_free(recall_datastore);
03151       return -1;
03152    }
03153 
03154    if (!(core_instance = find_cc_core_instance(core_id))) {
03155       ast_free(recall_data);
03156       ast_datastore_free(recall_datastore);
03157       return -1;
03158    }
03159 
03160    recall_data->interface_tree = cc_ref(core_instance->monitors,
03161          "Bump refcount for monitor tree for recall datastore");
03162    recall_data->core_id = core_id;
03163    recall_datastore->data = recall_data;
03164    recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
03165    ast_channel_lock(chan);
03166    ast_channel_datastore_add(chan, recall_datastore);
03167    ast_channel_unlock(chan);
03168    cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
03169    return 0;
03170 }

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

Definition at line 3322 of file ccss.c.

References AST_LIST_NEXT, AST_LIST_TRAVERSE, ast_log(), ast_str_strlen(), ast_str_truncate(), cc_unique_append(), extension_monitor_pvt::child_dialstrings, ast_cc_interface::device_name, ast_cc_monitor::dialstring, ast_cc_monitor::id, ast_cc_monitor::interface, extension_child_dialstring::is_valid, LOG_ERROR, extension_child_dialstring::original_dialstring, ast_cc_monitor::parent_id, and ast_cc_monitor::private_data.

Referenced by ast_cc_agent_set_interfaces_chanvar(), and ast_set_cc_interfaces_chanvar().

03323 {
03324    struct extension_monitor_pvt *extension_pvt;
03325    struct extension_child_dialstring *child_dialstring;
03326    struct ast_cc_monitor *monitor_iter = starting_point;
03327    int top_level_id = starting_point->id;
03328    size_t length;
03329 
03330    /* Init to an empty string. */
03331    ast_str_truncate(*str, 0);
03332 
03333    /* First we need to take all of the is_valid child_dialstrings from
03334     * the extension monitor we found and add them to the CC_INTERFACES
03335     * chanvar
03336     */
03337    extension_pvt = starting_point->private_data;
03338    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
03339       if (child_dialstring->is_valid) {
03340          cc_unique_append(str, child_dialstring->original_dialstring);
03341       }
03342    }
03343 
03344    /* And now we get the dialstrings from each of the device monitors */
03345    while ((monitor_iter = AST_LIST_NEXT(monitor_iter, next))) {
03346       if (monitor_iter->parent_id == top_level_id) {
03347          cc_unique_append(str, monitor_iter->dialstring);
03348       }
03349    }
03350 
03351    /* str will have an extra '&' tacked onto the end of it, so we need
03352     * to get rid of that.
03353     */
03354    length = ast_str_strlen(*str);
03355    if (length) {
03356       ast_str_truncate(*str, length - 1);
03357    }
03358    if (length <= 1) {
03359       /* Nothing to recall?  This should not happen. */
03360       ast_log(LOG_ERROR, "CC_INTERFACES is empty. starting device_name:'%s'\n",
03361          starting_point->interface->device_name);
03362    }
03363 }

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

Definition at line 1946 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().

01947 {
01948    const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
01949 
01950    if (!monitor_callbacks) {
01951       return;
01952    }
01953 
01954    monitor_callbacks->destructor(private_data);
01955 }

static void cancel_available_timer ( struct cc_core_instance core_instance  )  [static]

Definition at line 2955 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, ast_cc_interface::device_name, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, and ast_cc_monitor::parent_id.

Referenced by cc_recalling().

02956 {
02957    struct ast_cc_monitor *monitor_iter;
02958    AST_LIST_LOCK(core_instance->monitors);
02959    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02960       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02961          if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
02962             AST_LIST_REMOVE_CURRENT(next);
02963             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02964                   monitor_iter->interface->device_name, 1);
02965             cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
02966          }
02967       }
02968    }
02969    AST_LIST_TRAVERSE_SAFE_END;
02970 
02971    if (!has_device_monitors(core_instance)) {
02972       ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
02973    }
02974    AST_LIST_UNLOCK(core_instance->monitors);
02975 }

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 2888 of file ccss.c.

References cc_core_instance::agent, AST_CC_AGENT_RESPONSE_SUCCESS, 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, ast_cc_agent_callbacks::respond, and unsuspend().

02889 {
02890    /* Either
02891     * 1. Callee accepted CC request, call agent's ack callback.
02892     * 2. Caller became available, call agent's stop_monitoring callback and
02893     *    call monitor's unsuspend callback.
02894     */
02895    if (previous_state == CC_CALLER_REQUESTED) {
02896       core_instance->agent->callbacks->respond(core_instance->agent,
02897          AST_CC_AGENT_RESPONSE_SUCCESS);
02898       manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
02899          "CoreID: %d\r\n"
02900          "Caller: %s\r\n",
02901          core_instance->core_id, core_instance->agent->device_name);
02902    } else if (previous_state == CC_CALLER_BUSY) {
02903       manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
02904          "CoreID: %d\r\n"
02905          "Caller: %s\r\n",
02906          core_instance->core_id, core_instance->agent->device_name);
02907       unsuspend(core_instance);
02908    }
02909    /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
02910    return 0;
02911 }

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

Definition at line 434 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().

00435 {
00436    struct cc_core_instance *core_instance = obj;
00437    struct cc_callback_helper *helper = args;
00438 
00439    if (strcmp(core_instance->agent->callbacks->type, helper->type)) {
00440       return 0;
00441    }
00442 
00443    return helper->function(core_instance->agent, helper->args, flags);
00444 }

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, read]

Definition at line 2291 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, ast_cc_agent::callbacks, ast_cc_agent::cc_params, cc_unref(), check_callback_sanity(), ast_cc_agent::core_id, ast_cc_agent::device_name, find_agent_callbacks(), and ast_cc_agent_callbacks::init.

Referenced by cc_core_init_instance().

02294 {
02295    struct ast_cc_agent *agent;
02296    struct ast_cc_config_params *cc_params;
02297 
02298    if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
02299                "Allocating new ast_cc_agent"))) {
02300       return NULL;
02301    }
02302 
02303    agent->core_id = core_id;
02304    strcpy(agent->device_name, caller_name);
02305 
02306    cc_params = ast_channel_get_cc_config_params(caller_chan);
02307    if (!cc_params) {
02308       cc_unref(agent, "Could not get channel config params.");
02309       return NULL;
02310    }
02311    if (!(agent->cc_params = ast_cc_config_params_init())) {
02312       cc_unref(agent, "Could not init agent config params.");
02313       return NULL;
02314    }
02315    ast_cc_copy_config_params(agent->cc_params, cc_params);
02316 
02317    if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
02318       cc_unref(agent, "Could not find agent callbacks.");
02319       return NULL;
02320    }
02321    check_callback_sanity(agent->callbacks);
02322 
02323    if (agent->callbacks->init(agent, caller_chan)) {
02324       cc_unref(agent, "Agent init callback failed.");
02325       return NULL;
02326    }
02327    ast_log_dynamic_level(cc_logger_level, "Core %d: Created an agent for caller %s\n",
02328          agent->core_id, agent->device_name);
02329    return agent;
02330 }

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 2769 of file ccss.c.

References ast_log(), and LOG_WARNING.

02770 {
02771    /* This should never happen... */
02772    ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
02773    return -1;
02774 }

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 3858 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, 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().

03861 {
03862    struct ast_datastore *datastore;
03863    struct dialed_cc_interfaces *cc_interfaces;
03864    int dial_parent_id;
03865 
03866    ast_channel_lock(chan);
03867    datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL);
03868    if (!datastore) {
03869       ast_channel_unlock(chan);
03870       return -1;
03871    }
03872    cc_interfaces = datastore->data;
03873    dial_parent_id = cc_interfaces->dial_parent_id;
03874    ast_channel_unlock(chan);
03875 
03876    payload->monitor_type = monitor_type;
03877    payload->private_data = private_data;
03878    payload->service = service;
03879    ast_cc_copy_config_params(&payload->config_params, cc_params);
03880    payload->parent_interface_id = dial_parent_id;
03881    ast_copy_string(payload->device_name, device_name, sizeof(payload->device_name));
03882    ast_copy_string(payload->dialstring, dialstring, sizeof(payload->dialstring));
03883    return 0;
03884 }

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 2913 of file ccss.c.

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

02914 {
02915    core_instance->agent->callbacks->callee_available(core_instance->agent);
02916    return 0;
02917 }

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 2941 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().

02942 {
02943    /* Callee was available, but caller was busy, call agent's begin_monitoring callback
02944     * and call monitor's suspend callback.
02945     */
02946    suspend(core_instance);
02947    core_instance->agent->callbacks->start_monitoring(core_instance->agent);
02948    manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
02949       "CoreID: %d\r\n"
02950       "Caller: %s\r\n",
02951       core_instance->core_id, core_instance->agent->device_name);
02952    return 0;
02953 }

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 2776 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.

02777 {
02778    if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
02779       ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
02780             core_instance->agent->device_name);
02781       return -1;
02782    }
02783    manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
02784       "CoreID: %d\r\n"
02785       "Caller: %s\r\n"
02786       "Expires: %u\r\n",
02787       core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
02788    ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
02789          core_instance->core_id, core_instance->agent->device_name);
02790    return 0;
02791 }

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 2852 of file ccss.c.

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

02853 {
02854    if (!ast_cc_request_is_within_limits()) {
02855       ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
02856       core_instance->agent->callbacks->respond(core_instance->agent,
02857          AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY);
02858       ast_cc_failed(core_instance->core_id, "Too many requests in the system");
02859       return -1;
02860    }
02861    core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
02862    request_cc(core_instance);
02863    return 0;
02864 }

static int cc_cli_output_status ( void *  data  )  [static]

Definition at line 4178 of file ccss.c.

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

Referenced by handle_cc_status().

04179 {
04180    int *cli_fd = data;
04181    int count = ao2_container_count(cc_core_instances);
04182 
04183    if (!count) {
04184       ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
04185    } else {
04186       ast_cli(*cli_fd, "%d Call completion transactions\n", count);
04187       ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
04188       ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
04189       ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
04190    }
04191    ast_free(cli_fd);
04192    return 0;
04193 }

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

Definition at line 4145 of file ccss.c.

References AST_CC_DEVICE_MONITOR, ast_cli(), AST_LIST_NEXT, cc_service_to_string(), ast_cc_interface::device_name, ast_cc_monitor::id, ast_cc_monitor::interface, ast_cc_interface::monitor_class, ast_cc_monitor::parent_id, and ast_cc_monitor::service_offered.

Referenced by print_stats_cb().

04146 {
04147    struct ast_cc_monitor *child_monitor_iter = monitor;
04148    if (!monitor) {
04149       return;
04150    }
04151 
04152    ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
04153    if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
04154       ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
04155    }
04156    ast_cli(fd, "\n");
04157 
04158    while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
04159       if (child_monitor_iter->parent_id == monitor->id) {
04160          cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
04161       }
04162    }
04163 }

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 2989 of file ccss.c.

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

02990 {
02991    /* Recall has made progress, call agent and monitor destructor functions
02992     */
02993    manager_event(EVENT_FLAG_CC, "CCRecallComplete",
02994       "CoreID: %d\r\n"
02995       "Caller: %s\r\n",
02996       core_instance->core_id, core_instance->agent->device_name);
02997    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
02998    return 0;
02999 }

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, read]

Definition at line 2652 of file ccss.c.

References cc_core_instance::agent, 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_ref(), cc_unref(), cc_core_instance::core_id, count_agents(), kill_duplicate_offers(), and cc_core_instance::monitors.

Referenced by ast_handle_cc_control_frame().

02654 {
02655    char caller[AST_CHANNEL_NAME];
02656    struct cc_core_instance *core_instance;
02657    struct ast_cc_config_params *cc_params;
02658    long agent_count;
02659    int recall_core_id;
02660 
02661    ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
02662    cc_params = ast_channel_get_cc_config_params(caller_chan);
02663    if (!cc_params) {
02664       ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
02665          caller);
02666       return NULL;
02667    }
02668    /* First, we need to kill off other pending CC offers from caller. If the caller is going
02669     * to request a CC service, it may only be for the latest call he made.
02670     */
02671    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02672       kill_duplicate_offers(caller);
02673    }
02674 
02675    ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
02676    agent_count = count_agents(caller, recall_core_id);
02677    if (agent_count >= ast_get_cc_max_agents(cc_params)) {
02678       ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
02679       return NULL;
02680    }
02681 
02682    /* Generic agents can only have a single outstanding CC request per caller. */
02683    if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02684       ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
02685       return NULL;
02686    }
02687 
02688    /* Next, we need to create the core instance for this call */
02689    if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
02690       return NULL;
02691    }
02692 
02693    core_instance->core_id = core_id;
02694    if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
02695       cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
02696       return NULL;
02697    }
02698 
02699    core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");
02700 
02701    ao2_t_link(cc_core_instances, core_instance, "Link core instance into container");
02702 
02703    return core_instance;
02704 }

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

Definition at line 413 of file ccss.c.

References CMP_MATCH, CMP_STOP, and cc_core_instance::core_id.

Referenced by ast_cc_init().

00414 {
00415    struct cc_core_instance *core_instance1 = obj;
00416    struct cc_core_instance *core_instance2 = arg;
00417 
00418    return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
00419 }

static void cc_core_instance_destructor ( void *  data  )  [static]

Definition at line 2640 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().

02641 {
02642    struct cc_core_instance *core_instance = data;
02643    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
02644    if (core_instance->agent) {
02645       cc_unref(core_instance->agent, "Core instance is done with the agent now");
02646    }
02647    if (core_instance->monitors) {
02648       core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
02649    }
02650 }

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

Definition at line 407 of file ccss.c.

References cc_core_instance::core_id.

Referenced by ast_cc_init().

00408 {
00409    const struct cc_core_instance *core_instance = obj;
00410    return core_instance->core_id;
00411 }

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, read]

Definition at line 1982 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, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), cc_control_payload::config_params, ast_cc_interface::config_params, ast_cc_monitor::core_id, ast_cc_interface::device_name, ast_cc_monitor::dialstring, find_monitor_callbacks(), ast_cc_monitor::id, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, ast_cc_interface::monitor_type, cc_control_payload::monitor_type, ast_cc_monitor::parent_id, cc_control_payload::parent_interface_id, cc_control_payload::private_data, ast_cc_monitor::private_data, cc_control_payload::service, and ast_cc_monitor::service_offered.

Referenced by ast_handle_cc_control_frame().

01983 {
01984    struct ast_cc_interface *cc_interface;
01985    struct ast_cc_monitor *monitor;
01986    size_t device_name_len = strlen(device_name);
01987    int parent_id = cc_data->parent_interface_id;
01988 
01989    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
01990                "Allocating new ast_cc_interface"))) {
01991       return NULL;
01992    }
01993 
01994    if (!(cc_interface->config_params = ast_cc_config_params_init())) {
01995       cc_unref(cc_interface, "Failed to allocate config params, unref interface");
01996       return NULL;
01997    }
01998 
01999    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
02000       cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
02001       return NULL;
02002    }
02003 
02004    if (!(monitor->dialstring = ast_strdup(dialstring))) {
02005       cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
02006       cc_unref(cc_interface, "Failed to copy dialable name");
02007       return NULL;
02008    }
02009 
02010    if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
02011       cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
02012       cc_unref(cc_interface, "Failed to find monitor callbacks");
02013       return NULL;
02014    }
02015 
02016    strcpy(cc_interface->device_name, device_name);
02017    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
02018    monitor->parent_id = parent_id;
02019    monitor->core_id = core_id;
02020    monitor->service_offered = cc_data->service;
02021    monitor->private_data = cc_data->private_data;
02022    cc_interface->monitor_type = cc_data->monitor_type;
02023    cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
02024    monitor->interface = cc_interface;
02025    monitor->available_timer_id = -1;
02026    ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
02027    ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %d and parent %d\n",
02028          monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
02029    return monitor;
02030 }

static int cc_do_state_change ( void *  datap  )  [static]

Definition at line 3024 of file ccss.c.

References cc_core_instance::agent, args, AST_CC_AGENT_RESPONSE_FAILURE_INVALID, ast_free, ast_log_dynamic_level, ast_cc_agent::callbacks, CC_CALLER_REQUESTED, cc_state_to_string(), cc_unref(), cc_state_change_args::core_id, cc_state_change_args::core_instance, cc_core_instance::current_state, cc_state_change_args::debug, is_state_change_valid(), ast_cc_agent_callbacks::respond, cc_state_change_args::state, and state_change_funcs.

Referenced by cc_request_state_change().

03025 {
03026    struct cc_state_change_args *args = datap;
03027    struct cc_core_instance *core_instance;
03028    enum cc_state previous_state;
03029    int res;
03030 
03031    ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
03032          args->core_id, args->state, args->debug);
03033 
03034    core_instance = args->core_instance;
03035 
03036    if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
03037       ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
03038             args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
03039       if (args->state == CC_CALLER_REQUESTED) {
03040          /*
03041           * For out-of-order requests, we need to let the requester know that
03042           * we can't handle the request now.
03043           */
03044          core_instance->agent->callbacks->respond(core_instance->agent,
03045             AST_CC_AGENT_RESPONSE_FAILURE_INVALID);
03046       }
03047       ast_free(args);
03048       cc_unref(core_instance, "Unref core instance from when it was found earlier");
03049       return -1;
03050    }
03051 
03052    /* We can change to the new state now. */
03053    previous_state = core_instance->current_state;
03054    core_instance->current_state = args->state;
03055    res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);
03056 
03057    ast_free(args);
03058    cc_unref(core_instance, "Unref since state change has completed"); /* From ao2_find */
03059    return res;
03060 }

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 1780 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, and ast_cc_monitor::private_data.

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

01781 {
01782    struct ast_cc_monitor *monitor_iter;
01783    struct extension_monitor_pvt *extension_pvt;
01784    struct extension_child_dialstring *child_dialstring;
01785 
01786    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
01787       if (monitor_iter->id == parent_id) {
01788          break;
01789       }
01790    }
01791 
01792    if (!monitor_iter) {
01793       return;
01794    }
01795    extension_pvt = monitor_iter->private_data;
01796 
01797    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
01798       if (!strcmp(child_dialstring->device_name, device_name)) {
01799          child_dialstring->is_valid = is_valid;
01800          break;
01801       }
01802    }
01803 }

static void cc_extension_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1551 of file ccss.c.

References ast_free, AST_LIST_REMOVE_HEAD, and extension_monitor_pvt::child_dialstrings.

Referenced by cc_monitor_destroy().

01552 {
01553    struct extension_monitor_pvt *extension_pvt = private_data;
01554    struct extension_child_dialstring *child_dialstring;
01555 
01556    /* This shouldn't be possible, but I'm paranoid */
01557    if (!extension_pvt) {
01558       return;
01559    }
01560 
01561    while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
01562       ast_free(child_dialstring);
01563    }
01564    ast_free(extension_pvt);
01565 }

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

Definition at line 1819 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(), ast_cc_interface::device_name, extension_monitor_pvt_init(), ast_cc_monitor::id, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, ast_cc_interface::monitor_type, ast_cc_monitor::parent_id, ast_cc_monitor::private_data, and str.

Referenced by ast_cc_call_init(), and cc_interfaces_datastore_init().

01820 {
01821    struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
01822    struct ast_cc_interface *cc_interface;
01823    struct ast_cc_monitor *monitor;
01824 
01825    ast_str_set(&str, 0, "%s@%s", exten, context);
01826 
01827    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
01828                "Allocating new ast_cc_interface"))) {
01829       return NULL;
01830    }
01831 
01832    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
01833       cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
01834       return NULL;
01835    }
01836 
01837    if (!(monitor->private_data = extension_monitor_pvt_init())) {
01838       cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
01839       cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
01840    }
01841 
01842    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
01843    monitor->parent_id = parent_id;
01844    cc_interface->monitor_type = "extension";
01845    cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
01846    strcpy(cc_interface->device_name, ast_str_buffer(str));
01847    monitor->interface = cc_interface;
01848    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);
01849    return monitor;
01850 }

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 3001 of file ccss.c.

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

03002 {
03003    manager_event(EVENT_FLAG_CC, "CCFailure",
03004       "CoreID: %d\r\n"
03005       "Caller: %s\r\n"
03006       "Reason: %s\r\n",
03007       core_instance->core_id, core_instance->agent->device_name, args->debug);
03008    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
03009    return 0;
03010 }

static void cc_generic_agent_destructor ( struct ast_cc_agent agent  )  [static]

Definition at line 2623 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.

02624 {
02625    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02626 
02627    if (!agent_pvt) {
02628       /* The agent constructor probably failed. */
02629       return;
02630    }
02631 
02632    cc_generic_agent_stop_offer_timer(agent);
02633    if (agent_pvt->sub) {
02634       agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
02635    }
02636 
02637    ast_free(agent_pvt);
02638 }

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

Definition at line 2406 of file ccss.c.

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

02407 {
02408    struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
02409 
02410    if (!generic_pvt) {
02411       return -1;
02412    }
02413 
02414    generic_pvt->offer_timer_id = -1;
02415    if (chan->caller.id.number.valid && chan->caller.id.number.str) {
02416       ast_copy_string(generic_pvt->cid_num, chan->caller.id.number.str, sizeof(generic_pvt->cid_num));
02417    }
02418    if (chan->caller.id.name.valid && chan->caller.id.name.str) {
02419       ast_copy_string(generic_pvt->cid_name, chan->caller.id.name.str, sizeof(generic_pvt->cid_name));
02420    }
02421    ast_copy_string(generic_pvt->exten, S_OR(chan->macroexten, chan->exten), sizeof(generic_pvt->exten));
02422    ast_copy_string(generic_pvt->context, S_OR(chan->macrocontext, chan->context), sizeof(generic_pvt->context));
02423    agent->private_data = generic_pvt;
02424    ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
02425    return 0;
02426 }

static int cc_generic_agent_recall ( struct ast_cc_agent agent  )  [static]

Definition at line 2607 of file ccss.c.

References ast_cc_agent_caller_busy(), ast_pthread_create_detached_background, cc_generic_is_device_available(), ast_cc_agent::core_id, ast_cc_agent::device_name, and generic_recall().

02608 {
02609    pthread_t clotho;
02610    enum ast_device_state current_state = ast_device_state(agent->device_name);
02611 
02612    if (!cc_generic_is_device_available(current_state)) {
02613       /* We can't try to contact the device right now because he's not available
02614        * Let the core know he's busy.
02615        */
02616       ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
02617       return 0;
02618    }
02619    ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
02620    return 0;
02621 }

static void cc_generic_agent_respond ( struct ast_cc_agent agent,
enum ast_cc_agent_response_reason  reason 
) [static]

Definition at line 2472 of file ccss.c.

02473 {
02474    /* The generic agent doesn't have to do anything special to
02475     * acknowledge a CC request. Just return.
02476     */
02477    return;
02478 }

static int cc_generic_agent_start_monitoring ( struct ast_cc_agent agent  )  [static]

Definition at line 2529 of file ccss.c.

References ast_assert, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_EXISTS, AST_EVENT_IE_PLTYPE_STR, 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.

02530 {
02531    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02532    struct ast_str *str = ast_str_alloca(128);
02533 
02534    ast_assert(generic_pvt->sub == NULL);
02535    ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
02536       agent->device_name);
02537 
02538    if (!(generic_pvt->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
02539       generic_agent_devstate_cb, ast_str_buffer(str), agent,
02540       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->device_name,
02541       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
02542       AST_EVENT_IE_END))) {
02543       return -1;
02544    }
02545    return 0;
02546 }

static int cc_generic_agent_start_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2440 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(), ast_cc_agent::core_id, offer_timer_expire(), cc_generic_agent_pvt::offer_timer_id, and ast_cc_agent::private_data.

02441 {
02442    int when;
02443    int sched_id;
02444    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02445 
02446    ast_assert(cc_sched_thread != NULL);
02447    ast_assert(agent->cc_params != NULL);
02448 
02449    when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
02450    ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
02451          agent->core_id, when);
02452    if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
02453       return -1;
02454    }
02455    generic_pvt->offer_timer_id = sched_id;
02456    return 0;
02457 }

static int cc_generic_agent_status_request ( struct ast_cc_agent agent  )  [static]

Definition at line 2480 of file ccss.c.

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

02481 {
02482    ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
02483    return 0;
02484 }

static int cc_generic_agent_stop_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2459 of file ccss.c.

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

Referenced by cc_generic_agent_destructor().

02460 {
02461    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02462 
02463    if (generic_pvt->offer_timer_id != -1) {
02464       if (!ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id)) {
02465          cc_unref(agent, "Remove scheduler's reference to the agent");
02466       }
02467       generic_pvt->offer_timer_id = -1;
02468    }
02469    return 0;
02470 }

static int cc_generic_agent_stop_ringing ( struct ast_cc_agent agent  )  [static]

Definition at line 2486 of file ccss.c.

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

02487 {
02488    struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
02489 
02490    if (!recall_chan) {
02491       return 0;
02492    }
02493 
02494    ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
02495    return 0;
02496 }

static int cc_generic_is_device_available ( enum ast_device_state  state  )  [static]
static int cc_generic_monitor_cancel_available_timer ( struct ast_cc_monitor monitor,
int *  sched_id 
) [static]

Definition at line 1381 of file ccss.c.

References ast_assert, ast_log_dynamic_level, ast_sched_thread_del, cc_unref(), ast_cc_monitor::core_id, ast_cc_interface::device_name, and ast_cc_monitor::interface.

01382 {
01383    ast_assert(sched_id != NULL);
01384 
01385    if (*sched_id == -1) {
01386       return 0;
01387    }
01388 
01389    ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
01390          monitor->core_id, monitor->interface->device_name);
01391    if (!ast_sched_thread_del(cc_sched_thread, *sched_id)) {
01392       cc_unref(monitor, "Remove scheduler's reference to the monitor");
01393    }
01394    *sched_id = -1;
01395    return 0;
01396 }

static void cc_generic_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1398 of file ccss.c.

References ao2_t_unlink, ast_cc_monitor_callee_available(), 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_generic_is_device_available(), 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, and generic_monitor_instance::monitoring.

01399 {
01400    struct generic_monitor_pvt *gen_mon_pvt = private_data;
01401    struct generic_monitor_instance_list *generic_list;
01402    struct generic_monitor_instance *generic_instance;
01403 
01404    if (!private_data) {
01405       /* If the private data is NULL, that means that the monitor hasn't even
01406        * been created yet, but that the destructor was called. While this sort
01407        * of behavior is useful for native monitors, with a generic one, there is
01408        * nothing in particular to do.
01409        */
01410       return;
01411    }
01412 
01413    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying generic monitor %s\n",
01414          gen_mon_pvt->core_id, gen_mon_pvt->device_name);
01415 
01416    if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->device_name))) {
01417       /* If there's no generic list, that means that the monitor is being destroyed
01418        * before we actually got to request CC. Not a biggie. Same in the situation
01419        * below if the list traversal should complete without finding an entry.
01420        */
01421       ast_free((char *)gen_mon_pvt->device_name);
01422       ast_free(gen_mon_pvt);
01423       return;
01424    }
01425 
01426    AST_LIST_TRAVERSE_SAFE_BEGIN(&generic_list->list, generic_instance, next) {
01427       if (generic_instance->core_id == gen_mon_pvt->core_id) {
01428          AST_LIST_REMOVE_CURRENT(next);
01429          ast_free(generic_instance);
01430          break;
01431       }
01432    }
01433    AST_LIST_TRAVERSE_SAFE_END;
01434 
01435    if (AST_LIST_EMPTY(&generic_list->list)) {
01436       /* No more monitors with this device name exist. Time to unlink this
01437        * list from the container
01438        */
01439       ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
01440    } else {
01441       /* There are still instances for this particular device. The situation
01442        * may be that we were attempting a CC recall and a failure occurred, perhaps
01443        * on the agent side. If a failure happens here and the device being monitored
01444        * is available, then we need to signal on the first unsuspended instance that
01445        * the device is available for recall.
01446        */
01447 
01448       /* First things first. We don't even want to consider this action if
01449        * the device in question isn't available right now.
01450        */
01451       if (generic_list->fit_for_recall
01452          && cc_generic_is_device_available(generic_list->current_state)) {
01453          AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01454             if (!generic_instance->is_suspended && generic_instance->monitoring) {
01455                ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
01456                      "availability due to other instance's failure.");
01457                break;
01458             }
01459          }
01460       }
01461    }
01462    cc_unref(generic_list, "Done with generic list in generic monitor destructor");
01463    ast_free((char *)gen_mon_pvt->device_name);
01464    ast_free(gen_mon_pvt);
01465 }

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

Definition at line 1249 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_unref(), ast_cc_interface::config_params, generic_monitor_instance::core_id, ast_cc_monitor::core_id, generic_monitor_pvt::core_id, create_new_generic_list(), ast_cc_interface::device_name, generic_monitor_pvt::device_name, find_generic_monitor_instance_list(), generic_monitor_instance_list::fit_for_recall, ast_cc_monitor::interface, generic_monitor_instance_list::list, generic_monitor_instance::monitoring, ast_cc_monitor::private_data, service, and ast_cc_monitor::service_offered.

01250 {
01251    struct generic_monitor_instance_list *generic_list;
01252    struct generic_monitor_instance *generic_instance;
01253    struct generic_monitor_pvt *gen_mon_pvt;
01254    enum ast_cc_service_type service = monitor->service_offered;
01255    int when;
01256 
01257    /* First things first. Native channel drivers will have their private data allocated
01258     * at the time that they tell the core that they can offer CC. Generic is quite a bit
01259     * different, and we wait until this point to allocate our private data.
01260     */
01261    if (!(gen_mon_pvt = ast_calloc(1, sizeof(*gen_mon_pvt)))) {
01262       return -1;
01263    }
01264 
01265    if (!(gen_mon_pvt->device_name = ast_strdup(monitor->interface->device_name))) {
01266       ast_free(gen_mon_pvt);
01267       return -1;
01268    }
01269 
01270    gen_mon_pvt->core_id = monitor->core_id;
01271 
01272    monitor->private_data = gen_mon_pvt;
01273 
01274    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01275       if (!(generic_list = create_new_generic_list(monitor))) {
01276          return -1;
01277       }
01278    }
01279 
01280    if (!(generic_instance = ast_calloc(1, sizeof(*generic_instance)))) {
01281       /* The generic monitor destructor will take care of the appropriate
01282        * deallocations
01283        */
01284       cc_unref(generic_list, "Generic monitor instance failed to allocate");
01285       return -1;
01286    }
01287    generic_instance->core_id = monitor->core_id;
01288    generic_instance->monitoring = 1;
01289    AST_LIST_INSERT_TAIL(&generic_list->list, generic_instance, next);
01290    when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
01291       ast_get_ccnr_available_timer(monitor->interface->config_params);
01292 
01293    *available_timer_id = ast_sched_thread_add(cc_sched_thread, when * 1000,
01294          ast_cc_available_timer_expire, cc_ref(monitor, "Give the scheduler a monitor reference"));
01295    if (*available_timer_id == -1) {
01296       cc_unref(monitor, "Failed to schedule available timer. (monitor)");
01297       cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
01298       return -1;
01299    }
01300    /* If the new instance was created as CCNR, then that means this device is not currently
01301     * fit for recall even if it previously was.
01302     */
01303    if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
01304       generic_list->fit_for_recall = 0;
01305    }
01306    ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
01307          monitor->interface->device_name);
01308    cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
01309    return 0;
01310 }

static int cc_generic_monitor_suspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1312 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_LIST_TRAVERSE, cc_generic_is_device_available(), cc_unref(), ast_cc_monitor::core_id, generic_monitor_instance::core_id, ast_cc_interface::device_name, find_generic_monitor_instance_list(), ast_cc_monitor::interface, generic_monitor_instance::is_suspended, and generic_monitor_instance_list::list.

01313 {
01314    struct generic_monitor_instance_list *generic_list;
01315    struct generic_monitor_instance *generic_instance;
01316    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01317 
01318    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01319       return -1;
01320    }
01321 
01322    /* First we need to mark this particular monitor as being suspended. */
01323    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01324       if (generic_instance->core_id == monitor->core_id) {
01325          generic_instance->is_suspended = 1;
01326          break;
01327       }
01328    }
01329 
01330    /* If the device being suspended is currently in use, then we don't need to
01331     * take any further actions
01332     */
01333    if (!cc_generic_is_device_available(state)) {
01334       cc_unref(generic_list, "Device is in use. Nothing to do. Unref generic list.");
01335       return 0;
01336    }
01337 
01338    /* If the device is not in use, though, then it may be possible to report the
01339     * device's availability using a different monitor which is monitoring the
01340     * same device
01341     */
01342 
01343    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01344       if (!generic_instance->is_suspended) {
01345          ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01346          break;
01347       }
01348    }
01349    cc_unref(generic_list, "Done with generic list in suspend callback");
01350    return 0;
01351 }

static int cc_generic_monitor_unsuspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1353 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_LIST_TRAVERSE, cc_generic_is_device_available(), cc_unref(), generic_monitor_instance::core_id, ast_cc_monitor::core_id, ast_cc_interface::device_name, find_generic_monitor_instance_list(), ast_cc_monitor::interface, generic_monitor_instance::is_suspended, generic_monitor_instance_list::list, and generic_monitor_instance::monitoring.

01354 {
01355    struct generic_monitor_instance *generic_instance;
01356    struct generic_monitor_instance_list *generic_list = find_generic_monitor_instance_list(monitor->interface->device_name);
01357    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01358 
01359    if (!generic_list) {
01360       return -1;
01361    }
01362    /* If the device is currently available, we can immediately announce
01363     * its availability
01364     */
01365    if (cc_generic_is_device_available(state)) {
01366       ast_cc_monitor_callee_available(monitor->core_id, "Generic monitored party has become available");
01367    }
01368 
01369    /* In addition, we need to mark this generic_monitor_instance as not being suspended anymore */
01370    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01371       if (generic_instance->core_id == monitor->core_id) {
01372          generic_instance->is_suspended = 0;
01373          generic_instance->monitoring = 1;
01374          break;
01375       }
01376    }
01377    cc_unref(generic_list, "Done with generic list in cc_generic_monitor_unsuspend");
01378    return 0;
01379 }

static void cc_interface_destroy ( void *  data  )  [static]

Definition at line 1467 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().

01468 {
01469    struct ast_cc_interface *interface = data;
01470    ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
01471    ast_cc_config_params_destroy(interface->config_params);
01472 }

static void cc_interface_tree_destroy ( void *  data  )  [static]

Definition at line 1588 of file ccss.c.

References AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, ast_cc_monitor_callbacks::cancel_available_timer, cc_unref(), and monitor.

Referenced by cc_interfaces_datastore_init().

01589 {
01590    struct cc_monitor_tree *cc_interface_tree = data;
01591    struct ast_cc_monitor *monitor;
01592    while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
01593       if (monitor->callbacks) {
01594          monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
01595       }
01596       cc_unref(monitor, "Destroying all monitors");
01597    }
01598    AST_LIST_HEAD_DESTROY(cc_interface_tree);
01599 }

static int cc_interfaces_datastore_init ( struct ast_channel chan  )  [static]

Definition at line 1868 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_cc_monitor::core_id, dialed_cc_interfaces::core_id, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dialed_cc_interfaces::dial_parent_id, ast_channel::exten, ast_cc_monitor::id, ast_datastore::inheritance, dialed_cc_interfaces::interface_tree, dialed_cc_interfaces::is_original_caller, ast_channel::macrocontext, ast_channel::macroexten, monitor, and S_OR.

Referenced by ast_cc_call_init().

01868                                                                   {
01869    struct dialed_cc_interfaces *interfaces;
01870    struct ast_cc_monitor *monitor;
01871    struct ast_datastore *dial_cc_datastore;
01872 
01873    /*XXX This may be a bit controversial. In an attempt to not allocate
01874     * extra resources, I make sure that a future request will be within
01875     * limits. The problem here is that it is reasonable to think that
01876     * even if we're not within the limits at this point, we may be by
01877     * the time the requestor will have made his request. This may be
01878     * deleted at some point.
01879     */
01880    if (!ast_cc_request_is_within_limits()) {
01881       return 0;
01882    }
01883 
01884    if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
01885       return -1;
01886    }
01887 
01888    if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten), S_OR(chan->macrocontext, chan->context), 0))) {
01889       ast_free(interfaces);
01890       return -1;
01891    }
01892 
01893    if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
01894       cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
01895       ast_free(interfaces);
01896       return -1;
01897    }
01898 
01899    if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
01900                "Allocate monitor tree"))) {
01901       ast_datastore_free(dial_cc_datastore);
01902       cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
01903       ast_free(interfaces);
01904       return -1;
01905    }
01906 
01907    /* Finally, all that allocation is done... */
01908    AST_LIST_HEAD_INIT(interfaces->interface_tree);
01909    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
01910    cc_ref(monitor, "List's reference to extension monitor");
01911    dial_cc_datastore->data = interfaces;
01912    dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01913    interfaces->dial_parent_id = monitor->id;
01914    interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
01915    interfaces->is_original_caller = 1;
01916    ast_channel_lock(chan);
01917    ast_channel_datastore_add(chan, dial_cc_datastore);
01918    ast_channel_unlock(chan);
01919    cc_unref(monitor, "Unreffing allocation's reference");
01920    return 0;
01921 }

static void cc_monitor_destroy ( void *  data  )  [static]

Definition at line 1567 of file ccss.c.

References AST_CC_EXTENSION_MONITOR, ast_free, ast_log_dynamic_level, ast_cc_monitor::callbacks, cc_extension_monitor_destructor(), cc_unref(), ast_cc_monitor::core_id, ast_cc_monitor_callbacks::destructor, ast_cc_interface::device_name, ast_cc_monitor::dialstring, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, and ast_cc_monitor::private_data.

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

01568 {
01569    struct ast_cc_monitor *monitor = data;
01570    /* During the monitor creation process, it is possible for this
01571     * function to be called prior to when callbacks are assigned
01572     * to the monitor. Also, extension monitors do not have callbacks
01573     * assigned to them, so we wouldn't want to segfault when we try
01574     * to destroy one of them.
01575     */
01576    ast_log_dynamic_level(cc_logger_level, "Core %d: Calling destructor for monitor %s\n",
01577          monitor->core_id, monitor->interface->device_name);
01578    if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
01579       cc_extension_monitor_destructor(monitor->private_data);
01580    }
01581    if (monitor->callbacks) {
01582       monitor->callbacks->destructor(monitor->private_data);
01583    }
01584    cc_unref(monitor->interface, "Unreffing tree's reference to interface");
01585    ast_free(monitor->dialstring);
01586 }

static int cc_monitor_failed ( void *  data  )  [static]

Definition at line 3630 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, and ast_cc_monitor::parent_id.

Referenced by ast_cc_monitor_failed().

03631 {
03632    struct ast_cc_monitor_failure_data *failure_data = data;
03633    struct cc_core_instance *core_instance;
03634    struct ast_cc_monitor *monitor_iter;
03635 
03636    core_instance = find_cc_core_instance(failure_data->core_id);
03637    if (!core_instance) {
03638       /* Core instance no longer exists or invalid core_id. */
03639       ast_log_dynamic_level(cc_logger_level,
03640          "Core %d: Could not find core instance for device %s '%s'\n",
03641          failure_data->core_id, failure_data->device_name, failure_data->debug);
03642       ast_free((char *) failure_data->device_name);
03643       ast_free((char *) failure_data->debug);
03644       ast_free(failure_data);
03645       return -1;
03646    }
03647 
03648    AST_LIST_LOCK(core_instance->monitors);
03649    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
03650       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
03651          if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
03652             AST_LIST_REMOVE_CURRENT(next);
03653             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
03654                   monitor_iter->interface->device_name, 1);
03655             monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
03656             manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
03657                "CoreID: %d\r\n"
03658                "Callee: %s\r\n",
03659                monitor_iter->core_id, monitor_iter->interface->device_name);
03660             cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
03661          }
03662       }
03663    }
03664    AST_LIST_TRAVERSE_SAFE_END;
03665 
03666    if (!has_device_monitors(core_instance)) {
03667       ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
03668    }
03669    AST_LIST_UNLOCK(core_instance->monitors);
03670    cc_unref(core_instance, "Finished with core_instance in cc_monitor_failed\n");
03671 
03672    ast_free((char *) failure_data->device_name);
03673    ast_free((char *) failure_data->debug);
03674    ast_free(failure_data);
03675    return 0;
03676 }

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

Definition at line 3474 of file ccss.c.

References CC_CALLER_OFFERED, and cc_request_state_change().

Referenced by ast_cc_offer().

03475 {
03476    va_list ap;
03477    int res;
03478 
03479    va_start(ap, debug);
03480    res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
03481    va_end(ap);
03482    return res;
03483 }

static int cc_party_b_free ( void *  data  )  [static]

Definition at line 3776 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().

03777 {
03778    struct cc_core_instance *core_instance = data;
03779    int res = 0;
03780 
03781    if (core_instance->agent->callbacks->party_b_free) {
03782       res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
03783    }
03784    cc_unref(core_instance, "Party B free finished. Unref core_instance");
03785    return res;
03786 }

static void cc_recall_ds_destroy ( void *  data  )  [static]

Definition at line 3126 of file ccss.c.

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

03127 {
03128    struct cc_recall_ds_data *recall_data = data;
03129    recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
03130    ast_free(recall_data);
03131 }

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

Definition at line 3112 of file ccss.c.

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

03113 {
03114    struct cc_recall_ds_data *old_data = data;
03115    struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));
03116 
03117    if (!new_data) {
03118       return NULL;
03119    }
03120    new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
03121    new_data->core_id = old_data->core_id;
03122    new_data->nested = 1;
03123    return new_data;
03124 }

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 2977 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.

02978 {
02979    /* Both caller and callee are available, call agent's recall callback
02980     */
02981    cancel_available_timer(core_instance);
02982    manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
02983       "CoreID: %d\r\n"
02984       "Caller: %s\r\n",
02985       core_instance->core_id, core_instance->agent->device_name);
02986    return 0;
02987 }

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

Definition at line 3062 of file ccss.c.

References args, ast_calloc, ast_free, ast_log_dynamic_level, ast_taskprocessor_push(), cc_do_state_change(), cc_unref(), cc_state_change_args::core_id, cc_state_change_args::core_instance, cc_state_change_args::debug, dummy(), find_cc_core_instance(), and cc_state_change_args::state.

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().

03063 {
03064    int res;
03065    int debuglen;
03066    char dummy[1];
03067    va_list aq;
03068    struct cc_core_instance *core_instance;
03069    struct cc_state_change_args *args;
03070    /* This initial call to vsnprintf is simply to find what the
03071     * size of the string needs to be
03072     */
03073    va_copy(aq, ap);
03074    /* We add 1 to the result since vsnprintf's return does not
03075     * include the terminating null byte
03076     */
03077    debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
03078    va_end(aq);
03079 
03080    if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
03081       return -1;
03082    }
03083 
03084    core_instance = find_cc_core_instance(core_id);
03085    if (!core_instance) {
03086       ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n",
03087          core_id);
03088       ast_free(args);
03089       return -1;
03090    }
03091 
03092    args->core_instance = core_instance;
03093    args->state = state;
03094    args->core_id = core_id;
03095    vsnprintf(args->debug, debuglen, debug, ap);
03096 
03097    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
03098    if (res) {
03099       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03100       ast_free(args);
03101    }
03102    return res;
03103 }

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

Definition at line 402 of file ccss.c.

References cc_service_to_string_map.

Referenced by ast_handle_cc_control_frame(), and cc_cli_print_monitor_stats().

00403 {
00404    return cc_service_to_string_map[service].service_string;
00405 }

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

Definition at line 397 of file ccss.c.

References cc_state_to_string_map.

Referenced by cc_do_state_change(), and print_stats_cb().

00398 {
00399    return cc_state_to_string_map[state].state_string;
00400 }

static int cc_status_request ( void *  data  )  [static]

Definition at line 3713 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().

03714 {
03715    struct cc_core_instance *core_instance= data;
03716    int res;
03717 
03718    res = core_instance->agent->callbacks->status_request(core_instance->agent);
03719    cc_unref(core_instance, "Status request finished. Unref core instance");
03720    return res;
03721 }

static int cc_status_response ( void *  data  )  [static]

Definition at line 3809 of file ccss.c.

References args, AST_CC_DEVICE_MONITOR, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_cc_monitor::callbacks, cc_unref(), cc_status_response_args::core_instance, cc_status_response_args::devstate, ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, and ast_cc_monitor_callbacks::status_response.

Referenced by ast_cc_agent_status_response().

03810 {
03811    struct cc_status_response_args *args = data;
03812    struct cc_core_instance *core_instance = args->core_instance;
03813    struct ast_cc_monitor *monitor_iter;
03814    enum ast_device_state devstate = args->devstate;
03815 
03816    ast_free(args);
03817 
03818    AST_LIST_LOCK(core_instance->monitors);
03819    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03820       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
03821             monitor_iter->callbacks->status_response) {
03822          monitor_iter->callbacks->status_response(monitor_iter, devstate);
03823       }
03824    }
03825    AST_LIST_UNLOCK(core_instance->monitors);
03826    cc_unref(core_instance, "Status response finished. Unref core instance");
03827    return 0;
03828 }

static int cc_stop_ringing ( void *  data  )  [static]

Definition at line 3739 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().

03740 {
03741    struct cc_core_instance *core_instance = data;
03742    int res = 0;
03743 
03744    if (core_instance->agent->callbacks->stop_ringing) {
03745       res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
03746    }
03747    /* If an agent is being asked to stop ringing, then he needs to be prepared if for
03748     * whatever reason he needs to be called back again. The proper state to be in to
03749     * detect such a circumstance is the CC_ACTIVE state.
03750     *
03751     * We get to this state using the slightly unintuitive method of calling
03752     * ast_cc_monitor_request_acked because it gets us to the proper state.
03753     */
03754    ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
03755          core_instance->agent->device_name);
03756    cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
03757    return res;
03758 }

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

Definition at line 3292 of file ccss.c.

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

Referenced by build_cc_interfaces_chanvar().

03293 {
03294    char dialstring_search[AST_CHANNEL_NAME];
03295 
03296    if (ast_strlen_zero(dialstring)) {
03297       /* No dialstring to append. */
03298       return;
03299    }
03300    snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
03301    if (strstr(ast_str_buffer(*str), dialstring_search)) {
03302       return;
03303    }
03304    ast_str_append(str, 0, "%s", dialstring_search);
03305 }

static void* cc_unref ( void *  obj,
const char *  debug 
) [inline, static]
static int cccancel_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 4045 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_log_dynamic_level, ast_cc_agent::callbacks, cc_unref(), cc_core_instance::core_id, LOG_WARNING, match_agent(), MATCH_REQUEST, pbx_builtin_setvar_helper(), and ast_cc_agent_callbacks::type.

Referenced by ast_cc_init().

04046 {
04047    struct cc_core_instance *core_instance;
04048    char device_name[AST_CHANNEL_NAME];
04049    unsigned long match_flags;
04050    int res;
04051 
04052    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04053 
04054    match_flags = MATCH_REQUEST;
04055    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
04056       ast_log_dynamic_level(cc_logger_level, "Cannot find CC transaction to cancel for caller %s\n", device_name);
04057       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04058       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NO_CORE_INSTANCE");
04059       return 0;
04060    }
04061 
04062    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04063       ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
04064       cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04065       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04066       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NOT_GENERIC");
04067       return 0;
04068    }
04069    res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
04070          core_instance->core_id, device_name);
04071    cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04072    pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", res ? "FAIL" : "SUCCESS");
04073    if (res) {
04074       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "UNSPECIFIED");
04075    }
04076    return 0;
04077 }

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

Definition at line 3994 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_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().

03995 {
03996    struct cc_core_instance *core_instance;
03997    char device_name[AST_CHANNEL_NAME];
03998    unsigned long match_flags;
03999    int res;
04000 
04001    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04002 
04003    match_flags = MATCH_NO_REQUEST;
04004    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionRequest"))) {
04005       ast_log_dynamic_level(cc_logger_level, "Couldn't find a core instance for caller %s\n", device_name);
04006       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04007       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NO_CORE_INSTANCE");
04008       return 0;
04009    }
04010 
04011    ast_log_dynamic_level(cc_logger_level, "Core %d: Found core_instance for caller %s\n",
04012          core_instance->core_id, device_name);
04013 
04014    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04015       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest is only for generic agent types.\n",
04016             core_instance->core_id);
04017       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04018       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NOT_GENERIC");
04019       cc_unref(core_instance, "Unref core_instance since CallCompletionRequest was called with native agent");
04020       return 0;
04021    }
04022 
04023    if (!ast_cc_request_is_within_limits()) {
04024       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest failed. Too many requests in the system\n",
04025             core_instance->core_id);
04026       ast_cc_failed(core_instance->core_id, "Too many CC requests\n");
04027       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04028       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "TOO_MANY_REQUESTS");
04029       cc_unref(core_instance, "Unref core_instance since too many CC requests");
04030       return 0;
04031    }
04032 
04033    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);
04034    pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", res ? "FAIL" : "SUCCESS");
04035    if (res) {
04036       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "UNSPECIFIED");
04037    }
04038 
04039    cc_unref(core_instance, "Done with CallCompletionRequest");
04040    return 0;
04041 }

static void check_callback_sanity ( const struct ast_cc_agent_callbacks callbacks  )  [static]
static char* complete_core_id ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 4239 of file ccss.c.

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

Referenced by handle_cc_kill().

04240 {
04241    int which = 0;
04242    int wordlen = strlen(word);
04243    char *ret = NULL;
04244    struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
04245    struct cc_core_instance *core_instance;
04246 
04247    for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
04248          cc_unref(core_instance, "CLI tab completion iteration")) {
04249       char core_id_str[20];
04250       snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
04251       if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
04252          ret = ast_strdup(core_id_str);
04253          cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
04254          break;
04255       }
04256    }
04257    ao2_iterator_destroy(&core_iter);
04258 
04259    return ret;
04260 }

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

Definition at line 2243 of file ccss.c.

References ao2_t_callback_data, ast_log_dynamic_level, 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().

02244 {
02245    struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
02246 
02247    ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
02248    ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
02249    return data.count;
02250 }

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

Definition at line 520 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().

00521 {
00522    struct cc_core_instance *core_instance = obj;
00523    const char *name = arg;
00524    struct count_agents_cb_data *cb_data = data;
00525 
00526    if (cb_data->core_id_exception == core_instance->core_id) {
00527       ast_log_dynamic_level(cc_logger_level, "Found agent with core_id %d but not counting it toward total\n", core_instance->core_id);
00528       return 0;
00529    }
00530 
00531    if (core_instance->current_state >= CC_CALLER_REQUESTED && !strcmp(core_instance->agent->device_name, name)) {
00532       cb_data->count++;
00533    }
00534    return 0;
00535 }

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

Definition at line 4085 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, and cc_core_instance::monitors.

Referenced by ast_cc_monitor_count().

04086 {
04087    struct cc_core_instance *core_instance = obj;
04088    struct count_monitors_cb_data *cb_data = arg;
04089    const char *device_name = cb_data->device_name;
04090    const char *monitor_type = cb_data->monitor_type;
04091    struct ast_cc_monitor *monitor_iter;
04092 
04093    AST_LIST_LOCK(core_instance->monitors);
04094    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
04095       if (!strcmp(monitor_iter->interface->device_name, device_name) &&
04096             !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
04097          cb_data->count++;
04098          break;
04099       }
04100    }
04101    AST_LIST_UNLOCK(core_instance->monitors);
04102    return 0;
04103 }

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

Definition at line 1131 of file ccss.c.

References ao2_t_alloc, ao2_t_link, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_EXISTS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_STATE, ast_event_subscribe(), ast_strdup, ast_tech_to_upper(), cc_unref(), generic_monitor_instance_list::current_state, generic_monitor_instance_list::device_name, ast_cc_interface::device_name, generic_monitor_devstate_cb(), generic_monitor_instance_list_destructor(), generic_monitors, ast_cc_monitor::interface, and generic_monitor_instance_list::sub.

Referenced by cc_generic_monitor_request_cc().

01132 {
01133    struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
01134          generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
01135    char * device_name;
01136 
01137    if (!generic_list) {
01138       return NULL;
01139    }
01140 
01141    if (!(device_name = ast_strdup(monitor->interface->device_name))) {
01142       cc_unref(generic_list, "Failed to strdup the monitor's device name");
01143       return NULL;
01144    }
01145    ast_tech_to_upper(device_name);
01146    generic_list->device_name = device_name;
01147 
01148    if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
01149       generic_monitor_devstate_cb, "Requesting CC", NULL,
01150       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, monitor->interface->device_name,
01151       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
01152       AST_EVENT_IE_END))) {
01153       cc_unref(generic_list, "Failed to subscribe to device state");
01154       return NULL;
01155    }
01156    generic_list->current_state = ast_device_state(monitor->interface->device_name);
01157    ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
01158    return generic_list;
01159 }

static void dialed_cc_interfaces_destroy ( void *  data  )  [static]

Definition at line 1674 of file ccss.c.

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

01675 {
01676    struct dialed_cc_interfaces *cc_interfaces = data;
01677    cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
01678    ast_free(cc_interfaces);
01679 }

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

Definition at line 1694 of file ccss.c.

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

01695 {
01696    struct dialed_cc_interfaces *old_cc_interfaces = data;
01697    struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
01698    if (!new_cc_interfaces) {
01699       return NULL;
01700    }
01701    new_cc_interfaces->ignore = old_cc_interfaces->ignore;
01702    new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
01703    new_cc_interfaces->is_original_caller = 0;
01704    cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
01705    new_cc_interfaces->core_id = old_cc_interfaces->core_id;
01706    new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
01707    return new_cc_interfaces;
01708 }

static struct extension_monitor_pvt* extension_monitor_pvt_init ( void   )  [static, read]

Definition at line 1725 of file ccss.c.

References ast_calloc, AST_LIST_HEAD_INIT_NOLOCK, and extension_monitor_pvt::child_dialstrings.

Referenced by cc_extension_monitor_init().

01726 {
01727    struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
01728    if (!ext_pvt) {
01729       return NULL;
01730    }
01731    AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
01732    return ext_pvt;
01733 }

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

Definition at line 980 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().

00981 {
00982    struct cc_agent_backend *backend;
00983    const struct ast_cc_agent_callbacks *callbacks = NULL;
00984    struct ast_cc_config_params *cc_params;
00985    char type[32];
00986 
00987    cc_params = ast_channel_get_cc_config_params(chan);
00988    if (!cc_params) {
00989       return NULL;
00990    }
00991    switch (ast_get_cc_agent_policy(cc_params)) {
00992    case AST_CC_AGENT_GENERIC:
00993       ast_copy_string(type, "generic", sizeof(type));
00994       break;
00995    case AST_CC_AGENT_NATIVE:
00996       ast_channel_get_cc_agent_type(chan, type, sizeof(type));
00997       break;
00998    default:
00999       ast_log_dynamic_level(cc_logger_level, "Not returning agent callbacks since this channel is configured not to have a CC agent\n");
01000       return NULL;
01001    }
01002 
01003    AST_RWLIST_RDLOCK(&cc_agent_backends);
01004    AST_RWLIST_TRAVERSE(&cc_agent_backends, backend, next) {
01005       if (!strcmp(backend->callbacks->type, type)) {
01006          ast_log_dynamic_level(cc_logger_level, "Returning agent backend %s\n", backend->callbacks->type);
01007          callbacks = backend->callbacks;
01008          break;
01009       }
01010    }
01011    AST_RWLIST_UNLOCK(&cc_agent_backends);
01012    return callbacks;
01013 }

static struct cc_core_instance* find_cc_core_instance ( const int  core_id  )  [static, read]
static struct generic_monitor_instance_list* find_generic_monitor_instance_list ( const char *const   device_name  )  [static, read]

Definition at line 1108 of file ccss.c.

References ao2_t_find, ast_strdupa, ast_tech_to_upper(), 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().

01109 {
01110    struct generic_monitor_instance_list finder = {0};
01111    char *uppertech = ast_strdupa(device_name);
01112    ast_tech_to_upper(uppertech);
01113    finder.device_name = uppertech;
01114 
01115    return ao2_t_find(generic_monitors, &finder, OBJ_POINTER, "Finding generic monitor instance list");
01116 }

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

Definition at line 911 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().

00912 {
00913    struct cc_monitor_backend *backend;
00914    const struct ast_cc_monitor_callbacks *callbacks = NULL;
00915 
00916    AST_RWLIST_RDLOCK(&cc_monitor_backends);
00917    AST_RWLIST_TRAVERSE(&cc_monitor_backends, backend, next) {
00918       if (!strcmp(backend->callbacks->type, type)) {
00919          ast_log_dynamic_level(cc_logger_level, "Returning monitor backend %s\n", backend->callbacks->type);
00920          callbacks = backend->callbacks;
00921          break;
00922       }
00923    }
00924    AST_RWLIST_UNLOCK(&cc_monitor_backends);
00925    return callbacks;
00926 }

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

Definition at line 2510 of file ccss.c.

References ast_cc_agent_caller_available(), ast_event_get_ie_uint(), AST_EVENT_IE_STATE, ast_taskprocessor_push(), cc_generic_is_device_available(), 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().

02511 {
02512    struct ast_cc_agent *agent = userdata;
02513    enum ast_device_state new_state;
02514 
02515    new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
02516    if (!cc_generic_is_device_available(new_state)) {
02517       /* Not interested in this new state of the device.  It is still busy. */
02518       return;
02519    }
02520 
02521    /* We can't unsubscribe from device state events here because it causes a deadlock */
02522    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
02523          cc_ref(agent, "ref agent for device state unsubscription"))) {
02524       cc_unref(agent, "Unref agent unsubscribing from devstate failed");
02525    }
02526    ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
02527 }

static int generic_agent_devstate_unsubscribe ( void *  data  )  [static]

Definition at line 2498 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().

02499 {
02500    struct ast_cc_agent *agent = data;
02501    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02502 
02503    if (generic_pvt->sub != NULL) {
02504       generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
02505    }
02506    cc_unref(agent, "Done unsubscribing from devstate");
02507    return 0;
02508 }

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

Definition at line 1100 of file ccss.c.

References CMP_MATCH, CMP_STOP, and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01101 {
01102    const struct generic_monitor_instance_list *generic_list1 = obj;
01103    const struct generic_monitor_instance_list *generic_list2 = arg;
01104 
01105    return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
01106 }

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

Definition at line 1214 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(), generic_tp_cb_data::device_name, generic_monitor_devstate_tp_cb(), and generic_tp_cb_data::new_state.

Referenced by create_new_generic_list().

01215 {
01216    /* Wow, it's cool that we've picked up on a state change, but we really want
01217     * the actual work to be done in the core's taskprocessor execution thread
01218     * so that all monitor operations can be serialized. Locks?! We don't need
01219     * no steenkin' locks!
01220     */
01221    struct generic_tp_cb_data *gtcd = ast_calloc(1, sizeof(*gtcd));
01222 
01223    if (!gtcd) {
01224       return;
01225    }
01226 
01227    if (!(gtcd->device_name = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE)))) {
01228       ast_free(gtcd);
01229       return;
01230    }
01231    gtcd->new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01232 
01233    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, gtcd)) {
01234       ast_free((char *)gtcd->device_name);
01235       ast_free(gtcd);
01236    }
01237 }

static int generic_monitor_devstate_tp_cb ( void *  data  )  [static]

Definition at line 1166 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_UNAVAILABLE, ast_free, AST_LIST_TRAVERSE, cc_generic_is_device_available(), 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, and generic_tp_cb_data::new_state.

Referenced by generic_monitor_devstate_cb().

01167 {
01168    struct generic_tp_cb_data *gtcd = data;
01169    enum ast_device_state new_state = gtcd->new_state;
01170    enum ast_device_state previous_state = gtcd->new_state;
01171    const char *monitor_name = gtcd->device_name;
01172    struct generic_monitor_instance_list *generic_list;
01173    struct generic_monitor_instance *generic_instance;
01174 
01175    if (!(generic_list = find_generic_monitor_instance_list(monitor_name))) {
01176       /* The most likely cause for this is that we destroyed the monitor in the
01177        * time between subscribing to its device state and the time this executes.
01178        * Not really a big deal.
01179        */
01180       ast_free((char *) gtcd->device_name);
01181       ast_free(gtcd);
01182       return 0;
01183    }
01184 
01185    if (generic_list->current_state == new_state) {
01186       /* The device state hasn't actually changed, so we don't really care */
01187       cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01188       ast_free((char *) gtcd->device_name);
01189       ast_free(gtcd);
01190       return 0;
01191    }
01192 
01193    previous_state = generic_list->current_state;
01194    generic_list->current_state = new_state;
01195 
01196    if (cc_generic_is_device_available(new_state) &&
01197          (previous_state == AST_DEVICE_INUSE || previous_state == AST_DEVICE_UNAVAILABLE ||
01198           previous_state == AST_DEVICE_BUSY)) {
01199       AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01200          if (!generic_instance->is_suspended && generic_instance->monitoring) {
01201             generic_instance->monitoring = 0;
01202             generic_list->fit_for_recall = 1;
01203             ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01204             break;
01205          }
01206       }
01207    }
01208    cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01209    ast_free((char *) gtcd->device_name);
01210    ast_free(gtcd);
01211    return 0;
01212 }

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

Definition at line 1094 of file ccss.c.

References ast_str_hash(), and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01095 {
01096    const struct generic_monitor_instance_list *generic_list = obj;
01097    return ast_str_hash(generic_list->device_name);
01098 }

static void generic_monitor_instance_list_destructor ( void *  obj  )  [static]

Definition at line 1118 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, and generic_monitor_instance_list::sub.

Referenced by create_new_generic_list().

01119 {
01120    struct generic_monitor_instance_list *generic_list = obj;
01121    struct generic_monitor_instance *generic_instance;
01122 
01123    generic_list->sub = ast_event_unsubscribe(generic_list->sub);
01124    while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
01125       ast_free(generic_instance);
01126    }
01127    ast_free((char *)generic_list->device_name);
01128 }

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

Definition at line 2548 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, pbx_builtin_setvar_helper(), ast_channel::priority, ast_cc_agent::private_data, and S_OR.

Referenced by cc_generic_agent_recall().

02549 {
02550    struct ast_cc_agent *agent = data;
02551    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02552    const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
02553    const char *tech;
02554    char *target;
02555    int reason;
02556    struct ast_channel *chan;
02557    const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
02558    unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
02559 
02560    tech = interface;
02561    if ((target = strchr(interface, '/'))) {
02562       *target++ = '\0';
02563    }
02564    if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
02565       /* Hmm, no channel. Sucks for you, bud.
02566        */
02567       ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
02568             agent->core_id, agent->device_name, reason);
02569       ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
02570       return NULL;
02571    }
02572    
02573    /* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
02574     * This will be a common task for all recall functions. If it were possible, I'd have
02575     * the core do it automatically, but alas I cannot. Instead, I will provide a public
02576     * function to do so.
02577     */
02578    ast_setup_cc_recall_datastore(chan, agent->core_id);
02579    ast_cc_agent_set_interfaces_chanvar(chan);
02580 
02581    ast_copy_string(chan->exten, generic_pvt->exten, sizeof(chan->exten));
02582    ast_copy_string(chan->context, generic_pvt->context, sizeof(chan->context));
02583    chan->priority = 1;
02584 
02585    pbx_builtin_setvar_helper(chan, "CC_EXTEN", generic_pvt->exten);
02586    pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);
02587 
02588    if (!ast_strlen_zero(callback_macro)) {
02589       ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
02590             agent->core_id, agent->device_name);
02591       if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
02592          ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
02593          ast_hangup(chan);
02594          return NULL;
02595       }
02596    }
02597    if (ast_pbx_start(chan)) {
02598       ast_cc_failed(agent->core_id, "PBX failed to start for %s.", agent->device_name);
02599       ast_hangup(chan);
02600       return NULL;
02601    }
02602    ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling",
02603       agent->device_name);
02604    return NULL;
02605 }

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

Definition at line 4262 of file ccss.c.

References ao2_t_callback, ast_cli_args::argc, ast_cli_args::argv, ast_cli_complete(), 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.

04263 {
04264    static const char * const option[] = { "core", "all", NULL };
04265 
04266    switch (cmd) {
04267    case CLI_INIT:
04268       e->command = "cc cancel";
04269       e->usage =
04270          "Usage: cc cancel can be used in two ways.\n"
04271          "       1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
04272          "          core ID equal to the specified core ID.\n"
04273          "       2. 'cc cancel all' will cancel all active CC transactions.\n";
04274       return NULL;
04275    case CLI_GENERATE:
04276       if (a->pos == 2) {
04277          return ast_cli_complete(a->word, option, a->n);
04278       }
04279       if (a->pos == 3) {
04280          return complete_core_id(a->line, a->word, a->pos, a->n);
04281       }
04282       return NULL;
04283    }
04284 
04285    if (a->argc == 4) {
04286       int core_id;
04287       char *endptr;
04288       if (strcasecmp(a->argv[2], "core")) {
04289          return CLI_SHOWUSAGE;
04290       }
04291       core_id = strtol(a->argv[3], &endptr, 10);
04292       if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
04293          return CLI_SHOWUSAGE;
04294       }
04295       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, &core_id, "CLI Killing Core Id");
04296    } else if (a->argc == 3) {
04297       if (strcasecmp(a->argv[2], "all")) {
04298          return CLI_SHOWUSAGE;
04299       }
04300       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, NULL, "CLI Killing all CC cores");
04301    } else {
04302       return CLI_SHOWUSAGE;
04303    }
04304 
04305    return CLI_SUCCESS;
04306 }

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

Definition at line 4195 of file ccss.c.

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

04196 {
04197    int *cli_fd;
04198 
04199    switch (cmd) {
04200    case CLI_INIT:
04201       e->command = "cc report status";
04202       e->usage =
04203          "Usage: cc report status\n"
04204          "       Report the current status of any ongoing CC transactions\n";
04205       return NULL;
04206    case CLI_GENERATE:
04207       return NULL;
04208    }
04209 
04210    if (a->argc != 3) {
04211       return CLI_SHOWUSAGE;
04212    }
04213 
04214    cli_fd = ast_malloc(sizeof(*cli_fd));
04215    if (!cli_fd) {
04216       return CLI_FAILURE;
04217    }
04218 
04219    *cli_fd = a->fd;
04220 
04221    if (ast_taskprocessor_push(cc_core_taskprocessor, cc_cli_output_status, cli_fd)) {
04222       ast_free(cli_fd);
04223       return CLI_FAILURE;
04224    }
04225    return CLI_SUCCESS;
04226 }

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 2809 of file ccss.c.

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

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

02810 {
02811    struct ast_cc_monitor *iter;
02812    int res = 0;
02813 
02814    AST_LIST_TRAVERSE(core_instance->monitors, iter, next) {
02815       if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02816          res = 1;
02817          break;
02818       }
02819    }
02820 
02821    return res;
02822 }

static void initialize_cc_max_requests ( void   )  [static]

Definition at line 4114 of file ccss.c.

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

Referenced by ast_cc_init().

04115 {
04116    struct ast_config *cc_config;
04117    const char *cc_max_requests_str;
04118    struct ast_flags config_flags = {0,};
04119    char *endptr;
04120 
04121    cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
04122    if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
04123       ast_log(LOG_WARNING, "Could not find valid ccss.conf file. Using cc_max_requests default\n");
04124       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04125       return;
04126    }
04127 
04128    if (!(cc_max_requests_str = ast_variable_retrieve(cc_config, "general", "cc_max_requests"))) {
04129       ast_config_destroy(cc_config);
04130       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04131       return;
04132    }
04133 
04134    global_cc_max_requests = strtol(cc_max_requests_str, &endptr, 10);
04135 
04136    if (!ast_strlen_zero(endptr)) {
04137       ast_log(LOG_WARNING, "Invalid input given for cc_max_requests. Using default\n");
04138       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04139    }
04140 
04141    ast_config_destroy(cc_config);
04142    return;
04143 }

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 2713 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().

02714 {
02715    int is_valid = 0;
02716    switch (new_state) {
02717    case CC_AVAILABLE:
02718       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
02719             agent->core_id, new_state);
02720       break;
02721    case CC_CALLER_OFFERED:
02722       if (current_state == CC_AVAILABLE) {
02723          is_valid = 1;
02724       }
02725       break;
02726    case CC_CALLER_REQUESTED:
02727       if (current_state == CC_CALLER_OFFERED ||
02728             (current_state == CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
02729          is_valid = 1;
02730       }
02731       break;
02732    case CC_ACTIVE:
02733       if (current_state == CC_CALLER_REQUESTED || current_state == CC_CALLER_BUSY) {
02734          is_valid = 1;
02735       }
02736       break;
02737    case CC_CALLEE_READY:
02738       if (current_state == CC_ACTIVE) {
02739          is_valid = 1;
02740       }
02741       break;
02742    case CC_CALLER_BUSY:
02743       if (current_state == CC_CALLEE_READY) {
02744          is_valid = 1;
02745       }
02746       break;
02747    case CC_RECALLING:
02748       if (current_state == CC_CALLEE_READY) {
02749          is_valid = 1;
02750       }
02751       break;
02752    case CC_COMPLETE:
02753       if (current_state == CC_RECALLING) {
02754          is_valid = 1;
02755       }
02756       break;
02757    case CC_FAILED:
02758       is_valid = 1;
02759       break;
02760    default:
02761       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
02762             agent->core_id, new_state);
02763       break;
02764    }
02765 
02766    return is_valid;
02767 }

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

Definition at line 4228 of file ccss.c.

References ast_cc_failed(), and cc_core_instance::core_id.

Referenced by handle_cc_kill().

04229 {
04230    int *core_id = arg;
04231    struct cc_core_instance *core_instance = obj;
04232 
04233    if (!core_id || (core_instance->core_id == *core_id)) {
04234       ast_cc_failed(core_instance->core_id, "CC transaction canceled administratively\n");
04235    }
04236    return 0;
04237 }

static void kill_duplicate_offers ( char *  caller  )  [static]

Definition at line 2252 of file ccss.c.

References ao2_iterator_destroy(), ao2_t_callback_data, match_agent(), MATCH_NO_REQUEST, OBJ_MULTIPLE, and OBJ_UNLINK.

Referenced by cc_core_init_instance().

02253 {
02254    unsigned long match_flags = MATCH_NO_REQUEST;
02255    struct ao2_iterator *dups_iter;
02256 
02257    /*
02258     * Must remove the ref that was in cc_core_instances outside of
02259     * the container lock to prevent deadlock.
02260     */
02261    dups_iter = ao2_t_callback_data(cc_core_instances, OBJ_MULTIPLE | OBJ_UNLINK,
02262       match_agent, caller, &match_flags, "Killing duplicate offers");
02263    if (dups_iter) {
02264       /* Now actually unref any duplicate offers by simply destroying the iterator. */
02265       ao2_iterator_destroy(dups_iter);
02266    }
02267 }

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

Definition at line 482 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().

00483 {
00484    struct cc_core_instance *core_instance = obj;
00485    const char *name = arg;
00486    unsigned long match_flags = *(unsigned long *)data;
00487    int possible_match = 0;
00488 
00489    if ((match_flags & MATCH_NO_REQUEST) && core_instance->current_state < CC_CALLER_REQUESTED) {
00490       possible_match = 1;
00491    }
00492 
00493    if ((match_flags & MATCH_REQUEST) && core_instance->current_state >= CC_CALLER_REQUESTED) {
00494       possible_match = 1;
00495    }
00496 
00497    if (!possible_match) {
00498       return 0;
00499    }
00500 
00501    if (!strcmp(core_instance->agent->device_name, name)) {
00502       return CMP_MATCH | CMP_STOP;
00503    }
00504    return 0;
00505 }

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

Definition at line 629 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().

00630 {
00631    switch (policy) {
00632    case AST_CC_MONITOR_NEVER:
00633       return "never";
00634    case AST_CC_MONITOR_NATIVE:
00635       return "native";
00636    case AST_CC_MONITOR_GENERIC:
00637       return "generic";
00638    case AST_CC_MONITOR_ALWAYS:
00639       return "always";
00640    default:
00641       /* This should never happen... */
00642       return "";
00643    }
00644 }

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

Definition at line 2428 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().

02429 {
02430    struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
02431    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02432    ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
02433          agent->core_id);
02434    agent_pvt->offer_timer_id = -1;
02435    ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
02436    cc_unref(agent, "Remove scheduler's reference to the agent");
02437    return 0;
02438 }

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

Definition at line 4165 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().

04166 {
04167    int *cli_fd = arg;
04168    struct cc_core_instance *core_instance = obj;
04169 
04170    ast_cli(*cli_fd, "%d\t\t%s\t\t%s\n", core_instance->core_id, core_instance->agent->device_name,
04171          cc_state_to_string(core_instance->current_state));
04172    AST_LIST_LOCK(core_instance->monitors);
04173    cc_cli_print_monitor_stats(AST_LIST_FIRST(core_instance->monitors), *cli_fd, 0);
04174    AST_LIST_UNLOCK(core_instance->monitors);
04175    return 0;
04176 }

static void request_cc ( struct cc_core_instance core_instance  )  [static]

Definition at line 2824 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, ast_cc_interface::device_name, EVENT_FLAG_CC, has_device_monitors(), ast_cc_monitor::interface, manager_event, ast_cc_interface::monitor_class, cc_core_instance::monitors, ast_cc_monitor::parent_id, and ast_cc_monitor_callbacks::request_cc.

Referenced by cc_caller_requested().

02825 {
02826    struct ast_cc_monitor *monitor_iter;
02827    AST_LIST_LOCK(core_instance->monitors);
02828    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02829       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02830          if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
02831             AST_LIST_REMOVE_CURRENT(next);
02832             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02833                   monitor_iter->interface->device_name, 1);
02834             cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
02835          } else {
02836             manager_event(EVENT_FLAG_CC, "CCRequested",
02837                "CoreID: %d\r\n"
02838                "Caller: %s\r\n"
02839                "Callee: %s\r\n",
02840                core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
02841          }
02842       }
02843    }
02844    AST_LIST_TRAVERSE_SAFE_END;
02845 
02846    if (!has_device_monitors(core_instance)) {
02847       ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
02848    }
02849    AST_LIST_UNLOCK(core_instance->monitors);
02850 }

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

Definition at line 584 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().

00585 {
00586    if (!strcasecmp(value, "never")) {
00587       return AST_CC_AGENT_NEVER;
00588    } else if (!strcasecmp(value, "native")) {
00589       return AST_CC_AGENT_NATIVE;
00590    } else if (!strcasecmp(value, "generic")) {
00591       return AST_CC_AGENT_GENERIC;
00592    } else {
00593       ast_log(LOG_WARNING, "%s is an invalid value for cc_agent_policy. Switching to 'never'\n", value);
00594       return AST_CC_AGENT_NEVER;
00595    }
00596 }

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

Definition at line 598 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().

00599 {
00600    if (!strcasecmp(value, "never")) {
00601       return AST_CC_MONITOR_NEVER;
00602    } else if (!strcasecmp(value, "native")) {
00603       return AST_CC_MONITOR_NATIVE;
00604    } else if (!strcasecmp(value, "generic")) {
00605       return AST_CC_MONITOR_GENERIC;
00606    } else if (!strcasecmp(value, "always")) {
00607       return AST_CC_MONITOR_ALWAYS;
00608    } else {
00609       ast_log(LOG_WARNING, "%s is an invalid value for cc_monitor_policy. Switching to 'never'\n", value);
00610       return AST_CC_MONITOR_NEVER;
00611    }
00612 }

static void suspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2919 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, ast_cc_interface::device_name, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, ast_cc_monitor::parent_id, and ast_cc_monitor_callbacks::suspend.

Referenced by cc_caller_busy(), and handle_controlstreamfile().

02920 {
02921    struct ast_cc_monitor *monitor_iter;
02922    AST_LIST_LOCK(core_instance->monitors);
02923    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02924       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02925          if (monitor_iter->callbacks->suspend(monitor_iter)) {
02926             AST_LIST_REMOVE_CURRENT(next);
02927             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02928                   monitor_iter->interface->device_name, 1);
02929             cc_unref(monitor_iter, "suspend failed. Unref list's reference to monitor");
02930          }
02931       }
02932    }
02933    AST_LIST_TRAVERSE_SAFE_END;
02934 
02935    if (!has_device_monitors(core_instance)) {
02936       ast_cc_failed(core_instance->core_id, "All device monitors failed to suspend CC");
02937    }
02938    AST_LIST_UNLOCK(core_instance->monitors);
02939 }

static void unsuspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2866 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, ast_cc_interface::device_name, has_device_monitors(), ast_cc_monitor::interface, ast_cc_interface::monitor_class, cc_core_instance::monitors, ast_cc_monitor::parent_id, and ast_cc_monitor_callbacks::unsuspend.

Referenced by cc_active().

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


Variable Documentation

struct ast_cli_entry cc_cli[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_cc_status, "Reports CC stats"),
   AST_CLI_DEFINE(handle_cc_kill, "Kill a CC transaction"),
}

Definition at line 4308 of file ccss.c.

struct ao2_container* cc_core_instances [static]

Definition at line 317 of file ccss.c.

const int CC_CORE_INSTANCES_BUCKETS = 17 [static]

Definition at line 316 of file ccss.c.

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

Definition at line 116 of file ccss.c.

Definition at line 545 of file ccss.c.

int cc_logger_level [static]

Logger level registered by the CC core.

Definition at line 124 of file ccss.c.

const char* CC_LOGGER_LEVEL_NAME = "CC" [static]

Name printed on all CC log messages.

Definition at line 120 of file ccss.c.

int cc_request_count [static]

The current number of CC requests in the system

Definition at line 132 of file ccss.c.

The sched_thread ID used for all generic CC timeouts

Definition at line 106 of file ccss.c.

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 4043 of file ccss.c.

const char* ccreq_app = "CallCompletionRequest" [static]

Definition at line 3992 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 111 of file ccss.c.

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

Definition at line 1605 of file ccss.c.

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

Definition at line 1719 of file ccss.c.

Definition at line 2343 of file ccss.c.

Definition at line 1035 of file ccss.c.

Referenced by ast_cc_init(), and cc_shutdown().

unsigned int global_cc_max_requests [static]

Parsed configuration value for cc_max_requests

Definition at line 128 of file ccss.c.

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

Definition at line 3133 of file ccss.c.

Definition at line 373 of file ccss.c.

const char* service_string

Definition at line 374 of file ccss.c.

Definition at line 383 of file ccss.c.

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

Referenced by cc_do_state_change().

const char* state_string

Definition at line 384 of file ccss.c.


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1