static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata)
{
	char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN];
	struct ast_sip_endpoint *endpoint;
	RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);

	if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) {
		return NULL;
	}

	/* Attempt to find the endpoint given the name and domain provided */
	snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name);
	if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
		goto done;
	}

	/* See if an alias exists for the domain provided */
	if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
		snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain);
		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
			goto done;
		}
	}

	/* See if the transport this came in on has a provided domain */
	if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) &&
		(transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) &&
		!ast_strlen_zero(transport->domain)) {
		snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain);
		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
			goto done;
		}
	}

	/* Fall back to no domain */
	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);

done:
	if (endpoint) {
		if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) {
			ao2_ref(endpoint, -1);
			return NULL;
		}
		ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));
	} else {
		ast_debug(3, "Could not identify endpoint by username '%s'\n", endpoint_name);
	}
	return endpoint;
}
示例#2
0
static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint,
					 struct ast_sip_ami *ami)
{
	RAII_VAR(struct ast_str *, buf, NULL, ast_free);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);

	if (ast_strlen_zero(endpoint->transport)) {
		return 0;
	}

	buf = ast_sip_create_ami_event("TransportDetail", ami);
	if (!buf) {
		return -1;
	}

	transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
		endpoint->transport);
	if (!transport) {
		astman_send_error_va(ami->s, ami->m, "Unable to retrieve "
				     "transport %s\n", endpoint->transport);
		return -1;
	}

	sip_transport_to_ami(transport, &buf);

	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
		       ast_sorcery_object_get_id(endpoint));

	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
	ami->count++;

	return 0;
}
示例#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;

	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;
}
示例#4
0
static int format_contact_status(void *obj, void *arg, int flags)
{
	struct ast_sip_contact_wrapper *wrapper = obj;
	struct ast_sip_contact *contact = wrapper->contact;
	struct ast_sip_ami *ami = arg;
	struct ast_sip_contact_status *status;
	struct ast_str *buf;
	const struct ast_sip_endpoint *endpoint = ami->arg;

	buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
	if (!buf) {
		return -1;
	}

	status = ast_sorcery_retrieve_by_id(
		ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));

	ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
	ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
	ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status));
	if (status->status == UNKNOWN) {
		ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
	} else {
		ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
	}
	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
			ast_sorcery_object_get_id(endpoint));
	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
	ami->count++;
	
	ast_free(buf);
	ao2_cleanup(status);
	return 0;
}
示例#5
0
static int cli_contact_print_body(void *obj, void *arg, int flags)
{
	struct ast_sip_contact_wrapper *wrapper = obj;
	struct ast_sip_contact *contact = wrapper->contact;
	struct ast_sip_cli_context *context = arg;
	int indent;
	int flexwidth;
	const char *contact_id = ast_sorcery_object_get_id(contact);
	const char *hash_start = contact_id + strlen(contact->aor) + 2;
	struct ast_sip_contact_status *status;

	ast_assert(contact->uri != NULL);
	ast_assert(context->output_buffer != NULL);

	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, contact_id);

	indent = CLI_INDENT_TO_SPACES(context->indent_level);
	flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1;

	ast_str_append(&context->output_buffer, 0, "%*s:  %s/%-*.*s %-10.10s %-7.7s %11.3f\n",
		indent,
		"Contact",
		contact->aor,
		flexwidth, flexwidth,
		contact->uri,
		hash_start,
		ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN),
		(status && (status->status != UNKNOWN) ? ((long long) status->rtt) / 1000.0 : NAN));

	ao2_cleanup(status);
	return 0;
}
static int get_write_timeout(void)
{
	int write_timeout = -1;
	struct ao2_container *transport_states;

	transport_states = ast_sip_get_transport_states();

	if (transport_states) {
		struct ao2_iterator it_transport_states = ao2_iterator_init(transport_states, 0);
		struct ast_sip_transport_state *transport_state;

		for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) {
			struct ast_sip_transport *transport;
			if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) {
				continue;
			}
			transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id);
			ast_debug(5, "Found %s transport with write timeout: %d\n",
				transport->type == AST_TRANSPORT_WS ? "WS" : "WSS",
				transport->write_timeout);
			write_timeout = MAX(write_timeout, transport->write_timeout);
		}
		ao2_iterator_destroy(&it_transport_states);
		ao2_cleanup(transport_states);
	}

	if (write_timeout < 0) {
		write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
	}

	ast_debug(1, "Write timeout for WS/WSS transports: %d\n", write_timeout);
	return write_timeout;
}
示例#7
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;
}
示例#8
0
const struct ast_mwi_mailbox_object *ast_mwi_mailbox_get(const char *mailbox_id)
{
	if (ast_strlen_zero(mailbox_id)) {
		return NULL;
	}

	return ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
}
static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata)
{
	char domain_name[64], id[AST_UUID_STR_LEN];
	struct ast_sip_endpoint *endpoint;
	RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);

	if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) {
		return NULL;
	}

	/* Attempt to find the endpoint given the name and domain provided */
	snprintf(id, sizeof(id), "anonymous@%s", domain_name);
	if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
		goto done;
	}

	/* See if an alias exists for the domain provided */
	if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
		snprintf(id, sizeof(id), "anonymous@%s", alias->domain);
		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
			goto done;
		}
	}

	/* See if the transport this came in on has a provided domain */
	if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) &&
		(transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) &&
		!ast_strlen_zero(transport->domain)) {
		snprintf(id, sizeof(id), "anonymous@%s", transport->domain);
		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
			goto done;
		}
	}

	/* Fall back to no domain */
	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous");

