52 #include "asterisk/stasis_system.h"
143 static inline void *cc_ref(
void *obj,
const char *
debug)
145 ao2_t_ref(obj, +1, debug);
149 static inline void *cc_unref(
void *obj,
const char *
debug)
151 ao2_t_ref(obj, -1, debug);
164 unsigned int cc_offer_timer;
165 unsigned int ccnr_available_timer;
166 unsigned int ccbs_available_timer;
167 unsigned int cc_recall_timer;
168 unsigned int cc_max_agents;
169 unsigned int cc_max_monitors;
325 static const int CC_CORE_INSTANCES_BUCKETS = 17;
357 static int __attribute__((format(printf, 3, 0))) cc_request_state_change(enum
cc_state state, const
int core_id, const
char *
debug, va_list ap);
382 static const struct {
383 enum ast_cc_service_type service;
384 const char *service_string;
385 } cc_service_to_string_map[] = {
386 {AST_CC_NONE,
"NONE"},
387 {AST_CC_CCBS,
"CCBS"},
388 {AST_CC_CCNR,
"CCNR"},
389 {AST_CC_CCNL,
"CCNL"},
392 static const struct {
394 const char *state_string;
395 } cc_state_to_string_map[] = {
401 {
CC_CALLER_BUSY,
"Callee was ready, but caller is now unavailable"},
409 return cc_state_to_string_map[state].state_string;
412 static const char *cc_service_to_string(
enum ast_cc_service_type service)
414 return cc_service_to_string_map[service].service_string;
417 static int cc_core_instance_hash_fn(
const void *obj,
const int flags)
423 static int cc_core_instance_cmp_fn(
void *obj,
void *arg,
int flags)
444 static int cc_agent_callback_helper(
void *obj,
void *args,
int flags)
453 return helper->function(core_instance->
agent, helper->args, flags);
458 struct cc_callback_helper helper = {.function =
function, .args = args, .type = type};
460 if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
461 "Calling provided agent callback function"))) {
462 struct ast_cc_agent *agent = cc_ref(core_instance->
agent,
"An outside entity needs the agent");
463 cc_unref(core_instance,
"agent callback done with the core_instance");
473 MATCH_NO_REQUEST = (1 << 0),
477 MATCH_REQUEST = (1 << 1),
492 static int match_agent(
void *obj,
void *arg,
void *data,
int flags)
495 const char *name = arg;
496 unsigned long match_flags = *(
unsigned long *)data;
497 int possible_match = 0;
507 if (!possible_match) {
519 int core_id_exception;
530 static int count_agents_cb(
void *obj,
void *arg,
void *data,
int flags)
533 const char *name = arg;
536 if (cb_data->core_id_exception == core_instance->
core_id) {
549 #define CC_AVAILABLE_DEVSTATE_DEFAULT AST_DEVICE_NOT_INUSE
550 #define CC_CALLER_OFFERED_DEVSTATE_DEFAULT AST_DEVICE_NOT_INUSE
551 #define CC_CALLER_REQUESTED_DEVSTATE_DEFAULT AST_DEVICE_NOT_INUSE
552 #define CC_ACTIVE_DEVSTATE_DEFAULT AST_DEVICE_INUSE
553 #define CC_CALLEE_READY_DEVSTATE_DEFAULT AST_DEVICE_RINGING
554 #define CC_CALLER_BUSY_DEVSTATE_DEFAULT AST_DEVICE_ONHOLD
555 #define CC_RECALLING_DEVSTATE_DEFAULT AST_DEVICE_RINGING
556 #define CC_COMPLETE_DEVSTATE_DEFAULT AST_DEVICE_NOT_INUSE
557 #define CC_FAILED_DEVSTATE_DEFAULT AST_DEVICE_NOT_INUSE
567 [
CC_ACTIVE] = CC_ACTIVE_DEVSTATE_DEFAULT,
572 [
CC_FAILED] = CC_FAILED_DEVSTATE_DEFAULT,
586 return cc_state_to_devstate_map[state];
603 unsigned long match_flags;
606 match_flags = MATCH_NO_REQUEST;
608 (
char *) device_name, &match_flags,
609 "Find Core Instance for ccss_device_state reqeust.");
610 if (!core_instance) {
612 "Couldn't find a core instance for caller %s\n", device_name);
617 "Core %d: Found core_instance for caller %s in state %s\n",
622 "Core %d: Device State is only for generic agent types.\n",
624 cc_unref(core_instance,
"Unref core_instance since ccss_device_state was called with native agent");
627 cc_current_state = cc_state_to_devstate(core_instance->
current_state);
628 cc_unref(core_instance,
"Unref core_instance done with ccss_device_state");
629 return cc_current_state;
641 static void ccss_notify_device_state_change(
const char *device,
enum cc_state state)
645 devstate = cc_state_to_devstate(state);
648 "Notification of CCSS state change to '%s', device state '%s' for device '%s'\n",
654 #define CC_OFFER_TIMER_DEFAULT 20
655 #define CCNR_AVAILABLE_TIMER_DEFAULT 7200
656 #define CCBS_AVAILABLE_TIMER_DEFAULT 4800
657 #define CC_RECALL_TIMER_DEFAULT 20
658 #define CC_MAX_AGENTS_DEFAULT 5
659 #define CC_MAX_MONITORS_DEFAULT 5
660 #define GLOBAL_CC_MAX_REQUESTS_DEFAULT 20
665 .cc_offer_timer = CC_OFFER_TIMER_DEFAULT,
666 .ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT,
667 .ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT,
668 .cc_recall_timer = CC_RECALL_TIMER_DEFAULT,
669 .cc_max_agents = CC_MAX_AGENTS_DEFAULT,
670 .cc_max_monitors = CC_MAX_MONITORS_DEFAULT,
671 .cc_callback_sub =
"",
672 .cc_agent_dialstring =
"",
677 *params = cc_default_params;
699 if (!strcasecmp(value,
"never")) {
701 }
else if (!strcasecmp(value,
"native")) {
703 }
else if (!strcasecmp(value,
"generic")) {
706 ast_log(LOG_WARNING,
"%s is an invalid value for cc_agent_policy. Switching to 'never'\n", value);
713 if (!strcasecmp(value,
"never")) {
715 }
else if (!strcasecmp(value,
"native")) {
716 return AST_CC_MONITOR_NATIVE;
717 }
else if (!strcasecmp(value,
"generic")) {
719 }
else if (!strcasecmp(value,
"always")) {
722 ast_log(LOG_WARNING,
"%s is an invalid value for cc_monitor_policy. Switching to 'never'\n", value);
747 case AST_CC_MONITOR_NATIVE:
759 char *buf,
size_t buf_len)
761 const char *value = NULL;
763 if (!strcasecmp(name,
"cc_callback_sub")) {
765 }
else if (!strcasecmp(name,
"cc_agent_policy")) {
767 }
else if (!strcasecmp(name,
"cc_monitor_policy")) {
769 }
else if (!strcasecmp(name,
"cc_agent_dialstring")) {
781 if (!strcasecmp(name,
"cc_offer_timer")) {
783 }
else if (!strcasecmp(name,
"ccnr_available_timer")) {
785 }
else if (!strcasecmp(name,
"ccbs_available_timer")) {
787 }
else if (!strcasecmp(name,
"cc_max_agents")) {
789 }
else if (!strcasecmp(name,
"cc_max_monitors")) {
791 }
else if (!strcasecmp(name,
"cc_recall_timer")) {
794 ast_log(LOG_WARNING,
"%s is not a valid CC parameter. Ignoring.\n", name);
802 const char *
const value)
804 unsigned int value_as_uint;
805 if (!strcasecmp(name,
"cc_agent_policy")) {
807 }
else if (!strcasecmp(name,
"cc_monitor_policy")) {
809 }
else if (!strcasecmp(name,
"cc_agent_dialstring")) {
811 }
else if (!strcasecmp(name,
"cc_callback_sub")) {
816 if (sscanf(value,
"%30u", &value_as_uint) != 1) {
820 if (!strcasecmp(name,
"cc_offer_timer")) {
822 }
else if (!strcasecmp(name,
"ccnr_available_timer")) {
824 }
else if (!strcasecmp(name,
"ccbs_available_timer")) {
826 }
else if (!strcasecmp(name,
"cc_max_agents")) {
828 }
else if (!strcasecmp(name,
"cc_max_monitors")) {
830 }
else if (!strcasecmp(name,
"cc_recall_timer")) {
833 ast_log(LOG_WARNING,
"%s is not a valid CC parameter. Ignoring.\n", name);
842 return (!strcasecmp(name,
"cc_agent_policy") ||
843 !strcasecmp(name,
"cc_monitor_policy") ||
844 !strcasecmp(name,
"cc_offer_timer") ||
845 !strcasecmp(name,
"ccnr_available_timer") ||
846 !strcasecmp(name,
"ccbs_available_timer") ||
847 !strcasecmp(name,
"cc_max_agents") ||
848 !strcasecmp(name,
"cc_max_monitors") ||
849 !strcasecmp(name,
"cc_callback_sub") ||
850 !strcasecmp(name,
"cc_agent_dialstring") ||
851 !strcasecmp(name,
"cc_recall_timer"));
861 return config->cc_agent_policy;
872 config->cc_agent_policy = value;
878 return config->cc_monitor_policy;
889 config->cc_monitor_policy = value;
895 return config->cc_offer_timer;
902 ast_log(LOG_WARNING,
"0 is an invalid value for cc_offer_timer. Retaining value as %u\n", config->cc_offer_timer);
905 config->cc_offer_timer = value;
910 return config->ccnr_available_timer;
917 ast_log(LOG_WARNING,
"0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->ccnr_available_timer);
920 config->ccnr_available_timer = value;
925 return config->cc_recall_timer;
932 ast_log(LOG_WARNING,
"0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
935 config->cc_recall_timer = value;
940 return config->ccbs_available_timer;
947 ast_log(LOG_WARNING,
"0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
950 config->ccbs_available_timer = value;
955 return config->cc_agent_dialstring;
960 if (ast_strlen_zero(value)) {
961 config->cc_agent_dialstring[0] =
'\0';
963 ast_copy_string(config->cc_agent_dialstring, value,
sizeof(config->cc_agent_dialstring));
969 return config->cc_max_agents;
974 config->cc_max_agents = value;
979 return config->cc_max_monitors;
984 config->cc_max_monitors = value;
989 return config->cc_callback_sub;
994 if (ast_strlen_zero(value)) {
995 config->cc_callback_sub[0] =
'\0';
997 ast_copy_string(config->cc_callback_sub, value,
sizeof(config->cc_callback_sub));
1007 if (!message_type) {
1012 "core_id", core_id);
1041 static void cc_publish_available(
int core_id,
const char *callee,
const char *service)
1047 "service", service);
1049 cc_publish(ast_cc_available_type(), core_id, extras);
1053 static void cc_publish_offertimerstart(
int core_id,
const char *caller,
unsigned int expires)
1061 cc_publish(ast_cc_offertimerstart_type(), core_id, extras);
1065 static void cc_publish_requested(
int core_id,
const char *caller,
const char *callee)
1073 cc_publish(ast_cc_requested_type(), core_id, extras);
1077 static void cc_publish_requestacknowledged(
int core_id,
const char *caller)
1084 cc_publish(ast_cc_requestacknowledged_type(), core_id, extras);
1088 static void cc_publish_callerstopmonitoring(
int core_id,
const char *caller)
1095 cc_publish(ast_cc_callerstopmonitoring_type(), core_id, extras);
1099 static void cc_publish_callerstartmonitoring(
int core_id,
const char *caller)
1106 cc_publish(ast_cc_callerstartmonitoring_type(), core_id, extras);
1110 static void cc_publish_callerrecalling(
int core_id,
const char *caller)
1117 cc_publish(ast_cc_callerrecalling_type(), core_id, extras);
1121 static void cc_publish_recallcomplete(
int core_id,
const char *caller)
1128 cc_publish(ast_cc_recallcomplete_type(), core_id, extras);
1132 static void cc_publish_failure(
int core_id,
const char *caller,
const char *reason)
1140 cc_publish(ast_cc_failure_type(), core_id, extras);
1144 static void cc_publish_monitorfailed(
int core_id,
const char *callee)
1151 cc_publish(ast_cc_monitorfailed_type(), core_id, extras);
1170 backend->callbacks = callbacks;
1185 if (!strcmp(backend->callbacks->
type, type)) {
1187 callbacks = backend->callbacks;
1200 if (backend->callbacks == callbacks) {
1201 AST_RWLIST_REMOVE_CURRENT(next);
1206 AST_RWLIST_TRAVERSE_SAFE_END;
1225 backend->callbacks = callbacks;
1237 if (backend->callbacks == callbacks) {
1238 AST_RWLIST_REMOVE_CURRENT(next);
1243 AST_RWLIST_TRAVERSE_SAFE_END;
1272 if (!strcmp(backend->callbacks->
type, type)) {
1274 callbacks = backend->callbacks;
1296 static int cc_generic_monitor_request_cc(
struct ast_cc_monitor *monitor,
int *available_timer_id);
1297 static int cc_generic_monitor_suspend(
struct ast_cc_monitor *monitor);
1298 static int cc_generic_monitor_unsuspend(
struct ast_cc_monitor *monitor);
1300 static void cc_generic_monitor_destructor(
void *private_data);
1304 .request_cc = cc_generic_monitor_request_cc,
1305 .suspend = cc_generic_monitor_suspend,
1306 .unsuspend = cc_generic_monitor_unsuspend,
1307 .cancel_available_timer = cc_generic_monitor_cancel_available_timer,
1308 .destructor = cc_generic_monitor_destructor,
1321 const char *device_name;
1364 static struct generic_monitor_instance_list *find_generic_monitor_instance_list(const
char * const device_name)
1366 struct generic_monitor_instance_list finder = {0};
1369 finder.device_name = uppertech;
1374 static void generic_monitor_instance_list_destructor(
void *obj)
1381 ast_free(generic_instance);
1383 ast_free((
char *)generic_list->device_name);
1390 generic_monitor_instance_list_destructor,
"allocate generic monitor instance list");
1394 if (!generic_list) {
1399 cc_unref(generic_list,
"Failed to strdup the monitor's device name");
1403 generic_list->device_name = device_name;
1406 if (!device_specific_topic) {
1410 if (!(generic_list->sub = stasis_subscribe(device_specific_topic, generic_monitor_devstate_cb, NULL))) {
1411 cc_unref(generic_list,
"Failed to subscribe to device state");
1417 ao2_t_link(generic_monitors, generic_list,
"linking new generic monitor instance list");
1418 return generic_list;
1421 static int generic_monitor_devstate_tp_cb(
void *data)
1429 if (!(generic_list = find_generic_monitor_instance_list(dev_state->device))) {
1437 if (generic_list->current_state == new_state) {
1439 cc_unref(generic_list,
"Kill reference of generic list in devstate taskprocessor callback");
1443 previous_state = generic_list->current_state;
1444 generic_list->current_state = new_state;
1446 if (cc_generic_is_device_available(new_state) &&
1450 if (!generic_instance->is_suspended && generic_instance->monitoring) {
1451 generic_instance->monitoring = 0;
1452 generic_list->fit_for_recall = 1;
1458 cc_unref(generic_list,
"Kill reference of generic list in devstate taskprocessor callback");
1475 if (dev_state->
eid) {
1480 ao2_t_ref(dev_state, +1,
"Bumping dev_state ref for cc_core_taskprocessor");
1482 ao2_cleanup(dev_state);
1493 cc_unref(monitor,
"Unref reference from scheduler\n");
1509 if (!(gen_mon_pvt =
ast_calloc(1,
sizeof(*gen_mon_pvt)))) {
1514 ast_free(gen_mon_pvt);
1522 if (!(generic_list = find_generic_monitor_instance_list(monitor->
interface->device_name))) {
1523 if (!(generic_list = create_new_generic_list(monitor))) {
1528 if (!(generic_instance =
ast_calloc(1,
sizeof(*generic_instance)))) {
1532 cc_unref(generic_list,
"Generic monitor instance failed to allocate");
1535 generic_instance->core_id = monitor->
core_id;
1536 generic_instance->monitoring = 1;
1541 *available_timer_id =
ast_sched_add(cc_sched_context, when * 1000,
1543 if (*available_timer_id == -1) {
1544 cc_unref(monitor,
"Failed to schedule available timer. (monitor)");
1545 cc_unref(generic_list,
"Failed to schedule available timer. (generic_list)");
1551 if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
1552 generic_list->fit_for_recall = 0;
1556 cc_unref(generic_list,
"Finished with monitor instance reference in request cc callback");
1560 static int cc_generic_monitor_suspend(
struct ast_cc_monitor *monitor)
1566 if (!(generic_list = find_generic_monitor_instance_list(monitor->
interface->device_name))) {
1572 if (generic_instance->core_id == monitor->
core_id) {
1573 generic_instance->is_suspended = 1;
1581 if (!cc_generic_is_device_available(state)) {
1582 cc_unref(generic_list,
"Device is in use. Nothing to do. Unref generic list.");
1592 if (!generic_instance->is_suspended) {
1597 cc_unref(generic_list,
"Done with generic list in suspend callback");
1601 static int cc_generic_monitor_unsuspend(
struct ast_cc_monitor *monitor)
1607 if (!generic_list) {
1613 if (cc_generic_is_device_available(state)) {
1619 if (generic_instance->core_id == monitor->
core_id) {
1620 generic_instance->is_suspended = 0;
1621 generic_instance->monitoring = 1;
1625 cc_unref(generic_list,
"Done with generic list in cc_generic_monitor_unsuspend");
1631 ast_assert(sched_id != NULL);
1633 if (*sched_id == -1) {
1640 cc_unref(monitor,
"Remove scheduler's reference to the monitor");
1646 static void cc_generic_monitor_destructor(
void *private_data)
1652 if (!private_data) {
1664 if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->
device_name))) {
1670 ast_free(gen_mon_pvt);
1675 if (generic_instance->core_id == gen_mon_pvt->
core_id) {
1677 ast_free(generic_instance);
1687 ao2_t_unlink(generic_monitors, generic_list,
"Generic list is empty. Unlink it from the container");
1699 if (generic_list->fit_for_recall
1700 && cc_generic_is_device_available(generic_list->current_state)) {
1702 if (!generic_instance->is_suspended && generic_instance->monitoring) {
1704 "availability due to other instance's failure.");
1710 cc_unref(generic_list,
"Done with generic list in generic monitor destructor");
1712 ast_free(gen_mon_pvt);
1715 static void cc_interface_destroy(
void *data)
1799 static void cc_extension_monitor_destructor(
void *private_data)
1805 if (!extension_pvt) {
1810 ast_free(child_dialstring);
1812 ast_free(extension_pvt);
1815 static void cc_monitor_destroy(
void *data)
1826 if (monitor->
interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
1827 cc_extension_monitor_destructor(monitor->
private_data);
1832 cc_unref(monitor->
interface,
"Unreffing tree's reference to interface");
1836 static void cc_interface_tree_destroy(
void *data)
1844 cc_unref(monitor,
"Destroying all monitors");
1922 static void dialed_cc_interfaces_destroy(
void *data)
1925 cc_unref(cc_interfaces->
interface_tree,
"Unref dial's ref to monitor tree");
1926 ast_free(cc_interfaces);
1942 static void *dialed_cc_interfaces_duplicate(
void *data)
1946 if (!new_cc_interfaces) {
1952 cc_ref(old_cc_interfaces->
interface_tree,
"New ref due to duplication of monitor tree");
1955 return new_cc_interfaces;
1968 .
type =
"Dial CC Interfaces",
1969 .duplicate = dialed_cc_interfaces_duplicate,
1970 .destroy = dialed_cc_interfaces_destroy,
1993 ast_channel_lock(incoming);
1995 ast_channel_unlock(incoming);
1999 cc_interfaces = cc_datastore->
data;
2002 ast_channel_unlock(incoming);
2006 if (monitor->
id ==
id) {
2017 if (!(child_dialstring =
ast_calloc(1,
sizeof(*child_dialstring)))) {
2028 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)
2035 if (monitor_iter->
id == parent_id) {
2040 if (!monitor_iter) {
2046 if (!strcmp(child_dialstring->
device_name, device_name)) {
2067 static struct ast_cc_monitor *cc_extension_monitor_init(
const char *
const exten,
const char *
const context,
const unsigned int parent_id)
2075 if (!(cc_interface = ao2_t_alloc(
sizeof(*cc_interface) +
ast_str_strlen(str), cc_interface_destroy,
2076 "Allocating new ast_cc_interface"))) {
2080 if (!(monitor = ao2_t_alloc(
sizeof(*monitor), cc_monitor_destroy,
"Allocating new ast_cc_monitor"))) {
2081 cc_unref(cc_interface,
"failed to allocate the monitor, so unref the interface");
2085 if (!(monitor->
private_data = extension_monitor_pvt_init())) {
2086 cc_unref(monitor,
"Failed to initialize extension monitor private data. uref monitor");
2087 cc_unref(cc_interface,
"Failed to initialize extension monitor private data. unref cc_interface");
2093 cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
2116 static int cc_interfaces_datastore_init(
struct ast_channel *chan) {
2132 if (!(interfaces =
ast_calloc(1,
sizeof(*interfaces)))) {
2136 if (!(monitor = cc_extension_monitor_init(ast_channel_exten(chan), ast_channel_context(chan), 0))) {
2137 ast_free(interfaces);
2141 if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
2142 cc_unref(monitor,
"Could not allocate the dialed interfaces datastore. Unreffing monitor");
2143 ast_free(interfaces);
2148 "Allocate monitor tree"))) {
2150 cc_unref(monitor,
"Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
2151 ast_free(interfaces);
2158 cc_ref(monitor,
"List's reference to extension monitor");
2160 dial_cc_datastore->
inheritance = DATASTORE_INHERIT_FOREVER;
2164 ast_channel_lock(chan);
2166 ast_channel_unlock(chan);
2167 cc_unref(monitor,
"Unreffing allocation's reference");
2192 static void call_destructor_with_no_monitor(
const char *
const monitor_type,
void *private_data)
2196 if (!monitor_callbacks) {
2231 size_t device_name_len = strlen(device_name);
2234 if (!(cc_interface = ao2_t_alloc(
sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
2235 "Allocating new ast_cc_interface"))) {
2240 cc_unref(cc_interface,
"Failed to allocate config params, unref interface");
2244 if (!(monitor = ao2_t_alloc(
sizeof(*monitor), cc_monitor_destroy,
"Allocating new ast_cc_monitor"))) {
2245 cc_unref(cc_interface,
"Failed to allocate monitor, unref interface");
2250 cc_unref(monitor,
"Failed to copy dialable name. Unref monitor");
2251 cc_unref(cc_interface,
"Failed to copy dialable name");
2256 cc_unref(monitor,
"Failed to find monitor callbacks. Unref monitor");
2257 cc_unref(cc_interface,
"Failed to find monitor callbacks");
2261 strcpy(cc_interface->device_name, device_name);
2268 cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
2306 ast_channel_lock(inbound);
2308 ast_log(LOG_WARNING,
"Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
2309 ast_channel_unlock(inbound);
2314 cc_interfaces = cc_datastore->
data;
2316 if (cc_interfaces->
ignore) {
2317 ast_channel_unlock(inbound);
2328 ast_channel_unlock(inbound);
2333 core_instance = find_cc_core_instance(cc_interfaces->
core_id);
2334 if (!core_instance) {
2335 core_instance = cc_core_init_instance(inbound, cc_interfaces->
interface_tree,
2336 cc_interfaces->
core_id, cc_data);
2337 if (!core_instance) {
2338 cc_interfaces->
ignore = 1;
2339 ast_channel_unlock(inbound);
2345 ast_channel_unlock(inbound);
2355 if (!strcmp(monitor->
interface->device_name, device_name)) {
2357 core_instance->
core_id, device_name);
2359 cc_unref(core_instance,
"Returning early from ast_handle_cc_control_frame. Unref core_instance");
2366 if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->
core_id))) {
2367 ast_log(LOG_WARNING,
"Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
2368 cc_unref(core_instance,
"Returning early from ast_handle_cc_control_frame. Unref core_instance");
2374 cc_ref(monitor,
"monitor tree's reference to the monitor");
2378 cc_extension_monitor_change_is_valid(core_instance, monitor->
parent_id, monitor->
interface->device_name, 0);
2380 cc_publish_available(cc_interfaces->
core_id, device_name, cc_service_to_string(cc_data->
service));
2382 cc_unref(core_instance,
"Done with core_instance after handling CC control frame");
2383 cc_unref(monitor,
"Unref reference from allocating monitor");
2413 ast_channel_lock(chan);
2417 ast_channel_unlock(chan);
2424 ast_channel_unlock(chan);
2431 ast_channel_unlock(chan);
2432 return cc_interfaces_datastore_init(chan);
2434 interfaces = cc_interfaces_datastore->
data;
2435 ast_channel_unlock(chan);
2437 if (interfaces->
ignore) {
2445 if (!(monitor = cc_extension_monitor_init(ast_channel_exten(chan),
2446 ast_channel_context(chan),
2452 cc_ref(monitor,
"monitor tree's reference to the monitor");
2456 cc_unref(monitor,
"Unref monitor's allocation reference");
2471 ast_channel_lock(chan);
2473 ast_channel_unlock(chan);
2477 cc_interfaces = datastore->
data;
2478 core_id_return = cc_interfaces->
ignore ? -1 : cc_interfaces->
core_id;
2479 ast_channel_unlock(chan);
2480 return core_id_return;
2484 static long count_agents(
const char *
const caller,
const int core_id_exception)
2493 static void kill_duplicate_offers(
char *caller)
2495 unsigned long match_flags = MATCH_NO_REQUEST;
2503 match_agent, caller, &match_flags,
"Killing duplicate offers");
2512 ast_assert(callbacks->
init != NULL);
2515 ast_assert(callbacks->
respond != NULL);
2522 static void agent_destroy(
void *data)
2533 const char *
const caller_name,
const int core_id,
2539 if (!(agent = ao2_t_alloc(
sizeof(*agent) + strlen(caller_name), agent_destroy,
2540 "Allocating new ast_cc_agent"))) {
2549 cc_unref(agent,
"Could not get channel config params.");
2553 cc_unref(agent,
"Could not init agent config params.");
2558 if (!(agent->
callbacks = find_agent_callbacks(caller_chan))) {
2559 cc_unref(agent,
"Could not find agent callbacks.");
2562 check_callback_sanity(agent->
callbacks);
2565 cc_unref(agent,
"Agent init callback failed.");
2575 static int cc_generic_agent_start_offer_timer(
struct ast_cc_agent *agent);
2576 static int cc_generic_agent_stop_offer_timer(
struct ast_cc_agent *agent);
2578 static int cc_generic_agent_status_request(
struct ast_cc_agent *agent);
2579 static int cc_generic_agent_stop_ringing(
struct ast_cc_agent *agent);
2580 static int cc_generic_agent_start_monitoring(
struct ast_cc_agent *agent);
2581 static int cc_generic_agent_recall(
struct ast_cc_agent *agent);
2582 static void cc_generic_agent_destructor(
struct ast_cc_agent *agent);
2586 .init = cc_generic_agent_init,
2587 .start_offer_timer = cc_generic_agent_start_offer_timer,
2588 .stop_offer_timer = cc_generic_agent_stop_offer_timer,
2589 .respond = cc_generic_agent_respond,
2590 .status_request = cc_generic_agent_status_request,
2591 .stop_ringing = cc_generic_agent_stop_ringing,
2592 .start_monitoring = cc_generic_agent_start_monitoring,
2593 .callee_available = cc_generic_agent_recall,
2594 .destructor = cc_generic_agent_destructor,
2656 if (ast_channel_caller(chan)->
id.
number.valid && ast_channel_caller(chan)->
id.
number.str) {
2659 if (ast_channel_caller(chan)->
id.name.valid && ast_channel_caller(chan)->
id.name.str) {
2665 ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
2669 static int offer_timer_expire(
const void *data)
2677 cc_unref(agent,
"Remove scheduler's reference to the agent");
2681 static int cc_generic_agent_start_offer_timer(
struct ast_cc_agent *agent)
2687 ast_assert(cc_sched_context != NULL);
2693 if ((sched_id =
ast_sched_add(cc_sched_context, when, offer_timer_expire, cc_ref(agent,
"Give scheduler an agent ref"))) == -1) {
2700 static int cc_generic_agent_stop_offer_timer(
struct ast_cc_agent *agent)
2706 cc_unref(agent,
"Remove scheduler's reference to the agent");
2721 static int cc_generic_agent_status_request(
struct ast_cc_agent *agent)
2727 static int cc_generic_agent_stop_ringing(
struct ast_cc_agent *agent)
2747 cc_unref(agent,
"Done holding ref for subscription");
2754 if (dev_state->
eid) {
2759 new_state = dev_state->
state;
2760 if (!cc_generic_is_device_available(new_state)) {
2769 static int cc_generic_agent_start_monitoring(
struct ast_cc_agent *agent)
2772 struct ast_str *str = ast_str_alloca(128);
2775 ast_assert(generic_pvt->
sub == NULL);
2776 ast_str_set(&str, 0,
"Agent monitoring %s device state since it is busy\n",
2780 if (!device_specific_topic) {
2784 if (!(generic_pvt->
sub = stasis_subscribe(device_specific_topic, generic_agent_devstate_cb, agent))) {
2790 cc_ref(agent,
"Ref agent for subscription");
2794 static void *generic_recall(
void *data)
2812 if ((target = strchr(interface,
'/'))) {
2836 ast_channel_exten_set(chan, generic_pvt->
exten);
2837 ast_channel_context_set(chan, generic_pvt->
context);
2838 ast_channel_priority_set(chan, 1);
2843 if (!ast_strlen_zero(callback_sub)) {
2862 static int cc_generic_agent_recall(
struct ast_cc_agent *agent)
2867 if (!cc_generic_is_device_available(current_state)) {
2874 ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
2878 static void cc_generic_agent_destructor(
struct ast_cc_agent *agent)
2887 cc_generic_agent_stop_offer_timer(agent);
2888 if (agent_pvt->
sub) {
2892 ast_free(agent_pvt);
2895 static void cc_core_instance_destructor(
void *data)
2899 if (core_instance->
agent) {
2900 cc_unref(core_instance->
agent,
"Core instance is done with the agent now");
2903 core_instance->
monitors = cc_unref(core_instance->
monitors,
"Core instance is done with interface list");
2927 kill_duplicate_offers(caller);
2931 agent_count = count_agents(caller, recall_core_id);
2944 if (!(core_instance = ao2_t_alloc(
sizeof(*core_instance), cc_core_instance_destructor,
"Creating core instance for CC"))) {
2948 core_instance->
core_id = core_id;
2949 if (!(core_instance->
agent = cc_agent_init(caller_chan, caller, core_instance->
core_id, called_tree))) {
2950 cc_unref(core_instance,
"Couldn't allocate agent, unref core_instance");
2954 core_instance->
monitors = cc_ref(called_tree,
"Core instance getting ref to monitor tree");
2956 ao2_t_link(cc_core_instances, core_instance,
"Link core instance into container");
2958 return core_instance;
2971 switch (new_state) {
2983 (current_state ==
CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
3027 ast_log(LOG_WARNING,
"Someone requested to change to CC_AVAILABLE? Ignoring.\n");
3066 if (iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3080 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3083 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->
parent_id,
3084 monitor_iter->
interface->device_name, 1);
3085 cc_unref(monitor_iter,
"request_cc failed. Unref list's reference to monitor");
3102 ast_log(LOG_WARNING,
"Cannot request CC since there is no more room for requests\n");
3109 request_cc(core_instance);
3118 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3121 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->
parent_id,
3122 monitor_iter->
interface->device_name, 1);
3123 cc_unref(monitor_iter,
"unsuspend failed. Unref list's reference to monitor");
3148 unsuspend(core_instance);
3165 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3168 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->
parent_id,
3169 monitor_iter->
interface->device_name, 1);
3170 cc_unref(monitor_iter,
"suspend failed. Unref list's reference to monitor");
3187 suspend(core_instance);
3198 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3201 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->
parent_id,
3202 monitor_iter->
interface->device_name, 1);
3203 cc_unref(monitor_iter,
"cancel_available_timer failed. Unref list's reference to monitor");
3210 ast_cc_failed(core_instance->
core_id,
"All device monitors failed to cancel their available timers");
3219 cancel_available_timer(core_instance);
3229 ao2_t_unlink(cc_core_instances, core_instance,
"Unlink core instance since CC recall has completed");
3236 ao2_t_unlink(cc_core_instances, core_instance,
"Unlink core instance since CC failed");
3252 static int cc_do_state_change(
void *datap)
3260 args->core_id, args->state, args->debug);
3264 if (!is_state_change_valid(core_instance->
current_state, args->state, core_instance->
agent)) {
3266 args->core_id, cc_state_to_string(core_instance->
current_state), cc_state_to_string(args->state));
3276 cc_unref(core_instance,
"Unref core instance from when it was found earlier");
3283 res = state_change_funcs[core_instance->
current_state](core_instance, args, previous_state);
3286 if (!res && !strcmp(core_instance->agent->callbacks->type,
"generic")) {
3287 ccss_notify_device_state_change(core_instance->agent->device_name, core_instance->current_state);
3291 cc_unref(core_instance,
"Unref since state change has completed");
3295 static int cc_request_state_change(
enum cc_state state,
const int core_id,
const char *
debug, va_list ap)
3310 debuglen = vsnprintf(dummy,
sizeof(dummy), debug, aq) + 1;
3313 if (!(args =
ast_calloc(1,
sizeof(*args) + debuglen))) {
3317 core_instance = find_cc_core_instance(core_id);
3318 if (!core_instance) {
3326 args->state = state;
3327 args->core_id = core_id;
3328 vsnprintf(args->debug, debuglen, debug, ap);
3332 cc_unref(core_instance,
"Unref core instance. ast_taskprocessor_push failed");
3345 static void *cc_recall_ds_duplicate(
void *data)
3353 new_data->interface_tree = cc_ref(old_data->interface_tree,
"Bump refcount of monitor tree for recall datastore duplicate");
3354 new_data->core_id = old_data->core_id;
3355 new_data->nested = 1;
3359 static void cc_recall_ds_destroy(
void *data)
3362 recall_data->interface_tree = cc_unref(recall_data->interface_tree,
"Unref recall monitor tree");
3363 ast_free(recall_data);
3367 .
type =
"cc_recall",
3368 .duplicate = cc_recall_ds_duplicate,
3369 .destroy = cc_recall_ds_destroy,
3374 struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
3378 if (!recall_datastore) {
3382 if (!(recall_data =
ast_calloc(1,
sizeof(*recall_data)))) {
3387 if (!(core_instance = find_cc_core_instance(core_id))) {
3388 ast_free(recall_data);
3393 recall_data->interface_tree = cc_ref(core_instance->
monitors,
3394 "Bump refcount for monitor tree for recall datastore");
3395 recall_data->core_id =
core_id;
3396 recall_datastore->
data = recall_data;
3397 recall_datastore->
inheritance = DATASTORE_INHERIT_FOREVER;
3398 ast_channel_lock(chan);
3400 ast_channel_unlock(chan);
3401 cc_unref(core_instance,
"Recall datastore set up. No need for core_instance ref");
3412 int core_id_candidate;
3414 ast_assert(core_id != NULL);
3418 ast_channel_lock(chan);
3421 ast_channel_unlock(chan);
3425 recall_data = recall_datastore->
data;
3427 if (recall_data->ignore) {
3432 ast_channel_unlock(chan);
3436 if (!recall_data->nested) {
3443 *core_id = recall_data->core_id;
3444 ast_channel_unlock(chan);
3448 if (ast_strlen_zero(monitor_type)) {
3454 ast_channel_unlock(chan);
3458 interface_tree = recall_data->interface_tree;
3465 core_id_candidate = recall_data->core_id;
3466 ast_channel_unlock(chan);
3474 if (!strcmp(device_monitor->
interface->device_name, device_name) &&
3477 *core_id = core_id_candidate;
3491 if (!core_instance) {
3497 if (!strcmp(monitor_iter->
interface->device_name, device_name)) {
3499 cc_ref(monitor_iter,
"Hand the requester of the monitor a reference");
3504 cc_unref(core_instance,
"Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
3505 return monitor_iter;
3524 static void cc_unique_append(
struct ast_str **str,
const char *dialstring)
3528 if (ast_strlen_zero(dialstring)) {
3532 snprintf(dialstring_search,
sizeof(dialstring_search),
"%s%c", dialstring,
'&');
3553 static void build_cc_interfaces_chanvar(
struct ast_cc_monitor *starting_point,
struct ast_str **str)
3558 int top_level_id = starting_point->
id;
3576 while ((monitor_iter =
AST_LIST_NEXT(monitor_iter, next))) {
3577 if (monitor_iter->
parent_id == top_level_id) {
3578 cc_unique_append(str, monitor_iter->
dialstring);
3591 ast_log(LOG_ERROR,
"CC_INTERFACES is empty. starting device_name:'%s'\n",
3592 starting_point->
interface->device_name);
3609 ast_channel_lock(chan);
3611 ast_channel_unlock(chan);
3615 recall_data = recall_datastore->
data;
3616 interface_tree = recall_data->interface_tree;
3617 core_id = recall_data->core_id;
3618 ast_channel_unlock(chan);
3622 build_cc_interfaces_chanvar(monitor, &str);
3646 ast_channel_lock(chan);
3648 ast_channel_unlock(chan);
3652 recall_data = recall_datastore->
data;
3653 interface_tree = recall_data->interface_tree;
3654 core_id = recall_data->core_id;
3655 ast_channel_unlock(chan);
3659 if (!strcmp(monitor_iter->
interface->device_name, extension)) {
3664 if (!monitor_iter) {
3674 build_cc_interfaces_chanvar(monitor_iter, &str);
3692 ast_channel_lock(chan);
3694 cc_interfaces = cc_datastore->
data;
3695 cc_interfaces->
ignore = 1;
3699 recall_cc_data = cc_recall_datastore->
data;
3700 recall_cc_data->ignore = 1;
3702 ast_channel_unlock(chan);
3705 static __attribute__((format(printf, 2, 3))) int cc_offer(const
int core_id, const
char * const debug, ...)
3710 va_start(ap, debug);
3722 char cc_is_offerable;
3724 ast_channel_lock(caller_chan);
3726 ast_channel_unlock(caller_chan);
3730 cc_interfaces = datastore->
data;
3732 core_id = cc_interfaces->
core_id;
3733 ast_channel_unlock(caller_chan);
3735 if (cc_is_offerable) {
3736 res = cc_offer(core_id,
"CC offered to caller %s", ast_channel_name(caller_chan));
3746 va_start(ap, debug);
3757 va_start(ap, debug);
3758 res = cc_request_state_change(
CC_ACTIVE, core_id, debug, ap);
3768 va_start(ap, debug);
3779 va_start(ap, debug);
3780 res = cc_request_state_change(
CC_CALLER_BUSY, core_id, debug, ap);
3790 va_start(ap, debug);
3791 res = cc_request_state_change(
CC_ACTIVE, core_id, debug, ap);
3801 va_start(ap, debug);
3802 res = cc_request_state_change(
CC_RECALLING, core_id, debug, ap);
3815 ast_channel_lock(chan);
3818 ast_channel_unlock(chan);
3821 recall_data = recall_datastore->
data;
3822 if (recall_data->nested || recall_data->ignore) {
3833 ast_channel_unlock(chan);
3836 core_id = recall_data->core_id;
3837 ast_channel_unlock(chan);
3838 va_start(ap, debug);
3839 res = cc_request_state_change(
CC_COMPLETE, core_id, debug, ap);
3849 va_start(ap, debug);
3850 res = cc_request_state_change(
CC_FAILED, core_id, debug, ap);
3861 static int cc_monitor_failed(
void *data)
3867 core_instance = find_cc_core_instance(failure_data->core_id);
3868 if (!core_instance) {
3871 "Core %d: Could not find core instance for device %s '%s'\n",
3872 failure_data->core_id, failure_data->device_name, failure_data->debug);
3873 ast_free((
char *) failure_data->device_name);
3874 ast_free((
char *) failure_data->debug);
3875 ast_free(failure_data);
3881 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
3882 if (!strcmp(monitor_iter->
interface->device_name, failure_data->device_name)) {
3884 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->
parent_id,
3885 monitor_iter->
interface->device_name, 1);
3887 cc_publish_monitorfailed(monitor_iter->
core_id, monitor_iter->
interface->device_name);
3888 cc_unref(monitor_iter,
"Monitor reported failure. Unref list's reference.");
3898 cc_unref(core_instance,
"Finished with core_instance in cc_monitor_failed\n");
3900 ast_free((
char *) failure_data->device_name);
3901 ast_free((
char *) failure_data->debug);
3902 ast_free(failure_data);
3912 if (!(failure_data =
ast_calloc(1,
sizeof(*failure_data)))) {
3916 if (!(failure_data->device_name =
ast_strdup(monitor_name))) {
3917 ast_free(failure_data);
3921 va_start(ap, debug);
3924 ast_free((
char *)failure_data->device_name);
3925 ast_free(failure_data);
3930 failure_data->core_id = core_id;
3934 ast_free((
char *)failure_data->device_name);
3935 ast_free((
char *)failure_data->debug);
3936 ast_free(failure_data);
3941 static int cc_status_request(
void *data)
3947 cc_unref(core_instance,
"Status request finished. Unref core instance");
3956 if (!core_instance) {
3962 cc_unref(core_instance,
"Unref core instance. ast_taskprocessor_push failed");
3967 static int cc_stop_ringing(
void *data)
3984 cc_unref(core_instance,
"Stop ringing finished. Unref core_instance");
3993 if (!core_instance) {
3999 cc_unref(core_instance,
"Unref core instance. ast_taskprocessor_push failed");
4004 static int cc_party_b_free(
void *data)
4012 cc_unref(core_instance,
"Party B free finished. Unref core_instance");
4021 if (!core_instance) {
4027 cc_unref(core_instance,
"Unref core instance. ast_taskprocessor_push failed");
4037 static int cc_status_response(
void *data)
4048 if (monitor_iter->
interface->monitor_class == AST_CC_DEVICE_MONITOR &&
4054 cc_unref(core_instance,
"Status response finished. Unref core instance");
4069 core_instance = find_cc_core_instance(core_id);
4070 if (!core_instance) {
4075 args->core_instance = core_instance;
4076 args->devstate = devstate;
4080 cc_unref(core_instance,
"Unref core instance. ast_taskprocessor_push failed");
4087 const char *monitor_type,
const char *
const device_name,
const char * dialstring,
4088 enum ast_cc_service_type service,
void *private_data,
struct cc_control_payload *payload)
4094 ast_channel_lock(chan);
4097 ast_channel_unlock(chan);
4100 cc_interfaces = datastore->
data;
4102 ast_channel_unlock(chan);
4115 const char *
const dialstring,
enum ast_cc_service_type service,
void *private_data)
4128 ast_log(LOG_NOTICE,
"Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
4132 if (
ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
4142 const char *monitor_type,
const char *
const device_name,
4143 const char *
const dialstring,
enum ast_cc_service_type service,
void *private_data,
4151 if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
4158 frame->
data.ptr = payload;
4159 frame->
datalen =
sizeof(*payload);
4170 if (ast_channel_hangupcause(outgoing) != AST_CAUSE_BUSY && ast_channel_hangupcause(outgoing) != AST_CAUSE_CONGESTION) {
4190 dialstring, AST_CC_CCBS, NULL, &payload)) {
4198 const char *monitor_type,
const char *
const device_name,
const char *
const dialstring,
void *private_data)
4201 if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
4203 call_destructor_with_no_monitor(monitor_type, private_data);
4220 static const char *ccreq_app =
"CallCompletionRequest";
4222 static int ccreq_exec(
struct ast_channel *chan,
const char *data)
4226 unsigned long match_flags;
4231 match_flags = MATCH_NO_REQUEST;
4232 if (!(core_instance =
ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags,
"Find core instance for CallCompletionRequest"))) {
4240 core_instance->
core_id, device_name);
4247 cc_unref(core_instance,
"Unref core_instance since CallCompletionRequest was called with native agent");
4257 cc_unref(core_instance,
"Unref core_instance since too many CC requests");
4267 cc_unref(core_instance,
"Done with CallCompletionRequest");
4271 static const char *cccancel_app =
"CallCompletionCancel";
4273 static int cccancel_exec(
struct ast_channel *chan,
const char *data)
4277 unsigned long match_flags;
4282 match_flags = MATCH_REQUEST;
4283 if (!(core_instance =
ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags,
"Find core instance for CallCompletionCancel"))) {
4291 ast_log(LOG_WARNING,
"CallCompletionCancel may only be used for calles with a generic agent\n");
4292 cc_unref(core_instance,
"Unref core instance found during CallCompletionCancel");
4297 res =
ast_cc_failed(core_instance->
core_id,
"Call completion request Cancelled for core ID %d by caller %s",
4298 core_instance->
core_id, device_name);
4299 cc_unref(core_instance,
"Unref core instance found during CallCompletionCancel");
4309 const char *monitor_type;
4313 static int count_monitors_cb(
void *obj,
void *arg,
int flags)
4317 const char *device_name = cb_data->device_name;
4318 const char *monitor_type = cb_data->monitor_type;
4323 if (!strcmp(monitor_iter->
interface->device_name, device_name) &&
4337 ao2_t_callback(cc_core_instances,
OBJ_NODATA, count_monitors_cb, &data,
"Counting agents");
4342 static void initialize_cc_max_requests(
void)
4345 const char *cc_max_requests_str;
4350 if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
4351 ast_log(LOG_WARNING,
"Could not find valid ccss.conf file. Using cc_max_requests default\n");
4356 if (!(cc_max_requests_str = ast_variable_retrieve(cc_config,
"general",
"cc_max_requests"))) {
4364 if (!ast_strlen_zero(endptr)) {
4365 ast_log(LOG_WARNING,
"Invalid input given for cc_max_requests. Using default\n");
4377 static void initialize_cc_devstate_map_helper(
struct ast_config *cc_config,
enum cc_state state,
const char *cc_setting)
4379 const char *cc_devstate_str;
4382 if ((cc_devstate_str = ast_variable_retrieve(cc_config,
"general", cc_setting))) {
4385 cc_state_to_devstate_map[state] = this_devstate;
4401 static void initialize_cc_devstate_map(
void)
4407 if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
4408 ast_log(LOG_WARNING,
4409 "Could not find valid ccss.conf file. Using cc_[state]_devstate defaults\n");
4413 initialize_cc_devstate_map_helper(cc_config,
CC_AVAILABLE,
"cc_available_devstate");
4414 initialize_cc_devstate_map_helper(cc_config,
CC_CALLER_OFFERED,
"cc_caller_offered_devstate");
4415 initialize_cc_devstate_map_helper(cc_config,
CC_CALLER_REQUESTED,
"cc_caller_requested_devstate");
4416 initialize_cc_devstate_map_helper(cc_config,
CC_ACTIVE,
"cc_active_devstate");
4417 initialize_cc_devstate_map_helper(cc_config,
CC_CALLEE_READY,
"cc_callee_ready_devstate");
4418 initialize_cc_devstate_map_helper(cc_config,
CC_CALLER_BUSY,
"cc_caller_busy_devstate");
4419 initialize_cc_devstate_map_helper(cc_config,
CC_RECALLING,
"cc_recalling_devstate");
4420 initialize_cc_devstate_map_helper(cc_config,
CC_COMPLETE,
"cc_complete_devstate");
4421 initialize_cc_devstate_map_helper(cc_config,
CC_FAILED,
"cc_failed_devstate");
4426 static void cc_cli_print_monitor_stats(
struct ast_cc_monitor *monitor,
int fd,
int parent_id)
4433 ast_cli(fd,
"\t\t|-->%s", monitor->
interface->device_name);
4434 if (monitor->
interface->monitor_class == AST_CC_DEVICE_MONITOR) {
4439 while ((child_monitor_iter =
AST_LIST_NEXT(child_monitor_iter, next))) {
4440 if (child_monitor_iter->
parent_id == monitor->
id) {
4441 cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->
id);
4446 static int print_stats_cb(
void *obj,
void *arg,
int flags)
4459 static int cc_cli_output_status(
void *data)
4465 ast_cli(*cli_fd,
"There are currently no active call completion transactions\n");
4467 ast_cli(*cli_fd,
"%d Call completion transactions\n", count);
4468 ast_cli(*cli_fd,
"Core ID\t\tCaller\t\t\t\tStatus\n");
4469 ast_cli(*cli_fd,
"----------------------------------------------------------------------------\n");
4470 ao2_t_callback(cc_core_instances,
OBJ_NODATA, print_stats_cb, cli_fd,
"Printing stats to CLI");
4482 e->
command =
"cc report status";
4484 "Usage: cc report status\n"
4485 " Report the current status of any ongoing CC transactions\n";
4492 return CLI_SHOWUSAGE;
4509 static int kill_cores(
void *obj,
void *arg,
int flags)
4514 if (!core_id || (core_instance->
core_id == *core_id)) {
4520 static char *complete_core_id(
const char *word)
4522 int wordlen = strlen(word);
4526 for (; (core_instance = ao2_t_iterator_next(&core_iter,
"Next core instance"));
4527 cc_unref(core_instance,
"CLI tab completion iteration")) {
4528 char core_id_str[20];
4529 snprintf(core_id_str,
sizeof(core_id_str),
"%d", core_instance->
core_id);
4530 if (!strncmp(word, core_id_str, wordlen)) {
4532 cc_unref(core_instance,
"Found a matching core ID for CLI tab-completion");
4546 e->
command =
"cc cancel [core|all]";
4548 "Usage: cc cancel can be used in two ways.\n"
4549 " 1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
4550 " core ID equal to the specified core ID.\n"
4551 " 2. 'cc cancel all' will cancel all active CC transactions.\n";
4554 if (a->pos == 3 && !strcasecmp(a->argv[2],
"core")) {
4555 return complete_core_id(a->word);
4563 if (strcasecmp(a->argv[2],
"core")) {
4564 return CLI_SHOWUSAGE;
4566 core_id = strtol(a->argv[3], &endptr, 10);
4567 if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
4568 return CLI_SHOWUSAGE;
4570 ao2_t_callback(cc_core_instances,
OBJ_NODATA, kill_cores, &core_id,
"CLI Killing Core Id");
4571 }
else if (a->argc == 3) {
4572 if (strcasecmp(a->argv[2],
"all")) {
4573 return CLI_SHOWUSAGE;
4575 ao2_t_callback(cc_core_instances,
OBJ_NODATA, kill_cores, NULL,
"CLI Killing all CC cores");
4577 return CLI_SHOWUSAGE;
4584 AST_CLI_DEFINE(handle_cc_status,
"Reports CC stats"),
4585 AST_CLI_DEFINE(handle_cc_kill,
"Kill a CC transaction"),
4588 static int unload_module(
void)
4598 if (cc_sched_context) {
4600 cc_sched_context = NULL;
4602 if (cc_core_taskprocessor) {
4606 if (cc_core_instances) {
4607 ao2_t_ref(cc_core_instances, -1,
"Unref cc_core_instances container in cc_shutdown");
4608 cc_core_instances = NULL;
4610 if (generic_monitors) {
4611 ao2_t_ref(generic_monitors, -1,
"Unref generic_monitor container in cc_shutdown");
4612 generic_monitors = NULL;
4618 static int load_module(
void)
4623 CC_CORE_INSTANCES_BUCKETS,
4624 cc_core_instance_hash_fn, NULL, cc_core_instance_cmp_fn,
4625 "Create core instance container");
4626 if (!cc_core_instances) {
4631 CC_CORE_INSTANCES_BUCKETS,
4632 generic_monitor_instance_list_hash_fn, NULL, generic_monitor_instance_list_cmp_fn,
4633 "Create generic monitor container");
4634 if (!generic_monitors) {
4653 dialed_cc_interface_counter = 1;
4654 initialize_cc_max_requests();
4657 initialize_cc_devstate_map();
4663 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Call Completion Supplementary Services",
4664 .support_level = AST_MODULE_SUPPORT_CORE,
4665 .load = load_module,
4666 .unload = unload_module,
struct stasis_topic * ast_device_state_topic(const char *device)
Get the Stasis topic for device state messages for a specific device.
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.
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.
void(* ast_cc_callback_fn)(struct ast_channel *chan, 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.
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_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
unsigned int ast_get_ccnr_available_timer(struct ast_cc_config_params *config)
Get the ccnr_available_timer.
struct cc_monitor_tree * monitors
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Main Channel structure associated with a channel.
The payload for an AST_CONTROL_CC frame.
ast_device_state
Device States.
void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char *const value)
Set the callback subroutine name.
const char * type
Type of monitor the callbacks belong to.
void ast_set_cc_agent_dialstring(struct ast_cc_config_params *config, const char *const value)
Set the cc_agent_dialstring.
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk main include file. File version handling, generic pbx functions.
void * private_data
Private data allocated by the callee.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes. ...
static unsigned int global_cc_max_requests
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
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.
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
String manipulation functions.
char cid_num[AST_CHANNEL_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.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
const struct ast_channel_tech * ast_get_channel_tech(const char *name)
Get a channel technology structure by name.
int ast_cc_is_config_param(const char *const name)
Is this a CCSS configuration parameter?
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
struct ast_channel * ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int timeout, int *reason, const char *cid_num, const char *cid_name)
Request a channel of a given type, with data as optional information used by the low level module and...
unsigned int ast_get_cc_recall_timer(struct ast_cc_config_params *config)
Get the cc_recall_timer.
int is_valid
Is this structure valid for use in CC_INTERFACES?
int ast_cc_failed(int core_id, const char *const debug,...)
Indicate failure has occurred.
static int dialed_cc_interface_counter
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_set_ccbs_available_timer(struct ast_cc_config_params *config, unsigned int value)
Set the ccbs_available_timer.
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
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_agent_accept_request(int core_id, const char *const debug,...)
Accept inbound CC request.
descriptor for a cli entry.
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.
int(* party_b_free)(struct ast_cc_agent *agent)
Let the caller know that the callee has become free but that the caller cannot attempt to call back b...
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
struct ast_cc_config_params * cc_params
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static int debug
Global debug status.
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
char context[AST_CHANNEL_NAME]
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
int parent_interface_id
ID of parent extension.
int ast_set_cc_monitor_policy(struct ast_cc_config_params *config, enum ast_cc_monitor_policies value)
Set the cc_monitor_policy.
enum ast_device_state state
void ast_set_cc_max_monitors(struct ast_cc_config_params *config, unsigned int value)
Set the cc_max_monitors.
int(* cancel_available_timer)(struct ast_cc_monitor *monitor, int *sched_id)
Cancel the running available timer.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
int(* status_request)(struct ast_cc_agent *agent)
Request the status of the agent's device.
void(* destructor)(void *private_data)
Destroy private data on the monitor.
#define ast_log_dynamic_level(level,...)
Send a log message to a dynamically registered log level.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
return a reference to a taskprocessor, create one if it does not exist
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
int ast_setup_cc_recall_datastore(struct ast_channel *chan, const int core_id)
Set up a CC recall datastore on a channel.
int ast_devstate_prov_del(const char *label)
Remove device state provider.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Structure for a data store type.
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
int(* start_offer_timer)(struct ast_cc_agent *agent)
Start the offer timer.
char exten[AST_CHANNEL_NAME]
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
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 bac...
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
const struct ast_cc_monitor_callbacks * callbacks
ast_cc_agent_response_reason
static int core_id_counter
#define ast_cc_config_params_init()
Allocate and initialize an ast_cc_config_params structure.
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
struct cc_core_instance * core_instance
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
void ast_cc_config_params_destroy(struct ast_cc_config_params *params)
Free memory from CCSS configuration params.
int ast_cc_call_init(struct ast_channel *chan, int *ignore_cc)
Start the CC process on a call.
static const char * CC_LOGGER_LEVEL_NAME
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
ast_cc_monitor_policies
The various possibilities for cc_monitor_policy values.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
int ast_cc_agent_status_response(int core_id, enum ast_device_state devstate)
Response with a caller's current status.
struct ast_frame_subclass subclass
struct ast_cc_config_params * ast_channel_get_cc_config_params(struct ast_channel *chan)
Get the CCSS parameters from a channel.
int(* unsuspend)(struct ast_cc_monitor *monitor)
Unsuspend monitoring.
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
void ast_ignore_cc(struct ast_channel *chan)
Mark the channel to ignore further CC activity.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
int ast_cc_agent_recalling(int core_id, const char *const debug,...)
Tell the CC core that a caller is currently recalling.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
static struct ast_sched_context * cc_sched_context
void ast_set_cc_offer_timer(struct ast_cc_config_params *config, unsigned int value)
Set the cc_offer_timer.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
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.
enum ast_cc_monitor_policies ast_get_cc_monitor_policy(struct ast_cc_config_params *config)
Get the cc_monitor_policy.
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_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
int(* cc_callback)(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
Call a function with cc parameters as a function parameter.
char device_name[AST_CHANNEL_NAME]
Name of device to be monitored.
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
General Asterisk PBX channel definitions.
struct stasis_subscription * sub
const struct ast_eid * eid
The EID of the server where this message originated.
#define ast_strdupa(s)
duplicate a string in memory from the stack
char dialstring[AST_CHANNEL_NAME]
Recall dialstring.
const char * ast_get_cc_agent_dialstring(struct ast_cc_config_params *config)
Get the cc_agent_dialstring.
int ast_cc_available_timer_expire(const void *data)
Scheduler callback for available timer expiration.
Structure with information about an outbound interface.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_MAX_EXTENSION
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.
void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel *outbound, void *frame_data)
Properly react to a CC control frame.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
structure to hold extensions
int(* stop_ringing)(struct ast_cc_agent *agent)
Request for an agent's phone to stop ringing.
int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan)
Set the first level CC_INTERFACES channel variable for a channel.
struct ast_cc_agent * ast_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.
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_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_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, size_t size)
Find the appropriate CC agent type to use given a channel.
int(* start_monitoring)(struct ast_cc_agent *agent)
Begin monitoring a busy device.
int ast_cc_completed(struct ast_channel *chan, const char *const debug,...)
Indicate recall has been acknowledged.
#define ast_malloc(len)
A wrapper for malloc()
cc_state
The states used in the CCSS core state machine.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
void ast_set_ccnr_available_timer(struct ast_cc_config_params *config, unsigned int value)
Set the ccnr_available_timer.
void(* respond)(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
Respond to a CC request.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
int ast_cc_monitor_status_request(int core_id)
Request the status of a caller or callers.
#define AST_CC_GENERIC_MONITOR_TYPE
int ast_cc_offer(struct ast_channel *caller_chan)
Offer CC to a caller.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
struct ast_cc_config_params * config_params
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
const char * type
Type of agent the callbacks belong to.
int(* status_response)(struct ast_cc_monitor *monitor, enum ast_device_state devstate)
Status response to an ast_cc_monitor_status_request().
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
char * ast_tech_to_upper(char *dev_str)
Convert the tech portion of a device string to upper case.
Support for dynamic strings.
char device_name[AST_CHANNEL_NAME]
The name of the device being dialed.
Structure representing an agent.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
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.
int ast_cc_monitor_register(const struct ast_cc_monitor_callbacks *callbacks)
Register a set of monitor callbacks with the core.
enum ast_cc_service_type service
Service offered by the endpoint.
void ast_cc_agent_unregister(const struct ast_cc_agent_callbacks *callbacks)
Unregister a set of agent callbacks with the core.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
The "tree" of interfaces that is dialed.
enum cc_state current_state
int(* callee_available)(struct ast_cc_agent *agent)
Alert the caller that it is time to try recalling.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
union ast_frame::@224 data
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_calloc(num, len)
A wrapper for calloc()
int(* request_cc)(struct ast_cc_monitor *monitor, int *available_timer_id)
Request CCSS.
char * dialstring
Name that should be used to recall specified interface.
const char * monitor_type
The type of monitor that should be used for this interface.
Call Completion Supplementary Services API.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Module could not be loaded properly.
int ast_cc_get_current_core_id(struct ast_channel *chan)
Get the core id for the current call.
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_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
int ast_cc_agent_caller_available(int core_id, const char *const debug,...)
Indicate that a previously unavailable caller has become available.
An API for managing task processing threads that can be shared across modules.
struct ast_cc_interface * interface
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Structure used to handle boolean flags.
private data for generic device monitor
struct cc_monitor_tree * interface_tree
int(* suspend)(struct ast_cc_monitor *monitor)
Suspend monitoring.
unsigned int ast_get_cc_max_agents(struct ast_cc_config_params *config)
Get the cc_max_agents.
void ast_set_cc_recall_timer(struct ast_cc_config_params *config, unsigned int value)
Set the cc_recall_timer.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
unsigned int ast_get_cc_max_monitors(struct ast_cc_config_params *config)
Get the cc_max_monitors.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
const struct ast_cc_agent_callbacks * callbacks
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
A ast_taskprocessor structure is a singleton by name.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
char original_dialstring[AST_CHANNEL_NAME]
the original dialstring used to call a particular device
int ast_logger_register_level(const char *name)
Register a new logger level.
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container...
struct ast_cc_config_params config_params
Configuration parameters used by this endpoint.
void ast_cc_default_config_params(struct ast_cc_config_params *params)
Set the specified CC config params to default values.
int ast_cc_monitor_stop_ringing(int core_id)
Alert a caller to stop ringing.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
enum ast_cc_agent_policies ast_get_cc_agent_policy(struct ast_cc_config_params *config)
Get the cc_agent_policy.
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
Data regarding an extension monitor's child's dialstrings.
void ast_cc_monitor_unregister(const struct ast_cc_monitor_callbacks *callbacks)
Unregister a set of monitor callbacks with the core.
Private data for an extension monitor.
#define ao2_t_find(container, arg, flags, tag)
int(* init)(struct ast_cc_agent *agent, struct ast_channel *chan)
CC agent initialization.
char cid_name[AST_CHANNEL_NAME]
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
int ast_channel_get_device_name(struct ast_channel *chan, char *device_name, size_t name_buffer_length)
Get a device name given its channel structure.
Data structure associated with a single frame of data.
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Internal Asterisk hangup causes.
static int has_device_monitors(struct cc_core_instance *core_instance)
check if the core instance has any device monitors
int ast_register_application2(const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
Register an application.
Abstract JSON element (object, array, string, int, ...).
The structure that contains device state.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
ast_cc_agent_policies
The various possibilities for cc_agent_policy values.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
const char * monitor_type
The type of monitor to allocate.
struct ast_cc_monitor * ast_cc_get_monitor_by_recall_core_id(const int core_id, const char *const device_name)
Get the associated monitor given the device name and core_id.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
enum ast_frame_type frametype
struct ast_cc_agent * agent
void * private_data
Data that is private to a monitor technology.
int ast_cc_agent_register(const struct ast_cc_agent_callbacks *callbacks)
Register a set of agent callbacks with the core.
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
Callbacks defined by CC monitors.
void ast_set_cc_max_agents(struct ast_cc_config_params *config, unsigned int value)
Set the cc_max_agents.
unsigned int dial_parent_id
int ast_set_cc_agent_policy(struct ast_cc_config_params *config, enum ast_cc_agent_policies value)
Set the cc_agent_policy.
void(* destructor)(struct ast_cc_agent *agent)
Destroy private data on the agent.
const char * ast_get_cc_callback_sub(struct ast_cc_config_params *config)
Get the name of the callback subroutine.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
int ast_cc_agent_caller_busy(int core_id, const char *debug,...)
Indicate that the caller is busy.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
static int cc_logger_level
enum ast_cc_service_type service_offered
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
int(* stop_offer_timer)(struct ast_cc_agent *agent)
Stop the offer timer.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
unsigned int ast_get_cc_offer_timer(struct ast_cc_config_params *config)
Get the cc_offer_timer.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
static int cc_request_count
unsigned int ast_get_ccbs_available_timer(struct ast_cc_config_params *config)
Get the ccbs_available_timer.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
static struct ast_taskprocessor * cc_core_taskprocessor
int ast_cc_monitor_count(const char *const name, const char *const type)
Return the number of outstanding CC requests to a specific device.