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/devicestate.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/causes.h"
#include "asterisk/stasis_system.h"
#include "asterisk/format_cache.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...

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
#define CC_RECALL_TIMER_DEFAULT   20
#define CC_RECALLING_DEVSTATE_DEFAULT   AST_DEVICE_RINGING
#define CCBS_AVAILABLE_TIMER_DEFAULT   4800
#define CCNR_AVAILABLE_TIMER_DEFAULT   7200
#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

Enumerations

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

Functions

struct ast_cc_config_params__ast_cc_config_params_init (const char *file, int line, const char *function)
 Allocate and initialize an ast_cc_config_params structure.
static void __fini_cc_agent_backends (void)
static void __fini_cc_monitor_backends (void)
static void __init_cc_agent_backends (void)
static void __init_cc_monitor_backends (void)
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.
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 int cc_publish (struct stasis_message_type *message_type, int core_id, struct ast_json *extras)
static void cc_publish_available (int core_id, const char *callee, const char *service)
static void cc_publish_callerrecalling (int core_id, const char *caller)
static void cc_publish_callerstartmonitoring (int core_id, const char *caller)
static void cc_publish_callerstopmonitoring (int core_id, const char *caller)
static void cc_publish_failure (int core_id, const char *caller, const char *reason)
static void cc_publish_monitorfailed (int core_id, const char *callee)
static void cc_publish_offertimerstart (int core_id, const char *caller, unsigned int expires)
static void cc_publish_recallcomplete (int core_id, const char *caller)
static void cc_publish_requestacknowledged (int core_id, const char *caller)
static void cc_publish_requested (int core_id, const char *caller, const char *callee)
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)
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 (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static int generic_monitor_cmp_fn (void *obj, void *arg, int flags)
static void generic_monitor_devstate_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
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

static struct ast_cli_entry cc_cli []
static struct ao2_containercc_core_instances
static const int CC_CORE_INSTANCES_BUCKETS = 17
static struct ast_taskprocessorcc_core_taskprocessor
static struct ast_cc_config_params cc_default_params
static int cc_logger_level
static const char * CC_LOGGER_LEVEL_NAME = "CC"
static int cc_request_count
static struct ast_sched_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

#define CC_ACTIVE_DEVSTATE_DEFAULT   AST_DEVICE_INUSE

Definition at line 554 of file ccss.c.

#define CC_AVAILABLE_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE

Definition at line 551 of file ccss.c.

#define CC_CALLEE_READY_DEVSTATE_DEFAULT   AST_DEVICE_RINGING

Definition at line 555 of file ccss.c.

#define CC_CALLER_BUSY_DEVSTATE_DEFAULT   AST_DEVICE_ONHOLD

Definition at line 556 of file ccss.c.

#define CC_CALLER_OFFERED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE

Definition at line 552 of file ccss.c.

#define CC_CALLER_REQUESTED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE

Definition at line 553 of file ccss.c.

#define CC_COMPLETE_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE

Definition at line 558 of file ccss.c.

#define CC_FAILED_DEVSTATE_DEFAULT   AST_DEVICE_NOT_INUSE

Definition at line 559 of file ccss.c.

#define CC_MAX_AGENTS_DEFAULT   5

Definition at line 660 of file ccss.c.

#define CC_MAX_MONITORS_DEFAULT   5

Definition at line 661 of file ccss.c.

#define CC_OFFER_TIMER_DEFAULT   20

Definition at line 656 of file ccss.c.

#define CC_RECALL_TIMER_DEFAULT   20

Definition at line 659 of file ccss.c.

#define CC_RECALLING_DEVSTATE_DEFAULT   AST_DEVICE_RINGING

Definition at line 557 of file ccss.c.

#define CCBS_AVAILABLE_TIMER_DEFAULT   4800

Definition at line 658 of file ccss.c.

#define CCNR_AVAILABLE_TIMER_DEFAULT   7200

Definition at line 657 of file ccss.c.

#define GLOBAL_CC_MAX_REQUESTS_DEFAULT   20

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

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

Enumerator:
MATCH_NO_REQUEST 
MATCH_REQUEST 

Definition at line 471 of file ccss.c.

00471                  {
00472    /* Only match agents that have not yet
00473     * made a CC request
00474     */
00475    MATCH_NO_REQUEST = (1 << 0),
00476    /* Only match agents that have made
00477     * a CC request
00478     */
00479    MATCH_REQUEST = (1 << 1),
00480 };


Function Documentation

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

Allocate and initialize an ast_cc_config_params structure.

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

Definition at line 683 of file ccss.c.

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

00684 {
00685 #if defined(__AST_DEBUG_MALLOC)
00686    struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
00687 #else
00688    struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
00689 #endif
00690 
00691    if (!params) {
00692       return NULL;
00693    }
00694 
00695    ast_cc_default_config_params(params);
00696    return params;
00697 }

static void __fini_cc_agent_backends ( void   )  [static]

Definition at line 1226 of file ccss.c.

01229 {

static void __fini_cc_monitor_backends ( void   )  [static]

Definition at line 1171 of file ccss.c.

01174 {

static void __init_cc_agent_backends ( void   )  [static]

Definition at line 1226 of file ccss.c.

01229 {

static void __init_cc_monitor_backends ( void   )  [static]

Definition at line 1171 of file ccss.c.

01174 {

static void agent_destroy ( void *  data  )  [static]

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

02545 {
02546    struct ast_cc_agent *agent = data;
02547 
02548    if (agent->callbacks) {
02549       agent->callbacks->destructor(agent);
02550    }
02551    ast_cc_config_params_destroy(agent->cc_params);
02552 }

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

Definition at line 734 of file ccss.c.

References AST_CC_AGENT_GENERIC, AST_CC_AGENT_NATIVE, and AST_CC_AGENT_NEVER.

Referenced by ast_cc_get_param().

00735 {
00736    switch (policy) {
00737    case AST_CC_AGENT_NEVER:
00738       return "never";
00739    case AST_CC_AGENT_NATIVE:
00740       return "native";
00741    case AST_CC_AGENT_GENERIC:
00742       return "generic";
00743    default:
00744       /* This should never happen... */
00745       return "";
00746    }
00747 }

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

Accept inbound CC request.

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

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

Definition at line 3773 of file ccss.c.

References CC_CALLER_REQUESTED, and cc_request_state_change().

Referenced by ccreq_exec(), and handle_cc_subscribe().

03774 {
03775    va_list ap;
03776    int res;
03777 
03778    va_start(ap, debug);
03779    res = cc_request_state_change(CC_CALLER_REQUESTED, core_id, debug, ap);
03780    va_end(ap);
03781    return res;
03782 }

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

Call a callback on all agents of a specific type.

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

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

Definition at line 458 of file ccss.c.

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

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

00459 {
00460    struct cc_callback_helper helper = {.function = function, .args = args, .type = type};
00461    struct cc_core_instance *core_instance;
00462    if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
00463                "Calling provided agent callback function"))) {
00464       struct ast_cc_agent *agent = cc_ref(core_instance->agent, "An outside entity needs the agent");
00465       cc_unref(core_instance, "agent callback done with the core_instance");
00466       return agent;
00467    }
00468    return NULL;
00469 }

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

Indicate that a previously unavailable caller has become available.

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

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

Definition at line 3817 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

Referenced by generic_agent_devstate_cb().

03818 {
03819    va_list ap;
03820    int res;
03821 
03822    va_start(ap, debug);
03823    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03824    va_end(ap);
03825    return res;
03826 }

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

Indicate that the caller is busy.

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

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

Definition at line 3806 of file ccss.c.

References CC_CALLER_BUSY, and cc_request_state_change().

Referenced by cc_generic_agent_recall(), and sip_cc_agent_recall().

03807 {
03808    va_list ap;
03809    int res;
03810 
03811    va_start(ap, debug);
03812    res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
03813    va_end(ap);
03814    return res;
03815 }

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

Tell the CC core that a caller is currently recalling.

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

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

Definition at line 3828 of file ccss.c.

References CC_RECALLING, and cc_request_state_change().

Referenced by generic_recall(), and get_destination().

03829 {
03830    va_list ap;
03831    int res;
03832 
03833    va_start(ap, debug);
03834    res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
03835    va_end(ap);
03836    return res;
03837 }

int ast_cc_agent_register ( const struct ast_cc_agent_callbacks callbacks  ) 

Register a set of agent callbacks with the core.

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

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

Definition at line 1228 of file ccss.c.

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

Referenced by ast_cc_init(), and load_module().

01229 {
01230    struct cc_agent_backend *backend = ast_calloc(1, sizeof(*backend));
01231 
01232    if (!backend) {
01233       return -1;
01234    }
01235 
01236    backend->callbacks = callbacks;
01237    AST_RWLIST_WRLOCK(&cc_agent_backends);
01238    AST_RWLIST_INSERT_TAIL(&cc_agent_backends, backend, next);
01239    AST_RWLIST_UNLOCK(&cc_agent_backends);
01240    return 0;
01241 }

int ast_cc_agent_set_interfaces_chanvar ( struct ast_channel chan  ) 

Set the first level CC_INTERFACES channel variable for a channel.

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

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

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

Parameters:
chan The channel to set the CC_INTERFACES variable on

Definition at line 3628 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, NULL, pbx_builtin_setvar_helper(), and str.

Referenced by generic_recall(), and handle_request_invite().

03629 {
03630    struct ast_datastore *recall_datastore;
03631    struct cc_monitor_tree *interface_tree;
03632    struct ast_cc_monitor *monitor;
03633    struct cc_recall_ds_data *recall_data;
03634    struct ast_str *str = ast_str_create(64);
03635    int core_id;
03636 
03637    if (!str) {
03638       return -1;
03639    }
03640 
03641    ast_channel_lock(chan);
03642    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03643       ast_channel_unlock(chan);
03644       ast_free(str);
03645       return -1;
03646    }
03647    recall_data = recall_datastore->data;
03648    interface_tree = recall_data->interface_tree;
03649    core_id = recall_data->core_id;
03650    ast_channel_unlock(chan);
03651 
03652    AST_LIST_LOCK(interface_tree);
03653    monitor = AST_LIST_FIRST(interface_tree);
03654    build_cc_interfaces_chanvar(monitor, &str);
03655    AST_LIST_UNLOCK(interface_tree);
03656 
03657    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03658    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03659          core_id, ast_str_buffer(str));
03660 
03661    ast_free(str);
03662    return 0;
03663 }

int ast_cc_agent_status_response ( int  core_id,
enum ast_device_state  devstate 
)

Response with a caller's current status.

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

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

Definition at line 4090 of file ccss.c.

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

Referenced by cc_generic_agent_status_request(), and sip_cc_agent_status_request().

04091 {
04092    struct cc_status_response_args *args;
04093    struct cc_core_instance *core_instance;
04094    int res;
04095 
04096    args = ast_calloc(1, sizeof(*args));
04097    if (!args) {
04098       return -1;
04099    }
04100 
04101    core_instance = find_cc_core_instance(core_id);
04102    if (!core_instance) {
04103       ast_free(args);
04104       return -1;
04105    }
04106 
04107    args->core_instance = core_instance;
04108    args->devstate = devstate;
04109 
04110    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
04111    if (res) {
04112       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
04113       ast_free(args);
04114    }
04115    return res;
04116 }

void ast_cc_agent_unregister ( const struct ast_cc_agent_callbacks callbacks  ) 

Unregister a set of agent callbacks with the core.

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

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

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

01244 {
01245    struct cc_agent_backend *backend;
01246    AST_RWLIST_WRLOCK(&cc_agent_backends);
01247    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_agent_backends, backend, next) {
01248       if (backend->callbacks == callbacks) {
01249          AST_RWLIST_REMOVE_CURRENT(next);
01250          ast_free(backend);
01251          break;
01252       }
01253    }
01254    AST_RWLIST_TRAVERSE_SAFE_END;
01255    AST_RWLIST_UNLOCK(&cc_agent_backends);
01256 }

int ast_cc_available_timer_expire ( const void *  data  ) 

Scheduler callback for available timer expiration.

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

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

01508 {
01509    struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
01510    int res;
01511    monitor->available_timer_id = -1;
01512    res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
01513    cc_unref(monitor, "Unref reference from scheduler\n");
01514    return res;
01515 }

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

Create a CC Control frame.

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

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

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

04177 {
04178    struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));
04179 
04180    if (!payload) {
04181       return -1;
04182    }
04183    if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
04184       /* Something screwed up, we can't make a frame with this */
04185       ast_free(payload);
04186       return -1;
04187    }
04188    frame->frametype = AST_FRAME_CONTROL;
04189    frame->subclass.integer = AST_CONTROL_CC;
04190    frame->data.ptr = payload;
04191    frame->datalen = sizeof(*payload);
04192    frame->mallocd = AST_MALLOCD_DATA;
04193    return 0;
04194 }

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

Callback made from ast_cc_callback for certain channel types.

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

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

Definition at line 4229 of file ccss.c.

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

Referenced by dial_exec_full().

04231 {
04232    struct cc_control_payload payload;
04233    if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
04234       /* Something screwed up. Don't try to handle this payload */
04235       call_destructor_with_no_monitor(monitor_type, private_data);
04236       return;
04237    }
04238    ast_handle_cc_control_frame(inbound, NULL, &payload);
04239 }

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 4196 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(), cc_build_payload(), and NULL.

Referenced by dial_exec_full().

04197 {
04198    char device_name[AST_CHANNEL_NAME];
04199    struct cc_control_payload payload;
04200    struct ast_cc_config_params *cc_params;
04201 
04202    if (ast_channel_hangupcause(outgoing) != AST_CAUSE_BUSY && ast_channel_hangupcause(outgoing) != AST_CAUSE_CONGESTION) {
04203       /* It doesn't make sense to try to offer CCBS to the caller if the reason for ast_call
04204        * failing is something other than busy or congestion
04205        */
04206       return;
04207    }
04208 
04209    cc_params = ast_channel_get_cc_config_params(outgoing);
04210    if (!cc_params) {
04211       return;
04212    }
04213    if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
04214       /* This sort of CCBS only works if using generic CC. For native, we would end up sending
04215        * a CC request for a non-existent call. The far end will reject this every time
04216        */
04217       return;
04218    }
04219 
04220    ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
04221    if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
04222       dialstring, AST_CC_CCBS, NULL, &payload)) {
04223       /* Something screwed up, we can't make a frame with this */
04224       return;
04225    }
04226    ast_handle_cc_control_frame(incoming, outgoing, &payload);
04227 }

int ast_cc_call_init ( struct ast_channel chan,
int *  ignore_cc 
)

Start the CC process on a call.

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

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

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

Definition at line 2409 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(), dialed_cc_interfaces::core_id, ast_cc_monitor::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, NULL, and S_OR.

Referenced by dial_exec_full().

