Skip to content
Snippets Groups Projects
channel.c 328 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ast_free(doomed->number.str);
    	doomed->number.str = NULL;
    	ast_party_subaddress_free(&doomed->subaddress);
    }
    
    void ast_party_caller_init(struct ast_party_caller *init)
    {
    	ast_party_id_init(&init->id);
    
    	ast_party_id_init(&init->ani);
    
    	init->ani2 = 0;
    }
    
    void ast_party_caller_copy(struct ast_party_caller *dest, const struct ast_party_caller *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    
    	ast_party_id_copy(&dest->id, &src->id);
    
    	ast_party_id_copy(&dest->ani, &src->ani);
    
    	ast_party_id_copy(&dest->priv, &src->priv);
    
    	dest->ani2 = src->ani2;
    }
    
    void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
    {
    	ast_party_id_set_init(&init->id, &guide->id);
    
    	ast_party_id_set_init(&init->ani, &guide->ani);
    
    	ast_party_id_set_init(&init->priv, &guide->priv);
    
    	init->ani2 = guide->ani2;
    }
    
    void ast_party_caller_set(struct ast_party_caller *dest, const struct ast_party_caller *src, const struct ast_set_party_caller *update)
    {
    	ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL);
    
    	ast_party_id_set(&dest->ani, &src->ani, update ? &update->ani : NULL);
    
    	ast_party_id_set(&dest->priv, &src->priv, update ? &update->priv : NULL);
    
    }
    
    void ast_party_caller_free(struct ast_party_caller *doomed)
    {
    	ast_party_id_free(&doomed->id);
    
    	ast_party_id_free(&doomed->ani);
    
    }
    
    void ast_party_connected_line_init(struct ast_party_connected_line *init)
    {
    	ast_party_id_init(&init->id);
    
    	ast_party_id_init(&init->ani);
    
    	init->ani2 = 0;
    	init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
    }
    
    void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    	}
    
    	ast_party_id_copy(&dest->id, &src->id);
    
    	ast_party_id_copy(&dest->ani, &src->ani);
    
    	ast_party_id_copy(&dest->priv, &src->priv);
    
    	dest->ani2 = src->ani2;
    	dest->source = src->source;
    }
    
    void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
    {
    	ast_party_id_set_init(&init->id, &guide->id);
    
    	ast_party_id_set_init(&init->ani, &guide->ani);
    
    	ast_party_id_set_init(&init->priv, &guide->priv);
    
    	init->ani2 = guide->ani2;
    	init->source = guide->source;
    }
    
    
    void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
    
    	ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL);
    
    	ast_party_id_set(&dest->ani, &src->ani, update ? &update->ani : NULL);
    
    	ast_party_id_set(&dest->priv, &src->priv, update ? &update->priv : NULL);
    
    void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_party_caller *caller)
    
    	connected->id = caller->id;
    	connected->ani = caller->ani;
    
    	connected->ani2 = caller->ani2;
    
    	connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
    }
    
    void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
    {
    	ast_party_id_free(&doomed->id);
    
    	ast_party_id_free(&doomed->ani);
    
    void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init)
    {
    	init->str = NULL;
    	init->code = AST_REDIRECTING_REASON_UNKNOWN;
    }
    
    void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
    {
    	if (dest == src) {
    		return;
    	}
    
    	ast_free(dest->str);
    	dest->str = ast_strdup(src->str);
    	dest->code = src->code;
    }
    
    void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init, const struct ast_party_redirecting_reason *guide)
    {
    	init->str = NULL;
    	init->code = guide->code;
    }
    
    void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
    {
    	if (dest == src) {
    		return;
    	}
    
    	if (src->str && src->str != dest->str) {
    		ast_free(dest->str);
    		dest->str = ast_strdup(src->str);
    	}
    
    	dest->code = src->code;
    }
    
    void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed)
    {
    	ast_free(doomed->str);
    }
    
    
    
    void ast_party_redirecting_init(struct ast_party_redirecting *init)
    {
    
    	ast_party_id_init(&init->orig);
    
    	ast_party_id_init(&init->from);
    	ast_party_id_init(&init->to);
    
    	ast_party_id_init(&init->priv_orig);
    	ast_party_id_init(&init->priv_from);
    	ast_party_id_init(&init->priv_to);
    
    	ast_party_redirecting_reason_init(&init->reason);
    	ast_party_redirecting_reason_init(&init->orig_reason);
    
    	init->count = 0;
    
    }
    
    void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    	}
    
    
    	ast_party_id_copy(&dest->orig, &src->orig);
    
    	ast_party_id_copy(&dest->from, &src->from);
    	ast_party_id_copy(&dest->to, &src->to);
    
    	ast_party_id_copy(&dest->priv_orig, &src->priv_orig);
    	ast_party_id_copy(&dest->priv_from, &src->priv_from);
    	ast_party_id_copy(&dest->priv_to, &src->priv_to);
    
    	ast_party_redirecting_reason_copy(&dest->reason, &src->reason);
    	ast_party_redirecting_reason_copy(&dest->orig_reason, &src->orig_reason);
    
    	dest->count = src->count;
    }
    
    void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
    {
    
    	ast_party_id_set_init(&init->orig, &guide->orig);
    
    	ast_party_id_set_init(&init->from, &guide->from);
    	ast_party_id_set_init(&init->to, &guide->to);
    
    	ast_party_id_set_init(&init->priv_orig, &guide->priv_orig);
    	ast_party_id_set_init(&init->priv_from, &guide->priv_from);
    	ast_party_id_set_init(&init->priv_to, &guide->priv_to);
    
    	ast_party_redirecting_reason_set_init(&init->reason, &guide->reason);
    	ast_party_redirecting_reason_set_init(&init->orig_reason, &guide->orig_reason);
    
    void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src, const struct ast_set_party_redirecting *update)
    {
    
    	ast_party_id_set(&dest->orig, &src->orig, update ? &update->orig : NULL);
    
    	ast_party_id_set(&dest->from, &src->from, update ? &update->from : NULL);
    	ast_party_id_set(&dest->to, &src->to, update ? &update->to : NULL);
    
    	ast_party_id_set(&dest->priv_orig, &src->priv_orig, update ? &update->priv_orig : NULL);
    	ast_party_id_set(&dest->priv_from, &src->priv_from, update ? &update->priv_from : NULL);
    	ast_party_id_set(&dest->priv_to, &src->priv_to, update ? &update->priv_to : NULL);
    
    	ast_party_redirecting_reason_set(&dest->reason, &src->reason);
    	ast_party_redirecting_reason_set(&dest->orig_reason, &src->orig_reason);
    
    	dest->count = src->count;
    }
    
    
    void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
    {
    
    	ast_party_id_free(&doomed->orig);
    
    	ast_party_id_free(&doomed->from);
    	ast_party_id_free(&doomed->to);
    
    	ast_party_id_free(&doomed->priv_orig);
    	ast_party_id_free(&doomed->priv_from);
    	ast_party_id_free(&doomed->priv_to);
    
    	ast_party_redirecting_reason_free(&doomed->reason);
    	ast_party_redirecting_reason_free(&doomed->orig_reason);
    
    /*! \brief Free a channel structure */
    
    static void ast_channel_destructor(void *obj)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_var_t *vardata;
    
    	struct ast_frame *f;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct varshead *headp;
    
    	struct ast_datastore *datastore;
    	char device_name[AST_CHANNEL_NAME];
    
    	ast_debug(1, "Channel %p '%s' destroying\n", chan, ast_channel_name(chan));
    
    
    	/* Stop monitoring */
    	if (ast_channel_monitor(chan)) {
    		ast_channel_monitor(chan)->stop(chan, 0);
    	}
    
    	/* If there is native format music-on-hold state, free it */
    	if (ast_channel_music_state(chan)) {
    		ast_moh_cleanup(chan);
    	}
    
    	ast_pbx_hangup_handler_destroy(chan);
    
    	/* Things that may possibly raise Stasis messages shouldn't occur after this point */
    
    	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEAD);
    
    
    	if (ast_channel_internal_is_finalized(chan)) {
    		/* A channel snapshot should not be in the process of being staged now. */
    		ast_assert(!ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE));
    
    		ast_channel_lock(chan);
    		ast_channel_publish_snapshot(chan);
    		ast_channel_unlock(chan);
    		publish_cache_clear(chan);
    	}
    
    	ast_channel_lock(chan);
    
    
    	/* Get rid of each of the data stores on the channel */
    
    	while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry)))
    
    		/* Free the data store */
    
    
    	/* While the channel is locked, take the reference to its callid while we tear down the call. */
    	callid = ast_channel_callid(chan);
    	ast_channel_callid_cleanup(chan);
    
    
    	ast_channel_unlock(chan);
    
    
    	/* Lock and unlock the channel just to be sure nobody has it locked still
    	   due to a reference that was stored in a datastore. (i.e. app_chanspy) */
    	ast_channel_lock(chan);
    	ast_channel_unlock(chan);
    
    
    	if (ast_channel_tech_pvt(chan)) {
    
    		ast_log_callid(LOG_WARNING, callid, "Channel '%s' may not have been hung up properly\n", ast_channel_name(chan));
    
    		ast_free(ast_channel_tech_pvt(chan));
    
    	if (ast_channel_sched(chan)) {
    		ast_sched_context_destroy(ast_channel_sched(chan));
    
    	if (ast_channel_internal_is_finalized(chan)) {
    
    		ast_copy_string(device_name, ast_channel_name(chan), sizeof(device_name));
    
    		if ((dashptr = strrchr(device_name, '-'))) {
    			*dashptr = '\0';
    		}
    	} else {
    		device_name[0] = '\0';
    
    	if (ast_channel_readtrans(chan))
    		ast_translator_free_path(ast_channel_readtrans(chan));
    	if (ast_channel_writetrans(chan))
    		ast_translator_free_path(ast_channel_writetrans(chan));
    	if (ast_channel_pbx(chan))
    
    		ast_log_callid(LOG_WARNING, callid, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan));
    
    	/* Free formats */
    	ast_channel_set_oldwriteformat(chan, NULL);
    	ast_channel_set_rawreadformat(chan, NULL);
    	ast_channel_set_rawwriteformat(chan, NULL);
    	ast_channel_set_readformat(chan, NULL);
    	ast_channel_set_writeformat(chan, NULL);
    
    
    	ast_party_dialed_free(ast_channel_dialed(chan));
    	ast_party_caller_free(ast_channel_caller(chan));
    	ast_party_connected_line_free(ast_channel_connected(chan));
    
    	ast_party_connected_line_free(ast_channel_connected_indicated(chan));
    
    	ast_party_redirecting_free(ast_channel_redirecting(chan));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Close pipes if appropriate */
    
    	ast_channel_internal_alertpipe_close(chan);
    
    	if (ast_channel_timer(chan)) {
    		ast_timer_close(ast_channel_timer(chan));
    
    #ifdef HAVE_EPOLL
    	for (i = 0; i < AST_MAX_FDS; i++) {
    
    		if (ast_channel_internal_epfd_data(chan, i)) {
    			ast_free(ast_channel_internal_epfd_data(chan, i));
    		}
    
    	close(ast_channel_epfd(chan));
    
    	while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list)))
    
    		ast_frfree(f);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* loop over the variables list, freeing all data and deleting list items */
    	/* no need to lock the list, as the channel is already locked */
    
    	headp = ast_channel_varshead(chan);
    
    	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
    		ast_var_delete(vardata);
    
    	ast_app_group_discard(chan);
    
    
    	if (ast_channel_cdr(chan)) {
    
    		ast_cdr_free(ast_channel_cdr(chan));
    
    		ast_channel_cdr_set(chan, NULL);
    
    	if (ast_channel_zone(chan)) {
    		ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
    
    	ast_channel_internal_cleanup(chan);
    
    	if (device_name[0]) {
    		/*
    		 * We have a device name to notify of a new state.
    		 *
    		 * Queue an unknown state, because, while we know that this particular
    		 * instance is dead, we don't know the state of all other possible
    		 * instances.
    		 */
    
    		ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
    
    	ast_channel_nativeformats_set(chan, NULL);
    
    
    	ast_channel_named_callgroups_set(chan, NULL);
    	ast_channel_named_pickupgroups_set(chan, NULL);
    
    
    	ast_atomic_fetchadd_int(&chancount, -1);
    
    /*! \brief Free a dummy channel structure */
    static void ast_dummy_channel_destructor(void *obj)
    {
    	struct ast_channel *chan = obj;
    
    	struct ast_var_t *vardata;
    	struct varshead *headp;
    
    
    	ast_pbx_hangup_handler_destroy(chan);
    
    	/* Get rid of each of the data stores on the channel */
    	while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
    		/* Free the data store */
    		ast_datastore_free(datastore);
    	}
    
    	ast_party_dialed_free(ast_channel_dialed(chan));
    	ast_party_caller_free(ast_channel_caller(chan));
    	ast_party_connected_line_free(ast_channel_connected(chan));
    
    	ast_party_connected_line_free(ast_channel_connected_indicated(chan));
    
    	ast_party_redirecting_free(ast_channel_redirecting(chan));
    
    
    	/* loop over the variables list, freeing all data and deleting list items */
    	/* no need to lock the list, as the channel is already locked */
    
    	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
    		ast_var_delete(vardata);
    
    
    	if (ast_channel_cdr(chan)) {
    
    		ast_cdr_free(ast_channel_cdr(chan));
    
    		ast_channel_cdr_set(chan, NULL);
    
    	ast_channel_internal_cleanup(chan);
    
    struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
    
    }
    
    int ast_channel_datastore_free(struct ast_datastore *datastore)
    {
    
    int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
    {
    	struct ast_datastore *datastore = NULL, *datastore2;
    
    
    	AST_LIST_TRAVERSE(ast_channel_datastores(from), datastore, entry) {
    
    			datastore2 = ast_datastore_alloc(datastore->info, datastore->uid);
    
    				datastore2->data = datastore->info->duplicate ? datastore->info->duplicate(datastore->data) : NULL;
    
    				datastore2->inheritance = datastore->inheritance == DATASTORE_INHERIT_FOREVER ? DATASTORE_INHERIT_FOREVER : datastore->inheritance - 1;
    
    				AST_LIST_INSERT_TAIL(ast_channel_datastores(to), datastore2, entry);
    
    int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
    {
    	int res = 0;
    
    
    	AST_LIST_INSERT_HEAD(ast_channel_datastores(chan), datastore, entry);
    
    
    	return res;
    }
    
    int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
    {
    
    	return AST_LIST_REMOVE(ast_channel_datastores(chan), datastore, entry) ? 0 : -1;
    
    struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
    
    	AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
    
    		if (datastore->info != info) {
    			continue;
    		}
    
    		if (uid == NULL) {
    			/* matched by type only */
    			break;
    		}
    
    		if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
    			/* Matched by type AND uid */
    			break;
    
    /*! Set the file descriptor on the channel */
    void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
    {
    #ifdef HAVE_EPOLL
    	struct epoll_event ev;
    	struct ast_epoll_data *aed = NULL;
    
    
    	if (ast_channel_fd_isset(chan, which)) {
    		epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev);
    		aed = ast_channel_internal_epfd_data(chan, which);
    
    	}
    
    	/* If this new fd is valid, add it to the epoll */
    	if (fd > -1) {
    		if (!aed && (!(aed = ast_calloc(1, sizeof(*aed)))))
    			return;
    
    		ast_channel_internal_epfd_data_set(chan, which, aed);
    
    		ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
    		ev.data.ptr = aed;
    
    		epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev);
    
    	} else if (aed) {
    		/* We don't have to keep around this epoll data structure now */
    
    		ast_free(aed);
    		ast_channel_epfd_data_set(chan, which, NULL);
    
    	ast_channel_internal_fd_set(chan, which, fd);
    
    	return;
    }
    
    /*! Add a channel to an optimized waitfor */
    void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
    {
    #ifdef HAVE_EPOLL
    	struct epoll_event ev;
    	int i = 0;
    
    
    	if (ast_channel_epfd(chan0) == -1)
    
    		return;
    
    	/* Iterate through the file descriptors on chan1, adding them to chan0 */
    	for (i = 0; i < AST_MAX_FDS; i++) {
    
    		if (!ast_channel_fd_isset(chan1, i)) {
    
    		ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
    
    		ev.data.ptr = ast_channel_internal_epfd_data(chan1, i);
    		epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, i), &ev);
    
    	}
    
    #endif
    	return;
    }
    
    /*! Delete a channel from an optimized waitfor */
    void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
    {
    #ifdef HAVE_EPOLL
    	struct epoll_event ev;
    	int i = 0;
    
    
    	if (ast_channel_epfd(chan0) == -1)
    
    		if (!ast_channel_fd_isset(chan1, i)) {
    
    		}
    		epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev);
    
    void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
    {
    	ast_channel_lock(chan);
    
    
    	ast_channel_softhangup_internal_flag_clear(chan, flag);
    
    	if (!ast_channel_softhangup_internal_flag(chan)) {
    
    		struct ast_frame *fr;
    
    		/* If we have completely cleared the softhangup flag,
    		 * then we need to fully abort the hangup process.  This requires
    		 * pulling the END_OF_Q frame out of the channel frame queue if it
    		 * still happens to be there. */
    
    
    		fr = AST_LIST_LAST(ast_channel_readq(chan));
    
    		if (fr && fr->frametype == AST_FRAME_CONTROL &&
    				fr->subclass.integer == AST_CONTROL_END_OF_Q) {
    
    			AST_LIST_REMOVE(ast_channel_readq(chan), fr, frame_list);
    
    			ast_frfree(fr);
    		}
    	}
    
    	ast_channel_unlock(chan);
    }
    
    
    /*! \brief Softly hangup a channel, don't lock */
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_softhangup_nolock(struct ast_channel *chan, int cause)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	ast_debug(1, "Soft-Hanging (%#04x) up channel '%s'\n", (unsigned)cause, ast_channel_name(chan));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Inform channel driver that we need to be hung up, if it cares */
    
    	ast_channel_softhangup_internal_flag_add(chan, cause);
    
    	ast_queue_frame(chan, &ast_null_frame);
    
    	/* Interrupt any poll call or such */
    
    	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING))
    		pthread_kill(ast_channel_blocker(chan), SIGURG);
    
    /*! \brief Softly hangup a channel, lock */
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_softhangup(struct ast_channel *chan, int cause)
    {
    
    	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    
    	ast_channel_lock(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	res = ast_softhangup_nolock(chan, cause);
    
    	blob = ast_json_pack("{s: i, s: b}",
    
    	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), blob);
    
    	ast_channel_unlock(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    static void free_translation(struct ast_channel *clonechan)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (ast_channel_writetrans(clonechan)) {
    
    		ast_translator_free_path(ast_channel_writetrans(clonechan));
    
    		ast_translator_free_path(ast_channel_readtrans(clonechan));
    
    	ast_channel_writetrans_set(clonechan, NULL);
    	ast_channel_readtrans_set(clonechan, NULL);
    
    void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
    {
    
    	RAII_VAR(struct ast_channel *, bridge, ast_channel_bridge_peer(chan), ast_channel_cleanup);
    
    	if (force || ast_strlen_zero(ast_channel_hangupsource(chan))) {
    		ast_channel_hangupsource_set(chan, source);
    
    		ast_channel_lock(bridge);
    
    		if (force || ast_strlen_zero(ast_channel_hangupsource(bridge))) {
    			ast_channel_hangupsource_set(bridge, source);
    		}
    
    int ast_channel_has_audio_frame_or_monitor(struct ast_channel *chan)
    {
    	return ast_channel_monitor(chan)
    
    Richard Mudgett's avatar
    Richard Mudgett committed
    		|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
    
    		|| !ast_framehook_list_contains_no_active(ast_channel_framehooks(chan));
    }
    
    
    int ast_channel_has_hook_requiring_audio(struct ast_channel *chan)
    {
    	return ast_channel_monitor(chan)
    		|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
    		|| !ast_framehook_list_contains_no_active_of_type(ast_channel_framehooks(chan), AST_FRAME_VOICE);
    }
    
    
    static void destroy_hooks(struct ast_channel *chan)
    {
    
    	if (ast_channel_audiohooks(chan)) {
    		ast_audiohook_detach_list(ast_channel_audiohooks(chan));
    		ast_channel_audiohooks_set(chan, NULL);
    
    /*! \brief Hangup a channel */
    
    void ast_hangup(struct ast_channel *chan)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	/* Be NULL safe for RAII_VAR() usage. */
    	if (!chan) {
    		return;
    	}
    
    
    	ast_debug(1, "Channel %p '%s' hanging up.  Refs: %d\n", chan, ast_channel_name(chan),
    		ao2_ref(chan, 0));
    
    
    	ast_autoservice_stop(chan);
    
    
    	ast_channel_lock(chan);
    
    	while (ast_channel_masq(chan) || ast_channel_masqr(chan))  {
    		CHANNEL_DEADLOCK_AVOIDANCE(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* Mark as a zombie so a masquerade cannot be setup on this channel. */
    
    	ast_set_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE);
    
    
    	/*
    	 * XXX if running the hangup handlers here causes problems
    	 * because the handlers take too long to execute, we could move
    	 * the meat of this function into another thread.  A thread
    	 * where channels go to die.
    	 *
    	 * If this is done, ast_autoservice_chan_hangup_peer() will no
    	 * longer be needed.
    	 */
    	ast_pbx_hangup_handler_run(chan);
    
    	ao2_unlink(channels, chan);
    
    	ast_channel_lock(chan);
    
    	destroy_hooks(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	free_translation(chan);
    
    	/* Close audio stream */
    
    	if (ast_channel_stream(chan)) {
    		ast_closestream(ast_channel_stream(chan));
    		ast_channel_stream_set(chan, NULL);
    
    	}
    	/* Close video stream */
    
    	if (ast_channel_vstream(chan)) {
    		ast_closestream(ast_channel_vstream(chan));
    		ast_channel_vstream_set(chan, NULL);
    
    	if (ast_channel_sched(chan)) {
    		ast_sched_context_destroy(ast_channel_sched(chan));
    		ast_channel_sched_set(chan, NULL);
    
    	if (ast_channel_generatordata(chan)) {	/* Clear any tone stuff remaining */
    		if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) {
    			ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan));
    
    	ast_channel_generatordata_set(chan, NULL);
    	ast_channel_generator_set(chan, NULL);
    
    	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
    
    			"is blocked by thread %ld in procedure %s!  Expect a failure\n",
    
    			(long) pthread_self(), ast_channel_name(chan), (long)ast_channel_blocker(chan), ast_channel_blockproc(chan));
    		ast_assert(ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING) == 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (ast_channel_tech(chan)->hangup) {
    		ast_channel_tech(chan)->hangup(chan);
    
    	ast_channel_unlock(chan);
    
    	ast_cc_offer(chan);
    
    	ast_channel_unref(chan);
    
    /*!
     * \internal
     * \brief Set channel answered time if not already set.
     * \since 13.11.0
     *
     * \param chan Channel to set answered time.
     *
     * \return Nothing
     */
    static void set_channel_answer_time(struct ast_channel *chan)
    {
    	if (ast_tvzero(ast_channel_answertime(chan))) {
    		struct timeval answertime;
    
    		answertime = ast_tvnow();
    		ast_channel_answertime_set(chan, &answertime);
    	}
    }
    
    
    int ast_raw_answer(struct ast_channel *chan)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    	ast_channel_lock(chan);
    
    	/* You can't answer an outbound call */
    
    	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING)) {
    
    		ast_channel_unlock(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Stop if we're a zombie or need a soft hangup */
    
    	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
    
    		ast_channel_unlock(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    	/*
    	 * Mark when incoming channel answered so we can know how
    	 * long the channel has been up.
    	 */
    	set_channel_answer_time(chan);
    
    	switch (ast_channel_state(chan)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_STATE_RINGING:
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_STATE_RING:
    
    		if (ast_channel_tech(chan)->answer) {
    			res = ast_channel_tech(chan)->answer(chan);
    
    		ast_setstate(chan, AST_STATE_UP);
    
    		break;
    	case AST_STATE_UP:
    		break;
    	default:
    		break;
    	}
    
    	ast_indicate(chan, -1);
    
    	return res;
    }
    
    
    int __ast_answer(struct ast_channel *chan, unsigned int delay)
    
    {
    	int res = 0;
    	enum ast_channel_state old_state;
    
    
    	old_state = ast_channel_state(chan);
    
    	if ((res = ast_raw_answer(chan))) {
    
    		return res;
    	}
    
    	switch (old_state) {
    	case AST_STATE_RINGING:
    	case AST_STATE_RING:
    		/* wait for media to start flowing, but don't wait any longer
    		 * than 'delay' or 500 milliseconds, whichever is longer
    		 */
    		do {
    			AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
    
    			struct ast_frame *cur;
    			struct ast_frame *new_frame;
    
    			int timeout_ms = MAX(delay, 500);
    
    			struct timeval start;
    
    			start = ast_tvnow();
    
    				int ms = ast_remaining_ms(start, timeout_ms);
    
    				ms = ast_waitfor(chan, ms);
    				if (ms < 0) {
    
    					ast_log(LOG_WARNING, "Error condition occurred when polling channel %s for a voice frame: %s\n", ast_channel_name(chan), strerror(errno));
    
    					ast_debug(2, "Didn't receive a media frame from %s within %u ms of answering. Continuing anyway\n", ast_channel_name(chan), MAX(delay, 500));
    
    				cur = ast_read(chan);
    				if (!cur || ((cur->frametype == AST_FRAME_CONTROL) &&
    
    					     (cur->subclass.integer == AST_CONTROL_HANGUP))) {
    
    					ast_debug(2, "Hangup of channel %s detected in answer routine\n", ast_channel_name(chan));
    
    				if ((new_frame = ast_frisolate(cur)) != cur) {
    
    				AST_LIST_INSERT_HEAD(&frames, new_frame, frame_list);
    
    
    				/* if a specific delay period was requested, continue
    				 * until that delay has passed. don't stop just because
    				 * incoming media has arrived.
    				 */
    				if (delay) {
    					continue;
    				}
    
    
    				switch (new_frame->frametype) {
    
    					/* all of these frametypes qualify as 'media' */
    				case AST_FRAME_VOICE:
    				case AST_FRAME_VIDEO:
    				case AST_FRAME_TEXT:
    				case AST_FRAME_DTMF_BEGIN:
    				case AST_FRAME_DTMF_END:
    				case AST_FRAME_IMAGE:
    				case AST_FRAME_HTML:
    				case AST_FRAME_MODEM:
    					done = 1;
    					break;
    				case AST_FRAME_CONTROL:
    				case AST_FRAME_IAX:
    
    				case AST_FRAME_NULL:
    				case AST_FRAME_CNG:
    					break;
    				}
    
    				if (done) {
    
    			ast_channel_lock(chan);
    			while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
    				if (res == 0) {
    
    					ast_queue_frame_head(chan, cur);
    				}
    
    				ast_frfree(cur);
    
    			ast_channel_unlock(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    int ast_answer(struct ast_channel *chan)
    {
    
    inline int ast_auto_answer(struct ast_channel *chan)
    {
    	if (ast_channel_state(chan) == AST_STATE_UP) {
    		/* Already answered */
    		return 0;
    	}
    	return ast_answer(chan);
    }
    
    
    int ast_channel_get_duration(struct ast_channel *chan)
    {
    	ast_assert(NULL != chan);
    
    	if (ast_tvzero(ast_channel_creationtime(chan))) {
    		return 0;
    	}
    	return (ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(chan)) / 1000);
    }
    
    int ast_channel_get_up_time(struct ast_channel *chan)
    {
    	ast_assert(NULL != chan);
    
    	if (ast_tvzero(ast_channel_answertime(chan))) {
    		return 0;
    	}
    	return (ast_tvdiff_ms(ast_tvnow(), ast_channel_answertime(chan)) / 1000);
    
    static void deactivate_generator_nolock(struct ast_channel *chan)
    
    	if (ast_channel_generatordata(chan)) {
    
    		struct ast_generator *generator = ast_channel_generator(chan);
    
    		if (generator && generator->release) {
    			generator->release(chan, ast_channel_generatordata(chan));
    
    Olle Johansson's avatar
    Olle Johansson committed
    		}
    
    		ast_channel_generatordata_set(chan, NULL);
    		ast_channel_generator_set(chan, NULL);
    
    		ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
    
    		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
    
    		ast_settimeout(chan, 0, NULL, NULL);
    
    }
    
    void ast_deactivate_generator(struct ast_channel *chan)
    {
    	ast_channel_lock(chan);
    	deactivate_generator_nolock(chan);
    
    	ast_channel_unlock(chan);
    
    static void generator_write_format_change(struct ast_channel *chan)
    {
    
    	ast_channel_lock(chan);
    
    	generator = ast_channel_generator(chan);
    	if (generator && generator->write_format_change) {
    		generator->write_format_change(chan, ast_channel_generatordata(chan));
    
    static int generator_force(const void *data)
    
    {
    	/* Called if generator doesn't have data */
    	void *tmp;
    	int res;
    
    	int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = NULL;