Sat Mar 10 01:54:47 2012

Asterisk developer's documentation


ccss.c File Reference

Call Completion Supplementary Services implementation. More...

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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

Variables

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


Detailed Description

Call Completion Supplementary Services implementation.

Author:
Mark Michelson <mmichelson@digium.com>

Definition in file ccss.c.


Define Documentation

#define CC_MAX_AGENTS_DEFAULT   5

Definition at line 537 of file ccss.c.

#define CC_MAX_MONITORS_DEFAULT   5

Definition at line 538 of file ccss.c.

#define CC_OFFER_TIMER_DEFAULT   20

Definition at line 533 of file ccss.c.

#define CC_RECALL_TIMER_DEFAULT   20

Definition at line 536 of file ccss.c.

#define CCBS_AVAILABLE_TIMER_DEFAULT   4800

Definition at line 535 of file ccss.c.

#define CCNR_AVAILABLE_TIMER_DEFAULT   7200

Definition at line 534 of file ccss.c.

#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

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

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

enum match_flags

Enumerator:
MATCH_NO_REQUEST 
MATCH_REQUEST 

Definition at line 455 of file ccss.c.

00455                  {
00456    /* Only match agents that have not yet
00457     * made a CC request
00458     */
00459    MATCH_NO_REQUEST = (1 << 0),
00460    /* Only match agents that have made
00461     * a CC request
00462     */
00463    MATCH_REQUEST = (1 << 1),
00464 };


Function Documentation

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

Allocate and initialize an ast_cc_config_params structure.

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

Definition at line 559 of file ccss.c.

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

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

static void agent_destroy ( void *  data  )  [static]

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

02272 {
02273    struct ast_cc_agent *agent = data;
02274 
02275    if (agent->callbacks) {
02276       agent->callbacks->destructor(agent);
02277    }
02278    ast_cc_config_params_destroy(agent->cc_params);
02279 }

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

Definition at line 610 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, and AST_CC_AGENT_NEVER.

Referenced by ast_cc_get_param().

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

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

References CC_CALLER_REQUESTED, and cc_request_state_change().

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

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

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

Call a callback on all agents of a specific type.

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

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

Definition at line 442 of file ccss.c.

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

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

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

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

References CC_ACTIVE, and cc_request_state_change().

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

03540 {
03541    va_list ap;
03542    int res;
03543 
03544    va_start(ap, debug);
03545    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03546    va_end(ap);
03547    return res;
03548 }

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

References CC_CALLER_BUSY, and cc_request_state_change().

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

03529 {
03530    va_list ap;
03531    int res;
03532 
03533    va_start(ap, debug);
03534    res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
03535    va_end(ap);
03536    return res;
03537 }

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

References CC_RECALLING, and cc_request_state_change().

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

03551 {
03552    va_list ap;
03553    int res;
03554 
03555    va_start(ap, debug);
03556    res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
03557    va_end(ap);
03558    return res;
03559 }

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

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

Referenced by ast_cc_init(), and load_module().

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

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

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

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

03351 {
03352    struct ast_datastore *recall_datastore;
03353    struct cc_monitor_tree *interface_tree;
03354    struct ast_cc_monitor *monitor;
03355    struct cc_recall_ds_data *recall_data;
03356    struct ast_str *str = ast_str_create(64);
03357    int core_id;
03358 
03359    if (!str) {
03360       return -1;
03361    }
03362 
03363    ast_channel_lock(chan);
03364    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03365       ast_channel_unlock(chan);
03366       ast_free(str);
03367       return -1;
03368    }
03369    recall_data = recall_datastore->data;
03370    interface_tree = recall_data->interface_tree;
03371    core_id = recall_data->core_id;
03372    ast_channel_unlock(chan);
03373 
03374    AST_LIST_LOCK(interface_tree);
03375    monitor = AST_LIST_FIRST(interface_tree);
03376    build_cc_interfaces_chanvar(monitor, str);
03377    AST_LIST_UNLOCK(interface_tree);
03378 
03379    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03380    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03381          core_id, ast_str_buffer(str));
03382 
03383    ast_free(str);
03384    return 0;
03385 }

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

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

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

03816 {
03817    struct cc_status_response_args *args;
03818    struct cc_core_instance *core_instance;
03819    int res;
03820 
03821    args = ast_calloc(1, sizeof(*args));
03822    if (!args) {
03823       return -1;
03824    }
03825 
03826    core_instance = find_cc_core_instance(core_id);
03827    if (!core_instance) {
03828       ast_free(args);
03829       return -1;
03830    }
03831 
03832    args->core_instance = core_instance;
03833    args->devstate = devstate;
03834 
03835    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
03836    if (res) {
03837       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03838       ast_free(args);
03839    }
03840    return res;
03841 }

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

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

Referenced by __unload_module().

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

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

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

Referenced by cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

01230 {
01231    struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
01232    int res;
01233    monitor->available_timer_id = -1;
01234    res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
01235    cc_unref(monitor, "Unref reference from scheduler\n");
01236    return res;
01237 }

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

03902 {
03903    struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));
03904 
03905    if (!payload) {
03906       return -1;
03907    }
03908    if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
03909       /* Something screwed up, we can't make a frame with this */
03910       ast_free(payload);
03911       return -1;
03912    }
03913    frame->frametype = AST_FRAME_CONTROL;
03914    frame->subclass.integer = AST_CONTROL_CC;
03915    frame->data.ptr = payload;
03916    frame->datalen = sizeof(*payload);
03917    frame->mallocd = AST_MALLOCD_DATA;
03918    return 0;
03919 }

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

03956 {
03957    struct cc_control_payload payload;
03958    if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
03959       /* Something screwed up. Don't try to handle this payload */
03960       call_destructor_with_no_monitor(monitor_type, private_data);
03961       return;
03962    }
03963    ast_handle_cc_control_frame(inbound, NULL, &payload);
03964 }

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

03922 {
03923    char device_name[AST_CHANNEL_NAME];
03924    struct cc_control_payload payload;
03925    struct ast_cc_config_params *cc_params;
03926 
03927    if (outgoing->hangupcause != AST_CAUSE_BUSY && outgoing->hangupcause != AST_CAUSE_CONGESTION) {
03928       /* It doesn't make sense to try to offer CCBS to the caller if the reason for ast_call
03929        * failing is something other than busy or congestion
03930        */
03931       return;
03932    }
03933 
03934    cc_params = ast_channel_get_cc_config_params(outgoing);
03935    if (!cc_params) {
03936       return;
03937    }
03938    if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
03939       /* This sort of CCBS only works if using generic CC. For native, we would end up sending
03940        * a CC request for a non-existent call. The far end will reject this every time
03941        */
03942       return;
03943    }
03944 
03945    ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
03946    if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
03947       dialstring, AST_CC_CCBS, NULL, &payload)) {
03948       /* Something screwed up, we can't make a frame with this */
03949       return;
03950    }
03951    ast_handle_cc_control_frame(incoming, outgoing, &payload);
03952 }

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

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

Referenced by dial_exec_full().

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

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

References ast_get_channel_tech(), and ast_channel_tech::cc_callback.

Referenced by dial_exec_full().

03967 {
03968    const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);
03969 
03970    if (chantech && chantech->cc_callback) {
03971       chantech->cc_callback(inbound, dest, callback);
03972    }
03973 
03974    return 0;
03975 }

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

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

03562 {
03563    struct ast_datastore *recall_datastore;
03564    struct cc_recall_ds_data *recall_data;
03565    int core_id;
03566    va_list ap;
03567    int res;
03568 
03569    ast_channel_lock(chan);
03570    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03571       /* Silly! Why did you call this function if there's no recall DS? */
03572       ast_channel_unlock(chan);
03573       return -1;
03574    }
03575    recall_data = recall_datastore->data;
03576    if (recall_data->nested || recall_data->ignore) {
03577       /* If this is being called from a nested Dial, it is too
03578        * early to determine if the recall has actually completed.
03579        * The outermost dial is the only one with the authority to
03580        * declare the recall to be complete.
03581        *
03582        * Similarly, if this function has been called when the
03583        * recall has progressed beyond the first dial, this is not
03584        * a legitimate time to declare the recall to be done. In fact,
03585        * that should have been done already.
03586        */
03587       ast_channel_unlock(chan);
03588       return -1;
03589    }
03590    core_id = recall_data->core_id;
03591    ast_channel_unlock(chan);
03592    va_start(ap, debug);
03593    res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
03594    va_end(ap);
03595    return res;
03596 }

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

