Sat Apr 26 2014 22:01:58

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/devicestate.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/causes.h"
Include dependency graph for ccss.c:

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_ACTIVE_DEVSTATE_DEFAULT   AST_DEVICE_INUSE
#define CC_AVAILABLE_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE
#define CC_CALLEE_READY_DEVSTATE_DEFAULT   AST_DEVICE_RINGING
#define CC_CALLER_BUSY_DEVSTATE_DEFAULT   AST_DEVICE_ONHOLD
#define CC_CALLER_OFFERED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE
#define CC_CALLER_REQUESTED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE
#define CC_COMPLETE_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE
#define CC_FAILED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE
#define CC_MAX_AGENTS_DEFAULT   5
#define CC_MAX_MONITORS_DEFAULT   5
#define CC_OFFER_TIMER_DEFAULT   20 /* Seconds */
#define CC_RECALL_TIMER_DEFAULT   20 /* Seconds */
#define CC_RECALLING_DEVSTATE_DEFAULT   AST_DEVICE_RINGING
#define CCBS_AVAILABLE_TIMER_DEFAULT   4800 /* Seconds */
#define CCNR_AVAILABLE_TIMER_DEFAULT   7200 /* Seconds */
#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

Enumerations

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

Functions

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

struct cc_agent_backends cc_agent_backends
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"
struct cc_monitor_backends cc_monitor_backends
static int cc_request_count
static struct ast_sched_contextcc_sched_context
struct {
   enum ast_cc_service_type   service
   const char *   service_string
cc_service_to_string_map []
static enum ast_device_state cc_state_to_devstate_map []
struct {
   enum cc_state   state
   const char *   state_string
cc_state_to_string_map []
static const char * cccancel_app = "CallCompletionCancel"
static const char * ccreq_app = "CallCompletionRequest"
static int core_id_counter
static int dialed_cc_interface_counter
static struct ast_datastore_info dialed_cc_interfaces_info
static struct
ast_cc_agent_callbacks 
generic_agent_callbacks
static struct
ast_cc_monitor_callbacks 
generic_monitor_cbs
struct ao2_containergeneric_monitors
static unsigned int global_cc_max_requests
static struct ast_datastore_info recall_ds_info
static int(*const state_change_funcs [])(struct cc_core_instance *, struct cc_state_change_args *, enum cc_state previous_state)

Detailed Description

Call Completion Supplementary Services implementation.

Author:
Mark Michelson <mmichelson@digium.com>

Definition in file ccss.c.


Define Documentation

Definition at line 544 of file ccss.c.

Definition at line 541 of file ccss.c.

Definition at line 545 of file ccss.c.

Definition at line 546 of file ccss.c.

Definition at line 542 of file ccss.c.

Definition at line 543 of file ccss.c.

Definition at line 548 of file ccss.c.

Definition at line 549 of file ccss.c.

#define CC_MAX_AGENTS_DEFAULT   5

Definition at line 648 of file ccss.c.

#define CC_MAX_MONITORS_DEFAULT   5

Definition at line 649 of file ccss.c.

#define CC_OFFER_TIMER_DEFAULT   20 /* Seconds */

Definition at line 644 of file ccss.c.

#define CC_RECALL_TIMER_DEFAULT   20 /* Seconds */

Definition at line 647 of file ccss.c.

Definition at line 547 of file ccss.c.

#define CCBS_AVAILABLE_TIMER_DEFAULT   4800 /* Seconds */

Definition at line 646 of file ccss.c.

#define CCNR_AVAILABLE_TIMER_DEFAULT   7200 /* Seconds */

Definition at line 645 of file ccss.c.

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

              {
   /*! Entered when it is determined that CCSS may be used for the call */
   CC_AVAILABLE,
   /*! Entered when a CCSS agent has offered CCSS to a caller */
   CC_CALLER_OFFERED,
   /*! Entered when a CCSS agent confirms that a caller has
    * requested CCSS */
   CC_CALLER_REQUESTED,
   /*! Entered when a CCSS monitor confirms acknowledgment of an
    * outbound CCSS request */
   CC_ACTIVE,
   /*! Entered when a CCSS monitor alerts the core that the called party
    * has become available */
   CC_CALLEE_READY,
   /*! Entered when a CCSS agent alerts the core that the calling party
    * may not be recalled because he is unavailable
    */
   CC_CALLER_BUSY,
   /*! Entered when a CCSS agent alerts the core that the calling party
    * is attempting to recall the called party
    */
   CC_RECALLING,
   /*! Entered when an application alerts the core that the calling party's
    * recall attempt has had a call progress response indicated
    */
   CC_COMPLETE,
   /*! 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.
    */
   CC_FAILED,
};
Enumerator:
MATCH_NO_REQUEST 
MATCH_REQUEST 

Definition at line 461 of file ccss.c.

                 {
   /* Only match agents that have not yet
    * made a CC request
    */
   MATCH_NO_REQUEST = (1 << 0),
   /* Only match agents that have made
    * a CC request
    */
   MATCH_REQUEST = (1 << 1),
};

Function Documentation

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

Allocate and initialize an ast_cc_config_params structure.

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

Definition at line 671 of file ccss.c.

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

{
#if defined(__AST_DEBUG_MALLOC)
   struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
#else
   struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
#endif

   if (!params) {
      return NULL;
   }

   ast_cc_default_config_params(params);
   return params;
}
static void agent_destroy ( void *  data) [static]

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

{
   struct ast_cc_agent *agent = data;

   if (agent->callbacks) {
      agent->callbacks->destructor(agent);
   }
   ast_cc_config_params_destroy(agent->cc_params);
}
static const char* agent_policy_to_str ( enum ast_cc_agent_policies  policy) [static]

Definition at line 722 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, and AST_CC_AGENT_NEVER.

Referenced by ast_cc_get_param().

{
   switch (policy) {
   case AST_CC_AGENT_NEVER:
      return "never";
   case AST_CC_AGENT_NATIVE:
      return "native";
   case AST_CC_AGENT_GENERIC:
      return "generic";
   default:
      /* This should never happen... */
      return "";
   }
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_CALLER_REQUESTED, core_id, debug, ap);
   va_end(ap);
   return res;
}
struct ast_cc_agent* ast_cc_agent_callback ( int  flags,
ao2_callback_fn function,
void *  arg,
const char *const  type 
) [read]

Call a callback on all agents of a specific type.

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

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

Definition at line 448 of file ccss.c.

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

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

{
   struct cc_callback_helper helper = {.function = function, .args = args, .type = type};
   struct cc_core_instance *core_instance;
   if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
               "Calling provided agent callback function"))) {
      struct ast_cc_agent *agent = cc_ref(core_instance->agent, "An outside entity needs the agent");
      cc_unref(core_instance, "agent callback done with the core_instance");
      return agent;
   }
   return NULL;
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
   va_end(ap);
   return res;
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
   va_end(ap);
   return res;
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

Definition at line 3720 of file ccss.c.

References CC_RECALLING, and cc_request_state_change().

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
   va_end(ap);
   return res;
}
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:
callbacksThe callbacks used by the agent implementation
Return values:
0Successfully registered
-1Failure to register

Definition at line 1079 of file ccss.c.

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

Referenced by ast_cc_init(), and load_module().

{
   struct cc_agent_backend *backend = ast_calloc(1, sizeof(*backend));

   if (!backend) {
      return -1;
   }

   backend->callbacks = callbacks;
   AST_RWLIST_WRLOCK(&cc_agent_backends);
   AST_RWLIST_INSERT_TAIL(&cc_agent_backends, backend, next);
   AST_RWLIST_UNLOCK(&cc_agent_backends);
   return 0;
}

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:
chanThe channel to set the CC_INTERFACES variable on

Definition at line 3520 of file ccss.c.

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

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

{
   struct ast_datastore *recall_datastore;
   struct cc_monitor_tree *interface_tree;
   struct ast_cc_monitor *monitor;
   struct cc_recall_ds_data *recall_data;
   struct ast_str *str = ast_str_create(64);
   int core_id;

   if (!str) {
      return -1;
   }

   ast_channel_lock(chan);
   if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
      ast_channel_unlock(chan);
      ast_free(str);
      return -1;
   }
   recall_data = recall_datastore->data;
   interface_tree = recall_data->interface_tree;
   core_id = recall_data->core_id;
   ast_channel_unlock(chan);

   AST_LIST_LOCK(interface_tree);
   monitor = AST_LIST_FIRST(interface_tree);
   build_cc_interfaces_chanvar(monitor, &str);
   AST_LIST_UNLOCK(interface_tree);

   pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
   ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
         core_id, ast_str_buffer(str));

   ast_free(str);
   return 0;
}
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_idThe core ID of the CC transaction
devstateThe current state of the caller to which the agent pertains
Return values:
0Successfully responded with our status
-1Failed to respond with our status

Definition at line 3985 of file ccss.c.

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

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

{
   struct cc_status_response_args *args;
   struct cc_core_instance *core_instance;
   int res;

   args = ast_calloc(1, sizeof(*args));
   if (!args) {
      return -1;
   }

   core_instance = find_cc_core_instance(core_id);
   if (!core_instance) {
      ast_free(args);
      return -1;
   }

   args->core_instance = core_instance;
   args->devstate = devstate;

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
   if (res) {
      cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
      ast_free(args);
   }
   return res;
}
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:
callbacksThe callbacks used by the agent implementation
Return values:
0Successfully unregistered
-1Failure to unregister

Definition at line 1094 of file ccss.c.

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

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

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:
dataA reference to the CC monitor on which the timer was running.

Definition at line 1368 of file ccss.c.

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

Referenced by cc_generic_monitor_request_cc(), and sip_cc_monitor_request_cc().

{
   struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
   int res;
   monitor->available_timer_id = -1;
   res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
   cc_unref(monitor, "Unref reference from scheduler\n");
   return res;
}
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:
chanA channel involved in the call. What we want is on a datastore on both incoming and outgoing so either may be provided
cc_paramsThe CC configuration parameters for the outbound target
monitor_typeThe type of monitor to use when CC is requested
device_nameThe name of the outbound target device.
dialstringThe dial string used when calling this specific interface
serviceWhat kind of CC service is being offered. (CCBS/CCNR/etc...)
private_dataIf 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]frameThe 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:
-1Failure. At some point there was a failure. Do not attempt to use the frame in this case.
0Success

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

{
   struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));

   if (!payload) {
      return -1;
   }
   if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
      /* Something screwed up, we can't make a frame with this */
      ast_free(payload);
      return -1;
   }
   frame->frametype = AST_FRAME_CONTROL;
   frame->subclass.integer = AST_CONTROL_CC;
   frame->data.ptr = payload;
   frame->datalen = sizeof(*payload);
   frame->mallocd = AST_MALLOCD_DATA;
   return 0;
}
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:
inboundIncoming asterisk channel.
cc_paramsThe CC configuration parameters for the outbound target
monitor_typeThe type of monitor to use when CC is requested
device_nameThe name of the outbound target device.
dialstringThe dial string used when calling this specific interface
private_dataIf 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 4124 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().

{
   struct cc_control_payload payload;
   if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
      /* Something screwed up. Don't try to handle this payload */
      call_destructor_with_no_monitor(monitor_type, private_data);
      return;
   }
   ast_handle_cc_control_frame(inbound, NULL, &payload);
}
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 4091 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_hangupcause(), AST_CHANNEL_NAME, ast_get_cc_monitor_policy(), ast_handle_cc_control_frame(), and cc_build_payload().

Referenced by dial_exec_full().

{
   char device_name[AST_CHANNEL_NAME];
   struct cc_control_payload payload;
   struct ast_cc_config_params *cc_params;

   if (ast_channel_hangupcause(outgoing) != AST_CAUSE_BUSY && ast_channel_hangupcause(outgoing) != AST_CAUSE_CONGESTION) {
      /* It doesn't make sense to try to offer CCBS to the caller if the reason for ast_call
       * failing is something other than busy or congestion
       */
      return;
   }

   cc_params = ast_channel_get_cc_config_params(outgoing);
   if (!cc_params) {
      return;
   }
   if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
      /* This sort of CCBS only works if using generic CC. For native, we would end up sending
       * a CC request for a non-existent call. The far end will reject this every time
       */
      return;
   }

   ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
   if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
      dialstring, AST_CC_CCBS, NULL, &payload)) {
      /* Something screwed up, we can't make a frame with this */
      return;
   }
   ast_handle_cc_control_frame(incoming, outgoing, &payload);
}
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:
chanThe inbound channel calling the CC-capable application.
[out]ignore_ccWill be set non-zero if no further CC actions need to be taken
Return values:
0Success
-1Failure

Definition at line 2275 of file ccss.c.

References AST_CC_AGENT_NEVER, ast_channel_context(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_get_cc_config_params(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_macroexten(), ast_channel_name(), 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_cc_monitor::core_id, dialed_cc_interfaces::core_id, ast_datastore::data, dialed_cc_interfaces::dial_parent_id, ast_cc_monitor::id, dialed_cc_interfaces::ignore, dialed_cc_interfaces::interface_tree, interfaces, monitor, and S_OR.

Referenced by dial_exec_full().

{
   /* There are three situations to deal with here:
    *
    * 1. The channel does not have a dialed_cc_interfaces datastore on
    * it. This means that this is the first time that Dial has
    * been called. We need to create/initialize the datastore.
    *
    * 2. The channel does have a cc_interface datastore on it and
    * the "ignore" indicator is 0. This means that a Local channel
    * was called by a "parent" dial. We can check the datastore's
    * parent field to see who the root of this particular dial tree
    * is.
    *
    * 3. The channel does have a cc_interface datastore on it and
    * the "ignore" indicator is 1. This means that a second Dial call
    * is being made from an extension. In this case, we do not
    * want to make any additions/modifications to the datastore. We
    * will instead set a flag to indicate that CCSS is completely
    * disabled for this Dial attempt.
    */

   struct ast_datastore *cc_interfaces_datastore;
   struct dialed_cc_interfaces *interfaces;
   struct ast_cc_monitor *monitor;
   struct ast_cc_config_params *cc_params;

   ast_channel_lock(chan);

   cc_params = ast_channel_get_cc_config_params(chan);
   if (!cc_params) {
      ast_channel_unlock(chan);
      return -1;
   }
   if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
      /* We can't offer CC to this caller anyway, so don't bother with CC on this call
       */
      *ignore_cc = 1;
      ast_channel_unlock(chan);
      ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", ast_channel_name(chan));
      return 0;
   }

   if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
      /* Situation 1 has occurred */
      ast_channel_unlock(chan);
      return cc_interfaces_datastore_init(chan);
   }
   interfaces = cc_interfaces_datastore->data;
   ast_channel_unlock(chan);

   if (interfaces->ignore) {
      /* Situation 3 has occurred */
      *ignore_cc = 1;
      ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
      return 0;
   }

   /* Situation 2 has occurred */
   if (!(monitor = cc_extension_monitor_init(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)),
         S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), interfaces->dial_parent_id))) {
      return -1;
   }
   monitor->core_id = interfaces->core_id;
   AST_LIST_LOCK(interfaces->interface_tree);
   cc_ref(monitor, "monitor tree's reference to the monitor");
   AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
   AST_LIST_UNLOCK(interfaces->interface_tree);
   interfaces->dial_parent_id = monitor->id;
   cc_unref(monitor, "Unref monitor's allocation reference");
   return 0;
}
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
techChannel technology to use
destChannel/group/peer or whatever the specific technology uses
callbackFunction to call when a target is reached
Return values:
Always0, I guess.

