Beispiel #1
0
/*! \brief Frame hook callback for writing */
static struct ast_frame *t38_framehook_write(struct ast_sip_session *session, struct ast_frame *f)
{
	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS &&
		session->endpoint->media.t38.enabled) {
		struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(session, f);

		if (!data) {
			return f;
		}

		if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) {
			ao2_ref(data, -1);
		}

		f = &ast_null_frame;
	} else if (f->frametype == AST_FRAME_MODEM) {
		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);

		if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) &&
			session_media->udptl) {
			ast_udptl_write(session_media->udptl, f);
		}
	}

	return f;
}
Beispiel #2
0
static int load_module(void)
{
	CHECK_PJSIP_MODULE_LOADED();

	if (ast_sip_register_subscription_handler(&mwi_handler)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	unsolicited_mwi = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
	if (!unsolicited_mwi) {
		ast_sip_unregister_subscription_handler(&mwi_handler);
		return AST_MODULE_LOAD_DECLINE;
	}

	create_mwi_subscriptions();
	ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);

	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
		ast_sip_push_task(NULL, send_initial_notify_all, NULL);
	} else {
		stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL);
	}

	return AST_MODULE_LOAD_SUCCESS;
}
Beispiel #3
0
static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
		struct stasis_message *msg)
{
	struct mwi_subscription *mwi_sub = userdata;

	if (stasis_subscription_final_message(sub, msg)) {
		ao2_ref(mwi_sub, +1);
		ast_sip_push_task(NULL, serialized_cleanup, mwi_sub);
		return;
	}

	if (ast_mwi_state_type() == stasis_message_type(msg)) {
		struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
		ao2_ref(mwi_sub, +1);
		ast_sip_push_task(serializer, serialized_notify, mwi_sub);
	}
}
Beispiel #4
0
/*! \brief Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it */
static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
	struct ast_sip_session *session = entry->user_data;

	if (ast_sip_push_task(session->serializer, t38_automatic_reject, session)) {
		ao2_ref(session, -1);
	}
}
/*!
 * \internal
 * \brief Send qualify request to the given contact.
 */
static int ami_contact_cb(void *obj, void *arg, int flags)
{
	struct ast_sip_contact *contact = obj;

	ao2_ref(contact, +1);
	if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
		ao2_ref(contact, -1);
	}
	return 0;
}
/*
 * This function is run by the scheduler thread.  Its only job is to push the task
 * to the serialize and return.  It returns 0 so it's not rescheduled.
 */
static int push_to_serializer(const void *data)
{
	struct ast_sip_sched_task *schtd = (struct ast_sip_sched_task *)data;

	if (ast_sip_push_task(schtd->serializer, run_task, schtd)) {
		ao2_ref(schtd, -1);
	}

	return 0;
}
Beispiel #7
0
static int send_notify(void *obj, void *arg, int flags)
{
	struct mwi_subscription *mwi_sub = obj;
	struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;

	if (ast_sip_push_task(serializer, serialized_notify, ao2_bump(mwi_sub))) {
		ao2_ref(mwi_sub, -1);
	}

	return 0;
}
/*!
 * \internal
 * \brief Qualify the given contact and set up scheduling if configured.
 */
static void qualify_and_schedule(struct ast_sip_contact *contact)
{
	unschedule_qualify(contact);

	if (contact->qualify_frequency) {
		ao2_ref(contact, +1);
		if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
			ao2_ref(contact, -1);
		}

		schedule_qualify(contact, contact->qualify_frequency * 1000);
	} else {
		update_contact_status(contact, UNKNOWN);
	}
}
/*!
 * \internal
 * \brief The reliable transport we registered as a contact has shutdown.
 *
 * \param data What contact needs to be removed.
 *
 * \note Normally executed by the pjsip monitor thread.
 *
 * \return Nothing
 */
static void register_contact_transport_shutdown_cb(void *data)
{
	struct contact_transport_monitor *monitor = data;

	/*
	 * Push off to a default serializer.  This is in case sorcery
	 * does database accesses for contacts.  Database accesses may
	 * not be on this machine.  We don't want to tie up the pjsip
	 * monitor thread with potentially long access times.
	 */
	ao2_ref(monitor, +1);
	if (ast_sip_push_task(NULL, register_contact_transport_remove_cb, monitor)) {
		ao2_ref(monitor, -1);
	}
}
Beispiel #10
0
/*! \brief Function called to send MWI NOTIFY on any unsolicited mailboxes relating to this AOR */
static int send_contact_notify(void *obj, void *arg, int flags)
{
	struct mwi_subscription *mwi_sub = obj;
	const char *aor = arg;

	if (!mwi_sub->aors || !strstr(mwi_sub->aors, aor)) {
		return 0;
	}

	if (ast_sip_push_task(NULL, serialized_notify, ao2_bump(mwi_sub))) {
		ao2_ref(mwi_sub, -1);
	}

	return 0;
}
Beispiel #11
0
static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
		struct stasis_message *msg)
{
	struct mwi_subscription *mwi_sub = userdata;