References ast_free.

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

00576 {
00577    ast_free(params);
00578 }

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

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

00738 {
00739    *dest = *src;
00740 }

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

References cc_default_params.

Referenced by __ast_cc_config_params_init().

00555 {
00556    *params = cc_default_params;
00557 }

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

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

Referenced by dial_exec_full().

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

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

References CC_FAILED, and cc_request_state_change().

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

03599 {
03600    va_list ap;
03601    int res;
03602 
03603    va_start(ap, debug);
03604    res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
03605    va_end(ap);
03606    return res;
03607 }

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

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

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

02215 {
02216    struct ast_datastore *datastore;
02217    struct dialed_cc_interfaces *cc_interfaces;
02218    int core_id_return;
02219 
02220    ast_channel_lock(chan);
02221    if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02222       ast_channel_unlock(chan);
02223       return -1;
02224    }
02225 
02226    cc_interfaces = datastore->data;
02227    core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
02228    ast_channel_unlock(chan);
02229    return core_id_return;
02230 
02231 }

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

Get the associated monitor given the device name and core_id.

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

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

Definition at line 3238 of file ccss.c.

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

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

03239 {
03240    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03241    struct ast_cc_monitor *monitor_iter;
03242 
03243    if (!core_instance) {
03244       return NULL;
03245    }
03246 
03247    AST_LIST_LOCK(core_instance->monitors);
03248    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03249       if (!strcmp(monitor_iter->interface->device_name, device_name)) {
03250          /* Found a monitor. */
03251          cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
03252          break;
03253       }
03254    }
03255    AST_LIST_UNLOCK(core_instance->monitors);
03256    cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
03257    return monitor_iter;
03258 }

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

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

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

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

Referenced by main().

04299 {
04300    int res;
04301 
04302    if (!(cc_core_instances = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04303                cc_core_instance_hash_fn, cc_core_instance_cmp_fn,
04304                "Create core instance container"))) {
04305       return -1;
04306    }
04307    if (!(generic_monitors = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04308                generic_monitor_hash_fn, generic_monitor_cmp_fn,
04309                "Create generic monitor container"))) {
04310       return -1;
04311    }
04312    if (!(cc_core_taskprocessor = ast_taskprocessor_get("CCSS core", TPS_REF_DEFAULT))) {
04313       return -1;
04314    }
04315    if (!(cc_sched_thread = ast_sched_thread_create())) {
04316       return -1;
04317    }
04318    res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL);
04319    res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL);
04320    res |= ast_cc_monitor_register(&generic_monitor_cbs);
04321    res |= ast_cc_agent_register(&generic_agent_callbacks);
04322    ast_cli_register_multiple(cc_cli, ARRAY_LEN(cc_cli));
04323    cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME);
04324    dialed_cc_interface_counter = 1;
04325    initialize_cc_max_requests();
04326    return res;
04327 }

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

Referenced by build_peer().

00724 {
00725    return (!strcasecmp(name, "cc_agent_policy") ||
00726             !strcasecmp(name, "cc_monitor_policy") ||
00727             !strcasecmp(name, "cc_offer_timer") ||
00728             !strcasecmp(name, "ccnr_available_timer") ||
00729             !strcasecmp(name, "ccbs_available_timer") ||
00730             !strcasecmp(name, "cc_max_agents") ||
00731             !strcasecmp(name, "cc_max_monitors") ||
00732             !strcasecmp(name, "cc_callback_macro") ||
00733             !strcasecmp(name, "cc_agent_dialstring") ||
00734             !strcasecmp(name, "cc_recall_timer"));
00735 }

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

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

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

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

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

References CC_CALLEE_READY, and cc_request_state_change().

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

03518 {
03519    va_list ap;
03520    int res;
03521 
03522    va_start(ap, debug);
03523    res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
03524    va_end(ap);
03525    return res;
03526 }

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

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

Referenced by ast_queue_cc_frame().

04091 {
04092    struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};
04093 
04094    ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
04095    ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
04096    return data.count;
04097 }

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

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

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

03664 {
03665    struct ast_cc_monitor_failure_data *failure_data;
03666    int res;
03667    va_list ap;
03668 
03669    if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
03670       return -1;
03671    }
03672 
03673    if (!(failure_data->device_name = ast_strdup(monitor_name))) {
03674       ast_free(failure_data);
03675       return -1;
03676    }
03677 
03678    va_start(ap, debug);
03679    if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
03680       va_end(ap);
03681       ast_free((char *)failure_data->device_name);
03682       ast_free(failure_data);
03683       return -1;
03684    }
03685    va_end(ap);
03686 
03687    failure_data->core_id = core_id;
03688 
03689    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
03690    if (res) {
03691       ast_free((char *)failure_data->device_name);
03692       ast_free((char *)failure_data->debug);
03693       ast_free(failure_data);
03694    }
03695    return res;
03696 }

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

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

Referenced by sig_pri_handle_cis_subcmds().

03774 {
03775    int res;
03776    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03777 
03778    if (!core_instance) {
03779       return -1;
03780    }
03781 
03782    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
03783    if (res) {
03784       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03785    }
03786    return res;
03787 }

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

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

Referenced by ast_cc_init(), and load_module().

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

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

References CC_ACTIVE, and cc_request_state_change().

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

03507 {
03508    va_list ap;
03509    int res;
03510 
03511    va_start(ap, debug);
03512    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03513    va_end(ap);
03514    return res;
03515 }

int ast_cc_monitor_status_request ( int  core_id  ) 

Request the status of a caller or callers.

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

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

Definition at line 3708 of file ccss.c.

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

Referenced by sig_pri_handle_cis_subcmds().

03709 {
03710    int res;
03711    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03712 
03713    if (!core_instance) {
03714       return -1;
03715    }
03716 
03717    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
03718    if (res) {
03719       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03720    }
03721    return res;
03722 }

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

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

Referenced by sig_pri_handle_cis_subcmds().

03746 {
03747    int res;
03748    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03749 
03750    if (!core_instance) {
03751       return -1;
03752    }
03753 
03754    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
03755    if (res) {
03756       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03757    }
03758    return res;
03759 }

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

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

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

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

Referenced by ast_hangup().

03471 {
03472    int core_id;
03473    int res = -1;
03474    struct ast_datastore *datastore;
03475    struct dialed_cc_interfaces *cc_interfaces;
03476    char cc_is_offerable;
03477 
03478    ast_channel_lock(caller_chan);
03479    if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
03480       ast_channel_unlock(caller_chan);
03481       return res;
03482    }
03483 
03484    cc_interfaces = datastore->data;
03485    cc_is_offerable = cc_interfaces->is_original_caller;
03486    core_id = cc_interfaces->core_id;
03487    ast_channel_unlock(caller_chan);
03488 
03489    if (cc_is_offerable) {
03490       res = cc_offer(core_id, "CC offered to caller %s", caller_chan->name);
03491    }
03492    return res;
03493 }

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

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

02210 {
02211    return cc_request_count < global_cc_max_requests;
02212 }

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

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

Referenced by acf_cc_write(), and build_peer().

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

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

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00837 {
00838    return config->cc_agent_dialstring;
00839 }

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

References config.

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

00743 {
00744    return config->cc_agent_policy;
00745 }

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

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00871 {
00872    return config->cc_callback_macro;
00873 }

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

References config.

Referenced by ast_cc_get_param(), and cc_core_init_instance().

00851 {
00852    return config->cc_max_agents;
00853 }

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

References config.

Referenced by ast_cc_get_param(), and ast_queue_cc_frame().

00861 {
00862    return config->cc_max_monitors;
00863 }

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

References config.

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

00760 {
00761    return config->cc_monitor_policy;
00762 }

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

