Exemplo n.º 1
0
/*!
 * \brief Retrieve a ast_sip_contact_status object from sorcery creating
 *        one if not found.
 */
struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (status) {
		return status;
	}

	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (!status) {
		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s\n",
			contact->uri);
		return NULL;
	}

	status->status = UNKNOWN;
	status->rtt_start = ast_tv(0, 0);
	status->rtt = 0;

	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return NULL;
	}

	return status;
}
Exemplo n.º 2
0
/*!
 * \internal
 * \brief Initialize the start time on a contact status so the round
 *        trip time can be calculated upon a valid response.
 */
static void init_start_time(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;
	struct ast_sip_contact_status *update;

	status = ast_res_pjsip_find_or_create_contact_status(contact);
	if (!status) {
		ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(status));
	if (!update) {
		ast_log(LOG_ERROR, "Unable to copy ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	update->status = status->status;
	update->last_status = status->last_status;
	update->rtt = status->rtt;
	update->rtt_start = ast_tvnow();

	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
			contact->uri);
	}

	ao2_ref(status, -1);
	ao2_ref(update, -1);
}
Exemplo n.º 3
0
/*!
 * \brief Retrieve a ast_sip_contact_status object from sorcery creating
 *        one if not found.
 */
struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;
	SCOPED_MUTEX(lock, &creation_lock);

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (status) {
		return status;
	}

	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (!status) {
		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
			contact->aor, contact->uri);
		return NULL;
	}

	ast_string_field_set(status, uri, contact->uri);
	status->rtt_start = ast_tv(0, 0);
	status->rtt = 0;

	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return NULL;
	}

	ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
		"+1", 1.0, ast_sip_get_contact_status_label(status->status));

	return status;
}
Exemplo n.º 4
0
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
{
	const char *family_prefix = data;
	size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */
	char family[family_len + 1];
	char tree[prefix_len + 1];
	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
	struct ast_db_entry *entry;

	snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix);
	snprintf(family, sizeof(family), "%s/%s", family_prefix, type);

	if (!(entries = ast_db_gettree_by_prefix(family, tree))) {
		return;
	}

	for (entry = entries; entry; entry = entry->next) {
		/* The key in the entry includes the family, so we need to strip it out */
		const char *key = entry->key + family_len + 2;
		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
		struct ast_json_error error;
		RAII_VAR(void *, object, NULL, ao2_cleanup);
		RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);

		if (!(json = ast_json_load_string(entry->data, &error))
		   || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
		   || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
		   || !(object = ast_sorcery_alloc(sorcery, type, key))
		   || ast_sorcery_objectset_apply(sorcery, object, objset)) {
			return;
		}

		ao2_link(objects, object);
	}
}
Exemplo n.º 5
0
static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
{
	const char *prefix = data;
	char family[strlen(prefix) + strlen(type) + 2];
	RAII_VAR(char *, value, NULL, ast_free_ptr);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	struct ast_json_error error;
	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
	void *object = NULL;

	snprintf(family, sizeof(family), "%s/%s", prefix, type);

	if (ast_db_get_allocated(family, id, &value)
		|| !(json = ast_json_load_string(value, &error))
		|| (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
		|| !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
		|| !(object = ast_sorcery_alloc(sorcery, type, id))
		|| ast_sorcery_objectset_apply(sorcery, object, objset)) {
		ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id);
		ao2_cleanup(object);
		return NULL;
	}

	return object;
}
Exemplo n.º 6
0
/*!
 * \internal
 * \brief Initialize the start time on a contact status so the round
 *        trip time can be calculated upon a valid response.
 */
