Skip to content
Snippets Groups Projects
ccss.c 153 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * more information regarding the actual structure of the tree, see
     * the documentation provided in include/asterisk/ccss.h
     */
    
    static const struct ast_datastore_info dialed_cc_interfaces_info = {
    
    	.type = "Dial CC Interfaces",
    	.duplicate = dialed_cc_interfaces_duplicate,
    	.destroy = dialed_cc_interfaces_destroy,
    };
    
    static struct extension_monitor_pvt *extension_monitor_pvt_init(void)
    {
    	struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
    	if (!ext_pvt) {
    		return NULL;
    	}
    	AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
    	return ext_pvt;
    }
    
    void ast_cc_extension_monitor_add_dialstring(struct ast_channel *incoming, const char * const dialstring, const char * const device_name)
    {
    	struct ast_datastore *cc_datastore;
    	struct dialed_cc_interfaces *cc_interfaces;
    	struct ast_cc_monitor *monitor;
    	struct extension_monitor_pvt *extension_pvt;
    	struct extension_child_dialstring *child_dialstring;
    	struct cc_monitor_tree *interface_tree;
    	int id;
    
    	ast_channel_lock(incoming);
    	if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
    		ast_channel_unlock(incoming);
    		return;
    	}
    
    	cc_interfaces = cc_datastore->data;
    	interface_tree = cc_interfaces->interface_tree;
    	id = cc_interfaces->dial_parent_id;
    	ast_channel_unlock(incoming);
    
    	AST_LIST_LOCK(interface_tree);
    	AST_LIST_TRAVERSE(interface_tree, monitor, next) {
    		if (monitor->id == id) {
    			break;
    		}
    	}
    
    	if (!monitor) {
    		AST_LIST_UNLOCK(interface_tree);
    		return;
    	}
    
    	extension_pvt = monitor->private_data;
    	if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
    		AST_LIST_UNLOCK(interface_tree);
    		return;
    	}
    	ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
    	ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
    	child_dialstring->is_valid = 1;
    	AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
    	AST_LIST_UNLOCK(interface_tree);
    }
    
    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)
    {
    	struct ast_cc_monitor *monitor_iter;
    	struct extension_monitor_pvt *extension_pvt;
    	struct extension_child_dialstring *child_dialstring;
    
    	AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
    		if (monitor_iter->id == parent_id) {
    			break;
    		}
    	}
    
    	if (!monitor_iter) {
    		return;
    	}
    	extension_pvt = monitor_iter->private_data;
    
    	AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
    		if (!strcmp(child_dialstring->device_name, device_name)) {
    			child_dialstring->is_valid = is_valid;
    			break;
    		}
    	}
    }
    
    /*!
     * \internal
     * \brief Allocate and initialize an "extension" interface for CC purposes
     *
     * When app_dial starts, this function is called in order to set up the
     * information about the extension in which this Dial is occurring. Any
     * devices dialed will have this particular cc_monitor as a parent.
     *
     * \param exten Extension from which Dial is occurring
     * \param context Context to which exten belongs
     * \param parent_id What should we set the parent_id of this interface to?
     * \retval NULL Memory allocation failure
     * \retval non-NULL The newly-created cc_monitor for the extension
     */
    static struct ast_cc_monitor *cc_extension_monitor_init(const char * const exten, const char * const context, const unsigned int parent_id)
    {
    	struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
    	struct ast_cc_interface *cc_interface;
    	struct ast_cc_monitor *monitor;
    
    	ast_str_set(&str, 0, "%s@%s", exten, context);
    
    	if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
    					"Allocating new ast_cc_interface"))) {
    		return NULL;
    	}
    
    	if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
    		cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
    		return NULL;
    	}
    
    	if (!(monitor->private_data = extension_monitor_pvt_init())) {
    		cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
    		cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
    	}
    
    	monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
    	monitor->parent_id = parent_id;
    	cc_interface->monitor_type = "extension";
    	cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
    	strcpy(cc_interface->device_name, ast_str_buffer(str));
    	monitor->interface = cc_interface;
    
    	ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %u and parent %u\n", cc_interface->device_name, monitor->id, monitor->parent_id);
    
    	return monitor;
    }
    
    /*!
     * \internal
     * \brief allocate dialed_cc_interfaces datastore and initialize fields
     *
     * This function is called when Situation 1 occurs in ast_cc_call_init.
     * See that function for more information on what Situation 1 is.
     *
     * In this particular case, we have to do a lot of memory allocation in order
     * to create the datastore, the data for the datastore, the tree of interfaces
     * that we'll be adding to, and the initial extension interface for this Dial
     * attempt.
     *
     * \param chan The channel onto which the datastore should be added.
     * \retval -1 An error occurred
     * \retval 0 Success
     */
    static int cc_interfaces_datastore_init(struct ast_channel *chan) {
    	struct dialed_cc_interfaces *interfaces;
    	struct ast_cc_monitor *monitor;
    	struct ast_datastore *dial_cc_datastore;
    
    	/*XXX This may be a bit controversial. In an attempt to not allocate
    	 * extra resources, I make sure that a future request will be within
    	 * limits. The problem here is that it is reasonable to think that
    	 * even if we're not within the limits at this point, we may be by
    	 * the time the requestor will have made his request. This may be
    	 * deleted at some point.
    	 */
    	if (!ast_cc_request_is_within_limits()) {
    		return 0;
    	}
    
    	if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
    		return -1;
    	}
    
    
    	if (!(monitor = cc_extension_monitor_init(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)), S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), 0))) {
    
    		ast_free(interfaces);
    		return -1;
    	}
    
    	if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
    		cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
    		ast_free(interfaces);
    		return -1;
    	}
    
    	if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
    					"Allocate monitor tree"))) {
    		ast_datastore_free(dial_cc_datastore);
    		cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
    		ast_free(interfaces);
    		return -1;
    	}
    
    	/* Finally, all that allocation is done... */
    	AST_LIST_HEAD_INIT(interfaces->interface_tree);
    	AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
    	cc_ref(monitor, "List's reference to extension monitor");
    	dial_cc_datastore->data = interfaces;
    	dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
    	interfaces->dial_parent_id = monitor->id;
    	interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
    	interfaces->is_original_caller = 1;
    	ast_channel_lock(chan);
    	ast_channel_datastore_add(chan, dial_cc_datastore);
    	ast_channel_unlock(chan);
    	cc_unref(monitor, "Unreffing allocation's reference");
    	return 0;
    }
    
    /*!
     * \internal
     * \brief  Call a monitor's destructor before the monitor has been allocated
     * \since 1.8
     *
     * \param monitor_type The type of monitor callbacks to use when calling the destructor
     * \param private_data Data allocated by a channel driver that must be freed
     *
     * \details
     * I'll admit, this is a bit evil.
     *
     * When a channel driver determines that it can offer a call completion service to
     * a caller, it is very likely that the channel driver will need to allocate some
     * data so that when the time comes to request CC, the channel driver will have the
     * necessary data at hand.
     *
     * The problem is that there are many places where failures may occur before the monitor
     * has been properly allocated and had its callbacks assigned to it. If one of these
     * failures should occur, then we still need to let the channel driver know that it
     * must destroy the data that it allocated.
     *
     * \return Nothing
     */
    static void call_destructor_with_no_monitor(const char * const monitor_type, void *private_data)
    {
    	const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
    
    	if (!monitor_callbacks) {
    		return;
    	}
    
    	monitor_callbacks->destructor(private_data);
    }
    
    /*!
     * \internal
     * \brief Allocate and intitialize a device cc_monitor
     *
     * For all intents and purposes, this is the same as
     * cc_extension_monitor_init, except that there is only
     * a single parameter used for naming the interface.
     *
     * This function is called when handling AST_CONTROL_CC frames.
     * The device has reported that CC is possible, so we add it
     * to the interface_tree.
     *
     * Note that it is not necessarily erroneous to add the same
     * device to the tree twice. If the same device is called by
     * two different extension during the same call, then
    
     * that is a legitimate situation.
    
     *
     * \param device_name The name of the device being added to the tree
     * \param dialstring The dialstring used to dial the device being added
     * \param parent_id The parent of this new tree node.
     * \retval NULL Memory allocation failure
     * \retval non-NULL The new ast_cc_interface created.
     */
    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)
    {
    	struct ast_cc_interface *cc_interface;
    	struct ast_cc_monitor *monitor;
    	size_t device_name_len = strlen(device_name);
    	int parent_id = cc_data->parent_interface_id;
    
    	if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
    					"Allocating new ast_cc_interface"))) {
    		return NULL;
    	}
    
    	if (!(cc_interface->config_params = ast_cc_config_params_init())) {
    		cc_unref(cc_interface, "Failed to allocate config params, unref interface");
    		return NULL;
    	}
    
    	if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
    		cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
    		return NULL;
    	}
    
    	if (!(monitor->dialstring = ast_strdup(dialstring))) {
    		cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
    		cc_unref(cc_interface, "Failed to copy dialable name");
    		return NULL;
    	}
    
    	if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
    		cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
    		cc_unref(cc_interface, "Failed to find monitor callbacks");
    		return NULL;
    	}
    
    	strcpy(cc_interface->device_name, device_name);
    	monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
    	monitor->parent_id = parent_id;
    	monitor->core_id = core_id;
    	monitor->service_offered = cc_data->service;
    	monitor->private_data = cc_data->private_data;
    	cc_interface->monitor_type = cc_data->monitor_type;
    	cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
    	monitor->interface = cc_interface;
    	monitor->available_timer_id = -1;
    	ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
    
    	ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %u and parent %u\n",
    
    			monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
    	return monitor;
    }
    
    /*!
     * \details
     * 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.
     */
    void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel *outbound, void *frame_data)
    {
    	char *device_name;
    	char *dialstring;
    	struct ast_cc_monitor *monitor;
    	struct ast_datastore *cc_datastore;
    	struct dialed_cc_interfaces *cc_interfaces;
    	struct cc_control_payload *cc_data = frame_data;
    	struct cc_core_instance *core_instance;
    
    	device_name = cc_data->device_name;
    	dialstring = cc_data->dialstring;
    
    	ast_channel_lock(inbound);
    	if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
    		ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
    		ast_channel_unlock(inbound);
    		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
    		return;
    	}
    
    	cc_interfaces = cc_datastore->data;
    
    	if (cc_interfaces->ignore) {
    		ast_channel_unlock(inbound);
    		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
    		return;
    	}
    
    	if (!cc_interfaces->is_original_caller) {
    		/* If the is_original_caller is not set on the *inbound* channel, then
    		 * it must be a local channel. As such, we do not want to create a core instance
    		 * or an agent for the local channel. Instead, we want to pass this along to the
    		 * other side of the local channel so that the original caller can benefit.
    		 */
    		ast_channel_unlock(inbound);
    		ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
    		return;
    	}
    
    	core_instance = find_cc_core_instance(cc_interfaces->core_id);
    	if (!core_instance) {
    		core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
    			cc_interfaces->core_id, cc_data);
    		if (!core_instance) {
    			cc_interfaces->ignore = 1;
    			ast_channel_unlock(inbound);
    			call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
    			return;
    		}
    	}
    
    	ast_channel_unlock(inbound);
    
    	/* Yeah this kind of sucks, but luckily most people
    	 * aren't dialing thousands of interfaces on every call
    	 *
    	 * This traversal helps us to not create duplicate monitors in
    	 * case a device queues multiple CC control frames.
    	 */
    	AST_LIST_LOCK(cc_interfaces->interface_tree);
    	AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
    		if (!strcmp(monitor->interface->device_name, device_name)) {
    			ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
    					core_instance->core_id, device_name);
    			AST_LIST_UNLOCK(cc_interfaces->interface_tree);
    			cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
    			call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
    			return;
    		}
    	}
    	AST_LIST_UNLOCK(cc_interfaces->interface_tree);
    
    	if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
    		ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
    		cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
    		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
    		return;
    	}
    
    	AST_LIST_LOCK(cc_interfaces->interface_tree);
    	cc_ref(monitor, "monitor tree's reference to the monitor");
    	AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
    	AST_LIST_UNLOCK(cc_interfaces->interface_tree);
    
    	cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
    
    
    	cc_publish_available(cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service));
    
    
    	cc_unref(core_instance, "Done with core_instance after handling CC control frame");
    	cc_unref(monitor, "Unref reference from allocating monitor");
    }
    
    int ast_cc_call_init(struct ast_channel *chan, int *ignore_cc)
    {
    	/* There are three situations to deal with here:
    	 *
    	 * 1. The channel does not have a dialed_cc_interfaces datastore on
    	 * it. This means that this is the first time that Dial has
    	 * been called. We need to create/initialize the datastore.
    	 *
    	 * 2. The channel does have a cc_interface datastore on it and
    	 * the "ignore" indicator is 0. This means that a Local channel
    	 * was called by a "parent" dial. We can check the datastore's
    	 * parent field to see who the root of this particular dial tree
    	 * is.
    	 *
    	 * 3. The channel does have a cc_interface datastore on it and
    	 * the "ignore" indicator is 1. This means that a second Dial call
    	 * is being made from an extension. In this case, we do not
    	 * want to make any additions/modifications to the datastore. We
    	 * will instead set a flag to indicate that CCSS is completely
    	 * disabled for this Dial attempt.
    	 */
    
    	struct ast_datastore *cc_interfaces_datastore;
    	struct dialed_cc_interfaces *interfaces;
    	struct ast_cc_monitor *monitor;
    	struct ast_cc_config_params *cc_params;
    
    	ast_channel_lock(chan);
    
    	cc_params = ast_channel_get_cc_config_params(chan);
    	if (!cc_params) {
    		ast_channel_unlock(chan);
    		return -1;
    	}
    	if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
    		/* We can't offer CC to this caller anyway, so don't bother with CC on this call
    		 */
    		*ignore_cc = 1;
    		ast_channel_unlock(chan);
    
    		ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", ast_channel_name(chan));
    
    		return 0;
    	}
    
    	if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
    		/* Situation 1 has occurred */
    		ast_channel_unlock(chan);
    		return cc_interfaces_datastore_init(chan);
    	}
    	interfaces = cc_interfaces_datastore->data;
    	ast_channel_unlock(chan);
    
    	if (interfaces->ignore) {
    		/* Situation 3 has occurred */
    		*ignore_cc = 1;
    		ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
    		return 0;
    	}
    
    	/* Situation 2 has occurred */
    
    	if (!(monitor = cc_extension_monitor_init(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)),
    			S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), interfaces->dial_parent_id))) {
    
    		return -1;
    	}
    	monitor->core_id = interfaces->core_id;
    	AST_LIST_LOCK(interfaces->interface_tree);
    	cc_ref(monitor, "monitor tree's reference to the monitor");
    	AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
    	AST_LIST_UNLOCK(interfaces->interface_tree);
    	interfaces->dial_parent_id = monitor->id;
    	cc_unref(monitor, "Unref monitor's allocation reference");
    	return 0;
    }
    
    int ast_cc_request_is_within_limits(void)
    {
    	return cc_request_count < global_cc_max_requests;
    }
    
    int ast_cc_get_current_core_id(struct ast_channel *chan)
    {
    	struct ast_datastore *datastore;
    	struct dialed_cc_interfaces *cc_interfaces;
    	int core_id_return;
    
    	ast_channel_lock(chan);
    	if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
    		ast_channel_unlock(chan);
    		return -1;
    	}
    
    	cc_interfaces = datastore->data;
    	core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
    	ast_channel_unlock(chan);
    	return core_id_return;
    
    }
    
    static long count_agents(const char * const caller, const int core_id_exception)
    {
    	struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
    
    	ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
    	ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
    	return data.count;
    }
    
    static void kill_duplicate_offers(char *caller)
    {
    	unsigned long match_flags = MATCH_NO_REQUEST;
    
    	struct ao2_iterator *dups_iter;
    
    	/*
    	 * Must remove the ref that was in cc_core_instances outside of
    	 * the container lock to prevent deadlock.
    	 */
    	dups_iter = ao2_t_callback_data(cc_core_instances, OBJ_MULTIPLE | OBJ_UNLINK,
    		match_agent, caller, &match_flags, "Killing duplicate offers");
    	if (dups_iter) {
    		/* Now actually unref any duplicate offers by simply destroying the iterator. */
    		ao2_iterator_destroy(dups_iter);
    	}
    
    }
    
    static void check_callback_sanity(const struct ast_cc_agent_callbacks *callbacks)
    {
    	ast_assert(callbacks->init != NULL);
    	ast_assert(callbacks->start_offer_timer != NULL);
    	ast_assert(callbacks->stop_offer_timer != NULL);
    
    	ast_assert(callbacks->respond != NULL);
    
    	ast_assert(callbacks->status_request != NULL);
    	ast_assert(callbacks->start_monitoring != NULL);
    	ast_assert(callbacks->callee_available != NULL);
    	ast_assert(callbacks->destructor != NULL);
    }
    
    static void agent_destroy(void *data)
    {
    	struct ast_cc_agent *agent = data;
    
    	if (agent->callbacks) {
    		agent->callbacks->destructor(agent);
    	}
    	ast_cc_config_params_destroy(agent->cc_params);
    }
    
    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)
    {
    	struct ast_cc_agent *agent;
    	struct ast_cc_config_params *cc_params;
    
    	if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
    					"Allocating new ast_cc_agent"))) {
    		return NULL;
    	}
    
    	agent->core_id = core_id;
    	strcpy(agent->device_name, caller_name);
    
    	cc_params = ast_channel_get_cc_config_params(caller_chan);
    	if (!cc_params) {
    		cc_unref(agent, "Could not get channel config params.");
    		return NULL;
    	}
    	if (!(agent->cc_params = ast_cc_config_params_init())) {
    		cc_unref(agent, "Could not init agent config params.");
    		return NULL;
    	}
    	ast_cc_copy_config_params(agent->cc_params, cc_params);
    
    	if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
    		cc_unref(agent, "Could not find agent callbacks.");
    		return NULL;
    	}
    	check_callback_sanity(agent->callbacks);
    
    	if (agent->callbacks->init(agent, caller_chan)) {
    		cc_unref(agent, "Agent init callback failed.");
    		return NULL;
    	}
    
    	ast_log_dynamic_level(cc_logger_level, "Core %u: Created an agent for caller %s\n",
    
    			agent->core_id, agent->device_name);
    	return agent;
    }
    
    /* Generic agent callbacks */
    static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
    static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent);
    static int cc_generic_agent_stop_offer_timer(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_status_request(struct ast_cc_agent *agent);
    static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent);
    static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent);
    static int cc_generic_agent_recall(struct ast_cc_agent *agent);
    static void cc_generic_agent_destructor(struct ast_cc_agent *agent);
    
    static struct ast_cc_agent_callbacks generic_agent_callbacks = {
    	.type = "generic",
    	.init = cc_generic_agent_init,
    	.start_offer_timer = cc_generic_agent_start_offer_timer,
    	.stop_offer_timer = cc_generic_agent_stop_offer_timer,
    
    	.respond = cc_generic_agent_respond,
    
    	.status_request = cc_generic_agent_status_request,
    	.stop_ringing = cc_generic_agent_stop_ringing,
    	.start_monitoring = cc_generic_agent_start_monitoring,
    	.callee_available = cc_generic_agent_recall,
    	.destructor = cc_generic_agent_destructor,
    };
    
    struct cc_generic_agent_pvt {
    	/*!
    	 * Subscription to device state
    	 *
    	 * Used in the CC_CALLER_BUSY state. The
    	 * generic agent will subscribe to the
    	 * device state of the caller in order to
    	 * determine when we may move on
    	 */
    
    	struct stasis_subscription *sub;
    
    	/*!
    	 * Scheduler id of offer timer.
    	 */
    	int offer_timer_id;
    	/*!
    	 * Caller ID number
    	 *
    	 * When we re-call the caller, we need
    	 * to provide this information to
    	 * ast_request_and_dial so that the
    	 * information will be present in the
    	 * call to the callee
    	 */
    	char cid_num[AST_CHANNEL_NAME];
    	/*!
    	 * Caller ID name
    	 *
    	 * See the description of cid_num.
    	 * The same applies here, except this
    	 * is the caller's name.
    	 */
    	char cid_name[AST_CHANNEL_NAME];
    	/*!
    	 * Extension dialed
    	 *
    	 * The original extension dialed. This is used
    	 * so that when performing a recall, we can
    	 * call the proper extension.
    	 */
    	char exten[AST_CHANNEL_NAME];
    	/*!
    	 * Context dialed
    	 *
    	 * The original context dialed. This is used
    	 * so that when performaing a recall, we can
    	 * call into the proper context
    	 */
    	char context[AST_CHANNEL_NAME];
    };
    
    static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
    {
    	struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
    
    	if (!generic_pvt) {
    		return -1;
    	}
    
    	generic_pvt->offer_timer_id = -1;
    
    	if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
    		ast_copy_string(generic_pvt->cid_num, ast_channel_caller(chan)->id.number.str, sizeof(generic_pvt->cid_num));
    
    	if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
    		ast_copy_string(generic_pvt->cid_name, ast_channel_caller(chan)->id.name.str, sizeof(generic_pvt->cid_name));
    
    	ast_copy_string(generic_pvt->exten, S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)), sizeof(generic_pvt->exten));
    	ast_copy_string(generic_pvt->context, S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)), sizeof(generic_pvt->context));
    
    	agent->private_data = generic_pvt;
    	ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
    	return 0;
    }
    
    static int offer_timer_expire(const void *data)
    {
    
    	struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
    
    	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
    
    	ast_log_dynamic_level(cc_logger_level, "Core %u: Queuing change request because offer timer has expired.\n",
    
    			agent->core_id);
    	agent_pvt->offer_timer_id = -1;
    	ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
    
    	cc_unref(agent, "Remove scheduler's reference to the agent");
    
    	return 0;
    }
    
    static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent)
    {
    	int when;
    	int sched_id;
    	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
    
    
    	ast_assert(cc_sched_context != NULL);
    
    	ast_assert(agent->cc_params != NULL);
    
    	when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
    
    	ast_log_dynamic_level(cc_logger_level, "Core %u: About to schedule offer timer expiration for %d ms\n",
    
    			agent->core_id, when);
    
    	if ((sched_id = ast_sched_add(cc_sched_context, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
    
    		return -1;
    	}
    	generic_pvt->offer_timer_id = sched_id;
    	return 0;
    }
    
    static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent)
    {
    	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
    
    	if (generic_pvt->offer_timer_id != -1) {
    
    		if (!ast_sched_del(cc_sched_context, generic_pvt->offer_timer_id)) {
    
    			cc_unref(agent, "Remove scheduler's reference to the agent");
    		}
    		generic_pvt->offer_timer_id = -1;
    	}
    	return 0;
    }
    
    
    static void cc_generic_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
    
    {
    	/* The generic agent doesn't have to do anything special to
    	 * acknowledge a CC request. Just return.
    	 */
    	return;
    }
    
    static int cc_generic_agent_status_request(struct ast_cc_agent *agent)
    {
    	ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
    	return 0;
    }
    
    static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent)
    {
    	struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
    
    	if (!recall_chan) {
    		return 0;
    	}
    
    	ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
    	return 0;
    }
    
    
    static void generic_agent_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
    
    	struct ast_cc_agent *agent = userdata;
    	enum ast_device_state new_state;
    	struct ast_device_state_message *dev_state;
    
    	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
    
    
    	if (stasis_subscription_final_message(sub, msg)) {
    		cc_unref(agent, "Done holding ref for subscription");
    		return;
    	} else if (ast_device_state_message_type() != stasis_message_type(msg)) {
    		return;
    
    	dev_state = stasis_message_data(msg);
    	if (dev_state->eid) {
    		/* ignore non-aggregate states */
    		return;
    	}
    
    	new_state = dev_state->state;
    
    	if (!cc_generic_is_device_available(new_state)) {
    		/* Not interested in this new state of the device.  It is still busy. */
    		return;
    	}
    
    	generic_pvt->sub = stasis_unsubscribe(sub);
    
    	ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
    }
    
    static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
    {
    	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
    	struct ast_str *str = ast_str_alloca(128);
    
    	struct stasis_topic *device_specific_topic;
    
    
    	ast_assert(generic_pvt->sub == NULL);
    
    	ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
    		agent->device_name);
    
    	device_specific_topic = ast_device_state_topic(agent->device_name);
    	if (!device_specific_topic) {
    		return -1;
    	}
    
    	if (!(generic_pvt->sub = stasis_subscribe(device_specific_topic, generic_agent_devstate_cb, agent))) {
    
    	cc_ref(agent, "Ref agent for subscription");
    
    	return 0;
    }
    
    static void *generic_recall(void *data)
    {
    	struct ast_cc_agent *agent = data;
    	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
    	const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
    	const char *tech;
    	char *target;
    	int reason;
    	struct ast_channel *chan;
    	const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
    
    	const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params);
    
    	unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
    
    	struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
    
    
    	tech = interface;
    	if ((target = strchr(interface, '/'))) {
    		*target++ = '\0';
    	}
    
    	ast_format_cap_append(tmp_cap, ast_format_slin, 0);
    
    	if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
    
    		/* Hmm, no channel. Sucks for you, bud.
    		 */
    
    		ast_log_dynamic_level(cc_logger_level, "Core %u: Failed to call back %s for reason %d\n",
    
    				agent->core_id, agent->device_name, reason);
    		ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
    
    	/* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
    	 * This will be a common task for all recall functions. If it were possible, I'd have
    	 * the core do it automatically, but alas I cannot. Instead, I will provide a public
    	 * function to do so.
    	 */
    	ast_setup_cc_recall_datastore(chan, agent->core_id);
    	ast_cc_agent_set_interfaces_chanvar(chan);
    
    
    	ast_channel_exten_set(chan, generic_pvt->exten);
    	ast_channel_context_set(chan, generic_pvt->context);
    
    	ast_channel_priority_set(chan, 1);
    
    	pbx_builtin_setvar_helper(chan, "CC_EXTEN", generic_pvt->exten);
    	pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);
    
    
    	if (!ast_strlen_zero(callback_macro)) {
    
    		ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback macro configured for agent %s\n",
    
    				agent->core_id, agent->device_name);
    
    		if (ast_app_exec_macro(NULL, chan, callback_macro)) {
    
    			ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
    			ast_hangup(chan);
    			return NULL;
    		}
    	}
    
    
    	if (!ast_strlen_zero(callback_sub)) {
    
    		ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback subroutine configured for agent %s\n",
    
    				agent->core_id, agent->device_name);
    
    		if (ast_app_exec_sub(NULL, chan, callback_sub, 0)) {
    
    			ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name);
    			ast_hangup(chan);
    			return NULL;
    		}
    	}
    
    	if (ast_pbx_start(chan)) {
    		ast_cc_failed(agent->core_id, "PBX failed to start for %s.", agent->device_name);
    		ast_hangup(chan);
    		return NULL;
    	}
    	ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling",
    		agent->device_name);
    
    	return NULL;
    }
    
    static int cc_generic_agent_recall(struct ast_cc_agent *agent)
    {
    	pthread_t clotho;
    	enum ast_device_state current_state = ast_device_state(agent->device_name);
    
    
    	if (!cc_generic_is_device_available(current_state)) {
    
    		/* We can't try to contact the device right now because he's not available
    		 * Let the core know he's busy.
    		 */
    		ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
    		return 0;
    	}
    	ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
    	return 0;
    }
    
    static void cc_generic_agent_destructor(struct ast_cc_agent *agent)
    {
    	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
    
    	if (!agent_pvt) {
    		/* The agent constructor probably failed. */
    		return;
    	}
    
    	cc_generic_agent_stop_offer_timer(agent);
    	if (agent_pvt->sub) {
    
    		agent_pvt->sub = stasis_unsubscribe(agent_pvt->sub);
    
    	}
    
    	ast_free(agent_pvt);
    }
    
    static void cc_core_instance_destructor(void *data)
    {
    	struct cc_core_instance *core_instance = data;
    	ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
    	if (core_instance->agent) {
    		cc_unref(core_instance->agent, "Core instance is done with the agent now");
    	}
    	if (core_instance->monitors) {
    		core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
    	}
    }
    
    static 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)
    {
    	char caller[AST_CHANNEL_NAME];
    	struct cc_core_instance *core_instance;
    	struct ast_cc_config_params *cc_params;
    	long agent_count;
    	int recall_core_id;
    
    	ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
    	cc_params = ast_channel_get_cc_config_params(caller_chan);
    	if (!cc_params) {
    		ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
    			caller);
    		return NULL;
    	}
    	/* First, we need to kill off other pending CC offers from caller. If the caller is going
    	 * to request a CC service, it may only be for the latest call he made.
    	 */
    	if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
    		kill_duplicate_offers(caller);
    	}
    
    	ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
    	agent_count = count_agents(caller, recall_core_id);
    	if (agent_count >= ast_get_cc_max_agents(cc_params)) {
    		ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
    		return NULL;
    	}
    
    	/* Generic agents can only have a single outstanding CC request per caller. */
    	if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
    		ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
    		return NULL;
    	}
    
    	/* Next, we need to create the core instance for this call */
    	if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
    		return NULL;
    	}
    
    	core_instance->core_id = core_id;
    	if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
    		cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
    		return NULL;
    	}
    
    	core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");