done:
	if (endpoint) {
		ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint));
	}
	return endpoint;
}
示例#10
0
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
{
	struct ast_sip_contact_wrapper *wrapper = obj;
	struct ast_sip_contact *contact = wrapper->contact;
	struct ast_sip_ami *ami = arg;
	struct ast_sip_contact_status *status;
	struct ast_str *buf;
	const struct ast_sip_endpoint *endpoint = ami->arg;

	buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
	if (!buf) {
		return -1;
	}

	status = ast_sorcery_retrieve_by_id(
		ast_sip_get_sorcery(), CONTACT_STATUS,
		ast_sorcery_object_get_id(contact));

	ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
	ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
	ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
	ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec);
	if (!ast_strlen_zero(contact->via_addr)) {
		ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
		if (contact->via_port) {
			ast_str_append(&buf, 0, ":%d", contact->via_port);
		}
		ast_str_append(&buf, 0, "\r\n");
	}
	if (!ast_strlen_zero(contact->call_id)) {
		ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
	}
	ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status));
	if (status->status == UNKNOWN) {
		ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
	} else {
		ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
	}
	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
			endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));

	ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
	ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
	ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
	ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
	ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
	ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);

	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
	ami->count++;
	
	ast_free(buf);
	ao2_cleanup(status);
	return 0;
}
示例#11
0
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
{
	void *contact_status_obj;

	contact_status_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact));
	if (contact_status_obj) {
		ast_sorcery_delete(ast_sip_get_sorcery(), contact_status_obj);
		ao2_ref(contact_status_obj, -1);
	}

	return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
}
示例#12
0
static void delete_contact_status(const struct ast_sip_contact *contact)
{
	struct ast_sip_contact_status *status = ast_sorcery_retrieve_by_id(
		ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact));

	if (!status) {
		return;
	}

	ast_sorcery_delete(ast_sip_get_sorcery(), status);
	ao2_ref(status, -1);
}
static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata)
{
	char domain_name[DOMAIN_NAME_LEN + 1];
	struct ast_sip_endpoint *endpoint;

	if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) {
		return NULL;
	}

	if (!ast_sip_get_disable_multi_domain()) {
		struct ast_sip_domain_alias *alias;
		struct ao2_container *transport_states;
		struct ast_sip_transport_state *transport_state = NULL;
		struct ast_sip_transport *transport = NULL;
		char id[sizeof("anonymous@") + DOMAIN_NAME_LEN];

		/* Attempt to find the endpoint given the name and domain provided */
		snprintf(id, sizeof(id), "anonymous@%s", domain_name);
		endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
		if (endpoint) {
			goto done;
		}

		/* See if an alias exists for the domain provided */
		alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias",
			domain_name);
		if (alias) {
			snprintf(id, sizeof(id), "anonymous@%s", alias->domain);
			ao2_ref(alias, -1);
			endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
			if (endpoint) {
				goto done;
			}
		}

		/* See if the transport this came in on has a provided domain */
		if ((transport_states = ast_sip_get_transport_states())
			&& (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata))
			&& (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))
			&& !ast_strlen_zero(transport->domain)) {
			snprintf(id, sizeof(id), "anonymous@%s", transport->domain);
			endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
		}
		ao2_cleanup(transport);
		ao2_cleanup(transport_state);
		ao2_cleanup(transport_states);
		if (endpoint) {
			goto done;
		}
	}

	/* Fall back to no domain */
	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous");