Definition at line 4136 of file ccss.c.

References ast_get_channel_tech(), and ast_channel_tech::cc_callback.

Referenced by dial_exec_full().

{
   const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);

   if (chantech && chantech->cc_callback) {
      chantech->cc_callback(inbound, dest, callback);
   }

   return 0;
}
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:
chanThe inbound channel making the CC recall
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

Definition at line 3731 of file ccss.c.

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

Referenced by wait_for_answer().

{
   struct ast_datastore *recall_datastore;
   struct cc_recall_ds_data *recall_data;
   int core_id;
   va_list ap;
   int res;

   ast_channel_lock(chan);
   if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
      /* Silly! Why did you call this function if there's no recall DS? */
      ast_channel_unlock(chan);
      return -1;
   }
   recall_data = recall_datastore->data;
   if (recall_data->nested || recall_data->ignore) {
      /* If this is being called from a nested Dial, it is too
       * early to determine if the recall has actually completed.
       * The outermost dial is the only one with the authority to
       * declare the recall to be complete.
       *
       * Similarly, if this function has been called when the
       * recall has progressed beyond the first dial, this is not
       * a legitimate time to declare the recall to be done. In fact,
       * that should have been done already.
       */
      ast_channel_unlock(chan);
      return -1;
   }
   core_id = recall_data->core_id;
   ast_channel_unlock(chan);
   va_start(ap, debug);
   res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
   va_end(ap);
   return res;
}

Free memory from CCSS configuration params.

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

Definition at line 687 of file ccss.c.

References ast_free.

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

{
   ast_free(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

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:
srcThe structure from which data is copied
destThe structure to which data is copied
Returns:
Nothing

Definition at line 855 of file ccss.c.

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

{
   *dest = *src;
}

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:
paramsCC config params to set to default values.
Returns:
Nothing

Definition at line 666 of file ccss.c.

References cc_default_params.

Referenced by __ast_cc_config_params_init().

{
   *params = cc_default_params;
}
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:
incomingThe caller's channel
dialstringThe dialstring used when requesting the outbound channel
device_nameThe device name associated with the requested outbound channel
Return values:
void

Definition at line 1864 of file ccss.c.

References ast_calloc, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, extension_monitor_pvt::child_dialstrings, ast_datastore::data, extension_child_dialstring::device_name, dialed_cc_interfaces::dial_parent_id, ast_cc_monitor::id, id, dialed_cc_interfaces::interface_tree, extension_child_dialstring::is_valid, monitor, extension_child_dialstring::original_dialstring, and ast_cc_monitor::private_data.

Referenced by dial_exec_full().

{
   struct ast_datastore *cc_datastore;
   struct dialed_cc_interfaces *cc_interfaces;
   struct ast_cc_monitor *monitor;
   struct extension_monitor_pvt *extension_pvt;
   struct extension_child_dialstring *child_dialstring;
   struct cc_monitor_tree *interface_tree;
   int id;

   ast_channel_lock(incoming);
   if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
      ast_channel_unlock(incoming);
      return;
   }

   cc_interfaces = cc_datastore->data;
   interface_tree = cc_interfaces->interface_tree;
   id = cc_interfaces->dial_parent_id;
   ast_channel_unlock(incoming);

   AST_LIST_LOCK(interface_tree);
   AST_LIST_TRAVERSE(interface_tree, monitor, next) {
      if (monitor->id == id) {
         break;
      }
   }

   if (!monitor) {
      AST_LIST_UNLOCK(interface_tree);
      return;
   }

   extension_pvt = monitor->private_data;
   if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
      AST_LIST_UNLOCK(interface_tree);
      return;
   }
   ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
   ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
   child_dialstring->is_valid = 1;
   AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
   AST_LIST_UNLOCK(interface_tree);
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
   va_end(ap);
   return res;
}
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:
chanThe channel from which to get the core_id.
Return values:
core_idon success
-1Failure

Definition at line 2353 of file ccss.c.

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

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

{
   struct ast_datastore *datastore;
   struct dialed_cc_interfaces *cc_interfaces;
   int core_id_return;

   ast_channel_lock(chan);
   if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
      ast_channel_unlock(chan);
      return -1;
   }

   cc_interfaces = datastore->data;
   core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
   ast_channel_unlock(chan);
   return core_id_return;

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

Get the associated monitor given the device name and core_id.

Since:
1.8

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

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

Definition at line 3408 of file ccss.c.

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

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

{
   struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
   struct ast_cc_monitor *monitor_iter;

   if (!core_instance) {
      return NULL;
   }

   AST_LIST_LOCK(core_instance->monitors);
   AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
      if (!strcmp(monitor_iter->interface->device_name, device_name)) {
         /* Found a monitor. */
         cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
         break;
      }
   }
   AST_LIST_UNLOCK(core_instance->monitors);
   cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
   return monitor_iter;
}
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:
paramsThe CCSS configuration from which to get the value
nameThe name of the CCSS parameter we want
bufA preallocated buffer to hold the value
buf_lenThe size of buf
Return values:
0Success
-1Failure

Definition at line 753 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_callback_sub(), 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().

{
   const char *value = NULL;

   if (!strcasecmp(name, "cc_callback_macro")) {
      value = ast_get_cc_callback_macro(params);
   } else if (!strcasecmp(name, "cc_callback_sub")) {
      value = ast_get_cc_callback_sub(params);
   } else if (!strcasecmp(name, "cc_agent_policy")) {
      value = agent_policy_to_str(ast_get_cc_agent_policy(params));
   } else if (!strcasecmp(name, "cc_monitor_policy")) {
      value = monitor_policy_to_str(ast_get_cc_monitor_policy(params));
   } else if (!strcasecmp(name, "cc_agent_dialstring")) {
      value = ast_get_cc_agent_dialstring(params);
   }
   if (value) {
      ast_copy_string(buf, value, buf_len);
      return 0;
   }

   /* The rest of these are all ints of some sort and require some
    * snprintf-itude
    */

   if (!strcasecmp(name, "cc_offer_timer")) {
      snprintf(buf, buf_len, "%u", ast_get_cc_offer_timer(params));
   } else if (!strcasecmp(name, "ccnr_available_timer")) {
      snprintf(buf, buf_len, "%u", ast_get_ccnr_available_timer(params));
   } else if (!strcasecmp(name, "ccbs_available_timer")) {
      snprintf(buf, buf_len, "%u", ast_get_ccbs_available_timer(params));
   } else if (!strcasecmp(name, "cc_max_agents")) {
      snprintf(buf, buf_len, "%u", ast_get_cc_max_agents(params));
   } else if (!strcasecmp(name, "cc_max_monitors")) {
      snprintf(buf, buf_len, "%u", ast_get_cc_max_monitors(params));
   } else if (!strcasecmp(name, "cc_recall_timer")) {
      snprintf(buf, buf_len, "%u", ast_get_cc_recall_timer(params));
   } else {
      ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
      return -1;
   }

   return 0;
}
int ast_cc_init ( void  )

Initialize CCSS.

Since:
1.8 Performs startup routines necessary for CC operation.
Return values:
0Success
nonzeroFailure

Definition at line 4549 of file ccss.c.

References ao2_t_container_alloc, ARRAY_LEN, ast_cc_agent_register(), ast_cc_monitor_register(), ast_cli_register_multiple(), ast_devstate_prov_add(), ast_logger_register_level(), ast_register_application2(), ast_register_atexit(), ast_sched_context_create(), ast_sched_start_thread(), ast_taskprocessor_get(), cc_core_instance_cmp_fn(), cc_core_instance_hash_fn(), cc_shutdown(), cccancel_exec(), ccreq_exec(), ccss_device_state(), generic_monitor_cbs, generic_monitor_cmp_fn(), generic_monitor_hash_fn(), generic_monitors, initialize_cc_devstate_map(), initialize_cc_max_requests(), and TPS_REF_DEFAULT.

Referenced by main().

int ast_cc_is_config_param ( const char *const  name)

Is this a CCSS configuration parameter?

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

Definition at line 840 of file ccss.c.

Referenced by build_peer(), and process_dahdi().

{
   return (!strcasecmp(name, "cc_agent_policy") ||
            !strcasecmp(name, "cc_monitor_policy") ||
            !strcasecmp(name, "cc_offer_timer") ||
            !strcasecmp(name, "ccnr_available_timer") ||
            !strcasecmp(name, "ccbs_available_timer") ||
            !strcasecmp(name, "cc_max_agents") ||
            !strcasecmp(name, "cc_max_monitors") ||
            !strcasecmp(name, "cc_callback_macro") ||
            !strcasecmp(name, "cc_callback_sub") ||
            !strcasecmp(name, "cc_agent_dialstring") ||
            !strcasecmp(name, "cc_recall_timer"));
}
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:
chanThe channel to check
[out]core_idIf this is a valid CC recall, the core_id of the failed call will be placed in this output parameter
monitor_typeClarify 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:
0Either this is not a recall or it is but this channel is not part of the recall
non-zeroThis is a recall and the channel in question is directly involved.

Definition at line 3327 of file ccss.c.

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

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

{
   struct ast_datastore *recall_datastore;
   struct cc_recall_ds_data *recall_data;
   struct cc_monitor_tree *interface_tree;
   char device_name[AST_CHANNEL_NAME];
   struct ast_cc_monitor *device_monitor;
   int core_id_candidate;

   ast_assert(core_id != NULL);

   *core_id = -1;

   ast_channel_lock(chan);
   if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
      /* Obviously not a recall if the datastore isn't present */
      ast_channel_unlock(chan);
      return 0;
   }

   recall_data = recall_datastore->data;

   if (recall_data->ignore) {
      /* Though this is a recall, the call to this particular interface is not part of the
       * recall either because this is a call forward or because this is not the first
       * invocation of Dial during this call
       */
      ast_channel_unlock(chan);
      return 0;
   }

   if (!recall_data->nested) {
      /* If the nested flag is not set, then this means that
       * the channel passed to this function is the caller making
       * the recall. This means that we shouldn't look through
       * the monitor tree for the channel because it shouldn't be
       * there. However, this is a recall though, so return true.
       */
      *core_id = recall_data->core_id;
      ast_channel_unlock(chan);
      return 1;
   }

   if (ast_strlen_zero(monitor_type)) {
      /* If someone passed a NULL or empty monitor type, then it is clear
       * the channel they passed in was an incoming channel, and so searching
       * the list of dialed interfaces is not going to be helpful. Just return
       * false immediately.
       */
      ast_channel_unlock(chan);
      return 0;
   }

   interface_tree = recall_data->interface_tree;
   ast_channel_get_device_name(chan, device_name, sizeof(device_name));
   /* We grab the value of the recall_data->core_id so that we
    * can unlock the channel before we start looking through the
    * interface list. That way we don't have to worry about a possible
    * clash between the channel lock and the monitor tree lock.
    */
   core_id_candidate = recall_data->core_id;
   ast_channel_unlock(chan);

   /*
    * Now we need to find out if the channel device name
    * is in the list of interfaces in the called tree.
    */
   AST_LIST_LOCK(interface_tree);
   AST_LIST_TRAVERSE(interface_tree, device_monitor, next) {
      if (!strcmp(device_monitor->interface->device_name, device_name) &&
            !strcmp(device_monitor->interface->monitor_type, monitor_type)) {
         /* BOOM! Device is in the tree! We have a winner! */
         *core_id = core_id_candidate;
         AST_LIST_UNLOCK(interface_tree);
         return 1;
      }
   }
   AST_LIST_UNLOCK(interface_tree);
   return 0;
}
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_idThe core ID of the corresponding CC transaction
debug
Return values:
0Request successfully queued
-1Request could not be queued

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
   va_end(ap);
   return res;
}
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:
nameThe name of the monitored device
typeThe type of the monitored device (e.g. "generic")
Returns:
The number of CC requests for the monitor

Definition at line 4260 of file ccss.c.

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

Referenced by ast_queue_cc_frame().

{
   struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};

   ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
   ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
   return data.count;
}
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_idThe core ID for the CC transaction
monitor_nameThe name of the monitor on which the failure occurred
debugA debug message to print to the CC log
Returns:
void

Definition at line 3833 of file ccss.c.

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

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

{
   struct ast_cc_monitor_failure_data *failure_data;
   int res;
   va_list ap;

   if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
      return -1;
   }

   if (!(failure_data->device_name = ast_strdup(monitor_name))) {
      ast_free(failure_data);
      return -1;
   }

   va_start(ap, debug);
   if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
      va_end(ap);
      ast_free((char *)failure_data->device_name);
      ast_free(failure_data);
      return -1;
   }
   va_end(ap);

   failure_data->core_id = core_id;

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
   if (res) {
      ast_free((char *)failure_data->device_name);
      ast_free((char *)failure_data->debug);
      ast_free(failure_data);
   }
   return res;
}
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_idThe core ID of the CC transaction
Return values:
0Successfully alerted the core that party B is free
-1Could not alert the core that party B is free

Definition at line 3943 of file ccss.c.

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

Referenced by sig_pri_handle_cis_subcmds().

{
   int res;
   struct cc_core_instance *core_instance = find_cc_core_instance(core_id);

   if (!core_instance) {
      return -1;
   }

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
   if (res) {
      cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
   }
   return res;
}
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:
callbacksThe callbacks used by the monitor implementation
Return values:
0Successfully registered
-1Failure to register

Definition at line 1024 of file ccss.c.

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

Referenced by ast_cc_init(), and load_module().

{
   struct cc_monitor_backend *backend = ast_calloc(1, sizeof(*backend));

   if (!backend) {
      return -1;
   }

   backend->callbacks = callbacks;

   AST_RWLIST_WRLOCK(&cc_monitor_backends);
   AST_RWLIST_INSERT_TAIL(&cc_monitor_backends, backend, next);
   AST_RWLIST_UNLOCK(&cc_monitor_backends);
   return 0;
}
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_idcore_id of the CC transaction
debugoptional string to print for debugging purposes
Return values:
0Success
-1Failure

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

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
   va_end(ap);
   return res;
}
int ast_cc_monitor_status_request ( int  core_id)

Request the status of a caller or callers.

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

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

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

Definition at line 3878 of file ccss.c.

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

