コード例 #1
0
/*! \brief Adds devicestate to local channels */
static int local_devicestate(const char *data)
{
	char *exten = ast_strdupa(data);
	char *context = NULL, *opts = NULL;
	int res;
	struct local_pvt *lp;
	struct ao2_iterator it;

	if (!(context = strchr(exten, '@'))) {
		ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
		return AST_DEVICE_INVALID;
	}

	*context++ = '\0';

	/* Strip options if they exist */
	if ((opts = strchr(context, '/')))
		*opts = '\0';

	ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);

	res = ast_exists_extension(NULL, context, exten, 1, NULL);
	if (!res)
		return AST_DEVICE_INVALID;

	res = AST_DEVICE_NOT_INUSE;

	it = ao2_iterator_init(locals, 0);
	while ((lp = ao2_iterator_next(&it)) && (res == AST_DEVICE_NOT_INUSE)) {
		if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
			ao2_lock(lp);
			if (ast_test_flag(lp, LOCAL_LAUNCHED_PBX)) {
				res = AST_DEVICE_INUSE;
			}
			ao2_unlock(lp);
		}
		ao2_ref(lp, -1);
	}
	ao2_iterator_destroy(&it);

	return res;
}
コード例 #2
0
ファイル: func_dialgroup.c プロジェクト: abieuzent/iaxproxy
static int dialgroup_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
	struct ao2_iterator i;
	struct group *grhead = ao2_find(group_container, data, 0);
	struct group_entry *entry;
	size_t bufused = 0;
	int trunc_warning = 0;
	int res = 0;

	if (!grhead) {
		if (!ast_strlen_zero(cmd)) {
			ast_log(LOG_WARNING, "No such dialgroup '%s'\n", data);
		}
		return -1;
	}

	buf[0] = '\0';

	i = ao2_iterator_init(grhead->entries, OBJ_POINTER);
	while ((entry = ao2_iterator_next(&i))) {
		int tmp = strlen(entry->name);
		/* Ensure that we copy only complete names, not partials */
		if (len - bufused > tmp + 2) {
			if (bufused != 0)
				buf[bufused++] = '&';
			ast_copy_string(buf + bufused, entry->name, len - bufused);
			bufused += tmp;
		} else if (trunc_warning++ == 0) {
			if (!ast_strlen_zero(cmd)) {
				ast_log(LOG_WARNING, "Dialgroup '%s' is too large.  Truncating list.\n", data);
			} else {
				res = 1;
				ao2_ref(entry, -1);
				break;
			}
		}
		ao2_ref(entry, -1);
	}
	ao2_iterator_destroy(&i);

	return res;
}
コード例 #3
0
ファイル: control.c プロジェクト: vzar/asterisk
int control_dispatch_all(struct stasis_app_control *control,
                         struct ast_channel *chan)
{
    int count = 0;
    struct ao2_iterator i;
    void *obj;

    ast_assert(control->channel == chan);

    i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK);

    while ((obj = ao2_iterator_next(&i))) {
        RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup);
        command_invoke(command, control, chan);
        ++count;
    }

    ao2_iterator_destroy(&i);
    return count;
}
コード例 #4
0
ファイル: agent.c プロジェクト: xhook/asterisk-v11
static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
								  int exact, size_t *var_len, WriteMethod **write_method)
{
	static unsigned long long_ret;
	static char ret_buf[128];
	struct ast_tone_zone *tz = NULL;

	if (header_generic(vp, name, length, exact, var_len, write_method))
		return NULL;

	switch (vp->magic) {
	case ASTINDCOUNT:
	{
		struct ao2_iterator i;

		long_ret = 0;

		i = ast_tone_zone_iterator_init();
		while ((tz = ao2_iterator_next(&i))) {
			tz = ast_tone_zone_unref(tz);
			long_ret++;
		}
		ao2_iterator_destroy(&i);

		return (u_char *) &long_ret;
	}
	case ASTINDCURRENT:
		tz = ast_get_indication_zone(NULL);
		if (tz) {
			ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
			*var_len = strlen(ret_buf);
			tz = ast_tone_zone_unref(tz);
			return (u_char *) ret_buf;
		}
		*var_len = 0;
		return NULL;
	default:
		break;
	}
	return NULL;
}
コード例 #5
0
ファイル: res_mwi_external.c プロジェクト: adaptiman/asterisk
/*!
 * \internal
 * \brief Post initial MWI count events.
 * \since 12.1.0
 *
 * \return Nothing
 */
