示例#1
0
static struct ao2_container *cli_contact_get_container(const char *regex)
{
	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
	struct ao2_container *child_container;
	regex_t regexbuf;

	parent_container =  cli_aor_get_container("");
	if (!parent_container) {
		return NULL;
	}

	child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		cli_contact_sort, cli_contact_compare);
	if (!child_container) {
		return NULL;
	}

	ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);

	if (!ast_strlen_zero(regex)) {
		if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
			ao2_ref(child_container, -1);
			return NULL;
		}
		ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
		regfree(&regexbuf);
	}

	return child_container;
}
示例#2
0
static struct ao2_container *get_container(const char *regex, ao2_sort_fn sort_fn, ao2_callback_fn compare_fn)
{
	struct ao2_container *child_container;
	regex_t regexbuf;
	RAII_VAR(struct ao2_container *, parent_container,
		stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup);

	if (!parent_container) {
		return NULL;
	}

	child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, sort_fn, compare_fn);
	if (!child_container) {
		return NULL;
	}

	ao2_callback(parent_container, OBJ_MULTIPLE | OBJ_NODATA, cli_message_to_snapshot, child_container);

	if (!ast_strlen_zero(regex)) {
		if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
			ao2_ref(child_container, -1);
			return NULL;
		}
		ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, &regexbuf);
		regfree(&regexbuf);
	}

	return child_container;
}
示例#3
0
文件: control.c 项目: vzar/asterisk
struct stasis_app_control *control_create(struct ast_channel *channel)
{
    RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
    int res;

    control = ao2_alloc(sizeof(*control), control_dtor);
    if (!control) {
        return NULL;
    }

    res = ast_cond_init(&control->wait_cond, NULL);
    if (res != 0) {
        ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n",
                strerror(errno));
        return NULL;
    }

    control->command_queue = ao2_container_alloc_list(
                                 AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);

    if (!control->command_queue) {
        return NULL;
    }

    control->channel = channel;

    AST_LIST_HEAD_INIT(&control->add_rules);
    AST_LIST_HEAD_INIT(&control->remove_rules);

    ao2_ref(control, +1);
    return control;
}
示例#4
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;
}
示例#5
0
static int ami_show_auths(struct mansession *s, const struct message *m)
{
	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
	struct ao2_container *auths;

	auths = cli_get_auths();
	if (!auths) {
		astman_send_error(s, m, "Could not get Auths\n");
		return 0;
	}

	if (!ao2_container_count(auths)) {
		astman_send_error(s, m, "No Auths found\n");
		ao2_ref(auths, -1);
		return 0;
	}

	astman_send_listack(s, m, "A listing of Auths follows, presented as AuthList events",
			"start");

	ao2_callback(auths, OBJ_NODATA, format_ami_authlist_handler, &ami);

	astman_send_list_complete_start(s, m, "AuthListComplete", ami.count);
	astman_send_list_complete_end(s);

	ao2_ref(auths, -1);

	return 0;
}

static struct ao2_container *cli_get_container(const char *regex)
{
	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
	struct ao2_container *s_container;

	container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "auth", regex);
	if (!container) {
		return NULL;
	}

	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
	if (!s_container) {
		return NULL;
	}

	if (ao2_container_dup(s_container, container, 0)) {
		ao2_ref(s_container, -1);
		return NULL;
	}

	return s_container;
}
示例#6
0
struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const char *aor_list)
{
	struct ao2_container *contacts;

	contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
	if (!contacts) {
		return NULL;
	}

	ast_sip_for_each_aor(aor_list, gather_contacts_for_aor, contacts);

	return contacts;
}
示例#7
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;
}
示例#8
0
static struct ao2_container *cli_contact_get_container(void)
{
	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
	struct ao2_container *child_container;

	parent_container =  cli_aor_get_container();
	if (!parent_container) {
		return NULL;
	}