Referenced by sig_pri_handle_cis_subcmds().

{
   int res;
   struct cc_core_instance *core_instance = find_cc_core_instance(core_id);

   if (!core_instance) {
      return -1;
   }

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
   if (res) {
      cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
   }
   return res;
}
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_idThe core ID of the CC transaction
Return values:
0Successfully requested for the phone to stop ringing
-1Could not request for the phone to stop ringing

Definition at line 3915 of file ccss.c.

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

Referenced by sig_pri_handle_cis_subcmds().

{
   int res;
   struct cc_core_instance *core_instance = find_cc_core_instance(core_id);

   if (!core_instance) {
      return -1;
   }

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
   if (res) {
      cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
   }
   return res;
}
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:
callbacksThe callbacks used by the monitor implementation
Return values:
0Successfully unregistered
-1Failure to unregister

Definition at line 1057 of file ccss.c.

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

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

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_chanThe calling channel
Return values:
-1Error
0Success

Definition at line 3640 of file ccss.c.

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

Referenced by ast_hangup().

{
   int core_id;
   int res = -1;
   struct ast_datastore *datastore;
   struct dialed_cc_interfaces *cc_interfaces;
   char cc_is_offerable;

   ast_channel_lock(caller_chan);
   if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
      ast_channel_unlock(caller_chan);
      return res;
   }

   cc_interfaces = datastore->data;
   cc_is_offerable = cc_interfaces->is_original_caller;
   core_id = cc_interfaces->core_id;
   ast_channel_unlock(caller_chan);

   if (cc_is_offerable) {
      res = cc_offer(core_id, "CC offered to caller %s", ast_channel_name(caller_chan));
   }
   return res;
}

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:
0Not within the limits. Fail.
non-zeroWithin the limits. Success.

Definition at line 2348 of file ccss.c.

References global_cc_max_requests.

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

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:
paramsThe parameter structure to set the value on
nameThe name of the cc parameter
valueThe value of the parameter
Return values:
0Success
-1Failure

Definition at line 798 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_callback_sub(), ast_set_cc_max_agents(), ast_set_cc_max_monitors(), ast_set_cc_monitor_policy(), ast_set_cc_offer_timer(), ast_set_cc_recall_timer(), ast_set_ccbs_available_timer(), ast_set_ccnr_available_timer(), LOG_WARNING, str_to_agent_policy(), and str_to_monitor_policy().

Referenced by acf_cc_write(), build_peer(), and process_dahdi().

{
   unsigned int value_as_uint;
   if (!strcasecmp(name, "cc_agent_policy")) {
      return ast_set_cc_agent_policy(params, str_to_agent_policy(value));
   } else if (!strcasecmp(name, "cc_monitor_policy")) {
      return ast_set_cc_monitor_policy(params, str_to_monitor_policy(value));
   } else if (!strcasecmp(name, "cc_agent_dialstring")) {
      ast_set_cc_agent_dialstring(params, value);
   } else if (!strcasecmp(name, "cc_callback_macro")) {
      ast_set_cc_callback_macro(params, value);
      return 0;
   } else if (!strcasecmp(name, "cc_callback_sub")) {
      ast_set_cc_callback_sub(params, value);
      return 0;
   }

   if (!sscanf(value, "%30u", &value_as_uint) == 1) {
      return -1;
   }

   if (!strcasecmp(name, "cc_offer_timer")) {
      ast_set_cc_offer_timer(params, value_as_uint);
   } else if (!strcasecmp(name, "ccnr_available_timer")) {
      ast_set_ccnr_available_timer(params, value_as_uint);
   } else if (!strcasecmp(name, "ccbs_available_timer")) {
      ast_set_ccbs_available_timer(params, value_as_uint);
   } else if (!strcasecmp(name, "cc_max_agents")) {
      ast_set_cc_max_agents(params, value_as_uint);
   } else if (!strcasecmp(name, "cc_max_monitors")) {
      ast_set_cc_max_monitors(params, value_as_uint);
   } else if (!strcasecmp(name, "cc_recall_timer")) {
      ast_set_cc_recall_timer(params, value_as_uint);
   } else {
      ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
      return -1;
   }

   return 0;
}
const char* ast_get_cc_agent_dialstring ( struct ast_cc_config_params config)

Get the cc_agent_dialstring.

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

Definition at line 954 of file ccss.c.

References ast_cc_config_params::cc_agent_dialstring.

Referenced by ast_cc_get_param().

{
   return config->cc_agent_dialstring;
}

Get the cc_agent_policy.

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

Definition at line 860 of file ccss.c.

References ast_cc_config_params::cc_agent_policy.

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

{
   return config->cc_agent_policy;
}
const char* ast_get_cc_callback_macro ( struct ast_cc_config_params config)

Get the name of the callback_macro.

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

Definition at line 988 of file ccss.c.

References ast_cc_config_params::cc_callback_macro.

Referenced by ast_cc_get_param(), and generic_recall().

{
   return config->cc_callback_macro;
}
const char* ast_get_cc_callback_sub ( struct ast_cc_config_params config)

Get the name of the callback subroutine.

Since:
11
Parameters:
configThe configuration to retrieve the callback_sub from
Returns:
The callback_sub name

Definition at line 993 of file ccss.c.

References ast_cc_config_params::cc_callback_sub.

Referenced by ast_cc_get_param(), and generic_recall().

{
   return config->cc_callback_sub;
}
unsigned int ast_get_cc_max_agents ( struct ast_cc_config_params config)

Get the cc_max_agents.

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

Definition at line 968 of file ccss.c.

References ast_cc_config_params::cc_max_agents.

Referenced by ast_cc_get_param(), and cc_core_init_instance().

{
   return config->cc_max_agents;
}
unsigned int ast_get_cc_max_monitors ( struct ast_cc_config_params config)

Get the cc_max_monitors.

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

Definition at line 978 of file ccss.c.

References ast_cc_config_params::cc_max_monitors.

Referenced by ast_cc_get_param(), and ast_queue_cc_frame().

{
   return config->cc_max_monitors;
}

Get the cc_monitor_policy.

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

Definition at line 877 of file ccss.c.

References ast_cc_config_params::cc_monitor_policy.

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

{
   return config->cc_monitor_policy;
}
unsigned int ast_get_cc_offer_timer ( struct ast_cc_config_params config)

Get the cc_offer_timer.

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

Definition at line 894 of file ccss.c.

References ast_cc_config_params::cc_offer_timer.

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

{
   return config->cc_offer_timer;
}
unsigned int ast_get_cc_recall_timer ( struct ast_cc_config_params config)

Get the cc_recall_timer.

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

Definition at line 924 of file ccss.c.

References ast_cc_config_params::cc_recall_timer.

Referenced by ast_cc_get_param(), and generic_recall().

{
   return config->cc_recall_timer;
}
unsigned int ast_get_ccbs_available_timer ( struct ast_cc_config_params config)

Get the ccbs_available_timer.

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

Definition at line 939 of file ccss.c.

References ast_cc_config_params::ccbs_available_timer.

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

{
   return config->ccbs_available_timer;
}
unsigned int ast_get_ccnr_available_timer ( struct ast_cc_config_params config)

Get the ccnr_available_timer.

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

Definition at line 909 of file ccss.c.

References ast_cc_config_params::ccnr_available_timer.

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

{
   return config->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.

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

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

{
   char *device_name;
   char *dialstring;
   struct ast_cc_monitor *monitor;
   struct ast_datastore *cc_datastore;
   struct dialed_cc_interfaces *cc_interfaces;
   struct cc_control_payload *cc_data = frame_data;
   struct cc_core_instance *core_instance;

   device_name = cc_data->device_name;
   dialstring = cc_data->dialstring;

   ast_channel_lock(inbound);
   if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
      ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
      ast_channel_unlock(inbound);
      call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
      return;
   }

   cc_interfaces = cc_datastore->data;

   if (cc_interfaces->ignore) {
      ast_channel_unlock(inbound);
      call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
      return;
   }

   if (!cc_interfaces->is_original_caller) {
      /* If the is_original_caller is not set on the *inbound* channel, then
       * it must be a local channel. As such, we do not want to create a core instance
       * or an agent for the local channel. Instead, we want to pass this along to the
       * other side of the local channel so that the original caller can benefit.
       */
      ast_channel_unlock(inbound);
      ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
      return;
   }

   core_instance = find_cc_core_instance(cc_interfaces->core_id);
   if (!core_instance) {
      core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
         cc_interfaces->core_id, cc_data);
      if (!core_instance) {
         cc_interfaces->ignore = 1;
         ast_channel_unlock(inbound);
         call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
         return;
      }
   }

   ast_channel_unlock(inbound);

   /* Yeah this kind of sucks, but luckily most people
    * aren't dialing thousands of interfaces on every call
    *
    * This traversal helps us to not create duplicate monitors in
    * case a device queues multiple CC control frames.
    */
   AST_LIST_LOCK(cc_interfaces->interface_tree);
   AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
      if (!strcmp(monitor->interface->device_name, device_name)) {
         ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
               core_instance->core_id, device_name);
         AST_LIST_UNLOCK(cc_interfaces->interface_tree);
         cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
         call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
         return;
      }
   }
   AST_LIST_UNLOCK(cc_interfaces->interface_tree);

   if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
      ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
      cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
      call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
      return;
   }

   AST_LIST_LOCK(cc_interfaces->interface_tree);
   cc_ref(monitor, "monitor tree's reference to the monitor");
   AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
   AST_LIST_UNLOCK(cc_interfaces->interface_tree);

   cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);

   manager_event(EVENT_FLAG_CC, "CCAvailable",
      "CoreID: %d\r\n"
      "Callee: %s\r\n"
      "Service: %s\r\n",
      cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
   );

   cc_unref(core_instance, "Done with core_instance after handling CC control frame");
   cc_unref(monitor, "Unref reference from allocating monitor");
}
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:
chanThe channel for which further CC processing should be ignored.
Return values:
void

Definition at line 3609 of file ccss.c.

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

Referenced by dial_exec_full(), and do_forward().

{
   struct ast_datastore *cc_datastore;
   struct ast_datastore *cc_recall_datastore;
   struct dialed_cc_interfaces *cc_interfaces;
   struct cc_recall_ds_data *recall_cc_data;

   ast_channel_lock(chan);
   if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
      cc_interfaces = cc_datastore->data;
      cc_interfaces->ignore = 1;
   }

   if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
      recall_cc_data = cc_recall_datastore->data;
      recall_cc_data->ignore = 1;
   }
   ast_channel_unlock(chan);
}
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:
chanThe channel onto which to queue the frame
monitor_typeThe type of monitor to use when CC is requested
dialstringThe dial string used to call the device
serviceThe type of CC service the device is willing to offer
private_dataIf 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:
0Success
-1Error

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

{
   struct ast_frame frame = {0,};
   char device_name[AST_CHANNEL_NAME];
   int retval;
   struct ast_cc_config_params *cc_params;

   cc_params = ast_channel_get_cc_config_params(chan);
   if (!cc_params) {
      return -1;
   }
   ast_channel_get_device_name(chan, device_name, sizeof(device_name));
   if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
      ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
      return -1;
   }

   if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
      /* Frame building failed. We can't use this. */
      return -1;
   }
   retval = ast_queue_frame(chan, &frame);
   ast_frfree(&frame);
   return retval;
}
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:
configThe configuration to set the cc_agent_dialstring on
valueThe new cc_agent_dialstring we want to change to
Return values:
void

Definition at line 959 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   if (ast_strlen_zero(value)) {
      config->cc_agent_dialstring[0] = '\0';
   } else {
      ast_copy_string(config->cc_agent_dialstring, value, sizeof(config->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.

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

Definition at line 865 of file ccss.c.

References AST_CC_AGENT_GENERIC, ast_cc_config_params::cc_agent_policy, and value.

Referenced by ast_cc_set_param(), and build_peer().

{
   /* Screw C and its weak type checking for making me have to do this
    * validation at runtime.
    */
   if (value < AST_CC_AGENT_NEVER || value > AST_CC_AGENT_GENERIC) {
      return -1;
   }
   config->cc_agent_policy = value;
   return 0;
}
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:
configThe configuration to set the callback_macro on
valueThe new callback macro we want to change to
Return values:
void

Definition at line 998 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   ast_log(LOG_WARNING, "Usage of cc_callback_macro is deprecated.  Please use cc_callback_sub instead.\n");
   if (ast_strlen_zero(value)) {
      config->cc_callback_macro[0] = '\0';
   } else {
      ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
   }
}
void ast_set_cc_callback_sub ( struct ast_cc_config_params config,
const char *const  value 
)

Set the callback subroutine name.

Since:
11
Parameters:
configThe configuration to set the callback_sub on
valueThe new callback subroutine we want to change to
Return values:
void

Definition at line 1008 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   if (ast_strlen_zero(value)) {
      config->cc_callback_sub[0] = '\0';
   } else {
      ast_copy_string(config->cc_callback_sub, value, sizeof(config->cc_callback_sub));
   }
}
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:
chanThe channel to set the CC_INTERFACES variable on
extensionThe name of the extension for which we're setting the variable. This should be in the form of "exten@context"

Definition at line 3557 of file ccss.c.

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

Referenced by local_call().

{
   struct ast_datastore *recall_datastore;
   struct cc_monitor_tree *interface_tree;
   struct ast_cc_monitor *monitor_iter;
   struct cc_recall_ds_data *recall_data;
   struct ast_str *str = ast_str_create(64);
   int core_id;

   if (!str) {
      return -1;
   }

   ast_channel_lock(chan);
   if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
      ast_channel_unlock(chan);
      ast_free(str);
      return -1;
   }
   recall_data = recall_datastore->data;
   interface_tree = recall_data->interface_tree;
   core_id = recall_data->core_id;
   ast_channel_unlock(chan);

   AST_LIST_LOCK(interface_tree);
   AST_LIST_TRAVERSE(interface_tree, monitor_iter, next) {
      if (!strcmp(monitor_iter->interface->device_name, extension)) {
         break;
      }
   }

   if (!monitor_iter) {
      /* We couldn't find this extension. This may be because
       * we have been directed into an unexpected extension because
       * the admin has changed a CC_INTERFACES variable at some point.
       */
      AST_LIST_UNLOCK(interface_tree);
      ast_free(str);
      return -1;
   }

   build_cc_interfaces_chanvar(monitor_iter, &str);
   AST_LIST_UNLOCK(interface_tree);

   pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
   ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
         core_id, ast_str_buffer(str));

   ast_free(str);
   return 0;
}
void ast_set_cc_max_agents ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_agents.

Since:
1.8
Parameters:
configThe configuration to set the cc_max_agents on
valueThe new cc_max_agents we want to change to
Return values:
void

Definition at line 973 of file ccss.c.

References ast_cc_config_params::cc_max_agents, and value.

Referenced by ast_cc_set_param().

