Пример #1
0
static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
{
	struct ast_channel *chan;
	struct ast_format format;
	const char *conf_name = data;

	chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0,
		"CBRec/conf-%s-uid-%d",
		conf_name, (int) ast_random());
	if (!chan) {
		return NULL;
	}
	if (ast_channel_add_bridge_role(chan, "recorder")) {
		ast_channel_release(chan);
		return NULL;
	}
	ast_format_set(&format, AST_FORMAT_SLINEAR, 0);
	ast_channel_tech_set(chan, conf_record_get_tech());
	ast_format_cap_add_all(ast_channel_nativeformats(chan));
	ast_format_copy(ast_channel_writeformat(chan), &format);
	ast_format_copy(ast_channel_rawwriteformat(chan), &format);
	ast_format_copy(ast_channel_readformat(chan), &format);
	ast_format_copy(ast_channel_rawreadformat(chan), &format);
	return chan;
}
Пример #2
0
char *ast_generate_random_string(char *buf, size_t size)
{
    int i;

    for (i = 0; i < size - 1; ++i) {
        buf[i] = 'a' + (ast_random() % 26);
    }
    buf[i] = '\0';

    return buf;
}
Пример #3
0
/*!
 * \brief Create a new OGG/Vorbis filestream and set it up for writing.
 * \param s File pointer that points to on-disk storage.
 * \param comment Comment that should be embedded in the OGG/Vorbis file.
 * \return A new filestream.
 */
static int ogg_vorbis_rewrite(struct ast_filestream *s,
						 const char *comment)
{
	ogg_packet header;
	ogg_packet header_comm;
	ogg_packet header_code;
	struct ogg_vorbis_desc *tmp = (struct ogg_vorbis_desc *) s->_private;

	tmp->writing = 1;
	tmp->writing_pcm_pos = 0;

	vorbis_info_init(&tmp->vi);

	if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
		ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
		return -1;
	}

	vorbis_comment_init(&tmp->vc);
	vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
	if (comment)
		vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);

	vorbis_analysis_init(&tmp->vd, &tmp->vi);
	vorbis_block_init(&tmp->vd, &tmp->vb);

	ogg_stream_init(&tmp->os, ast_random());

	vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm,
				  &header_code);
	ogg_stream_packetin(&tmp->os, &header);
	ogg_stream_packetin(&tmp->os, &header_comm);
	ogg_stream_packetin(&tmp->os, &header_code);

	while (!tmp->eos) {
		if (ogg_stream_flush(&tmp->os, &tmp->og) == 0)
			break;
		if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) {
			ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
		}
		if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) {
			ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
		}
		if (ogg_page_eos(&tmp->og))
			tmp->eos = 1;
	}

	return 0;
}
Пример #4
0
static int page_exec(struct ast_channel *chan, const char *data)
{
	char *tech, *resource, *tmp;
	char confbridgeopts[128], originator[AST_CHANNEL_NAME];
	struct page_options options = { { 0, }, { 0, } };
	unsigned int confid = ast_random();
	struct ast_app *app;
	int res = 0, pos = 0, i = 0;
	struct ast_dial **dial_list;
	unsigned int num_dials;
	int timeout = 0;
	char *parse;

	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(devices);
		AST_APP_ARG(options);
		AST_APP_ARG(timeout);
	);