done:
	if (endpoint) {
		ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint));
	}
	return endpoint;
}
示例#14
0
static char *find_aor_name(const char *username, const char *domain, const char *aors)
{
	char *configured_aors;
	char *aors_buf;
	char *aor_name;
	char *id_domain;
	struct ast_sip_domain_alias *alias;

	id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
	sprintf(id_domain, "%s@%s", username, domain);

	aors_buf = ast_strdupa(aors);

	/* Look for exact match on username@domain */
	configured_aors = aors_buf;
	while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
		if (match_aor(aor_name, id_domain)) {
			return ast_strdup(aor_name);
		}
	}

	/* If there's a domain alias, look for exact match on username@domain_alias */
	alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
	if (alias) {
		char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);

		sprintf(id_domain, "%s@%s", username, alias->domain);
		ao2_cleanup(alias);

		configured_aors = strcpy(aors_buf, aors);/* Safe */
		while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
			if (match_aor(aor_name, id_domain_alias)) {
				return ast_strdup(aor_name);
			}
		}
	}

	if (ast_strlen_zero(username)) {
		/* No username, no match */
		return NULL;
	}

	/* Look for exact match on username only */
	configured_aors = strcpy(aors_buf, aors);/* Safe */
	while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
		if (match_aor(aor_name, username)) {
			return ast_strdup(aor_name);
		}
	}

	return NULL;
}
示例#15
0
/*!
 * \internal
 * \brief Attempt to qualify the contact
 *
 * \details Sends a SIP OPTIONS request to the given contact in order to make
 *         sure that contact is available.
 */
static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact)
{
	pjsip_tx_data *tdata;
	RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup);

	if (endpoint) {
		endpoint_local = ao2_bump(endpoint);
	} else {
		if (!ast_strlen_zero(contact->endpoint_name)) {
			endpoint_local = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", contact->endpoint_name);
		}
		if (!endpoint_local) {
			endpoint_local = find_an_endpoint(contact);
		}
		if (!endpoint_local) {
			ast_log(LOG_WARNING, "Unable to find an endpoint to qualify contact %s. Deleting this contact\n",
				contact->uri);
			contact_deleted(contact);
			return -1;
		}
	}

	if (ast_sip_create_request("OPTIONS", NULL, endpoint_local, NULL, contact, &tdata)) {
		ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n",
			contact->uri);
		return -1;
	}

	/* If an outbound proxy is specified set it on this request */
	if (!ast_strlen_zero(contact->outbound_proxy) &&
		ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
		pjsip_tx_data_dec_ref(tdata);
		ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
			contact->uri);
		return -1;
	}

	init_start_time(contact);

	ao2_ref(contact, +1);
	if (ast_sip_send_out_of_dialog_request(tdata, endpoint_local, (int)(contact->qualify_timeout * 1000), contact, qualify_contact_cb)
		!= PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
			contact->uri);
		update_contact_status(contact, UNAVAILABLE, 0);
		ao2_ref(contact, -1);
		return -1;
	}

	return 0;
}
示例#16
0
static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
{
	char *configured_aors, *aor_name;
	pjsip_sip_uri *sip_uri;
	char *domain_name;
	RAII_VAR(struct ast_str *, id, NULL, ast_free);

	if (ast_strlen_zero(endpoint->aors)) {
		return NULL;
	}

	sip_uri = pjsip_uri_get_uri(uri);
	domain_name = ast_alloca(sip_uri->host.slen + 1);
	ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);

	configured_aors = ast_strdupa(endpoint->aors);

	/* Iterate the configured AORs to see if the user or the user+domain match */
	while ((aor_name = strsep(&configured_aors, ","))) {
		struct ast_sip_domain_alias *alias = NULL;

		if (!pj_strcmp2(&sip_uri->user, aor_name)) {
			break;
		}

		if (!id && !(id = ast_str_create(sip_uri->user.slen + sip_uri->host.slen + 2))) {
			return NULL;
		}

		ast_str_set(&id, 0, "%.*s@", (int)sip_uri->user.slen, sip_uri->user.ptr);
		if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
			ast_str_append(&id, 0, "%s", alias->domain);
			ao2_cleanup(alias);
		} else {
			ast_str_append(&id, 0, "%s", domain_name);
		}

		if (!strcmp(aor_name, ast_str_buffer(id))) {
			ast_free(id);
			break;
		}
	}

	if (ast_strlen_zero(aor_name)) {
		return NULL;
	}

	return ast_sip_location_retrieve_aor(aor_name);
}
示例#17
0
int ast_mwi_mailbox_update(struct ast_mwi_mailbox_object *mailbox)
{
	const struct ast_mwi_mailbox_object *exists;
	int res;

	exists = ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE,
		ast_sorcery_object_get_id(mailbox));
	if (exists) {
		res = ast_sorcery_update(mwi_sorcery, mailbox);
		ast_mwi_mailbox_unref(exists);
	} else {
		res = ast_sorcery_create(mwi_sorcery, mailbox);
	}
	return res;
}
示例#18
0
/*!
 * \internal
 * \brief Retrieves an endpoint if specified in the given 'to'
 *
 * Expects the given 'to' to be in one of the following formats:
 *      sip[s]:endpoint[/aor]
 *      sip[s]:endpoint[/uri]
 *      sip[s]:uri <-- will use default outbound endpoint
 *
 * If an optional aor is given it will try to find an associated uri
 * to return.  If an optional uri is given then that will be returned,
 * otherwise uri will be NULL.
 *
 * \param to 'From' or 'To' field with possible endpoint
 * \param uri Optional uri to return
 */