02410 {
02411    /* There are three situations to deal with here:
02412     *
02413     * 1. The channel does not have a dialed_cc_interfaces datastore on
02414     * it. This means that this is the first time that Dial has
02415     * been called. We need to create/initialize the datastore.
02416     *
02417     * 2. The channel does have a cc_interface datastore on it and
02418     * the "ignore" indicator is 0. This means that a Local channel
02419     * was called by a "parent" dial. We can check the datastore's
02420     * parent field to see who the root of this particular dial tree
02421     * is.
02422     *
02423     * 3. The channel does have a cc_interface datastore on it and
02424     * the "ignore" indicator is 1. This means that a second Dial call
02425     * is being made from an extension. In this case, we do not
02426     * want to make any additions/modifications to the datastore. We
02427     * will instead set a flag to indicate that CCSS is completely
02428     * disabled for this Dial attempt.
02429     */
02430 
02431    struct ast_datastore *cc_interfaces_datastore;
02432    struct dialed_cc_interfaces *interfaces;
02433    struct ast_cc_monitor *monitor;
02434    struct ast_cc_config_params *cc_params;
02435 
02436    ast_channel_lock(chan);
02437 
02438    cc_params = ast_channel_get_cc_config_params(chan);
02439    if (!cc_params) {
02440       ast_channel_unlock(chan);
02441       return -1;
02442    }
02443    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
02444       /* We can't offer CC to this caller anyway, so don't bother with CC on this call
02445        */
02446       *ignore_cc = 1;
02447       ast_channel_unlock(chan);
02448       ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", ast_channel_name(chan));
02449       return 0;
02450    }
02451 
02452    if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02453       /* Situation 1 has occurred */
02454       ast_channel_unlock(chan);
02455       return cc_interfaces_datastore_init(chan);
02456    }
02457    interfaces = cc_interfaces_datastore->data;
02458    ast_channel_unlock(chan);
02459 
02460    if (interfaces->ignore) {
02461       /* Situation 3 has occurred */
02462       *ignore_cc = 1;
02463       ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
02464       return 0;
02465    }
02466 
02467    /* Situation 2 has occurred */
02468    if (!(monitor = cc_extension_monitor_init(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)),
02469          S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), interfaces->dial_parent_id))) {
02470       return -1;
02471    }
02472    monitor->core_id = interfaces->core_id;
02473    AST_LIST_LOCK(interfaces->interface_tree);
02474    cc_ref(monitor, "monitor tree's reference to the monitor");
02475    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
02476    AST_LIST_UNLOCK(interfaces->interface_tree);
02477    interfaces->dial_parent_id = monitor->id;
02478    cc_unref(monitor, "Unref monitor's allocation reference");
02479    return 0;
02480 }

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

Run a callback for potential matching destinations.

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

Definition at line 4241 of file ccss.c.

References ast_get_channel_tech(), and ast_channel_tech::cc_callback.

Referenced by dial_exec_full().

04242 {
04243    const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);
04244 
04245    if (chantech && chantech->cc_callback) {
04246       chantech->cc_callback(inbound, dest, callback);
04247    }
04248 
04249    return 0;
04250 }

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

Indicate recall has been acknowledged.

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

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

Definition at line 3839 of file ccss.c.

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

Referenced by wait_for_answer().

03840 {
03841    struct ast_datastore *recall_datastore;
03842    struct cc_recall_ds_data *recall_data;
03843    int core_id;
03844    va_list ap;
03845    int res;
03846 
03847    ast_channel_lock(chan);
03848    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03849       /* Silly! Why did you call this function if there's no recall DS? */
03850       ast_channel_unlock(chan);
03851       return -1;
03852    }
03853    recall_data = recall_datastore->data;
03854    if (recall_data->nested || recall_data->ignore) {
03855       /* If this is being called from a nested Dial, it is too
03856        * early to determine if the recall has actually completed.
03857        * The outermost dial is the only one with the authority to
03858        * declare the recall to be complete.
03859        *
03860        * Similarly, if this function has been called when the
03861        * recall has progressed beyond the first dial, this is not
03862        * a legitimate time to declare the recall to be done. In fact,
03863        * that should have been done already.
03864        */
03865       ast_channel_unlock(chan);
03866       return -1;
03867    }
03868    core_id = recall_data->core_id;
03869    ast_channel_unlock(chan);
03870    va_start(ap, debug);
03871    res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
03872    va_end(ap);
03873    return res;
03874 }

void ast_cc_config_params_destroy ( struct ast_cc_config_params params  ) 

Free memory from CCSS configuration params.

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

Definition at line 699 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(), dahdi_create_channel_range(), destroy_dahdi_pvt(), process_dahdi(), setup_dahdi(), and sip_destroy_peer().

00700 {
00701    ast_free(params);
00702 }

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

copy CCSS configuration parameters from one structure to another

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

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

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

00868 {
00869    *dest = *src;
00870 }

void ast_cc_default_config_params ( struct ast_cc_config_params params  ) 

Set the specified CC config params to default values.

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

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

Definition at line 678 of file ccss.c.

Referenced by __ast_cc_config_params_init().

00679 {
00680    *params = cc_default_params;
00681 }

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

Add a child dialstring to an extension monitor.

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

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

Definition at line 2003 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, NULL, extension_child_dialstring::original_dialstring, and ast_cc_monitor::private_data.

Referenced by dial_exec_full().

02004 {
02005    struct ast_datastore *cc_datastore;
02006    struct dialed_cc_interfaces *cc_interfaces;
02007    struct ast_cc_monitor *monitor;
02008    struct extension_monitor_pvt *extension_pvt;
02009    struct extension_child_dialstring *child_dialstring;
02010    struct cc_monitor_tree *interface_tree;
02011    int id;
02012 
02013    ast_channel_lock(incoming);
02014    if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
02015       ast_channel_unlock(incoming);
02016       return;
02017    }
02018 
02019    cc_interfaces = cc_datastore->data;
02020    interface_tree = cc_interfaces->interface_tree;
02021    id = cc_interfaces->dial_parent_id;
02022    ast_channel_unlock(incoming);
02023 
02024    AST_LIST_LOCK(interface_tree);
02025    AST_LIST_TRAVERSE(interface_tree, monitor, next) {
02026       if (monitor->id == id) {
02027          break;
02028       }
02029    }
02030 
02031    if (!monitor) {
02032       AST_LIST_UNLOCK(interface_tree);
02033       return;
02034    }
02035 
02036    extension_pvt = monitor->private_data;
02037    if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
02038       AST_LIST_UNLOCK(interface_tree);
02039       return;
02040    }
02041    ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
02042    ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
02043    child_dialstring->is_valid = 1;
02044    AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
02045    AST_LIST_UNLOCK(interface_tree);
02046 }

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

Indicate failure has occurred.

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

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

Definition at line 3876 of file ccss.c.

References CC_FAILED, and cc_request_state_change().

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

03877 {
03878    va_list ap;
03879    int res;
03880 
03881    va_start(ap, debug);
03882    res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
03883    va_end(ap);
03884    return res;
03885 }

int ast_cc_get_current_core_id ( struct ast_channel chan  ) 

Get the core id for the current call.

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

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

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

Definition at line 2487 of file ccss.c.

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

Referenced by sip_handle_cc().

02488 {
02489    struct ast_datastore *datastore;
02490    struct dialed_cc_interfaces *cc_interfaces;
02491    int core_id_return;
02492 
02493    ast_channel_lock(chan);
02494    if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02495       ast_channel_unlock(chan);
02496       return -1;
02497    }
02498 
02499    cc_interfaces = datastore->data;
02500    core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
02501    ast_channel_unlock(chan);
02502    return core_id_return;
02503 
02504 }

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

Get the associated monitor given the device name and core_id.

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

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

Definition at line 3516 of file ccss.c.

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

Referenced by sip_call().

03517 {
03518    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03519    struct ast_cc_monitor *monitor_iter;
03520 
03521    if (!core_instance) {
03522       return NULL;
03523    }
03524 
03525    AST_LIST_LOCK(core_instance->monitors);
03526    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03527       if (!strcmp(monitor_iter->interface->device_name, device_name)) {
03528          /* Found a monitor. */
03529          cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
03530          break;
03531       }
03532    }
03533    AST_LIST_UNLOCK(core_instance->monitors);
03534    cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
03535    return monitor_iter;
03536 }

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

get a CCSS configuration parameter, given its name

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

Definition at line 765 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(), NULL, and value.

Referenced by acf_cc_read().

00767 {
00768    const char *value = NULL;
00769 
00770    if (!strcasecmp(name, "cc_callback_macro")) {
00771       value = ast_get_cc_callback_macro(params);
00772    } else if (!strcasecmp(name, "cc_callback_sub")) {
00773       value = ast_get_cc_callback_sub(params);
00774    } else if (!strcasecmp(name, "cc_agent_policy")) {
00775       value = agent_policy_to_str(ast_get_cc_agent_policy(params));
00776    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00777       value = monitor_policy_to_str(ast_get_cc_monitor_policy(params));
00778    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00779       value = ast_get_cc_agent_dialstring(params);
00780    }
00781    if (value) {
00782       ast_copy_string(buf, value, buf_len);
00783       return 0;
00784    }
00785 
00786    /* The rest of these are all ints of some sort and require some
00787     * snprintf-itude
00788     */
00789 
00790    if (!strcasecmp(name, "cc_offer_timer")) {
00791       snprintf(buf, buf_len, "%u", ast_get_cc_offer_timer(params));
00792    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00793       snprintf(buf, buf_len, "%u", ast_get_ccnr_available_timer(params));
00794    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00795       snprintf(buf, buf_len, "%u", ast_get_ccbs_available_timer(params));
00796    } else if (!strcasecmp(name, "cc_max_agents")) {
00797       snprintf(buf, buf_len, "%u", ast_get_cc_max_agents(params));
00798    } else if (!strcasecmp(name, "cc_max_monitors")) {
00799       snprintf(buf, buf_len, "%u", ast_get_cc_max_monitors(params));
00800    } else if (!strcasecmp(name, "cc_recall_timer")) {
00801       snprintf(buf, buf_len, "%u", ast_get_cc_recall_timer(params));
00802    } else {
00803       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00804       return -1;
00805    }
00806 
00807    return 0;
00808 }

int ast_cc_init ( void   ) 

Initialize CCSS.

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

Definition at line 4654 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_cleanup(), 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(), NULL, and TPS_REF_DEFAULT.

Referenced by main().

04655 {
04656    int res;
04657 
04658    if (!(cc_core_instances = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04659                cc_core_instance_hash_fn, cc_core_instance_cmp_fn,
04660                "Create core instance container"))) {
04661       return -1;
04662    }
04663    if (!(generic_monitors = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04664                generic_monitor_hash_fn, generic_monitor_cmp_fn,
04665                "Create generic monitor container"))) {
04666       return -1;
04667    }
04668    if (!(cc_core_taskprocessor = ast_taskprocessor_get("CCSS core", TPS_REF_DEFAULT))) {
04669       return -1;
04670    }
04671    if (!(cc_sched_context = ast_sched_context_create())) {
04672       return -1;
04673    }
04674    if (ast_sched_start_thread(cc_sched_context)) {
04675       return -1;
04676    }
04677    res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL);
04678    res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL);
04679    res |= ast_cc_monitor_register(&generic_monitor_cbs);
04680    res |= ast_cc_agent_register(&generic_agent_callbacks);
04681 
04682    ast_cli_register_multiple(cc_cli, ARRAY_LEN(cc_cli));
04683    cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME);
04684    dialed_cc_interface_counter = 1;
04685    initialize_cc_max_requests();
04686 
04687    /* Read the map and register the device state callback for generic agents */
04688    initialize_cc_devstate_map();
04689    res |= ast_devstate_prov_add("ccss", ccss_device_state);
04690 
04691    ast_register_cleanup(cc_shutdown);
04692 
04693    return res;
04694 }

int ast_cc_is_config_param ( const char *const   name  ) 

Is this a CCSS configuration parameter?

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

Definition at line 852 of file ccss.c.

Referenced by build_peer(), and process_dahdi().

00853 {
00854    return (!strcasecmp(name, "cc_agent_policy") ||
00855             !strcasecmp(name, "cc_monitor_policy") ||
00856             !strcasecmp(name, "cc_offer_timer") ||
00857             !strcasecmp(name, "ccnr_available_timer") ||
00858             !strcasecmp(name, "ccbs_available_timer") ||
00859             !strcasecmp(name, "cc_max_agents") ||
00860             !strcasecmp(name, "cc_max_monitors") ||
00861             !strcasecmp(name, "cc_callback_macro") ||
00862             !strcasecmp(name, "cc_callback_sub") ||
00863             !strcasecmp(name, "cc_agent_dialstring") ||
00864             !strcasecmp(name, "cc_recall_timer"));
00865 }

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

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

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

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

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

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

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

Definition at line 3435 of file ccss.c.

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

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

03436 {
03437    struct ast_datastore *recall_datastore;
03438    struct cc_recall_ds_data *recall_data;
03439    struct cc_monitor_tree *interface_tree;
03440    char device_name[AST_CHANNEL_NAME];
03441    struct ast_cc_monitor *device_monitor;
03442    int core_id_candidate;
03443 
03444    ast_assert(core_id != NULL);
03445 
03446    *core_id = -1;
03447 
03448    ast_channel_lock(chan);
03449    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03450       /* Obviously not a recall if the datastore isn't present */
03451       ast_channel_unlock(chan);
03452       return 0;
03453    }
03454 
03455    recall_data = recall_datastore->data;
03456 
03457    if (recall_data->ignore) {
03458       /* Though this is a recall, the call to this particular interface is not part of the
03459        * recall either because this is a call forward or because this is not the first
03460        * invocation of Dial during this call
03461        */
03462       ast_channel_unlock(chan);
03463       return 0;
03464    }
03465 
03466    if (!recall_data->nested) {
03467       /* If the nested flag is not set, then this means that
03468        * the channel passed to this function is the caller making
03469        * the recall. This means that we shouldn't look through
03470        * the monitor tree for the channel because it shouldn't be
03471        * there. However, this is a recall though, so return true.
03472        */
03473       *core_id = recall_data->core_id;
03474       ast_channel_unlock(chan);
03475       return 1;
03476    }
03477 
03478    if (ast_strlen_zero(monitor_type)) {
03479       /* If someone passed a NULL or empty monitor type, then it is clear
03480        * the channel they passed in was an incoming channel, and so searching
03481        * the list of dialed interfaces is not going to be helpful. Just return
03482        * false immediately.
03483        */
03484       ast_channel_unlock(chan);
03485       return 0;
03486    }
03487 
03488    interface_tree = recall_data->interface_tree;
03489    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03490    /* We grab the value of the recall_data->core_id so that we
03491     * can unlock the channel before we start looking through the
03492     * interface list. That way we don't have to worry about a possible
03493     * clash between the channel lock and the monitor tree lock.
03494     */
03495    core_id_candidate = recall_data->core_id;
03496    ast_channel_unlock(chan);
03497 
03498    /*
03499     * Now we need to find out if the channel device name
03500     * is in the list of interfaces in the called tree.
03501     */
03502    AST_LIST_LOCK(interface_tree);
03503    AST_LIST_TRAVERSE(interface_tree, device_monitor, next) {
03504       if (!strcmp(device_monitor->interface->device_name, device_name) &&
03505             !strcmp(device_monitor->interface->monitor_type, monitor_type)) {
03506          /* BOOM! Device is in the tree! We have a winner! */
03507          *core_id = core_id_candidate;
03508          AST_LIST_UNLOCK(interface_tree);
03509          return 1;
03510       }
03511    }
03512    AST_LIST_UNLOCK(interface_tree);
03513    return 0;
03514 }

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.
core_id The core ID of the corresponding CC transaction
debug
Return values:
0 Request successfully queued
-1 Request could not be queued