static void init_start_time(const struct ast_sip_contact *contact)
{
	RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup);

	status = ast_res_pjsip_find_or_create_contact_status(contact);
	if (!status) {
		ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(status));
	if (!update) {
		ast_log(LOG_ERROR, "Unable to copy ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	ast_string_field_set(status, uri, contact->uri);
	update->status = status->status;
	update->last_status = status->last_status;
	update->rtt = status->rtt;
	update->rtt_start = ast_tvnow();

	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
			contact->uri);
	}
}
Exemplo n.º 7
0
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
		struct timeval expiration_time, const char *path_info, const char *user_agent)
{
	char name[MAX_OBJECT_FIELD * 2 + 3];
	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);

	snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri);

	if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) {
		return -1;
	}

	ast_string_field_set(contact, uri, uri);
	contact->expiration_time = expiration_time;
	contact->qualify_frequency = aor->qualify_frequency;
	contact->authenticate_qualify = aor->authenticate_qualify;
	if (path_info && aor->support_path) {
		ast_string_field_set(contact, path, path_info);
	}

	if (!ast_strlen_zero(aor->outbound_proxy)) {
		ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
	}

	if (!ast_strlen_zero(user_agent)) {
		ast_string_field_set(contact, user_agent, user_agent);
	}

	return ast_sorcery_create(ast_sip_get_sorcery(), contact);
}
Exemplo n.º 8
0
struct ast_mwi_mailbox_object *ast_mwi_mailbox_alloc(const char *mailbox_id)
{
	if (ast_strlen_zero(mailbox_id)) {
		return NULL;
	}

	return ast_sorcery_alloc(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
}
Exemplo n.º 9
0
int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
		struct timeval expiration_time, const char *path_info, const char *user_agent,
		const char *via_addr, int via_port, const char *call_id,
		struct ast_sip_endpoint *endpoint)
{
	struct ast_sip_contact *contact;
	int res;
	char name[MAX_OBJECT_FIELD * 2 + 3];
	char hash[33];