References config.

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

00777 {
00778    return config->cc_offer_timer;
00779 }

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

References config.

Referenced by ast_cc_get_param(), and generic_recall().

00807 {
00808    return config->cc_recall_timer;
00809 }

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

References config.

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

00822 {
00823    return config->ccbs_available_timer;
00824 }

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

References config.

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

00792 {
00793    return config->ccnr_available_timer;
00794 }

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

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

Referenced by ast_cc_busy_interface(), and ast_cc_call_failed().

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

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

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

Referenced by dial_exec_full(), and do_forward().

03440 {
03441    struct ast_datastore *cc_datastore;
03442    struct ast_datastore *cc_recall_datastore;
03443    struct dialed_cc_interfaces *cc_interfaces;
03444    struct cc_recall_ds_data *recall_cc_data;
03445 
03446    ast_channel_lock(chan);
03447    if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
03448       cc_interfaces = cc_datastore->data;
03449       cc_interfaces->ignore = 1;
03450    }
03451 
03452    if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03453       recall_cc_data = cc_recall_datastore->data;
03454       recall_cc_data->ignore = 1;
03455    }
03456    ast_channel_unlock(chan);
03457 }

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

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

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

03873 {
03874    struct ast_frame frame = {0,};
03875    char device_name[AST_CHANNEL_NAME];
03876    int retval;
03877    struct ast_cc_config_params *cc_params;
03878 
03879    cc_params = ast_channel_get_cc_config_params(chan);
03880    if (!cc_params) {
03881       return -1;
03882    }
03883    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03884    if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
03885       ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
03886       return -1;
03887    }
03888 
03889    if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
03890       /* Frame building failed. We can't use this. */
03891       return -1;
03892    }
03893    retval = ast_queue_frame(chan, &frame);
03894    ast_frfree(&frame);
03895    return retval;
03896 }

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

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

Referenced by ast_cc_set_param().

00842 {
00843    if (ast_strlen_zero(value)) {
00844       config->cc_agent_dialstring[0] = '\0';
00845    } else {
00846       ast_copy_string(config->cc_agent_dialstring, value, sizeof(config->cc_agent_dialstring));
00847    }
00848 }

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

References AST_CC_AGENT_GENERIC, and config.

Referenced by ast_cc_set_param(), and build_peer().

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

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

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

Referenced by ast_cc_set_param().

00876 {
00877    if (ast_strlen_zero(value)) {
00878       config->cc_callback_macro[0] = '\0';
00879    } else {
00880       ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
00881    }
00882 }

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

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

Referenced by local_call().

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

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

References config.

Referenced by ast_cc_set_param().

00856 {
00857    config->cc_max_agents = value;
00858 }

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

References config.

Referenced by ast_cc_set_param().

00866 {
00867    config->cc_max_monitors = value;
00868 }

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

References AST_CC_MONITOR_ALWAYS, and config.

Referenced by ast_cc_set_param().

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

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

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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

References ast_log(), config, and LOG_WARNING.

Referenced by ast_cc_set_param().

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

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

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

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

03125 {
03126    struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
03127    struct cc_recall_ds_data *recall_data;
03128    struct cc_core_instance *core_instance;
03129 
03130    if (!recall_datastore) {
03131       return -1;
03132    }
03133 
03134    if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
03135       ast_datastore_free(recall_datastore);
03136       return -1;
03137    }
03138 
03139    if (!(core_instance = find_cc_core_instance(core_id))) {
03140       ast_free(recall_data);
03141       ast_datastore_free(recall_datastore);
03142       return -1;
03143    }
03144 
03145    recall_data->interface_tree = cc_ref(core_instance->monitors,
03146          "Bump refcount for monitor tree for recall datastore");
03147    recall_data->core_id = core_id;
03148    recall_datastore->data = recall_data;
03149    recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
03150    ast_channel_lock(chan);
03151    ast_channel_datastore_add(chan, recall_datastore);
03152    ast_channel_unlock(chan);
03153    cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
03154    return 0;
03155 }

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

Definition at line 3307 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, cc_monitor_backend::next, extension_child_dialstring::original_dialstring, ast_cc_monitor::parent_id, ast_cc_monitor::private_data, and str.

Referenced by ast_cc_agent_set_interfaces_chanvar(), and ast_set_cc_interfaces_chanvar().

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

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

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

01937 {
01938    const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
01939 
01940    if (!monitor_callbacks) {
01941       return;
01942    }
01943 
01944    monitor_callbacks->destructor(private_data);
01945 }

static void cancel_available_timer ( struct cc_core_instance core_instance  )  [static]

Definition at line 2940 of file ccss.c.

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

Referenced by cc_recalling().

02941 {
02942    struct ast_cc_monitor *monitor_iter;
02943    AST_LIST_LOCK(core_instance->monitors);
02944    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02945       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02946          if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
02947             AST_LIST_REMOVE_CURRENT(next);
02948             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02949                   monitor_iter->interface->device_name, 1);
02950             cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
02951          }
02952       }
02953    }
02954    AST_LIST_TRAVERSE_SAFE_END;
02955 
02956    if (!has_device_monitors(core_instance)) {
02957       ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
02958    }
02959    AST_LIST_UNLOCK(core_instance->monitors);
02960 }

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

02874 {
02875    /* Either
02876     * 1. Callee accepted CC request, call agent's ack callback.
02877     * 2. Caller became available, call agent's stop_monitoring callback and
02878     *    call monitor's unsuspend callback.
02879     */
02880    if (previous_state == CC_CALLER_REQUESTED) {
02881       core_instance->agent->callbacks->respond(core_instance->agent,
02882          AST_CC_AGENT_RESPONSE_SUCCESS);
02883       manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
02884          "CoreID: %d\r\n"
02885          "Caller: %s\r\n",
02886          core_instance->core_id, core_instance->agent->device_name);
02887    } else if (previous_state == CC_CALLER_BUSY) {
02888       manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
02889          "CoreID: %d\r\n"
02890          "Caller: %s\r\n",
02891          core_instance->core_id, core_instance->agent->device_name);
02892       unsuspend(core_instance);
02893    }
02894    /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
02895    return 0;
02896 }

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

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

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

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

Definition at line 2281 of file ccss.c.

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

Referenced by cc_core_init_instance().

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

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

References ast_log(), and LOG_WARNING.

02755 {
02756    /* This should never happen... */
02757    ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
02758    return -1;
02759 }

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

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

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

03846 {
03847    struct ast_datastore *datastore;
03848    struct dialed_cc_interfaces *cc_interfaces;
03849    int dial_parent_id;
03850 
03851    ast_channel_lock(chan);
03852    datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL);
03853    if (!datastore) {
03854       ast_channel_unlock(chan);
03855       return -1;
03856    }
03857    cc_interfaces = datastore->data;
03858    dial_parent_id = cc_interfaces->dial_parent_id;
03859    ast_channel_unlock(chan);
03860 
03861    payload->monitor_type = monitor_type;
03862    payload->private_data = private_data;
03863    payload->service = service;
03864    ast_cc_copy_config_params(&payload->config_params, cc_params);
03865    payload->parent_interface_id = dial_parent_id;
03866    ast_copy_string(payload->device_name, device_name, sizeof(payload->device_name));
03867    ast_copy_string(payload->dialstring, dialstring, sizeof(payload->dialstring));
03868    return 0;
03869 }

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

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

02899 {
02900    core_instance->agent->callbacks->callee_available(core_instance->agent);
02901    return 0;
02902 }

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

02927 {
02928    /* Callee was available, but caller was busy, call agent's begin_monitoring callback
02929     * and call monitor's suspend callback.
02930     */
02931    suspend(core_instance);
02932    core_instance->agent->callbacks->start_monitoring(core_instance->agent);
02933    manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
02934       "CoreID: %d\r\n"
02935       "Caller: %s\r\n",
02936       core_instance->core_id, core_instance->agent->device_name);
02937    return 0;
02938 }

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