{
   config->cc_max_agents = value;
}
void ast_set_cc_max_monitors ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_monitors.

Since:
1.8
Parameters:
configThe configuration to set the cc_max_monitors on
valueThe new cc_max_monitors we want to change to
Return values:
void

Definition at line 983 of file ccss.c.

References ast_cc_config_params::cc_max_monitors, and value.

Referenced by ast_cc_set_param().

{
   config->cc_max_monitors = value;
}
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:
configThe configuration to set the cc_monitor_policy on
valueThe new cc_monitor_policy we want to change to
Return values:
0Success
-1Failure (likely due to bad input)

Definition at line 882 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, ast_cc_config_params::cc_monitor_policy, and value.

Referenced by ast_cc_set_param().

{
   /* Screw C and its weak type checking for making me have to do this
    * validation at runtime.
    */
   if (value < AST_CC_MONITOR_NEVER || value > AST_CC_MONITOR_ALWAYS) {
      return -1;
   }
   config->cc_monitor_policy = value;
   return 0;
}
void ast_set_cc_offer_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_offer_timer.

Since:
1.8
Parameters:
configThe configuration to set the cc_offer_timer on
valueThe new cc_offer_timer we want to change to
Return values:
void

Definition at line 899 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   /* 0 is an unreasonable value for any timer. Stick with the default */
   if (value == 0) {
      ast_log(LOG_WARNING, "0 is an invalid value for cc_offer_timer. Retaining value as %u\n", config->cc_offer_timer);
      return;
   }
   config->cc_offer_timer = value;
}
void ast_set_cc_recall_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_recall_timer.

Since:
1.8
Parameters:
configThe configuration to set the cc_recall_timer on
valueThe new cc_recall_timer we want to change to
Return values:
void

Definition at line 929 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   /* 0 is an unreasonable value for any timer. Stick with the default */
   if (value == 0) {
      ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
      return;
   }
   config->cc_recall_timer = value;
}
void ast_set_ccbs_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccbs_available_timer.

Since:
1.8
Parameters:
configThe configuration to set the ccbs_available_timer on
valueThe new ccbs_available_timer we want to change to
Return values:
void

Definition at line 944 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   /* 0 is an unreasonable value for any timer. Stick with the default */
   if (value == 0) {
      ast_log(LOG_WARNING, "0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
      return;
   }
   config->ccbs_available_timer = value;
}
void ast_set_ccnr_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccnr_available_timer.

Since:
1.8
Parameters:
configThe configuration to set the ccnr_available_timer on
valueThe new ccnr_available_timer we want to change to
Return values:
void

Definition at line 914 of file ccss.c.

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

Referenced by ast_cc_set_param().

{
   /* 0 is an unreasonable value for any timer. Stick with the default */
   if (value == 0) {
      ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->ccnr_available_timer);
      return;
   }
   config->ccnr_available_timer = value;
}
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 3294 of file ccss.c.

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

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

{
   struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
   struct cc_recall_ds_data *recall_data;
   struct cc_core_instance *core_instance;

   if (!recall_datastore) {
      return -1;
   }

   if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
      ast_datastore_free(recall_datastore);
      return -1;
   }

   if (!(core_instance = find_cc_core_instance(core_id))) {
      ast_free(recall_data);
      ast_datastore_free(recall_datastore);
      return -1;
   }

   recall_data->interface_tree = cc_ref(core_instance->monitors,
         "Bump refcount for monitor tree for recall datastore");
   recall_data->core_id = core_id;
   recall_datastore->data = recall_data;
   recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
   ast_channel_lock(chan);
   ast_channel_datastore_add(chan, recall_datastore);
   ast_channel_unlock(chan);
   cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
   return 0;
}
static void build_cc_interfaces_chanvar ( struct ast_cc_monitor starting_point,
struct ast_str **  str 
) [static]

Definition at line 3477 of file ccss.c.

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

Referenced by ast_cc_agent_set_interfaces_chanvar(), and ast_set_cc_interfaces_chanvar().

{
   struct extension_monitor_pvt *extension_pvt;
   struct extension_child_dialstring *child_dialstring;
   struct ast_cc_monitor *monitor_iter = starting_point;
   int top_level_id = starting_point->id;
   size_t length;

   /* Init to an empty string. */
   ast_str_truncate(*str, 0);

   /* First we need to take all of the is_valid child_dialstrings from
    * the extension monitor we found and add them to the CC_INTERFACES
    * chanvar
    */
   extension_pvt = starting_point->private_data;
   AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
      if (child_dialstring->is_valid) {
         cc_unique_append(str, child_dialstring->original_dialstring);
      }
   }

   /* And now we get the dialstrings from each of the device monitors */
   while ((monitor_iter = AST_LIST_NEXT(monitor_iter, next))) {
      if (monitor_iter->parent_id == top_level_id) {
         cc_unique_append(str, monitor_iter->dialstring);
      }
   }

   /* str will have an extra '&' tacked onto the end of it, so we need
    * to get rid of that.
    */
   length = ast_str_strlen(*str);
   if (length) {
      ast_str_truncate(*str, length - 1);
   }
   if (length <= 1) {
      /* Nothing to recall?  This should not happen. */
      ast_log(LOG_ERROR, "CC_INTERFACES is empty. starting device_name:'%s'\n",
         starting_point->interface->device_name);
   }
}
static void call_destructor_with_no_monitor ( const char *const  monitor_type,
void *  private_data 
) [static]

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

{
   const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);

   if (!monitor_callbacks) {
      return;
   }

   monitor_callbacks->destructor(private_data);
}
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 3038 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().

{
   /* Either
    * 1. Callee accepted CC request, call agent's ack callback.
    * 2. Caller became available, call agent's stop_monitoring callback and
    *    call monitor's unsuspend callback.
    */
   if (previous_state == CC_CALLER_REQUESTED) {
      core_instance->agent->callbacks->respond(core_instance->agent,
         AST_CC_AGENT_RESPONSE_SUCCESS);
      manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
         "CoreID: %d\r\n"
         "Caller: %s\r\n",
         core_instance->core_id, core_instance->agent->device_name);
   } else if (previous_state == CC_CALLER_BUSY) {
      manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
         "CoreID: %d\r\n"
         "Caller: %s\r\n",
         core_instance->core_id, core_instance->agent->device_name);
      unsuspend(core_instance);
   }
   /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
   return 0;
}
static int cc_agent_callback_helper ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 436 of file ccss.c.

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

{
   struct cc_core_instance *core_instance = obj;
   struct cc_callback_helper *helper = args;

   if (strcmp(core_instance->agent->callbacks->type, helper->type)) {
      return 0;
   }

   return helper->function(core_instance->agent, helper->args, flags);
}
static struct ast_cc_agent* cc_agent_init ( struct ast_channel caller_chan,
const char *const  caller_name,
const int  core_id,
struct cc_monitor_tree interface_tree 
) [static, read]

Definition at line 2420 of file ccss.c.

References agent_destroy(), ao2_t_alloc, ast_cc_config_params_init, ast_cc_copy_config_params(), ast_channel_get_cc_config_params(), ast_log_dynamic_level, ast_cc_agent::callbacks, ast_cc_agent::cc_params, cc_unref(), check_callback_sanity(), ast_cc_agent::core_id, ast_cc_agent::device_name, find_agent_callbacks(), and ast_cc_agent_callbacks::init.

Referenced by cc_core_init_instance().

{
   struct ast_cc_agent *agent;
   struct ast_cc_config_params *cc_params;

   if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
               "Allocating new ast_cc_agent"))) {
      return NULL;
   }

   agent->core_id = core_id;
   strcpy(agent->device_name, caller_name);

   cc_params = ast_channel_get_cc_config_params(caller_chan);
   if (!cc_params) {
      cc_unref(agent, "Could not get channel config params.");
      return NULL;
   }
   if (!(agent->cc_params = ast_cc_config_params_init())) {
      cc_unref(agent, "Could not init agent config params.");
      return NULL;
   }
   ast_cc_copy_config_params(agent->cc_params, cc_params);

   if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
      cc_unref(agent, "Could not find agent callbacks.");
      return NULL;
   }
   check_callback_sanity(agent->callbacks);

   if (agent->callbacks->init(agent, caller_chan)) {
      cc_unref(agent, "Agent init callback failed.");
      return NULL;
   }
   ast_log_dynamic_level(cc_logger_level, "Core %d: Created an agent for caller %s\n",
         agent->core_id, agent->device_name);
   return agent;
}
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 2919 of file ccss.c.

References ast_log(), and LOG_WARNING.

{
   /* This should never happen... */
   ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
   return -1;
}
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]
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 3063 of file ccss.c.

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

{
   core_instance->agent->callbacks->callee_available(core_instance->agent);
   return 0;
}
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 3091 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().

{
   /* Callee was available, but caller was busy, call agent's begin_monitoring callback
    * and call monitor's suspend callback.
    */
   suspend(core_instance);
   core_instance->agent->callbacks->start_monitoring(core_instance->agent);
   manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
      "CoreID: %d\r\n"
      "Caller: %s\r\n",
      core_instance->core_id, core_instance->agent->device_name);
   return 0;
}
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 2926 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.

{
   if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
      ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
            core_instance->agent->device_name);
      return -1;
   }
   manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
      "CoreID: %d\r\n"
      "Caller: %s\r\n"
      "Expires: %u\r\n",
      core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
   ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
         core_instance->core_id, core_instance->agent->device_name);
   return 0;
}
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 3002 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.

{
   if (!ast_cc_request_is_within_limits()) {
      ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
      core_instance->agent->callbacks->respond(core_instance->agent,
         AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY);
      ast_cc_failed(core_instance->core_id, "Too many requests in the system");
      return -1;
   }
   core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
   request_cc(core_instance);
   return 0;
}
static int cc_cli_output_status ( void *  data) [static]

Definition at line 4386 of file ccss.c.

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

Referenced by handle_cc_status().

{
   int *cli_fd = data;
   int count = ao2_container_count(cc_core_instances);

   if (!count) {
      ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
   } else {
      ast_cli(*cli_fd, "%d Call completion transactions\n", count);
      ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
      ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
      ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
   }
   ast_free(cli_fd);
   return 0;
}
static void cc_cli_print_monitor_stats ( struct ast_cc_monitor monitor,
int  fd,
int  parent_id 
) [static]

Definition at line 4353 of file ccss.c.

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

Referenced by print_stats_cb().

{
   struct ast_cc_monitor *child_monitor_iter = monitor;
   if (!monitor) {
      return;
   }

   ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
   if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
      ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
   }
   ast_cli(fd, "\n");

   while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
      if (child_monitor_iter->parent_id == monitor->id) {
         cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
      }
   }
}
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 3139 of file ccss.c.

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

{
   /* Recall has made progress, call agent and monitor destructor functions
    */
   manager_event(EVENT_FLAG_CC, "CCRecallComplete",
      "CoreID: %d\r\n"
      "Caller: %s\r\n",
      core_instance->core_id, core_instance->agent->device_name);
   ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
   return 0;
}
static struct cc_core_instance * cc_core_init_instance ( struct ast_channel caller_chan,
struct cc_monitor_tree called_tree,
const int  core_id,
struct cc_control_payload cc_data 
) [static, read]

Definition at line 2802 of file ccss.c.

References cc_core_instance::agent, ao2_t_alloc, ao2_t_link, AST_CC_AGENT_GENERIC, ast_cc_is_recall(), ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_get_cc_agent_policy(), ast_get_cc_max_agents(), ast_log_dynamic_level, cc_agent_init(), cc_core_instance_destructor(), cc_ref(), cc_unref(), cc_core_instance::core_id, count_agents(), kill_duplicate_offers(), and cc_core_instance::monitors.

Referenced by ast_handle_cc_control_frame().

{
   char caller[AST_CHANNEL_NAME];
   struct cc_core_instance *core_instance;
   struct ast_cc_config_params *cc_params;
   long agent_count;
   int recall_core_id;

   ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
   cc_params = ast_channel_get_cc_config_params(caller_chan);
   if (!cc_params) {
      ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
         caller);
      return NULL;
   }
   /* First, we need to kill off other pending CC offers from caller. If the caller is going
    * to request a CC service, it may only be for the latest call he made.
    */
   if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
      kill_duplicate_offers(caller);
   }

   ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
   agent_count = count_agents(caller, recall_core_id);
   if (agent_count >= ast_get_cc_max_agents(cc_params)) {
      ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
      return NULL;
   }

   /* Generic agents can only have a single outstanding CC request per caller. */
   if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
      ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
      return NULL;
   }

   /* Next, we need to create the core instance for this call */
   if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
      return NULL;
   }

   core_instance->core_id = core_id;
   if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
      cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
      return NULL;
   }

   core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");

   ao2_t_link(cc_core_instances, core_instance, "Link core instance into container");

   return core_instance;
}
static int cc_core_instance_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 415 of file ccss.c.

References CMP_MATCH, CMP_STOP, and cc_core_instance::core_id.

Referenced by ast_cc_init().

{
   struct cc_core_instance *core_instance1 = obj;
   struct cc_core_instance *core_instance2 = arg;

   return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
}
static void cc_core_instance_destructor ( void *  data) [static]

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

{
   struct cc_core_instance *core_instance = data;
   ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
   if (core_instance->agent) {
      cc_unref(core_instance->agent, "Core instance is done with the agent now");
   }
   if (core_instance->monitors) {
      core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
   }
}
static int cc_core_instance_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 409 of file ccss.c.

References cc_core_instance::core_id.

Referenced by ast_cc_init().

{
   const struct cc_core_instance *core_instance = obj;
   return core_instance->core_id;
}
static struct ast_cc_monitor* cc_device_monitor_init ( const char *const  device_name,
const char *const  dialstring,
const struct cc_control_payload cc_data,
int  core_id 
) [static, read]

Definition at line 2111 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), ast_cc_config_params_init, ast_cc_copy_config_params(), AST_CC_DEVICE_MONITOR, ast_log_dynamic_level, ast_strdup, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), cc_control_payload::config_params, ast_cc_interface::config_params, ast_cc_monitor::core_id, ast_cc_interface::device_name, ast_cc_monitor::dialstring, find_monitor_callbacks(), ast_cc_monitor::id, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, cc_control_payload::monitor_type, ast_cc_interface::monitor_type, ast_cc_monitor::parent_id, cc_control_payload::parent_interface_id, cc_control_payload::private_data, ast_cc_monitor::private_data, cc_control_payload::service, and ast_cc_monitor::service_offered.

Referenced by ast_handle_cc_control_frame().