Definition at line 3795 of file ccss.c.

References CC_CALLEE_READY, and cc_request_state_change().

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

03796 {
03797    va_list ap;
03798    int res;
03799 
03800    va_start(ap, debug);
03801    res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
03802    va_end(ap);
03803    return res;
03804 }

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

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

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

Definition at line 4365 of file ccss.c.

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

Referenced by ast_queue_cc_frame().

04366 {
04367    struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};
04368 
04369    ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
04370    ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
04371    return data.count;
04372 }

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

Indicate that a failure has occurred on a specific monitor.

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

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

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

Definition at line 3938 of file ccss.c.

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

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

03939 {
03940    struct ast_cc_monitor_failure_data *failure_data;
03941    int res;
03942    va_list ap;
03943 
03944    if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
03945       return -1;
03946    }
03947 
03948    if (!(failure_data->device_name = ast_strdup(monitor_name))) {
03949       ast_free(failure_data);
03950       return -1;
03951    }
03952 
03953    va_start(ap, debug);
03954    if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
03955       va_end(ap);
03956       ast_free((char *)failure_data->device_name);
03957       ast_free(failure_data);
03958       return -1;
03959    }
03960    va_end(ap);
03961 
03962    failure_data->core_id = core_id;
03963 
03964    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
03965    if (res) {
03966       ast_free((char *)failure_data->device_name);
03967       ast_free((char *)failure_data->debug);
03968       ast_free(failure_data);
03969    }
03970    return res;
03971 }

int ast_cc_monitor_party_b_free ( int  core_id  ) 

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

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

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

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

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

Definition at line 4048 of file ccss.c.

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

04049 {
04050    int res;
04051    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
04052 
04053    if (!core_instance) {
04054       return -1;
04055    }
04056 
04057    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
04058    if (res) {
04059       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
04060    }
04061    return res;
04062 }

int ast_cc_monitor_register ( const struct ast_cc_monitor_callbacks callbacks  ) 

Register a set of monitor callbacks with the core.

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

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

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

01174 {
01175    struct cc_monitor_backend *backend = ast_calloc(1, sizeof(*backend));
01176 
01177    if (!backend) {
01178       return -1;
01179    }
01180 
01181    backend->callbacks = callbacks;
01182 
01183    AST_RWLIST_WRLOCK(&cc_monitor_backends);
01184    AST_RWLIST_INSERT_TAIL(&cc_monitor_backends, backend, next);
01185    AST_RWLIST_UNLOCK(&cc_monitor_backends);
01186    return 0;
01187 }

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

Indicate that an outbound entity has accepted our CC request.

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

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

Definition at line 3784 of file ccss.c.

References CC_ACTIVE, and cc_request_state_change().

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

03785 {
03786    va_list ap;
03787    int res;
03788 
03789    va_start(ap, debug);
03790    res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03791    va_end(ap);
03792    return res;
03793 }

int ast_cc_monitor_status_request ( int  core_id  ) 

Request the status of a caller or callers.

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

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

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

Definition at line 3983 of file ccss.c.

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

03984 {
03985    int res;
03986    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03987 
03988    if (!core_instance) {
03989       return -1;
03990    }
03991 
03992    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
03993    if (res) {
03994       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03995    }
03996    return res;
03997 }

int ast_cc_monitor_stop_ringing ( int  core_id  ) 

Alert a caller to stop ringing.

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

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

Definition at line 4020 of file ccss.c.

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

04021 {
04022    int res;
04023    struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
04024 
04025    if (!core_instance) {
04026       return -1;
04027    }
04028 
04029    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
04030    if (res) {
04031       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
04032    }
04033    return res;
04034 }

void ast_cc_monitor_unregister ( const struct ast_cc_monitor_callbacks callbacks  ) 

Unregister a set of monitor callbacks with the core.

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

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

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

01207 {
01208    struct cc_monitor_backend *backend;
01209    AST_RWLIST_WRLOCK(&cc_monitor_backends);
01210    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_monitor_backends, backend, next) {
01211       if (backend->callbacks == callbacks) {
01212          AST_RWLIST_REMOVE_CURRENT(next);
01213          ast_free(backend);
01214          break;
01215       }
01216    }
01217    AST_RWLIST_TRAVERSE_SAFE_END;
01218    AST_RWLIST_UNLOCK(&cc_monitor_backends);
01219 }

int ast_cc_offer ( struct ast_channel caller_chan  ) 

Offer CC to a caller.

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

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

Definition at line 3748 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, dialed_cc_interfaces::is_original_caller, and NULL.

Referenced by ast_hangup().

03749 {
03750    int core_id;
03751    int res = -1;
03752    struct ast_datastore *datastore;
03753    struct dialed_cc_interfaces *cc_interfaces;
03754    char cc_is_offerable;
03755 
03756    ast_channel_lock(caller_chan);
03757    if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
03758       ast_channel_unlock(caller_chan);
03759       return res;
03760    }
03761 
03762    cc_interfaces = datastore->data;
03763    cc_is_offerable = cc_interfaces->is_original_caller;
03764    core_id = cc_interfaces->core_id;
03765    ast_channel_unlock(caller_chan);
03766 
03767    if (cc_is_offerable) {
03768       res = cc_offer(core_id, "CC offered to caller %s", ast_channel_name(caller_chan));
03769    }
03770    return res;
03771 }

int ast_cc_request_is_within_limits ( void   ) 

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

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

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

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

Definition at line 2482 of file ccss.c.

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

02483 {
02484    return cc_request_count < global_cc_max_requests;
02485 }

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

set a CCSS configuration parameter, given its name

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

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

00812 {
00813    unsigned int value_as_uint;
00814    if (!strcasecmp(name, "cc_agent_policy")) {
00815       return ast_set_cc_agent_policy(params, str_to_agent_policy(value));
00816    } else if (!strcasecmp(name, "cc_monitor_policy")) {
00817       return ast_set_cc_monitor_policy(params, str_to_monitor_policy(value));
00818    } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00819       ast_set_cc_agent_dialstring(params, value);
00820    } else if (!strcasecmp(name, "cc_callback_macro")) {
00821       ast_set_cc_callback_macro(params, value);
00822       return 0;
00823    } else if (!strcasecmp(name, "cc_callback_sub")) {
00824       ast_set_cc_callback_sub(params, value);
00825       return 0;
00826    }
00827 
00828    if (sscanf(value, "%30u", &value_as_uint) != 1) {
00829       return -1;
00830    }
00831 
00832    if (!strcasecmp(name, "cc_offer_timer")) {
00833       ast_set_cc_offer_timer(params, value_as_uint);
00834    } else if (!strcasecmp(name, "ccnr_available_timer")) {
00835       ast_set_ccnr_available_timer(params, value_as_uint);
00836    } else if (!strcasecmp(name, "ccbs_available_timer")) {
00837       ast_set_ccbs_available_timer(params, value_as_uint);
00838    } else if (!strcasecmp(name, "cc_max_agents")) {
00839       ast_set_cc_max_agents(params, value_as_uint);
00840    } else if (!strcasecmp(name, "cc_max_monitors")) {
00841       ast_set_cc_max_monitors(params, value_as_uint);
00842    } else if (!strcasecmp(name, "cc_recall_timer")) {
00843       ast_set_cc_recall_timer(params, value_as_uint);
00844    } else {
00845       ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00846       return -1;
00847    }
00848 
00849    return 0;
00850 }

const char* ast_get_cc_agent_dialstring ( struct ast_cc_config_params config  ) 

Get the cc_agent_dialstring.

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

Definition at line 966 of file ccss.c.

References ast_cc_config_params::cc_agent_dialstring.

Referenced by ast_cc_get_param(), and generic_recall().

00967 {
00968    return config->cc_agent_dialstring;
00969 }

enum ast_cc_agent_policies ast_get_cc_agent_policy ( struct ast_cc_config_params config  ) 

Get the cc_agent_policy.

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

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

00873 {
00874    return config->cc_agent_policy;
00875 }

const char* ast_get_cc_callback_macro ( struct ast_cc_config_params config  ) 

Get the name of the callback_macro.

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

Definition at line 1000 of file ccss.c.

References ast_cc_config_params::cc_callback_macro.

Referenced by ast_cc_get_param(), and generic_recall().

01001 {
01002    return config->cc_callback_macro;
01003 }

const char* ast_get_cc_callback_sub ( struct ast_cc_config_params config  ) 

Get the name of the callback subroutine.

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

Definition at line 1005 of file ccss.c.

References ast_cc_config_params::cc_callback_sub.

Referenced by ast_cc_get_param(), and generic_recall().

01006 {
01007    return config->cc_callback_sub;
01008 }

unsigned int ast_get_cc_max_agents ( struct ast_cc_config_params config  ) 

Get the cc_max_agents.

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

Definition at line 980 of file ccss.c.

References ast_cc_config_params::cc_max_agents.

Referenced by ast_cc_get_param(), and cc_core_init_instance().

00981 {
00982    return config->cc_max_agents;
00983 }

unsigned int ast_get_cc_max_monitors ( struct ast_cc_config_params config  ) 

Get the cc_max_monitors.

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

Definition at line 990 of file ccss.c.

References ast_cc_config_params::cc_max_monitors.

Referenced by ast_cc_get_param(), and ast_queue_cc_frame().

00991 {
00992    return config->cc_max_monitors;
00993 }

enum ast_cc_monitor_policies ast_get_cc_monitor_policy ( struct ast_cc_config_params config  ) 

Get the cc_monitor_policy.

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

Definition at line 889 of file ccss.c.

References ast_cc_config_params::cc_monitor_policy.

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

00890 {
00891    return config->cc_monitor_policy;
00892 }

unsigned int ast_get_cc_offer_timer ( struct ast_cc_config_params config  ) 

Get the cc_offer_timer.

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

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

00907 {
00908    return config->cc_offer_timer;
00909 }

unsigned int ast_get_cc_recall_timer ( struct ast_cc_config_params config  ) 

Get the cc_recall_timer.

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

Definition at line 936 of file ccss.c.

References ast_cc_config_params::cc_recall_timer.

Referenced by ast_cc_get_param(), and generic_recall().

00937 {
00938    return config->cc_recall_timer;
00939 }

unsigned int ast_get_ccbs_available_timer ( struct ast_cc_config_params config  ) 

Get the ccbs_available_timer.

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

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

00952 {
00953    return config->ccbs_available_timer;
00954 }

unsigned int ast_get_ccnr_available_timer ( struct ast_cc_config_params config  ) 

Get the ccnr_available_timer.

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

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

00922 {
00923    return config->ccnr_available_timer;
00924 }

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 2316 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_publish_available(), cc_ref(), cc_service_to_string(), cc_unref(), cc_core_instance::core_id, dialed_cc_interfaces::core_id, ast_datastore::data, ast_cc_interface::device_name, cc_control_payload::device_name, cc_control_payload::dialstring, ast_cc_monitor::dialstring, 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, monitor, cc_control_payload::monitor_type, NULL, 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().

02317 {
02318    char *device_name;
02319    char *dialstring;
02320    struct ast_cc_monitor *monitor;
02321    struct ast_datastore *cc_datastore;
02322    struct dialed_cc_interfaces *cc_interfaces;
02323    struct cc_control_payload *cc_data = frame_data;
02324    struct cc_core_instance *core_instance;
02325 
02326    device_name = cc_data->device_name;
02327    dialstring = cc_data->dialstring;
02328 
02329    ast_channel_lock(inbound);
02330    if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
02331       ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
02332       ast_channel_unlock(inbound);
02333       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02334       return;
02335    }
02336 
02337    cc_interfaces = cc_datastore->data;
02338 
02339    if (cc_interfaces->ignore) {
02340       ast_channel_unlock(inbound);
02341       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02342       return;
02343    }
02344 
02345    if (!cc_interfaces->is_original_caller) {
02346       /* If the is_original_caller is not set on the *inbound* channel, then
02347        * it must be a local channel. As such, we do not want to create a core instance
02348        * or an agent for the local channel. Instead, we want to pass this along to the
02349        * other side of the local channel so that the original caller can benefit.
02350        */
02351       ast_channel_unlock(inbound);
02352       ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
02353       return;
02354    }
02355 
02356    core_instance = find_cc_core_instance(cc_interfaces->core_id);
02357    if (!core_instance) {
02358       core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
02359          cc_interfaces->core_id, cc_data);
02360       if (!core_instance) {
02361          cc_interfaces->ignore = 1;
02362          ast_channel_unlock(inbound);
02363          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02364          return;
02365       }
02366    }
02367 
02368    ast_channel_unlock(inbound);
02369 
02370    /* Yeah this kind of sucks, but luckily most people
02371     * aren't dialing thousands of interfaces on every call
02372     *
02373     * This traversal helps us to not create duplicate monitors in
02374     * case a device queues multiple CC control frames.
02375     */
02376    AST_LIST_LOCK(cc_interfaces->interface_tree);
02377    AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
02378       if (!strcmp(monitor->interface->device_name, device_name)) {
02379          ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
02380                core_instance->core_id, device_name);
02381          AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02382          cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02383          call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02384          return;
02385       }
02386    }
02387    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02388 
02389    if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
02390       ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
02391       cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02392       call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02393       return;
02394    }
02395 
02396    AST_LIST_LOCK(cc_interfaces->interface_tree);
02397    cc_ref(monitor, "monitor tree's reference to the monitor");
02398    AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
02399    AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02400 
02401    cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
02402 
02403    cc_publish_available(cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service));
02404 
02405    cc_unref(core_instance, "Done with core_instance after handling CC control frame");
02406    cc_unref(monitor, "Unref reference from allocating monitor");
02407 }

void ast_ignore_cc ( struct ast_channel chan  ) 

Mark the channel to ignore further CC activity.

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

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

Definition at line 3717 of file ccss.c.

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

Referenced by dial_exec_full(), and do_forward().

03718 {
03719    struct ast_datastore *cc_datastore;
03720    struct ast_datastore *cc_recall_datastore;
03721    struct dialed_cc_interfaces *cc_interfaces;
03722    struct cc_recall_ds_data *recall_cc_data;
03723 
03724    ast_channel_lock(chan);
03725    if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
03726       cc_interfaces = cc_datastore->data;
03727       cc_interfaces->ignore = 1;
03728    }
03729 
03730    if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03731       recall_cc_data = cc_recall_datastore->data;
03732       recall_cc_data->ignore = 1;
03733    }
03734    ast_channel_unlock(chan);
03735 }

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

Queue an AST_CONTROL_CC frame.

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

Definition at line 4146 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(), LOG_NOTICE, and retval.

Referenced by analog_call(), and sip_handle_cc().

04148 {
04149    struct ast_frame frame = {0,};
04150    char device_name[AST_CHANNEL_NAME];
04151    int retval;
04152    struct ast_cc_config_params *cc_params;
04153 
04154    cc_params = ast_channel_get_cc_config_params(chan);
04155    if (!cc_params) {
04156       return -1;
04157    }
04158    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04159    if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
04160       ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
04161       return -1;
04162    }
04163 
04164    if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
04165       /* Frame building failed. We can't use this. */
04166       return -1;
04167    }
04168    retval = ast_queue_frame(chan, &frame);
04169    ast_frfree(&frame);
04170    return retval;
04171 }

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