02762 {
02763    if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
02764       ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
02765             core_instance->agent->device_name);
02766       return -1;
02767    }
02768    manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
02769       "CoreID: %d\r\n"
02770       "Caller: %s\r\n"
02771       "Expires: %u\r\n",
02772       core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
02773    ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
02774          core_instance->core_id, core_instance->agent->device_name);
02775    return 0;
02776 }

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

02838 {
02839    if (!ast_cc_request_is_within_limits()) {
02840       ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
02841       core_instance->agent->callbacks->respond(core_instance->agent,
02842          AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY);
02843       ast_cc_failed(core_instance->core_id, "Too many requests in the system");
02844       return -1;
02845    }
02846    core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
02847    request_cc(core_instance);
02848    return 0;
02849 }

static int cc_cli_output_status ( void *  data  )  [static]

Definition at line 4163 of file ccss.c.

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

Referenced by handle_cc_status().

04164 {
04165    int *cli_fd = data;
04166    int count = ao2_container_count(cc_core_instances);
04167 
04168    if (!count) {
04169       ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
04170    } else {
04171       ast_cli(*cli_fd, "%d Call completion transactions\n", count);
04172       ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
04173       ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
04174       ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
04175    }
04176    ast_free(cli_fd);
04177    return 0;
04178 }

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

Definition at line 4130 of file ccss.c.

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

Referenced by print_stats_cb().

04131 {
04132    struct ast_cc_monitor *child_monitor_iter = monitor;
04133    if (!monitor) {
04134       return;
04135    }
04136 
04137    ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
04138    if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
04139       ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
04140    }
04141    ast_cli(fd, "\n");
04142 
04143    while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
04144       if (child_monitor_iter->parent_id == monitor->id) {
04145          cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
04146       }
04147    }
04148 }

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

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

02975 {
02976    /* Recall has made progress, call agent and monitor destructor functions
02977     */
02978    manager_event(EVENT_FLAG_CC, "CCRecallComplete",
02979       "CoreID: %d\r\n"
02980       "Caller: %s\r\n",
02981       core_instance->core_id, core_instance->agent->device_name);
02982    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
02983    return 0;
02984 }

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

Definition at line 2637 of file ccss.c.

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

Referenced by ast_handle_cc_control_frame().

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

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

Definition at line 409 of file ccss.c.

References CMP_MATCH, CMP_STOP, and cc_core_instance::core_id.

Referenced by ast_cc_init().

00410 {
00411    struct cc_core_instance *core_instance1 = obj;
00412    struct cc_core_instance *core_instance2 = arg;
00413 
00414    return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
00415 }

static void cc_core_instance_destructor ( void *  data  )  [static]

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

02626 {
02627    struct cc_core_instance *core_instance = data;
02628    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
02629    if (core_instance->agent) {
02630       cc_unref(core_instance->agent, "Core instance is done with the agent now");
02631    }
02632    if (core_instance->monitors) {
02633       core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
02634    }
02635 }

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

Definition at line 403 of file ccss.c.

References cc_core_instance::core_id.

Referenced by ast_cc_init().

00404 {
00405    const struct cc_core_instance *core_instance = obj;
00406    return core_instance->core_id;
00407 }

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

Definition at line 1972 of file ccss.c.

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

Referenced by ast_handle_cc_control_frame().

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

static int cc_do_state_change ( void *  datap  )  [static]

Definition at line 3009 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_core_instance::current_state, is_state_change_valid(), ast_cc_agent_callbacks::respond, and state_change_funcs.

Referenced by cc_request_state_change().

03010 {
03011    struct cc_state_change_args *args = datap;
03012    struct cc_core_instance *core_instance;
03013    enum cc_state previous_state;
03014    int res;
03015 
03016    ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
03017          args->core_id, args->state, args->debug);
03018 
03019    core_instance = args->core_instance;
03020 
03021    if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
03022       ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
03023             args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
03024       if (args->state == CC_CALLER_REQUESTED) {
03025          /*
03026           * For out-of-order requests, we need to let the requester know that
03027           * we can't handle the request now.
03028           */
03029          core_instance->agent->callbacks->respond(core_instance->agent,
03030             AST_CC_AGENT_RESPONSE_FAILURE_INVALID);
03031       }
03032       ast_free(args);
03033       cc_unref(core_instance, "Unref core instance from when it was found earlier");
03034       return -1;
03035    }
03036 
03037    /* We can change to the new state now. */
03038    previous_state = core_instance->current_state;
03039    core_instance->current_state = args->state;
03040    res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);
03041 
03042    ast_free(args);
03043    cc_unref(core_instance, "Unref since state change has completed"); /* From ao2_find */
03044    return res;
03045 }

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

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

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

01771 {
01772    struct ast_cc_monitor *monitor_iter;
01773    struct extension_monitor_pvt *extension_pvt;
01774    struct extension_child_dialstring *child_dialstring;
01775 
01776    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
01777       if (monitor_iter->id == parent_id) {
01778          break;
01779       }
01780    }
01781 
01782    if (!monitor_iter) {
01783       return;
01784    }
01785    extension_pvt = monitor_iter->private_data;
01786 
01787    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
01788       if (!strcmp(child_dialstring->device_name, device_name)) {
01789          child_dialstring->is_valid = is_valid;
01790          break;
01791       }
01792    }
01793 }

static void cc_extension_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1541 of file ccss.c.

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

Referenced by cc_monitor_destroy().

01542 {
01543    struct extension_monitor_pvt *extension_pvt = private_data;
01544    struct extension_child_dialstring *child_dialstring;
01545 
01546    /* This shouldn't be possible, but I'm paranoid */
01547    if (!extension_pvt) {
01548       return;
01549    }
01550 
01551    while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
01552       ast_free(child_dialstring);
01553    }
01554    ast_free(extension_pvt);
01555 }

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

Definition at line 1809 of file ccss.c.

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

Referenced by ast_cc_call_init(), and cc_interfaces_datastore_init().

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

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

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

02987 {
02988    manager_event(EVENT_FLAG_CC, "CCFailure",
02989       "CoreID: %d\r\n"
02990       "Caller: %s\r\n"
02991       "Reason: %s\r\n",
02992       core_instance->core_id, core_instance->agent->device_name, args->debug);
02993    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
02994    return 0;
02995 }

static void cc_generic_agent_destructor ( struct ast_cc_agent agent  )  [static]

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

02609 {
02610    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02611 
02612    if (!agent_pvt) {
02613       /* The agent constructor probably failed. */
02614       return;
02615    }
02616 
02617    cc_generic_agent_stop_offer_timer(agent);
02618    if (agent_pvt->sub) {
02619       agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
02620    }
02621 
02622    ast_free(agent_pvt);
02623 }

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

Definition at line 2396 of file ccss.c.

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

02397 {
02398    struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
02399 
02400    if (!generic_pvt) {
02401       return -1;
02402    }
02403 
02404    generic_pvt->offer_timer_id = -1;
02405    if (chan->caller.id.number.valid && chan->caller.id.number.str) {
02406       ast_copy_string(generic_pvt->cid_num, chan->caller.id.number.str, sizeof(generic_pvt->cid_num));
02407    }
02408    if (chan->caller.id.name.valid && chan->caller.id.name.str) {
02409       ast_copy_string(generic_pvt->cid_name, chan->caller.id.name.str, sizeof(generic_pvt->cid_name));
02410    }
02411    ast_copy_string(generic_pvt->exten, S_OR(chan->macroexten, chan->exten), sizeof(generic_pvt->exten));
02412    ast_copy_string(generic_pvt->context, S_OR(chan->macrocontext, chan->context), sizeof(generic_pvt->context));
02413    agent->private_data = generic_pvt;
02414    ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
02415    return 0;
02416 }

static int cc_generic_agent_recall ( struct ast_cc_agent agent  )  [static]

Definition at line 2592 of file ccss.c.

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

02593 {
02594    pthread_t clotho;
02595    enum ast_device_state current_state = ast_device_state(agent->device_name);
02596 
02597    if (!cc_generic_is_device_available(current_state)) {
02598       /* We can't try to contact the device right now because he's not available
02599        * Let the core know he's busy.
02600        */
02601       ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
02602       return 0;
02603    }
02604    ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
02605    return 0;
02606 }

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