Пример #5
0
static int random_exec(struct ast_channel *chan, void *data)
{
	int res=0;
	struct localuser *u;

	char *s;
	char *prob;
	int probint;
	static int deprecated = 0;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
		return -1;
	}
	
	LOCAL_USER_ADD(u);

	s = ast_strdupa(data);

	prob = strsep(&s,":");
	if ((!prob) || (sscanf(prob, "%d", &probint) != 1))
		probint = 0;

	if (!deprecated) {
		deprecated = 1;
		ast_log(LOG_WARNING, "Random is deprecated in Asterisk 1.4.  Replace with GotoIf($[${RAND(0,99)} + %d >= 100]?%s)\n", probint, s);
	}

	if ((ast_random() % 100) + probint >= 100) {
		res = ast_parseable_goto(chan, s);
		if (option_verbose > 2)
			ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
				chan->context,chan->exten, chan->priority+1);
	}
	LOCAL_USER_REMOVE(u);
	return res;
}
Пример #6
0
static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ast_sched_context *con;
	struct timeval start;
	unsigned int num, i;
	int *sched_ids = NULL;

	switch (cmd) {
	case CLI_INIT:
		e->command = "sched benchmark";
		e->usage = ""
			"Usage: sched benchmark <num>\n"
			"";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != e->args + 1) {
		return CLI_SHOWUSAGE;
	}

	if (sscanf(a->argv[e->args], "%u", &num) != 1) {
		return CLI_SHOWUSAGE;
	}

	if (!(con = ast_sched_context_create())) {
		ast_cli(a->fd, "Test failed - could not create scheduler context\n");
		return CLI_FAILURE;
	}

	if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) {
		ast_cli(a->fd, "Test failed - memory allocation failure\n");
		goto return_cleanup;
	}

	ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes "
			"to add %u entries at random time intervals from 0 to 60 seconds\n", num);

	start = ast_tvnow();

	for (i = 0; i < num; i++) {
		int when = abs(ast_random()) % 60000;
		if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) {
			ast_cli(a->fd, "Test failed - sched_add returned -1\n");
			goto return_cleanup;
		}
	}

	ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));

	ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes "
			"to delete %u entries with random time intervals from 0 to 60 seconds\n", num);

	start = ast_tvnow();

	for (i = 0; i < num; i++) {
		if (ast_sched_del(con, sched_ids[i]) == -1) {
			ast_cli(a->fd, "Test failed - sched_del returned -1\n");
			goto return_cleanup;
		}
	}

	ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));

return_cleanup:
	ast_sched_context_destroy(con);
	if (sched_ids) {
		ast_free(sched_ids);
	}

	return CLI_SUCCESS;
}
Пример #7
0
/*!
 * \internal
 * \since 12
 * \brief Construct a parked_user struct assigned to the specified parking lot
 *
 * \param lot The parking lot we are assigning the user to
 * \param parkee The channel being parked
 * \param parker The channel performing the park operation (may be the same channel)
 * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
 * \param use_random_space if true, prioritize using a random parking space instead
 *        of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
 * \param time_limit If using a custom timeout, this should be supplied so that the
 *        parked_user struct can provide this information for manager events. If <0,
 *        use the parking lot limit instead.
 *
 * \retval NULL on failure
 * \retval reference to the parked user
 *
 * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
 */