static void mwi_initial_events(void)
{
	struct ao2_container *mailboxes;
	const struct ast_mwi_mailbox_object *mailbox;
	struct ao2_iterator iter;

	/* Get all mailbox counts. */
	mailboxes = ast_mwi_mailbox_get_all();
	if (!mailboxes) {
		return;
	}

	/* Post all mailbox counts. */
	iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
		mwi_post_event(mailbox);
	}
	ao2_iterator_destroy(&iter);

	ao2_ref(mailboxes, -1);
}
コード例 #6
0
ファイル: app.c プロジェクト: roramirez/asterisk
/*! \brief Callback function for checking if channels in a bridge are subscribed to */
static int bridge_app_subscribed_involved(struct stasis_app *app, struct ast_bridge_snapshot *snapshot)
{
	int subscribed = 0;
	struct ao2_iterator iter;
	char *uniqueid;

	if (bridge_app_subscribed(app, snapshot->uniqueid)) {
		return 1;
	}

	iter = ao2_iterator_init(snapshot->channels, 0);
	for (; (uniqueid = ao2_iterator_next(&iter)); ao2_ref(uniqueid, -1)) {
		if (bridge_app_subscribed(app, uniqueid)) {
			subscribed = 1;
			ao2_ref(uniqueid, -1);
			break;
		}
	}
	ao2_iterator_destroy(&iter);

	return subscribed;
}
コード例 #7
0
/*! \brief CLI command "local show channels" */
static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct local_pvt *p;
	struct ao2_iterator it;

	switch (cmd) {
	case CLI_INIT:
		e->command = "local show channels";
		e->usage =
			"Usage: local show channels\n"
			"       Provides summary information on active local proxy channels.\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != 3) {
		return CLI_SHOWUSAGE;
	}

	if (ao2_container_count(locals) == 0) {
		ast_cli(a->fd, "No local channels in use\n");
		return RESULT_SUCCESS;
	}

	it = ao2_iterator_init(locals, 0);
	while ((p = ao2_iterator_next(&it))) {
		ao2_lock(p);
		ast_cli(a->fd, "%s -- %s\n",
			p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
			p->base.name);
		ao2_unlock(p);
		ao2_ref(p, -1);
	}
	ao2_iterator_destroy(&it);

	return CLI_SUCCESS;
}
コード例 #8
0
static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ao2_iterator i;
	struct ast_sip_sched_task *schtd;
	const char *log_format = ast_logger_get_dateformat();
	struct ast_tm tm;
	char queued[32];
	char last_start[32];
	char last_end[32];
	int datelen;
	struct timeval now = ast_tvnow();
	const char *separator = "======================================";

	switch (cmd) {
	case CLI_INIT:
		e->command = "pjsip show scheduled_tasks";
		e->usage = "Usage: pjsip show scheduled_tasks\n"
		            "      Show all scheduled tasks\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != 3) {
		return CLI_SHOWUSAGE;
	}

	ast_localtime(&now, &tm, NULL);
	datelen = ast_strftime(queued, sizeof(queued), log_format, &tm);

	ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n");

	ast_cli(a->fd, " %1$-24s %2$-8s %3$-9s %4$-7s  %6$-*5$s  %7$-*5$s  %8$-*5$s\n",
		"Task Name", "Interval", "Times Run", "State",
		datelen, "Queued", "Last Started", "Last Ended");

	ast_cli(a->fd, " %1$-24.24s %2$-8.8s %3$-9.9s %4$-7.7s  %6$-*5$.*5$s  %7$-*5$.*5$s  %8$-*5$.*5$s\n",
		separator, separator, separator, separator,
		datelen, separator, separator, separator);


	ao2_ref(tasks, +1);
	ao2_rdlock(tasks);
	i = ao2_iterator_init(tasks, 0);
	while ((schtd = ao2_iterator_next(&i))) {

		ast_localtime(&schtd->when_queued, &tm, NULL);
		ast_strftime(queued, sizeof(queued), log_format, &tm);

		if (ast_tvzero(schtd->last_start)) {
			strcpy(last_start, "not yet started");
		} else {
			ast_localtime(&schtd->last_start, &tm, NULL);
			ast_strftime(last_start, sizeof(last_start), log_format, &tm);
		}

		if (ast_tvzero(schtd->last_end)) {
			if (ast_tvzero(schtd->last_start)) {
				strcpy(last_end, "not yet started");
			} else {
				strcpy(last_end, "running");
			}
		} else {
			ast_localtime(&schtd->last_end, &tm, NULL);
			ast_strftime(last_end, sizeof(last_end), log_format, &tm);
		}

		ast_cli(a->fd, " %1$-24.24s %2$-8.3f %3$-9d %4$-7s  %6$-*5$s  %7$-*5$s  %8$-*5$s\n",
			schtd->name,
			schtd->interval / 1000.0,
			schtd->run_count,
			schtd->is_running ? "running" : "waiting",
			datelen, queued, last_start, last_end);
		ao2_cleanup(schtd);
	}
	ao2_iterator_destroy(&i);
	ao2_unlock(tasks);
	ao2_ref(tasks, -1);
	ast_cli(a->fd, "\n");

	return CLI_SUCCESS;
}
コード例 #9
0
int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_found = 0,
		.joint_cap = NULL,
	};

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return data.joint_found ? 1 : 0;
}