Definition at line 2462 of file ccss.c.

02463 {
02464    /* The generic agent doesn't have to do anything special to
02465     * acknowledge a CC request. Just return.
02466     */
02467    return;
02468 }

static int cc_generic_agent_start_monitoring ( struct ast_cc_agent agent  )  [static]

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

02520 {
02521    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02522    struct ast_str *str = ast_str_alloca(128);
02523 
02524    ast_assert(generic_pvt->sub == NULL);
02525    ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
02526       agent->device_name);
02527 
02528    if (!(generic_pvt->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
02529       generic_agent_devstate_cb, ast_str_buffer(str), agent,
02530       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->device_name,
02531       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
02532       AST_EVENT_IE_END))) {
02533       return -1;
02534    }
02535    return 0;
02536 }

static int cc_generic_agent_start_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2430 of file ccss.c.

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

02431 {
02432    int when;
02433    int sched_id;
02434    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02435 
02436    ast_assert(cc_sched_thread != NULL);
02437    ast_assert(agent->cc_params != NULL);
02438 
02439    when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
02440    ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
02441          agent->core_id, when);
02442    if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
02443       return -1;
02444    }
02445    generic_pvt->offer_timer_id = sched_id;
02446    return 0;
02447 }

static int cc_generic_agent_status_request ( struct ast_cc_agent agent  )  [static]

Definition at line 2470 of file ccss.c.

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

02471 {
02472    ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
02473    return 0;
02474 }

static int cc_generic_agent_stop_offer_timer ( struct ast_cc_agent agent  )  [static]

Definition at line 2449 of file ccss.c.

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

Referenced by cc_generic_agent_destructor().

02450 {
02451    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02452 
02453    if (generic_pvt->offer_timer_id != -1) {
02454       if (!ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id)) {
02455          cc_unref(agent, "Remove scheduler's reference to the agent");
02456       }
02457       generic_pvt->offer_timer_id = -1;
02458    }
02459    return 0;
02460 }

static int cc_generic_agent_stop_ringing ( struct ast_cc_agent agent  )  [static]

Definition at line 2476 of file ccss.c.

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

02477 {
02478    struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
02479 
02480    if (!recall_chan) {
02481       return 0;
02482    }
02483 
02484    ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
02485    return 0;
02486 }

static int cc_generic_is_device_available ( enum ast_device_state  state  )  [static]

Definition at line 1020 of file ccss.c.

References AST_DEVICE_NOT_INUSE, and AST_DEVICE_UNKNOWN.

Referenced by cc_generic_agent_recall(), cc_generic_monitor_destructor(), cc_generic_monitor_suspend(), cc_generic_monitor_unsuspend(), generic_agent_devstate_cb(), and generic_monitor_devstate_tp_cb().

01021 {
01022    return state == AST_DEVICE_NOT_INUSE || state == AST_DEVICE_UNKNOWN;
01023 }

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

Definition at line 1371 of file ccss.c.

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

01372 {
01373    ast_assert(sched_id != NULL);
01374 
01375    if (*sched_id == -1) {
01376       return 0;
01377    }
01378 
01379    ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
01380          monitor->core_id, monitor->interface->device_name);
01381    if (!ast_sched_thread_del(cc_sched_thread, *sched_id)) {
01382       cc_unref(monitor, "Remove scheduler's reference to the monitor");
01383    }
01384    *sched_id = -1;
01385    return 0;
01386 }

static void cc_generic_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1388 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, generic_monitor_instance::monitoring, and cc_monitor_backend::next.

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

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

Definition at line 1239 of file ccss.c.

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

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

static int cc_generic_monitor_suspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1302 of file ccss.c.

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

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

static int cc_generic_monitor_unsuspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1343 of file ccss.c.

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

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

static void cc_interface_destroy ( void *  data  )  [static]

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

01458 {
01459    struct ast_cc_interface *interface = data;
01460    ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
01461    ast_cc_config_params_destroy(interface->config_params);
01462 }

static void cc_interface_tree_destroy ( void *  data  )  [static]

Definition at line 1578 of file ccss.c.

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

Referenced by cc_interfaces_datastore_init().

01579 {
01580    struct cc_monitor_tree *cc_interface_tree = data;
01581    struct ast_cc_monitor *monitor;
01582    while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
01583       if (monitor->callbacks) {
01584          monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
01585       }
01586       cc_unref(monitor, "Destroying all monitors");
01587    }
01588    AST_LIST_HEAD_DESTROY(cc_interface_tree);
01589 }

static int cc_interfaces_datastore_init ( struct ast_channel chan  )  [static]

Definition at line 1858 of file ccss.c.

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

Referenced by ast_cc_call_init().

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

static void cc_monitor_destroy ( void *  data  )  [static]

Definition at line 1557 of file ccss.c.

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

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

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

static int cc_monitor_failed ( void *  data  )  [static]

Definition at line 3615 of file ccss.c.

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

Referenced by ast_cc_monitor_failed().

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

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

Definition at line 3459 of file ccss.c.

References CC_CALLER_OFFERED, and cc_request_state_change().

Referenced by ast_cc_offer().

03460 {
03461    va_list ap;
03462    int res;
03463 
03464    va_start(ap, debug);
03465    res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
03466    va_end(ap);
03467    return res;
03468 }

static int cc_party_b_free ( void *  data  )  [static]

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

03762 {
03763    struct cc_core_instance *core_instance = data;
03764    int res = 0;
03765 
03766    if (core_instance->agent->callbacks->party_b_free) {
03767       res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
03768    }
03769    cc_unref(core_instance, "Party B free finished. Unref core_instance");
03770    return res;
03771 }

static void cc_recall_ds_destroy ( void *  data  )  [static]

Definition at line 3111 of file ccss.c.

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

03112 {
03113    struct cc_recall_ds_data *recall_data = data;
03114    recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
03115    ast_free(recall_data);
03116 }

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

Definition at line 3097 of file ccss.c.

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

03098 {
03099    struct cc_recall_ds_data *old_data = data;
03100    struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));
03101 
03102    if (!new_data) {
03103       return NULL;
03104    }
03105    new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
03106    new_data->core_id = old_data->core_id;
03107    new_data->nested = 1;
03108    return new_data;
03109 }

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

02963 {
02964    /* Both caller and callee are available, call agent's recall callback
02965     */
02966    cancel_available_timer(core_instance);
02967    manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
02968       "CoreID: %d\r\n"
02969       "Caller: %s\r\n",
02970       core_instance->core_id, core_instance->agent->device_name);
02971    return 0;
02972 }

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

Definition at line 130 of file ccss.c.

References ao2_t_ref.

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

00131 {
00132    ao2_t_ref(obj, +1, debug);
00133    return obj;
00134 }

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

Definition at line 3047 of file ccss.c.

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

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

03048 {
03049    int res;
03050    int debuglen;
03051    char dummy[1];
03052    va_list aq;
03053    struct cc_core_instance *core_instance;
03054    struct cc_state_change_args *args;
03055    /* This initial call to vsnprintf is simply to find what the
03056     * size of the string needs to be
03057     */
03058    va_copy(aq, ap);
03059    /* We add 1 to the result since vsnprintf's return does not
03060     * include the terminating null byte
03061     */
03062    debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
03063    va_end(aq);
03064 
03065    if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
03066       return -1;
03067    }
03068 
03069    core_instance = find_cc_core_instance(core_id);
03070    if (!core_instance) {
03071       ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n",
03072          core_id);
03073       ast_free(args);
03074       return -1;
03075    }
03076 
03077    args->core_instance = core_instance;
03078    args->state = state;
03079    args->core_id = core_id;
03080    vsnprintf(args->debug, debuglen, debug, ap);
03081 
03082    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
03083    if (res) {
03084       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03085       ast_free(args);
03086    }
03087    return res;
03088 }

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

Definition at line 398 of file ccss.c.

References cc_service_to_string_map.

Referenced by ast_handle_cc_control_frame(), and cc_cli_print_monitor_stats().

00399 {
00400    return cc_service_to_string_map[service].service_string;
00401 }

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