	ast_md5_hash(hash, uri);
	snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash);

	contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name);
	if (!contact) {
		return -1;
	}

	ast_string_field_set(contact, uri, uri);
	contact->expiration_time = expiration_time;
	contact->qualify_frequency = aor->qualify_frequency;
	contact->qualify_timeout = aor->qualify_timeout;
	contact->authenticate_qualify = aor->authenticate_qualify;
	if (path_info && aor->support_path) {
		ast_string_field_set(contact, path, path_info);
	}

	if (!ast_strlen_zero(aor->outbound_proxy)) {
		ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
	}

	if (!ast_strlen_zero(user_agent)) {
		ast_string_field_set(contact, user_agent, user_agent);
	}

	if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
		ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME);
	}

	if (!ast_strlen_zero(via_addr)) {
		ast_string_field_set(contact, via_addr, via_addr);
	}
	contact->via_port = via_port;

	if (!ast_strlen_zero(call_id)) {
		ast_string_field_set(contact, call_id, call_id);
	}

	contact->endpoint = ao2_bump(endpoint);

	if (endpoint) {
		ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint));
	}

	res = ast_sorcery_create(ast_sip_get_sorcery(), contact);
	ao2_ref(contact, -1);
	return res;
}
Exemplo n.º 10
0
/*! \brief Custom handler for permanent URIs */
static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
	struct ast_sip_aor *aor = obj;
	const char *aor_id = ast_sorcery_object_get_id(aor);
	char *contacts;
	char *contact_uri;

	if (ast_strlen_zero(var->value)) {
		return 0;
	}

	contacts = ast_strdupa(var->value);
	while ((contact_uri = ast_strip(strsep(&contacts, ",")))) {
		struct ast_sip_contact *contact;
		struct ast_sip_contact_status *status;
		char hash[33];
		char contact_id[strlen(aor_id) + sizeof(hash) + 2];

		if (ast_strlen_zero(contact_uri)) {
			continue;
		}

		if (ast_sip_validate_uri_length(contact_uri)) {
			ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit: %s\n", contact_uri);
			return -1;
		}

		if (!aor->permanent_contacts) {
			aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
				AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
			if (!aor->permanent_contacts) {
				return -1;
			}
		}

		ast_md5_hash(hash, contact_uri);
		snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash);
		contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
		if (!contact) {
			return -1;
		}

		ast_string_field_set(contact, uri, contact_uri);

		status = ast_res_pjsip_find_or_create_contact_status(contact);
		if (!status) {
			ao2_ref(contact, -1);
			return -1;
		}
		ao2_ref(status, -1);

		ao2_link(aor->permanent_contacts, contact);
		ao2_ref(contact, -1);
	}

	return 0;
}
Exemplo n.º 11
0
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
{
	const char *prefix = data;
	char family[strlen(prefix) + strlen(type) + 2];
	char tree[strlen(regex) + 1];
	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
	regex_t expression;
	struct ast_db_entry *entry;

	snprintf(family, sizeof(family), "%s/%s", prefix, type);

	if (regex[0] == '^') {
		/*
		 * For performance reasons, try to create an astDB prefix
		 * pattern from the regex to reduce the number of entries
		 * retrieved from astDB for regex to then match.
		 */
		if (make_astdb_prefix_pattern(tree, regex)) {
			return;
		}
	} else {
		tree[0] = '\0';
	}

	if (!(entries = ast_db_gettree(family, tree))
		|| regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
		return;
	}

	for (entry = entries; entry; entry = entry->next) {
		/* The key in the entry includes the family, so we need to strip it out for regex purposes */
		const char *key = entry->key + strlen(family) + 2;
		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
		struct ast_json_error error;
		RAII_VAR(void *, object, NULL, ao2_cleanup);
		RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);

		if (regexec(&expression, key, 0, NULL, 0)) {
			continue;
		} else if (!(json = ast_json_load_string(entry->data, &error))
			|| (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
			|| !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
			|| !(object = ast_sorcery_alloc(sorcery, type, key))
			|| ast_sorcery_objectset_apply(sorcery, object, objset)) {
			regfree(&expression);
			return;
		}

		ao2_link(objects, object);
	}

	regfree(&expression);
}
Exemplo n.º 12
0
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */
static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects)
{
	const char *prefix = data;
	char family[strlen(prefix) + strlen(type) + 2];
	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
	struct ast_db_entry *entry;

	snprintf(family, sizeof(family), "%s/%s", prefix, type);

	if (!(entries = ast_db_gettree(family, NULL))) {
		return NULL;
	}

	for (entry = entries; entry; entry = entry->next) {
		const char *key = entry->key + strlen(family) + 2;
		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
		struct ast_json_error error;
		RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy);
		void *object = NULL;

		if (!(json = ast_json_load_string(entry->data, &error))) {
			return NULL;
		}

		if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) {
			return NULL;
		}

		existing = sorcery_astdb_filter_objectset(existing, sorcery, type);

		if (fields && !ast_variable_lists_match(existing, fields, 0)) {
			continue;
		}

		if (!(object = ast_sorcery_alloc(sorcery, type, key)) ||
			ast_sorcery_objectset_apply(sorcery, object, existing)) {
			ao2_cleanup(object);
			return NULL;
		}

		if (!objects) {
			return object;
		}

		ao2_link(objects, object);
		ao2_cleanup(object);
	}

	return NULL;
}
Exemplo n.º 13
0
static int create_artificial_endpoint(void)
{
	artificial_endpoint = ast_sorcery_alloc(ast_sip_get_sorcery(), "endpoint", NULL);
	if (!artificial_endpoint) {
		return -1;
	}

	AST_VECTOR_INIT(&artificial_endpoint->inbound_auths, 1);
	/* Pushing a bogus value into the vector will ensure that
	 * the proper size of the vector is returned. This value is
	 * not actually used anywhere
	 */
	AST_VECTOR_APPEND(&artificial_endpoint->inbound_auths, ast_strdup("artificial-auth"));
	return 0;
}
Exemplo n.º 14
0
/*!
 * \brief Retrieve a ast_sip_contact_status object from sorcery creating
 *        one if not found.
 */
struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status;
	SCOPED_MUTEX(lock, &creation_lock);

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (status) {
		return status;
	}

	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));
	if (!status) {
		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
			contact->aor, contact->uri);
		return NULL;
	}

	ast_string_field_set(status, uri, contact->uri);
	status->rtt_start = ast_tv(0, 0);
	status->rtt = 0;

	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return NULL;
	}

	/* The permanent contact added after asterisk start should be qualified. */
	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED) && ast_tvzero(contact->expiration_time)) {
		/*
		 * The FULLY_BOOTED to filter out contacts that already existed when asterisk started.
		 * The zero expiration_time to select only permanent contacts.
		 */
		ao2_ref((struct ast_sip_contact *) contact, +1);
		if (ast_sip_push_task(NULL, qualify_and_schedule_aor_contact, (struct ast_sip_contact *) contact)) {
			ao2_ref((struct ast_sip_contact *) contact, -1);
		}
	}

	ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
		"+1", 1.0, ast_sip_get_contact_status_label(status->status));

	return status;
}
Exemplo n.º 15
0
/*!
 * \internal
 * \brief Update an ast_sip_contact_status's elements.
 */
static void update_contact_status(const struct ast_sip_contact *contact,
	enum ast_sip_contact_status_type value)
{
	struct ast_sip_contact_status *status;
	struct ast_sip_contact_status *update;

	status = ast_res_pjsip_find_or_create_contact_status(contact);
	if (!status) {
		ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(status));
	if (!update) {
		ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	update->last_status = status->status;
	update->status = value;

	/* if the contact is available calculate the rtt as
	   the diff between the last start time and "now" */
	update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ?
		ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;

	update->rtt_start = ast_tv(0, 0);

	ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
		"Contact: %s\r\n"
			"Status: %s\r\n"
			"RTT: %" PRId64,
		ast_sorcery_object_get_id(update),
		ast_sip_get_contact_status_label(update->status),
		update->rtt);

	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
			contact->uri);
	}

	ao2_ref(status, -1);
	ao2_ref(update, -1);
}
Exemplo n.º 16
0
static struct ast_sip_auth *alloc_artificial_auth(char *default_realm)
{
	struct ast_sip_auth *fake_auth;

	fake_auth = ast_sorcery_alloc(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE,
		"artificial");
	if (!fake_auth) {
		return NULL;
	}

	ast_string_field_set(fake_auth, realm, default_realm);
	ast_string_field_set(fake_auth, auth_user, "");
	ast_string_field_set(fake_auth, auth_pass, "");
	fake_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL;