static struct ast_sip_endpoint* get_outbound_endpoint(
	const char *to, char **uri)
{
	char *name, *aor_uri;
	struct ast_sip_endpoint* endpoint;
	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);

	name = ast_strdupa(skip_sip(to));

	/* attempt to extract the endpoint name */
	if ((aor_uri = strchr(name, '/'))) {
		/* format was 'endpoint/' */
		*aor_uri++ = '\0';
	} else if ((aor_uri = strchr(name, '@'))) {
		/* format was 'endpoint@' - don't use the rest */
		*aor_uri = '\0';
	}

	/* at this point, if name is not empty then it
	   might be an endpoint, so try to retrieve it */
	if (ast_strlen_zero(name) || !(endpoint = ast_sorcery_retrieve_by_id(
		      ast_sip_get_sorcery(), "endpoint", name))) {
		/* an endpoint was not found, so assume sending directly
		   to a uri and use the default outbound endpoint */
		*uri = ast_strdup(to);
		return ast_sip_default_outbound_endpoint();
	}

	*uri = aor_uri;
	if (*uri) {
		char *end = strchr(*uri, '>');
		if (end) {
			*end++ = '\0';
		}

		/* if what's in 'uri' is a retrievable aor use the uri on it
		   instead, otherwise assume what's there is already a uri*/
		if ((aor = ast_sip_location_retrieve_aor(*uri)) &&
			(contact = ast_sip_location_retrieve_first_aor_contact(aor))) {
			*uri = (char*)contact->uri;
		}
		/* need to copy because underlying uri goes away */
		*uri = ast_strdup(*uri);
	}

	return endpoint;
}
示例#19
0
static int ami_sip_qualify(struct mansession *s, const struct message *m)
{
	const char *endpoint_name = astman_get_header(m, "Endpoint");
	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
	char *aors;
	char *aor_name;

	if (ast_strlen_zero(endpoint_name)) {
		astman_send_error(s, m, "Endpoint parameter missing.");
		return 0;
	}

	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
		endpoint_name);
	if (!endpoint) {
		astman_send_error(s, m, "Unable to retrieve endpoint\n");
		return 0;
	}

	/* send a qualify for all contacts registered with the endpoint */
	if (ast_strlen_zero(endpoint->aors)) {
		astman_send_error(s, m, "No AoRs configured for endpoint\n");
		return 0;
	}

	aors = ast_strdupa(endpoint->aors);
	while ((aor_name = strsep(&aors, ","))) {
		struct ast_sip_aor *aor;
		struct ao2_container *contacts;

		aor = ast_sip_location_retrieve_aor(aor_name);
		if (!aor) {
			continue;
		}

		contacts = ast_sip_location_retrieve_aor_contacts(aor);
		if (contacts) {
			ao2_callback(contacts, OBJ_NODATA, ami_contact_cb, NULL);
			ao2_ref(contacts, -1);
		}

		ao2_ref(aor, -1);
	}

	astman_send_ack(s, m, "Endpoint found, will qualify");
	return 0;
}
示例#20
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;
}
示例#21
0
void ast_ari_asterisk_delete_object(struct ast_variable *headers,
	struct ast_ari_asterisk_delete_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);

	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_ari_response_error(
			response, 404, "Not Found",
			"Object with id '%s' not found",
			args->id);
		return;
	}

	if (ast_sorcery_delete(sorcery, sorcery_obj)) {
		ast_ari_response_error(
			response, 403, "Forbidden",
			"Could not delete object with id '%s'",
			args->id);
		return;
	}

	ast_ari_response_no_content(response);
}
示例#22
0
/*!
 * \internal
 * \brief A contact has been deleted remove status tracking.
 */