{
   struct ast_cc_interface *cc_interface;
   struct ast_cc_monitor *monitor;
   size_t device_name_len = strlen(device_name);
   int parent_id = cc_data->parent_interface_id;

   if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
               "Allocating new ast_cc_interface"))) {
      return NULL;
   }

   if (!(cc_interface->config_params = ast_cc_config_params_init())) {
      cc_unref(cc_interface, "Failed to allocate config params, unref interface");
      return NULL;
   }

   if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
      cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
      return NULL;
   }

   if (!(monitor->dialstring = ast_strdup(dialstring))) {
      cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
      cc_unref(cc_interface, "Failed to copy dialable name");
      return NULL;
   }

   if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
      cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
      cc_unref(cc_interface, "Failed to find monitor callbacks");
      return NULL;
   }

   strcpy(cc_interface->device_name, device_name);
   monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
   monitor->parent_id = parent_id;
   monitor->core_id = core_id;
   monitor->service_offered = cc_data->service;
   monitor->private_data = cc_data->private_data;
   cc_interface->monitor_type = cc_data->monitor_type;
   cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
   monitor->interface = cc_interface;
   monitor->available_timer_id = -1;
   ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
   ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %d and parent %d\n",
         monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
   return monitor;
}
static int cc_do_state_change ( void *  datap) [static]

Definition at line 3174 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(), ccss_notify_device_state_change(), cc_state_change_args::core_id, cc_state_change_args::core_instance, cc_core_instance::current_state, cc_state_change_args::debug, is_state_change_valid(), ast_cc_agent_callbacks::respond, cc_state_change_args::state, and state_change_funcs.

Referenced by cc_request_state_change().

{
   struct cc_state_change_args *args = datap;
   struct cc_core_instance *core_instance;
   enum cc_state previous_state;
   int res;

   ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
         args->core_id, args->state, args->debug);

   core_instance = args->core_instance;

   if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
            args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
      if (args->state == CC_CALLER_REQUESTED) {
         /*
          * For out-of-order requests, we need to let the requester know that
          * we can't handle the request now.
          */
         core_instance->agent->callbacks->respond(core_instance->agent,
            AST_CC_AGENT_RESPONSE_FAILURE_INVALID);
      }
      ast_free(args);
      cc_unref(core_instance, "Unref core instance from when it was found earlier");
      return -1;
   }

   /* We can change to the new state now. */
   previous_state = core_instance->current_state;
   core_instance->current_state = args->state;
   res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);

   /* If state change successful then notify any device state watchers of the change */
   if (!res && !strcmp(core_instance->agent->callbacks->type, "generic")) {
      ccss_notify_device_state_change(core_instance->agent->device_name, core_instance->current_state);
   }

   ast_free(args);
   cc_unref(core_instance, "Unref since state change has completed"); /* From ao2_find */
   return res;
}
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 1909 of file ccss.c.

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

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

{
   struct ast_cc_monitor *monitor_iter;
   struct extension_monitor_pvt *extension_pvt;
   struct extension_child_dialstring *child_dialstring;

   AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
      if (monitor_iter->id == parent_id) {
         break;
      }
   }

   if (!monitor_iter) {
      return;
   }
   extension_pvt = monitor_iter->private_data;

   AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
      if (!strcmp(child_dialstring->device_name, device_name)) {
         child_dialstring->is_valid = is_valid;
         break;
      }
   }
}
static void cc_extension_monitor_destructor ( void *  private_data) [static]

Definition at line 1680 of file ccss.c.

References ast_free, AST_LIST_REMOVE_HEAD, and extension_monitor_pvt::child_dialstrings.

Referenced by cc_monitor_destroy().

{
   struct extension_monitor_pvt *extension_pvt = private_data;
   struct extension_child_dialstring *child_dialstring;

   /* This shouldn't be possible, but I'm paranoid */
   if (!extension_pvt) {
      return;
   }

   while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
      ast_free(child_dialstring);
   }
   ast_free(extension_pvt);
}
static struct ast_cc_monitor* cc_extension_monitor_init ( const char *const  exten,
const char *const  context,
const unsigned int  parent_id 
) [static, read]

Definition at line 1948 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), AST_CC_EXTENSION_MONITOR, ast_log_dynamic_level, AST_MAX_EXTENSION, ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_str_strlen(), cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), ast_cc_interface::device_name, extension_monitor_pvt_init(), ast_cc_monitor::id, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, ast_cc_interface::monitor_type, ast_cc_monitor::parent_id, ast_cc_monitor::private_data, and str.

Referenced by ast_cc_call_init(), and cc_interfaces_datastore_init().

{
   struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
   struct ast_cc_interface *cc_interface;
   struct ast_cc_monitor *monitor;

   ast_str_set(&str, 0, "%s@%s", exten, context);

   if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
               "Allocating new ast_cc_interface"))) {
      return NULL;
   }

   if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
      cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
      return NULL;
   }

   if (!(monitor->private_data = extension_monitor_pvt_init())) {
      cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
      cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
   }

   monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
   monitor->parent_id = parent_id;
   cc_interface->monitor_type = "extension";
   cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
   strcpy(cc_interface->device_name, ast_str_buffer(str));
   monitor->interface = cc_interface;
   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);
   return monitor;
}
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 3151 of file ccss.c.

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

{
   manager_event(EVENT_FLAG_CC, "CCFailure",
      "CoreID: %d\r\n"
      "Caller: %s\r\n"
      "Reason: %s\r\n",
      core_instance->core_id, core_instance->agent->device_name, args->debug);
   ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
   return 0;
}
static void cc_generic_agent_destructor ( struct ast_cc_agent agent) [static]

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

{
   struct cc_generic_agent_pvt *agent_pvt = agent->private_data;

   if (!agent_pvt) {
      /* The agent constructor probably failed. */
      return;
   }

   cc_generic_agent_stop_offer_timer(agent);
   if (agent_pvt->sub) {
      agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
   }

   ast_free(agent_pvt);
}
static int cc_generic_agent_init ( struct ast_cc_agent agent,
struct ast_channel chan 
) [static]

Definition at line 2535 of file ccss.c.

References ast_calloc, AST_CC_AGENT_SKIP_OFFER, ast_channel_caller(), ast_channel_context(), ast_channel_exten(), ast_channel_macrocontext(), ast_channel_macroexten(), ast_copy_string(), ast_set_flag, cc_generic_agent_pvt::cid_name, cc_generic_agent_pvt::cid_num, cc_generic_agent_pvt::context, cc_generic_agent_pvt::exten, name, cc_generic_agent_pvt::offer_timer_id, ast_cc_agent::private_data, and S_OR.

{
   struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));

   if (!generic_pvt) {
      return -1;
   }

   generic_pvt->offer_timer_id = -1;
   if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
      ast_copy_string(generic_pvt->cid_num, ast_channel_caller(chan)->id.number.str, sizeof(generic_pvt->cid_num));
   }
   if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
      ast_copy_string(generic_pvt->cid_name, ast_channel_caller(chan)->id.name.str, sizeof(generic_pvt->cid_name));
   }
   ast_copy_string(generic_pvt->exten, S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)), sizeof(generic_pvt->exten));
   ast_copy_string(generic_pvt->context, S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), sizeof(generic_pvt->context));
   agent->private_data = generic_pvt;
   ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
   return 0;
}
static int cc_generic_agent_recall ( struct ast_cc_agent agent) [static]

Definition at line 2757 of file ccss.c.

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

{
   pthread_t clotho;
   enum ast_device_state current_state = ast_device_state(agent->device_name);

   if (!cc_generic_is_device_available(current_state)) {
      /* We can't try to contact the device right now because he's not available
       * Let the core know he's busy.
       */
      ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
      return 0;
   }
   ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
   return 0;
}
static void cc_generic_agent_respond ( struct ast_cc_agent agent,
enum ast_cc_agent_response_reason  reason 
) [static]

Definition at line 2601 of file ccss.c.

{
   /* The generic agent doesn't have to do anything special to
    * acknowledge a CC request. Just return.
    */
   return;
}
static int cc_generic_agent_start_offer_timer ( struct ast_cc_agent agent) [static]

Definition at line 2569 of file ccss.c.

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

{
   int when;
   int sched_id;
   struct cc_generic_agent_pvt *generic_pvt = agent->private_data;

   ast_assert(cc_sched_context != NULL);
   ast_assert(agent->cc_params != NULL);

   when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
   ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
         agent->core_id, when);
   if ((sched_id = ast_sched_add(cc_sched_context, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
      return -1;
   }
   generic_pvt->offer_timer_id = sched_id;
   return 0;
}
static int cc_generic_agent_status_request ( struct ast_cc_agent agent) [static]
static int cc_generic_agent_stop_offer_timer ( struct ast_cc_agent agent) [static]

Definition at line 2588 of file ccss.c.

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

Referenced by cc_generic_agent_destructor().

{
   struct cc_generic_agent_pvt *generic_pvt = agent->private_data;

   if (generic_pvt->offer_timer_id != -1) {
      if (!ast_sched_del(cc_sched_context, generic_pvt->offer_timer_id)) {
         cc_unref(agent, "Remove scheduler's reference to the agent");
      }
      generic_pvt->offer_timer_id = -1;
   }
   return 0;
}
static int cc_generic_agent_stop_ringing ( struct ast_cc_agent agent) [static]

Definition at line 2615 of file ccss.c.

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

{
   struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));

   if (!recall_chan) {
      return 0;
   }

   ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
   return 0;
}
static int cc_generic_monitor_cancel_available_timer ( struct ast_cc_monitor monitor,
int *  sched_id 
) [static]

Definition at line 1510 of file ccss.c.

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

{
   ast_assert(sched_id != NULL);

   if (*sched_id == -1) {
      return 0;
   }

   ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
         monitor->core_id, monitor->interface->device_name);
   if (!ast_sched_del(cc_sched_context, *sched_id)) {
      cc_unref(monitor, "Remove scheduler's reference to the monitor");
   }
   *sched_id = -1;
   return 0;
}
static void cc_generic_monitor_destructor ( void *  private_data) [static]

Definition at line 1527 of file ccss.c.

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

{
   struct generic_monitor_pvt *gen_mon_pvt = private_data;
   struct generic_monitor_instance_list *generic_list;
   struct generic_monitor_instance *generic_instance;

   if (!private_data) {
      /* If the private data is NULL, that means that the monitor hasn't even
       * been created yet, but that the destructor was called. While this sort
       * of behavior is useful for native monitors, with a generic one, there is
       * nothing in particular to do.
       */
      return;
   }

   ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying generic monitor %s\n",
         gen_mon_pvt->core_id, gen_mon_pvt->device_name);

   if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->device_name))) {
      /* If there's no generic list, that means that the monitor is being destroyed
       * before we actually got to request CC. Not a biggie. Same in the situation
       * below if the list traversal should complete without finding an entry.
       */
      ast_free((char *)gen_mon_pvt->device_name);
      ast_free(gen_mon_pvt);
      return;
   }

   AST_LIST_TRAVERSE_SAFE_BEGIN(&generic_list->list, generic_instance, next) {
      if (generic_instance->core_id == gen_mon_pvt->core_id) {
         AST_LIST_REMOVE_CURRENT(next);
         ast_free(generic_instance);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;

   if (AST_LIST_EMPTY(&generic_list->list)) {
      /* No more monitors with this device name exist. Time to unlink this
       * list from the container
       */
      ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
   } else {
      /* There are still instances for this particular device. The situation
       * may be that we were attempting a CC recall and a failure occurred, perhaps
       * on the agent side. If a failure happens here and the device being monitored
       * is available, then we need to signal on the first unsuspended instance that
       * the device is available for recall.
       */

      /* First things first. We don't even want to consider this action if
       * the device in question isn't available right now.
       */
      if (generic_list->fit_for_recall
         && cc_generic_is_device_available(generic_list->current_state)) {
         AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
            if (!generic_instance->is_suspended && generic_instance->monitoring) {
               ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
                     "availability due to other instance's failure.");
               break;
            }
         }
      }
   }
   cc_unref(generic_list, "Done with generic list in generic monitor destructor");
   ast_free((char *)gen_mon_pvt->device_name);
   ast_free(gen_mon_pvt);
}
static int cc_generic_monitor_request_cc ( struct ast_cc_monitor monitor,
int *  available_timer_id 
) [static]

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

{
   struct generic_monitor_instance_list *generic_list;
   struct generic_monitor_instance *generic_instance;
   struct generic_monitor_pvt *gen_mon_pvt;
   enum ast_cc_service_type service = monitor->service_offered;
   int when;

   /* First things first. Native channel drivers will have their private data allocated
    * at the time that they tell the core that they can offer CC. Generic is quite a bit
    * different, and we wait until this point to allocate our private data.
    */
   if (!(gen_mon_pvt = ast_calloc(1, sizeof(*gen_mon_pvt)))) {
      return -1;
   }

   if (!(gen_mon_pvt->device_name = ast_strdup(monitor->interface->device_name))) {
      ast_free(gen_mon_pvt);
      return -1;
   }

   gen_mon_pvt->core_id = monitor->core_id;

   monitor->private_data = gen_mon_pvt;

   if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
      if (!(generic_list = create_new_generic_list(monitor))) {
         return -1;
      }
   }

   if (!(generic_instance = ast_calloc(1, sizeof(*generic_instance)))) {
      /* The generic monitor destructor will take care of the appropriate
       * deallocations
       */
      cc_unref(generic_list, "Generic monitor instance failed to allocate");
      return -1;
   }
   generic_instance->core_id = monitor->core_id;
   generic_instance->monitoring = 1;
   AST_LIST_INSERT_TAIL(&generic_list->list, generic_instance, next);
   when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
      ast_get_ccnr_available_timer(monitor->interface->config_params);

   *available_timer_id = ast_sched_add(cc_sched_context, when * 1000,
         ast_cc_available_timer_expire, cc_ref(monitor, "Give the scheduler a monitor reference"));
   if (*available_timer_id == -1) {
      cc_unref(monitor, "Failed to schedule available timer. (monitor)");
      cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
      return -1;
   }
   /* If the new instance was created as CCNR, then that means this device is not currently
    * fit for recall even if it previously was.
    */
   if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
      generic_list->fit_for_recall = 0;
   }
   ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
         monitor->interface->device_name);
   cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
   return 0;
}
static int cc_generic_monitor_suspend ( struct ast_cc_monitor monitor) [static]

Definition at line 1441 of file ccss.c.

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

{
   struct generic_monitor_instance_list *generic_list;
   struct generic_monitor_instance *generic_instance;
   enum ast_device_state state = ast_device_state(monitor->interface->device_name);

   if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
      return -1;
   }

   /* First we need to mark this particular monitor as being suspended. */
   AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
      if (generic_instance->core_id == monitor->core_id) {
         generic_instance->is_suspended = 1;
         break;
      }
   }

   /* If the device being suspended is currently in use, then we don't need to
    * take any further actions
    */
   if (!cc_generic_is_device_available(state)) {
      cc_unref(generic_list, "Device is in use. Nothing to do. Unref generic list.");
      return 0;
   }

   /* If the device is not in use, though, then it may be possible to report the
    * device's availability using a different monitor which is monitoring the
    * same device
    */

   AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
      if (!generic_instance->is_suspended) {
         ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
         break;
      }
   }
   cc_unref(generic_list, "Done with generic list in suspend callback");
   return 0;
}
static int cc_generic_monitor_unsuspend ( struct ast_cc_monitor monitor) [static]