Set the cc_agent_dialstring.

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

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

00972 {
00973    if (ast_strlen_zero(value)) {
00974       config->cc_agent_dialstring[0] = '\0';
00975    } else {
00976       ast_copy_string(config->cc_agent_dialstring, value, sizeof(config->cc_agent_dialstring));
00977    }
00978 }

int ast_set_cc_agent_policy ( struct ast_cc_config_params config,
enum ast_cc_agent_policies  value 
)

Set the cc_agent_policy.

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

Definition at line 877 of file ccss.c.

References AST_CC_AGENT_GENERIC, and ast_cc_config_params::cc_agent_policy.

Referenced by ast_cc_set_param(), and build_peer().

00878 {
00879    /* Screw C and its weak type checking for making me have to do this
00880     * validation at runtime.
00881     */
00882    if (value < AST_CC_AGENT_NEVER || value > AST_CC_AGENT_GENERIC) {
00883       return -1;
00884    }
00885    config->cc_agent_policy = value;
00886    return 0;
00887 }

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

Set the callback_macro name.

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

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

01011 {
01012    ast_log(LOG_WARNING, "Usage of cc_callback_macro is deprecated.  Please use cc_callback_sub instead.\n");
01013    if (ast_strlen_zero(value)) {
01014       config->cc_callback_macro[0] = '\0';
01015    } else {
01016       ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
01017    }
01018 }

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

Set the callback subroutine name.

Since:
11
Parameters:
config The configuration to set the callback_sub on
value The new callback subroutine we want to change to
Return values:
void 

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

01021 {
01022    if (ast_strlen_zero(value)) {
01023       config->cc_callback_sub[0] = '\0';
01024    } else {
01025       ast_copy_string(config->cc_callback_sub, value, sizeof(config->cc_callback_sub));
01026    }
01027 }

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.

Since:
1.8
extension@context 
as a starting point
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 local channels, wherein we need to set CC_INTERFACES based on an extension and context that appear in the middle of the tree of dialed interfaces.

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

Definition at line 3665 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, NULL, pbx_builtin_setvar_helper(), and str.

Referenced by local_call().

03666 {
03667    struct ast_datastore *recall_datastore;
03668    struct cc_monitor_tree *interface_tree;
03669    struct ast_cc_monitor *monitor_iter;
03670    struct cc_recall_ds_data *recall_data;
03671    struct ast_str *str = ast_str_create(64);
03672    int core_id;
03673 
03674    if (!str) {
03675       return -1;
03676    }
03677 
03678    ast_channel_lock(chan);
03679    if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03680       ast_channel_unlock(chan);
03681       ast_free(str);
03682       return -1;
03683    }
03684    recall_data = recall_datastore->data;
03685    interface_tree = recall_data->interface_tree;
03686    core_id = recall_data->core_id;
03687    ast_channel_unlock(chan);
03688 
03689    AST_LIST_LOCK(interface_tree);
03690    AST_LIST_TRAVERSE(interface_tree, monitor_iter, next) {
03691       if (!strcmp(monitor_iter->interface->device_name, extension)) {
03692          break;
03693       }
03694    }
03695 
03696    if (!monitor_iter) {
03697       /* We couldn't find this extension. This may be because
03698        * we have been directed into an unexpected extension because
03699        * the admin has changed a CC_INTERFACES variable at some point.
03700        */
03701       AST_LIST_UNLOCK(interface_tree);
03702       ast_free(str);
03703       return -1;
03704    }
03705 
03706    build_cc_interfaces_chanvar(monitor_iter, &str);
03707    AST_LIST_UNLOCK(interface_tree);
03708 
03709    pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03710    ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03711          core_id, ast_str_buffer(str));
03712 
03713    ast_free(str);
03714    return 0;
03715 }

void ast_set_cc_max_agents ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_agents.

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

Definition at line 985 of file ccss.c.

References ast_cc_config_params::cc_max_agents.

Referenced by ast_cc_set_param().

00986 {
00987    config->cc_max_agents = value;
00988 }

void ast_set_cc_max_monitors ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_max_monitors.

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

Definition at line 995 of file ccss.c.

References ast_cc_config_params::cc_max_monitors.

Referenced by ast_cc_set_param().

00996 {
00997    config->cc_max_monitors = value;
00998 }

int ast_set_cc_monitor_policy ( struct ast_cc_config_params config,
enum ast_cc_monitor_policies  value 
)

Set the cc_monitor_policy.

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

Definition at line 894 of file ccss.c.

References AST_CC_MONITOR_ALWAYS, and ast_cc_config_params::cc_monitor_policy.

Referenced by ast_cc_set_param().

00895 {
00896    /* Screw C and its weak type checking for making me have to do this
00897     * validation at runtime.
00898     */
00899    if (value < AST_CC_MONITOR_NEVER || value > AST_CC_MONITOR_ALWAYS) {
00900       return -1;
00901    }
00902    config->cc_monitor_policy = value;
00903    return 0;
00904 }

void ast_set_cc_offer_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_offer_timer.

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

Definition at line 911 of file ccss.c.

References ast_log, ast_cc_config_params::cc_offer_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00912 {
00913    /* 0 is an unreasonable value for any timer. Stick with the default */
00914    if (value == 0) {
00915       ast_log(LOG_WARNING, "0 is an invalid value for cc_offer_timer. Retaining value as %u\n", config->cc_offer_timer);
00916       return;
00917    }
00918    config->cc_offer_timer = value;
00919 }

void ast_set_cc_recall_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the cc_recall_timer.

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

Definition at line 941 of file ccss.c.

References ast_log, ast_cc_config_params::cc_recall_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00942 {
00943    /* 0 is an unreasonable value for any timer. Stick with the default */
00944    if (value == 0) {
00945       ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
00946       return;
00947    }
00948    config->cc_recall_timer = value;
00949 }

void ast_set_ccbs_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccbs_available_timer.

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

Definition at line 956 of file ccss.c.

References ast_log, ast_cc_config_params::ccbs_available_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00957 {
00958    /* 0 is an unreasonable value for any timer. Stick with the default */
00959    if (value == 0) {
00960       ast_log(LOG_WARNING, "0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
00961       return;
00962    }
00963    config->ccbs_available_timer = value;
00964 }

void ast_set_ccnr_available_timer ( struct ast_cc_config_params config,
unsigned int  value 
)

Set the ccnr_available_timer.

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

Definition at line 926 of file ccss.c.

References ast_log, ast_cc_config_params::ccnr_available_timer, and LOG_WARNING.

Referenced by ast_cc_set_param().

00927 {
00928    /* 0 is an unreasonable value for any timer. Stick with the default */
00929    if (value == 0) {
00930       ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->ccnr_available_timer);
00931       return;
00932    }
00933    config->ccnr_available_timer = value;
00934 }

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

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

Referenced by generic_recall(), and handle_request_invite().

03403 {
03404    struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
03405    struct cc_recall_ds_data *recall_data;
03406    struct cc_core_instance *core_instance;
03407 
03408    if (!recall_datastore) {
03409       return -1;
03410    }
03411 
03412    if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
03413       ast_datastore_free(recall_datastore);
03414       return -1;
03415    }
03416 
03417    if (!(core_instance = find_cc_core_instance(core_id))) {
03418       ast_free(recall_data);
03419       ast_datastore_free(recall_datastore);
03420       return -1;
03421    }
03422 
03423    recall_data->interface_tree = cc_ref(core_instance->monitors,
03424          "Bump refcount for monitor tree for recall datastore");
03425    recall_data->core_id = core_id;
03426    recall_datastore->data = recall_data;
03427    recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
03428    ast_channel_lock(chan);
03429    ast_channel_datastore_add(chan, recall_datastore);
03430    ast_channel_unlock(chan);
03431    cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
03432    return 0;
03433 }

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

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

03586 {
03587    struct extension_monitor_pvt *extension_pvt;
03588    struct extension_child_dialstring *child_dialstring;
03589    struct ast_cc_monitor *monitor_iter = starting_point;
03590    int top_level_id = starting_point->id;
03591    size_t length;
03592 
03593    /* Init to an empty string. */
03594    ast_str_truncate(*str, 0);
03595 
03596    /* First we need to take all of the is_valid child_dialstrings from
03597     * the extension monitor we found and add them to the CC_INTERFACES
03598     * chanvar
03599     */
03600    extension_pvt = starting_point->private_data;
03601    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
03602       if (child_dialstring->is_valid) {
03603          cc_unique_append(str, child_dialstring->original_dialstring);
03604       }
03605    }
03606 
03607    /* And now we get the dialstrings from each of the device monitors */
03608    while ((monitor_iter = AST_LIST_NEXT(monitor_iter, next))) {
03609       if (monitor_iter->parent_id == top_level_id) {
03610          cc_unique_append(str, monitor_iter->dialstring);
03611       }
03612    }
03613 
03614    /* str will have an extra '&' tacked onto the end of it, so we need
03615     * to get rid of that.
03616     */
03617    length = ast_str_strlen(*str);
03618    if (length) {
03619       ast_str_truncate(*str, length - 1);
03620    }
03621    if (length <= 1) {
03622       /* Nothing to recall?  This should not happen. */
03623       ast_log(LOG_ERROR, "CC_INTERFACES is empty. starting device_name:'%s'\n",
03624          starting_point->interface->device_name);
03625    }
03626 }

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

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

02215 {
02216    const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
02217 
02218    if (!monitor_callbacks) {
02219       return;
02220    }
02221 
02222    monitor_callbacks->destructor(private_data);
02223 }

static void cancel_available_timer ( struct cc_core_instance core_instance  )  [static]

Definition at line 3223 of file ccss.c.

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

Referenced by cc_recalling().

03224 {
03225    struct ast_cc_monitor *monitor_iter;
03226    AST_LIST_LOCK(core_instance->monitors);
03227    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
03228       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
03229          if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
03230             AST_LIST_REMOVE_CURRENT(next);
03231             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
03232                   monitor_iter->interface->device_name, 1);
03233             cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
03234          }
03235       }
03236    }
03237    AST_LIST_TRAVERSE_SAFE_END;
03238 
03239    if (!has_device_monitors(core_instance)) {
03240       ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
03241    }
03242    AST_LIST_UNLOCK(core_instance->monitors);
03243 }

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 3165 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_publish_callerstopmonitoring(), cc_publish_requestacknowledged(), cc_core_instance::core_id, ast_cc_agent::device_name, ast_cc_agent_callbacks::respond, and unsuspend().

03166 {
03167    /* Either
03168     * 1. Callee accepted CC request, call agent's ack callback.
03169     * 2. Caller became available, call agent's stop_monitoring callback and
03170     *    call monitor's unsuspend callback.
03171     */
03172    if (previous_state == CC_CALLER_REQUESTED) {
03173       core_instance->agent->callbacks->respond(core_instance->agent,
03174          AST_CC_AGENT_RESPONSE_SUCCESS);
03175       cc_publish_requestacknowledged(core_instance->core_id, core_instance->agent->device_name);
03176    } else if (previous_state == CC_CALLER_BUSY) {
03177       cc_publish_callerstopmonitoring(core_instance->core_id, core_instance->agent->device_name);
03178       unsuspend(core_instance);
03179    }
03180    /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
03181    return 0;
03182 }

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

Definition at line 446 of file ccss.c.

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

Referenced by ast_cc_agent_callback().

00447 {
00448    struct cc_core_instance *core_instance = obj;
00449    struct cc_callback_helper *helper = args;
00450 
00451    if (strcmp(core_instance->agent->callbacks->type, helper->type)) {
00452       return 0;
00453    }
00454 
00455    return helper->function(core_instance->agent, helper->args, flags);
00456 }

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 2554 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(), ast_cc_agent_callbacks::init, and NULL.

Referenced by cc_core_init_instance().

02557 {
02558    struct ast_cc_agent *agent;
02559    struct ast_cc_config_params *cc_params;
02560 
02561    if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
02562                "Allocating new ast_cc_agent"))) {
02563       return NULL;
02564    }
02565 
02566    agent->core_id = core_id;
02567    strcpy(agent->device_name, caller_name);
02568 
02569    cc_params = ast_channel_get_cc_config_params(caller_chan);
02570    if (!cc_params) {
02571       cc_unref(agent, "Could not get channel config params.");
02572       return NULL;
02573    }
02574    if (!(agent->cc_params = ast_cc_config_params_init())) {
02575       cc_unref(agent, "Could not init agent config params.");
02576       return NULL;
02577    }
02578    ast_cc_copy_config_params(agent->cc_params, cc_params);
02579 
02580    if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
02581       cc_unref(agent, "Could not find agent callbacks.");
02582       return NULL;
02583    }
02584    check_callback_sanity(agent->callbacks);
02585 
02586    if (agent->callbacks->init(agent, caller_chan)) {
02587       cc_unref(agent, "Agent init callback failed.");
02588       return NULL;
02589    }
02590    ast_log_dynamic_level(cc_logger_level, "Core %u: Created an agent for caller %s\n",
02591          agent->core_id, agent->device_name);
02592    return agent;
02593 }

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

References ast_log, and LOG_WARNING.

03055 {
03056    /* This should never happen... */
03057    ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
03058    return -1;
03059 }

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

Definition at line 4118 of file ccss.c.

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

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

04121 {
04122    struct ast_datastore *datastore;
04123    struct dialed_cc_interfaces *cc_interfaces;
04124    int dial_parent_id;
04125 
04126    ast_channel_lock(chan);
04127    datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL);
04128    if (!datastore) {
04129       ast_channel_unlock(chan);
04130       return -1;
04131    }
04132    cc_interfaces = datastore->data;
04133    dial_parent_id = cc_interfaces->dial_parent_id;
04134    ast_channel_unlock(chan);
04135 
04136    payload->monitor_type = monitor_type;
04137    payload->private_data = private_data;
04138    payload->service = service;
04139    ast_cc_copy_config_params(&payload->config_params, cc_params);
04140    payload->parent_interface_id = dial_parent_id;
04141    ast_copy_string(payload->device_name, device_name, sizeof(payload->device_name));
04142    ast_copy_string(payload->dialstring, dialstring, sizeof(payload->dialstring));
04143    return 0;
04144 }

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

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

03185 {
03186    core_instance->agent->callbacks->callee_available(core_instance->agent);
03187    return 0;
03188 }

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

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

03213 {
03214    /* Callee was available, but caller was busy, call agent's begin_monitoring callback
03215     * and call monitor's suspend callback.
03216     */
03217    suspend(core_instance);
03218    core_instance->agent->callbacks->start_monitoring(core_instance->agent);
03219    cc_publish_callerstartmonitoring(core_instance->core_id, core_instance->agent->device_name);
03220    return 0;
03221 }

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 3061 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_publish_offertimerstart(), cc_core_instance::core_id, ast_cc_agent::device_name, and ast_cc_agent_callbacks::start_offer_timer.

03062 {
03063    if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
03064       ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
03065             core_instance->agent->device_name);
03066       return -1;
03067    }
03068    cc_publish_offertimerstart(core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
03069    ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
03070          core_instance->core_id, core_instance->agent->device_name);
03071    return 0;
03072 }

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