	child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		cli_contact_sort, cli_contact_compare);
	if (!child_container) {
		return NULL;
	}

	ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);

	return child_container;
}
示例#9
0
int ast_local_init(void)
{

	if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_begin_type)) {
		return -1;
	}

	if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_end_type)) {
		return -1;
	}

	if (STASIS_MESSAGE_TYPE_INIT(ast_local_bridge_type)) {
		return -1;
	}

	if (!(local_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
		return -1;
	}
	ast_format_cap_append_by_type(local_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);

	locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
	if (!locals) {
		ao2_cleanup(local_tech.capabilities);
		local_tech.capabilities = NULL;
		return -1;
	}

	/* Make sure we can register our channel type */
	if (ast_channel_register(&local_tech)) {
		ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
		ao2_ref(locals, -1);
		ao2_cleanup(local_tech.capabilities);
		local_tech.capabilities = NULL;
		return -1;
	}
	ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
	ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);

	ast_register_cleanup(local_shutdown);
	return 0;
}
示例#10
0
static void *notify_option_alloc(const char *category)
{
	int category_size = strlen(category) + 1;

	struct notify_option *option = ao2_alloc(
		sizeof(*option) + category_size, notify_option_destroy);

	if (!option) {
		return NULL;
	}

	ast_copy_string(option->name, category, category_size);

	if (!(option->items = ao2_container_alloc_list(
		      AO2_ALLOC_OPT_LOCK_NOLOCK,
		      AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW, NULL, NULL))) {
		ao2_cleanup(option);
		return NULL;
	}

	return option;
}
示例#11
0
static struct ao2_container *cli_aor_get_container(const char *regex)
{
	struct ao2_container *container;
	struct ao2_container *s_container;

	container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex);
	if (!container) {
		return NULL;
	}

	/* Create a sorted container of aors. */
	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
	if (s_container
		&& ao2_container_dup(s_container, container, 0)) {
		ao2_ref(s_container, -1);
		s_container = NULL;
	}
	ao2_ref(container, -1);

	return s_container;
}
示例#12
0
static struct ao2_container *cli_aor_get_container(const char *regex)
{
	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
	struct ao2_container *s_container;

	container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex);
	if (!container) {
		return NULL;
	}

	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
	if (!s_container) {
		return NULL;
	}

	if (ao2_container_dup(s_container, container, 0)) {
		ao2_ref(s_container, -1);
		return NULL;
	}

	return s_container;
}
示例#13
0
static struct ao2_container *cli_get_container(void)
{
	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
	struct ao2_container *s_container;

	container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "auth",
		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
	if (!container) {
		return NULL;
	}

	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
	if (!s_container) {
		return NULL;
	}

	if (ao2_container_dup(s_container, container, 0)) {
		ao2_ref(s_container, -1);
		return NULL;
	}

	return s_container;
}
示例#14
0
static int distribute(void *data)
{
	static pjsip_process_rdata_param param = {
		.start_mod = &distributor_mod,
		.idx_after_start = 1,
	};
	pj_bool_t handled = PJ_FALSE;
	pjsip_rx_data *rdata = data;
	int is_request = rdata->msg_info.msg->type == PJSIP_REQUEST_MSG;
	int is_ack = is_request ? rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD : 0;
	struct ast_sip_endpoint *endpoint;

	pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), rdata, &param, &handled);
	if (!handled && is_request && !is_ack) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 501, NULL, NULL, NULL);
	}

	/* The endpoint_mod stores an endpoint reference in the mod_data of rdata. This
	 * is the only appropriate spot to actually decrement the reference.
	 */
	endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
	ao2_cleanup(endpoint);
	pjsip_rx_data_free_cloned(rdata);
	return 0;
}

struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
{
	struct ast_sip_endpoint *endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
	if (endpoint) {
		ao2_ref(endpoint, +1);
	}
	return endpoint;
}

static int suspects_sort(const void *obj, const void *arg, int flags)
{
	const struct unidentified_request *object_left = obj;
	const struct unidentified_request *object_right = arg;
	const char *right_key = arg;
	int cmp;

	switch (flags & OBJ_SEARCH_MASK) {
	case OBJ_SEARCH_OBJECT:
		right_key = object_right->src_name;
		/* Fall through */
	case OBJ_SEARCH_KEY:
		cmp = strcmp(object_left->src_name, right_key);
		break;
	case OBJ_SEARCH_PARTIAL_KEY:
		cmp = strncmp(object_left->src_name, right_key, strlen(right_key));
		break;
	default:
		cmp = 0;
		break;
	}
	return cmp;
}

static int suspects_compare(void *obj, void *arg, int flags)
{
	const struct unidentified_request *object_left = obj;
	const struct unidentified_request *object_right = arg;
	const char *right_key = arg;
	int cmp = 0;

	switch (flags & OBJ_SEARCH_MASK) {
	case OBJ_SEARCH_OBJECT:
		right_key = object_right->src_name;
		/* Fall through */
	case OBJ_SEARCH_KEY:
		if (strcmp(object_left->src_name, right_key) == 0) {
			cmp = CMP_MATCH;
		}
		break;
	case OBJ_SEARCH_PARTIAL_KEY:
		if (strncmp(object_left->src_name, right_key, strlen(right_key)) == 0) {
			cmp = CMP_MATCH;
		}
		break;
	default:
		cmp = 0;
		break;
	}
	return cmp;
}