int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format *tmp;

	if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
		return 0; /* if they are not the same size, they are not identical */
	}

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (!ast_format_cap_iscompatible(cap2, tmp)) {
			ao2_ref(tmp, -1);
			ao2_iterator_destroy(&it);
			return 0;
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return 1;
}

struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_found = 0,
		.joint_cap = result,
	};
	if (!result) {
		return NULL;
	}

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	if (ao2_container_count(result->formats)) {
		return result;
	}

	result = ast_format_cap_destroy(result);
	return NULL;
}

static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
{
	struct ao2_iterator it;
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_cap = result,
		.joint_found = 0,
	};
	if (!append) {
		ast_format_cap_remove_all(result);
	}
	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return ao2_container_count(result->formats) ? 1 : 0;
}

int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
{
	return joint_copy_helper(cap1, cap2, result, 1);
}

int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
{
	return joint_copy_helper(cap1, cap2, result, 0);
}

struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
{
	struct ao2_iterator it;
	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
	struct ast_format *tmp;

	if (!result) {
		return NULL;
	}

	/* for each format in cap1, see if that format is
	 * compatible with cap2. If so copy it to the result */
	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
			/* copy format */
			ast_format_cap_add(result, tmp);
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	if (ao2_container_count(result->formats)) {
		return result;
	}
	result = ast_format_cap_destroy(result);

	return NULL;
}


int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
{
	struct ao2_iterator it;
	struct ast_format *tmp;

	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
			ao2_ref(tmp, -1);
			ao2_iterator_destroy(&it);
			return 1;
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return 0;
}

void ast_format_cap_iter_start(struct ast_format_cap *cap)
{
	if (!cap->nolock) {
		ao2_lock(cap->formats);
	}
	cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
}

void ast_format_cap_iter_end(struct ast_format_cap *cap)
{
	ao2_iterator_destroy(&cap->it);
	if (!cap->nolock) {
		ao2_unlock(cap->formats);
	}
}

int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
{
	struct ast_format *tmp = ao2_iterator_next(&cap->it);

	if (!tmp) {
		return -1;
	}
	ast_format_copy(format, tmp);
	ao2_ref(tmp, -1);

	return 0;
}

char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
{
	int x;
	unsigned len;
	char *start, *end = buf;
	struct ast_format tmp_fmt;
	size_t f_len;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	if (!size) {
		f_list = ast_format_list_destroy(f_list);
		return buf;
	}
	snprintf(end, size, "(");
	len = strlen(end);
	end += len;
	size -= len;
	start = end;
	for (x = 0; x < f_len; x++) {
		ast_format_copy(&tmp_fmt, &f_list[x].format);
		if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
			snprintf(end, size, "%s|", f_list[x].name);
			len = strlen(end);
			end += len;
			size -= len;
		}
	}
	if (start == end) {
		ast_copy_string(start, "nothing)", size);
	} else if (size > 1) {
		*(end - 1) = ')';
	}
	f_list = ast_format_list_destroy(f_list);
	return buf;
}

uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
{
	uint64_t res = 0;
	struct ao2_iterator it;
	struct ast_format *tmp;

	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		res |= ast_format_to_old_bitfield(tmp);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);
	return res;
}
コード例 #10
0
ファイル: resource_endpoints.c プロジェクト: aderbas/asterisk
void ast_ari_endpoints_list_by_tech(struct ast_variable *headers,
	struct ast_ari_endpoints_list_by_tech_args *args,
	struct ast_ari_response *response)
{
	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
	RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	struct ao2_iterator i;
	void *obj;

	if (!ast_get_channel_tech(args->tech)) {
		ast_ari_response_error(response, 404, "Not Found",
				       "No Endpoints found - invalid tech %s", args->tech);
		return;
	}