static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit)
{
	struct parked_user *new_parked_user;
	int preferred_space = -1; /* Initialize to use parking lot defaults */
	int parking_space;
	const char *parkingexten;

	if (lot->mode == PARKINGLOT_DISABLED) {
		ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
		return NULL;
	}

	new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
	if (!new_parked_user) {
		return NULL;
	}

	if (use_random_space) {
		preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
		preferred_space += lot->cfg->parking_start;
	} else {
		ast_channel_lock(chan);
		if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
			parkingexten = ast_strdupa(parkingexten);
		}
		ast_channel_unlock(chan);

		if (!ast_strlen_zero(parkingexten)) {
			if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
				ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
				ao2_ref(new_parked_user, -1);
				return NULL;
			}
		}
	}

	/* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
	ao2_lock(lot);

	parking_space = parking_lot_get_space(lot, preferred_space);
	if (parking_space == -1) {
		ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
		ao2_ref(new_parked_user, -1);
		ao2_unlock(lot);
		return NULL;
	}

	lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
	new_parked_user->chan = chan;
	new_parked_user->parking_space = parking_space;

	/* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
	new_parked_user->lot = lot;
	ao2_ref(lot, +1);

	new_parked_user->start = ast_tvnow();
	new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;

	if (parker_dial_string) {
		new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
	} else {
		if (parked_user_set_parker_dial_string(new_parked_user, parker)) {
			ao2_ref(new_parked_user, -1);
			ao2_unlock(lot);
			return NULL;
		}
	}

	if (!new_parked_user->parker_dial_string) {
		ao2_ref(new_parked_user, -1);
		ao2_unlock(lot);
		return NULL;
	}

	/* Insert into the parking lot's parked user list. We can unlock the lot now. */
	ao2_link(lot->parked_users, new_parked_user);
	ao2_unlock(lot);

	return new_parked_user;
}
static int astobj2_test_helper(int use_hash, int use_cmp, unsigned int lim, struct ast_test *test)
{
	struct ao2_container *c1;
	struct ao2_container *c2;
	struct ao2_iterator it;
	struct test_obj *obj;
	struct test_obj tmp_obj;
	int bucket_size;
	int increment = 0;
	int destructor_count = 0;
	int num;
	int  res = AST_TEST_PASS;

	/* This test needs at least 5 objects */
	if (lim < 5) {
		lim = 5;
	}

	bucket_size = (ast_random() % ((lim / 4) + 1)) + 1;
	c1 = ao2_container_alloc(bucket_size, use_hash ? test_hash_cb : NULL, use_cmp ? test_cmp_cb : NULL);
	c2 = ao2_container_alloc(bucket_size, test_hash_cb, test_cmp_cb);

	if (!c1 || !c2) {
		ast_test_status_update(test, "ao2_container_alloc failed.\n");
		res = AST_TEST_FAIL;
		goto cleanup;
	}

	/* Create objects and link into container */
	destructor_count = lim;
	for (num = 1; num <= lim; num++) {
		if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) {
			ast_test_status_update(test, "ao2_alloc failed.\n");
			res = AST_TEST_FAIL;
			goto cleanup;
		}
		snprintf(obj->c, sizeof(obj->c), "zombie #%d", num);
		obj->destructor_count = &destructor_count;
		obj->i = num;
		ao2_link(c1, obj);
		ao2_ref(obj, -1);
		if (ao2_container_count(c1) != num) {
			ast_test_status_update(test, "container did not link correctly\n");
			res = AST_TEST_FAIL;
		}
	}

	ast_test_status_update(test, "Container created: random bucket size %d: number of items: %d\n", bucket_size, lim);

	/* Testing ao2_find with no flags */
	num = 100;
	for (; num; num--) {
		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
		tmp_obj.i = i;
		if (!(obj = ao2_find(c1, &tmp_obj, 0))) {
			res = AST_TEST_FAIL;
			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
		} else {
			/* a correct match will only take place when the custom cmp function is used */
			if (use_cmp && obj->i != i) {
				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
				res = AST_TEST_FAIL;
			}
			ao2_ref(obj, -1);
		}
	}

	/* Testing ao2_find with OBJ_POINTER */
	num = 75;
	for (; num; num--) {
		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
		snprintf(tmp_obj.c, sizeof(tmp_obj.c), "zombie #%d", i);
		tmp_obj.i = i;
		if (!(obj = ao2_find(c1, &tmp_obj, OBJ_POINTER))) {
			res = AST_TEST_FAIL;
			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
		} else {
			/* a correct match will only take place when the custom cmp function is used */
			if (use_cmp && obj->i != i) {
				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
				res = AST_TEST_FAIL;
			}
			ao2_ref(obj, -1);
		}
	}

	/* Testing ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE.
	 * In this test items are unlinked from c1 and placed in c2.  Then
	 * unlinked from c2 and placed back into c1.
	 *
	 * For this module and set of custom hash/cmp functions, an object
	 * should only be found if the astobj2 default cmp function is used.
	 * This test is designed to mimic the chan_iax.c call number use case. */
	num = lim < 25 ? lim : 25;
	for (; num; num--) {
		if (!(obj = ao2_find(c1, NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE))) {
			if (!use_cmp) {
				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with default hash function.\n");
				res = AST_TEST_FAIL;
			}
		} else {
			if (use_cmp) {
				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with custom hash function.\n");
				res = AST_TEST_FAIL;
			}
			ao2_link(c2, obj);
			ao2_ref(obj, -1);
		}
	}
	it = ao2_iterator_init(c2, 0);
	while ((obj = ao2_iterator_next(&it))) {
		ao2_unlink(c2, obj);
		ao2_link(c1, obj);
		ao2_ref(obj, -1);
	}
	ao2_iterator_destroy(&it);

	/* Test Callback with no flags. */
	increment = 0;
	ao2_callback(c1, 0, increment_cb, &increment);
	if (increment != lim) {
		ast_test_status_update(test, "callback with no flags failed. Increment is %d\n", increment);
		res = AST_TEST_FAIL;
	}

	/* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */
	increment = 0;
	ao2_callback(c1, OBJ_NODATA, increment_cb, &increment);
	if (increment != lim) {
		ast_test_status_update(test, "callback with OBJ_NODATA failed. Increment is %d\n", increment);
		res = AST_TEST_FAIL;
	}

	/* Is the container count what we expect after all the finds and unlinks?*/
	if (ao2_container_count(c1) != lim) {
		ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n");
		res = AST_TEST_FAIL;
	}

	/* Testing iterator.  Unlink a single object and break. do not add item back */
	it = ao2_iterator_init(c1, 0);
	num = (lim / 4) + 1;
	while ((obj = ao2_iterator_next(&it))) {
		if (obj->i == num) {
			ao2_ref(obj, -1);
			ao2_unlink(c1, obj);
			break;
		}
		ao2_ref(obj, -1);
	}
	ao2_iterator_destroy(&it);

	/* Is the container count what we expect after removing a single item? */
	if (ao2_container_count(c1) != (lim - 1)) {
		ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num);
		res = AST_TEST_FAIL;
	}

	/* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */
	ao2_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, all_but_one_cb, NULL);
	/* check to make sure all test_obj destructors were called except for 1 */
	if (destructor_count != 1) {
		ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
		res = AST_TEST_FAIL;
	}