static int suspects_hash(const void *obj, int flags)
{
	const struct unidentified_request *object;
	const char *key;

	switch (flags & OBJ_SEARCH_MASK) {
	case OBJ_SEARCH_KEY:
		key = obj;
		break;
	case OBJ_SEARCH_OBJECT:
		object = obj;
		key = object->src_name;
		break;
	default:
		/* Hash can only work on something with a full key. */
		ast_assert(0);
		return 0;
	}
	return ast_str_hash(key);
}

static struct ao2_container *cli_unid_get_container(const char *regex)
{
	struct ao2_container *s_container;

	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
		suspects_sort, suspects_compare);
	if (!s_container) {
		return NULL;
	}

	if (ao2_container_dup(s_container, unidentified_requests, 0)) {
		ao2_ref(s_container, -1);
		return NULL;
	}

	return s_container;
}

static int cli_unid_iterate(void *container, ao2_callback_fn callback, void *args)
{
	ao2_callback(container, 0, callback, args);

	return 0;
}
示例#15
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;
}
示例#16
0
static void register_aor_core(pjsip_rx_data *rdata,
	struct ast_sip_endpoint *endpoint,
	struct ast_sip_aor *aor,
	const char *aor_name,
	struct ao2_container *contacts,
	struct aor_core_response *response)
{
	static const pj_str_t USER_AGENT = { "User-Agent", 10 };

	int added = 0;
	int updated = 0;
	int deleted = 0;
	int permanent = 0;
	int contact_count;
	struct ao2_container *existing_contacts = NULL;
	pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
	struct registrar_contact_details details = { 0, };
	pjsip_tx_data *tdata;
	RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
	struct ast_sip_contact *response_contact;
	char *user_agent = NULL;
	pjsip_user_agent_hdr *user_agent_hdr;
	pjsip_expires_hdr *expires_hdr;
	pjsip_via_hdr *via_hdr;
	pjsip_via_hdr *via_hdr_last;
	char *via_addr = NULL;
	int via_port = 0;
	pjsip_cid_hdr *call_id_hdr;
	char *call_id = NULL;
	size_t alloc_size;