	cache = ast_endpoint_cache();
	if (!cache) {
		ast_ari_response_error(
			response, 500, "Internal Server Error",
			"Message bus not initialized");
		return;
	}
	ao2_ref(cache, +1);

	snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
	if (!snapshots) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	json = ast_json_array_create();
	if (!json) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	i = ao2_iterator_init(snapshots, 0);
	while ((obj = ao2_iterator_next(&i))) {
		RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
		struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
		struct ast_json *json_endpoint;
		int r;

		if (strcasecmp(args->tech, snapshot->tech) != 0) {
			continue;
		}

		json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
		if (!json_endpoint) {
			continue;
		}

		r = ast_json_array_append(
			json, json_endpoint);
		if (r != 0) {
			ast_ari_response_alloc_failed(response);
			return;
		}
	}
	ao2_iterator_destroy(&i);
	ast_ari_response_ok(response, ast_json_ref(json));
}
コード例 #11
0
ファイル: codec.c プロジェクト: GGGO/asterisk
static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ao2_iterator i;
	struct ast_codec *codec;

	switch (cmd) {
	case CLI_INIT:
		e->command = "core show codecs [audio|video|image|text]";
		e->usage =
			"Usage: core show codecs [audio|video|image|text]\n"
			"       Displays codec mapping\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if ((a->argc < 3) || (a->argc > 4)) {
		return CLI_SHOWUSAGE;
	}

	if (!ast_opt_dont_warn) {
		ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
				"\tIt does not indicate anything about your configuration.\n");
	}

	ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
	ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");

	ao2_rdlock(codecs);
	i = ao2_iterator_init(codecs, AO2_ITERATOR_DONTLOCK);

	for (; (codec = ao2_iterator_next(&i)); ao2_ref(codec, -1)) {
		if (a->argc == 4) {
			if (!strcasecmp(a->argv[3], "audio")) {
				if (codec->type != AST_MEDIA_TYPE_AUDIO) {
					continue;
				}
			} else if (!strcasecmp(a->argv[3], "video")) {
				if (codec->type != AST_MEDIA_TYPE_VIDEO) {
					continue;
				}
			} else if (!strcasecmp(a->argv[3], "image")) {
				if (codec->type != AST_MEDIA_TYPE_IMAGE) {
					continue;
				}
			} else if (!strcasecmp(a->argv[3], "text")) {
				if (codec->type != AST_MEDIA_TYPE_TEXT) {
					continue;
				}
			} else {
				continue;
			}
		}

		ast_cli(a->fd, "%8u %5s %8s (%s)\n",
			codec->id,
			ast_codec_media_type2str(codec->type),
			codec->name,
			codec->description);
	}

	ao2_iterator_destroy(&i);
	ao2_unlock(codecs);

	return CLI_SUCCESS;
}
コード例 #12
0
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;
}
コード例 #13
0
ファイル: res_pjsip_mwi.c プロジェクト: juned/asterisk
static void send_mwi_notify(struct mwi_subscription *sub)
{
	struct ast_sip_message_accumulator counter = {
		.old_msgs = 0,
		.new_msgs = 0,
	};
	struct ast_sip_body_data data = {
		.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
		.body_data = &counter,
	};

	ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter);

	if (sub->is_solicited) {
		ast_sip_subscription_notify(sub->sip_sub, &data, 0);
		return;
	}

	send_unsolicited_mwi_notify(sub, &counter);
}

static int unsubscribe_stasis(void *obj, void *arg, int flags)
{
	struct mwi_stasis_subscription *mwi_stasis = obj;
	if (mwi_stasis->stasis_sub) {
		ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);
		mwi_stasis->stasis_sub = stasis_unsubscribe_and_join(mwi_stasis->stasis_sub);
	}
	return CMP_MATCH;
}

static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
{
	struct mwi_subscription *mwi_sub;
	struct ast_datastore *mwi_datastore;

	mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
	if (!mwi_datastore) {
		return;
	}

	mwi_sub = mwi_datastore->data;
	ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
	ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);

	ao2_ref(mwi_datastore, -1);
}

static void mwi_ds_destroy(void *data)
{
	struct mwi_subscription *sub = data;

	ao2_ref(sub, -1);
}

static struct ast_datastore_info mwi_ds_info = {
	.destroy = mwi_ds_destroy,
};

static int add_mwi_datastore(struct mwi_subscription *sub)
{
	struct ast_datastore *mwi_datastore;
	int res;

	mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
	if (!mwi_datastore) {
		return -1;
	}
	ao2_ref(sub, +1);
	mwi_datastore->data = sub;

	/*
	 * NOTE:  Adding the datastore to the subscription creates a ref loop
	 * that must be manually broken.
	 */
	res = ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
	ao2_ref(mwi_datastore, -1);
	return res;
}