	if (stasis_subscription_final_message(sub, msg)) {
		if (ast_sip_push_task(NULL, serialized_cleanup, ao2_bump(mwi_sub))) {
			ao2_ref(mwi_sub, -1);
		}
		return;
	}

	if (ast_mwi_state_type() == stasis_message_type(msg)) {
		send_notify(mwi_sub, NULL, 0);
	}
}
Beispiel #12
0
/*!
 * \internal
 * \brief Send a NOTIFY request to the URI within an threaded task.
 */
static enum notify_result push_notify_uri(const char *uri, void *info,
	task_uri_data_create data_create)
{
	struct notify_uri_data *data;

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

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

	return SUCCESS;
}
/*!
 * \internal
 * \brief Send a scheduled qualify contact request.
 */
static int qualify_contact_sched(const void *obj)
{
	struct sched_data *data = (struct sched_data *) obj;

	ao2_ref(data->contact, +1);
	if (ast_sip_push_task(NULL, qualify_contact_task, data->contact)) {
		ao2_ref(data->contact, -1);
	}

	/*
	 * Always reschedule rather than have a potential race cleaning
	 * up the data object ref between self deletion and an external
	 * deletion.
	 */
	return data->contact->qualify_frequency * 1000;
}
Beispiel #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;
}
Beispiel #15
0
/*! \brief Event callback which fires initial unsolicited MWI NOTIFY messages when we're fully booted */
static void mwi_startup_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
{
	struct ast_json_payload *payload;
	const char *type;

	if (stasis_message_type(message) != ast_manager_get_generic_type()) {
		return;
	}

	payload = stasis_message_data(message);
	type = ast_json_string_get(ast_json_object_get(payload->json, "type"));

	if (strcmp(type, "FullyBooted")) {
		return;
	}

	ast_sip_push_task(NULL, send_initial_notify_all, NULL);

	stasis_unsubscribe(sub);
}
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;
}
Beispiel #17
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;
}
Beispiel #18
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;
}
Beispiel #19
0
static pj_bool_t distributor(pjsip_rx_data *rdata)
{
	pjsip_dialog *dlg;
	struct distributor_dialog_data *dist = NULL;
	struct ast_taskprocessor *serializer = NULL;
	pjsip_rx_data *clone;

	if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
		/*
		 * Ignore everything until we are fully booted.  Let the
		 * peer retransmit messages until we are ready.
		 */
		return PJ_TRUE;
	}

	dlg = find_dialog(rdata);
	if (dlg) {
		ast_debug(3, "Searching for serializer associated with dialog %s for %s\n",
			dlg->obj_name, pjsip_rx_data_get_info(rdata));
		dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY);
		if (dist) {
			ao2_lock(dist);
			serializer = ao2_bump(dist->serializer);
			ao2_unlock(dist);
			if (serializer) {
				ast_debug(3, "Found serializer %s associated with dialog %s\n",
					ast_taskprocessor_name(serializer), dlg->obj_name);
			}
		}
	}

	if (serializer) {
		/* We have a serializer so we know where to send the message. */
	} else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
		ast_debug(3, "No dialog serializer for %s.  Using request transaction as basis.\n",
			pjsip_rx_data_get_info(rdata));
		serializer = find_request_serializer(rdata);
		if (!serializer) {
			/*
			 * Pick a serializer for the unmatched response.
			 * We couldn't determine what serializer originally
			 * sent the request or the serializer is gone.
			 */
			serializer = ast_sip_get_distributor_serializer(rdata);
		}
	} else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method)
		|| !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) {
		/* We have a BYE or CANCEL request without a serializer. */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
			PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
		ao2_cleanup(dist);
		return PJ_TRUE;
	} else {
		if (ast_taskprocessor_alert_get()) {
			/*
			 * When taskprocessors get backed up, there is a good chance that
			 * we are being overloaded and need to defer adding new work to
			 * the system.  To defer the work we will ignore the request and
			 * rely on the peer's transport layer to retransmit the message.
			 * We usually work off the overload within a few seconds.  The
			 * alternative is to send back a 503 response to these requests
			 * and be done with it.
			 */
			ast_debug(3, "Taskprocessor overload alert: Ignoring '%s'.\n",
				pjsip_rx_data_get_info(rdata));
			ao2_cleanup(dist);
			return PJ_TRUE;
		}

		/* Pick a serializer for the out-of-dialog request. */
		serializer = ast_sip_get_distributor_serializer(rdata);
	}

	if (pjsip_rx_data_clone(rdata, 0, &clone) != PJ_SUCCESS) {
		ast_taskprocessor_unreference(serializer);
		ao2_cleanup(dist);
		return PJ_TRUE;
	}

	if (dist) {
		ao2_lock(dist);
		clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint);
		ao2_unlock(dist);
		ao2_cleanup(dist);
	}

	if (ast_sip_push_task(serializer, distribute, clone)) {
		ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]);
		pjsip_rx_data_free_cloned(clone);
	}

	ast_taskprocessor_unreference(serializer);

	return PJ_TRUE;
}
Beispiel #20
0
static int msg_send(void *data)
{
	RAII_VAR(struct msg_data *, mdata, data, ao2_cleanup);

	const struct ast_sip_body body = {
		.type = "text",
		.subtype = "plain",
		.body_text = ast_msg_get_body(mdata->msg)
	};

	pjsip_tx_data *tdata;
	RAII_VAR(char *, uri, NULL, ast_free);
	RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint(
			 mdata->to, &uri), ao2_cleanup);

	if (!endpoint) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint and "
			"no default outbound endpoint configured\n");
		return -1;
	}

	if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n");
		return -1;
	}

	update_to(tdata, mdata->to);
	update_from(tdata, mdata->from);

	if (ast_sip_add_body(tdata, &body)) {
		pjsip_tx_data_dec_ref(tdata);
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n");
		return -1;
	}

	vars_to_headers(mdata->msg, tdata);

	if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
		return -1;
	}

	return PJ_SUCCESS;
}