03130 {
03131    if (!ast_cc_request_is_within_limits()) {
03132       ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
03133       core_instance->agent->callbacks->respond(core_instance->agent,
03134          AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY);
03135       ast_cc_failed(core_instance->core_id, "Too many requests in the system");
03136       return -1;
03137    }
03138    core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
03139    request_cc(core_instance);
03140    return 0;
03141 }

static int cc_cli_output_status ( void *  data  )  [static]

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

04492 {
04493    int *cli_fd = data;
04494    int count = ao2_container_count(cc_core_instances);
04495 
04496    if (!count) {
04497       ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
04498    } else {
04499       ast_cli(*cli_fd, "%d Call completion transactions\n", count);
04500       ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
04501       ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
04502       ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
04503    }
04504    ast_free(cli_fd);
04505    return 0;
04506 }

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

Definition at line 4458 of file ccss.c.

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

Referenced by print_stats_cb().

04459 {
04460    struct ast_cc_monitor *child_monitor_iter = monitor;
04461    if (!monitor) {
04462       return;
04463    }
04464 
04465    ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
04466    if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
04467       ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
04468    }
04469    ast_cli(fd, "\n");
04470 
04471    while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
04472       if (child_monitor_iter->parent_id == monitor->id) {
04473          cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
04474       }
04475    }
04476 }

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

References cc_core_instance::agent, ao2_t_unlink, cc_publish_recallcomplete(), cc_core_instance::core_id, and ast_cc_agent::device_name.

03255 {
03256    /* Recall has made progress, call agent and monitor destructor functions
03257     */
03258    cc_publish_recallcomplete(core_instance->core_id, core_instance->agent->device_name);
03259    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
03260    return 0;
03261 }

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 2937 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(), cc_core_instance::monitors, and NULL.

Referenced by ast_handle_cc_control_frame().

02939 {
02940    char caller[AST_CHANNEL_NAME];
02941    struct cc_core_instance *core_instance;
02942    struct ast_cc_config_params *cc_params;
02943    long agent_count;
02944    int recall_core_id;
02945 
02946    ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
02947    cc_params = ast_channel_get_cc_config_params(caller_chan);
02948    if (!cc_params) {
02949       ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
02950          caller);
02951       return NULL;
02952    }
02953    /* First, we need to kill off other pending CC offers from caller. If the caller is going
02954     * to request a CC service, it may only be for the latest call he made.
02955     */
02956    if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02957       kill_duplicate_offers(caller);
02958    }
02959 
02960    ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
02961    agent_count = count_agents(caller, recall_core_id);
02962    if (agent_count >= ast_get_cc_max_agents(cc_params)) {
02963       ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
02964       return NULL;
02965    }
02966 
02967    /* Generic agents can only have a single outstanding CC request per caller. */
02968    if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02969       ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
02970       return NULL;
02971    }
02972 
02973    /* Next, we need to create the core instance for this call */
02974    if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
02975       return NULL;
02976    }
02977 
02978    core_instance->core_id = core_id;
02979    if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
02980       cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
02981       return NULL;
02982    }
02983 
02984    core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");
02985 
02986    ao2_t_link(cc_core_instances, core_instance, "Link core instance into container");
02987 
02988    return core_instance;
02989 }

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

Definition at line 425 of file ccss.c.

References CMP_MATCH, CMP_STOP, and cc_core_instance::core_id.

Referenced by ast_cc_init().

00426 {
00427    struct cc_core_instance *core_instance1 = obj;
00428    struct cc_core_instance *core_instance2 = arg;
00429 
00430    return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
00431 }

static void cc_core_instance_destructor ( void *  data  )  [static]

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

02926 {
02927    struct cc_core_instance *core_instance = data;
02928    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
02929    if (core_instance->agent) {
02930       cc_unref(core_instance->agent, "Core instance is done with the agent now");
02931    }
02932    if (core_instance->monitors) {
02933       core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
02934    }
02935 }

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

Definition at line 419 of file ccss.c.

References cc_core_instance::core_id.

Referenced by ast_cc_init().

00420 {
00421    const struct cc_core_instance *core_instance = obj;
00422    return core_instance->core_id;
00423 }

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

References ao2_t_alloc, ast_atomic_fetchadd_int(), ast_cc_config_params_init, ast_cc_copy_config_params(), AST_CC_DEVICE_MONITOR, ast_log_dynamic_level, ast_strdup, ast_cc_monitor::available_timer_id, ast_cc_monitor::callbacks, cc_interface_destroy(), cc_monitor_destroy(), cc_unref(), cc_control_payload::config_params, ast_cc_interface::config_params, ast_cc_monitor::core_id, ast_cc_interface::device_name, ast_cc_monitor::dialstring, find_monitor_callbacks(), ast_cc_monitor::id, ast_cc_monitor::interface, monitor, ast_cc_interface::monitor_class, ast_cc_interface::monitor_type, cc_control_payload::monitor_type, NULL, 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().

02251 {
02252    struct ast_cc_interface *cc_interface;
02253    struct ast_cc_monitor *monitor;
02254    size_t device_name_len = strlen(device_name);
02255    int parent_id = cc_data->parent_interface_id;
02256 
02257    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
02258                "Allocating new ast_cc_interface"))) {
02259       return NULL;
02260    }
02261 
02262    if (!(cc_interface->config_params = ast_cc_config_params_init())) {
02263       cc_unref(cc_interface, "Failed to allocate config params, unref interface");
02264       return NULL;
02265    }
02266 
02267    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
02268       cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
02269       return NULL;
02270    }
02271 
02272    if (!(monitor->dialstring = ast_strdup(dialstring))) {
02273       cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
02274       cc_unref(cc_interface, "Failed to copy dialable name");
02275       return NULL;
02276    }
02277 
02278    if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
02279       cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
02280       cc_unref(cc_interface, "Failed to find monitor callbacks");
02281       return NULL;
02282    }
02283 
02284    strcpy(cc_interface->device_name, device_name);
02285    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
02286    monitor->parent_id = parent_id;
02287    monitor->core_id = core_id;
02288    monitor->service_offered = cc_data->service;
02289    monitor->private_data = cc_data->private_data;
02290    cc_interface->monitor_type = cc_data->monitor_type;
02291    cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
02292    monitor->interface = cc_interface;
02293    monitor->available_timer_id = -1;
02294    ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
02295    ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %u and parent %u\n",
02296          monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
02297    return monitor;
02298 }

static int cc_do_state_change ( void *  datap  )  [static]

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

03283 {
03284    struct cc_state_change_args *args = datap;
03285    struct cc_core_instance *core_instance;
03286    enum cc_state previous_state;
03287    int res;
03288 
03289    ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %u requested. Reason: %s\n",
03290          args->core_id, args->state, args->debug);
03291 
03292    core_instance = args->core_instance;
03293 
03294    if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
03295       ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
03296             args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
03297       if (args->state == CC_CALLER_REQUESTED) {
03298          /*
03299           * For out-of-order requests, we need to let the requester know that
03300           * we can't handle the request now.
03301           */
03302          core_instance->agent->callbacks->respond(core_instance->agent,
03303             AST_CC_AGENT_RESPONSE_FAILURE_INVALID);
03304       }
03305       ast_free(args);
03306       cc_unref(core_instance, "Unref core instance from when it was found earlier");
03307       return -1;
03308    }
03309 
03310    /* We can change to the new state now. */
03311    previous_state = core_instance->current_state;
03312    core_instance->current_state = args->state;
03313    res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);
03314 
03315    /* If state change successful then notify any device state watchers of the change */
03316    if (!res && !strcmp(core_instance->agent->callbacks->type, "generic")) {
03317       ccss_notify_device_state_change(core_instance->agent->device_name, core_instance->current_state);
03318    }
03319 
03320    ast_free(args);
03321    cc_unref(core_instance, "Unref since state change has completed"); /* From ao2_find */
03322    return res;
03323 }

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

02049 {
02050    struct ast_cc_monitor *monitor_iter;
02051    struct extension_monitor_pvt *extension_pvt;
02052    struct extension_child_dialstring *child_dialstring;
02053 
02054    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
02055       if (monitor_iter->id == parent_id) {
02056          break;
02057       }
02058    }
02059 
02060    if (!monitor_iter) {
02061       return;
02062    }
02063    extension_pvt = monitor_iter->private_data;
02064 
02065    AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
02066       if (!strcmp(child_dialstring->device_name, device_name)) {
02067          child_dialstring->is_valid = is_valid;
02068          break;
02069       }
02070    }
02071 }

static void cc_extension_monitor_destructor ( void *  private_data  )  [static]

Definition at line 1819 of file ccss.c.

References ast_free, AST_LIST_REMOVE_HEAD, and extension_monitor_pvt::child_dialstrings.

Referenced by cc_monitor_destroy().

01820 {
01821    struct extension_monitor_pvt *extension_pvt = private_data;
01822    struct extension_child_dialstring *child_dialstring;
01823 
01824    /* This shouldn't be possible, but I'm paranoid */
01825    if (!extension_pvt) {
01826       return;
01827    }
01828 
01829    while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
01830       ast_free(child_dialstring);
01831    }
01832    ast_free(extension_pvt);
01833 }

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 2087 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, NULL, ast_cc_monitor::parent_id, ast_cc_monitor::private_data, and str.

Referenced by ast_cc_call_init(), and cc_interfaces_datastore_init().

02088 {
02089    struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
02090    struct ast_cc_interface *cc_interface;
02091    struct ast_cc_monitor *monitor;
02092 
02093    ast_str_set(&str, 0, "%s@%s", exten, context);
02094 
02095    if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
02096                "Allocating new ast_cc_interface"))) {
02097       return NULL;
02098    }
02099 
02100    if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
02101       cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
02102       return NULL;
02103    }
02104 
02105    if (!(monitor->private_data = extension_monitor_pvt_init())) {
02106       cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
02107       cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
02108    }
02109 
02110    monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
02111    monitor->parent_id = parent_id;
02112    cc_interface->monitor_type = "extension";
02113    cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
02114    strcpy(cc_interface->device_name, ast_str_buffer(str));
02115    monitor->interface = cc_interface;
02116    ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %u and parent %u\n", cc_interface->device_name, monitor->id, monitor->parent_id);
02117    return monitor;
02118 }

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

References cc_core_instance::agent, ao2_t_unlink, cc_publish_failure(), cc_core_instance::core_id, cc_state_change_args::debug, and ast_cc_agent::device_name.

03264 {
03265    cc_publish_failure(core_instance->core_id, core_instance->agent->device_name, args->debug);
03266    ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
03267    return 0;
03268 }

static void cc_generic_agent_destructor ( struct ast_cc_agent agent  )  [static]

Definition at line 2908 of file ccss.c.

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

02909 {
02910    struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02911 
02912    if (!agent_pvt) {
02913       /* The agent constructor probably failed. */
02914       return;
02915    }
02916 
02917    cc_generic_agent_stop_offer_timer(agent);
02918    if (agent_pvt->sub) {
02919       agent_pvt->sub = stasis_unsubscribe(agent_pvt->sub);
02920    }
02921 
02922    ast_free(agent_pvt);
02923 }

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

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

02670 {
02671    struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
02672 
02673    if (!generic_pvt) {
02674       return -1;
02675    }
02676 
02677    generic_pvt->offer_timer_id = -1;
02678    if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
02679       ast_copy_string(generic_pvt->cid_num, ast_channel_caller(chan)->id.number.str, sizeof(generic_pvt->cid_num));
02680    }
02681    if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
02682       ast_copy_string(generic_pvt->cid_name, ast_channel_caller(chan)->id.name.str, sizeof(generic_pvt->cid_name));
02683    }
02684    ast_copy_string(generic_pvt->exten, S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)), sizeof(generic_pvt->exten));
02685    ast_copy_string(generic_pvt->context, S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), sizeof(generic_pvt->context));
02686    agent->private_data = generic_pvt;
02687    ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
02688    return 0;
02689 }

static int cc_generic_agent_recall ( struct ast_cc_agent agent  )  [static]

Definition at line 2892 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, generic_recall(), and NULL.

02893 {
02894    pthread_t clotho;
02895    enum ast_device_state current_state = ast_device_state(agent->device_name);
02896 
02897    if (!cc_generic_is_device_available(current_state)) {
02898       /* We can't try to contact the device right now because he's not available
02899        * Let the core know he's busy.
02900        */
02901       ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
02902       return 0;
02903    }
02904    ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
02905    return 0;
02906 }

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

Definition at line 2735 of file ccss.c.

02736 {
02737    /* The generic agent doesn't have to do anything special to
02738     * acknowledge a CC request. Just return.
02739     */
02740    return;
02741 }

static int cc_generic_agent_start_monitoring ( struct ast_cc_agent agent  )  [static]

Definition at line 2791 of file ccss.c.

References ast_assert, ast_device_state_topic(), ast_str_alloca, ast_str_set(), cc_ref(), ast_cc_agent::device_name, generic_agent_devstate_cb(), NULL, ast_cc_agent::private_data, stasis_subscribe(), str, and cc_generic_agent_pvt::sub.

02792 {
02793    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02794    struct ast_str *str = ast_str_alloca(128);
02795    struct stasis_topic *device_specific_topic;
02796 
02797    ast_assert(generic_pvt->sub == NULL);
02798    ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
02799       agent->device_name);
02800 
02801    device_specific_topic = ast_device_state_topic(agent->device_name);
02802    if (!device_specific_topic) {
02803       return -1;
02804    }
02805 
02806    if (!(generic_pvt->sub = stasis_subscribe(device_specific_topic, generic_agent_devstate_cb, agent))) {
02807       return -1;
02808    }
02809    cc_ref(agent, "Ref agent for subscription");
02810    return 0;
02811 }

static int cc_generic_agent_start_offer_timer ( struct ast_cc_agent agent  )  [static]

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