/*!
 * \brief Determines if an endpoint is receiving unsolicited MWI for a particular mailbox.
 *
 * \param endpoint The endpoint to check
 * \param mailbox The candidate mailbox
 * \retval 0 The endpoint does not receive unsolicited MWI for this mailbox
 * \retval 1 The endpoint receives unsolicited MWI for this mailbox
 */
static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,
		const char *mailbox)
{
	struct ao2_iterator *mwi_subs;
	struct mwi_subscription *mwi_sub;
	const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
	int ret = 0;

	mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);

	if (!mwi_subs) {
		return 0;
	}

	for (; (mwi_sub = ao2_iterator_next(mwi_subs)) && !ret; ao2_cleanup(mwi_sub)) {
		struct mwi_stasis_subscription *mwi_stasis;

		mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);
		if (mwi_stasis) {
			ret = 1;
			ao2_cleanup(mwi_stasis);
		}
	}

	ao2_iterator_destroy(mwi_subs);
	return ret;
}

/*!
 * \brief Determine if an endpoint is a candidate to be able to subscribe for MWI
 *
 * Currently, this just makes sure that the endpoint is not already receiving unsolicted
 * MWI for any of an AOR's configured mailboxes.
 *
 * \param obj The AOR to which the endpoint is subscribing.
 * \param arg The endpoint that is attempting to subscribe.
 * \param flags Unused.
 * \retval 0 Endpoint is a candidate to subscribe to MWI on the AOR.
 * \retval -1 The endpoint cannot subscribe to MWI on the AOR.
 */
static int mwi_validate_for_aor(void *obj, void *arg, int flags)
{
	struct ast_sip_aor *aor = obj;
	struct ast_sip_endpoint *endpoint = arg;
	char *mailboxes;
	char *mailbox;

	if (ast_strlen_zero(aor->mailboxes)) {
		return 0;
	}

	mailboxes = ast_strdupa(aor->mailboxes);
	while ((mailbox = strsep(&mailboxes, ","))) {
		if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) {
			ast_log(LOG_NOTICE, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
					"Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox,
					ast_sorcery_object_get_id(aor));
			return -1;
		}
	}

	return 0;
}

static int mwi_on_aor(void *obj, void *arg, int flags)
{
	struct ast_sip_aor *aor = obj;
	struct mwi_subscription *sub = arg;
	char *mailboxes;
	char *mailbox;

	if (ast_strlen_zero(aor->mailboxes)) {
		return 0;
	}

	mailboxes = ast_strdupa(aor->mailboxes);
	while ((mailbox = strsep(&mailboxes, ","))) {
		struct mwi_stasis_subscription *mwi_stasis_sub;

		mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
		if (!mwi_stasis_sub) {
			continue;
		}

		ao2_link(sub->stasis_subs, mwi_stasis_sub);
		ao2_ref(mwi_stasis_sub, -1);
	}

	return 0;
}

static struct mwi_subscription *mwi_create_subscription(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
{
	struct mwi_subscription *sub = mwi_subscription_alloc(endpoint, 1, sip_sub);

	if (!sub) {
		return NULL;
	}

	if (add_mwi_datastore(sub)) {
		ast_log(LOG_WARNING, "Unable to add datastore for MWI subscription to %s\n",
			sub->id);
		ao2_ref(sub, -1);
		return NULL;
	}

	return sub;
}

static struct mwi_subscription *mwi_subscribe_single(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
{
	struct ast_sip_aor *aor;
	struct mwi_subscription *sub;

	aor = ast_sip_location_retrieve_aor(name);
	if (!aor) {
		/*! I suppose it's possible for the AOR to disappear on us
		 * between accepting the subscription and sending the first
		 * NOTIFY...
		 */
		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
			name);
		return NULL;
	}

	sub = mwi_create_subscription(endpoint, sip_sub);
	if (sub) {
		mwi_on_aor(aor, sub, 0);
	}

	ao2_ref(aor, -1);
	return sub;
}

static struct mwi_subscription *mwi_subscribe_all(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
{
	struct mwi_subscription *sub;

	sub = mwi_create_subscription(endpoint, sip_sub);
	if (!sub) {
		return NULL;
	}

	ast_sip_for_each_aor(endpoint->aors, mwi_on_aor, sub);
	return sub;
}

static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
		const char *resource)
{
	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);

	if (ast_strlen_zero(resource)) {
		if (ast_sip_for_each_aor(endpoint->aors, mwi_validate_for_aor, endpoint)) {
			return 500;
		}
		return 200;
	}

	aor = ast_sip_location_retrieve_aor(resource);
	if (!aor) {
		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
			resource);
		return 404;
	}

	if (ast_strlen_zero(aor->mailboxes)) {
		ast_log(LOG_NOTICE, "AOR %s has no configured mailboxes. MWI subscription failed.\n",
			resource);
		return 404;
	}

	if (mwi_validate_for_aor(aor, endpoint, 0)) {
		return 500;
	}

	return 200;
}
コード例 #14
0
/*!
 * \internal
 * \brief Get the requested mailboxes.
 * \since 12.1.0
 *
 * \param s AMI session.
 * \param m AMI message.
 *
 * \retval 0 to keep AMI connection.
 * \retval -1 to disconnect AMI connection.
 */