static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from)
{
	struct msg_data *mdata;

	if (ast_strlen_zero(to)) {
		ast_log(LOG_ERROR, "SIP MESSAGE - a 'To' URI  must be specified\n");
		return -1;
	}

	if (!(mdata = msg_data_create(msg, to, from)) ||
	    ast_sip_push_task(NULL, msg_send, mdata)) {
		ao2_ref(mdata, -1);
		return -1;
	}
	return 0;
}

static const struct ast_msg_tech msg_tech = {
	.name = "pjsip",
	.msg_send = sip_msg_send,
};

static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code,
				 pjsip_dialog *dlg, pjsip_transaction *tsx)
{
	pjsip_tx_data *tdata;
	pj_status_t status;
	pjsip_response_addr res_addr;

	status = ast_sip_create_response(rdata, code, NULL, &tdata);
	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
		return status;
	}

	if (dlg && tsx) {
		status = pjsip_dlg_send_response(dlg, tsx, tdata);
	} else {
		/* Get where to send request. */
		status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
		if (status != PJ_SUCCESS) {
			ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status);
			return status;
		}
		status = ast_sip_send_response(&res_addr, tdata, ast_pjsip_rdata_get_endpoint(rdata));
	}

	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
	}

	return status;
}

static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
{
	enum pjsip_status_code code;
	struct ast_msg *msg;

	/* if not a MESSAGE, don't handle */
	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_message_method)) {
		return PJ_FALSE;
	}

	msg = ast_msg_alloc();
	if (!msg) {
		send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
		return PJ_TRUE;
	}

	if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
		send_response(rdata, code, NULL, NULL);
		return PJ_TRUE;
	}

	if ((code = rx_data_to_ast_msg(rdata, msg)) == PJSIP_SC_OK) {
		/* send it to the dialplan */
		ast_msg_queue(msg);
		code = PJSIP_SC_ACCEPTED;
	}

	send_response(rdata, code, NULL, NULL);
	return PJ_TRUE;
}