cleanup:
	/* destroy containers */
	if (c1) {
		ao2_ref(c1, -1);
	}
	if (c2) {
		ao2_ref(c2, -1);
	}

	if (destructor_count > 0) {
		ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count);
		res = AST_TEST_FAIL;
	} else if (destructor_count < 0) {
		ast_test_status_update(test, "Destructor was called too many times, destructor count is %d\n", destructor_count);
		res = AST_TEST_FAIL;
	}

	return res;
}
Пример #9
0
static int page_exec(struct ast_channel *chan, void *data)
{
	struct ast_module_user *u;
	char *options, *tech, *resource, *tmp;
	char meetmeopts[88], originator[AST_CHANNEL_NAME];
	struct ast_flags flags = { 0 };
	unsigned int confid = ast_random();
	struct ast_app *app;
	int res = 0, pos = 0, i = 0;
	struct ast_dial *dials[MAX_DIALS];

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
		return -1;
	}

	u = ast_module_user_add(chan);

	if (!(app = pbx_findapp("MeetMe"))) {
		ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
		ast_module_user_remove(u);
		return -1;
	};

	options = ast_strdupa(data);

	ast_copy_string(originator, chan->name, sizeof(originator));
	if ((tmp = strchr(originator, '-')))
		*tmp = '\0';

	tmp = strsep(&options, "|");
	if (options)
		ast_app_parse_options(page_opts, &flags, NULL, options);

	snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
		(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );

	/* Go through parsing/calling each device */
	while ((tech = strsep(&tmp, "&"))) {
		struct ast_dial *dial = NULL;

		/* don't call the originating device */
		if (!strcasecmp(tech, originator))
			continue;

		/* If no resource is available, continue on */
		if (!(resource = strchr(tech, '/'))) {
			ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
			continue;
		}

		*resource++ = '\0';

		/* Create a dialing structure */
		if (!(dial = ast_dial_create())) {
			ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
			continue;
		}

		/* Append technology and resource */
		ast_dial_append(dial, tech, resource);

		/* Set ANSWER_EXEC as global option */
		ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts);

		/* Run this dial in async mode */
		ast_dial_run(dial, chan, 1);

		/* Put in our dialing array */
		dials[pos++] = dial;
	}

	if (!ast_test_flag(&flags, PAGE_QUIET)) {
		res = ast_streamfile(chan, "beep", chan->language);
		if (!res)
			res = ast_waitstream(chan, "");
	}

	if (!res) {
		snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"), 
			(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
		pbx_exec(chan, app, meetmeopts);
	}

	/* Go through each dial attempt cancelling, joining, and destroying */
	for (i = 0; i < pos; i++) {
		struct ast_dial *dial = dials[i];

		/* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */
		ast_dial_join(dial);

		/* Hangup all channels */
		ast_dial_hangup(dial);

		/* Destroy dialing structure */
		ast_dial_destroy(dial);
	}

	ast_module_user_remove(u);

	return -1;
}