static int mwi_mailbox_get(struct mansession *s, const struct message *m)
{
	char id_text[256];
	const char *id;
	const char *mailbox_id = astman_get_header(m, "Mailbox");
	const struct ast_mwi_mailbox_object *mailbox;
	struct ao2_container *mailboxes;
	unsigned count;
	struct ao2_iterator iter;

	if (ast_strlen_zero(mailbox_id)) {
		astman_send_error(s, m, "Missing mailbox parameter in request");
		return 0;
	}

	if (*mailbox_id == '/') {
		struct ast_str *regex_string;

		regex_string = ast_str_create(strlen(mailbox_id) + 1);
		if (!regex_string) {
			astman_send_error(s, m, "Memory Allocation Failure");
			return 0;
		}

		/* Make "/regex/" into "regex" */
		if (ast_regex_string_to_regex_pattern(mailbox_id, &regex_string) != 0) {
			astman_send_error_va(s, m, "Mailbox regex format invalid in: %s", mailbox_id);
			ast_free(regex_string);
			return 0;
		}

		mailboxes = ast_mwi_mailbox_get_by_regex(ast_str_buffer(regex_string));
		ast_free(regex_string);
	} else {
		mailboxes = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
		if (mailboxes) {
			mailbox = ast_mwi_mailbox_get(mailbox_id);
			if (mailbox) {
				if (!ao2_link(mailboxes, (void *) mailbox)) {
					ao2_ref(mailboxes, -1);
					mailboxes = NULL;
				}
				ast_mwi_mailbox_unref(mailbox);
			}
		}
	}
	if (!mailboxes) {
		astman_send_error(s, m, "Mailbox container creation failure");
		return 0;
	}

	astman_send_listack(s, m, "Mailboxes will follow", "start");

	id = astman_get_header(m, "ActionID");
	if (!ast_strlen_zero(id)) {
		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
	} else {
		id_text[0] = '\0';
	}

	/* Output mailbox list. */
	count = 0;
	iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
		++count;
		astman_append(s,
			"Event: MWIGet\r\n"
			"Mailbox: %s\r\n"
			"OldMessages: %u\r\n"
			"NewMessages: %u\r\n"
			"%s"
			"\r\n",
			ast_mwi_mailbox_get_id(mailbox),
			ast_mwi_mailbox_get_msgs_old(mailbox),
			ast_mwi_mailbox_get_msgs_new(mailbox),
			id_text);
	}
	ao2_iterator_destroy(&iter);
	ao2_ref(mailboxes, -1);

	astman_send_list_complete_start(s, m, "MWIGetComplete", count);
	astman_send_list_complete_end(s);

	return 0;
}
コード例 #15
0
ファイル: parking_manager.c プロジェクト: lyx2014/Asterisk
static void manager_parking_status_all_lots(struct mansession *s, const struct message *m, const char *id_text)
{
	struct parked_user *curuser;
	struct ao2_container *lot_container;
	struct ao2_iterator iter_lots;
	struct ao2_iterator iter_users;
	struct parking_lot *curlot;
	int total = 0;

	lot_container = get_parking_lot_container();
	if (!lot_container) {
		ast_log(LOG_ERROR, "Failed to obtain parking lot list. Action canceled.\n");
		astman_send_error(s, m, "Could not create parking lot list");
		return;
	}

	astman_send_listack(s, m, "Parked calls will follow", "start");

	iter_lots = ao2_iterator_init(lot_container, 0);
	while ((curlot = ao2_iterator_next(&iter_lots))) {
		iter_users = ao2_iterator_init(curlot->parked_users, 0);
		while ((curuser = ao2_iterator_next(&iter_users))) {
			RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
			RAII_VAR(struct ast_str *, parked_call_string, NULL, ast_free);

			payload = parked_call_payload_from_parked_user(curuser, PARKED_CALL);
			if (!payload) {
				ao2_ref(curuser, -1);
				ao2_iterator_destroy(&iter_users);
				ao2_ref(curlot, -1);
				goto abort_list;
			}

			parked_call_string = manager_build_parked_call_string(payload);
			if (!parked_call_string) {
				ao2_ref(curuser, -1);
				ao2_iterator_destroy(&iter_users);
				ao2_ref(curlot, -1);
				goto abort_list;
			}

			total++;

			astman_append(s, "Event: ParkedCall\r\n"
				"%s" /* The parked call string */
				"%s" /* The action ID */
				"\r\n",
				ast_str_buffer(parked_call_string),
				id_text);

			ao2_ref(curuser, -1);
		}
		ao2_iterator_destroy(&iter_users);
		ao2_ref(curlot, -1);
	}
abort_list:
	ao2_iterator_destroy(&iter_lots);

	astman_send_list_complete_start(s, m, "ParkedCallsComplete", total);
	astman_append(s, "Total: %d\r\n", total);
	astman_send_list_complete_end(s);
}
コード例 #16
0
/*! \brief Function which passes through an aliased CLI command to the real one */
static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct cli_alias *alias;
	struct cli_alias tmp = {
		.cli_entry.command = e->command,
	};
	char *generator;
	const char *line;

	/* Try to find the alias based on the CLI entry */
	if (!(alias = ao2_find(cli_aliases, &tmp, OBJ_POINTER))) {
		return 0;
	}

	switch (cmd) {
	case CLI_INIT:
		ao2_ref(alias, -1);
		return NULL;
	case CLI_GENERATE:
		line = a->line;
		line += (strlen(alias->alias));
		if (!strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) {
			generator = NULL;
		} else if (!ast_strlen_zero(a->word)) {
			struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1);
			ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line);
			generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n);
		} else {
			generator = ast_cli_generator(alias->real_cmd, a->word, a->n);
		}
		ao2_ref(alias, -1);
		return generator;
	}

	/* If they gave us extra arguments we need to construct a string to pass in */
	if (a->argc != e->args) {
		struct ast_str *real_cmd = ast_str_alloca(2048);
		int i;

		ast_str_append(&real_cmd, 0, "%s", alias->real_cmd);

		/* Add the additional arguments that have been passed in */
		for (i = e->args + 1; i <= a->argc; i++) {
			ast_str_append(&real_cmd, 0, " %s", a->argv[i - 1]);
		}

		ast_cli_command(a->fd, ast_str_buffer(real_cmd));
	} else {
		ast_cli_command(a->fd, alias->real_cmd);
	}

	ao2_ref(alias, -1);

	return CLI_SUCCESS;
}