	return fake_auth;
}
Exemplo n.º 17
0
/*! \brief Custom handler for permanent URIs */
static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
	struct ast_sip_aor *aor = obj;
	const char *aor_id = ast_sorcery_object_get_id(aor);
	char *contacts;
	char *contact_uri;

	if (ast_strlen_zero(var->value)) {
		return 0;
	}

	contacts = ast_strdupa(var->value);
	while ((contact_uri = strsep(&contacts, ","))) {
		struct ast_sip_contact *contact;
		char contact_id[strlen(aor_id) + strlen(contact_uri) + 2 + 1];

		if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, contact_uri)) {
			ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n",
				ast_sorcery_object_get_id(aor), contact_uri);
			return -1;
		}

		if (!aor->permanent_contacts) {
			aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
				AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
			if (!aor->permanent_contacts) {
				return -1;
			}
		}

		snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, contact_uri);
		contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
		if (!contact) {
			return -1;
		}

		ast_string_field_set(contact, uri, contact_uri);
		ao2_link(aor->permanent_contacts, contact);
		ao2_ref(contact, -1);
	}

	return 0;
}
Exemplo n.º 18
0
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */
static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects)
{
	const char *prefix = data;
	char family[strlen(prefix) + strlen(type) + 2];
	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
	RAII_VAR(struct ast_json *, criteria, NULL, ast_json_unref);
	struct ast_db_entry *entry;

	snprintf(family, sizeof(family), "%s/%s", prefix, type);

	if (!(entries = ast_db_gettree(family, NULL)) || (fields && !(criteria = sorcery_objectset_to_json(fields)))) {
		return NULL;
	}

	for (entry = entries; entry; entry = entry->next) {
		const char *key = entry->key + strlen(family) + 2;
		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
		struct ast_json_error error;
		RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
		void *object = NULL;

		if (!(json = ast_json_load_string(entry->data, &error))) {
			return NULL;
		} else if (criteria && !sorcery_json_equal(json, criteria)) {
			continue;
		} else if (!(objset = sorcery_json_to_objectset(json)) ||
			!(object = ast_sorcery_alloc(sorcery, type, key)) ||
			ast_sorcery_objectset_apply(sorcery, object, objset)) {
			ao2_cleanup(object);
			return NULL;
		}

		if (!objects) {
			return object;
		}

		ao2_link(objects, object);
		ao2_cleanup(object);
	}

	return NULL;
}
static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
{
	const char *family = data;
	RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
	RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
	void *object = NULL;

	if (!(objectset = ast_load_realtime_fields(family, fields))) {
		return NULL;
	}

	objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);

	if (!id
		|| !(object = ast_sorcery_alloc(sorcery, type, id->value))
		|| ast_sorcery_objectset_apply(sorcery, object, objectset)) {
		return NULL;
	}

	return object;
}
Exemplo n.º 20
0
static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
{
	const char *prefix = data;
	char family[strlen(prefix) + strlen(type) + 2];
	RAII_VAR(char *, value, NULL, ast_free_ptr);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	struct ast_json_error error;
	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
	void *object = NULL;

	snprintf(family, sizeof(family), "%s/%s", prefix, type);

	if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) ||
		!(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, id)) ||
		ast_sorcery_objectset_apply(sorcery, object, objset)) {
		ao2_cleanup(object);
		return NULL;
	}

	return object;
}
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
{
	const char *family = data;
	RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy);
	RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy);
	struct ast_category *row = NULL;

	if (!fields) {
		char field[strlen(UUID_FIELD) + 6], value[2];

		/* If no fields have been specified we want all rows, so trick realtime into doing it */
		snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
		snprintf(value, sizeof(value), "%%");

		if (!(all = ast_variable_new(field, value, ""))) {
			return;
		}

		fields = all;
	}

	if (!(rows = ast_load_realtime_multientry_fields(family, fields))) {
		return;
	}

	while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) {
		struct ast_variable *objectset = ast_category_detach_variables(row);
		RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
		RAII_VAR(void *, object, NULL, ao2_cleanup);

		objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);

		if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) {
			ao2_link(objects, object);
		}

		ast_variables_destroy(objectset);
	}
}
Exemplo n.º 22
0
/*!
 * \internal
 * \brief Update an ast_sip_contact_status's elements.
 */
static void update_contact_status(const struct ast_sip_contact *contact,
	enum ast_sip_contact_status_type value)
{
	struct ast_sip_contact_status *status;
	struct ast_sip_contact_status *update;

	status = find_or_create_contact_status(contact);
	if (!status) {
		return;
	}

	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(status));
	if (!update) {
		ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n",
			contact->uri);
		ao2_ref(status, -1);
		return;
	}

	update->status = value;

	/* if the contact is available calculate the rtt as
	   the diff between the last start time and "now" */
	update->rtt = update->status == AVAILABLE ?
		ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;

	update->rtt_start = ast_tv(0, 0);

	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
			contact->uri);
	}

	ao2_ref(update, -1);
	ao2_ref(status, -1);
}
Exemplo n.º 23
0
/*!
 * \internal
 * \brief Update an ast_sip_contact_status's elements.
 */