02704 {
02705    int when;
02706    int sched_id;
02707    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02708 
02709    ast_assert(cc_sched_context != NULL);
02710    ast_assert(agent->cc_params != NULL);
02711 
02712    when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
02713    ast_log_dynamic_level(cc_logger_level, "Core %u: About to schedule offer timer expiration for %d ms\n",
02714          agent->core_id, when);
02715    if ((sched_id = ast_sched_add(cc_sched_context, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
02716       return -1;
02717    }
02718    generic_pvt->offer_timer_id = sched_id;
02719    return 0;
02720 }

static int cc_generic_agent_status_request ( struct ast_cc_agent agent  )  [static]

Definition at line 2743 of file ccss.c.

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

02744 {
02745    ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
02746    return 0;
02747 }

static int cc_generic_agent_stop_offer_timer ( struct ast_cc_agent agent  )  [static]

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

02723 {
02724    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02725 
02726    if (generic_pvt->offer_timer_id != -1) {
02727       if (!ast_sched_del(cc_sched_context, generic_pvt->offer_timer_id)) {
02728          cc_unref(agent, "Remove scheduler's reference to the agent");
02729       }
02730       generic_pvt->offer_timer_id = -1;
02731    }
02732    return 0;
02733 }

static int cc_generic_agent_stop_ringing ( struct ast_cc_agent agent  )  [static]

Definition at line 2749 of file ccss.c.

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

02750 {
02751    struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
02752 
02753    if (!recall_chan) {
02754       return 0;
02755    }
02756 
02757    ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
02758    return 0;
02759 }

static int cc_generic_is_device_available ( enum ast_device_state  state  )  [static]

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

Definition at line 1649 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, ast_cc_monitor::interface, and NULL.

01650 {
01651    ast_assert(sched_id != NULL);
01652 
01653    if (*sched_id == -1) {
01654       return 0;
01655    }
01656 
01657    ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
01658          monitor->core_id, monitor->interface->device_name);
01659    if (!ast_sched_del(cc_sched_context, *sched_id)) {
01660       cc_unref(monitor, "Remove scheduler's reference to the monitor");
01661    }
01662    *sched_id = -1;
01663    return 0;
01664 }

static void cc_generic_monitor_destructor ( void *  private_data  )  [static]

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

01667 {
01668    struct generic_monitor_pvt *gen_mon_pvt = private_data;
01669    struct generic_monitor_instance_list *generic_list;
01670    struct generic_monitor_instance *generic_instance;
01671 
01672    if (!private_data) {
01673       /* If the private data is NULL, that means that the monitor hasn't even
01674        * been created yet, but that the destructor was called. While this sort
01675        * of behavior is useful for native monitors, with a generic one, there is
01676        * nothing in particular to do.
01677        */
01678       return;
01679    }
01680 
01681    ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying generic monitor %s\n",
01682          gen_mon_pvt->core_id, gen_mon_pvt->device_name);
01683 
01684    if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->device_name))) {
01685       /* If there's no generic list, that means that the monitor is being destroyed
01686        * before we actually got to request CC. Not a biggie. Same in the situation
01687        * below if the list traversal should complete without finding an entry.
01688        */
01689       ast_free((char *)gen_mon_pvt->device_name);
01690       ast_free(gen_mon_pvt);
01691       return;
01692    }
01693 
01694    AST_LIST_TRAVERSE_SAFE_BEGIN(&generic_list->list, generic_instance, next) {
01695       if (generic_instance->core_id == gen_mon_pvt->core_id) {
01696          AST_LIST_REMOVE_CURRENT(next);
01697          ast_free(generic_instance);
01698          break;
01699       }
01700    }
01701    AST_LIST_TRAVERSE_SAFE_END;
01702 
01703    if (AST_LIST_EMPTY(&generic_list->list)) {
01704       /* No more monitors with this device name exist. Time to unlink this
01705        * list from the container
01706        */
01707       ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
01708    } else {
01709       /* There are still instances for this particular device. The situation
01710        * may be that we were attempting a CC recall and a failure occurred, perhaps
01711        * on the agent side. If a failure happens here and the device being monitored
01712        * is available, then we need to signal on the first unsuspended instance that
01713        * the device is available for recall.
01714        */
01715 
01716       /* First things first. We don't even want to consider this action if
01717        * the device in question isn't available right now.
01718        */
01719       if (generic_list->fit_for_recall
01720          && cc_generic_is_device_available(generic_list->current_state)) {
01721          AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01722             if (!generic_instance->is_suspended && generic_instance->monitoring) {
01723                ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
01724                      "availability due to other instance's failure.");
01725                break;
01726             }
01727          }
01728       }
01729    }
01730    cc_unref(generic_list, "Done with generic list in generic monitor destructor");
01731    ast_free((char *)gen_mon_pvt->device_name);
01732    ast_free(gen_mon_pvt);
01733 }

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

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

01518 {
01519    struct generic_monitor_instance_list *generic_list;
01520    struct generic_monitor_instance *generic_instance;
01521    struct generic_monitor_pvt *gen_mon_pvt;
01522    enum ast_cc_service_type service = monitor->service_offered;
01523    int when;
01524 
01525    /* First things first. Native channel drivers will have their private data allocated
01526     * at the time that they tell the core that they can offer CC. Generic is quite a bit
01527     * different, and we wait until this point to allocate our private data.
01528     */
01529    if (!(gen_mon_pvt = ast_calloc(1, sizeof(*gen_mon_pvt)))) {
01530       return -1;
01531    }
01532 
01533    if (!(gen_mon_pvt->device_name = ast_strdup(monitor->interface->device_name))) {
01534       ast_free(gen_mon_pvt);
01535       return -1;
01536    }
01537 
01538    gen_mon_pvt->core_id = monitor->core_id;
01539 
01540    monitor->private_data = gen_mon_pvt;
01541 
01542    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01543       if (!(generic_list = create_new_generic_list(monitor))) {
01544          return -1;
01545       }
01546    }
01547 
01548    if (!(generic_instance = ast_calloc(1, sizeof(*generic_instance)))) {
01549       /* The generic monitor destructor will take care of the appropriate
01550        * deallocations
01551        */
01552       cc_unref(generic_list, "Generic monitor instance failed to allocate");
01553       return -1;
01554    }
01555    generic_instance->core_id = monitor->core_id;
01556    generic_instance->monitoring = 1;
01557    AST_LIST_INSERT_TAIL(&generic_list->list, generic_instance, next);
01558    when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
01559       ast_get_ccnr_available_timer(monitor->interface->config_params);
01560 
01561    *available_timer_id = ast_sched_add(cc_sched_context, when * 1000,
01562          ast_cc_available_timer_expire, cc_ref(monitor, "Give the scheduler a monitor reference"));
01563    if (*available_timer_id == -1) {
01564       cc_unref(monitor, "Failed to schedule available timer. (monitor)");
01565       cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
01566       return -1;
01567    }
01568    /* If the new instance was created as CCNR, then that means this device is not currently
01569     * fit for recall even if it previously was.
01570     */
01571    if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
01572       generic_list->fit_for_recall = 0;
01573    }
01574    ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
01575          monitor->interface->device_name);
01576    cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
01577    return 0;
01578 }

static int cc_generic_monitor_suspend ( struct ast_cc_monitor monitor  )  [static]

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

01581 {
01582    struct generic_monitor_instance_list *generic_list;
01583    struct generic_monitor_instance *generic_instance;
01584    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01585 
01586    if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01587       return -1;
01588    }
01589 
01590    /* First we need to mark this particular monitor as being suspended. */
01591    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01592       if (generic_instance->core_id == monitor->core_id) {
01593          generic_instance->is_suspended = 1;
01594          break;
01595       }
01596    }
01597 
01598    /* If the device being suspended is currently in use, then we don't need to
01599     * take any further actions
01600     */
01601    if (!cc_generic_is_device_available(state)) {
01602       cc_unref(generic_list, "Device is in use. Nothing to do. Unref generic list.");
01603       return 0;
01604    }
01605 
01606    /* If the device is not in use, though, then it may be possible to report the
01607     * device's availability using a different monitor which is monitoring the
01608     * same device
01609     */
01610 
01611    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01612       if (!generic_instance->is_suspended) {
01613          ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01614          break;
01615       }
01616    }
01617    cc_unref(generic_list, "Done with generic list in suspend callback");
01618    return 0;
01619 }

static int cc_generic_monitor_unsuspend ( struct ast_cc_monitor monitor  )  [static]

Definition at line 1621 of file ccss.c.

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

01622 {
01623    struct generic_monitor_instance *generic_instance;
01624    struct generic_monitor_instance_list *generic_list = find_generic_monitor_instance_list(monitor->interface->device_name);
01625    enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01626 
01627    if (!generic_list) {
01628       return -1;
01629    }
01630    /* If the device is currently available, we can immediately announce
01631     * its availability
01632     */
01633    if (cc_generic_is_device_available(state)) {
01634       ast_cc_monitor_callee_available(monitor->core_id, "Generic monitored party has become available");
01635    }
01636 
01637    /* In addition, we need to mark this generic_monitor_instance as not being suspended anymore */
01638    AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01639       if (generic_instance->core_id == monitor->core_id) {
01640          generic_instance->is_suspended = 0;
01641          generic_instance->monitoring = 1;
01642          break;
01643       }
01644    }
01645    cc_unref(generic_list, "Done with generic list in cc_generic_monitor_unsuspend");
01646    return 0;
01647 }

static void cc_interface_destroy ( void *  data  )  [static]

Definition at line 1735 of file ccss.c.

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

Referenced by cc_device_monitor_init(), and cc_extension_monitor_init().

01736 {
01737    struct ast_cc_interface *interface = data;
01738    ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
01739    ast_cc_config_params_destroy(interface->config_params);
01740 }

static void cc_interface_tree_destroy ( void *  data  )  [static]

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

01857 {
01858    struct cc_monitor_tree *cc_interface_tree = data;
01859    struct ast_cc_monitor *monitor;
01860    while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
01861       if (monitor->callbacks) {
01862          monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
01863       }
01864       cc_unref(monitor, "Destroying all monitors");
01865    }
01866    AST_LIST_HEAD_DESTROY(cc_interface_tree);
01867 }

static int cc_interfaces_datastore_init ( struct ast_channel chan  )  [static]

Definition at line 2136 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, NULL, and S_OR.

Referenced by ast_cc_call_init().

02136                                                                   {
02137    struct dialed_cc_interfaces *interfaces;
02138    struct ast_cc_monitor *monitor;
02139    struct ast_datastore *dial_cc_datastore;
02140 
02141    /*XXX This may be a bit controversial. In an attempt to not allocate
02142     * extra resources, I make sure that a future request will be within
02143     * limits. The problem here is that it is reasonable to think that
02144     * even if we're not within the limits at this point, we may be by
02145     * the time the requestor will have made his request. This may be
02146     * deleted at some point.
02147     */
02148    if (!ast_cc_request_is_within_limits()) {
02149       return 0;
02150    }
02151 
02152    if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
02153       return -1;
02154    }
02155 
02156    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))) {
02157       ast_free(interfaces);
02158       return -1;
02159    }
02160 
02161    if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
02162       cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
02163       ast_free(interfaces);
02164       return -1;
02165    }
02166 
02167    if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
02168                "Allocate monitor tree"))) {
02169       ast_datastore_free(dial_cc_datastore);
02170       cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
02171       ast_free(interfaces);
02172       return -1;
02173    }
02174 
02175    /* Finally, all that allocation is done... */
02176    AST_LIST_HEAD_INIT(interfaces->interface_tree);
02177    AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
02178    cc_ref(monitor, "List's reference to extension monitor");
02179    dial_cc_datastore->data = interfaces;
02180    dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
02181    interfaces->dial_parent_id = monitor->id;
02182    interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
02183    interfaces->is_original_caller = 1;
02184    ast_channel_lock(chan);
02185    ast_channel_datastore_add(chan, dial_cc_datastore);
02186    ast_channel_unlock(chan);
02187    cc_unref(monitor, "Unreffing allocation's reference");
02188    return 0;
02189 }

static void cc_monitor_destroy ( void *  data  )  [static]

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

01836 {
01837    struct ast_cc_monitor *monitor = data;
01838    /* During the monitor creation process, it is possible for this
01839     * function to be called prior to when callbacks are assigned
01840     * to the monitor. Also, extension monitors do not have callbacks
01841     * assigned to them, so we wouldn't want to segfault when we try
01842     * to destroy one of them.
01843     */
01844    ast_log_dynamic_level(cc_logger_level, "Core %d: Calling destructor for monitor %s\n",
01845          monitor->core_id, monitor->interface->device_name);
01846    if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
01847       cc_extension_monitor_destructor(monitor->private_data);
01848    }
01849    if (monitor->callbacks) {
01850       monitor->callbacks->destructor(monitor->private_data);
01851    }
01852    cc_unref(monitor->interface, "Unreffing tree's reference to interface");
01853    ast_free(monitor->dialstring);
01854 }

static int cc_monitor_failed ( void *  data  )  [static]

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

Referenced by ast_cc_monitor_failed().

03894 {
03895    struct ast_cc_monitor_failure_data *failure_data = data;
03896    struct cc_core_instance *core_instance;
03897    struct ast_cc_monitor *monitor_iter;
03898 
03899    core_instance = find_cc_core_instance(failure_data->core_id);
03900    if (!core_instance) {
03901       /* Core instance no longer exists or invalid core_id. */
03902       ast_log_dynamic_level(cc_logger_level,
03903          "Core %d: Could not find core instance for device %s '%s'\n",
03904          failure_data->core_id, failure_data->device_name, failure_data->debug);
03905       ast_free((char *) failure_data->device_name);
03906       ast_free((char *) failure_data->debug);
03907       ast_free(failure_data);
03908       return -1;
03909    }
03910 
03911    AST_LIST_LOCK(core_instance->monitors);
03912    AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
03913       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
03914          if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
03915             AST_LIST_REMOVE_CURRENT(next);
03916             cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
03917                   monitor_iter->interface->device_name, 1);
03918             monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
03919             cc_publish_monitorfailed(monitor_iter->core_id, monitor_iter->interface->device_name);
03920             cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
03921          }
03922       }
03923    }
03924    AST_LIST_TRAVERSE_SAFE_END;
03925 
03926    if (!has_device_monitors(core_instance)) {
03927       ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
03928    }
03929    AST_LIST_UNLOCK(core_instance->monitors);
03930    cc_unref(core_instance, "Finished with core_instance in cc_monitor_failed\n");
03931 
03932    ast_free((char *) failure_data->device_name);
03933    ast_free((char *) failure_data->debug);
03934    ast_free(failure_data);
03935    return 0;
03936 }

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

Definition at line 3737 of file ccss.c.

References CC_CALLER_OFFERED, and cc_request_state_change().

Referenced by ast_cc_offer().

03738 {
03739    va_list ap;
03740    int res;
03741 
03742    va_start(ap, debug);
03743    res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
03744    va_end(ap);
03745    return res;
03746 }

static int cc_party_b_free ( void *  data  )  [static]

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

04037 {
04038    struct cc_core_instance *core_instance = data;
04039    int res = 0;
04040 
04041    if (core_instance->agent->callbacks->party_b_free) {
04042       res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
04043    }
04044    cc_unref(core_instance, "Party B free finished. Unref core_instance");
04045    return res;
04046 }

static int cc_publish ( struct stasis_message_type message_type,
int  core_id,
struct ast_json extras 
) [static]

Definition at line 1029 of file ccss.c.

References ao2_cleanup, ast_json_object_update(), ast_json_pack(), ast_json_payload_create(), ast_json_unref(), ast_system_topic(), NULL, RAII_VAR, stasis_message_create(), and stasis_publish().

Referenced by cc_publish_available(), cc_publish_callerrecalling(), cc_publish_callerstartmonitoring(), cc_publish_callerstopmonitoring(), cc_publish_failure(), cc_publish_monitorfailed(), cc_publish_offertimerstart(), cc_publish_recallcomplete(), cc_publish_requestacknowledged(), and cc_publish_requested().

01030 {
01031    RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
01032    RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
01033    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
01034 
01035    if (!message_type) {
01036       return -1;
01037    }
01038 
01039    blob = ast_json_pack("{s: i}",
01040       "core_id", core_id);
01041    if (!blob) {
01042       return -1;
01043    }
01044 
01045    if (extras) {
01046       ast_json_object_update(blob, extras);
01047    }
01048 
01049    if (!(payload = ast_json_payload_create(blob))) {
01050       return -1;
01051    }
01052 
01053    if (!(message = stasis_message_create(message_type, payload))) {
01054       return -1;
01055    }
01056 
01057    stasis_publish(ast_system_topic(), message);
01058 
01059    return 0;
01060 }