Definition at line 1482 of file ccss.c.

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

{
   struct generic_monitor_instance *generic_instance;
   struct generic_monitor_instance_list *generic_list = find_generic_monitor_instance_list(monitor->interface->device_name);
   enum ast_device_state state = ast_device_state(monitor->interface->device_name);

   if (!generic_list) {
      return -1;
   }
   /* If the device is currently available, we can immediately announce
    * its availability
    */
   if (cc_generic_is_device_available(state)) {
      ast_cc_monitor_callee_available(monitor->core_id, "Generic monitored party has become available");
   }

   /* In addition, we need to mark this generic_monitor_instance as not being suspended anymore */
   AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
      if (generic_instance->core_id == monitor->core_id) {
         generic_instance->is_suspended = 0;
         generic_instance->monitoring = 1;
         break;
      }
   }
   cc_unref(generic_list, "Done with generic list in cc_generic_monitor_unsuspend");
   return 0;
}
static void cc_interface_destroy ( void *  data) [static]

Definition at line 1596 of file ccss.c.

References ast_cc_config_params_destroy(), and ast_log_dynamic_level.

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

{
   struct ast_cc_interface *interface = data;
   ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
   ast_cc_config_params_destroy(interface->config_params);
}
static void cc_interface_tree_destroy ( void *  data) [static]

Definition at line 1717 of file ccss.c.

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

Referenced by cc_interfaces_datastore_init().

{
   struct cc_monitor_tree *cc_interface_tree = data;
   struct ast_cc_monitor *monitor;
   while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
      if (monitor->callbacks) {
         monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
      }
      cc_unref(monitor, "Destroying all monitors");
   }
   AST_LIST_HEAD_DESTROY(cc_interface_tree);
}
static int cc_interfaces_datastore_init ( struct ast_channel chan) [static]

Definition at line 1997 of file ccss.c.

References ao2_t_alloc, ast_atomic_fetchadd_int(), ast_calloc, ast_cc_request_is_within_limits(), ast_channel_context(), ast_channel_datastore_add(), ast_channel_exten(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_macroexten(), 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_cc_monitor::core_id, dialed_cc_interfaces::core_id, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dialed_cc_interfaces::dial_parent_id, ast_cc_monitor::id, ast_datastore::inheritance, dialed_cc_interfaces::interface_tree, interfaces, dialed_cc_interfaces::is_original_caller, monitor, and S_OR.

Referenced by ast_cc_call_init().

                                                                  {
   struct dialed_cc_interfaces *interfaces;
   struct ast_cc_monitor *monitor;
   struct ast_datastore *dial_cc_datastore;

   /*XXX This may be a bit controversial. In an attempt to not allocate
    * extra resources, I make sure that a future request will be within
    * limits. The problem here is that it is reasonable to think that
    * even if we're not within the limits at this point, we may be by
    * the time the requestor will have made his request. This may be
    * deleted at some point.
    */
   if (!ast_cc_request_is_within_limits()) {
      return 0;
   }

   if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
      return -1;
   }

   if (!(monitor = cc_extension_monitor_init(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)), S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), 0))) {
      ast_free(interfaces);
      return -1;
   }

   if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
      cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
      ast_free(interfaces);
      return -1;
   }

   if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
               "Allocate monitor tree"))) {
      ast_datastore_free(dial_cc_datastore);
      cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
      ast_free(interfaces);
      return -1;
   }

   /* Finally, all that allocation is done... */
   AST_LIST_HEAD_INIT(interfaces->interface_tree);
   AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
   cc_ref(monitor, "List's reference to extension monitor");
   dial_cc_datastore->data = interfaces;
   dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
   interfaces->dial_parent_id = monitor->id;
   interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
   interfaces->is_original_caller = 1;
   ast_channel_lock(chan);
   ast_channel_datastore_add(chan, dial_cc_datastore);
   ast_channel_unlock(chan);
   cc_unref(monitor, "Unreffing allocation's reference");
   return 0;
}
static void cc_monitor_destroy ( void *  data) [static]

Definition at line 1696 of file ccss.c.

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

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

{
   struct ast_cc_monitor *monitor = data;
   /* During the monitor creation process, it is possible for this
    * function to be called prior to when callbacks are assigned
    * to the monitor. Also, extension monitors do not have callbacks
    * assigned to them, so we wouldn't want to segfault when we try
    * to destroy one of them.
    */
   ast_log_dynamic_level(cc_logger_level, "Core %d: Calling destructor for monitor %s\n",
         monitor->core_id, monitor->interface->device_name);
   if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
      cc_extension_monitor_destructor(monitor->private_data);
   }
   if (monitor->callbacks) {
      monitor->callbacks->destructor(monitor->private_data);
   }
   cc_unref(monitor->interface, "Unreffing tree's reference to interface");
   ast_free(monitor->dialstring);
}
static int cc_monitor_failed ( void *  data) [static]

Definition at line 3785 of file ccss.c.

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

Referenced by ast_cc_monitor_failed().

{
   struct ast_cc_monitor_failure_data *failure_data = data;
   struct cc_core_instance *core_instance;
   struct ast_cc_monitor *monitor_iter;

   core_instance = find_cc_core_instance(failure_data->core_id);
   if (!core_instance) {
      /* Core instance no longer exists or invalid core_id. */
      ast_log_dynamic_level(cc_logger_level,
         "Core %d: Could not find core instance for device %s '%s'\n",
         failure_data->core_id, failure_data->device_name, failure_data->debug);
      ast_free((char *) failure_data->device_name);
      ast_free((char *) failure_data->debug);
      ast_free(failure_data);
      return -1;
   }

   AST_LIST_LOCK(core_instance->monitors);
   AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
      if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
         if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
            AST_LIST_REMOVE_CURRENT(next);
            cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
                  monitor_iter->interface->device_name, 1);
            monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
            manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
               "CoreID: %d\r\n"
               "Callee: %s\r\n",
               monitor_iter->core_id, monitor_iter->interface->device_name);
            cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
         }
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;

   if (!has_device_monitors(core_instance)) {
      ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
   }
   AST_LIST_UNLOCK(core_instance->monitors);
   cc_unref(core_instance, "Finished with core_instance in cc_monitor_failed\n");

   ast_free((char *) failure_data->device_name);
   ast_free((char *) failure_data->debug);
   ast_free(failure_data);
   return 0;
}
static int cc_offer ( const int  core_id,
const char *const  debug,
  ... 
) [static]

Definition at line 3629 of file ccss.c.

References CC_CALLER_OFFERED, and cc_request_state_change().

Referenced by ast_cc_offer().

{
   va_list ap;
   int res;

   va_start(ap, debug);
   res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
   va_end(ap);
   return res;
}
static int cc_party_b_free ( void *  data) [static]

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

{
   struct cc_core_instance *core_instance = data;
   int res = 0;

   if (core_instance->agent->callbacks->party_b_free) {
      res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
   }
   cc_unref(core_instance, "Party B free finished. Unref core_instance");
   return res;
}
static void cc_recall_ds_destroy ( void *  data) [static]

Definition at line 3281 of file ccss.c.

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

{
   struct cc_recall_ds_data *recall_data = data;
   recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
   ast_free(recall_data);
}
static void* cc_recall_ds_duplicate ( void *  data) [static]

Definition at line 3267 of file ccss.c.

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

{
   struct cc_recall_ds_data *old_data = data;
   struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));

   if (!new_data) {
      return NULL;
   }
   new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
   new_data->core_id = old_data->core_id;
   new_data->nested = 1;
   return new_data;
}
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 3127 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.

{
   /* Both caller and callee are available, call agent's recall callback
    */
   cancel_available_timer(core_instance);
   manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
      "CoreID: %d\r\n"
      "Caller: %s\r\n",
      core_instance->core_id, core_instance->agent->device_name);
   return 0;
}
static int cc_request_state_change ( enum cc_state  state,
const int  core_id,
const char *  debug,
va_list  ap 
) [static]

Definition at line 3217 of file ccss.c.

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

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

{
   int res;
   int debuglen;
   char dummy[1];
   va_list aq;
   struct cc_core_instance *core_instance;
   struct cc_state_change_args *args;
   /* This initial call to vsnprintf is simply to find what the
    * size of the string needs to be
    */
   va_copy(aq, ap);
   /* We add 1 to the result since vsnprintf's return does not
    * include the terminating null byte
    */
   debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
   va_end(aq);

   if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
      return -1;
   }

   core_instance = find_cc_core_instance(core_id);
   if (!core_instance) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n",
         core_id);
      ast_free(args);
      return -1;
   }

   args->core_instance = core_instance;
   args->state = state;
   args->core_id = core_id;
   vsnprintf(args->debug, debuglen, debug, ap);

   res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
   if (res) {
      cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
      ast_free(args);
   }
   return res;
}
static const char* cc_service_to_string ( enum ast_cc_service_type  service) [static]

Definition at line 404 of file ccss.c.

References cc_service_to_string_map, and service.

Referenced by ast_handle_cc_control_frame(), and cc_cli_print_monitor_stats().

{
   return cc_service_to_string_map[service].service_string;
}
static enum ast_device_state cc_state_to_devstate ( enum cc_state  state) [static]

lookup the ast_device_state mapped to cc_state

Returns:
the correponding DEVICE STATE from the cc_state_to_devstate_map when passed an internal state.

Definition at line 574 of file ccss.c.

References state.

Referenced by ccss_device_state(), and ccss_notify_device_state_change().

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

Definition at line 399 of file ccss.c.

References cc_state_to_string_map, and state.

Referenced by cc_do_state_change(), ccss_device_state(), ccss_notify_device_state_change(), and print_stats_cb().

{
   return cc_state_to_string_map[state].state_string;
}
static int cc_status_request ( void *  data) [static]

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

{
   struct cc_core_instance *core_instance= data;
   int res;

   res = core_instance->agent->callbacks->status_request(core_instance->agent);
   cc_unref(core_instance, "Status request finished. Unref core instance");
   return res;
}
static int cc_status_response ( void *  data) [static]

Definition at line 3964 of file ccss.c.

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

Referenced by ast_cc_agent_status_response().

{
   struct cc_status_response_args *args = data;
   struct cc_core_instance *core_instance = args->core_instance;
   struct ast_cc_monitor *monitor_iter;
   enum ast_device_state devstate = args->devstate;

   ast_free(args);

   AST_LIST_LOCK(core_instance->monitors);
   AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
      if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
            monitor_iter->callbacks->status_response) {
         monitor_iter->callbacks->status_response(monitor_iter, devstate);
      }
   }
   AST_LIST_UNLOCK(core_instance->monitors);
   cc_unref(core_instance, "Status response finished. Unref core instance");
   return 0;
}
static int cc_stop_ringing ( void *  data) [static]

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

{
   struct cc_core_instance *core_instance = data;
   int res = 0;

   if (core_instance->agent->callbacks->stop_ringing) {
      res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
   }
   /* If an agent is being asked to stop ringing, then he needs to be prepared if for
    * whatever reason he needs to be called back again. The proper state to be in to
    * detect such a circumstance is the CC_ACTIVE state.
    *
    * We get to this state using the slightly unintuitive method of calling
    * ast_cc_monitor_request_acked because it gets us to the proper state.
    */
   ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
         core_instance->agent->device_name);
   cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
   return res;
}
static void cc_unique_append ( struct ast_str **  str,
const char *  dialstring 
) [static]

Definition at line 3447 of file ccss.c.

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

Referenced by build_cc_interfaces_chanvar().

{
   char dialstring_search[AST_CHANNEL_NAME];

   if (ast_strlen_zero(dialstring)) {
      /* No dialstring to append. */
      return;
   }
   snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
   if (strstr(ast_str_buffer(*str), dialstring_search)) {
      return;
   }
   ast_str_append(str, 0, "%s", dialstring_search);
}
static int cccancel_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 4200 of file ccss.c.

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

Referenced by ast_cc_init().

{
   struct cc_core_instance *core_instance;
   char device_name[AST_CHANNEL_NAME];
   unsigned long match_flags;
   int res;

   ast_channel_get_device_name(chan, device_name, sizeof(device_name));

   match_flags = MATCH_REQUEST;
   if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
      ast_log_dynamic_level(cc_logger_level, "Cannot find CC transaction to cancel for caller %s\n", device_name);
      pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
      pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NO_CORE_INSTANCE");
      return 0;
   }

   if (strcmp(core_instance->agent->callbacks->type, "generic")) {
      ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
      cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
      pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
      pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NOT_GENERIC");
      return 0;
   }
   res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
         core_instance->core_id, device_name);
   cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
   pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", res ? "FAIL" : "SUCCESS");
   if (res) {
      pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "UNSPECIFIED");
   }
   return 0;
}
static int ccreq_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 4149 of file ccss.c.

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

Referenced by ast_cc_init().

{
   struct cc_core_instance *core_instance;
   char device_name[AST_CHANNEL_NAME];
   unsigned long match_flags;
   int res;

   ast_channel_get_device_name(chan, device_name, sizeof(device_name));

   match_flags = MATCH_NO_REQUEST;
   if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionRequest"))) {
      ast_log_dynamic_level(cc_logger_level, "Couldn't find a core instance for caller %s\n", device_name);
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NO_CORE_INSTANCE");
      return 0;
   }

   ast_log_dynamic_level(cc_logger_level, "Core %d: Found core_instance for caller %s\n",
         core_instance->core_id, device_name);

   if (strcmp(core_instance->agent->callbacks->type, "generic")) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest is only for generic agent types.\n",
            core_instance->core_id);
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NOT_GENERIC");
      cc_unref(core_instance, "Unref core_instance since CallCompletionRequest was called with native agent");
      return 0;
   }

   if (!ast_cc_request_is_within_limits()) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest failed. Too many requests in the system\n",
            core_instance->core_id);
      ast_cc_failed(core_instance->core_id, "Too many CC requests\n");
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "TOO_MANY_REQUESTS");
      cc_unref(core_instance, "Unref core_instance since too many CC requests");
      return 0;
   }

   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);
   pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", res ? "FAIL" : "SUCCESS");
   if (res) {
      pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "UNSPECIFIED");
   }

   cc_unref(core_instance, "Done with CallCompletionRequest");
   return 0;
}
static enum ast_device_state ccss_device_state ( const char *  device_name) [static]

Definition at line 590 of file ccss.c.

References cc_core_instance::agent, ao2_t_callback_data, ast_log_dynamic_level, ast_cc_agent::callbacks, CC_FAILED, cc_state_to_devstate(), cc_state_to_string(), cc_unref(), cc_core_instance::core_id, cc_core_instance::current_state, match_agent(), MATCH_NO_REQUEST, and ast_cc_agent_callbacks::type.