/*! \brief CLI Command to display CLI Aliases */
static char *alias_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
#define FORMAT "%-50.50s %-50.50s\n"
	struct cli_alias *alias;
	struct ao2_iterator i;

	switch (cmd) {
	case CLI_INIT:
		e->command = "cli show aliases";
		e->usage =
			"Usage: cli show aliases\n"
			"       Displays a list of aliased CLI commands.\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	ast_cli(a->fd, FORMAT, "Alias Command", "Real Command");

	i = ao2_iterator_init(cli_aliases, 0);
	for (; (alias = ao2_iterator_next(&i)); ao2_ref(alias, -1)) {
		ast_cli(a->fd, FORMAT, alias->alias, alias->real_cmd);
	}
	ao2_iterator_destroy(&i);

	return CLI_SUCCESS;
#undef FORMAT
}

/*! \brief CLI commands to interact with things */
static struct ast_cli_entry cli_alias[] = {
	AST_CLI_DEFINE(alias_show, "Show CLI command aliases"),
};

/*! \brief Function called to load or reload the configuration file */
static void load_config(int reload)
{
	struct ast_config *cfg = NULL;
	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
	struct cli_alias *alias;
	struct ast_variable *v, *v1;

	if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
		ast_log(LOG_ERROR, "res_clialiases configuration file '%s' not found\n", config_file);
		return;
	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
		return;
	}

	/* Destroy any existing CLI aliases */
	if (reload) {
		ao2_callback(cli_aliases, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
	}

	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
		if (strcmp(v->name, "template")) {
			ast_log(LOG_WARNING, "%s is not a correct option in [%s]\n", v->name, "general");
			continue;
		}
		/* Read in those there CLI aliases */
		for (v1 = ast_variable_browse(cfg, v->value); v1; v1 = v1->next) {
			if (!(alias = ao2_alloc((sizeof(*alias) + strlen(v1->name) + strlen(v1->value) + 2), alias_destroy))) {
				continue;
			}
			alias->alias = ((char *) alias) + sizeof(*alias);
			alias->real_cmd = ((char *) alias->alias) + strlen(v1->name) + 1;
			strcpy(alias->alias, v1->name);
			strcpy(alias->real_cmd, v1->value);
			alias->cli_entry.handler = cli_alias_passthrough;
			alias->cli_entry.command = alias->alias;
			alias->cli_entry.usage = "Aliased CLI Command\n";

			ast_cli_register(&alias->cli_entry);
			ao2_link(cli_aliases, alias);
			ast_verbose(VERBOSE_PREFIX_2 "Aliased CLI command '%s' to '%s'\n", v1->name, v1->value);
			ao2_ref(alias, -1);
		}
	}

	ast_config_destroy(cfg);

	return;
}