static void cc_publish_available ( int  core_id,
const char *  callee,
const char *  service 
) [static]

Definition at line 1062 of file ccss.c.

References ast_cc_available_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by ast_handle_cc_control_frame().

01063 {
01064    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01065 
01066    extras = ast_json_pack("{s: s, s: s}",
01067       "callee", callee,
01068       "service", service);
01069 
01070    cc_publish(ast_cc_available_type(), core_id, extras);
01071 }

static void cc_publish_callerrecalling ( int  core_id,
const char *  caller 
) [static]

Definition at line 1125 of file ccss.c.

References ast_cc_callerrecalling_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_recalling().

01126 {
01127    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01128 
01129    extras = ast_json_pack("{s: s}",
01130       "caller", caller);
01131 
01132    cc_publish(ast_cc_callerrecalling_type(), core_id, extras);
01133 }

static void cc_publish_callerstartmonitoring ( int  core_id,
const char *  caller 
) [static]

Definition at line 1115 of file ccss.c.

References ast_cc_callerstartmonitoring_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_caller_busy().

01116 {
01117    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01118 
01119    extras = ast_json_pack("{s: s}",
01120       "caller", caller);
01121 
01122    cc_publish(ast_cc_callerstartmonitoring_type(), core_id, extras);
01123 }

static void cc_publish_callerstopmonitoring ( int  core_id,
const char *  caller 
) [static]

Definition at line 1105 of file ccss.c.

References ast_cc_callerstopmonitoring_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_active().

01106 {
01107    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01108 
01109    extras = ast_json_pack("{s: s}",
01110       "caller", caller);
01111 
01112    cc_publish(ast_cc_callerstopmonitoring_type(), core_id, extras);
01113 }

static void cc_publish_failure ( int  core_id,
const char *  caller,
const char *  reason 
) [static]

Definition at line 1145 of file ccss.c.

References ast_cc_failure_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_failed().

01146 {
01147    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01148 
01149    extras = ast_json_pack("{s: s, s: s}",
01150       "caller", caller,
01151       "reason", reason);
01152 
01153    cc_publish(ast_cc_failure_type(), core_id, extras);
01154 }

static void cc_publish_monitorfailed ( int  core_id,
const char *  callee 
) [static]

Definition at line 1156 of file ccss.c.

References ast_cc_monitorfailed_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_monitor_failed().

01157 {
01158    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01159 
01160    extras = ast_json_pack("{s: s}",
01161       "callee", callee);
01162 
01163    cc_publish(ast_cc_monitorfailed_type(), core_id, extras);
01164 }

static void cc_publish_offertimerstart ( int  core_id,
const char *  caller,
unsigned int  expires 
) [static]

Definition at line 1073 of file ccss.c.

References ast_cc_offertimerstart_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_caller_offered().

01074 {
01075    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01076 
01077    extras = ast_json_pack("{s: s, s: i}",
01078       "caller", caller,
01079       "expires", expires);
01080 
01081    cc_publish(ast_cc_offertimerstart_type(), core_id, extras);
01082 }

static void cc_publish_recallcomplete ( int  core_id,
const char *  caller 
) [static]

Definition at line 1135 of file ccss.c.

References ast_cc_recallcomplete_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_complete().

01136 {
01137    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01138 
01139    extras = ast_json_pack("{s: s}",
01140       "caller", caller);
01141 
01142    cc_publish(ast_cc_recallcomplete_type(), core_id, extras);
01143 }

static void cc_publish_requestacknowledged ( int  core_id,
const char *  caller 
) [static]

Definition at line 1095 of file ccss.c.

References ast_cc_requestacknowledged_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by cc_active().

01096 {
01097    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01098 
01099    extras = ast_json_pack("{s: s}",
01100       "caller", caller);
01101 
01102    cc_publish(ast_cc_requestacknowledged_type(), core_id, extras);
01103 }

static void cc_publish_requested ( int  core_id,
const char *  caller,
const char *  callee 
) [static]

Definition at line 1084 of file ccss.c.

References ast_cc_requested_type(), ast_json_pack(), ast_json_unref(), cc_publish(), NULL, and RAII_VAR.

Referenced by request_cc().

01085 {
01086    RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
01087 
01088    extras = ast_json_pack("{s: s, s: s}",
01089       "caller", caller,
01090       "callee", callee);
01091 
01092    cc_publish(ast_cc_requested_type(), core_id, extras);
01093 }

static void cc_recall_ds_destroy ( void *  data  )  [static]

Definition at line 3389 of file ccss.c.

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

03390 {
03391    struct cc_recall_ds_data *recall_data = data;
03392    recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
03393    ast_free(recall_data);
03394 }

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

Definition at line 3375 of file ccss.c.

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

03376 {
03377    struct cc_recall_ds_data *old_data = data;
03378    struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));
03379 
03380    if (!new_data) {
03381       return NULL;
03382    }
03383    new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
03384    new_data->core_id = old_data->core_id;
03385    new_data->nested = 1;
03386    return new_data;
03387 }

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

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

03246 {
03247    /* Both caller and callee are available, call agent's recall callback
03248     */
03249    cancel_available_timer(core_instance);
03250    cc_publish_callerrecalling(core_instance->core_id, core_instance->agent->device_name);
03251    return 0;
03252 }

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

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

Definition at line 3325 of file ccss.c.

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

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

03326 {
03327    int res;
03328    int debuglen;
03329    char dummy[1];
03330    va_list aq;
03331    struct cc_core_instance *core_instance;
03332    struct cc_state_change_args *args;
03333    /* This initial call to vsnprintf is simply to find what the
03334     * size of the string needs to be
03335     */
03336    va_copy(aq, ap);
03337    /* We add 1 to the result since vsnprintf's return does not
03338     * include the terminating null byte
03339     */
03340    debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
03341    va_end(aq);
03342 
03343    if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
03344       return -1;
03345    }
03346 
03347    core_instance = find_cc_core_instance(core_id);
03348    if (!core_instance) {
03349       ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n",
03350          core_id);
03351       ast_free(args);
03352       return -1;
03353    }
03354 
03355    args->core_instance = core_instance;
03356    args->state = state;
03357    args->core_id = core_id;
03358    vsnprintf(args->debug, debuglen, debug, ap);
03359 
03360    res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
03361    if (res) {
03362       cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03363       ast_free(args);
03364    }
03365    return res;
03366 }

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

Definition at line 414 of file ccss.c.

References cc_service_to_string_map.

Referenced by ast_handle_cc_control_frame(), and cc_cli_print_monitor_stats().

00415 {
00416    return cc_service_to_string_map[service].service_string;
00417 }

static void cc_shutdown ( void   )  [static]

static enum ast_device_state cc_state_to_devstate ( enum cc_state  state  )  [static]

Definition at line 586 of file ccss.c.

Referenced by ccss_device_state(), and ccss_notify_device_state_change().

00587 {
00588    return cc_state_to_devstate_map[state];
00589 }

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

Definition at line 409 of file ccss.c.

References cc_state_to_string_map.

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

00410 {
00411    return cc_state_to_string_map[state].state_string;
00412 }

static int cc_status_request ( void *  data  )  [static]

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

03974 {
03975    struct cc_core_instance *core_instance= data;
03976    int res;
03977 
03978    res = core_instance->agent->callbacks->status_request(core_instance->agent);
03979    cc_unref(core_instance, "Status request finished. Unref core instance");
03980    return res;
03981 }

static int cc_status_response ( void *  data  )  [static]

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

04070 {
04071    struct cc_status_response_args *args = data;
04072    struct cc_core_instance *core_instance = args->core_instance;
04073    struct ast_cc_monitor *monitor_iter;
04074    enum ast_device_state devstate = args->devstate;
04075 
04076    ast_free(args);
04077 
04078    AST_LIST_LOCK(core_instance->monitors);
04079    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
04080       if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
04081             monitor_iter->callbacks->status_response) {
04082          monitor_iter->callbacks->status_response(monitor_iter, devstate);
04083       }
04084    }
04085    AST_LIST_UNLOCK(core_instance->monitors);
04086    cc_unref(core_instance, "Status response finished. Unref core instance");
04087    return 0;
04088 }

static int cc_stop_ringing ( void *  data  )  [static]

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

04000 {
04001    struct cc_core_instance *core_instance = data;
04002    int res = 0;
04003 
04004    if (core_instance->agent->callbacks->stop_ringing) {
04005       res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
04006    }
04007    /* If an agent is being asked to stop ringing, then he needs to be prepared if for
04008     * whatever reason he needs to be called back again. The proper state to be in to
04009     * detect such a circumstance is the CC_ACTIVE state.
04010     *
04011     * We get to this state using the slightly unintuitive method of calling
04012     * ast_cc_monitor_request_acked because it gets us to the proper state.
04013     */
04014    ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
04015          core_instance->agent->device_name);
04016    cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
04017    return res;
04018 }

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

Definition at line 3555 of file ccss.c.

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

Referenced by build_cc_interfaces_chanvar().

03556 {
03557    char dialstring_search[AST_CHANNEL_NAME];
03558 
03559    if (ast_strlen_zero(dialstring)) {
03560       /* No dialstring to append. */
03561       return;
03562    }
03563    snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
03564    if (strstr(ast_str_buffer(*str), dialstring_search)) {
03565       return;
03566    }
03567    ast_str_append(str, 0, "%s", dialstring_search);
03568 }

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

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

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

04306 {
04307    struct cc_core_instance *core_instance;
04308    char device_name[AST_CHANNEL_NAME];
04309    unsigned long match_flags;
04310    int res;
04311 
04312    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04313 
04314    match_flags = MATCH_REQUEST;
04315    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
04316       ast_log_dynamic_level(cc_logger_level, "Cannot find CC transaction to cancel for caller %s\n", device_name);
04317       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04318       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NO_CORE_INSTANCE");
04319       return 0;
04320    }
04321 
04322    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04323       ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
04324       cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04325       pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04326       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NOT_GENERIC");
04327       return 0;
04328    }
04329    res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
04330          core_instance->core_id, device_name);
04331    cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04332    pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", res ? "FAIL" : "SUCCESS");
04333    if (res) {
04334       pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "UNSPECIFIED");
04335    }
04336    return 0;
04337 }

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

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

04255 {
04256    struct cc_core_instance *core_instance;
04257    char device_name[AST_CHANNEL_NAME];
04258    unsigned long match_flags;
04259    int res;
04260 
04261    ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04262 
04263    match_flags = MATCH_NO_REQUEST;
04264    if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionRequest"))) {
04265       ast_log_dynamic_level(cc_logger_level, "Couldn't find a core instance for caller %s\n", device_name);
04266       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04267       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NO_CORE_INSTANCE");
04268       return 0;
04269    }
04270 
04271    ast_log_dynamic_level(cc_logger_level, "Core %d: Found core_instance for caller %s\n",
04272          core_instance->core_id, device_name);
04273 
04274    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04275       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest is only for generic agent types.\n",
04276             core_instance->core_id);
04277       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04278       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NOT_GENERIC");
04279       cc_unref(core_instance, "Unref core_instance since CallCompletionRequest was called with native agent");
04280       return 0;
04281    }
04282 
04283    if (!ast_cc_request_is_within_limits()) {
04284       ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest failed. Too many requests in the system\n",
04285             core_instance->core_id);
04286       ast_cc_failed(core_instance->core_id, "Too many CC requests\n");
04287       pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04288       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "TOO_MANY_REQUESTS");
04289       cc_unref(core_instance, "Unref core_instance since too many CC requests");
04290       return 0;
04291    }
04292 
04293    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);
04294    pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", res ? "FAIL" : "SUCCESS");
04295    if (res) {
04296       pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "UNSPECIFIED");
04297    }
04298 
04299    cc_unref(core_instance, "Done with CallCompletionRequest");
04300    return 0;
04301 }

static enum ast_device_state ccss_device_state ( const char *  device_name  )  [static]

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

00603 {
00604    struct cc_core_instance *core_instance;
00605    unsigned long match_flags;
00606    enum ast_device_state cc_current_state;
00607 
00608    match_flags = MATCH_NO_REQUEST;
00609    core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent,
00610       (char *) device_name, &match_flags,
00611       "Find Core Instance for ccss_device_state reqeust.");
00612    if (!core_instance) {
00613       ast_log_dynamic_level(cc_logger_level,
00614          "Couldn't find a core instance for caller %s\n", device_name);
00615       return cc_state_to_devstate(CC_FAILED);
00616    }
00617 
00618    ast_log_dynamic_level(cc_logger_level,
00619       "Core %d: Found core_instance for caller %s in state %s\n",
00620       core_instance->core_id, device_name, cc_state_to_string(core_instance->current_state));
00621 
00622    if (strcmp(core_instance->agent->callbacks->type, "generic")) {
00623       ast_log_dynamic_level(cc_logger_level,
00624          "Core %d: Device State is only for generic agent types.\n",
00625          core_instance->core_id);
00626       cc_unref(core_instance, "Unref core_instance since ccss_device_state was called with native agent");
00627       return cc_state_to_devstate(CC_FAILED);
00628    }
00629    cc_current_state = cc_state_to_devstate(core_instance->current_state);
00630    cc_unref(core_instance, "Unref core_instance done with ccss_device_state");
00631    return cc_current_state;
00632 }

static void ccss_notify_device_state_change ( const char *  device,
enum cc_state  state 
) [static]

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

00644 {
00645    enum ast_device_state devstate;
00646 
00647    devstate = cc_state_to_devstate(state);
00648 
00649    ast_log_dynamic_level(cc_logger_level,
00650       "Notification of CCSS state change to '%s', device state '%s' for device '%s'\n",
00651       cc_state_to_string(state), ast_devstate2str(devstate), device);
00652 
00653    ast_devstate_changed(devstate, AST_DEVSTATE_CACHABLE, "ccss:%s", device);
00654 }

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

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

Definition at line 4552 of file ccss.c.

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

Referenced by handle_cc_kill().

04553 {
04554    int which = 0;
04555    int wordlen = strlen(word);
04556    char *ret = NULL;
04557    struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
04558    struct cc_core_instance *core_instance;
04559 
04560    for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
04561          cc_unref(core_instance, "CLI tab completion iteration")) {
04562       char core_id_str[20];
04563       snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
04564       if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
04565          ret = ast_strdup(core_id_str);
04566          cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
04567          break;
04568       }
04569    }
04570    ao2_iterator_destroy(&core_iter);
04571 
04572    return ret;
04573 }

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

Definition at line 2506 of file ccss.c.

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

Referenced by cc_core_init_instance().

02507 {
02508    struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
02509 
02510    ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
02511    ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
02512    return data.count;
02513 }

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

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

00533 {
00534    struct cc_core_instance *core_instance = obj;
00535    const char *name = arg;
00536    struct count_agents_cb_data *cb_data = data;
00537 
00538    if (cb_data->core_id_exception == core_instance->core_id) {
00539       ast_log_dynamic_level(cc_logger_level, "Found agent with core_id %d but not counting it toward total\n", core_instance->core_id);
00540       return 0;
00541    }
00542 
00543    if (core_instance->current_state >= CC_CALLER_REQUESTED && !strcmp(core_instance->agent->device_name, name)) {
00544       cb_data->count++;
00545    }
00546    return 0;
00547 }

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

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