Definition at line 393 of file ccss.c.

References cc_state_to_string_map.

Referenced by cc_do_state_change(), and print_stats_cb().

00394 {
00395    return cc_state_to_string_map[state].state_string;
00396 }

static int cc_status_request ( void *  data  )  [static]

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

03699 {
03700    struct cc_core_instance *core_instance= data;
03701    int res;
03702 
03703    res = core_instance->agent->callbacks->status_request(core_instance->agent);
03704    cc_unref(core_instance, "Status request finished. Unref core instance");
03705    return res;
03706 }

static int cc_status_response ( void *  data  )  [static]

Definition at line 3794 of file ccss.c.

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

Referenced by ast_cc_agent_status_response().

03795 {
03796    struct cc_status_response_args *args = data;
03797    struct cc_core_instance *core_instance = args->core_instance;
03798    struct ast_cc_monitor *monitor_iter;
03799    enum ast_device_state devstate = args->devstate;
03800 
03801    ast_free(args);
03802 
03803    AST_LIST_LOCK(core_instance->monitors);
03804    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03805       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
03806             monitor_iter->callbacks->status_response) {
03807          monitor_iter->callbacks->status_response(monitor_iter, devstate);
03808       }
03809    }
03810    AST_LIST_UNLOCK(core_instance->monitors);
03811    cc_unref(core_instance, "Status response finished. Unref core instance");
03812    return 0;
03813 }

static int cc_stop_ringing ( void *  data  )  [static]

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

03725 {
03726    struct cc_core_instance *core_instance = data;
03727    int res = 0;
03728 
03729    if (core_instance->agent->callbacks->stop_ringing) {
03730       res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
03731    }
03732    /* If an agent is being asked to stop ringing, then he needs to be prepared if for
03733     * whatever reason he needs to be called back again. The proper state to be in to
03734     * detect such a circumstance is the CC_ACTIVE state.
03735     *
03736     * We get to this state using the slightly unintuitive method of calling
03737     * ast_cc_monitor_request_acked because it gets us to the proper state.
03738     */
03739    ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
03740          core_instance->agent->device_name);
03741    cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
03742    return res;
03743 }

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

Definition at line 3277 of file ccss.c.

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

Referenced by build_cc_interfaces_chanvar().

03278 {
03279    char dialstring_search[AST_CHANNEL_NAME];
03280 
03281    if (ast_strlen_zero(dialstring)) {
03282       /* No dialstring to append. */
03283       return;
03284    }
03285    snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
03286    if (strstr(ast_str_buffer(str), dialstring_search)) {
03287       return;
03288    }
03289    ast_str_append(&str, 0, "%s", dialstring_search);
03290 }

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

Definition at line 136 of file ccss.c.

References ao2_t_ref.

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

00137 {
00138    ao2_t_ref(obj, -1, debug);
00139    return NULL;
00140 }

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

Definition at line 4030 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_core_instances, 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().

04031 {
04032    struct cc_core_instance *core_instance;
04033    char device_name[AST_CHANNEL_NAME];
04034    unsigned long match_flags;
04035    int res;
04036 
04037    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04038 
04039    match_flags = MATCH_REQUEST;
04040    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
04041       ast_log_dynamic_level(cc_logger_level, "Cannot find CC transaction to cancel for caller %s\n", device_name);
04042       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04043       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NO_CORE_INSTANCE");
04044       return 0;
04045    }
04046 
04047    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04048       ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
04049       cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04050       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04051       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NOT_GENERIC");
04052       return 0;
04053    }
04054    res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
04055          core_instance->core_id, device_name);
04056    cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04057    pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", res ? "FAIL" : "SUCCESS");
04058    if (res) {
04059       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "UNSPECIFIED");
04060    }
04061    return 0;
04062 }

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

Definition at line 3979 of file ccss.c.

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

Referenced by ast_cc_init().

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

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

Definition at line 2259 of file ccss.c.

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

Referenced by cc_agent_init().

02260 {
02261    ast_assert(callbacks->init != NULL);
02262    ast_assert(callbacks->start_offer_timer != NULL);
02263    ast_assert(callbacks->stop_offer_timer != NULL);
02264    ast_assert(callbacks->respond != NULL);
02265    ast_assert(callbacks->status_request != NULL);
02266    ast_assert(callbacks->start_monitoring != NULL);
02267    ast_assert(callbacks->callee_available != NULL);
02268    ast_assert(callbacks->destructor != NULL);
02269 }

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

Definition at line 4224 of file ccss.c.

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

Referenced by handle_cc_kill().

04225 {
04226    int which = 0;
04227    int wordlen = strlen(word);
04228    char *ret = NULL;
04229    struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
04230    struct cc_core_instance *core_instance;
04231 
04232    for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
04233          cc_unref(core_instance, "CLI tab completion iteration")) {
04234       char core_id_str[20];
04235       snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
04236       if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
04237          ret = ast_strdup(core_id_str);
04238          cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
04239          break;
04240       }
04241    }
04242    ao2_iterator_destroy(&core_iter);
04243 
04244    return ret;
04245 }

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

Definition at line 2233 of file ccss.c.

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

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

02234 {
02235    struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
02236 
02237    ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
02238    ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
02239    return data.count;
02240 }

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

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

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

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

Definition at line 4070 of file ccss.c.

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

Referenced by ast_cc_monitor_count().

04071 {
04072    struct cc_core_instance *core_instance = obj;
04073    struct count_monitors_cb_data *cb_data = arg;
04074    const char *device_name = cb_data->device_name;
04075    const char *monitor_type = cb_data->monitor_type;
04076    struct ast_cc_monitor *monitor_iter;
04077 
04078    AST_LIST_LOCK(core_instance->monitors);
04079    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
04080       if (!strcmp(monitor_iter->interface->device_name, device_name) &&
04081             !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
04082          cb_data->count++;
04083          break;
04084       }
04085    }
04086    AST_LIST_UNLOCK(core_instance->monitors);
04087    return 0;
04088 }

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

Definition at line 1124 of file ccss.c.

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

Referenced by cc_generic_monitor_request_cc().

01125 {
01126    struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
01127          generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
01128 
01129    if (!generic_list) {
01130       return NULL;
01131    }
01132 
01133    if (!(generic_list->device_name = ast_strdup(monitor->interface->device_name))) {
01134       cc_unref(generic_list, "Failed to strdup the monitor's device name");
01135       return NULL;
01136    }
01137 
01138    if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
01139       generic_monitor_devstate_cb, "Requesting CC", NULL,
01140       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, monitor->interface->device_name,
01141       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
01142       AST_EVENT_IE_END))) {
01143       cc_unref(generic_list, "Failed to subscribe to device state");
01144       return NULL;
01145    }
01146    generic_list->current_state = ast_device_state(monitor->interface->device_name);
01147    ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
01148    return generic_list;
01149 }

static void dialed_cc_interfaces_destroy ( void *  data  )  [static]

Definition at line 1664 of file ccss.c.

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

01665 {
01666    struct dialed_cc_interfaces *cc_interfaces = data;
01667    cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
01668    ast_free(cc_interfaces);
01669 }

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

Definition at line 1684 of file ccss.c.

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

01685 {
01686    struct dialed_cc_interfaces *old_cc_interfaces = data;
01687    struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
01688    if (!new_cc_interfaces) {
01689       return NULL;
01690    }
01691    new_cc_interfaces->ignore = old_cc_interfaces->ignore;
01692    new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
01693    new_cc_interfaces->is_original_caller = 0;
01694    cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
01695    new_cc_interfaces->core_id = old_cc_interfaces->core_id;
01696    new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
01697    return new_cc_interfaces;
01698 }

static struct extension_monitor_pvt* extension_monitor_pvt_init ( void   )  [static]

Definition at line 1715 of file ccss.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by cc_extension_monitor_init().

01716 {
01717    struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
01718    if (!ext_pvt) {
01719       return NULL;
01720    }
01721    AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
01722    return ext_pvt;
01723 }

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

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

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

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

Definition at line 417 of file ccss.c.

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

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