Referenced by ast_cc_init().

{
   struct cc_core_instance *core_instance;
   unsigned long match_flags;
   enum ast_device_state cc_current_state;

   match_flags = MATCH_NO_REQUEST;
   core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent,
      (char *) device_name, &match_flags,
      "Find Core Instance for ccss_device_state reqeust.");
   if (!core_instance) {
      ast_log_dynamic_level(cc_logger_level,
         "Couldn't find a core instance for caller %s\n", device_name);
      return cc_state_to_devstate(CC_FAILED);
   }

   ast_log_dynamic_level(cc_logger_level,
      "Core %d: Found core_instance for caller %s in state %s\n",
      core_instance->core_id, device_name, cc_state_to_string(core_instance->current_state));

   if (strcmp(core_instance->agent->callbacks->type, "generic")) {
      ast_log_dynamic_level(cc_logger_level,
         "Core %d: Device State is only for generic agent types.\n",
         core_instance->core_id);
      cc_unref(core_instance, "Unref core_instance since ccss_device_state was called with native agent");
      return cc_state_to_devstate(CC_FAILED);
   }
   cc_current_state = cc_state_to_devstate(core_instance->current_state);
   cc_unref(core_instance, "Unref core_instance done with ccss_device_state");
   return cc_current_state;
}
static void ccss_notify_device_state_change ( const char *  device,
enum cc_state  state 
) [static]

Definition at line 631 of file ccss.c.

References ast_devstate2str(), AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_log_dynamic_level, cc_state_to_devstate(), and cc_state_to_string().

Referenced by cc_do_state_change().

{
   enum ast_device_state devstate;

   devstate = cc_state_to_devstate(state);

   ast_log_dynamic_level(cc_logger_level,
      "Notification of CCSS state change to '%s', device state '%s' for device '%s'\n",
      cc_state_to_string(state), ast_devstate2str(devstate), device);

   ast_devstate_changed(devstate, AST_DEVSTATE_CACHABLE, "ccss:%s", device);
}
static char* complete_core_id ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 4447 of file ccss.c.

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

Referenced by handle_cc_kill().

{
   int which = 0;
   int wordlen = strlen(word);
   char *ret = NULL;
   struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
   struct cc_core_instance *core_instance;

   for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
         cc_unref(core_instance, "CLI tab completion iteration")) {
      char core_id_str[20];
      snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
      if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
         ret = ast_strdup(core_id_str);
         cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
         break;
      }
   }
   ao2_iterator_destroy(&core_iter);

   return ret;
}
static long count_agents ( const char *const  caller,
const int  core_id_exception 
) [static]
static int count_agents_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

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

{
   struct cc_core_instance *core_instance = obj;
   const char *name = arg;
   struct count_agents_cb_data *cb_data = data;

   if (cb_data->core_id_exception == core_instance->core_id) {
      ast_log_dynamic_level(cc_logger_level, "Found agent with core_id %d but not counting it toward total\n", core_instance->core_id);
      return 0;
   }

   if (core_instance->current_state >= CC_CALLER_REQUESTED && !strcmp(core_instance->agent->device_name, name)) {
      cb_data->count++;
   }
   return 0;
}
static int count_monitors_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 4240 of file ccss.c.

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

Referenced by ast_cc_monitor_count().

{
   struct cc_core_instance *core_instance = obj;
   struct count_monitors_cb_data *cb_data = arg;
   const char *device_name = cb_data->device_name;
   const char *monitor_type = cb_data->monitor_type;
   struct ast_cc_monitor *monitor_iter;

   AST_LIST_LOCK(core_instance->monitors);
   AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
      if (!strcmp(monitor_iter->interface->device_name, device_name) &&
            !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
         cb_data->count++;
         break;
      }
   }
   AST_LIST_UNLOCK(core_instance->monitors);
   return 0;
}
static struct generic_monitor_instance_list* create_new_generic_list ( struct ast_cc_monitor monitor) [static, read]

Definition at line 1260 of file ccss.c.

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

Referenced by cc_generic_monitor_request_cc().

{
   struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
         generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
   char * device_name;

   if (!generic_list) {
      return NULL;
   }

   if (!(device_name = ast_strdup(monitor->interface->device_name))) {
      cc_unref(generic_list, "Failed to strdup the monitor's device name");
      return NULL;
   }
   ast_tech_to_upper(device_name);
   generic_list->device_name = device_name;

   if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
      generic_monitor_devstate_cb, "Requesting CC", NULL,
      AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, monitor->interface->device_name,
      AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
      AST_EVENT_IE_END))) {
      cc_unref(generic_list, "Failed to subscribe to device state");
      return NULL;
   }
   generic_list->current_state = ast_device_state(monitor->interface->device_name);
   ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
   return generic_list;
}
static void dialed_cc_interfaces_destroy ( void *  data) [static]

Definition at line 1803 of file ccss.c.

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

{
   struct dialed_cc_interfaces *cc_interfaces = data;
   cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
   ast_free(cc_interfaces);
}
static void* dialed_cc_interfaces_duplicate ( void *  data) [static]

Definition at line 1823 of file ccss.c.

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

{
   struct dialed_cc_interfaces *old_cc_interfaces = data;
   struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
   if (!new_cc_interfaces) {
      return NULL;
   }
   new_cc_interfaces->ignore = old_cc_interfaces->ignore;
   new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
   new_cc_interfaces->is_original_caller = 0;
   cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
   new_cc_interfaces->core_id = old_cc_interfaces->core_id;
   new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
   return new_cc_interfaces;
}
static struct extension_monitor_pvt* extension_monitor_pvt_init ( void  ) [static, read]

Definition at line 1854 of file ccss.c.

References ast_calloc, AST_LIST_HEAD_INIT_NOLOCK, and extension_monitor_pvt::child_dialstrings.

Referenced by cc_extension_monitor_init().

{
   struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
   if (!ext_pvt) {
      return NULL;
   }
   AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
   return ext_pvt;
}
static struct ast_cc_agent_callbacks* find_agent_callbacks ( struct ast_channel chan) [static, read]

Definition at line 1109 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_monitor_backend::callbacks, cc_agent_backend::callbacks, cc_monitor_backend::next, type, and ast_cc_agent_callbacks::type.

Referenced by cc_agent_init().

{
   struct cc_agent_backend *backend;
   const struct ast_cc_agent_callbacks *callbacks = NULL;
   struct ast_cc_config_params *cc_params;
   char type[32];

   cc_params = ast_channel_get_cc_config_params(chan);
   if (!cc_params) {
      return NULL;
   }
   switch (ast_get_cc_agent_policy(cc_params)) {
   case AST_CC_AGENT_GENERIC:
      ast_copy_string(type, "generic", sizeof(type));
      break;
   case AST_CC_AGENT_NATIVE:
      ast_channel_get_cc_agent_type(chan, type, sizeof(type));
      break;
   default:
      ast_log_dynamic_level(cc_logger_level, "Not returning agent callbacks since this channel is configured not to have a CC agent\n");
      return NULL;
   }

   AST_RWLIST_RDLOCK(&cc_agent_backends);
   AST_RWLIST_TRAVERSE(&cc_agent_backends, backend, next) {
      if (!strcmp(backend->callbacks->type, type)) {
         ast_log_dynamic_level(cc_logger_level, "Returning agent backend %s\n", backend->callbacks->type);
         callbacks = backend->callbacks;
         break;
      }
   }
   AST_RWLIST_UNLOCK(&cc_agent_backends);
   return callbacks;
}
static struct generic_monitor_instance_list* find_generic_monitor_instance_list ( const char *const  device_name) [static, read]
static struct ast_cc_monitor_callbacks* find_monitor_callbacks ( const char *const  type) [static, read]

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

{
   struct cc_monitor_backend *backend;
   const struct ast_cc_monitor_callbacks *callbacks = NULL;

   AST_RWLIST_RDLOCK(&cc_monitor_backends);
   AST_RWLIST_TRAVERSE(&cc_monitor_backends, backend, next) {
      if (!strcmp(backend->callbacks->type, type)) {
         ast_log_dynamic_level(cc_logger_level, "Returning monitor backend %s\n", backend->callbacks->type);
         callbacks = backend->callbacks;
         break;
      }
   }
   AST_RWLIST_UNLOCK(&cc_monitor_backends);
   return callbacks;
}
static void generic_agent_devstate_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 2639 of file ccss.c.

References ast_cc_agent_caller_available(), ast_event_get_ie_uint(), AST_EVENT_IE_STATE, ast_taskprocessor_push(), cc_generic_is_device_available(), cc_ref(), cc_unref(), ast_cc_agent::core_id, ast_cc_agent::device_name, and generic_agent_devstate_unsubscribe().

Referenced by cc_generic_agent_start_monitoring().

{
   struct ast_cc_agent *agent = userdata;
   enum ast_device_state new_state;

   new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
   if (!cc_generic_is_device_available(new_state)) {
      /* Not interested in this new state of the device.  It is still busy. */
      return;
   }

   /* We can't unsubscribe from device state events here because it causes a deadlock */
   if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
         cc_ref(agent, "ref agent for device state unsubscription"))) {
      cc_unref(agent, "Unref agent unsubscribing from devstate failed");
   }
   ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
}
static int generic_agent_devstate_unsubscribe ( void *  data) [static]

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

{
   struct ast_cc_agent *agent = data;
   struct cc_generic_agent_pvt *generic_pvt = agent->private_data;

   if (generic_pvt->sub != NULL) {
      generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
   }
   cc_unref(agent, "Done unsubscribing from devstate");
   return 0;
}
static int generic_monitor_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1229 of file ccss.c.

References CMP_MATCH, CMP_STOP, and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

{
   const struct generic_monitor_instance_list *generic_list1 = obj;
   const struct generic_monitor_instance_list *generic_list2 = arg;

   return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
}
static void generic_monitor_devstate_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 1343 of file ccss.c.

References ast_calloc, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_strdup, ast_taskprocessor_push(), generic_tp_cb_data::device_name, generic_monitor_devstate_tp_cb(), and generic_tp_cb_data::new_state.

Referenced by create_new_generic_list().

{
   /* Wow, it's cool that we've picked up on a state change, but we really want
    * the actual work to be done in the core's taskprocessor execution thread
    * so that all monitor operations can be serialized. Locks?! We don't need
    * no steenkin' locks!
    */
   struct generic_tp_cb_data *gtcd = ast_calloc(1, sizeof(*gtcd));

   if (!gtcd) {
      return;
   }

   if (!(gtcd->device_name = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE)))) {
      ast_free(gtcd);
      return;
   }
   gtcd->new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);

   if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, gtcd)) {
      ast_free((char *)gtcd->device_name);
      ast_free(gtcd);
   }
}
static int generic_monitor_devstate_tp_cb ( void *  data) [static]

Definition at line 1295 of file ccss.c.

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

Referenced by generic_monitor_devstate_cb().

{
   struct generic_tp_cb_data *gtcd = data;
   enum ast_device_state new_state = gtcd->new_state;
   enum ast_device_state previous_state = gtcd->new_state;
   const char *monitor_name = gtcd->device_name;
   struct generic_monitor_instance_list *generic_list;
   struct generic_monitor_instance *generic_instance;

   if (!(generic_list = find_generic_monitor_instance_list(monitor_name))) {
      /* The most likely cause for this is that we destroyed the monitor in the
       * time between subscribing to its device state and the time this executes.
       * Not really a big deal.
       */
      ast_free((char *) gtcd->device_name);
      ast_free(gtcd);
      return 0;
   }

   if (generic_list->current_state == new_state) {
      /* The device state hasn't actually changed, so we don't really care */
      cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
      ast_free((char *) gtcd->device_name);
      ast_free(gtcd);
      return 0;
   }

   previous_state = generic_list->current_state;
   generic_list->current_state = new_state;

   if (cc_generic_is_device_available(new_state) &&
         (previous_state == AST_DEVICE_INUSE || previous_state == AST_DEVICE_UNAVAILABLE ||
          previous_state == AST_DEVICE_BUSY)) {
      AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
         if (!generic_instance->is_suspended && generic_instance->monitoring) {
            generic_instance->monitoring = 0;
            generic_list->fit_for_recall = 1;
            ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
            break;
         }
      }
   }
   cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
   ast_free((char *) gtcd->device_name);
   ast_free(gtcd);
   return 0;
}
static int generic_monitor_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 1223 of file ccss.c.

References ast_str_hash(), and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

{
   const struct generic_monitor_instance_list *generic_list = obj;
   return ast_str_hash(generic_list->device_name);
}
static void generic_monitor_instance_list_destructor ( void *  obj) [static]

Definition at line 1247 of file ccss.c.

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

Referenced by create_new_generic_list().

{
   struct generic_monitor_instance_list *generic_list = obj;
   struct generic_monitor_instance *generic_instance;

   generic_list->sub = ast_event_unsubscribe(generic_list->sub);
   while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
      ast_free(generic_instance);
   }
   ast_free((char *)generic_list->device_name);
}
static void* generic_recall ( void *  data) [static]

Definition at line 2677 of file ccss.c.

References ast_app_exec_macro(), ast_app_exec_sub(), ast_cc_agent_recalling(), ast_cc_agent_set_interfaces_chanvar(), ast_cc_failed(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_priority_set(), ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_set(), AST_FORMAT_SLINEAR, ast_get_cc_callback_macro(), ast_get_cc_callback_sub(), ast_get_cc_recall_timer(), ast_hangup(), ast_log_dynamic_level, ast_pbx_start(), ast_request_and_dial(), ast_setup_cc_recall_datastore(), ast_strlen_zero(), cc_generic_agent_pvt::cid_name, cc_generic_agent_pvt::cid_num, cc_generic_agent_pvt::context, cc_generic_agent_pvt::exten, pbx_builtin_setvar_helper(), ast_cc_agent::private_data, and S_OR.

Referenced by cc_generic_agent_recall().

{
   struct ast_cc_agent *agent = data;
   struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
   const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
   const char *tech;
   char *target;
   int reason;
   struct ast_channel *chan;
   const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
   const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params);
   unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
   struct ast_format tmp_fmt;
   struct ast_format_cap *tmp_cap = ast_format_cap_alloc_nolock();

   if (!tmp_cap) {
      return NULL;
   }

   tech = interface;
   if ((target = strchr(interface, '/'))) {
      *target++ = '\0';
   }

   ast_format_cap_add(tmp_cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
   if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
      /* Hmm, no channel. Sucks for you, bud.
       */
      ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
            agent->core_id, agent->device_name, reason);
      ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
      ast_format_cap_destroy(tmp_cap);
      return NULL;
   }
   ast_format_cap_destroy(tmp_cap);
   
   /* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
    * This will be a common task for all recall functions. If it were possible, I'd have
    * the core do it automatically, but alas I cannot. Instead, I will provide a public
    * function to do so.
    */
   ast_setup_cc_recall_datastore(chan, agent->core_id);
   ast_cc_agent_set_interfaces_chanvar(chan);

   ast_channel_exten_set(chan, generic_pvt->exten);
   ast_channel_context_set(chan, generic_pvt->context);
   ast_channel_priority_set(chan, 1);

   pbx_builtin_setvar_helper(chan, "CC_EXTEN", generic_pvt->exten);
   pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);

   if (!ast_strlen_zero(callback_macro)) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
            agent->core_id, agent->device_name);
      if (ast_app_exec_macro(NULL, chan, callback_macro)) {
         ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
         ast_hangup(chan);
         return NULL;
      }
   }

   if (!ast_strlen_zero(callback_sub)) {
      ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback subroutine configured for agent %s\n",
            agent->core_id, agent->device_name);
      if (ast_app_exec_sub(NULL, chan, callback_sub, 0)) {
         ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name);
         ast_hangup(chan);
         return NULL;
      }
   }
   if (ast_pbx_start(chan)) {
      ast_cc_failed(agent->core_id, "PBX failed to start for %s.", agent->device_name);
      ast_hangup(chan);
      return NULL;
   }
   ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling",
      agent->device_name);
   return NULL;
}
static char* handle_cc_kill ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4470 of file ccss.c.

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