04346 {
04347    struct cc_core_instance *core_instance = obj;
04348    struct count_monitors_cb_data *cb_data = arg;
04349    const char *device_name = cb_data->device_name;
04350    const char *monitor_type = cb_data->monitor_type;
04351    struct ast_cc_monitor *monitor_iter;
04352 
04353    AST_LIST_LOCK(core_instance->monitors);
04354    AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
04355       if (!strcmp(monitor_iter->interface->device_name, device_name) &&
04356             !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
04357          cb_data->count++;
04358          break;
04359       }
04360    }
04361    AST_LIST_UNLOCK(core_instance->monitors);
04362    return 0;
04363 }

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

Definition at line 1409 of file ccss.c.

References ao2_t_alloc, ao2_t_link, ast_device_state_topic(), ast_strdup, ast_tech_to_upper(), cc_unref(), generic_monitor_instance_list::current_state, generic_monitor_instance_list::device_name, ast_cc_interface::device_name, generic_monitor_devstate_cb(), generic_monitor_instance_list_destructor(), generic_monitors, ast_cc_monitor::interface, NULL, stasis_subscribe(), and generic_monitor_instance_list::sub.

Referenced by cc_generic_monitor_request_cc().

01410 {
01411    struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
01412          generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
01413    char * device_name;
01414    struct stasis_topic *device_specific_topic;
01415 
01416    if (!generic_list) {
01417       return NULL;
01418    }
01419 
01420    if (!(device_name = ast_strdup(monitor->interface->device_name))) {
01421       cc_unref(generic_list, "Failed to strdup the monitor's device name");
01422       return NULL;
01423    }
01424    ast_tech_to_upper(device_name);
01425    generic_list->device_name = device_name;
01426 
01427    device_specific_topic = ast_device_state_topic(device_name);
01428    if (!device_specific_topic) {
01429       return NULL;
01430    }
01431 
01432    if (!(generic_list->sub = stasis_subscribe(device_specific_topic, generic_monitor_devstate_cb, NULL))) {
01433       cc_unref(generic_list, "Failed to subscribe to device state");
01434       return NULL;
01435    }
01436    generic_list->current_state = ast_device_state(monitor->interface->device_name);
01437    ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
01438    return generic_list;
01439 }

static void dialed_cc_interfaces_destroy ( void *  data  )  [static]

Definition at line 1942 of file ccss.c.

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

01943 {
01944    struct dialed_cc_interfaces *cc_interfaces = data;
01945    cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
01946    ast_free(cc_interfaces);
01947 }

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

Definition at line 1962 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, dialed_cc_interfaces::is_original_caller, and NULL.

01963 {
01964    struct dialed_cc_interfaces *old_cc_interfaces = data;
01965    struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
01966    if (!new_cc_interfaces) {
01967       return NULL;
01968    }
01969    new_cc_interfaces->ignore = old_cc_interfaces->ignore;
01970    new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
01971    new_cc_interfaces->is_original_caller = 0;
01972    cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
01973    new_cc_interfaces->core_id = old_cc_interfaces->core_id;
01974    new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
01975    return new_cc_interfaces;
01976 }

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

Definition at line 1993 of file ccss.c.

References ast_calloc, AST_LIST_HEAD_INIT_NOLOCK, extension_monitor_pvt::child_dialstrings, and NULL.

Referenced by cc_extension_monitor_init().

01994 {
01995    struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
01996    if (!ext_pvt) {
01997       return NULL;
01998    }
01999    AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
02000    return ext_pvt;
02001 }

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

Definition at line 1258 of file ccss.c.

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

Referenced by cc_agent_init().

01259 {
01260    struct cc_agent_backend *backend;
01261    const struct ast_cc_agent_callbacks *callbacks = NULL;
01262    struct ast_cc_config_params *cc_params;
01263    char type[32];
01264 
01265    cc_params = ast_channel_get_cc_config_params(chan);
01266    if (!cc_params) {
01267       return NULL;
01268    }
01269    switch (ast_get_cc_agent_policy(cc_params)) {
01270    case AST_CC_AGENT_GENERIC:
01271       ast_copy_string(type, "generic", sizeof(type));
01272       break;
01273    case AST_CC_AGENT_NATIVE:
01274       ast_channel_get_cc_agent_type(chan, type, sizeof(type));
01275       break;
01276    default:
01277       ast_log_dynamic_level(cc_logger_level, "Not returning agent callbacks since this channel is configured not to have a CC agent\n");
01278       return NULL;
01279    }
01280 
01281    AST_RWLIST_RDLOCK(&cc_agent_backends);
01282    AST_RWLIST_TRAVERSE(&cc_agent_backends, backend, next) {
01283       if (!strcmp(backend->callbacks->type, type)) {
01284          ast_log_dynamic_level(cc_logger_level, "Returning agent backend %s\n", backend->callbacks->type);
01285          callbacks = backend->callbacks;
01286          break;
01287       }
01288    }
01289    AST_RWLIST_UNLOCK(&cc_agent_backends);
01290    return callbacks;
01291 }

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

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

Definition at line 1386 of file ccss.c.

References ao2_t_find, ast_strdupa, ast_tech_to_upper(), generic_monitor_instance_list::device_name, generic_monitors, and OBJ_POINTER.

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

01387 {
01388    struct generic_monitor_instance_list finder = {0};
01389    char *uppertech = ast_strdupa(device_name);
01390    ast_tech_to_upper(uppertech);
01391    finder.device_name = uppertech;
01392 
01393    return ao2_t_find(generic_monitors, &finder, OBJ_POINTER, "Finding generic monitor instance list");
01394 }

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

Definition at line 1189 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, NULL, and ast_cc_monitor_callbacks::type.

Referenced by call_destructor_with_no_monitor(), and cc_device_monitor_init().

01190 {
01191    struct cc_monitor_backend *backend;
01192    const struct ast_cc_monitor_callbacks *callbacks = NULL;
01193 
01194    AST_RWLIST_RDLOCK(&cc_monitor_backends);
01195    AST_RWLIST_TRAVERSE(&cc_monitor_backends, backend, next) {
01196       if (!strcmp(backend->callbacks->type, type)) {
01197          ast_log_dynamic_level(cc_logger_level, "Returning monitor backend %s\n", backend->callbacks->type);
01198          callbacks = backend->callbacks;
01199          break;
01200       }
01201    }
01202    AST_RWLIST_UNLOCK(&cc_monitor_backends);
01203    return callbacks;
01204 }

static void generic_agent_devstate_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
) [static]

Definition at line 2761 of file ccss.c.

References ast_cc_agent_caller_available(), ast_device_state_message_type(), cc_generic_is_device_available(), cc_unref(), ast_cc_agent::core_id, ast_cc_agent::device_name, ast_device_state_message::eid, ast_cc_agent::private_data, stasis_message_data(), stasis_message_type(), stasis_subscription_final_message(), stasis_unsubscribe(), ast_device_state_message::state, and cc_generic_agent_pvt::sub.

Referenced by cc_generic_agent_start_monitoring().

02762 {
02763    struct ast_cc_agent *agent = userdata;
02764    enum ast_device_state new_state;
02765    struct ast_device_state_message *dev_state;
02766    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02767 
02768    if (stasis_subscription_final_message(sub, msg)) {
02769       cc_unref(agent, "Done holding ref for subscription");
02770       return;
02771    } else if (ast_device_state_message_type() != stasis_message_type(msg)) {
02772       return;
02773    }
02774 
02775    dev_state = stasis_message_data(msg);
02776    if (dev_state->eid) {
02777       /* ignore non-aggregate states */
02778       return;
02779    }
02780 
02781    new_state = dev_state->state;
02782    if (!cc_generic_is_device_available(new_state)) {
02783       /* Not interested in this new state of the device.  It is still busy. */
02784       return;
02785    }
02786 
02787    generic_pvt->sub = stasis_unsubscribe(sub);
02788    ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
02789 }

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

Definition at line 1378 of file ccss.c.

References CMP_MATCH, CMP_STOP, and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01379 {
01380    const struct generic_monitor_instance_list *generic_list1 = obj;
01381    const struct generic_monitor_instance_list *generic_list2 = arg;
01382 
01383    return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
01384 }

static void generic_monitor_devstate_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
) [static]

Definition at line 1482 of file ccss.c.

References ao2_cleanup, ao2_t_ref, ast_device_state_message_type(), ast_taskprocessor_push(), ast_device_state_message::eid, generic_monitor_devstate_tp_cb(), stasis_message_data(), and stasis_message_type().

Referenced by create_new_generic_list().

01483 {
01484    /* Wow, it's cool that we've picked up on a state change, but we really want
01485     * the actual work to be done in the core's taskprocessor execution thread
01486     * so that all monitor operations can be serialized. Locks?! We don't need
01487     * no steenkin' locks!
01488     */
01489    struct ast_device_state_message *dev_state;
01490    if (ast_device_state_message_type() != stasis_message_type(msg)) {
01491       return;
01492    }
01493 
01494    dev_state = stasis_message_data(msg);
01495    if (dev_state->eid) {
01496       /* ignore non-aggregate states */
01497       return;
01498    }
01499 
01500    ao2_t_ref(dev_state, +1, "Bumping dev_state ref for cc_core_taskprocessor");
01501    if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, dev_state)) {
01502       ao2_cleanup(dev_state);
01503       return;
01504    }
01505 }

static int generic_monitor_devstate_tp_cb ( void *  data  )  [static]

Definition at line 1441 of file ccss.c.

References ao2_cleanup, ast_cc_monitor_callee_available(), AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_UNAVAILABLE, AST_LIST_TRAVERSE, cc_generic_is_device_available(), cc_unref(), generic_monitor_instance::core_id, generic_monitor_instance_list::current_state, 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 RAII_VAR.

Referenced by generic_monitor_devstate_cb().

01442 {
01443    RAII_VAR(struct ast_device_state_message *, dev_state, data, ao2_cleanup);
01444    enum ast_device_state new_state = dev_state->state;
01445    enum ast_device_state previous_state;
01446    struct generic_monitor_instance_list *generic_list;
01447    struct generic_monitor_instance *generic_instance;
01448 
01449    if (!(generic_list = find_generic_monitor_instance_list(dev_state->device))) {
01450       /* The most likely cause for this is that we destroyed the monitor in the
01451        * time between subscribing to its device state and the time this executes.
01452        * Not really a big deal.
01453        */
01454       return 0;
01455    }
01456 
01457    if (generic_list->current_state == new_state) {
01458       /* The device state hasn't actually changed, so we don't really care */
01459       cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01460       return 0;
01461    }
01462 
01463    previous_state = generic_list->current_state;
01464    generic_list->current_state = new_state;
01465 
01466    if (cc_generic_is_device_available(new_state) &&
01467          (previous_state == AST_DEVICE_INUSE || previous_state == AST_DEVICE_UNAVAILABLE ||
01468           previous_state == AST_DEVICE_BUSY)) {
01469       AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01470          if (!generic_instance->is_suspended && generic_instance->monitoring) {
01471             generic_instance->monitoring = 0;
01472             generic_list->fit_for_recall = 1;
01473             ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01474             break;
01475          }
01476       }
01477    }
01478    cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01479    return 0;
01480 }

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

Definition at line 1372 of file ccss.c.

References ast_str_hash(), and generic_monitor_instance_list::device_name.

Referenced by ast_cc_init().

01373 {
01374    const struct generic_monitor_instance_list *generic_list = obj;
01375    return ast_str_hash(generic_list->device_name);
01376 }

static void generic_monitor_instance_list_destructor ( void *  obj  )  [static]

Definition at line 1396 of file ccss.c.

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

Referenced by create_new_generic_list().

01397 {
01398    struct generic_monitor_instance_list *generic_list = obj;
01399    struct generic_monitor_instance *generic_instance;
01400 
01401    generic_list->sub = stasis_unsubscribe(generic_list->sub);
01402    while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
01403       ast_free(generic_instance);
01404    }
01405    ast_free((char *)generic_list->device_name);
01406 }

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

Definition at line 2813 of file ccss.c.

References ao2_ref, 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_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, ast_get_cc_agent_dialstring(), 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_strdupa, ast_strlen_zero, ast_cc_agent::cc_params, cc_generic_agent_pvt::cid_name, cc_generic_agent_pvt::cid_num, cc_generic_agent_pvt::context, ast_cc_agent::core_id, ast_cc_agent::device_name, cc_generic_agent_pvt::exten, NULL, pbx_builtin_setvar_helper(), ast_cc_agent::private_data, and S_OR.

Referenced by cc_generic_agent_recall().

02814 {
02815    struct ast_cc_agent *agent = data;
02816    struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02817    const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
02818    const char *tech;
02819    char *target;
02820    int reason;
02821    struct ast_channel *chan;
02822    const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
02823    const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params);
02824    unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
02825    struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
02826 
02827    if (!tmp_cap) {
02828       return NULL;
02829    }
02830 
02831    tech = interface;
02832    if ((target = strchr(interface, '/'))) {
02833       *target++ = '\0';
02834    }
02835 
02836    ast_format_cap_append(tmp_cap, ast_format_slin, 0);
02837    if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
02838       /* Hmm, no channel. Sucks for you, bud.
02839        */
02840       ast_log_dynamic_level(cc_logger_level, "Core %u: Failed to call back %s for reason %d\n",
02841             agent->core_id, agent->device_name, reason);
02842       ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
02843       ao2_ref(tmp_cap, -1);
02844       return NULL;
02845    }
02846    ao2_ref(tmp_cap, -1);
02847    
02848    /* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
02849     * This will be a common task for all recall functions. If it were possible, I'd have
02850     * the core do it automatically, but alas I cannot. Instead, I will provide a public
02851     * function to do so.
02852     */
02853    ast_setup_cc_recall_datastore(chan, agent->core_id);
02854    ast_cc_agent_set_interfaces_chanvar(chan);
02855 
02856    ast_channel_exten_set(chan, generic_pvt->exten);
02857    ast_channel_context_set(chan, generic_pvt->context);
02858    ast_channel_priority_set(chan, 1);
02859 
02860    pbx_builtin_setvar_helper(chan, "CC_EXTEN", generic_pvt->exten);
02861    pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);
02862 
02863    if (!ast_strlen_zero(callback_macro)) {
02864       ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback macro configured for agent %s\n",
02865             agent->core_id, agent->device_name);
02866       if (ast_app_exec_macro(NULL, chan, callback_macro)) {
02867          ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
02868          ast_hangup(chan);
02869          return NULL;
02870       }
02871    }
02872 
02873    if (!ast_strlen_zero(callback_sub)) {
02874       ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback subroutine configured for agent %s\n",
02875             agent->core_id, agent->device_name);
02876       if (ast_app_exec_sub(NULL, chan, callback_sub, 0)) {
02877          ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name);
02878          ast_hangup(chan);
02879          return NULL;
02880       }
02881    }
02882    if (ast_pbx_start(chan)) {
02883       ast_cc_failed(agent->core_id, "PBX failed to start for %s.", agent->device_name);
02884       ast_hangup(chan);
02885       return NULL;
02886    }
02887    ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling",
02888       agent->device_name);
02889    return NULL;
02890 }

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