	/* We create a single pool and use it throughout this function where we need one */
	details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
		"Contact Comparison", 1024, 256);
	if (!details.pool) {
		response->code = 500;
		return;
	}

	/* If there are any permanent contacts configured on the AOR we need to take them
	 * into account when counting contacts.
	 */
	if (aor->permanent_contacts) {
		permanent = ao2_container_count(aor->permanent_contacts);
	}

	if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
		/* The provided Contact headers do not conform to the specification */
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
		ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
				ast_sorcery_object_get_id(endpoint));
		response->code = 400;
		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
		return;
	}

	if (registrar_validate_path(rdata, aor, &path_str)) {
		/* Ensure that intervening proxies did not make invalid modifications to the request */
		ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
				ast_sorcery_object_get_id(endpoint));
		response->code = 420;
		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
		return;
	}

	if (aor->remove_existing) {
		/* Cumulative number of contacts affected by this registration */
		contact_count = MAX(updated + added - deleted,  0);

		/* We need to keep track of only existing contacts so we can later
		 * remove them if need be.
		 */
		existing_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
			NULL, ast_sorcery_object_id_compare);
		if (!existing_contacts) {
			response->code = 500;
			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
			return;
		}

		ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
	} else {
		/* Total contacts after this registration */
		contact_count = ao2_container_count(contacts) - permanent + added - deleted;
	}
	if (contact_count > aor->max_contacts) {
		/* Enforce the maximum number of contacts */
		ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
		ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
				ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
		response->code = 403;
		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
		ao2_cleanup(existing_contacts);
		return;
	}

	user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
	if (user_agent_hdr) {
		alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
		user_agent = ast_alloca(alloc_size);
		ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
	}

	/* Find the first Via header */
	via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
	if (via_hdr) {
		/* Find the last Via header */
		while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
				PJSIP_H_VIA, via_hdr->next)) != NULL) {
			via_hdr_last = via_hdr;
		}
		alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
		via_addr = ast_alloca(alloc_size);
		ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
		via_port=via_hdr_last->sent_by.port;
	}

	call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
	if (call_id_hdr) {
		alloc_size = pj_strlen(&call_id_hdr->id) + 1;
		call_id = ast_alloca(alloc_size);
		ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
	}

	/* Iterate each provided Contact header and add, update, or delete */
	for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
		int expiration;
		char contact_uri[pjsip_max_url_size];
		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);

		if (contact_hdr->star) {
			/* A star means to unregister everything, so do so for the possible contacts */
			ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
				registrar_delete_contact, (void *)aor_name);
			/* If we are keeping track of existing contacts for removal then, well, there is
			 * absolutely nothing left so no need to try to remove any.
			 */
			if (existing_contacts) {
				ao2_ref(existing_contacts, -1);
				existing_contacts = NULL;
			}
			break;
		}

		if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
			/* This registrar only currently supports sip: and sips: URI schemes */
			continue;
		}

		expiration = registrar_get_expiration(aor, contact_hdr, rdata);
		details.uri = pjsip_uri_get_uri(contact_hdr->uri);
		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));

		contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);

		/* If a contact was returned and we need to keep track of existing contacts then it
		 * should be removed.
		 */
		if (contact && existing_contacts) {
			ao2_unlink(existing_contacts, contact);
		}

		if (!contact) {
			int prune_on_boot;

			/* If they are actually trying to delete a contact that does not exist... be forgiving */
			if (!expiration) {
				ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
					contact_uri, aor_name);
				continue;
			}

			prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata);

			contact = ast_sip_location_create_contact(aor, contact_uri,
				ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
				path_str ? ast_str_buffer(path_str) : NULL,
				user_agent, via_addr, via_port, call_id, prune_on_boot, endpoint);
			if (!contact) {
				ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
					contact_uri, aor_name);
				continue;
			}

			if (prune_on_boot) {
				const char *contact_name;
				struct contact_transport_monitor *monitor;

				/*
				 * Monitor the transport in case it gets disconnected because
				 * the contact won't be valid anymore if that happens.
				 */
				contact_name = ast_sorcery_object_get_id(contact);
				monitor = ao2_alloc_options(sizeof(*monitor) + 2 + strlen(aor_name)
					+ strlen(contact_name), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
				if (monitor) {
					strcpy(monitor->aor_name, aor_name);/* Safe */
					monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
					strcpy(monitor->contact_name, contact_name);/* Safe */

					ast_sip_transport_monitor_register(rdata->tp_info.transport,
						register_contact_transport_shutdown_cb, monitor);
					ao2_ref(monitor, -1);
				}
			}

			ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_ADDED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					expiration,
					user_agent);

			ao2_link(contacts, contact);
		} else if (expiration) {
			struct ast_sip_contact *contact_update;

			contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
			if (!contact_update) {
				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
					contact->uri, expiration);
				continue;
			}

			contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
			contact_update->qualify_frequency = aor->qualify_frequency;
			contact_update->authenticate_qualify = aor->authenticate_qualify;
			if (path_str) {
				ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
			}
			if (user_agent) {
				ast_string_field_set(contact_update, user_agent, user_agent);
			}
			if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
				ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME);
			}

			if (ast_sip_location_update_contact(contact_update)) {
				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
					contact->uri, expiration);
				ast_sip_location_delete_contact(contact);
				continue;
			}
			ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					expiration,
					contact_update->user_agent);
			ao2_link(contacts, contact_update);
			ao2_cleanup(contact_update);
		} else {
			if (contact->prune_on_boot) {
				struct contact_transport_monitor *monitor;
				const char *contact_name =
					ast_sorcery_object_get_id(contact);

				monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(aor_name)
					+ strlen(contact_name));
				strcpy(monitor->aor_name, aor_name);/* Safe */
				monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
				strcpy(monitor->contact_name, contact_name);/* Safe */

				ast_sip_transport_monitor_unregister(rdata->tp_info.transport,
					register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher);
			}

			/* We want to report the user agent that was actually in the removed contact */
			ast_sip_location_delete_contact(contact);
			ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
			ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"UserAgent: %s",
					contact_uri,
					aor_name,
					contact->user_agent);
		}
	}

	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);

	/*
	 * If the AOR is configured to remove any contacts over max_contacts
	 * that have not been updated/added/deleted as a result of this
	 * REGISTER do so.
	 *
	 * The existing contacts container holds all contacts that were not
	 * involved in this REGISTER.
	 * The contacts container holds the current contacts of the AOR.
	 */
	if (aor->remove_existing && existing_contacts) {
		/* Total contacts after this registration */
		contact_count = ao2_container_count(existing_contacts) + updated + added;
		if (contact_count > aor->max_contacts) {
			/* Remove excess existing contacts that expire the soonest */
			remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts);
		}
		ao2_ref(existing_contacts, -1);
	}

	response_contact = ao2_callback(contacts, 0, NULL, NULL);

	/* Send a response containing all of the contacts (including static) that are present on this AOR */
	if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
		ao2_cleanup(response_contact);
		ao2_cleanup(contacts);
		response->code = 500;
		return;
	}
	ao2_cleanup(response_contact);

	/* Add the date header to the response, some UAs use this to set their date and time */
	registrar_add_date_header(tdata);

	ao2_callback(contacts, 0, registrar_add_contact, tdata);

	if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
		expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
	}

	response->tdata = tdata;
}