00418 {
00419    struct cc_core_instance finder = {.core_id = core_id,};
00420 
00421    return ao2_t_find(cc_core_instances, &finder, OBJ_POINTER, "Finding a core_instance");
00422 }

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

Definition at line 1104 of file ccss.c.

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

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

01105 {
01106    struct generic_monitor_instance_list finder = {.device_name = device_name};
01107 
01108    return ao2_t_find(generic_monitors, &finder, OBJ_POINTER, "Finding generic monitor instance list");
01109 }

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

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

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

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

Definition at line 2500 of file ccss.c.

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

02501 {
02502    struct ast_cc_agent *agent = userdata;
02503    enum ast_device_state new_state;
02504 
02505    new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
02506    if (!cc_generic_is_device_available(new_state)) {
02507       /* Not interested in this new state of the device.  It is still busy. */
02508       return;
02509    }
02510 
02511    /* We can't unsubscribe from device state events here because it causes a deadlock */
02512    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
02513          cc_ref(agent, "ref agent for device state unsubscription"))) {
02514       cc_unref(agent, "Unref agent unsubscribing from devstate failed");
02515    }
02516    ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
02517 }

static int generic_agent_devstate_unsubscribe ( void *  data  )  [static]

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

02489 {
02490    struct ast_cc_agent *agent = data;
02491    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02492 
02493    if (generic_pvt->sub != NULL) {
02494       generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
02495    }
02496    cc_unref(agent, "Done unsubscribing from devstate");
02497    return 0;
02498 }

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

Definition at line 1096 of file ccss.c.

References CMP_MATCH, CMP_STOP, and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01097 {
01098    const struct generic_monitor_instance_list *generic_list1 = obj;
01099    const struct generic_monitor_instance_list *generic_list2 = arg;
01100 
01101    return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
01102 }

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

Definition at line 1204 of file ccss.c.

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

Referenced by create_new_generic_list().

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

static int generic_monitor_devstate_tp_cb ( void *  data  )  [static]

Definition at line 1156 of file ccss.c.

References ast_cc_monitor_callee_available(), AST_DEVICE_BUSY, AST_DEVICE_INUSE, ast_device_state(), 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, generic_tp_cb_data::new_state, and cc_monitor_backend::next.

Referenced by generic_monitor_devstate_cb().

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

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

Definition at line 1090 of file ccss.c.

References ast_str_hash(), and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01091 {
01092    const struct generic_monitor_instance_list *generic_list = obj;
01093    return ast_str_hash(generic_list->device_name);
01094 }

static void generic_monitor_instance_list_destructor ( void *  obj  )  [static]

Definition at line 1111 of file ccss.c.

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

Referenced by create_new_generic_list().

01112 {
01113    struct generic_monitor_instance_list *generic_list = obj;
01114    struct generic_monitor_instance *generic_instance;
01115 
01116    generic_list->sub = ast_event_unsubscribe(generic_list->sub);
01117    while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
01118       ast_free(generic_instance);
01119    }
01120    ast_free((char *)generic_list->device_name);
01121 }

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

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

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

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

Definition at line 4247 of file ccss.c.

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

04248 {
04249    static const char * const option[] = { "core", "all", NULL };
04250 
04251    switch (cmd) {
04252    case CLI_INIT:
04253       e->command = "cc cancel";
04254       e->usage =
04255          "Usage: cc cancel can be used in two ways.\n"
04256          "       1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
04257          "          core ID equal to the specified core ID.\n"
04258          "       2. 'cc cancel all' will cancel all active CC transactions.\n";
04259       return NULL;
04260    case CLI_GENERATE:
04261       if (a->pos == 2) {
04262          return ast_cli_complete(a->word, option, a->n);
04263       }
04264       if (a->pos == 3) {
04265          return complete_core_id(a->line, a->word, a->pos, a->n);
04266       }
04267       return NULL;
04268    }
04269 
04270    if (a->argc == 4) {
04271       int core_id;
04272       char *endptr;
04273       if (strcasecmp(a->argv[2], "core")) {
04274          return CLI_SHOWUSAGE;
04275       }
04276       core_id = strtol(a->argv[3], &endptr, 10);
04277       if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
04278          return CLI_SHOWUSAGE;
04279       }
04280       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, &core_id, "CLI Killing Core Id");
04281    } else if (a->argc == 3) {
04282       if (strcasecmp(a->argv[2], "all")) {
04283          return CLI_SHOWUSAGE;
04284       }
04285       ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, NULL, "CLI Killing all CC cores");
04286    } else {
04287       return CLI_SHOWUSAGE;
04288    }
04289 
04290    return CLI_SUCCESS;
04291 }

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

Definition at line 4180 of file ccss.c.

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

04181 {
04182    int *cli_fd;
04183 
04184    switch (cmd) {
04185    case CLI_INIT:
04186       e->command = "cc report status";
04187       e->usage =
04188          "Usage: cc report status\n"
04189          "       Report the current status of any ongoing CC transactions\n";
04190       return NULL;
04191    case CLI_GENERATE:
04192       return NULL;
04193    }
04194 
04195    if (a->argc != 3) {
04196       return CLI_SHOWUSAGE;
04197    }
04198 
04199    cli_fd = ast_malloc(sizeof(*cli_fd));
04200    if (!cli_fd) {
04201       return CLI_FAILURE;
04202    }
04203 
04204    *cli_fd = a->fd;
04205 
04206    if (ast_taskprocessor_push(cc_core_taskprocessor, cc_cli_output_status, cli_fd)) {
04207       ast_free(cli_fd);
04208       return CLI_FAILURE;
04209    }
04210    return CLI_SUCCESS;
04211 }

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

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

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

02795 {
02796    struct ast_cc_monitor *iter;
02797    int res = 0;
02798 
02799    AST_LIST_TRAVERSE(core_instance->monitors, iter, next) {
02800       if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02801          res = 1;
02802          break;
02803       }
02804    }
02805 
02806    return res;
02807 }

static void initialize_cc_max_requests ( void   )  [static]

Definition at line 4099 of file ccss.c.

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

Referenced by ast_cc_init().

04100 {
04101    struct ast_config *cc_config;
04102    const char *cc_max_requests_str;
04103    struct ast_flags config_flags = {0,};
04104    char *endptr;
04105 
04106    cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
04107    if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
04108       ast_log(LOG_WARNING, "Could not find valid ccss.conf file. Using cc_max_requests default\n");
04109       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04110       return;
04111    }
04112 
04113    if (!(cc_max_requests_str = ast_variable_retrieve(cc_config, "general", "cc_max_requests"))) {
04114       ast_config_destroy(cc_config);
04115       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04116       return;
04117    }
04118 
04119    global_cc_max_requests = strtol(cc_max_requests_str, &endptr, 10);
04120 
04121    if (!ast_strlen_zero(endptr)) {
04122       ast_log(LOG_WARNING, "Invalid input given for cc_max_requests. Using default\n");
04123       global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04124    }
04125 
04126    ast_config_destroy(cc_config);
04127    return;
04128 }

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

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

02699 {
02700    int is_valid = 0;
02701    switch (new_state) {
02702    case CC_AVAILABLE:
02703       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
02704             agent->core_id, new_state);
02705       break;
02706    case CC_CALLER_OFFERED:
02707       if (current_state == CC_AVAILABLE) {
02708          is_valid = 1;
02709       }
02710       break;
02711    case CC_CALLER_REQUESTED:
02712       if (current_state == CC_CALLER_OFFERED ||
02713             (current_state == CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
02714          is_valid = 1;
02715       }
02716       break;
02717    case CC_ACTIVE:
02718       if (current_state == CC_CALLER_REQUESTED || current_state == CC_CALLER_BUSY) {
02719          is_valid = 1;
02720       }
02721       break;
02722    case CC_CALLEE_READY:
02723       if (current_state == CC_ACTIVE) {
02724          is_valid = 1;
02725       }
02726       break;
02727    case CC_CALLER_BUSY:
02728       if (current_state == CC_CALLEE_READY) {
02729          is_valid = 1;
02730       }
02731       break;
02732    case CC_RECALLING:
02733       if (current_state == CC_CALLEE_READY) {
02734          is_valid = 1;
02735       }
02736       break;
02737    case CC_COMPLETE:
02738       if (current_state == CC_RECALLING) {
02739          is_valid = 1;
02740       }
02741       break;
02742    case CC_FAILED:
02743       is_valid = 1;
02744       break;
02745    default:
02746       ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
02747             agent->core_id, new_state);
02748       break;
02749    }
02750 
02751    return is_valid;
02752 }

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