static void contact_deleted(const void *obj)
{
	struct ast_sip_contact *contact = (struct ast_sip_contact *) obj;
	struct ast_sip_contact_status *status;

	unschedule_qualify(contact);

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

	if (ast_sorcery_delete(ast_sip_get_sorcery(), status)) {
		ast_log(LOG_ERROR, "Unable to delete ast_sip_contact_status for contact %s\n",
			contact->uri);
	}
	ao2_ref(status, -1);
}
示例#23
0
static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
	const char *endpoint_name;
	struct qualify_data *qual_data;

	switch (cmd) {
	case CLI_INIT:
		e->command = "pjsip qualify";
		e->usage =
			"Usage: pjsip qualify <endpoint>\n"
			"       Send a SIP OPTIONS request to all contacts on the endpoint.\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

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

	endpoint_name = a->argv[2];

	if (!(endpoint = ast_sorcery_retrieve_by_id(
		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
		ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
		return CLI_FAILURE;
	}

	qual_data = qualify_data_alloc(endpoint, a->fd);
	if (!qual_data) {
		return CLI_FAILURE;
	}

	if (ast_sip_push_task(NULL, cli_qualify_contacts, qual_data)) {
		qualify_data_destroy(qual_data);
		return CLI_FAILURE;
	}

	return CLI_SUCCESS;
}
示例#24
0
/*!
 * \internal
 * \brief Send a NOTIFY request to the endpoint within a threaded task.
 */
static enum notify_result push_notify(const char *endpoint_name, void *info,
				      task_data_create data_create)
{
	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
	struct notify_data *data;

	if (!(endpoint = ast_sorcery_retrieve_by_id(
		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
		return INVALID_ENDPOINT;
	}

	if (!(data = data_create(endpoint, info))) {
		return ALLOC_ERROR;
	}

	if (ast_sip_push_task(NULL, notify_endpoint, data)) {
		ao2_cleanup(data);
		return TASK_PUSH_ERROR;
	}

	return SUCCESS;
}
static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoint_name,
	char *domain_name)
{
	char id[AST_UUID_STR_LEN];
	struct ast_sip_endpoint *endpoint;
	RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
	RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);

	if (!ast_sip_get_disable_multi_domain()) {
		/* Attempt to find the endpoint given the name and domain provided */
		snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name);
		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
			return endpoint;
		}

		/* See if an alias exists for the domain provided */
		if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
			snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain);
			if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
				return endpoint;
			}
		}
		/* See if the transport this came in on has a provided domain */
		if ((transport_states = ast_sip_get_transport_states())
			&& (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata))
			&& (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))
			&& !ast_strlen_zero(transport->domain)) {
			snprintf(id, sizeof(id), "anonymous@%s", transport->domain);
			if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
				return endpoint;
			}
		}
	}

	/* Fall back to no domain */
	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
}
示例#26
0
static void *cli_aor_retrieve_by_id(const char *id)
{
	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id);
}
示例#27
0
struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
{
	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
}
示例#28
0
struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
{
	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
}
示例#29
0
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
{
	RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
	struct rx_task_data *task_data;

	RAII_VAR(struct ast_sip_endpoint *, endpoint,
		 ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
	pjsip_sip_uri *uri;
	char user_name[64], domain_name[64];
	char *configured_aors, *aor_name;

	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
		return PJ_FALSE;
	}

	if (ast_strlen_zero(endpoint->aors)) {
		/* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
		ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
		ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
	ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
	ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));

	configured_aors = ast_strdupa(endpoint->aors);

	/* Iterate the configured AORs to see if the user or the user+domain match */
	while ((aor_name = strsep(&configured_aors, ","))) {
		char id[AST_UUID_STR_LEN];
		RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);

		snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
		if (!strcmp(aor_name, id)) {
			break;
		}

		if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
			snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
			if (!strcmp(aor_name, id)) {
				break;
			}
		}

		if (!strcmp(aor_name, user_name)) {
			break;
		}
	}

	if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
		/* The provided AOR name was not found (be it within the configuration or sorcery itself) */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
		ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
		ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	if (!aor->max_contacts) {
		/* Registration is not permitted for this AOR */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
		ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
				ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint));
		return PJ_TRUE;
	}

	if (!(ser = serializer_find_or_create(aor_name))) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_mem_limit(endpoint, rdata);
		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n",
			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
		return PJ_TRUE;
	}

	if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_mem_limit(endpoint, rdata);
		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n",
			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
		return PJ_TRUE;
	}

	if (ast_sip_push_task(ser->serializer, rx_task, task_data)) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
		ast_sip_report_mem_limit(endpoint, rdata);
		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n",
			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
		ao2_ref(task_data, -1);
	}
	return PJ_TRUE;
}
示例#30
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);
}