static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
{
	char buf[MAX_BODY_SIZE];
	enum pjsip_status_code code;
	struct ast_frame f;

	pjsip_dialog *dlg = session->inv_session->dlg;
	pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);

	if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
		send_response(rdata, code, dlg, tsx);
		return 0;
	}

	if (print_body(rdata, buf, sizeof(buf)-1) < 1) {
		/* invalid body size */
		return 0;
	}

	ast_debug(3, "Received in dialog SIP message\n");

	memset(&f, 0, sizeof(f));
	f.frametype = AST_FRAME_TEXT;
	f.subclass.integer = 0;
	f.offset = 0;
	f.data.ptr = buf;
	f.datalen = strlen(buf) + 1;
	ast_queue_frame(session->channel, &f);

	send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx);
	return 0;
}
static int msg_send(void *data)
{
	RAII_VAR(struct msg_data *, mdata, data, ao2_cleanup);

	const struct ast_sip_body body = {
		.type = "text",
		.subtype = "plain",
		.body_text = ast_msg_get_body(mdata->msg)
	};

	pjsip_tx_data *tdata;
	RAII_VAR(char *, uri, NULL, ast_free);
	RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint(
			 mdata->to, &uri), ao2_cleanup);

	if (!endpoint) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint '%s' and "
			"no default outbound endpoint configured\n", mdata->to);
		return -1;
	}

	if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n");
		return -1;
	}

	update_to(tdata, mdata->to);
	update_from(tdata, mdata->from);

	if (ast_sip_add_body(tdata, &body)) {
		pjsip_tx_data_dec_ref(tdata);
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n");
		return -1;
	}

	vars_to_headers(mdata->msg, tdata);

	ast_debug(1, "Sending message to '%s' (via endpoint %s) from '%s'\n",
		mdata->to, ast_sorcery_object_get_id(endpoint), mdata->from);

	if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
		return -1;
	}

	return PJ_SUCCESS;
}

static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from)
{
	struct msg_data *mdata;

	if (ast_strlen_zero(to)) {
		ast_log(LOG_ERROR, "SIP MESSAGE - a 'To' URI  must be specified\n");
		return -1;
	}

	if (!(mdata = msg_data_create(msg, to, from)) ||
	    ast_sip_push_task(message_serializer, msg_send, mdata)) {
		ao2_ref(mdata, -1);
		return -1;
	}
	return 0;
}

static const struct ast_msg_tech msg_tech = {
	.name = "pjsip",
	.msg_send = sip_msg_send,
};

static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code,
				 pjsip_dialog *dlg, pjsip_transaction *tsx)
{
	pjsip_tx_data *tdata;
	pj_status_t status;

	status = ast_sip_create_response(rdata, code, NULL, &tdata);
	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
		return status;
	}

	if (dlg && tsx) {
		status = pjsip_dlg_send_response(dlg, tsx, tdata);
	} else {
		struct ast_sip_endpoint *endpoint;

		endpoint = ast_pjsip_rdata_get_endpoint(rdata);
		status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
		ao2_cleanup(endpoint);
	}

	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
	}

	return status;
}

static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
{
	enum pjsip_status_code code;
	struct ast_msg *msg;

	/* if not a MESSAGE, don't handle */
	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_message_method)) {
		return PJ_FALSE;
	}

	code = check_content_type(rdata);
	if (code != PJSIP_SC_OK) {
		send_response(rdata, code, NULL, NULL);
		return PJ_TRUE;
	}

	msg = ast_msg_alloc();
	if (!msg) {
		send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
		return PJ_TRUE;
	}

	code = rx_data_to_ast_msg(rdata, msg);
	if (code != PJSIP_SC_OK) {
		send_response(rdata, code, NULL, NULL);
		ast_msg_destroy(msg);
		return PJ_TRUE;
	}

	if (!ast_msg_has_destination(msg)) {
		ast_debug(1, "MESSAGE request received, but no handler wanted it\n");
		send_response(rdata, PJSIP_SC_NOT_FOUND, NULL, NULL);
		ast_msg_destroy(msg);
		return PJ_TRUE;
	}

	/* Send it to the messaging core.
	 *
	 * If we are unable to send a response, the most likely reason is that we
	 * are handling a retransmission of an incoming MESSAGE and were unable to
	 * create a transaction due to a duplicate key. If we are unable to send
	 * a response, we should not queue the message to the dialplan
	 */
	if (!send_response(rdata, PJSIP_SC_ACCEPTED, NULL, NULL)) {
		ast_msg_queue(msg);
	}

	return PJ_TRUE;
}

static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
{
	char buf[MAX_BODY_SIZE];
	enum pjsip_status_code code;
	struct ast_frame f;
	pjsip_dialog *dlg = session->inv_session->dlg;
	pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);

	if (!session->channel) {
		send_response(rdata, PJSIP_SC_NOT_FOUND, dlg, tsx);
		return 0;
	}

	if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
		send_response(rdata, code, dlg, tsx);
		return 0;
	}

	if (print_body(rdata, buf, sizeof(buf)-1) < 1) {
		/* invalid body size */
		send_response(rdata, PJSIP_SC_REQUEST_ENTITY_TOO_LARGE, dlg, tsx);
		return 0;
	}

	ast_debug(3, "Received in dialog SIP message\n");

	memset(&f, 0, sizeof(f));
	f.frametype = AST_FRAME_TEXT;
	f.subclass.integer = 0;
	f.offset = 0;
	f.data.ptr = buf;
	f.datalen = strlen(buf) + 1;
	ast_queue_frame(session->channel, &f);

	send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx);
	return 0;
}