Definition at line 4213 of file ccss.c.

References ast_cc_failed(), and cc_core_instance::core_id.

Referenced by handle_cc_kill().

04214 {
04215    int *core_id = arg;
04216    struct cc_core_instance *core_instance = obj;
04217 
04218    if (!core_id || (core_instance->core_id == *core_id)) {
04219       ast_cc_failed(core_instance->core_id, "CC transaction canceled administratively\n");
04220    }
04221    return 0;
04222 }

static void kill_duplicate_offers ( char *  caller  )  [static]

Definition at line 2242 of file ccss.c.

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

Referenced by cc_core_init_instance().

02243 {
02244    unsigned long match_flags = MATCH_NO_REQUEST;
02245    struct ao2_iterator *dups_iter;
02246 
02247    /*
02248     * Must remove the ref that was in cc_core_instances outside of
02249     * the container lock to prevent deadlock.
02250     */
02251    dups_iter = ao2_t_callback_data(cc_core_instances, OBJ_MULTIPLE | OBJ_UNLINK,
02252       match_agent, caller, &match_flags, "Killing duplicate offers");
02253    if (dups_iter) {
02254       /* Now actually unref any duplicate offers by simply destroying the iterator. */
02255       ao2_iterator_destroy(dups_iter);
02256    }
02257 }

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

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

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

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

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

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

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

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

02419 {
02420    struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
02421    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02422    ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
02423          agent->core_id);
02424    agent_pvt->offer_timer_id = -1;
02425    ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
02426    cc_unref(agent, "Remove scheduler's reference to the agent");
02427    return 0;
02428 }

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

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

04151 {
04152    int *cli_fd = arg;
04153    struct cc_core_instance *core_instance = obj;
04154 
04155    ast_cli(*cli_fd, "%d\t\t%s\t\t%s\n", core_instance->core_id, core_instance->agent->device_name,
04156          cc_state_to_string(core_instance->current_state));
04157    AST_LIST_LOCK(core_instance->monitors);
04158    cc_cli_print_monitor_stats(AST_LIST_FIRST(core_instance->monitors), *cli_fd, 0);
04159    AST_LIST_UNLOCK(core_instance->monitors);
04160    return 0;
04161 }

static void request_cc ( struct cc_core_instance core_instance  )  [static]

Definition at line 2809 of file ccss.c.

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

Referenced by cc_caller_requested().

02810 {
02811    struct ast_cc_monitor *monitor_iter;
02812    AST_LIST_LOCK(core_instance->monitors);
02813    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02814       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02815          if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
02816             AST_LIST_REMOVE_CURRENT(next);
02817             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02818                   monitor_iter->interface->device_name, 1);
02819             cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
02820          } else {
02821             manager_event(EVENT_FLAG_CC, "CCRequested",
02822                "CoreID: %d\r\n"
02823                "Caller: %s\r\n"
02824                "Callee: %s\r\n",
02825                core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
02826          }
02827       }
02828    }
02829    AST_LIST_TRAVERSE_SAFE_END;
02830 
02831    if (!has_device_monitors(core_instance)) {
02832       ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
02833    }
02834    AST_LIST_UNLOCK(core_instance->monitors);
02835 }

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

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

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

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

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

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

static void suspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2904 of file ccss.c.

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

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

02905 {
02906    struct ast_cc_monitor *monitor_iter;
02907    AST_LIST_LOCK(core_instance->monitors);
02908    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02909       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02910          if (monitor_iter->callbacks->suspend(monitor_iter)) {
02911             AST_LIST_REMOVE_CURRENT(next);
02912             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02913                   monitor_iter->interface->device_name, 1);
02914             cc_unref(monitor_iter, "suspend failed. Unref list's reference to monitor");
02915          }
02916       }
02917    }
02918    AST_LIST_TRAVERSE_SAFE_END;
02919 
02920    if (!has_device_monitors(core_instance)) {
02921       ast_cc_failed(core_instance->core_id, "All device monitors failed to suspend CC");
02922    }
02923    AST_LIST_UNLOCK(core_instance->monitors);
02924 }

static void unsuspend ( struct cc_core_instance core_instance  )  [static]

Definition at line 2851 of file ccss.c.

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

Referenced by cc_active().

02852 {
02853    struct ast_cc_monitor *monitor_iter;
02854    AST_LIST_LOCK(core_instance->monitors);
02855    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02856       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02857          if (monitor_iter->callbacks->unsuspend(monitor_iter)) {
02858             AST_LIST_REMOVE_CURRENT(next);
02859             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02860                   monitor_iter->interface->device_name, 1);
02861             cc_unref(monitor_iter, "unsuspend failed. Unref list's reference to monitor");
02862          }
02863       }
02864    }
02865    AST_LIST_TRAVERSE_SAFE_END;
02866 
02867    if (!has_device_monitors(core_instance)) {
02868       ast_cc_failed(core_instance->core_id, "All device monitors failed to unsuspend CC");
02869    }
02870    AST_LIST_UNLOCK(core_instance->monitors);
02871 }


Variable Documentation

struct ast_cli_entry cc_cli[] [static]

Initial value:

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

Definition at line 4293 of file ccss.c.

Referenced by ast_cc_init().

struct ao2_container* cc_core_instances [static]

Definition at line 313 of file ccss.c.

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

const int CC_CORE_INSTANCES_BUCKETS = 17 [static]

Definition at line 312 of file ccss.c.

struct ast_taskprocessor* cc_core_taskprocessor [static]

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

Definition at line 112 of file ccss.c.

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

struct ast_cc_config_params cc_default_params [static]

Definition at line 541 of file ccss.c.

Referenced by ast_cc_default_config_params().

int cc_logger_level [static]

Logger level registered by the CC core.

Definition at line 120 of file ccss.c.

const char* CC_LOGGER_LEVEL_NAME = "CC" [static]

Name printed on all CC log messages.

Definition at line 116 of file ccss.c.

int cc_request_count [static]

The current number of CC requests in the system

Definition at line 128 of file ccss.c.

struct ast_sched_thread* cc_sched_thread [static]

The sched_thread ID used for all generic CC timeouts

Definition at line 102 of file ccss.c.

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

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

Referenced by cc_service_to_string().

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

Referenced by cc_state_to_string().

const char* cccancel_app = "CallCompletionCancel" [static]

Definition at line 4028 of file ccss.c.

const char* ccreq_app = "CallCompletionRequest" [static]

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

int dialed_cc_interface_counter [static]

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

Definition at line 1595 of file ccss.c.

struct ast_datastore_info dialed_cc_interfaces_info [static]

Initial value:

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

Definition at line 1709 of file ccss.c.

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

struct ast_cc_agent_callbacks generic_agent_callbacks [static]

Definition at line 2333 of file ccss.c.

Referenced by ast_cc_init().

struct ast_cc_monitor_callbacks generic_monitor_cbs [static]

Definition at line 1031 of file ccss.c.

Referenced by ast_cc_init().

struct ao2_container* generic_monitors

Definition at line 1040 of file ccss.c.

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

unsigned int global_cc_max_requests [static]

Parsed configuration value for cc_max_requests

Definition at line 124 of file ccss.c.

struct ast_datastore_info recall_ds_info [static]

Initial value:

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

Definition at line 3118 of file ccss.c.

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

enum ast_cc_service_type service

Definition at line 369 of file ccss.c.

const char* service_string

Definition at line 370 of file ccss.c.

enum cc_state state

Definition at line 379 of file ccss.c.

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

Definition at line 2997 of file ccss.c.

Referenced by cc_do_state_change().

const char* state_string

Definition at line 380 of file ccss.c.


Generated on Sat Mar 10 01:54:48 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7