static void update_contact_status(const struct ast_sip_contact *contact,
	enum ast_sip_contact_status_type value, int is_contact_refresh)
{
	RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup);

	status = ast_res_pjsip_find_or_create_contact_status(contact);
	if (!status) {
		ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	if (is_contact_refresh
		&& status->status == CREATED) {
		/*
		 * The contact status hasn't been updated since creation
		 * and we don't want to re-send a created status.
		 */
		if (contact->qualify_frequency
			|| status->rtt_start.tv_sec > 0) {
			/* Ignore, the status will change soon. */
			return;
		}

		/*
		 * Convert to a regular contact status update
		 * because the status may never change.
		 */
		is_contact_refresh = 0;
		value = UNKNOWN;
	}

	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(status));
	if (!update) {
		ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status for contact %s\n",
			contact->uri);
		return;
	}

	ast_string_field_set(update, uri, contact->uri);

	if (is_contact_refresh) {
		/* Copy everything just to set the refresh flag. */
		update->status = status->status;
		update->last_status = status->last_status;
		update->rtt = status->rtt;
		update->rtt_start = status->rtt_start;
		update->refresh = 1;
	} else {
		update->last_status = status->status;
		update->status = value;

		/*
		 * if the contact is available calculate the rtt as
		 * the diff between the last start time and "now"
		 */
		update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0
			? ast_tvdiff_us(ast_tvnow(), status->rtt_start)
			: 0;
		update->rtt_start = ast_tv(0, 0);

		ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
			"Contact: %s\r\n"
			"Status: %s\r\n"
			"RTT: %" PRId64,
			ast_sorcery_object_get_id(update),
			ast_sip_get_contact_status_label(update->status),
			update->rtt);
	}

	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
			contact->uri);
	}
}
Exemplo n.º 24
0
void ast_ari_asterisk_update_object(struct ast_variable *headers, struct ast_ari_asterisk_update_object_args *args, struct ast_ari_response *response)
{
	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
	RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
	RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup);
	struct ast_json *fields;
	struct ast_variable *update_set = NULL;
	int created = 0;

	sorcery = ast_sorcery_retrieve_by_module_name(args->config_class);
	if (!sorcery) {
		ast_ari_response_error(
			response, 404, "Not Found",
			"configClass '%s' not found",
			args->config_class);
		return;
	}

	object_type = ast_sorcery_get_object_type(sorcery, args->object_type);
	if (!object_type) {
		ast_ari_response_error(
			response, 404, "Not Found",
			"objectType '%s' not found",
			args->object_type);
		return;
	}

	sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args->object_type, args->id);
	if (!sorcery_obj) {
		ast_debug(5, "Sorcery object '%s' does not exist; creating it\n", args->id);
		sorcery_obj = ast_sorcery_alloc(sorcery, args->object_type, args->id);
		if (!sorcery_obj) {
			ast_ari_response_alloc_failed(response);
			return;
		}

		created = 1;
	} else {
		void *copy;

		copy = ast_sorcery_copy(sorcery, sorcery_obj);
		if (!copy) {
			ast_ari_response_alloc_failed(response);
			return;
		}

		ao2_ref(sorcery_obj, -1);
		sorcery_obj = copy;
	}

	fields = ast_json_object_get(args->fields, "fields");
	if (!fields && !created) {
		/* Whoops. We need data. */
		ast_ari_response_error(
			response, 400, "Bad request",
			"Fields must be provided to update object '%s'",
			args->id);
		return;
	} else if (fields) {
		size_t i;

		for (i = 0; i < ast_json_array_size(fields); i++) {
			struct ast_variable *new_var;
			struct ast_json *json_value = ast_json_array_get(fields, i);

			if (!json_value) {
				continue;
			}

			new_var = ast_variable_new(
				ast_json_string_get(ast_json_object_get(json_value, "attribute")),
				ast_json_string_get(ast_json_object_get(json_value, "value")),
				"");
			if (!new_var) {
				ast_variables_destroy(update_set);
				ast_ari_response_alloc_failed(response);
				return;
			}
			ast_variable_list_append(&update_set, new_var);
		}
	}

	/* APPLY! Note that a NULL update_set is fine (and necessary), as it
	 * will force validation on a newly created object.
	 */
	if (ast_sorcery_objectset_apply(sorcery, sorcery_obj, update_set)) {
		ast_variables_destroy(update_set);
		ast_ari_response_error(
			response, 400, "Bad request",
			"%s of object '%s' failed field value validation",
			created ? "Creation" : "Update",
			args->id);
		return;
	}

	ast_variables_destroy(update_set);

	if (created) {
		if (ast_sorcery_create(sorcery, sorcery_obj)) {
			ast_ari_response_error(
				response, 403, "Forbidden",
				"Cannot create sorcery objects of type '%s'",
				args->object_type);
			return;
		}
	} else {
		if (ast_sorcery_update(sorcery, sorcery_obj)) {
			ast_ari_response_error(
				response, 403, "Forbidden",
				"Cannot update sorcery objects of type '%s'",
				args->object_type);
			return;
		}
	}

	return_sorcery_object(sorcery, sorcery_obj, response);
}