/*! \brief Function called to reload the module */
static int reload_module(void)
{
	load_config(1);
	return 0;
}
コード例 #17
0
/*
 * This is testing code for astobj
 */
static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ao2_container *c1;
	struct ao2_container *c2;
	int i, lim;
	char *obj;
	static int prof_id = -1;
	struct ast_cli_args fake_args = { a->fd, 0, NULL };

	switch (cmd) {
	case CLI_INIT:
		e->command = "astobj2 test";
		e->usage = "Usage: astobj2 test <num>\n"
			   "       Runs astobj2 test. Creates 'num' objects,\n"
			   "       and test iterators, callbacks and maybe other stuff\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != 3) {
		return CLI_SHOWUSAGE;
	}

	if (prof_id == -1) {
		prof_id = ast_add_profile("ao2_alloc", 0);
	}

	ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
	lim = atoi(a->argv[2]);
	ast_cli(a->fd, "called astobj_test\n");

	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
	/*
	 * Allocate a list container.
	 */
	c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
		NULL /* no callback */, "test");
	ast_cli(a->fd, "container allocated as %p\n", c1);

	/*
	 * fill the container with objects.
	 * ao2_alloc() gives us a reference which we pass to the
	 * container when we do the insert.
	 */
	for (i = 0; i < lim; i++) {
		ast_mark(prof_id, 1 /* start */);
		obj = ao2_t_alloc(80, NULL,"test");
		ast_mark(prof_id, 0 /* stop */);
		ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
		sprintf(obj, "-- this is obj %d --", i);
		ao2_link(c1, obj);
		/* At this point, the refcount on obj is 2 due to the allocation
		 * and linking. We can go ahead and reduce the refcount by 1
		 * right here so that when the container is unreffed later, the
		 * objects will be freed
		 */
		ao2_t_ref(obj, -1, "test");
	}

	ast_cli(a->fd, "testing callbacks\n");
	ao2_t_callback(c1, 0, print_cb, a, "test callback");

	ast_cli(a->fd, "testing container cloning\n");
	c2 = ao2_container_clone(c1, 0);
	if (ao2_container_count(c1) != ao2_container_count(c2)) {
		ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
	}
	ao2_t_callback(c2, 0, print_cb, a, "test callback");

	ast_cli(a->fd, "testing iterators, remove every second object\n");
	{
		struct ao2_iterator ai;
		int x = 0;

		ai = ao2_iterator_init(c1, 0);
		while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
			ast_cli(a->fd, "iterator on <%s>\n", obj);
			if (x++ & 1)
				ao2_t_unlink(c1, obj,"test");
			ao2_t_ref(obj, -1,"test");
		}
		ao2_iterator_destroy(&ai);
		ast_cli(a->fd, "testing iterators again\n");
		ai = ao2_iterator_init(c1, 0);
		while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
			ast_cli(a->fd, "iterator on <%s>\n", obj);
			ao2_t_ref(obj, -1,"test");
		}
		ao2_iterator_destroy(&ai);
	}

	ast_cli(a->fd, "testing callbacks again\n");
	ao2_t_callback(c1, 0, print_cb, a, "test callback");

	ast_verbose("now you should see an error and possible assertion failure messages:\n");
	ao2_t_ref(&i, -1, "");	/* i is not a valid object so we print an error here */

	ast_cli(a->fd, "destroy container\n");
	ao2_t_ref(c1, -1, "");	/* destroy container */
	ao2_t_ref(c2, -1, "");	/* destroy container */
	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
	return CLI_SUCCESS;
}