{
   static const char * const option[] = { "core", "all", NULL };

   switch (cmd) {
   case CLI_INIT:
      e->command = "cc cancel";
      e->usage =
         "Usage: cc cancel can be used in two ways.\n"
         "       1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
         "          core ID equal to the specified core ID.\n"
         "       2. 'cc cancel all' will cancel all active CC transactions.\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 2) {
         return ast_cli_complete(a->word, option, a->n);
      }
      if (a->pos == 3) {
         return complete_core_id(a->line, a->word, a->pos, a->n);
      }
      return NULL;
   }

   if (a->argc == 4) {
      int core_id;
      char *endptr;
      if (strcasecmp(a->argv[2], "core")) {
         return CLI_SHOWUSAGE;
      }
      core_id = strtol(a->argv[3], &endptr, 10);
      if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
         return CLI_SHOWUSAGE;
      }
      ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, &core_id, "CLI Killing Core Id");
   } else if (a->argc == 3) {
      if (strcasecmp(a->argv[2], "all")) {
         return CLI_SHOWUSAGE;
      }
      ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, NULL, "CLI Killing all CC cores");
   } else {
      return CLI_SHOWUSAGE;
   }

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

Definition at line 4403 of file ccss.c.

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

{
   int *cli_fd;

   switch (cmd) {
   case CLI_INIT:
      e->command = "cc report status";
      e->usage =
         "Usage: cc report status\n"
         "       Report the current status of any ongoing CC transactions\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }

   cli_fd = ast_malloc(sizeof(*cli_fd));
   if (!cli_fd) {
      return CLI_FAILURE;
   }

   *cli_fd = a->fd;

   if (ast_taskprocessor_push(cc_core_taskprocessor, cc_cli_output_status, cli_fd)) {
      ast_free(cli_fd);
      return CLI_FAILURE;
   }
   return CLI_SUCCESS;
}
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_instanceThe core instance we are checking for the existence of device monitors
Return values:
0No device monitors exist on this core_instance
1There is still at least 1 device monitor remaining

Definition at line 2959 of file ccss.c.

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

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

{
   struct ast_cc_monitor *iter;
   int res = 0;

   AST_LIST_TRAVERSE(core_instance->monitors, iter, next) {
      if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
         res = 1;
         break;
      }
   }

   return res;
}
static void initialize_cc_devstate_map ( void  ) [static]

Definition at line 4328 of file ccss.c.

References ast_config_destroy(), ast_config_load2(), ast_log(), CC_ACTIVE, CC_AVAILABLE, CC_CALLEE_READY, CC_CALLER_BUSY, CC_CALLER_OFFERED, CC_CALLER_REQUESTED, CC_COMPLETE, CC_FAILED, CC_RECALLING, CONFIG_STATUS_FILEINVALID, initialize_cc_devstate_map_helper(), and LOG_WARNING.

Referenced by ast_cc_init().

{
   struct ast_config *cc_config;
   struct ast_flags config_flags = { 0, };

   cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
   if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING,
         "Could not find valid ccss.conf file. Using cc_[state]_devstate defaults\n");
      return;
   }

   initialize_cc_devstate_map_helper(cc_config, CC_AVAILABLE, "cc_available_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_CALLER_OFFERED, "cc_caller_offered_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_CALLER_REQUESTED, "cc_caller_requested_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_ACTIVE, "cc_active_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_CALLEE_READY, "cc_callee_ready_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_CALLER_BUSY, "cc_caller_busy_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_RECALLING, "cc_recalling_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_COMPLETE, "cc_complete_devstate");
   initialize_cc_devstate_map_helper(cc_config, CC_FAILED, "cc_failed_devstate");

   ast_config_destroy(cc_config);
}
static void initialize_cc_devstate_map_helper ( struct ast_config cc_config,
enum cc_state  state,
const char *  cc_setting 
) [static]

Definition at line 4304 of file ccss.c.

References AST_DEVICE_UNKNOWN, ast_devstate_val(), ast_variable_retrieve(), and state.

Referenced by initialize_cc_devstate_map().

{
   const char *cc_devstate_str;
   enum ast_device_state this_devstate;

   if ((cc_devstate_str = ast_variable_retrieve(cc_config, "general", cc_setting))) {
      this_devstate = ast_devstate_val(cc_devstate_str);
      if (this_devstate != AST_DEVICE_UNKNOWN) {
         cc_state_to_devstate_map[state] = this_devstate;
      }
   }
}
static void initialize_cc_max_requests ( void  ) [static]

Definition at line 4269 of file ccss.c.

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

Referenced by ast_cc_init().

{
   struct ast_config *cc_config;
   const char *cc_max_requests_str;
   struct ast_flags config_flags = {0,};
   char *endptr;

   cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
   if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING, "Could not find valid ccss.conf file. Using cc_max_requests default\n");
      global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
      return;
   }

   if (!(cc_max_requests_str = ast_variable_retrieve(cc_config, "general", "cc_max_requests"))) {
      ast_config_destroy(cc_config);
      global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
      return;
   }

   global_cc_max_requests = strtol(cc_max_requests_str, &endptr, 10);

   if (!ast_strlen_zero(endptr)) {
      ast_log(LOG_WARNING, "Invalid input given for cc_max_requests. Using default\n");
      global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
   }

   ast_config_destroy(cc_config);
   return;
}
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 2863 of file ccss.c.

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

Referenced by cc_do_state_change().

{
   int is_valid = 0;
   switch (new_state) {
   case CC_AVAILABLE:
      ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
            agent->core_id, new_state);
      break;
   case CC_CALLER_OFFERED:
      if (current_state == CC_AVAILABLE) {
         is_valid = 1;
      }
      break;
   case CC_CALLER_REQUESTED:
      if (current_state == CC_CALLER_OFFERED ||
            (current_state == CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
         is_valid = 1;
      }
      break;
   case CC_ACTIVE:
      if (current_state == CC_CALLER_REQUESTED || current_state == CC_CALLER_BUSY) {
         is_valid = 1;
      }
      break;
   case CC_CALLEE_READY:
      if (current_state == CC_ACTIVE) {
         is_valid = 1;
      }
      break;
   case CC_CALLER_BUSY:
      if (current_state == CC_CALLEE_READY) {
         is_valid = 1;
      }
      break;
   case CC_RECALLING:
      if (current_state == CC_CALLEE_READY) {
         is_valid = 1;
      }
      break;
   case CC_COMPLETE:
      if (current_state == CC_RECALLING) {
         is_valid = 1;
      }
      break;
   case CC_FAILED:
      is_valid = 1;
      break;
   default:
      ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
            agent->core_id, new_state);
      break;
   }

   return is_valid;
}
static int kill_cores ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 4436 of file ccss.c.

References ast_cc_failed(), and cc_core_instance::core_id.

Referenced by handle_cc_kill().

{
   int *core_id = arg;
   struct cc_core_instance *core_instance = obj;

   if (!core_id || (core_instance->core_id == *core_id)) {
      ast_cc_failed(core_instance->core_id, "CC transaction canceled administratively\n");
   }
   return 0;
}
static void kill_duplicate_offers ( char *  caller) [static]

Definition at line 2381 of file ccss.c.

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

Referenced by cc_core_init_instance().

{
   unsigned long match_flags = MATCH_NO_REQUEST;
   struct ao2_iterator *dups_iter;

   /*
    * Must remove the ref that was in cc_core_instances outside of
    * the container lock to prevent deadlock.
    */
   dups_iter = ao2_t_callback_data(cc_core_instances, OBJ_MULTIPLE | OBJ_UNLINK,
      match_agent, caller, &match_flags, "Killing duplicate offers");
   if (dups_iter) {
      /* Now actually unref any duplicate offers by simply destroying the iterator. */
      ao2_iterator_destroy(dups_iter);
   }
}
static int match_agent ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

Definition at line 484 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(), ccss_device_state(), and kill_duplicate_offers().

{
   struct cc_core_instance *core_instance = obj;
   const char *name = arg;
   unsigned long match_flags = *(unsigned long *)data;
   int possible_match = 0;

   if ((match_flags & MATCH_NO_REQUEST) && core_instance->current_state < CC_CALLER_REQUESTED) {
      possible_match = 1;
   }

   if ((match_flags & MATCH_REQUEST) && core_instance->current_state >= CC_CALLER_REQUESTED) {
      possible_match = 1;
   }

   if (!possible_match) {
      return 0;
   }

   if (!strcmp(core_instance->agent->device_name, name)) {
      return CMP_MATCH | CMP_STOP;
   }
   return 0;
}
static const char* monitor_policy_to_str ( enum ast_cc_monitor_policies  policy) [static]

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

{
   switch (policy) {
   case AST_CC_MONITOR_NEVER:
      return "never";
   case AST_CC_MONITOR_NATIVE:
      return "native";
   case AST_CC_MONITOR_GENERIC:
      return "generic";
   case AST_CC_MONITOR_ALWAYS:
      return "always";
   default:
      /* This should never happen... */
      return "";
   }
}
static int offer_timer_expire ( const void *  data) [static]

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

{
   struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
   struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
   ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
         agent->core_id);
   agent_pvt->offer_timer_id = -1;
   ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
   cc_unref(agent, "Remove scheduler's reference to the agent");
   return 0;
}
static int print_stats_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

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

{
   int *cli_fd = arg;
   struct cc_core_instance *core_instance = obj;

   ast_cli(*cli_fd, "%d\t\t%s\t\t%s\n", core_instance->core_id, core_instance->agent->device_name,
         cc_state_to_string(core_instance->current_state));
   AST_LIST_LOCK(core_instance->monitors);
   cc_cli_print_monitor_stats(AST_LIST_FIRST(core_instance->monitors), *cli_fd, 0);
   AST_LIST_UNLOCK(core_instance->monitors);
   return 0;
}
static void request_cc ( struct cc_core_instance core_instance) [static]

Definition at line 2974 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_interface::device_name, 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, ast_cc_monitor::parent_id, and ast_cc_monitor_callbacks::request_cc.

Referenced by cc_caller_requested().

{
   struct ast_cc_monitor *monitor_iter;
   AST_LIST_LOCK(core_instance->monitors);
   AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
      if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
         if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
            AST_LIST_REMOVE_CURRENT(next);
            cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
                  monitor_iter->interface->device_name, 1);
            cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
         } else {
            manager_event(EVENT_FLAG_CC, "CCRequested",
               "CoreID: %d\r\n"
               "Caller: %s\r\n"
               "Callee: %s\r\n",
               core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
         }
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;

   if (!has_device_monitors(core_instance)) {
      ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
   }
   AST_LIST_UNLOCK(core_instance->monitors);
}
static enum ast_cc_agent_policies str_to_agent_policy ( const char *const  value) [static]

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

{
   if (!strcasecmp(value, "never")) {
      return AST_CC_AGENT_NEVER;
   } else if (!strcasecmp(value, "native")) {
      return AST_CC_AGENT_NATIVE;
   } else if (!strcasecmp(value, "generic")) {
      return AST_CC_AGENT_GENERIC;
   } else {
      ast_log(LOG_WARNING, "%s is an invalid value for cc_agent_policy. Switching to 'never'\n", value);
      return AST_CC_AGENT_NEVER;
   }
}
static enum ast_cc_monitor_policies str_to_monitor_policy ( const char *const  value) [static]

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

{
   if (!strcasecmp(value, "never")) {
      return AST_CC_MONITOR_NEVER;
   } else if (!strcasecmp(value, "native")) {
      return AST_CC_MONITOR_NATIVE;
   } else if (!strcasecmp(value, "generic")) {
      return AST_CC_MONITOR_GENERIC;
   } else if (!strcasecmp(value, "always")) {
      return AST_CC_MONITOR_ALWAYS;
   } else {
      ast_log(LOG_WARNING, "%s is an invalid value for cc_monitor_policy. Switching to 'never'\n", value);
      return AST_CC_MONITOR_NEVER;
   }
}
static void unsuspend ( struct cc_core_instance core_instance) [static]

Variable Documentation

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

Definition at line 4516 of file ccss.c.

struct ao2_container* cc_core_instances [static]

Definition at line 319 of file ccss.c.

const int CC_CORE_INSTANCES_BUCKETS = 17 [static]

Definition at line 318 of file ccss.c.

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

Definition at line 117 of file ccss.c.

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

const char* CC_LOGGER_LEVEL_NAME = "CC" [static]

Name printed on all CC log messages.

Definition at line 121 of file ccss.c.

int cc_request_count [static]

The current number of CC requests in the system

Definition at line 133 of file ccss.c.

The ast_sched_context used for all generic CC timeouts

Definition at line 107 of file ccss.c.

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

Referenced by cc_service_to_string().

Definition at line 555 of file ccss.c.

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

Referenced by cc_state_to_string().

const char* cccancel_app = "CallCompletionCancel" [static]

Definition at line 4198 of file ccss.c.

const char* ccreq_app = "CallCompletionRequest" [static]

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

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

Definition at line 1734 of file ccss.c.

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

Definition at line 1848 of file ccss.c.

Definition at line 2472 of file ccss.c.

Definition at line 1164 of file ccss.c.

Referenced by ast_cc_init(), and cc_shutdown().

unsigned int global_cc_max_requests [static]

Parsed configuration value for cc_max_requests

Definition at line 129 of file ccss.c.

Referenced by ast_cc_request_is_within_limits().

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

Definition at line 3288 of file ccss.c.

Definition at line 375 of file ccss.c.

const char* service_string

Definition at line 376 of file ccss.c.

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

Referenced by cc_do_state_change().

const char* state_string

Definition at line 386 of file ccss.c.